diff --git a/services/apps/packages_worker/src/enricher/computeMedians.ts b/services/apps/packages_worker/src/enricher/computeMedians.ts index a5b7cdd7e5..a9d0a41fb9 100644 --- a/services/apps/packages_worker/src/enricher/computeMedians.ts +++ b/services/apps/packages_worker/src/enricher/computeMedians.ts @@ -26,6 +26,7 @@ export interface ResponseNode { export interface PrNode { createdAt: string mergedAt: string | null + closedAt: string | null author: { login: string } | null comments: { nodes: ResponseNode[] } reviews: { nodes: ResponseNode[] } diff --git a/services/apps/packages_worker/src/enricher/fetchActivitySnapshot.ts b/services/apps/packages_worker/src/enricher/fetchActivitySnapshot.ts index 90605d5005..7de9ba9982 100644 --- a/services/apps/packages_worker/src/enricher/fetchActivitySnapshot.ts +++ b/services/apps/packages_worker/src/enricher/fetchActivitySnapshot.ts @@ -70,16 +70,11 @@ async function graphqlRequest( return json.data as T } -function toDateString(date: Date): string { - return date.toISOString().slice(0, 10) -} - function buildDateWindows(): { since12m: Date + since6m: Date since12mIso: string since6mIso: string - since12mDate: string - since6mDate: string } { const now = new Date() @@ -91,10 +86,9 @@ function buildDateWindows(): { return { since12m, + since6m, since12mIso: since12m.toISOString(), since6mIso: since6m.toISOString(), - since12mDate: toDateString(since12m), - since6mDate: toDateString(since6m), } } @@ -104,10 +98,6 @@ interface RateLimit { resetAt: string } -interface IssueCount { - issueCount: number -} - interface CommitHistory { totalCount: number } @@ -127,14 +117,8 @@ interface SummaryQueryResult { commitsPrior6m?: CommitHistory } } + openIssues: { totalCount: number } } - prsOpened: IssueCount - prsMerged: IssueCount - prsClosedUnmerged: IssueCount - issuesOpened: IssueCount - issuesClosed: IssueCount - issuesOpened6m: IssueCount - issuesOpenNow: IssueCount } interface PrPageQueryResult { @@ -158,14 +142,7 @@ interface IssuePageQueryResult { } const SUMMARY_QUERY = ` - query( - $owner: String!, $name: String!, - $since12m: GitTimestamp!, $since6m: GitTimestamp!, - $searchPrsOpened: String!, $searchPrsMerged: String!, - $searchPrsClosedUnmerged: String!, - $searchIssuesOpened: String!, $searchIssuesClosed: String!, - $searchIssuesOpened6m: String!, $searchIssuesOpenNow: String! - ) { + query($owner: String!, $name: String!, $since12m: GitTimestamp!, $since6m: GitTimestamp!) { rateLimit { cost remaining resetAt } repository(owner: $owner, name: $name) { defaultBranchRef { @@ -177,14 +154,8 @@ const SUMMARY_QUERY = ` } } } + openIssues: issues(states: OPEN) { totalCount } } - prsOpened: search(query: $searchPrsOpened, type: ISSUE) { issueCount } - prsMerged: search(query: $searchPrsMerged, type: ISSUE) { issueCount } - prsClosedUnmerged: search(query: $searchPrsClosedUnmerged, type: ISSUE) { issueCount } - issuesOpened: search(query: $searchIssuesOpened, type: ISSUE) { issueCount } - issuesClosed: search(query: $searchIssuesClosed, type: ISSUE) { issueCount } - issuesOpened6m: search(query: $searchIssuesOpened6m, type: ISSUE) { issueCount } - issuesOpenNow: search(query: $searchIssuesOpenNow, type: ISSUE) { issueCount } } ` @@ -197,6 +168,7 @@ const PR_PAGE_QUERY = ` nodes { createdAt mergedAt + closedAt author { login } comments(first: ${RESPONSES_PER_NODE}) { nodes { createdAt author { login } } } reviews(first: ${RESPONSES_PER_NODE}) { nodes { createdAt author { login } } } @@ -325,24 +297,11 @@ export async function fetchActivitySnapshot( token: string, timeoutMs: number, ): Promise { - const { since12m, since12mIso, since6mIso, since12mDate, since6mDate } = buildDateWindows() - const repoFilter = `repo:${owner}/${name}` + const { since12m, since6m, since12mIso, since6mIso } = buildDateWindows() const summaryData = await graphqlRequest( SUMMARY_QUERY, - { - owner, - name, - since12m: since12mIso, - since6m: since6mIso, - searchPrsOpened: `${repoFilter} is:pr created:>=${since12mDate}`, - searchPrsMerged: `${repoFilter} is:pr is:merged created:>=${since12mDate}`, - searchPrsClosedUnmerged: `${repoFilter} is:pr is:unmerged is:closed created:>=${since12mDate}`, - searchIssuesOpened: `${repoFilter} is:issue created:>=${since12mDate}`, - searchIssuesClosed: `${repoFilter} is:issue is:closed created:>=${since12mDate}`, - searchIssuesOpened6m: `${repoFilter} is:issue created:>=${since6mDate}`, - searchIssuesOpenNow: `${repoFilter} is:issue is:open`, - }, + { owner, name, since12m: since12mIso, since6m: since6mIso }, token, timeoutMs, ) @@ -378,6 +337,9 @@ export async function fetchActivitySnapshot( const prMedians = computePrMedians(prResult.nodes) const issueMedians = computeIssueMedians(issueResult.nodes) + const issuesOpenedLast6m = issueResult.nodes.filter( + (n) => new Date(n.createdAt) >= since6m, + ).length // Lowest remaining across all requests — remaining only decreases within a reset window const lastRateLimit = [summaryData.rateLimit, prResult.rateLimit, issueResult.rateLimit] @@ -391,17 +353,16 @@ export async function fetchActivitySnapshot( commitsLast12m, commitsLast6m, commitsPrior6m, - prsOpenedLast12m: summaryData.prsOpened.issueCount, - prsMergedLast12m: summaryData.prsMerged.issueCount, - prsClosedUnmerged12m: summaryData.prsClosedUnmerged.issueCount, + prsOpenedLast12m: prResult.nodes.length, + prsMergedLast12m: prResult.nodes.filter((n) => n.mergedAt).length, + prsClosedUnmerged12m: prResult.nodes.filter((n) => n.closedAt && !n.mergedAt).length, prMedianTimeToMergeHours: prMedians.medianTimeToMergeHours, prMedianTimeToFirstResponseHours: prMedians.medianTimeToFirstResponseHours, - issuesOpenedLast12m: summaryData.issuesOpened.issueCount, - issuesClosedLast12m: summaryData.issuesClosed.issueCount, - issuesOpenedLast6m: summaryData.issuesOpened6m.issueCount, - issuesOpenedPrior6m: - summaryData.issuesOpened.issueCount - summaryData.issuesOpened6m.issueCount, - issuesOpenNow: summaryData.issuesOpenNow.issueCount, + issuesOpenedLast12m: issueResult.nodes.length, + issuesClosedLast12m: issueResult.nodes.filter((n) => n.closedAt).length, + issuesOpenedLast6m, + issuesOpenedPrior6m: issueResult.nodes.length - issuesOpenedLast6m, + issuesOpenNow: summaryData.repository.openIssues.totalCount, issueMedianTimeToCloseHours: issueMedians.medianTimeToCloseHours, issueMedianTimeToFirstResponseHours: issueMedians.medianTimeToFirstResponseHours, httpRequestCount: totalHttpRequests,