mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-06-12 04:17:15 -07:00
## Metrics Standardization & Quality Fixes
This PR updates the metrics scripts to resolve lint errors and improve architectural consistency after the conversion to CSV format.
### 🛠 Fixes
1. **Lint Errors**: Resolved 6 `@typescript-eslint/no-unused-vars` errors by removing the unused `MetricOutput` import across the metric suite.
2. **License Standardization**: Removed redundant `@license` tags from all 8 metric scripts to match repository standards.
3. **GraphQL Consistency**: Updated `open_issues.ts` and `open_prs.ts` to use GraphQL variables (`-F`) and the `gh api graphql` pattern used by other scripts, improving security and readability.
4. **Output Consistency**: Migrated `open_issues.ts` and `open_prs.ts` from `console.log` to `process.stdout.write` for unified output behavior.
5. **Robust Execution**: Added `stdio: ['ignore', 'pipe', 'ignore']` to all `execSync` calls to ensure clean output streams and prevent unintentional inheritance of the parent process's stdio.
6. **Code Cleanup**: Removed the now-unused `MetricOutput` interface from `types.ts` and simplified `metrics/index.ts` by removing legacy JSON parsing logic.
### 🧪 Verification
- `npm run lint` now passes for all files in `tools/gemini-cli-bot/metrics/`.
- Validated all 8 scripts manually to ensure they still produce the correct CSV output.
This commit is contained in:
@@ -42,43 +42,16 @@ function processOutputLine(line: string, results: string[]) {
|
|||||||
const trimmedLine = line.trim();
|
const trimmedLine = line.trim();
|
||||||
if (!trimmedLine) return;
|
if (!trimmedLine) return;
|
||||||
|
|
||||||
let metricName = '';
|
const parts = trimmedLine.split(',');
|
||||||
let metricValue = 0;
|
if (parts.length !== 2) {
|
||||||
|
results.push(trimmedLine);
|
||||||
try {
|
return;
|
||||||
const parsed = JSON.parse(trimmedLine);
|
|
||||||
if (
|
|
||||||
parsed &&
|
|
||||||
typeof parsed === 'object' &&
|
|
||||||
'metric' in parsed &&
|
|
||||||
'value' in parsed
|
|
||||||
) {
|
|
||||||
metricName = parsed.metric;
|
|
||||||
metricValue = parseFloat(parsed.value);
|
|
||||||
results.push(`${metricName},${metricValue}`);
|
|
||||||
} else {
|
|
||||||
const parts = trimmedLine.split(',');
|
|
||||||
if (parts.length === 2) {
|
|
||||||
metricName = parts[0];
|
|
||||||
metricValue = parseFloat(parts[1]);
|
|
||||||
results.push(trimmedLine);
|
|
||||||
} else {
|
|
||||||
results.push(trimmedLine);
|
|
||||||
return; // Unable to parse for deltas
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
const parts = trimmedLine.split(',');
|
|
||||||
if (parts.length === 2) {
|
|
||||||
metricName = parts[0];
|
|
||||||
metricValue = parseFloat(parts[1]);
|
|
||||||
results.push(trimmedLine);
|
|
||||||
} else {
|
|
||||||
results.push(trimmedLine);
|
|
||||||
return; // Unable to parse for deltas
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const metricName = parts[0];
|
||||||
|
const metricValue = parseFloat(parts[1]);
|
||||||
|
results.push(trimmedLine);
|
||||||
|
|
||||||
// Calculate and append deltas if the metric is a valid number
|
// Calculate and append deltas if the metric is a valid number
|
||||||
if (metricName && !isNaN(metricValue)) {
|
if (metricName && !isNaN(metricValue)) {
|
||||||
const avg7d = getHistoricalAverage(metricName, 7);
|
const avg7d = getHistoricalAverage(metricName, 7);
|
||||||
|
|||||||
@@ -2,11 +2,9 @@
|
|||||||
* @license
|
* @license
|
||||||
* Copyright 2026 Google LLC
|
* Copyright 2026 Google LLC
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
|
||||||
* @license
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { GITHUB_OWNER, GITHUB_REPO, type MetricOutput } from '../types.js';
|
import { GITHUB_OWNER, GITHUB_REPO } from '../types.js';
|
||||||
import { execSync } from 'node:child_process';
|
import { execSync } from 'node:child_process';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|||||||
@@ -2,11 +2,9 @@
|
|||||||
* @license
|
* @license
|
||||||
* Copyright 2026 Google LLC
|
* Copyright 2026 Google LLC
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
|
||||||
* @license
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { GITHUB_OWNER, GITHUB_REPO, type MetricOutput } from '../types.js';
|
import { GITHUB_OWNER, GITHUB_REPO } from '../types.js';
|
||||||
import { execSync } from 'node:child_process';
|
import { execSync } from 'node:child_process';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -32,7 +30,7 @@ try {
|
|||||||
`;
|
`;
|
||||||
const output = execSync(
|
const output = execSync(
|
||||||
`gh api graphql -F owner=${GITHUB_OWNER} -F repo=${GITHUB_REPO} -f query='${query}'`,
|
`gh api graphql -F owner=${GITHUB_OWNER} -F repo=${GITHUB_REPO} -f query='${query}'`,
|
||||||
{ encoding: 'utf-8' },
|
{ encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] },
|
||||||
);
|
);
|
||||||
const data = JSON.parse(output).data.repository;
|
const data = JSON.parse(output).data.repository;
|
||||||
|
|
||||||
|
|||||||
@@ -2,25 +2,24 @@
|
|||||||
* @license
|
* @license
|
||||||
* Copyright 2026 Google LLC
|
* Copyright 2026 Google LLC
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
|
||||||
* @license
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { execSync } from 'node:child_process';
|
import { execSync } from 'node:child_process';
|
||||||
import { GITHUB_OWNER, GITHUB_REPO } from '../types.js';
|
import { GITHUB_OWNER, GITHUB_REPO } from '../types.js';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const query = `query { repository(owner: "${GITHUB_OWNER}", name: "${GITHUB_REPO}") { issues(states: OPEN) { totalCount } } }`;
|
const query = 'query($owner: String!, $repo: String!) { repository(owner: $owner, name: $repo) { issues(states: OPEN) { totalCount } } }';
|
||||||
const output = execSync(
|
const output = execSync(
|
||||||
`gh api graphql -f query='${query}'`,
|
`gh api graphql -F owner=${GITHUB_OWNER} -F repo=${GITHUB_REPO} -f query='${query}'`,
|
||||||
{
|
{
|
||||||
encoding: 'utf-8',
|
encoding: 'utf-8',
|
||||||
|
stdio: ['ignore', 'pipe', 'ignore'],
|
||||||
},
|
},
|
||||||
).trim();
|
).trim();
|
||||||
const parsed = JSON.parse(output);
|
const parsed = JSON.parse(output);
|
||||||
const totalCount = parsed?.data?.repository?.issues?.totalCount ?? 0;
|
const totalCount = parsed?.data?.repository?.issues?.totalCount ?? 0;
|
||||||
console.log(`open_issues,${totalCount}`);
|
process.stdout.write(`open_issues,${totalCount}\n`);
|
||||||
} catch {
|
} catch {
|
||||||
// Fallback if gh fails or no issues found
|
// Fallback if gh fails or no issues found
|
||||||
console.log('open_issues,0');
|
process.stdout.write('open_issues,0\n');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,25 +2,24 @@
|
|||||||
* @license
|
* @license
|
||||||
* Copyright 2026 Google LLC
|
* Copyright 2026 Google LLC
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
|
||||||
* @license
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { execSync } from 'node:child_process';
|
import { execSync } from 'node:child_process';
|
||||||
import { GITHUB_OWNER, GITHUB_REPO } from '../types.js';
|
import { GITHUB_OWNER, GITHUB_REPO } from '../types.js';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const query = `query { repository(owner: "${GITHUB_OWNER}", name: "${GITHUB_REPO}") { pullRequests(states: OPEN) { totalCount } } }`;
|
const query = 'query($owner: String!, $repo: String!) { repository(owner: $owner, name: $repo) { pullRequests(states: OPEN) { totalCount } } }';
|
||||||
const output = execSync(
|
const output = execSync(
|
||||||
`gh api graphql -f query='${query}'`,
|
`gh api graphql -F owner=${GITHUB_OWNER} -F repo=${GITHUB_REPO} -f query='${query}'`,
|
||||||
{
|
{
|
||||||
encoding: 'utf-8',
|
encoding: 'utf-8',
|
||||||
|
stdio: ['ignore', 'pipe', 'ignore'],
|
||||||
},
|
},
|
||||||
).trim();
|
).trim();
|
||||||
const parsed = JSON.parse(output);
|
const parsed = JSON.parse(output);
|
||||||
const totalCount = parsed?.data?.repository?.pullRequests?.totalCount ?? 0;
|
const totalCount = parsed?.data?.repository?.pullRequests?.totalCount ?? 0;
|
||||||
console.log(`open_prs,${totalCount}`);
|
process.stdout.write(`open_prs,${totalCount}\n`);
|
||||||
} catch {
|
} catch {
|
||||||
// Fallback if gh fails or no PRs found
|
// Fallback if gh fails or no PRs found
|
||||||
console.log('open_prs,0');
|
process.stdout.write('open_prs,0\n');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,9 @@
|
|||||||
* @license
|
* @license
|
||||||
* Copyright 2026 Google LLC
|
* Copyright 2026 Google LLC
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
|
||||||
* @license
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { GITHUB_OWNER, GITHUB_REPO, type MetricOutput } from '../types.js';
|
import { GITHUB_OWNER, GITHUB_REPO } from '../types.js';
|
||||||
import { execSync } from 'node:child_process';
|
import { execSync } from 'node:child_process';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -28,7 +26,7 @@ try {
|
|||||||
`;
|
`;
|
||||||
const output = execSync(
|
const output = execSync(
|
||||||
`gh api graphql -F owner=${GITHUB_OWNER} -F repo=${GITHUB_REPO} -f query='${query}'`,
|
`gh api graphql -F owner=${GITHUB_OWNER} -F repo=${GITHUB_REPO} -f query='${query}'`,
|
||||||
{ encoding: 'utf-8' },
|
{ encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] },
|
||||||
);
|
);
|
||||||
const data = JSON.parse(output).data.repository;
|
const data = JSON.parse(output).data.repository;
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,9 @@
|
|||||||
* @license
|
* @license
|
||||||
* Copyright 2026 Google LLC
|
* Copyright 2026 Google LLC
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
|
||||||
* @license
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { GITHUB_OWNER, GITHUB_REPO, type MetricOutput } from '../types.js';
|
import { GITHUB_OWNER, GITHUB_REPO } from '../types.js';
|
||||||
import { execSync } from 'node:child_process';
|
import { execSync } from 'node:child_process';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -30,7 +28,7 @@ try {
|
|||||||
`;
|
`;
|
||||||
const output = execSync(
|
const output = execSync(
|
||||||
`gh api graphql -F owner=${GITHUB_OWNER} -F repo=${GITHUB_REPO} -f query='${query}'`,
|
`gh api graphql -F owner=${GITHUB_OWNER} -F repo=${GITHUB_REPO} -f query='${query}'`,
|
||||||
{ encoding: 'utf-8' },
|
{ encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] },
|
||||||
);
|
);
|
||||||
const data = JSON.parse(output).data.repository;
|
const data = JSON.parse(output).data.repository;
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,9 @@
|
|||||||
* @license
|
* @license
|
||||||
* Copyright 2026 Google LLC
|
* Copyright 2026 Google LLC
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
|
||||||
* @license
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { GITHUB_OWNER, GITHUB_REPO, type MetricOutput } from '../types.js';
|
import { GITHUB_OWNER, GITHUB_REPO } from '../types.js';
|
||||||
import { execSync } from 'node:child_process';
|
import { execSync } from 'node:child_process';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -50,7 +48,7 @@ try {
|
|||||||
`;
|
`;
|
||||||
const output = execSync(
|
const output = execSync(
|
||||||
`gh api graphql -F owner=${GITHUB_OWNER} -F repo=${GITHUB_REPO} -f query='${query}'`,
|
`gh api graphql -F owner=${GITHUB_OWNER} -F repo=${GITHUB_REPO} -f query='${query}'`,
|
||||||
{ encoding: 'utf-8' },
|
{ encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] },
|
||||||
);
|
);
|
||||||
const data = JSON.parse(output).data.repository;
|
const data = JSON.parse(output).data.repository;
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,9 @@
|
|||||||
* @license
|
* @license
|
||||||
* Copyright 2026 Google LLC
|
* Copyright 2026 Google LLC
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
|
||||||
* @license
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { GITHUB_OWNER, GITHUB_REPO, type MetricOutput } from '../types.js';
|
import { GITHUB_OWNER, GITHUB_REPO } from '../types.js';
|
||||||
import { execSync } from 'node:child_process';
|
import { execSync } from 'node:child_process';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -31,7 +29,7 @@ try {
|
|||||||
`;
|
`;
|
||||||
const output = execSync(
|
const output = execSync(
|
||||||
`gh api graphql -F owner=${GITHUB_OWNER} -F repo=${GITHUB_REPO} -f query='${query}'`,
|
`gh api graphql -F owner=${GITHUB_OWNER} -F repo=${GITHUB_REPO} -f query='${query}'`,
|
||||||
{ encoding: 'utf-8' },
|
{ encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] },
|
||||||
);
|
);
|
||||||
const data = JSON.parse(output).data.repository;
|
const data = JSON.parse(output).data.repository;
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,5 @@
|
|||||||
* Copyright 2026 Google LLC
|
* Copyright 2026 Google LLC
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
export interface MetricOutput {
|
|
||||||
metric: string;
|
|
||||||
value: number | string;
|
|
||||||
timestamp: string;
|
|
||||||
details?: Record<string, unknown>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const GITHUB_OWNER = 'google-gemini';
|
export const GITHUB_OWNER = 'google-gemini';
|
||||||
export const GITHUB_REPO = 'gemini-cli';
|
export const GITHUB_REPO = 'gemini-cli';
|
||||||
|
|||||||
Reference in New Issue
Block a user