Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions torchci/clickhouse_queries/autorevert_commits/params.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"params": {
"repo": "String",
"shas": "Array(String)"
},
"tests": [
{
"repo": "pytorch/pytorch",
"shas": ["abc123", "def456"]
}
]
}
11 changes: 11 additions & 0 deletions torchci/clickhouse_queries/autorevert_commits/query.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
SELECT
commit_sha,
groupArray(workflows) as all_workflows,
groupArray(source_signal_keys) as all_source_signal_keys
FROM misc.autorevert_events_v2
WHERE repo = {repo: String}
AND action = 'revert'
AND dry_run = 0
AND failed = 0
AND commit_sha IN {shas: Array(String)}
GROUP BY commit_sha
12 changes: 12 additions & 0 deletions torchci/clickhouse_queries/autorevert_details/params.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"params": {
"repo": "String",
"sha": "String"
},
"tests": [
{
"repo": "pytorch/pytorch",
"sha": "321e60abc123"
}
]
}
13 changes: 13 additions & 0 deletions torchci/clickhouse_queries/autorevert_details/query.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
SELECT
commit_sha,
workflows,
source_signal_keys,
ts
FROM misc.autorevert_events_v2
WHERE
repo = {repo: String}
AND commit_sha = {sha: String}
AND action = 'revert'
AND dry_run = 0
AND failed = 0
ORDER BY ts DESC
52 changes: 52 additions & 0 deletions torchci/components/commit/AutorevertBanner.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
.autorevertBanner {
background-color: var(--sev-banner-bg);
border: 2px solid var(--autoreverted-signal-border);
border-radius: 8px;
padding: 16px;
margin: 16px 0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.bannerHeader {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 12px;
font-size: 1.1em;
}

.warningIcon {
font-size: 1.2em;
}

.bannerContent {
color: var(--text-color);
}

.bannerContent p {
margin: 8px 0;
}

.workflowList {
margin: 12px 0;
padding-left: 24px;
}

.workflowList li {
margin: 6px 0;
list-style-type: disc;
}

.workflowList a {
color: var(--link-color);
text-decoration: none;
}

.workflowList a:hover {
text-decoration: underline;
}

.investigateMessage {
font-style: italic;
margin-top: 12px;
}
133 changes: 133 additions & 0 deletions torchci/components/commit/AutorevertBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import useSWR from "swr";
import styles from "./AutorevertBanner.module.css";

interface AutorevertDetails {
commit_sha: string;
workflows: string[];
source_signal_keys: string[];
job_ids: number[];
job_base_names: string[];
wf_run_ids: number[];
created_at: string;
}

interface SignalInfo {
workflow_name: string;
signals: Array<{
key: string;
job_url?: string;
hud_url?: string;
}>;
}

export function AutorevertBanner({
repoOwner,
repoName,
sha,
}: {
repoOwner: string;
repoName: string;
sha: string;
}) {
const { data: autorevertData, error } = useSWR<AutorevertDetails>(
`/api/autorevert/${repoOwner}/${repoName}/${sha}`,
async (url) => {
try {
const response = await fetch(url);

if (response.status === 404) {
// No autorevert data for this commit
return null;
}

if (!response.ok) {
const errorText = await response.text();
throw new Error(`Failed to fetch: ${response.status} - ${errorText}`);
}

const data = await response.json();
return data;
} catch (e) {
// Silently fail - no autorevert data
return null;
}
},
{
refreshInterval: 0, // Don't refresh autorevert data
}
);

// Don't show banner if no data or error
if (!autorevertData) {
return null;
}

// Handle case where arrays might be undefined or have different structure
const workflows = autorevertData.workflows || [];
const sourceSignalKeys = autorevertData.source_signal_keys || [];
const jobIds = autorevertData.job_ids || [];
const wfRunIds = autorevertData.wf_run_ids || [];
const jobBaseNames = autorevertData.job_base_names || [];

// If no workflows data, don't show the banner
if (!workflows.length) {
return null;
}

// Group signals by workflow
const signalsByWorkflow = new Map<string, SignalInfo>();

workflows.forEach((workflow, idx) => {
if (!signalsByWorkflow.has(workflow)) {
signalsByWorkflow.set(workflow, {
workflow_name: workflow,
signals: [],
});
}

const signalKey = sourceSignalKeys[idx] || "";

const signal = {
key: signalKey,
// Since we don't have job IDs in the table, we can't create direct job links
job_url: undefined,
// Try to create a HUD URL using the signal key as a filter
hud_url: signalKey
? `/hud/${repoOwner}/${repoName}/main?nameFilter=${encodeURIComponent(
signalKey
)}`
: undefined,
};

signalsByWorkflow.get(workflow)!.signals.push(signal);
});

return (
<div className={styles.autorevertBanner}>
<div className={styles.bannerHeader}>
<span className={styles.warningIcon}>⚠️</span>
<strong>This commit was automatically reverted</strong>
</div>
<div className={styles.bannerContent}>
<p>This PR is attributed to have caused regression in:</p>
<ul className={styles.workflowList}>
{Array.from(signalsByWorkflow.values()).map((workflowInfo) => (
<li key={workflowInfo.workflow_name}>
<strong>{workflowInfo.workflow_name}:</strong>{" "}
{workflowInfo.signals.map((signal, idx) => (
<span key={idx}>
{idx > 0 && ", "}
<span>{signal.key}</span>
</span>
))}
</li>
))}
</ul>
<p className={styles.investigateMessage}>
You can add the label <code>autorevert: disable</code> to disable
autorevert for a specific PR.
</p>
</div>
</div>
);
}
9 changes: 9 additions & 0 deletions torchci/components/hud.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,15 @@
background-color: var(--forced-merge-failure-bg);
}

