From af4f5395907f1f18a954edb1b665841769400683 Mon Sep 17 00:00:00 2001 From: "Molecule AI Dev Engineer A (Kimi)" Date: Sun, 14 Jun 2026 07:20:58 +0000 Subject: [PATCH 1/3] ci(workflows): #2802 propagate detect-changes debug output + fail-open All detect-changes jobs now expose a "debug" output and echo it in their downstream no-op pass steps, so run=false/chat=false/canvas=false no-ops are no longer silent: the debug line shows which path-filter branch was taken. Also adds fail-open handling so a Compare-API / labels-API / script crash does not silently skip a gate that should have run: - harness-replays.yml: declare "debug" output (already set by step). - e2e-chat.yml, e2e-staging-canvas.yml: set "debug" per branch; labels API failure now defaults to chat=true/canvas=true. - ci.yml, handlers-postgres-integration.yml, e2e-api.yml, e2e-peer-visibility.yml: declare "debug"; wrap detect-changes.py with a fail-open fallback that sets all profile outputs to true. Refs are unchanged (per #101245). Pure workflow-yaml change. Fixes #2802 Co-Authored-By: Claude --- .gitea/workflows/ci.yml | 25 ++++++++++++++++--- .gitea/workflows/e2e-api.yml | 11 +++++++- .gitea/workflows/e2e-chat.yml | 18 ++++++++++++- .gitea/workflows/e2e-peer-visibility.yml | 11 +++++++- .gitea/workflows/e2e-staging-canvas.yml | 18 ++++++++++++- .../handlers-postgres-integration.yml | 11 +++++++- .gitea/workflows/harness-replays.yml | 1 + 7 files changed, 86 insertions(+), 9 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index d846abd00..090cae958 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -80,6 +80,7 @@ jobs: canvas: ${{ steps.check.outputs.canvas }} python: ${{ steps.check.outputs.python }} scripts: ${{ steps.check.outputs.scripts }} + debug: ${{ steps.check.outputs.debug }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: @@ -95,7 +96,17 @@ jobs: --event-name "${{ github.event_name }}" \ --pr-base-sha "$PR_BASE_SHA" \ --base-ref "$PR_BASE_REF" \ - --push-before "${GITHUB_EVENT_BEFORE:-$PUSH_BEFORE}" + --push-before "${GITHUB_EVENT_BEFORE:-$PUSH_BEFORE}" || { + # Script crash / uncaught error: fail open so every CI profile + # runs rather than silently no-oping a potentially-breaking PR. + echo "platform=true" >> "$GITHUB_OUTPUT" + echo "canvas=true" >> "$GITHUB_OUTPUT" + echo "python=true" >> "$GITHUB_OUTPUT" + echo "scripts=true" >> "$GITHUB_OUTPUT" + echo "debug=detect-script-error event=${{ github.event_name }} base=${{ github.event.pull_request.base.sha || github.event.before }}" >> "$GITHUB_OUTPUT" + exit 0 + } + echo "debug=profile=ci event=${{ github.event_name }} base=${{ github.event.pull_request.base.sha || github.event.before }}" >> "$GITHUB_OUTPUT" # Platform (Go) — Go build/vet/test/lint + coverage gates. The job always # emits the required context, but expensive steps are path-scoped on every @@ -126,7 +137,9 @@ jobs: steps: - if: ${{ needs.changes.outputs.platform != 'true' }} working-directory: . - run: echo "No workspace-server/** changes — Platform (Go) gate satisfied without running Go build/test/lint." + run: | + echo "No workspace-server/** changes — Platform (Go) gate satisfied without running Go build/test/lint." + echo "::notice::detect-changes debug: ${{ needs.changes.outputs.debug }}" - if: ${{ needs.changes.outputs.platform == 'true' }} uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - if: ${{ needs.changes.outputs.platform == 'true' }} @@ -303,7 +316,9 @@ jobs: steps: - if: ${{ needs.changes.outputs.canvas != 'true' }} working-directory: . - run: echo "No canvas/** changes — Canvas (Next.js) gate satisfied without running npm build/test." + run: | + echo "No canvas/** changes — Canvas (Next.js) gate satisfied without running npm build/test." + echo "::notice::detect-changes debug: ${{ needs.changes.outputs.debug }}" - if: ${{ needs.changes.outputs.canvas == 'true' }} uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - if: ${{ needs.changes.outputs.canvas == 'true' }} @@ -351,7 +366,9 @@ jobs: continue-on-error: false steps: - if: ${{ needs.changes.outputs.scripts != 'true' }} - run: echo "No tests/e2e, scripts, or infra/scripts changes — Shellcheck gate satisfied without running script checks." + run: | + echo "No tests/e2e, scripts, or infra/scripts changes — Shellcheck gate satisfied without running script checks." + echo "::notice::detect-changes debug: ${{ needs.changes.outputs.debug }}" - if: ${{ needs.changes.outputs.scripts == 'true' }} uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - if: ${{ needs.changes.outputs.scripts == 'true' }} diff --git a/.gitea/workflows/e2e-api.yml b/.gitea/workflows/e2e-api.yml index bc0f11ea2..cfd943ae1 100644 --- a/.gitea/workflows/e2e-api.yml +++ b/.gitea/workflows/e2e-api.yml @@ -128,6 +128,7 @@ jobs: continue-on-error: false outputs: api: ${{ steps.decide.outputs.api }} + debug: ${{ steps.decide.outputs.debug }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: @@ -139,7 +140,14 @@ jobs: --event-name "${{ github.event_name }}" \ --pr-base-sha "${{ github.event.pull_request.base.sha }}" \ --base-ref "${{ github.event.pull_request.base.ref }}" \ - --push-before "${GITHUB_EVENT_BEFORE:-${{ github.event.before }}}" + --push-before "${GITHUB_EVENT_BEFORE:-${{ github.event.before }}}" || { + # Script crash / uncaught error: fail open so the E2E gate runs + # rather than silently no-oping a potentially-breaking PR. + echo "api=true" >> "$GITHUB_OUTPUT" + echo "debug=detect-script-error event=${{ github.event_name }} base=${{ github.event.pull_request.base.sha || github.event.before }}" >> "$GITHUB_OUTPUT" + exit 0 + } + echo "debug=profile=e2e-api event=${{ github.event_name }} base=${{ github.event.pull_request.base.sha || github.event.before }}" >> "$GITHUB_OUTPUT" # ONE job (no job-level `if:`) that always runs and reports under the # required-check name `E2E API Smoke Test`. Real work is gated per-step @@ -179,6 +187,7 @@ jobs: run: | echo "No workspace-server / tests/e2e / workflow changes — E2E API gate satisfied without running tests." echo "::notice::E2E API Smoke Test no-op pass (paths filter excluded this commit)." + echo "::notice::detect-changes debug: ${{ needs.detect-changes.outputs.debug }}" - if: needs.detect-changes.outputs.api == 'true' uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - if: needs.detect-changes.outputs.api == 'true' diff --git a/.gitea/workflows/e2e-chat.yml b/.gitea/workflows/e2e-chat.yml index 4e6e887d7..9fe3468aa 100644 --- a/.gitea/workflows/e2e-chat.yml +++ b/.gitea/workflows/e2e-chat.yml @@ -52,6 +52,7 @@ jobs: continue-on-error: true outputs: chat: ${{ steps.decide.outputs.chat }} + debug: ${{ steps.decide.outputs.debug }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: @@ -63,6 +64,7 @@ jobs: run: | if [ "${{ github.event_name }}" = "schedule" ] || [ "${{ github.event_name }}" = "workflow_dispatch" ]; then echo "chat=true" >> "$GITHUB_OUTPUT" + echo "debug=manual-trigger event=${{ github.event_name }}" >> "$GITHUB_OUTPUT" exit 0 fi BASE="${GITHUB_BASE_REF:-${{ github.event.before }}}" @@ -71,6 +73,7 @@ jobs: fi if [ -z "$BASE" ] || echo "$BASE" | grep -qE '^0+$'; then echo "chat=true" >> "$GITHUB_OUTPUT" + echo "debug=new-branch-fallback base=$BASE" >> "$GITHUB_OUTPUT" exit 0 fi if ! git cat-file -e "$BASE" 2>/dev/null; then @@ -78,15 +81,18 @@ jobs: fi if ! git cat-file -e "$BASE" 2>/dev/null; then echo "chat=true" >> "$GITHUB_OUTPUT" + echo "debug=base-missing-fallback base=$BASE" >> "$GITHUB_OUTPUT" exit 0 fi CHANGED=$(git diff --name-only "$BASE" HEAD) if ! echo "$CHANGED" | grep -qE '^(canvas/|workspace-server/|\.gitea/workflows/e2e-chat\.yml$)'; then echo "chat=false" >> "$GITHUB_OUTPUT" + echo "debug=no-matching-paths base=$BASE changed=$CHANGED" >> "$GITHUB_OUTPUT" exit 0 fi if [ "${{ github.event_name }}" != "pull_request" ]; then echo "chat=true" >> "$GITHUB_OUTPUT" + echo "debug=non-pr-run base=$BASE changed=$CHANGED" >> "$GITHUB_OUTPUT" exit 0 fi @@ -95,13 +101,22 @@ jobs: printf 'header = "Authorization: token %s"\n' "$GITEA_TOKEN" > "$authfile" labels=$(curl -fsS -K "$authfile" \ "${{ github.server_url }}/api/v1/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels" \ - | python3 -c 'import json,sys; print("\n".join(label.get("name","") for label in json.load(sys.stdin)))') + | python3 -c 'import json,sys; print("\n".join(label.get("name","") for label in json.load(sys.stdin)))') || { + # Labels API unavailable: fail open so the E2E gate runs rather + # than silently no-oping a potentially-breaking PR. + rm -f "$authfile" + echo "chat=true" >> "$GITHUB_OUTPUT" + echo "debug=labels-api-unavailable pr=${{ github.event.pull_request.number }} base=$BASE changed=$CHANGED" >> "$GITHUB_OUTPUT" + exit 0 + } rm -f "$authfile" if printf '%s\n' "$labels" | grep -qx "$QUEUE_LABEL"; then echo "chat=true" >> "$GITHUB_OUTPUT" + echo "debug=merge-queue-labeled base=$BASE changed=$CHANGED" >> "$GITHUB_OUTPUT" else echo "PR is not in merge-queue; skipping heavy E2E Chat for normal PR path." echo "chat=false" >> "$GITHUB_OUTPUT" + echo "debug=no-merge-queue-label base=$BASE changed=$CHANGED labels=$labels" >> "$GITHUB_OUTPUT" fi # bp-required: pending #1142 — new E2E check; add to branch protection after 3 green runs. @@ -146,6 +161,7 @@ jobs: run: | echo "No canvas / workspace-server / workflow changes — E2E Chat gate satisfied without running tests." echo "::notice::E2E Chat no-op pass (paths filter excluded this commit)." + echo "::notice::detect-changes debug: ${{ needs.detect-changes.outputs.debug }}" - if: needs.detect-changes.outputs.chat == 'true' uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 diff --git a/.gitea/workflows/e2e-peer-visibility.yml b/.gitea/workflows/e2e-peer-visibility.yml index 18e4c84c2..064e7d123 100644 --- a/.gitea/workflows/e2e-peer-visibility.yml +++ b/.gitea/workflows/e2e-peer-visibility.yml @@ -125,6 +125,7 @@ jobs: continue-on-error: false outputs: peervis: ${{ steps.filter.outputs.peervis }} + debug: ${{ steps.filter.outputs.debug }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: @@ -142,7 +143,14 @@ jobs: --event-name "${{ github.event_name }}" \ --pr-base-sha "$PR_BASE_SHA" \ --base-ref "$PR_BASE_REF" \ - --push-before "${GITHUB_EVENT_BEFORE:-$PUSH_BEFORE}" + --push-before "${GITHUB_EVENT_BEFORE:-$PUSH_BEFORE}" || { + # Script crash / uncaught error: fail open so the E2E gate runs + # rather than silently no-oping a potentially-breaking PR. + echo "peervis=true" >> "$GITHUB_OUTPUT" + echo "debug=detect-script-error event=${{ github.event_name }} base=${{ github.event.pull_request.base.sha || github.event.before }}" >> "$GITHUB_OUTPUT" + exit 0 + } + echo "debug=profile=peer-visibility event=${{ github.event_name }} base=${{ github.event.pull_request.base.sha || github.event.before }}" >> "$GITHUB_OUTPUT" # THE required-check emitter. ONE always-running job (no job-level `if:`) # named `E2E Peer Visibility`, so it posts EXACTLY ONE check run under the @@ -208,6 +216,7 @@ jobs: run: | echo "No peer-visibility-relevant changes — E2E Peer Visibility gate satisfied without running the staging E2E." echo "::notice::E2E Peer Visibility no-op pass (detect-changes profile peer-visibility excluded this push)." + echo "::notice::detect-changes debug: ${{ needs.changes.outputs.debug }}" # --- push/dispatch/cron + relevant change: the REAL staging E2E ------ - name: Verify admin token present diff --git a/.gitea/workflows/e2e-staging-canvas.yml b/.gitea/workflows/e2e-staging-canvas.yml index c5d46ddfd..83e1eba75 100644 --- a/.gitea/workflows/e2e-staging-canvas.yml +++ b/.gitea/workflows/e2e-staging-canvas.yml @@ -96,6 +96,7 @@ jobs: continue-on-error: true outputs: canvas: ${{ steps.decide.outputs.canvas }} + debug: ${{ steps.decide.outputs.debug }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: @@ -109,6 +110,7 @@ jobs: run: | if [ "${{ github.event_name }}" = "schedule" ] || [ "${{ github.event_name }}" = "workflow_dispatch" ]; then echo "canvas=true" >> "$GITHUB_OUTPUT" + echo "debug=manual-trigger event=${{ github.event_name }}" >> "$GITHUB_OUTPUT" exit 0 fi BASE="${GITHUB_BASE_REF:-${{ github.event.before }}}" @@ -117,6 +119,7 @@ jobs: fi if [ -z "$BASE" ] || echo "$BASE" | grep -qE '^0+$'; then echo "canvas=true" >> "$GITHUB_OUTPUT" + echo "debug=new-branch-fallback base=$BASE" >> "$GITHUB_OUTPUT" exit 0 fi if ! git cat-file -e "$BASE" 2>/dev/null; then @@ -124,15 +127,18 @@ jobs: fi if ! git cat-file -e "$BASE" 2>/dev/null; then echo "canvas=true" >> "$GITHUB_OUTPUT" + echo "debug=base-missing-fallback base=$BASE" >> "$GITHUB_OUTPUT" exit 0 fi CHANGED=$(git diff --name-only "$BASE" HEAD) if ! echo "$CHANGED" | grep -qE '^(canvas/|\.gitea/workflows/e2e-staging-canvas\.yml$)'; then echo "canvas=false" >> "$GITHUB_OUTPUT" + echo "debug=no-matching-paths base=$BASE changed=$CHANGED" >> "$GITHUB_OUTPUT" exit 0 fi if [ "${{ github.event_name }}" != "pull_request" ]; then echo "canvas=true" >> "$GITHUB_OUTPUT" + echo "debug=non-pr-run base=$BASE changed=$CHANGED" >> "$GITHUB_OUTPUT" exit 0 fi @@ -141,13 +147,22 @@ jobs: printf 'header = "Authorization: token %s"\n' "$GITEA_TOKEN" > "$authfile" labels=$(curl -fsS -K "$authfile" \ "${{ github.server_url }}/api/v1/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels" \ - | python3 -c 'import json,sys; print("\n".join(label.get("name","") for label in json.load(sys.stdin)))') + | python3 -c 'import json,sys; print("\n".join(label.get("name","") for label in json.load(sys.stdin)))') || { + # Labels API unavailable: fail open so the E2E gate runs rather + # than silently no-oping a potentially-breaking PR. + rm -f "$authfile" + echo "canvas=true" >> "$GITHUB_OUTPUT" + echo "debug=labels-api-unavailable pr=${{ github.event.pull_request.number }} base=$BASE changed=$CHANGED" >> "$GITHUB_OUTPUT" + exit 0 + } rm -f "$authfile" if printf '%s\n' "$labels" | grep -qx "$QUEUE_LABEL"; then echo "canvas=true" >> "$GITHUB_OUTPUT" + echo "debug=merge-queue-labeled base=$BASE changed=$CHANGED" >> "$GITHUB_OUTPUT" else echo "PR is not in merge-queue; skipping heavy E2E Staging Canvas for normal PR path." echo "canvas=false" >> "$GITHUB_OUTPUT" + echo "debug=no-merge-queue-label base=$BASE changed=$CHANGED labels=$labels" >> "$GITHUB_OUTPUT" fi # ONE job (no job-level `if:`) that always runs and reports under the @@ -184,6 +199,7 @@ jobs: run: | echo "No canvas / workflow changes — E2E Staging Canvas gate satisfied without running tests." echo "::notice::E2E Staging Canvas no-op pass (paths filter excluded this commit)." + echo "::notice::detect-changes debug: ${{ needs.detect-changes.outputs.debug }}" - if: needs.detect-changes.outputs.canvas == 'true' uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 diff --git a/.gitea/workflows/handlers-postgres-integration.yml b/.gitea/workflows/handlers-postgres-integration.yml index 93a9fd91f..810e84383 100644 --- a/.gitea/workflows/handlers-postgres-integration.yml +++ b/.gitea/workflows/handlers-postgres-integration.yml @@ -93,6 +93,7 @@ jobs: continue-on-error: false outputs: handlers: ${{ steps.filter.outputs.handlers }} + debug: ${{ steps.filter.outputs.debug }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: @@ -108,7 +109,14 @@ jobs: --event-name "${{ github.event_name }}" \ --pr-base-sha "${{ github.event.pull_request.base.sha }}" \ --base-ref "${{ github.event.pull_request.base.ref }}" \ - --push-before "${GITHUB_EVENT_BEFORE:-}" + --push-before "${GITHUB_EVENT_BEFORE:-}" || { + # Script crash / uncaught error: fail open so the integration gate + # runs rather than silently no-oping a potentially-breaking PR. + echo "handlers=true" >> "$GITHUB_OUTPUT" + echo "debug=detect-script-error event=${{ github.event_name }} base=${{ github.event.pull_request.base.sha || github.event.before }}" >> "$GITHUB_OUTPUT" + exit 0 + } + echo "debug=profile=handlers-postgres event=${{ github.event_name }} base=${{ github.event.pull_request.base.sha || github.event.before }}" >> "$GITHUB_OUTPUT" # ONE job (no job-level `if:`) that always runs and reports under the # required-check name `Handlers Postgres Integration`. Real work is gated @@ -148,6 +156,7 @@ jobs: run: | echo "No handlers/migrations changes — Handlers Postgres Integration gate satisfied without running tests." echo "::notice::Handlers Postgres Integration no-op pass (paths filter excluded this commit)." + echo "::notice::detect-changes debug: ${{ needs.detect-changes.outputs.debug }}" - if: needs.detect-changes.outputs.handlers == 'true' uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 diff --git a/.gitea/workflows/harness-replays.yml b/.gitea/workflows/harness-replays.yml index 095d8a436..bc938ea09 100644 --- a/.gitea/workflows/harness-replays.yml +++ b/.gitea/workflows/harness-replays.yml @@ -74,6 +74,7 @@ jobs: continue-on-error: true outputs: run: ${{ steps.decide.outputs.run }} + debug: ${{ steps.decide.outputs.debug }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: -- 2.52.0 From 8ca2a3930176e5b3fa7a75024b22d517366d2b66 Mon Sep 17 00:00:00 2001 From: "Molecule AI Dev Engineer A (Kimi)" Date: Sun, 14 Jun 2026 07:32:53 +0000 Subject: [PATCH 2/3] ci(workflows): #2833 flatten multiline debug outputs + avoid || in expressions CR2 RC #11614: raw newline-separated file lists in $GITHUB_OUTPUT ('debug=... changed=$CHANGED') are invalid ("expected a line with '=' or '<<'"). Fix by flattening $CHANGED/$DIFF_FILES/$labels with tr '\n' ',' before writing the debug output. Also replaces ${{ ... || ... }} expressions in debug lines with shell fallbacks (BASE_SHA) to avoid any Gitea Actions expression-parser ambiguity. Preserved the existing diff-files debug in harness-replays.yml (now flattened). Co-Authored-By: Claude --- .gitea/workflows/ci.yml | 5 +++-- .gitea/workflows/e2e-api.yml | 6 ++++-- .gitea/workflows/e2e-chat.yml | 12 +++++++----- .gitea/workflows/e2e-peer-visibility.yml | 5 +++-- .gitea/workflows/e2e-staging-canvas.yml | 12 +++++++----- .gitea/workflows/handlers-postgres-integration.yml | 6 ++++-- .gitea/workflows/harness-replays.yml | 6 ++++-- 7 files changed, 32 insertions(+), 20 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 090cae958..3cd89596a 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -91,6 +91,7 @@ jobs: PR_BASE_REF: ${{ github.event.pull_request.base.ref }} PUSH_BEFORE: ${{ github.event.before }} run: | + BASE_SHA="${PR_BASE_SHA:-$PUSH_BEFORE}" python3 .gitea/scripts/detect-changes.py \ --profile ci \ --event-name "${{ github.event_name }}" \ @@ -103,10 +104,10 @@ jobs: echo "canvas=true" >> "$GITHUB_OUTPUT" echo "python=true" >> "$GITHUB_OUTPUT" echo "scripts=true" >> "$GITHUB_OUTPUT" - echo "debug=detect-script-error event=${{ github.event_name }} base=${{ github.event.pull_request.base.sha || github.event.before }}" >> "$GITHUB_OUTPUT" + echo "debug=detect-script-error event=${{ github.event_name }} base=$BASE_SHA" >> "$GITHUB_OUTPUT" exit 0 } - echo "debug=profile=ci event=${{ github.event_name }} base=${{ github.event.pull_request.base.sha || github.event.before }}" >> "$GITHUB_OUTPUT" + echo "debug=profile=ci event=${{ github.event_name }} base=$BASE_SHA" >> "$GITHUB_OUTPUT" # Platform (Go) — Go build/vet/test/lint + coverage gates. The job always # emits the required context, but expensive steps are path-scoped on every diff --git a/.gitea/workflows/e2e-api.yml b/.gitea/workflows/e2e-api.yml index cfd943ae1..c3333f4a1 100644 --- a/.gitea/workflows/e2e-api.yml +++ b/.gitea/workflows/e2e-api.yml @@ -135,6 +135,8 @@ jobs: fetch-depth: 0 - id: decide run: | + BASE_SHA="${{ github.event.pull_request.base.sha }}" + BASE_SHA="${BASE_SHA:-${{ github.event.before }}}" python3 .gitea/scripts/detect-changes.py \ --profile e2e-api \ --event-name "${{ github.event_name }}" \ @@ -144,10 +146,10 @@ jobs: # Script crash / uncaught error: fail open so the E2E gate runs # rather than silently no-oping a potentially-breaking PR. echo "api=true" >> "$GITHUB_OUTPUT" - echo "debug=detect-script-error event=${{ github.event_name }} base=${{ github.event.pull_request.base.sha || github.event.before }}" >> "$GITHUB_OUTPUT" + echo "debug=detect-script-error event=${{ github.event_name }} base=$BASE_SHA" >> "$GITHUB_OUTPUT" exit 0 } - echo "debug=profile=e2e-api event=${{ github.event_name }} base=${{ github.event.pull_request.base.sha || github.event.before }}" >> "$GITHUB_OUTPUT" + echo "debug=profile=e2e-api event=${{ github.event_name }} base=$BASE_SHA" >> "$GITHUB_OUTPUT" # ONE job (no job-level `if:`) that always runs and reports under the # required-check name `E2E API Smoke Test`. Real work is gated per-step diff --git a/.gitea/workflows/e2e-chat.yml b/.gitea/workflows/e2e-chat.yml index 9fe3468aa..8cbc9ec63 100644 --- a/.gitea/workflows/e2e-chat.yml +++ b/.gitea/workflows/e2e-chat.yml @@ -85,14 +85,15 @@ jobs: exit 0 fi CHANGED=$(git diff --name-only "$BASE" HEAD) + CHANGED_FLAT=$(echo "$CHANGED" | tr '\n' ',') if ! echo "$CHANGED" | grep -qE '^(canvas/|workspace-server/|\.gitea/workflows/e2e-chat\.yml$)'; then echo "chat=false" >> "$GITHUB_OUTPUT" - echo "debug=no-matching-paths base=$BASE changed=$CHANGED" >> "$GITHUB_OUTPUT" + echo "debug=no-matching-paths base=$BASE changed=$CHANGED_FLAT" >> "$GITHUB_OUTPUT" exit 0 fi if [ "${{ github.event_name }}" != "pull_request" ]; then echo "chat=true" >> "$GITHUB_OUTPUT" - echo "debug=non-pr-run base=$BASE changed=$CHANGED" >> "$GITHUB_OUTPUT" + echo "debug=non-pr-run base=$BASE changed=$CHANGED_FLAT" >> "$GITHUB_OUTPUT" exit 0 fi @@ -106,17 +107,18 @@ jobs: # than silently no-oping a potentially-breaking PR. rm -f "$authfile" echo "chat=true" >> "$GITHUB_OUTPUT" - echo "debug=labels-api-unavailable pr=${{ github.event.pull_request.number }} base=$BASE changed=$CHANGED" >> "$GITHUB_OUTPUT" + echo "debug=labels-api-unavailable pr=${{ github.event.pull_request.number }} base=$BASE changed=$CHANGED_FLAT" >> "$GITHUB_OUTPUT" exit 0 } rm -f "$authfile" + LABELS_FLAT=$(echo "$labels" | tr '\n' ',') if printf '%s\n' "$labels" | grep -qx "$QUEUE_LABEL"; then echo "chat=true" >> "$GITHUB_OUTPUT" - echo "debug=merge-queue-labeled base=$BASE changed=$CHANGED" >> "$GITHUB_OUTPUT" + echo "debug=merge-queue-labeled base=$BASE changed=$CHANGED_FLAT" >> "$GITHUB_OUTPUT" else echo "PR is not in merge-queue; skipping heavy E2E Chat for normal PR path." echo "chat=false" >> "$GITHUB_OUTPUT" - echo "debug=no-merge-queue-label base=$BASE changed=$CHANGED labels=$labels" >> "$GITHUB_OUTPUT" + echo "debug=no-merge-queue-label base=$BASE changed=$CHANGED_FLAT labels=$LABELS_FLAT" >> "$GITHUB_OUTPUT" fi # bp-required: pending #1142 — new E2E check; add to branch protection after 3 green runs. diff --git a/.gitea/workflows/e2e-peer-visibility.yml b/.gitea/workflows/e2e-peer-visibility.yml index 064e7d123..4cf7664a0 100644 --- a/.gitea/workflows/e2e-peer-visibility.yml +++ b/.gitea/workflows/e2e-peer-visibility.yml @@ -138,6 +138,7 @@ jobs: PR_BASE_REF: ${{ github.event.pull_request.base.ref }} PUSH_BEFORE: ${{ github.event.before }} run: | + BASE_SHA="${PR_BASE_SHA:-$PUSH_BEFORE}" python3 .gitea/scripts/detect-changes.py \ --profile peer-visibility \ --event-name "${{ github.event_name }}" \ @@ -147,10 +148,10 @@ jobs: # Script crash / uncaught error: fail open so the E2E gate runs # rather than silently no-oping a potentially-breaking PR. echo "peervis=true" >> "$GITHUB_OUTPUT" - echo "debug=detect-script-error event=${{ github.event_name }} base=${{ github.event.pull_request.base.sha || github.event.before }}" >> "$GITHUB_OUTPUT" + echo "debug=detect-script-error event=${{ github.event_name }} base=$BASE_SHA" >> "$GITHUB_OUTPUT" exit 0 } - echo "debug=profile=peer-visibility event=${{ github.event_name }} base=${{ github.event.pull_request.base.sha || github.event.before }}" >> "$GITHUB_OUTPUT" + echo "debug=profile=peer-visibility event=${{ github.event_name }} base=$BASE_SHA" >> "$GITHUB_OUTPUT" # THE required-check emitter. ONE always-running job (no job-level `if:`) # named `E2E Peer Visibility`, so it posts EXACTLY ONE check run under the diff --git a/.gitea/workflows/e2e-staging-canvas.yml b/.gitea/workflows/e2e-staging-canvas.yml index 83e1eba75..eff410503 100644 --- a/.gitea/workflows/e2e-staging-canvas.yml +++ b/.gitea/workflows/e2e-staging-canvas.yml @@ -131,14 +131,15 @@ jobs: exit 0 fi CHANGED=$(git diff --name-only "$BASE" HEAD) + CHANGED_FLAT=$(echo "$CHANGED" | tr '\n' ',') if ! echo "$CHANGED" | grep -qE '^(canvas/|\.gitea/workflows/e2e-staging-canvas\.yml$)'; then echo "canvas=false" >> "$GITHUB_OUTPUT" - echo "debug=no-matching-paths base=$BASE changed=$CHANGED" >> "$GITHUB_OUTPUT" + echo "debug=no-matching-paths base=$BASE changed=$CHANGED_FLAT" >> "$GITHUB_OUTPUT" exit 0 fi if [ "${{ github.event_name }}" != "pull_request" ]; then echo "canvas=true" >> "$GITHUB_OUTPUT" - echo "debug=non-pr-run base=$BASE changed=$CHANGED" >> "$GITHUB_OUTPUT" + echo "debug=non-pr-run base=$BASE changed=$CHANGED_FLAT" >> "$GITHUB_OUTPUT" exit 0 fi @@ -152,17 +153,18 @@ jobs: # than silently no-oping a potentially-breaking PR. rm -f "$authfile" echo "canvas=true" >> "$GITHUB_OUTPUT" - echo "debug=labels-api-unavailable pr=${{ github.event.pull_request.number }} base=$BASE changed=$CHANGED" >> "$GITHUB_OUTPUT" + echo "debug=labels-api-unavailable pr=${{ github.event.pull_request.number }} base=$BASE changed=$CHANGED_FLAT" >> "$GITHUB_OUTPUT" exit 0 } rm -f "$authfile" + LABELS_FLAT=$(echo "$labels" | tr '\n' ',') if printf '%s\n' "$labels" | grep -qx "$QUEUE_LABEL"; then echo "canvas=true" >> "$GITHUB_OUTPUT" - echo "debug=merge-queue-labeled base=$BASE changed=$CHANGED" >> "$GITHUB_OUTPUT" + echo "debug=merge-queue-labeled base=$BASE changed=$CHANGED_FLAT" >> "$GITHUB_OUTPUT" else echo "PR is not in merge-queue; skipping heavy E2E Staging Canvas for normal PR path." echo "canvas=false" >> "$GITHUB_OUTPUT" - echo "debug=no-merge-queue-label base=$BASE changed=$CHANGED labels=$labels" >> "$GITHUB_OUTPUT" + echo "debug=no-merge-queue-label base=$BASE changed=$CHANGED_FLAT labels=$LABELS_FLAT" >> "$GITHUB_OUTPUT" fi # ONE job (no job-level `if:`) that always runs and reports under the diff --git a/.gitea/workflows/handlers-postgres-integration.yml b/.gitea/workflows/handlers-postgres-integration.yml index 810e84383..36fe3eff1 100644 --- a/.gitea/workflows/handlers-postgres-integration.yml +++ b/.gitea/workflows/handlers-postgres-integration.yml @@ -104,6 +104,8 @@ jobs: fetch-depth: 2 - id: filter run: | + BASE_SHA="${{ github.event.pull_request.base.sha }}" + BASE_SHA="${BASE_SHA:-${{ github.event.before }}}" python3 .gitea/scripts/detect-changes.py \ --profile handlers-postgres \ --event-name "${{ github.event_name }}" \ @@ -113,10 +115,10 @@ jobs: # Script crash / uncaught error: fail open so the integration gate # runs rather than silently no-oping a potentially-breaking PR. echo "handlers=true" >> "$GITHUB_OUTPUT" - echo "debug=detect-script-error event=${{ github.event_name }} base=${{ github.event.pull_request.base.sha || github.event.before }}" >> "$GITHUB_OUTPUT" + echo "debug=detect-script-error event=${{ github.event_name }} base=$BASE_SHA" >> "$GITHUB_OUTPUT" exit 0 } - echo "debug=profile=handlers-postgres event=${{ github.event_name }} base=${{ github.event.pull_request.base.sha || github.event.before }}" >> "$GITHUB_OUTPUT" + echo "debug=profile=handlers-postgres event=${{ github.event_name }} base=$BASE_SHA" >> "$GITHUB_OUTPUT" # ONE job (no job-level `if:`) that always runs and reports under the # required-check name `Handlers Postgres Integration`. Real work is gated diff --git a/.gitea/workflows/harness-replays.yml b/.gitea/workflows/harness-replays.yml index bc938ea09..728f1118c 100644 --- a/.gitea/workflows/harness-replays.yml +++ b/.gitea/workflows/harness-replays.yml @@ -121,12 +121,13 @@ jobs: | bash .gitea/scripts/push-commits-diff-files.py \ > .push-diff-files.txt 2>/dev/null || true DIFF_FILES=$(cat .push-diff-files.txt 2>/dev/null || true) + DIFF_FILES_FLAT=$(echo "$DIFF_FILES" | tr '\n' ',') if [ -n "$DIFF_FILES" ] && echo "$DIFF_FILES" | grep -qE '^workspace-server/|^canvas/|^tests/harness/|^.gitea/workflows/harness-replays\.yml$'; then echo "run=true" >> "$GITHUB_OUTPUT" else echo "run=false" >> "$GITHUB_OUTPUT" fi - echo "debug=push-files=$DIFF_FILES" >> "$GITHUB_OUTPUT" + echo "debug=push-files=$DIFF_FILES_FLAT" >> "$GITHUB_OUTPUT" exit 0 else # New branch or github.event.before unavailable — run everything. @@ -149,8 +150,9 @@ jobs: exit 0 } DIFF_FILES=$(echo "$RESP" | bash .gitea/scripts/compare-api-diff-files.py 2>/dev/null || true) + DIFF_FILES_FLAT=$(echo "$DIFF_FILES" | tr '\n' ',') - echo "debug=diff-base=$BASE diff-files=$DIFF_FILES" >> "$GITHUB_OUTPUT" + echo "debug=diff-base=$BASE diff-files=$DIFF_FILES_FLAT" >> "$GITHUB_OUTPUT" if echo "$DIFF_FILES" | grep -qE '^workspace-server/|^canvas/|^tests/harness/|^.gitea/workflows/harness-replays\.yml$'; then echo "run=true" >> "$GITHUB_OUTPUT" -- 2.52.0 From ccd384b8bd9808d27e52e056b23b6745afa793af Mon Sep 17 00:00:00 2001 From: "Molecule AI Dev Engineer A (Kimi)" Date: Sun, 14 Jun 2026 08:38:55 +0000 Subject: [PATCH 3/3] fix(e2e-api,handlers-postgres): avoid nested ${{ }} in shell ${...:-...} expansions (#2833 RC) CR2 RC #11614 flagged a Gitea Actions format error attributed to e2e-api.yml. The existing fix already flattened multiline $GITHUB_OUTPUT values; this follow-up removes the remaining nested ${{ ... }} expressions inside shell parameter expansions in e2e-api.yml and handlers-postgres-integration.yml by moving those values to step env vars and referencing them as plain shell variables. This eliminates any act-runner expression-parser ambiguity around ${{ github.event.before }} inside ${BASE_SHA:-...} / ${GITHUB_EVENT_BEFORE:-...}. Co-Authored-By: Claude --- .gitea/workflows/e2e-api.yml | 13 ++++++++----- .gitea/workflows/handlers-postgres-integration.yml | 11 +++++++---- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/.gitea/workflows/e2e-api.yml b/.gitea/workflows/e2e-api.yml index c3333f4a1..99631c0c7 100644 --- a/.gitea/workflows/e2e-api.yml +++ b/.gitea/workflows/e2e-api.yml @@ -134,15 +134,18 @@ jobs: with: fetch-depth: 0 - id: decide + env: + PR_BASE_SHA: ${{ github.event.pull_request.base.sha }} + PR_BASE_REF: ${{ github.event.pull_request.base.ref }} + PUSH_BEFORE: ${{ github.event.before }} run: | - BASE_SHA="${{ github.event.pull_request.base.sha }}" - BASE_SHA="${BASE_SHA:-${{ github.event.before }}}" + BASE_SHA="${PR_BASE_SHA:-$PUSH_BEFORE}" python3 .gitea/scripts/detect-changes.py \ --profile e2e-api \ --event-name "${{ github.event_name }}" \ - --pr-base-sha "${{ github.event.pull_request.base.sha }}" \ - --base-ref "${{ github.event.pull_request.base.ref }}" \ - --push-before "${GITHUB_EVENT_BEFORE:-${{ github.event.before }}}" || { + --pr-base-sha "$PR_BASE_SHA" \ + --base-ref "$PR_BASE_REF" \ + --push-before "${GITHUB_EVENT_BEFORE:-$PUSH_BEFORE}" || { # Script crash / uncaught error: fail open so the E2E gate runs # rather than silently no-oping a potentially-breaking PR. echo "api=true" >> "$GITHUB_OUTPUT" diff --git a/.gitea/workflows/handlers-postgres-integration.yml b/.gitea/workflows/handlers-postgres-integration.yml index 36fe3eff1..389bc005a 100644 --- a/.gitea/workflows/handlers-postgres-integration.yml +++ b/.gitea/workflows/handlers-postgres-integration.yml @@ -103,14 +103,17 @@ jobs: # not present in the shallow checkout. fetch-depth: 2 - id: filter + env: + PR_BASE_SHA: ${{ github.event.pull_request.base.sha }} + PR_BASE_REF: ${{ github.event.pull_request.base.ref }} + PUSH_BEFORE: ${{ github.event.before }} run: | - BASE_SHA="${{ github.event.pull_request.base.sha }}" - BASE_SHA="${BASE_SHA:-${{ github.event.before }}}" + BASE_SHA="${PR_BASE_SHA:-$PUSH_BEFORE}" python3 .gitea/scripts/detect-changes.py \ --profile handlers-postgres \ --event-name "${{ github.event_name }}" \ - --pr-base-sha "${{ github.event.pull_request.base.sha }}" \ - --base-ref "${{ github.event.pull_request.base.ref }}" \ + --pr-base-sha "$PR_BASE_SHA" \ + --base-ref "$PR_BASE_REF" \ --push-before "${GITHUB_EVENT_BEFORE:-}" || { # Script crash / uncaught error: fail open so the integration gate # runs rather than silently no-oping a potentially-breaking PR. -- 2.52.0