mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-10 14:10:37 -07:00
160 lines
5.9 KiB
YAML
160 lines
5.9 KiB
YAML
name: '🔒 Gemini Scheduled Stale Issue Closer'
|
|
|
|
on:
|
|
schedule:
|
|
- cron: '0 0 * * 0' # Every Sunday at midnight UTC
|
|
workflow_dispatch:
|
|
inputs:
|
|
dry_run:
|
|
description: 'Run in dry-run mode (no changes applied)'
|
|
required: false
|
|
default: false
|
|
type: 'boolean'
|
|
|
|
concurrency:
|
|
group: '${{ github.workflow }}'
|
|
cancel-in-progress: true
|
|
|
|
defaults:
|
|
run:
|
|
shell: 'bash'
|
|
|
|
jobs:
|
|
close-stale-issues:
|
|
if: "github.repository == 'google-gemini/gemini-cli'"
|
|
runs-on: 'ubuntu-latest'
|
|
permissions:
|
|
issues: 'write'
|
|
steps:
|
|
- name: 'Generate GitHub App Token'
|
|
id: 'generate_token'
|
|
uses: 'actions/create-github-app-token@v2'
|
|
with:
|
|
app-id: '${{ secrets.APP_ID }}'
|
|
private-key: '${{ secrets.PRIVATE_KEY }}'
|
|
permission-issues: 'write'
|
|
|
|
- name: 'Process Stale Issues'
|
|
uses: 'actions/github-script@v7'
|
|
env:
|
|
DRY_RUN: '${{ inputs.dry_run }}'
|
|
with:
|
|
github-token: '${{ steps.generate_token.outputs.token }}'
|
|
script: |
|
|
const dryRun = process.env.DRY_RUN === 'true';
|
|
if (dryRun) {
|
|
core.info('DRY RUN MODE ENABLED: No changes will be applied.');
|
|
}
|
|
const batchLabel = 'Stale';
|
|
|
|
const threeMonthsAgo = new Date();
|
|
threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3);
|
|
|
|
const tenDaysAgo = new Date();
|
|
tenDaysAgo.setDate(tenDaysAgo.getDate() - 10);
|
|
|
|
core.info(`Cutoff date for creation: ${threeMonthsAgo.toISOString()}`);
|
|
core.info(`Cutoff date for updates: ${tenDaysAgo.toISOString()}`);
|
|
|
|
const query = `repo:${context.repo.owner}/${context.repo.repo} is:issue is:open created:<${threeMonthsAgo.toISOString()}`;
|
|
core.info(`Searching with query: ${query}`);
|
|
|
|
const itemsToCheck = await github.paginate(github.rest.search.issuesAndPullRequests, {
|
|
q: query,
|
|
sort: 'created',
|
|
order: 'asc',
|
|
per_page: 100
|
|
});
|
|
|
|
core.info(`Found ${itemsToCheck.length} open issues to check.`);
|
|
|
|
let processedCount = 0;
|
|
|
|
for (const issue of itemsToCheck) {
|
|
const createdAt = new Date(issue.created_at);
|
|
const updatedAt = new Date(issue.updated_at);
|
|
const reactionCount = issue.reactions.total_count;
|
|
|
|
// Basic thresholds
|
|
if (reactionCount >= 5) {
|
|
continue;
|
|
}
|
|
|
|
// Skip if it has a maintainer, help wanted, or Public Roadmap label
|
|
const rawLabels = issue.labels.map((l) => l.name);
|
|
const lowercaseLabels = rawLabels.map((l) => l.toLowerCase());
|
|
if (
|
|
lowercaseLabels.some((l) => l.includes('maintainer')) ||
|
|
lowercaseLabels.includes('help wanted') ||
|
|
rawLabels.includes('🗓️ Public Roadmap')
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
let isStale = updatedAt < tenDaysAgo;
|
|
|
|
// If apparently active, check if it's only bot activity
|
|
if (!isStale) {
|
|
try {
|
|
const comments = await github.rest.issues.listComments({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: issue.number,
|
|
per_page: 100,
|
|
sort: 'created',
|
|
direction: 'desc'
|
|
});
|
|
|
|
const lastHumanComment = comments.data.find(comment => comment.user.type !== 'Bot');
|
|
if (lastHumanComment) {
|
|
isStale = new Date(lastHumanComment.created_at) < tenDaysAgo;
|
|
} else {
|
|
// No human comments. Check if creator is human.
|
|
if (issue.user.type !== 'Bot') {
|
|
isStale = createdAt < tenDaysAgo;
|
|
} else {
|
|
isStale = true; // Bot created, only bot comments
|
|
}
|
|
}
|
|
} catch (error) {
|
|
core.warning(`Failed to fetch comments for issue #${issue.number}: ${error.message}`);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (isStale) {
|
|
processedCount++;
|
|
const message = `Closing stale issue #${issue.number}: "${issue.title}" (${issue.html_url})`;
|
|
core.info(message);
|
|
|
|
if (!dryRun) {
|
|
// Add label
|
|
await github.rest.issues.addLabels({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: issue.number,
|
|
labels: [batchLabel]
|
|
});
|
|
|
|
// Add comment
|
|
await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: issue.number,
|
|
body: 'Hello! As part of our effort to keep our backlog manageable and focus on the most active issues, we are tidying up older reports.\n\nIt looks like this issue hasn\'t been active for a while, so we are closing it for now. However, if you are still experiencing this bug on the latest stable build, please feel free to comment on this issue or create a new one with updated details.\n\nThank you for your contribution!'
|
|
});
|
|
|
|
// Close issue
|
|
await github.rest.issues.update({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: issue.number,
|
|
state: 'closed',
|
|
state_reason: 'not_planned'
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
core.info(`\nTotal issues processed: ${processedCount}`);
|