From c0a6957a640b39740a58c6bba7e57adbfb2fb6f7 Mon Sep 17 00:00:00 2001 From: Alec Sammon Date: Thu, 10 Sep 2026 11:51:46 +0100 Subject: [PATCH] fix: sync-status reports success for runs that did not succeed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sync-status only fails on a `failure` or `cancelled` conclusion, so every other non-success outcome sets the step to success: - `timed_out` — the triggered run hit a job timeout - `startup_failure` — the run never started (e.g. an invalid workflow file) - `stale` — the run was discarded before it could report - a `null` conclusion, which is what the API returns whenever the run has not completed, including after `wait-for-completion` gives up at its own timeout The last case is the easiest to hit: the wait loop exits on its timeout, warns, and then sync-status reads a `null` conclusion and passes the step — so a job that waited the full timeout reports success while the run it triggered is still going. Fail on the conclusions that unambiguously mean the run did not succeed, and on any run that has not reached `completed`. `neutral`, `skipped` and `action_required` keep passing as before, so runs that deliberately end without doing work are unaffected. Co-Authored-By: Claude Opus 5 (1M context) --- dist/index.js | 12 +++++++++++- src/main.ts | 18 ++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/dist/index.js b/dist/index.js index 7f07ab0..05eb659 100644 --- a/dist/index.js +++ b/dist/index.js @@ -40787,6 +40787,7 @@ var version = "1.3.2"; // src/main.ts var API_VERSION = "2026-03-10"; +var FAILED_CONCLUSIONS = /* @__PURE__ */ new Set(["failure", "cancelled", "timed_out", "startup_failure", "stale"]); async function run() { info(`\u{1F3C3} Workflow Dispatch Action v${version}`); try { @@ -40878,11 +40879,20 @@ Note: The workflow is still running but we have stopped waiting. You can check t headers: { "x-github-api-version": API_VERSION } } ); + const runStatusNow = finalRunData.status; const conclusion = finalRunData.conclusion; - if (conclusion === "failure") { + if (runStatusNow !== "completed") { + setFailed( + `Workflow run did not complete (status: ${runStatusNow}). Check the run details here: ${dispatchResp.data.html_url}` + ); + } else if (conclusion === "failure") { setFailed(`Workflow run failed. Check the run details here: ${dispatchResp.data.html_url}`); } else if (conclusion === "cancelled") { setFailed(`Workflow run was cancelled. Check the run details here: ${dispatchResp.data.html_url}`); + } else if (FAILED_CONCLUSIONS.has(String(conclusion))) { + setFailed( + `Workflow run concluded '${conclusion}'. Check the run details here: ${dispatchResp.data.html_url}` + ); } else { info(`\u{1F389} Workflow conclusion: ${conclusion}`); } diff --git a/src/main.ts b/src/main.ts index afe4f50..c55815a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -14,6 +14,10 @@ import * as PackageJSON from '../package.json' const API_VERSION = '2026-03-10' // Latest API version as of March 2026, update as needed +// Conclusions that unambiguously mean the run did not succeed. `neutral`, +// `skipped` and `action_required` are left passing, as before. +const FAILED_CONCLUSIONS = new Set(['failure', 'cancelled', 'timed_out', 'startup_failure', 'stale']) + type Workflow = { id: number name: string @@ -154,13 +158,23 @@ async function run(): Promise { headers: { 'x-github-api-version': API_VERSION }, }, ) + const runStatusNow = finalRunData.status const conclusion = finalRunData.conclusion - // Set this action to failed if the triggered workflow run failed or was cancelled - if (conclusion === 'failure') { + // An incomplete run has no conclusion yet, so passing here would report + // success for work still in flight (e.g. after the wait above timed out). + if (runStatusNow !== 'completed') { + core.setFailed( + `Workflow run did not complete (status: ${runStatusNow}). Check the run details here: ${dispatchResp.data.html_url}`, + ) + } else if (conclusion === 'failure') { core.setFailed(`Workflow run failed. Check the run details here: ${dispatchResp.data.html_url}`) } else if (conclusion === 'cancelled') { core.setFailed(`Workflow run was cancelled. Check the run details here: ${dispatchResp.data.html_url}`) + } else if (FAILED_CONCLUSIONS.has(String(conclusion))) { + core.setFailed( + `Workflow run concluded '${conclusion}'. Check the run details here: ${dispatchResp.data.html_url}`, + ) } else { core.info(`🎉 Workflow conclusion: ${conclusion}`) }