mirror of
https://gh-proxy.org/https://github.com/klinsmaya/portal-template-default.git
synced 2026-11-08 17:17:28 +08:00
134 lines
6.2 KiB
Bash
Executable File
134 lines
6.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
: "${GITHUB_REPOSITORY:?GITHUB_REPOSITORY is required}"
|
|
: "${SOURCE_RUN_ID:?SOURCE_RUN_ID is required}"
|
|
: "${SOURCE_ATTEMPT:?SOURCE_ATTEMPT is required}"
|
|
: "${FACTORY_REPORT_REF:?FACTORY_REPORT_REF is required}"
|
|
: "${GH_TOKEN:?GH_TOKEN is required}"
|
|
if [[ ! "$SOURCE_RUN_ID" =~ ^[1-9][0-9]*$ || ! "$SOURCE_ATTEMPT" =~ ^[1-9][0-9]*$ ]]; then
|
|
echo "Source run and attempt must be positive integers." >&2
|
|
exit 2
|
|
fi
|
|
|
|
# GITHUB_TOKEN can explicitly dispatch workflows even when a bot-triggered
|
|
# continuation does not produce the downstream workflow_run event.
|
|
# A request normally returns in a second or two. Worst case per report: three
|
|
# 15 s attempts (plus 5 s to kill each) and the 2 s and 8 s backoffs, 70 s; six
|
|
# reports and a comment round's queue request take 490 s, inside the 10-minute
|
|
# dispatch-reports job in code-agent-task.yml. task-report-dispatch.test.mjs
|
|
# checks that budget.
|
|
#
|
|
# A request killed by the timeout may already have been accepted, so a retry
|
|
# can dispatch the same report twice. That is safe by design, not by luck:
|
|
# every target already receives duplicate requests for one source run (this
|
|
# step and its workflow_run copy both ran before report-dispatch-gate.yml, and
|
|
# a replay or an operator can request any of them again), so each one is
|
|
# idempotent per source run and attempt:
|
|
# report-task-progress rewrites one comment; an equal or older record is refused
|
|
# report-task-usage archives and comments under the run/attempt marker
|
|
# publish-agent-history uploads content-addressed archives, upserts by marker
|
|
# publish-retro upserts its comment and ledger row by marker
|
|
# publish-visual-report upserts its PR comment by marker
|
|
# deploy-preview keeps a running instance of the same build (no force)
|
|
# comment-build-queue reconciles receipts; a second pass finds nothing to do
|
|
# Retrying only before a connection was established would trade that for lost
|
|
# reports whenever GitHub accepts slowly, which continuations cannot recover
|
|
# (they emit no workflow_run). task-report-dispatch.test.mjs keeps this list in
|
|
# step with the accepted workflows.
|
|
DISPATCH_ATTEMPT_TIMEOUT=15s
|
|
DISPATCH_KILL_AFTER=5s
|
|
DISPATCH_BACKOFF=(2 8)
|
|
dispatch() {
|
|
local workflow="$1"
|
|
local fields=(--field "run_id=$SOURCE_RUN_ID" --field "attempt=$SOURCE_ATTEMPT")
|
|
# The progress reporter serializes per Issue, so a continuation's snapshots
|
|
# and this run's final report cannot rewrite the comment at the same time.
|
|
# The Issue only names the concurrency group; the publisher still derives
|
|
# the target from the source run itself.
|
|
if [[ "$workflow" == report-task-progress.yml && "${ISSUE_NUMBER:-}" =~ ^[1-9][0-9]*$ ]]; then
|
|
fields+=(--field "issue=$ISSUE_NUMBER")
|
|
fi
|
|
# The comment queue reconciles one Issue once this run has completed.
|
|
if [[ "$workflow" == comment-build-queue.yml ]]; then
|
|
fields=(--field "issue_number=$ISSUE_NUMBER" --field "run_id=$SOURCE_RUN_ID")
|
|
fi
|
|
for attempt in 1 2 3; do
|
|
if timeout --kill-after="$DISPATCH_KILL_AFTER" "$DISPATCH_ATTEMPT_TIMEOUT" gh workflow run "$workflow" \
|
|
--repo "$GITHUB_REPOSITORY" --ref "$FACTORY_REPORT_REF" "${fields[@]}"; then
|
|
echo "Requested $workflow for run $SOURCE_RUN_ID, attempt $SOURCE_ATTEMPT."
|
|
return 0
|
|
fi
|
|
if [[ "$attempt" -lt 3 ]]; then sleep "${DISPATCH_BACKOFF[attempt - 1]}"; fi
|
|
done
|
|
echo "::warning::Could not dispatch $workflow; replay it with run_id=$SOURCE_RUN_ID and attempt=$SOURCE_ATTEMPT."
|
|
if [[ -n "${GITHUB_STEP_SUMMARY:-}" ]]; then
|
|
printf '\nReport dispatch failed: `%s`. Replay with `run_id=%s`, `attempt=%s`; do not rebuild the application.\n' \
|
|
"$workflow" "$SOURCE_RUN_ID" "$SOURCE_ATTEMPT" >> "$GITHUB_STEP_SUMMARY"
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
# Published failed work has evidence and deserves a preview attempt too.
|
|
published="${FACTORY_TASK_PUBLISHED:-false}"
|
|
# A rejected GitHub Re-run did no work: its attempt has no progress, usage,
|
|
# history or retro of its own, and a report for it would rank as the Issue's
|
|
# latest and replace the real one (the progress comment included, which
|
|
# orders attempts by number). No report is requested; only the comment queue
|
|
# still moves on. Each step still succeeds, so report-dispatch-gate.yml counts
|
|
# it as handled and the workflow_run copy does not publish the empty report.
|
|
rerun_rejected="${FACTORY_RERUN_REJECTED:-false}"
|
|
# Rejected in prepare ("Re-run all jobs"), the attempt claimed no comment
|
|
# either: nothing at all is requested.
|
|
prepare_rejected="${FACTORY_PREPARE_REJECTED:-false}"
|
|
request() {
|
|
local workflow="$1"
|
|
if [[ "$prepare_rejected" == 'true' ]]; then
|
|
echo "Not requesting $workflow: prepare rejected attempt $SOURCE_ATTEMPT as a GitHub Re-run."
|
|
return 0
|
|
fi
|
|
if [[ "$rerun_rejected" == 'true' && "$workflow" != comment-build-queue.yml ]]; then
|
|
echo "Not requesting $workflow: attempt $SOURCE_ATTEMPT was a rejected GitHub Re-run."
|
|
return 0
|
|
fi
|
|
case "$workflow" in
|
|
publish-visual-report.yml | deploy-preview.yml)
|
|
# Requested explicitly for the same reason as the media report: a preview
|
|
# is expected to appear after a delivery, and the workflow_run event is not
|
|
# guaranteed for a bot-triggered continuation.
|
|
if [[ "$published" != 'true' ]]; then
|
|
echo "Not requesting $workflow: the task published no work."
|
|
return 0
|
|
fi
|
|
;;
|
|
esac
|
|
dispatch "$workflow"
|
|
}
|
|
|
|
# The task requests each report in a step of its own, so
|
|
# report-dispatch-gate.yml can tell which ones went out. The dispatcher is
|
|
# checked out at the calling workflow's own commit, so every caller names its
|
|
# workflows.
|
|
if (( $# == 0 )); then
|
|
echo "Name the report workflows to request." >&2
|
|
exit 2
|
|
fi
|
|
# The interaction history and retro are worth keeping for failures and
|
|
# handoffs too, not only deliveries.
|
|
failed=0
|
|
for workflow in "$@"; do
|
|
case "$workflow" in
|
|
report-task-progress.yml | report-task-usage.yml | publish-agent-history.yml | \
|
|
publish-retro.yml | publish-visual-report.yml | deploy-preview.yml) ;;
|
|
comment-build-queue.yml)
|
|
if [[ ! "${ISSUE_NUMBER:-}" =~ ^[1-9][0-9]*$ ]]; then
|
|
echo "comment-build-queue.yml needs ISSUE_NUMBER." >&2
|
|
exit 2
|
|
fi
|
|
;;
|
|
*) echo "Unknown report workflow: $workflow" >&2; exit 2 ;;
|
|
esac
|
|
request "$workflow" || failed=1
|
|
done
|
|
exit "$failed"
|