Skip to content

Commit ad1bb73

Browse files
authored
[HUD] Selector for workflow id in commit and PR pages (#6919)
When multiple workflows run on the same commit (ex memory leak check + non mem leak check), HUD tries to filter the results so that only the most recent job is shown, but sometimes I want to find older ones. An unfortunately large change because we usually query jobs for the entire commit instead of workflow by workflow I reused the commit query because it already queries the necessary fields (name id time duration etc) and didn't want to write another query that we would have to keep in sync Open to better solutions for how to get this data b/c imo this is kind of ugly TODO: also handle reruns, better error handling New <img width="1257" height="117" alt="image" src="https://github.com/user-attachments/assets/ecb1b246-573a-45fd-ba3c-0a7cd39f31ef" /> <img width="250" height="124" alt="image" src="https://github.com/user-attachments/assets/bb145f65-7c62-4bb4-adb4-aba3816cf1f5" /> Probably review #6922 first
1 parent 75ac42e commit ad1bb73

File tree

7 files changed

+113
-12
lines changed

7 files changed

+113
-12
lines changed
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
{
22
"params": {
33
"repo": "String",
4-
"sha": "String"
4+
"sha": "String",
5+
"workflowId": "Int64"
56
},
67
"tests": [
78
{
89
"repo": "pytorch/pytorch",
9-
"sha": "85df746892d9b0e87e7a5dfa78ef81a84aec6de0"
10+
"sha": "85df746892d9b0e87e7a5dfa78ef81a84aec6de0",
11+
"workflow_id": 0
1012
}
1113
]
1214
}

torchci/clickhouse_queries/commit_jobs_query/query.sql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ WITH job AS (
4646
AND workflow.event != 'workflow_run' -- Filter out workflow_run-triggered jobs, which have nothing to do with the SHA
4747
AND workflow.event != 'repository_dispatch' -- Filter out repository_dispatch-triggered jobs, which have nothing to do with the SHA
4848
AND workflow.id in (select id from materialized_views.workflow_run_by_head_sha where head_sha = {sha: String})
49+
AND (
50+
{workflowId: Int64} = 0
51+
OR workflow.id = {workflowId: Int64} -- If a specific workflow ID is provided, filter by it
52+
)
4953
AND job.id in (select id from materialized_views.workflow_job_by_head_sha where head_sha = {sha: String})
5054
AND workflow.repository. 'full_name' = {repo: String } -- UNION
5155
AND workflow.name != 'Upload test stats while running' -- Continuously running cron job that cancels itself to avoid running concurrently
@@ -84,6 +88,10 @@ WITH job AS (
8488
workflow.event != 'workflow_run' -- Filter out workflow_run-triggered jobs, which have nothing to do with the SHA
8589
AND workflow.event != 'repository_dispatch' -- Filter out repository_dispatch-triggered jobs, which have nothing to do with the SHA
8690
AND workflow.id in (select id from materialized_views.workflow_run_by_head_sha where head_sha = {sha: String})
91+
AND (
92+
{workflowId: Int64} = 0
93+
OR workflow.id = {workflowId: Int64} -- If a specific workflow ID is provided, filter by it
94+
)
8795
AND workflow.repository.full_name = {repo: String }
8896
AND workflow.name != 'Upload test stats while running' -- Continuously running cron job that cancels itself to avoid running concurrently
8997
)

torchci/components/commit/CommitInfo.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export function CommitInfo({
4343
return <div>Loading...</div>;
4444
}
4545

46-
const { commit, jobs } = commitData;
46+
const { commit, jobs, workflowIdsByName } = commitData;
4747

4848
return (
4949
<div>
@@ -53,6 +53,7 @@ export function CommitInfo({
5353
repoName={repoName}
5454
commit={commit}
5555
jobs={jobs}
56+
workflowIdsByName={workflowIdsByName}
5657
isCommitPage={isCommitPage}
5758
unstableIssues={unstableIssuesData ?? []}
5859
/>

torchci/components/commit/CommitStatus.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,12 @@ function getBoxOrdering(jobs: JobData[], wideBoxes: Set<string>) {
5454
function WorkflowsContainer({
5555
jobs,
5656
unstableIssues,
57+
workflowIdsByName,
5758
repoFullName,
5859
}: {
5960
jobs: JobData[];
6061
unstableIssues: IssueData[];
62+
workflowIdsByName: Record<string, number[]>;
6163
repoFullName: string;
6264
}) {
6365
useScrollTo();
@@ -81,6 +83,7 @@ function WorkflowsContainer({
8183
repoFullName={repoFullName}
8284
key={workflowName}
8385
workflowName={workflowName}
86+
allWorkflowIds={workflowIdsByName[workflowName] || []}
8487
jobs={jobs}
8588
unstableIssues={unstableIssues}
8689
wide={wideBoxes.has(workflowName)}
@@ -106,13 +109,15 @@ export default function CommitStatus({
106109
repoName,
107110
commit,
108111
jobs,
112+
workflowIdsByName,
109113
isCommitPage,
110114
unstableIssues,
111115
}: {
112116
repoOwner: string;
113117
repoName: string;
114118
commit: CommitData;
115119
jobs: JobData[];
120+
workflowIdsByName: Record<string, number[]>;
116121
isCommitPage: boolean;
117122
unstableIssues: IssueData[];
118123
}) {
@@ -174,6 +179,7 @@ export default function CommitStatus({
174179
/>
175180
<WorkflowsContainer
176181
jobs={jobs}
182+
workflowIdsByName={workflowIdsByName}
177183
unstableIssues={unstableIssues}
178184
repoFullName={`${repoOwner}/${repoName}`}
179185
/>

torchci/components/commit/WorkflowBox.tsx

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Button, Stack, styled, Typography } from "@mui/material";
1+
import { Button, Stack, styled, Tooltip, Typography } from "@mui/material";
22
import { TestInfo } from "components/additionalTestInfo/TestInfo";
33
import styles from "components/commit/commit.module.css";
44
import LogViewer, { SearchLogViewer } from "components/common/log/LogViewer";
@@ -14,7 +14,10 @@ import {
1414
ListUtilizationMetadataInfoAPIResponse,
1515
UtilizationMetadataInfo,
1616
} from "lib/utilization/types";
17+
import { CommitApiResponse } from "pages/api/[repoOwner]/[repoName]/commit/[sha]";
1718
import React, { useEffect, useState } from "react";
19+
import { FaInfoCircle } from "react-icons/fa";
20+
import useSWR from "swr";
1821
import useSWRImmutable from "swr/immutable";
1922

2023
function sortJobsByConclusion(jobA: JobData, jobB: JobData): number {
@@ -140,16 +143,32 @@ export default function WorkflowBox({
140143
unstableIssues,
141144
wide,
142145
setWide,
146+
allWorkflowIds,
143147
repoFullName,
144148
}: {
145149
workflowName: string;
146150
jobs: JobData[];
147151
unstableIssues: IssueData[];
148152
wide: boolean;
153+
allWorkflowIds: number[];
149154
setWide: any;
150155
repoFullName: string;
151156
}) {
152-
const workflowId = jobs[0].workflowId;
157+
const [selectedWorkflowId, setSelectedWorkflowId] = useState<
158+
string | undefined
159+
>(undefined);
160+
const workflowId = selectedWorkflowId || jobs[0].workflowId;
161+
162+
const { data: jobsFromSelectedWorkflowId } = useSWR<CommitApiResponse>(
163+
selectedWorkflowId &&
164+
`/api/${repoFullName}/commit/${jobs[0].sha}?workflowId=${selectedWorkflowId}`,
165+
fetcher
166+
);
167+
168+
if (selectedWorkflowId) {
169+
jobs = jobsFromSelectedWorkflowId?.jobs || [];
170+
}
171+
153172
const isFailed = jobs.some(isFailedJob) !== false;
154173
const workflowClass = isFailed
155174
? styles.workflowBoxFail
@@ -163,6 +182,7 @@ export default function WorkflowBox({
163182
const { artifacts, error } = useArtifacts(jobs.map((job) => job.workflowId));
164183
const [artifactsToShow, setArtifactsToShow] = useState(new Set<string>());
165184
const groupedArtifacts = groupArtifacts(jobs, artifacts);
185+
166186
const [searchString, setSearchString] = useState("");
167187
const [searchRes, setSearchRes] = useState<{
168188
results: Map<string, LogSearchResult>;
@@ -196,7 +216,28 @@ export default function WorkflowBox({
196216
Job Status
197217
</Typography>
198218
</Stack>
199-
<Stack direction="column" spacing={1} paddingTop={6}>
219+
<Stack direction="column" spacing={1}>
220+
<Stack direction="row" spacing={1}>
221+
<select
222+
value={selectedWorkflowId}
223+
onChange={(e) => {
224+
setSelectedWorkflowId(e.target.value);
225+
}}
226+
style={{ width: "100%" }}
227+
>
228+
<option value={""}>Select Workflow ID</option>
229+
{allWorkflowIds.sort().map((id) => (
230+
<option key={id} value={id}>
231+
{id}
232+
</option>
233+
))}
234+
</select>
235+
<Tooltip title="By default the box will show what it believes to be the latest jobs. Use this to select a specific workflow ID if it's wrong.">
236+
<Typography>
237+
<FaInfoCircle />
238+
</Typography>
239+
</Tooltip>
240+
</Stack>
200241
<div>
201242
{repoFullName == "pytorch/pytorch" && (
202243
<button

torchci/lib/fetchCommit.ts

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
import _ from "lodash";
22
import { Octokit } from "octokit";
3+
import { CommitApiResponse } from "pages/api/[repoOwner]/[repoName]/commit/[sha]";
34
import { queryClickhouseSaved } from "./clickhouse";
45
import { commitDataFromResponse, getOctokit } from "./github";
56
import { removeCancelledJobAfterRetry } from "./jobUtils";
6-
import { CommitData, JobData } from "./types";
7+
import { JobData } from "./types";
78

8-
async function fetchDatabaseInfo(owner: string, repo: string, sha: string) {
9+
async function fetchDatabaseInfo(
10+
owner: string,
11+
repo: string,
12+
sha: string,
13+
workflowId: number
14+
) {
915
const response = await queryClickhouseSaved("commit_jobs_query", {
1016
repo: `${owner}/${repo}`,
1117
sha: sha,
18+
workflowId,
1219
});
1320

1421
for (const row of response) {
@@ -20,21 +27,53 @@ async function fetchDatabaseInfo(owner: string, repo: string, sha: string) {
2027
return response;
2128
}
2229

30+
/**
31+
* Get a mapping of workflow names to all workflow IDs from a list of job data.
32+
* @param jobs
33+
* @returns
34+
*/
35+
function getWorkflowIdsByName(jobs: JobData[]): Record<string, number[]> {
36+
return _(jobs)
37+
.groupBy((job) => job.workflowName)
38+
.map((jobs, key) => {
39+
const workflowIds = _(jobs)
40+
.map((job) => job.workflowId)
41+
.filter((id) => id !== null && id !== undefined)
42+
.uniq()
43+
.value();
44+
return [key, workflowIds];
45+
})
46+
.fromPairs()
47+
.value();
48+
}
49+
50+
/**
51+
*
52+
* @param owner
53+
* @param repo
54+
* @param sha
55+
* @param workflowId Optional workflow ID to filter jobs by. If not provided,
56+
* all jobs for the commit will be returned.
57+
* @returns
58+
*/
2359
export default async function fetchCommit(
2460
owner: string,
2561
repo: string,
26-
sha: string
27-
): Promise<{ commit: CommitData; jobs: JobData[] }> {
62+
sha: string,
63+
workflowId: number = 0
64+
): Promise<CommitApiResponse> {
2865
// Retrieve commit data from GitHub
2966
const octokit = await getOctokit(owner, repo);
3067

3168
const [githubResponse, response] = await Promise.all([
3269
octokit.rest.repos.getCommit({ owner, repo, ref: sha }),
33-
await fetchDatabaseInfo(owner, repo, sha),
70+
await fetchDatabaseInfo(owner, repo, sha, workflowId),
3471
]);
3572

3673
let jobs = response as any[];
3774

75+
const workflowIdsByName = getWorkflowIdsByName(jobs);
76+
3877
// Subtle: we need to unique jobs by name, taking the most recent job. This is
3978
// because there might be many periodic jobs with the same name, and we want
4079
// to avoid noising up the display with many duplicate jobs.
@@ -65,6 +104,7 @@ export default async function fetchCommit(
65104
return {
66105
commit: commitDataFromResponse(githubResponse.data),
67106
jobs: _.concat(filteredJobs, badWorkflows),
107+
workflowIdsByName,
68108
};
69109
}
70110

torchci/pages/api/[repoOwner]/[repoName]/commit/[sha].ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,22 @@ import type { NextApiRequest, NextApiResponse } from "next";
55
export type CommitApiResponse = {
66
commit: CommitData;
77
jobs: JobData[];
8+
workflowIdsByName: Record<string, number[]>;
89
};
910

1011
export default async function handler(
1112
req: NextApiRequest,
1213
res: NextApiResponse<CommitApiResponse>
1314
) {
15+
const workflowId = parseInt(req.query.workflowId as string, 10) || 0;
1416
res
1517
.status(200)
1618
.json(
1719
await fetchCommit(
1820
req.query.repoOwner as string,
1921
req.query.repoName as string,
20-
req.query.sha as string
22+
req.query.sha as string,
23+
workflowId
2124
)
2225
);
2326
}

0 commit comments

Comments
 (0)