Skip to content

Commit 543c82c

Browse files
authored
[HUD] add filter for non-viable strict jobs (#7349)
1. adds a filter to hide non-viable strict jobs: <img width="240" height="34" alt="image" src="https://github.com/user-attachments/assets/8e8a6eef-bc7c-492b-9de2-c28412b439a8" /> 2. in grouped view makes the border more obvious / adds tooltip info: <img width="826" height="173" alt="image" src="https://github.com/user-attachments/assets/c5e9d07a-1651-4f0d-86f5-4430b5a6c3f8" /> <img width="303" height="108" alt="image" src="https://github.com/user-attachments/assets/c4b8ba14-461e-42d2-a970-3489c7e2cc5d" /> 3. syncs the viable-strict logic with [the source](https://github.com/pytorch/pytorch/blob/main/.github/workflows/update-viablestrict.yml#L26) (per the comment in the original implementation) Note: we really need to centralize the config for viable/strict, but that's out of the scope of this PR.
1 parent a102908 commit 543c82c

File tree

6 files changed

+207
-61
lines changed

6 files changed

+207
-61
lines changed

torchci/components/job/GroupJobConclusion.tsx

Lines changed: 55 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import {
33
isGroupAutorevertSignal,
44
isJobAutorevertSignal,
55
} from "lib/autorevertUtils";
6-
import { getGroupConclusionChar } from "lib/JobClassifierUtil";
6+
import {
7+
getGroupConclusionChar,
8+
isJobViableStrictBlocking,
9+
} from "lib/JobClassifierUtil";
710
import {
811
isCancellationSuccessJob,
912
isFailedJob,
@@ -43,44 +46,6 @@ export enum GroupedJobStatus {
4346
Pending = "pending",
4447
}
4548

46-
type RepoViableStrictBlockingJobsMap = {
47-
[key: string]: RegExp[];
48-
};
49-
50-
// TODO: Move this to a config file
51-
const VIABLE_STRICT_BLOCKING_JOBS: RepoViableStrictBlockingJobsMap = {
52-
// Source of truth for these jobs is in https://github.com/pytorch/pytorch/blob/main/.github/workflows/update-viablestrict.yml#L26
53-
"pytorch/pytorch": [
54-
/trunk/i,
55-
/pull/i,
56-
/lint/i,
57-
/linux-binary-libtorch-release /i,
58-
/linux-binary-manywheel /i,
59-
/linux-aarch64/i,
60-
],
61-
};
62-
63-
function isJobViableStrictBlocking(
64-
jobName: string | undefined,
65-
repoOwner: string,
66-
repoName: string
67-
): boolean {
68-
if (!jobName) {
69-
return false;
70-
}
71-
72-
const repo = `${repoOwner}/${repoName}`;
73-
let viablestrict_blocking_jobs_patterns =
74-
VIABLE_STRICT_BLOCKING_JOBS[repo] ?? [];
75-
76-
for (const regex of viablestrict_blocking_jobs_patterns) {
77-
if (jobName.match(regex)) {
78-
return true;
79-
}
80-
}
81-
return false;
82-
}
83-
8449
// React component to render either a group conclusion character or monsterized icons for failures
8550
function GroupConclusionContent({
8651
conclusion,
@@ -276,6 +241,8 @@ export default function HudGroupedCell({
276241
failedPreviousRunJobs={failedPreviousRunJobs}
277242
sha={sha}
278243
rowData={rowData}
244+
repoOwner={repoOwner}
245+
repoName={repoName}
279246
/>
280247
}
281248
>
@@ -326,6 +293,8 @@ function GroupTooltip({
326293
failedPreviousRunJobs,
327294
sha,
328295
rowData,
296+
repoOwner,
297+
repoName,
329298
}: {
330299
conclusion: GroupedJobStatus;
331300
groupName: string;
@@ -335,6 +304,8 @@ function GroupTooltip({
335304
failedPreviousRunJobs: JobData[];
336305
sha?: string;
337306
rowData?: RowData;
307+
repoOwner?: string;
308+
repoName?: string;
338309
}) {
339310
const [monsterFailures] = useContext(MonsterFailuresContext);
340311

@@ -382,6 +353,10 @@ function GroupTooltip({
382353
const isAutorevert = rowData
383354
? isJobAutorevertSignal(job, rowData)
384355
: false;
356+
const isViableStrictBlocking =
357+
repoOwner &&
358+
repoName &&
359+
isJobViableStrictBlocking(job.name, repoOwner, repoName);
385360
return (
386361
<div
387362
key={jobIndex}
@@ -400,6 +375,12 @@ function GroupTooltip({
400375
{job.name}
401376
{isAutorevert && " ⚠️ (triggered autorevert)"}
402377
</a>
378+
{isViableStrictBlocking && (
379+
<span style={{ color: "orange", fontWeight: "bold" }}>
380+
{" "}
381+
[viable/strict blocking]
382+
</span>
383+
)}
403384
</div>
404385
);
405386
})}
@@ -416,6 +397,8 @@ function GroupTooltip({
416397
jobs={erroredJobs}
417398
message={"The following jobs errored out:"}
418399
rowData={rowData}
400+
repoOwner={repoOwner}
401+
repoName={repoName}
419402
/>
420403
);
421404
} else if (conclusion === GroupedJobStatus.Queued) {
@@ -426,6 +409,8 @@ function GroupTooltip({
426409
jobs={queuedJobs}
427410
message={"The following jobs are still in queue:"}
428411
rowData={rowData}
412+
repoOwner={repoOwner}
413+
repoName={repoName}
429414
/>
430415
);
431416
} else if (conclusion === GroupedJobStatus.Pending) {
@@ -436,6 +421,8 @@ function GroupTooltip({
436421
jobs={pendingJobs}
437422
message={"The following jobs are still pending:"}
438423
rowData={rowData}
424+
repoOwner={repoOwner}
425+
repoName={repoName}
439426
/>
440427
);
441428
} else if (conclusion === GroupedJobStatus.Flaky) {
@@ -446,6 +433,8 @@ function GroupTooltip({
446433
jobs={failedPreviousRunJobs}
447434
message={"The following jobs were flaky:"}
448435
rowData={rowData}
436+
repoOwner={repoOwner}
437+
repoName={repoName}
449438
/>
450439
);
451440
} else if (conclusion === GroupedJobStatus.AllNull) {
@@ -473,12 +462,16 @@ function ToolTip({
473462
message,
474463
jobs,
475464
rowData,
465+
repoOwner,
466+
repoName,
476467
}: {
477468
conclusion: string;
478469
groupName: string;
479470
message: string;
480471
jobs: JobData[];
481472
rowData?: RowData;
473+
repoOwner?: string;
474+
repoName?: string;
482475
}) {
483476
return (
484477
<div>
@@ -488,19 +481,30 @@ function ToolTip({
488481
const isAutorevert = rowData
489482
? isJobAutorevertSignal(job, rowData)
490483
: false;
484+
const isViableStrictBlocking =
485+
repoOwner &&
486+
repoName &&
487+
isJobViableStrictBlocking(job.name, repoOwner, repoName);
491488
return (
492-
<a
493-
key={ind}
494-
href={job.htmlUrl}
495-
target="_blank"
496-
rel="noreferrer"
497-
className={
498-
isAutorevert ? styles.autorevert_tooltip_anchor : undefined
499-
}
500-
>
501-
{job.name}
502-
{isAutorevert && " ⚠️ (triggered autorevert)"}
503-
</a>
489+
<div key={ind}>
490+
<a
491+
href={job.htmlUrl}
492+
target="_blank"
493+
rel="noreferrer"
494+
className={
495+
isAutorevert ? styles.autorevert_tooltip_anchor : undefined
496+
}
497+
>
498+
{job.name}
499+
{isAutorevert && " ⚠️ (triggered autorevert)"}
500+
</a>
501+
{isViableStrictBlocking && (
502+
<span style={{ color: "orange", fontWeight: "bold" }}>
503+
{" "}
504+
[viable/strict blocking]
505+
</span>
506+
)}
507+
</div>
504508
);
505509
})}
506510
</div>

torchci/components/job/JobConclusion.module.css

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,9 @@
103103
}
104104

105105
.viablestrict_blocking {
106-
border-left: 1px solid var(--color-failure);
107-
border-right: 1px solid var(--color-failure);
106+
border: 2px solid var(--color-failure);
107+
background-color: rgba(255, 0, 0, 0.1);
108+
border-radius: 2px;
108109
}
109110

110111
.autorevert_tooltip_anchor {

torchci/components/job/JobTooltip.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { isJobViableStrictBlocking } from "lib/JobClassifierUtil";
12
import { JobData } from "../../lib/types";
23
import { SingleWorkflowDispatcher } from "../commit/WorkflowDispatcher";
34
import LogViewer from "../common/log/LogViewer";
@@ -7,10 +8,14 @@ export default function JobTooltip({
78
job,
89
sha,
910
isAutorevertSignal,
11+
repoOwner,
12+
repoName,
1013
}: {
1114
job: JobData;
1215
sha?: string;
1316
isAutorevertSignal?: boolean;
17+
repoOwner?: string;
18+
repoName?: string;
1419
}) {
1520
// For nonexistent jobs, just show something basic:
1621
if (!job.hasOwnProperty("id")) {
@@ -24,6 +29,11 @@ export default function JobTooltip({
2429
);
2530
}
2631

32+
const isViableStrictBlocking =
33+
repoOwner &&
34+
repoName &&
35+
isJobViableStrictBlocking(job.name, repoOwner, repoName);
36+
2737
return (
2838
<div>
2939
{`[${job.conclusion}] ${job.name}`}
@@ -32,6 +42,11 @@ export default function JobTooltip({
3242
Failure in this job has triggered autorevert.
3343
</div>
3444
)}
45+
{isViableStrictBlocking && (
46+
<div style={{ color: "orange", fontWeight: "bold" }}>
47+
This job is viable/strict blocking.
48+
</div>
49+
)}
3550
<div>
3651
<em>click to pin this tooltip, double-click for job page</em>
3752
</div>

torchci/lib/JobClassifierUtil.ts

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,41 @@ import { GroupedJobStatus, JobStatus } from "components/job/GroupJobConclusion";
22
import { getOpenUnstableIssues } from "lib/jobUtils";
33
import { IssueData, RowData } from "./types";
44

5+
type RepoViableStrictBlockingJobsMap = {
6+
[key: string]: RegExp[];
7+
};
8+
9+
// Source of truth for these jobs is in https://github.com/pytorch/pytorch/blob/main/.github/workflows/update-viablestrict.yml#L26
10+
export const VIABLE_STRICT_BLOCKING_JOBS: RepoViableStrictBlockingJobsMap = {
11+
"pytorch/pytorch": [/pull/i, /trunk/i, /lint/i, /linux-aarch64/i],
12+
};
13+
14+
export function isJobViableStrictBlocking(
15+
jobName: string | undefined,
16+
repoOwner: string,
17+
repoName: string
18+
): boolean {
19+
if (!jobName) {
20+
return false;
21+
}
22+
23+
// Exclude memory leak and rerun disabled tests jobs
24+
if (jobName.match(/, mem_leak/) || jobName.match(/, rerun_/)) {
25+
return false;
26+
}
27+
28+
const repo = `${repoOwner}/${repoName}`;
29+
const viablestrictBlockingJobsPatterns =
30+
VIABLE_STRICT_BLOCKING_JOBS[repo] ?? [];
31+
32+
for (const regex of viablestrictBlockingJobsPatterns) {
33+
if (jobName.match(regex)) {
34+
return true;
35+
}
36+
}
37+
return false;
38+
}
39+
540
const GROUP_MEMORY_LEAK_CHECK = "Memory Leak Check";
641
const GROUP_RERUN_DISABLED_TESTS = "Rerun Disabled Tests";
742
const GROUP_UNSTABLE = "Unstable";
@@ -355,14 +390,19 @@ export function getGroupingData(
355390
shaGrid: RowData[],
356391
jobNames: Set<string>,
357392
showUnstableGroup: boolean,
358-
unstableIssues?: IssueData[]
393+
unstableIssues?: IssueData[],
394+
repoOwner?: string,
395+
repoName?: string
359396
) {
360397
// Construct Job Groupping Mapping
361398
const groupNameMapping = new Map<string, Array<string>>(); // group -> [job names]
362399

363400
// Track which jobs have failures
364401
const jobsWithFailures = new Set<string>();
365402

403+
// Track which jobs are viable/strict blocking
404+
const jobsViableStrictBlocking = new Set<string>();
405+
366406
// First pass: check failures for each job across all commits
367407
for (const name of jobNames) {
368408
// Check if this job has failures in any commit
@@ -374,6 +414,15 @@ export function getGroupingData(
374414
if (hasFailure) {
375415
jobsWithFailures.add(name);
376416
}
417+
418+
// Check if this job is viable/strict blocking
419+
if (
420+
repoOwner &&
421+
repoName &&
422+
isJobViableStrictBlocking(name, repoOwner, repoName)
423+
) {
424+
jobsViableStrictBlocking.add(name);
425+
}
377426
}
378427

379428
// Second pass: group jobs
@@ -392,11 +441,21 @@ export function getGroupingData(
392441
}
393442
}
394443

444+
// Calculate which groups have viable/strict blocking jobs
445+
const groupsViableStrictBlocking = new Set<string>();
446+
for (const [groupName, jobs] of groupNameMapping.entries()) {
447+
if (jobs.some((jobName) => jobsViableStrictBlocking.has(jobName))) {
448+
groupsViableStrictBlocking.add(groupName);
449+
}
450+
}
451+
395452
return {
396453
shaGrid,
397454
groupNameMapping,
398455
jobsWithFailures,
399456
groupsWithFailures,
457+
jobsViableStrictBlocking,
458+
groupsViableStrictBlocking,
400459
};
401460
}
402461

torchci/lib/useGroupingPreference.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,15 @@ export function useHideGreenColumnsPreference(): [
7777
);
7878
return [state, setState];
7979
}
80+
81+
export function useHideNonViableStrictPreference(): [
82+
boolean,
83+
(_hideNonViableStrictValue: boolean) => void
84+
] {
85+
const [state, setState] = usePreference(
86+
"hideNonViableStrict",
87+
/*override*/ undefined,
88+
/*default*/ false
89+
);
90+
return [state, setState];
91+
}

0 commit comments

Comments
 (0)