diff --git a/tools/gemini-cli-bot/metrics/scripts/latency.ts b/tools/gemini-cli-bot/metrics/scripts/latency.ts index 7dd5dcd1f6..83b1a85c07 100644 --- a/tools/gemini-cli-bot/metrics/scripts/latency.ts +++ b/tools/gemini-cli-bot/metrics/scripts/latency.ts @@ -2,26 +2,30 @@ * @license * Copyright 2026 Google LLC * SPDX-License-Identifier: Apache-2.0 - * - * @license */ import { GITHUB_OWNER, GITHUB_REPO } from '../types.js'; import { execSync } from 'node:child_process'; try { + const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) + .toISOString() + .split('T')[0]; + const query = ` - query($owner: String!, $repo: String!) { - repository(owner: $owner, name: $repo) { - pullRequests(last: 100, states: MERGED) { - nodes { + query($owner: String!, $repo: String!, $prQ: String!, $issueQ: String!) { + pullRequests: search(query: $prQ, type: ISSUE, first: 100) { + nodes { + ... on PullRequest { authorAssociation createdAt mergedAt } } - issues(last: 100, states: CLOSED) { - nodes { + } + issues: search(query: $issueQ, type: ISSUE, first: 100) { + nodes { + ... on Issue { authorAssociation createdAt closedAt @@ -30,18 +34,18 @@ try { } } `; + + const prQ = `repo:${GITHUB_OWNER}/${GITHUB_REPO} is:pr is:merged merged:>${sevenDaysAgo}`; + const issueQ = `repo:${GITHUB_OWNER}/${GITHUB_REPO} is:issue is:closed closed:>${sevenDaysAgo}`; + 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 prQ='${prQ}' -F issueQ='${issueQ}' -f query='${query}'`, { encoding: 'utf-8' }, ); - const data = JSON.parse(output).data.repository; + const data = JSON.parse(output).data; const prs = data.pullRequests.nodes.map( - (p: { - authorAssociation: string; - mergedAt: string; - createdAt: string; - }) => ({ + (p: { authorAssociation: string; mergedAt: string; createdAt: string }) => ({ association: p.authorAssociation, latencyHours: (new Date(p.mergedAt).getTime() - new Date(p.createdAt).getTime()) / @@ -49,11 +53,7 @@ try { }), ); const issues = data.issues.nodes.map( - (i: { - authorAssociation: string; - closedAt: string; - createdAt: string; - }) => ({ + (i: { authorAssociation: string; closedAt: string; createdAt: string }) => ({ association: i.authorAssociation, latencyHours: (new Date(i.closedAt).getTime() - new Date(i.createdAt).getTime()) / diff --git a/tools/gemini-cli-bot/metrics/scripts/throughput.ts b/tools/gemini-cli-bot/metrics/scripts/throughput.ts index 3806dd407a..086ca1489a 100644 --- a/tools/gemini-cli-bot/metrics/scripts/throughput.ts +++ b/tools/gemini-cli-bot/metrics/scripts/throughput.ts @@ -2,25 +2,29 @@ * @license * Copyright 2026 Google LLC * SPDX-License-Identifier: Apache-2.0 - * - * @license */ import { GITHUB_OWNER, GITHUB_REPO } from '../types.js'; import { execSync } from 'node:child_process'; try { + const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) + .toISOString() + .split('T')[0]; + const query = ` - query($owner: String!, $repo: String!) { - repository(owner: $owner, name: $repo) { - pullRequests(last: 100, states: MERGED) { - nodes { + query($owner: String!, $repo: String!, $prQ: String!, $issueQ: String!) { + pullRequests: search(query: $prQ, type: ISSUE, first: 100) { + nodes { + ... on PullRequest { authorAssociation mergedAt } } - issues(last: 100, states: CLOSED) { - nodes { + } + issues: search(query: $issueQ, type: ISSUE, first: 100) { + nodes { + ... on Issue { authorAssociation closedAt } @@ -28,25 +32,29 @@ try { } } `; + + const prQ = `repo:${GITHUB_OWNER}/${GITHUB_REPO} is:pr is:merged merged:>${sevenDaysAgo}`; + const issueQ = `repo:${GITHUB_OWNER}/${GITHUB_REPO} is:issue is:closed closed:>${sevenDaysAgo}`; + 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 prQ='${prQ}' -F issueQ='${issueQ}' -f query='${query}'`, { encoding: 'utf-8' }, ); - const data = JSON.parse(output).data.repository; + const data = JSON.parse(output).data; - const prs = data.pullRequests.nodes - .map((p: { authorAssociation: string; mergedAt: string }) => ({ + const prs = data.pullRequests.nodes.map( + (p: { authorAssociation: string; mergedAt: string }) => ({ association: p.authorAssociation, date: new Date(p.mergedAt).getTime(), - })) - .sort((a: { date: number }, b: { date: number }) => a.date - b.date); + }), + ); - const issues = data.issues.nodes - .map((i: { authorAssociation: string; closedAt: string }) => ({ + const issues = data.issues.nodes.map( + (i: { authorAssociation: string; closedAt: string }) => ({ association: i.authorAssociation, date: new Date(i.closedAt).getTime(), - })) - .sort((a: { date: number }, b: { date: number }) => a.date - b.date); + }), + ); const isMaintainer = (assoc: string) => ['MEMBER', 'OWNER', 'COLLABORATOR'].includes(assoc); @@ -54,11 +62,7 @@ try { const calculateThroughput = ( items: { association: string; date: number }[], ) => { - if (items.length < 2) return 0; - const first = items[0].date; - const last = items[items.length - 1].date; - const days = (last - first) / (1000 * 60 * 60 * 24); - return days > 0 ? items.length / days : items.length; // items per day + return items.length / 7; // items per day over 7 day window }; const prOverall = calculateThroughput(prs); diff --git a/tools/gemini-cli-bot/metrics/scripts/user_touches.ts b/tools/gemini-cli-bot/metrics/scripts/user_touches.ts index 5ccffa94fc..1745f7794a 100644 --- a/tools/gemini-cli-bot/metrics/scripts/user_touches.ts +++ b/tools/gemini-cli-bot/metrics/scripts/user_touches.ts @@ -2,26 +2,30 @@ * @license * Copyright 2026 Google LLC * SPDX-License-Identifier: Apache-2.0 - * - * @license */ import { GITHUB_OWNER, GITHUB_REPO } from '../types.js'; import { execSync } from 'node:child_process'; try { + const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) + .toISOString() + .split('T')[0]; + const query = ` - query($owner: String!, $repo: String!) { - repository(owner: $owner, name: $repo) { - pullRequests(last: 100, states: MERGED) { - nodes { + query($owner: String!, $repo: String!, $prQ: String!, $issueQ: String!) { + pullRequests: search(query: $prQ, type: ISSUE, first: 100) { + nodes { + ... on PullRequest { authorAssociation comments { totalCount } reviews { totalCount } } } - issues(last: 100, states: CLOSED) { - nodes { + } + issues: search(query: $issueQ, type: ISSUE, first: 100) { + nodes { + ... on Issue { authorAssociation comments { totalCount } } @@ -29,11 +33,15 @@ try { } } `; + + const prQ = `repo:${GITHUB_OWNER}/${GITHUB_REPO} is:pr is:merged merged:>${sevenDaysAgo}`; + const issueQ = `repo:${GITHUB_OWNER}/${GITHUB_REPO} is:issue is:closed closed:>${sevenDaysAgo}`; + 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 prQ='${prQ}' -F issueQ='${issueQ}' -f query='${query}'`, { encoding: 'utf-8' }, ); - const data = JSON.parse(output).data.repository; + const data = JSON.parse(output).data; const prs = data.pullRequests.nodes; const issues = data.issues.nodes;