Skip to content

Locker

Locker #446

Workflow file for this run

name: Locker
on:
schedule:
- cron: 0 5 * * * # 10:00pm PT
workflow_dispatch:
workflow_call:
inputs:
days:
description: 'Number of days of inactivity before locking a closed issue (default: 28)'
required: false
type: string
default: '28'
permissions:
issues: write
jobs:
main:
runs-on: ubuntu-latest
steps:
- name: Lock Inactive Closed Issues
uses: actions/github-script@v8
env:
DAYS: ${{ inputs.days || '28' }}
with:
script: |
const days = parseInt(process.env.DAYS);
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - days);
core.info(`Locking closed issues with no activity since ${cutoffDate.toISOString()} (${days} days)`);
// Fetch all closed, unlocked issues (search API supports is:unlocked to skip already-locked issues)
const issues = await github.paginate(github.rest.search.issuesAndPullRequests, {
q: `repo:${context.repo.owner}/${context.repo.repo} is:issue is:closed is:unlocked`,
per_page: 100,
});
core.info(`Found ${issues.length} closed unlocked issue(s) to evaluate`);
let lockedCount = 0;
for (const issue of issues) {
// Skip pull requests (search may return them if the query matches)
if (issue.pull_request) {
continue;
}
// updated_at reflects the most recent activity (comments, label changes, state changes)
const lastActivity = new Date(issue.updated_at);
if (lastActivity >= cutoffDate) {
continue;
}
core.info(`Locking issue #${issue.number}: last activity on ${issue.updated_at}`);
await github.rest.issues.lock({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
lock_reason: 'resolved',
});
lockedCount++;
}
core.info(`Done. Locked ${lockedCount} issue(s).`);