mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-15 06:12:50 -07:00
80 lines
2.6 KiB
TypeScript
80 lines
2.6 KiB
TypeScript
|
|
/**
|
||
|
|
* @license
|
||
|
|
* Copyright 2026 Google LLC
|
||
|
|
* SPDX-License-Identifier: Apache-2.0
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { GITHUB_OWNER, GITHUB_REPO } from '../types.js';
|
||
|
|
import { execSync } from 'node:child_process';
|
||
|
|
|
||
|
|
interface HotIssueNode {
|
||
|
|
number: number;
|
||
|
|
comments: {
|
||
|
|
totalCount: number;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Identifies "Zombie" issues (open issues with no activity for > 30 days).
|
||
|
|
*/
|
||
|
|
function run() {
|
||
|
|
try {
|
||
|
|
const now = new Date();
|
||
|
|
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
|
||
|
|
const sevenDaysAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
|
||
|
|
|
||
|
|
// 1. Count Zombie issues using Search API totalCount (unlimited)
|
||
|
|
const zombieSearchQuery = `is:issue is:open repo:${GITHUB_OWNER}/${GITHUB_REPO} updated:<${thirtyDaysAgo.toISOString()}`;
|
||
|
|
const zombieQuery = `
|
||
|
|
query($searchQuery: String!) {
|
||
|
|
search(query: $searchQuery, type: ISSUE, first: 0) {
|
||
|
|
issueCount
|
||
|
|
}
|
||
|
|
}
|
||
|
|
`;
|
||
|
|
const zombieOutput = execSync(
|
||
|
|
`gh api graphql -F searchQuery='${zombieSearchQuery}' -f query='${zombieQuery}'`,
|
||
|
|
{ encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] },
|
||
|
|
).trim();
|
||
|
|
const zombieCount = JSON.parse(zombieOutput).data.search.issueCount;
|
||
|
|
process.stdout.write(`bottleneck_zombie_issues_count,${zombieCount}\n`);
|
||
|
|
|
||
|
|
// 2. Identify "Hot" issues. Since we need to count comments per issue,
|
||
|
|
// we still need to fetch some nodes, but we can target the most active ones.
|
||
|
|
const hotSearchQuery = `is:issue is:open repo:${GITHUB_OWNER}/${GITHUB_REPO} updated:>${sevenDaysAgo.toISOString()} sort:comments-desc`;
|
||
|
|
const hotQuery = `
|
||
|
|
query($searchQuery: String!) {
|
||
|
|
search(query: $searchQuery, type: ISSUE, first: 100) {
|
||
|
|
nodes {
|
||
|
|
... on Issue {
|
||
|
|
number
|
||
|
|
comments {
|
||
|
|
totalCount
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
`;
|
||
|
|
const hotOutput = execSync(
|
||
|
|
`gh api graphql -F searchQuery='${hotSearchQuery}' -f query='${hotQuery}'`,
|
||
|
|
{ encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] },
|
||
|
|
).trim();
|
||
|
|
const hotNodes = JSON.parse(hotOutput).data.search.nodes as HotIssueNode[];
|
||
|
|
|
||
|
|
// We define "Hot" as > 10 comments in the last 7 days.
|
||
|
|
// Note: Search query 'sort:comments-desc' gets those with most total comments,
|
||
|
|
// which is a good proxy for 'Hot' when filtered by recent updates.
|
||
|
|
const veryHot = hotNodes.filter((node) => node.comments.totalCount > 10);
|
||
|
|
process.stdout.write(`bottleneck_hot_issues_count,${veryHot.length}\n`);
|
||
|
|
|
||
|
|
} catch (error) {
|
||
|
|
process.stderr.write(
|
||
|
|
error instanceof Error ? error.message : String(error),
|
||
|
|
);
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
run();
|