Skip to content

Commit 82b39f0

Browse files
authored
Merge pull request #7152 from JSONbored/fix/reconcile-stale-run-detection
fix(release): correct two real bugs found in the just-shipped reconciliation job
2 parents 3c91cf3 + b36ea6c commit 82b39f0

1 file changed

Lines changed: 59 additions & 7 deletions

File tree

.github/workflows/mcp-release-please.yml

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ jobs:
223223
needs: release-please
224224
if: ${{ !cancelled() }}
225225
environment: release
226-
timeout-minutes: 25
226+
timeout-minutes: 35
227227
permissions:
228228
contents: read
229229
actions: write
@@ -258,10 +258,34 @@ jobs:
258258
259259
dispatch_and_wait() {
260260
local workflow="$1"
261-
gh workflow run "$workflow" --repo "$GITHUB_REPOSITORY"
262-
sleep 8
263-
local run_id
264-
run_id="$(gh run list --repo "$GITHUB_REPOSITORY" --workflow "$workflow" --limit 1 --json databaseId --jq '.[0].databaseId')"
261+
# `gh run list --limit 1` right after dispatch is NOT reliable for finding the run just
262+
# created: it can return a DIFFERENT, already-completed run from before this dispatch if
263+
# the new one hasn't been indexed by the API yet (confirmed live: the first version of
264+
# this job grabbed a stale prior run, reported its old "success", and silently never
265+
# published the new version at all -- packages/loopover-engine committed 3.2.3 while npm
266+
# still had 3.2.2, undetected until a human happened to check the actual log output).
267+
#
268+
# `gh workflow run`'s own stdout prints the created run's URL ("if available" per its
269+
# --help) -- parse the run ID directly from THAT first, since it's the actual identity of
270+
# what was just dispatched, not a guess. Falls back to polling for a run created after
271+
# `before_ts` only on the rare case the URL wasn't returned.
272+
local before_ts run_id dispatch_output
273+
before_ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
274+
dispatch_output="$(gh workflow run "$workflow" --repo "$GITHUB_REPOSITORY" 2>&1)"
275+
echo "$dispatch_output"
276+
run_id="$(printf '%s' "$dispatch_output" | grep -oE '/runs/[0-9]+' | grep -oE '[0-9]+' | tail -1 || true)"
277+
if [ -z "$run_id" ]; then
278+
echo "No run URL in dispatch output; polling for a run created after $before_ts..."
279+
for _attempt in $(seq 1 30); do
280+
sleep 5
281+
run_id="$(gh run list --repo "$GITHUB_REPOSITORY" --workflow "$workflow" --limit 5 --json databaseId,createdAt --jq "[.[] | select(.createdAt > \"$before_ts\")] | sort_by(.createdAt) | .[0].databaseId // empty")"
282+
if [ -n "$run_id" ]; then break; fi
283+
done
284+
fi
285+
if [ -z "$run_id" ]; then
286+
echo "::error::Could not identify the run just dispatched for $workflow."
287+
return 1
288+
fi
265289
echo "Dispatched $workflow as run $run_id, waiting for it to complete..."
266290
while [ "$(gh run view "$run_id" --repo "$GITHUB_REPOSITORY" --json status --jq '.status')" != "completed" ]; do
267291
sleep 15
@@ -272,17 +296,45 @@ jobs:
272296
[ "$conclusion" = "success" ]
273297
}
274298
299+
# mcp/miner's own isolated pack/smoke-test step resolves @loopover/engine from the real npm
300+
# registry in a bare temp dir (no local workspace symlink there), so it can transiently fail
301+
# with ETARGET for a few tens of seconds after engine's OWN publish reports success --
302+
# npm's registry is CDN-backed, not instantly consistent across every edge node (confirmed
303+
# live: dispatching mcp and miner back-to-back right after engine's publish job completed,
304+
# mcp's smoke-test hit an edge node that had already propagated and succeeded; miner's hit
305+
# one that hadn't and failed with the exact same ETARGET this whole job exists to fix,
306+
# despite both being dispatched at the same moment against the same already-published
307+
# engine version). Retrying after a short wait resolves it once propagation catches up --
308+
# this is NOT the same failure class as a genuine test regression, which would fail
309+
# identically on every retry.
310+
dispatch_and_wait_with_retry() {
311+
local workflow="$1" max_attempts=3 attempt=1
312+
while [ "$attempt" -le "$max_attempts" ]; do
313+
if dispatch_and_wait "$workflow"; then
314+
return 0
315+
fi
316+
echo "$workflow attempt $attempt/$max_attempts did not succeed -- likely npm registry propagation lag for a dependency that just published; retrying shortly."
317+
sleep 30
318+
attempt=$((attempt + 1))
319+
done
320+
return 1
321+
}
322+
275323
engine_ok=true
276324
if needs_publish packages/loopover-engine @loopover/engine; then
277325
dispatch_and_wait publish-engine.yml || engine_ok=false
326+
if [ "$engine_ok" = "true" ]; then
327+
echo "Waiting for npm registry propagation before publishing engine's dependents..."
328+
sleep 30
329+
fi
278330
fi
279331
280332
if [ "$engine_ok" = "true" ]; then
281333
if needs_publish packages/loopover-mcp @loopover/mcp; then
282-
dispatch_and_wait publish-mcp.yml || echo "::warning::publish-mcp.yml did not succeed -- left for manual follow-up."
334+
dispatch_and_wait_with_retry publish-mcp.yml || echo "::warning::publish-mcp.yml did not succeed after retries -- left for manual follow-up."
283335
fi
284336
if needs_publish packages/loopover-miner @loopover/miner; then
285-
dispatch_and_wait publish-miner.yml || echo "::warning::publish-miner.yml did not succeed -- left for manual follow-up."
337+
dispatch_and_wait_with_retry publish-miner.yml || echo "::warning::publish-miner.yml did not succeed after retries -- left for manual follow-up."
286338
fi
287339
else
288340
echo "::warning::Skipping mcp/miner reconciliation -- publish-engine.yml did not succeed, and they depend on it."

0 commit comments

Comments
 (0)