mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-07-16 04:50:29 -07:00
## Description
Fixes the throughput metrics script and introduces new visibility into backlog bottlenecks and priority distribution. ### Changes - **Throughput Fixes**: Resolved a `ReferenceError` where `isMaintainer` was not correctly scoped, fixed a malformed license header, and added a new metric for `issue_arrival_rate_per_day` to enable growth-vs-closure analysis. - **Backlog Bottlenecks**: Introduced `bottlenecks.ts` to identify "Zombie" issues (no activity > 30 days) and "Hot" issues (high activity). - **Priority Distribution**: Introduced `priority_distribution.ts` to track the count of open issues by priority level (P0-P3). ### Impact These metrics will provide the necessary data to confirm if the repository is experiencing systemic backlog growth (Arrival Rate > Throughput) and help identify which segments of the backlog require urgent triage.
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* @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 IssueNode {
|
||||
number: number;
|
||||
updatedAt: string;
|
||||
comments: {
|
||||
totalCount: number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies "Zombie" issues (open issues with no activity for > 30 days).
|
||||
*/
|
||||
function run() {
|
||||
try {
|
||||
// Fetch 100 open issues, sorted by least recently updated.
|
||||
const query = `
|
||||
query($owner: String!, $repo: String!) {
|
||||
repository(owner: $owner, name: $repo) {
|
||||
issues(first: 100, states: OPEN, orderBy: {field: UPDATED_AT, direction: ASC}) {
|
||||
nodes {
|
||||
number
|
||||
updatedAt
|
||||
comments {
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
const output = execSync(
|
||||
`gh api graphql -F owner=${GITHUB_OWNER} -F repo=${GITHUB_REPO} -f query='${query}'`,
|
||||
{ encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] },
|
||||
).trim();
|
||||
const data = JSON.parse(output).data.repository;
|
||||
const issues: IssueNode[] = data.issues.nodes;
|
||||
|
||||
if (issues.length === 0) {
|
||||
process.stdout.write('bottleneck_zombie_issues_count,0\n');
|
||||
return;
|
||||
}
|
||||
|
||||
const now = new Date().getTime();
|
||||
const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1000;
|
||||
|
||||
const zombies = issues.filter((issue) => {
|
||||
const updated = new Date(issue.updatedAt).getTime();
|
||||
return updated < thirtyDaysAgo;
|
||||
});
|
||||
|
||||
process.stdout.write(`bottleneck_zombie_issues_count,${zombies.length}\n`);
|
||||
|
||||
// Also identify "Hot" issues in the same sample (though less likely to find them in the 'oldest' sample)
|
||||
// But we can also fetch 'most recently updated' to find Hot issues.
|
||||
const hotQuery = `
|
||||
query($owner: String!, $repo: String!) {
|
||||
repository(owner: $owner, name: $repo) {
|
||||
issues(last: 100, states: OPEN, orderBy: {field: UPDATED_AT, direction: ASC}) {
|
||||
nodes {
|
||||
number
|
||||
updatedAt
|
||||
comments {
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
const hotOutput = execSync(
|
||||
`gh api graphql -F owner=${GITHUB_OWNER} -F repo=${GITHUB_REPO} -f query='${hotQuery}'`,
|
||||
{ encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] },
|
||||
).trim();
|
||||
const hotData = JSON.parse(hotOutput).data.repository;
|
||||
const hotIssues: IssueNode[] = hotData.issues.nodes;
|
||||
|
||||
const sevenDaysAgo = now - 7 * 24 * 60 * 60 * 1000;
|
||||
const veryHot = hotIssues.filter((issue) => {
|
||||
const updated = new Date(issue.updatedAt).getTime();
|
||||
return updated > sevenDaysAgo && issue.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();
|
||||
Reference in New Issue
Block a user