From 24bb449a799f44258decb78426a7626c6d5ca352 Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Sun, 21 Jun 2026 13:15:54 +0200 Subject: [PATCH] fix(ci): detect-changes.sh always emits outputs (kill the cascade) detect-changes used set -e; an aborting git/grep killed it before writing GITHUB_OUTPUT -> the job outputs mapping evaluated to %!t(string=) and failed detect-changes + every job that needs it. Drop set -e, treat base/diff failure as rebuild-all, add an EXIT trap that emits rebuild-all + exit 0 on any early exit. Verified locally: empty/unreachable BASE_SHA + real diff all emit a full 11-key set. Co-Authored-By: Claude Opus 4.7 --- scripts/detect-changes.sh | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/scripts/detect-changes.sh b/scripts/detect-changes.sh index d7f0d626..3e170093 100755 --- a/scripts/detect-changes.sh +++ b/scripts/detect-changes.sh @@ -2,16 +2,23 @@ # Emit per-service + aggregate change flags for the CI / build workflows. # # Reads: -# BASE_SHA — diff base. Empty / unreachable → emit everything as true. +# BASE_SHA — diff base. Empty / unreachable / diff-failure → emit everything as true. # HEAD_SHA — diff target. Defaults to HEAD. # # Writes key=value lines to $GITHUB_OUTPUT (defaults to /dev/stdout for local runs). # +# ROBUSTNESS CONTRACT: this script must ALWAYS emit a full set of outputs. A +# missing/empty output makes the job's `outputs:` mapping evaluate to a Go format +# error (`%!t(string=)`) which fails detect-changes AND every job that `needs` it +# (cascade). So we do NOT use `set -e` (an aborting git/grep must not kill the +# script before it emits), we treat any base/diff failure as "rebuild all", and an +# EXIT trap emits rebuild-all + forces exit 0 if we ever exit early/unexpectedly. +# # Keys emitted: # admin, backend, sdk, portal, tts, crawler, dsms_gateway, dsms_node # any_python, any_node, any -set -euo pipefail +set -uo pipefail BASE_SHA="${BASE_SHA:-}" HEAD_SHA="${HEAD_SHA:-HEAD}" @@ -31,17 +38,27 @@ emit_all_true() { done } +# Safety net: never let the job end with undefined outputs. If we exit before +# DONE=1 (any error / early termination), emit rebuild-all and exit 0 so the +# step still succeeds — rebuild-all is the safe over-approximation. +DONE=0 +trap '[ "$DONE" = 1 ] || emit_all_true "safety-net (unexpected exit)"; exit 0' EXIT + if [ -z "$BASE_SHA" ]; then emit_all_true "no BASE_SHA provided" - exit 0 + DONE=1; exit 0 fi if ! git rev-parse --verify "${BASE_SHA}^{commit}" >/dev/null 2>&1; then emit_all_true "BASE_SHA ${BASE_SHA} unreachable" - exit 0 + DONE=1; exit 0 +fi + +if ! changed=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA" 2>/dev/null); then + emit_all_true "git diff against ${BASE_SHA} failed" + DONE=1; exit 0 fi -changed=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA" || true) echo "Changed files since ${BASE_SHA}:" echo "${changed:-(none)}" echo "---" @@ -91,3 +108,5 @@ else emit any false echo " any: false" fi + +DONE=1