sessions: add rerun action for failed CI checks in PR checks view (#306347)

Add a per-check rerun button for failed CI checks in the changes view.
Uses the GitHub Actions rerun-failed-jobs API, extracting the workflow
run ID from the check's detailsUrl.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Sandeep Somavarapu
2026-03-30 16:26:58 +02:00
committed by GitHub
parent 64e73b0366
commit af50a47c13
3 changed files with 52 additions and 1 deletions

View File

@@ -66,6 +66,7 @@ class CICheckListRenderer implements IListRenderer<ICICheckListItem, ICICheckTem
constructor(
private readonly _labels: ResourceLabels,
private readonly _openerService: IOpenerService,
private readonly _getModel: () => GitHubPullRequestCIModel | undefined,
) { }
renderTemplate(container: HTMLElement): ICICheckTemplateData {
@@ -104,6 +105,18 @@ class CICheckListRenderer implements IListRenderer<ICICheckListItem, ICICheckTem
const actions: Action[] = [];
if (element.group === CICheckGroup.Failed) {
actions.push(templateData.elementDisposables.add(new Action(
'ci.rerunCheck',
localize('ci.rerunCheck', "Rerun Check"),
ThemeIcon.asClassName(Codicon.debugRerun),
true,
async () => {
await this._getModel()?.rerunFailedCheck(element.check);
},
)));
}
if (element.check.detailsUrl) {
actions.push(templateData.elementDisposables.add(new Action(
'ci.openOnGitHub',
@@ -210,7 +223,7 @@ export class CIStatusWidget extends Disposable {
'CIStatusWidget',
listContainer,
new CICheckListDelegate(),
[new CICheckListRenderer(this._labels, this._openerService)],
[new CICheckListRenderer(this._labels, this._openerService, () => this._model)],
{
multipleSelectionSupport: false,
openOnSingleClick: false,

View File

@@ -68,6 +68,17 @@ export class GitHubPRCIFetcher {
return data.check_runs.map(mapCheckRun);
}
/**
* Rerun failed jobs in a GitHub Actions workflow run.
*/
async rerunFailedJobs(owner: string, repo: string, runId: number): Promise<void> {
await this._apiClient.request<void>(
'POST',
`/repos/${e(owner)}/${e(repo)}/actions/runs/${runId}/rerun-failed-jobs`,
'githubApi.rerunFailedJobs'
);
}
/**
* Get logs/output for a specific check run.
*

View File

@@ -60,6 +60,20 @@ export class GitHubPullRequestCIModel extends Disposable {
return this._fetcher.getCheckRunAnnotations(this.owner, this.repo, checkRunId);
}
/**
* Rerun a failed check by extracting the workflow run ID from its details URL
* and calling the GitHub Actions rerun-failed-jobs API, then refresh status.
*/
async rerunFailedCheck(check: IGitHubCICheck): Promise<void> {
const runId = parseWorkflowRunId(check.detailsUrl);
if (!runId) {
this._logService.warn(`${LOG_PREFIX} Cannot rerun check "${check.name}": no workflow run ID found in detailsUrl`);
return;
}
await this._fetcher.rerunFailedJobs(this.owner, this.repo, runId);
await this.refresh();
}
/**
* Start periodic polling. Each cycle refreshes CI check data.
*/
@@ -88,3 +102,16 @@ export class GitHubPullRequestCIModel extends Disposable {
super.dispose();
}
}
/**
* Extract the GitHub Actions workflow run ID from a check run's details URL.
* URLs follow the pattern: `https://github.com/{owner}/{repo}/actions/runs/{run_id}/job/{job_id}`
*/
function parseWorkflowRunId(detailsUrl: string | undefined): number | undefined {
if (!detailsUrl) {
return undefined;
}
const match = /\/actions\/runs\/(?<runId>\d+)/.exec(detailsUrl);
const runId = match?.groups?.runId;
return runId ? parseInt(runId, 10) : undefined;
}