.autoreverted {
background-color: var(--autoreverted-bg);
}

.autorevertSignal {
background-color: var(--autoreverted-signal-bg);
border: 2px solid var(--autoreverted-signal-border);
}

.selectedRow {
background-color: var(--selected-row-bg);
font-weight: bold;
Expand Down
26 changes: 26 additions & 0 deletions torchci/lib/fetchHud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,28 @@ export default async function fetchHud(
)
);

// Check if any of these commits were autoreverted
const autorevertedCommits = await queryClickhouseSaved("autorevert_commits", {
repo: `${params.repoOwner}/${params.repoName}`,
shas: shas,
});

// Create a map from sha to autorevert data
const autorevertDataBySha = new Map<
string,
{ workflows: string[]; signals: string[] }
>();
autorevertedCommits.forEach((r) => {
// Flatten the nested arrays
const allWorkflows = r.all_workflows.flat();
const allSignals = r.all_source_signal_keys.flat();

autorevertDataBySha.set(r.commit_sha, {
workflows: allWorkflows,
signals: allSignals,
});
});

const commitsBySha = _.keyBy(commits, "sha");

if (params.filter_reruns) {
Expand Down Expand Up @@ -151,11 +173,15 @@ export default async function fetchHud(
}
}

const autorevertData = autorevertDataBySha.get(commit.sha);
const row = {
...commit,
jobs: jobs,
isForcedMerge: forcedMergeShas.has(commit.sha),
isForcedMergeWithFailures: forcedMergeWithFailuresShas.has(commit.sha),
isAutoreverted: autorevertData !== undefined,
autorevertWorkflows: autorevertData?.workflows,
autorevertSignals: autorevertData?.signals,
};
shaGrid.push(row);
});
Expand Down
3 changes: 3 additions & 0 deletions torchci/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ export interface Highlight {
interface RowDataBase extends CommitData {
isForcedMerge: boolean | false;
isForcedMergeWithFailures: boolean | false;
isAutoreverted: boolean | false;
autorevertWorkflows?: string[];
autorevertSignals?: string[];
}

export interface RowData extends RowDataBase {
Expand Down
2 changes: 1 addition & 1 deletion torchci/lib/utilization/fetchUtilization.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ describe("Test flattenTS to flatten timestamp", () => {

// assert log
expect(logSpy).toHaveBeenCalledWith(
`Warning: Error parsing JSON:SyntaxError: Expected property name or '}' in JSON at position 1 for data string '{{}dsad}'`
`Warning: Error parsing JSON:SyntaxError: Expected property name or '}' in JSON at position 1 (line 1 column 2) for data string '{{}dsad}'`
Copy link
Contributor

@izaitsevfb izaitsevfb Oct 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

accidental change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no tried to fix, but the message is not correct, I can remove the change

);
});
});
Expand Down
20 changes: 14 additions & 6 deletions torchci/pages/[repoOwner]/[repoName]/commit/[sha].tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AutorevertBanner } from "components/commit/AutorevertBanner";
import { CommitInfo } from "components/commit/CommitInfo";
import { useSetTitle } from "components/layout/DynamicTitle";
import { useRouter } from "next/router";
Expand All @@ -24,12 +25,19 @@ export default function Page() {
{fancyName} Commit: <code>{sha}</code>
</h1>
{sha !== undefined && (
<CommitInfo
repoOwner={repoOwner as string}
repoName={repoName as string}
sha={sha as string}
isCommitPage={true}
/>
<>
<AutorevertBanner
repoOwner={repoOwner as string}
repoName={repoName as string}
sha={sha as string}
/>
<CommitInfo
repoOwner={repoOwner as string}
repoName={repoName as string}
sha={sha as string}
isCommitPage={true}
/>
</>
)}
</div>
);
Expand Down
Loading
Loading