Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions .github/workflows/lock.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
name: Lock closed issues and PRs

on:
schedule:
- cron: "45 0 * * *" # Run daily at 00:45 UTC
workflow_dispatch:

permissions:
issues: write
pull-requests: write

concurrency:
group: lock-closed
cancel-in-progress: false

jobs:
lock:
runs-on: ubuntu-latest
steps:
- name: Lock closed issues and PRs
uses: actions/github-script@v7.0.1
with:
script: |
const PR_CLOSE_DAYS = 1;
const ISSUE_CLOSE_DAYS = 7;
const EXCLUDE_LABEL = 'keep-open';
const LOCK_REASON = 'resolved';

const now = new Date();
const prCutoffDate = new Date(now.getTime() - PR_CLOSE_DAYS * 24 * 60 * 60 * 1000);
const issueCutoffDate = new Date(now.getTime() - ISSUE_CLOSE_DAYS * 24 * 60 * 60 * 1000);

console.log(`Will lock PRs closed before: ${prCutoffDate.toISOString()}`);
console.log(`Will lock issues closed before: ${issueCutoffDate.toISOString()}`);

// The `listForRepo` endpoint fetches both issues and pull requests.
// We fetch all closed items and filter them in the script.
const closedItems = await github.paginate(github.rest.issues.listForRepo, {
Copy link

Copilot AI Jun 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fetching all closed items may lead to performance issues in large repositories. Consider using filters such as a 'since' parameter or setting 'per_page' to limit the number of items retrieved.

Copilot uses AI. Check for mistakes.
owner: context.repo.owner,
repo: context.repo.repo,
state: 'closed',
});

for (const item of closedItems) {
if (item.locked) continue;

const hasExcludeLabel = item.labels.some(label => label.name === EXCLUDE_LABEL);
if (hasExcludeLabel) continue;

const closedAt = new Date(item.closed_at);
const isPr = 'pull_request' in item;

if ((isPr && closedAt < prCutoffDate) || (!isPr && closedAt < issueCutoffDate)) {
console.log(`Locking ${isPr ? 'PR' : 'issue'} #${item.number} which was closed at ${item.closed_at}`);
try {
await github.rest.issues.lock({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: item.number,
});
console.log(`Successfully locked #${item.number}.`);
} catch (e) {
console.error(`Failed to lock #${item.number}: ${e.message}`);
}
}
}