mirror of
https://github.com/h3pdesign/Neon-Vision-Editor
synced 2026-04-21 13:27:16 +00:00
ci(release): add resume auto and harden homebrew tap orchestration
This commit is contained in:
parent
0a758770de
commit
af8d59c416
6 changed files with 457 additions and 56 deletions
|
|
@ -299,19 +299,70 @@ jobs:
|
|||
sleep 5
|
||||
done
|
||||
|
||||
for dispatch_attempt in {1..5}; do
|
||||
if gh api repos/h3pdesign/homebrew-tap/dispatches \
|
||||
dispatch_homebrew() {
|
||||
gh api repos/h3pdesign/homebrew-tap/dispatches \
|
||||
-f event_type=notarized_release \
|
||||
-f client_payload[tag]="$TAG_NAME"; then
|
||||
echo "homebrew-tap dispatch accepted (attempt ${dispatch_attempt})."
|
||||
-f client_payload[tag]="$TAG_NAME"
|
||||
}
|
||||
|
||||
wait_for_tap_run() {
|
||||
local start_ts="$1"
|
||||
local run_id=""
|
||||
for poll in {1..24}; do
|
||||
run_id="$(gh run list -R h3pdesign/homebrew-tap \
|
||||
--workflow update-cask.yml \
|
||||
--event repository_dispatch \
|
||||
--limit 20 \
|
||||
--json databaseId,displayTitle,createdAt \
|
||||
--jq ".[] | select(.displayTitle == \"notarized_release\") | select(.createdAt >= \"${start_ts}\") | .databaseId" | head -n1 || true)"
|
||||
if [[ -n "${run_id}" ]]; then
|
||||
echo "${run_id}"
|
||||
return 0
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
wait_for_tap_completion() {
|
||||
local run_id="$1"
|
||||
gh run watch -R h3pdesign/homebrew-tap "${run_id}" || true
|
||||
local conclusion
|
||||
conclusion="$(gh run view -R h3pdesign/homebrew-tap "${run_id}" --json conclusion --jq .conclusion || true)"
|
||||
if [[ "${conclusion}" == "success" ]]; then
|
||||
return 0
|
||||
fi
|
||||
echo "homebrew-tap run ${run_id} concluded with '${conclusion:-unknown}'." >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
for dispatch_attempt in {1..3}; do
|
||||
dispatch_start="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
if ! dispatch_homebrew; then
|
||||
echo "homebrew-tap dispatch failed on attempt ${dispatch_attempt}." >&2
|
||||
sleep $((dispatch_attempt * 5))
|
||||
continue
|
||||
fi
|
||||
echo "homebrew-tap dispatch accepted (attempt ${dispatch_attempt})."
|
||||
|
||||
run_id="$(wait_for_tap_run "${dispatch_start}" || true)"
|
||||
if [[ -z "${run_id}" ]]; then
|
||||
echo "No homebrew-tap run appeared after dispatch attempt ${dispatch_attempt}." >&2
|
||||
sleep $((dispatch_attempt * 5))
|
||||
continue
|
||||
fi
|
||||
|
||||
if wait_for_tap_completion "${run_id}"; then
|
||||
echo "homebrew-tap run ${run_id} succeeded."
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$dispatch_attempt" -lt 5 ]]; then
|
||||
sleep $((dispatch_attempt * 5))
|
||||
|
||||
if [[ "${dispatch_attempt}" -lt 3 ]]; then
|
||||
sleep $((dispatch_attempt * 10))
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Failed to dispatch homebrew-tap update after retries." >&2
|
||||
echo "Failed to complete homebrew-tap update after retries." >&2
|
||||
exit 1
|
||||
|
||||
- name: Restore user keychain state
|
||||
|
|
|
|||
65
.github/workflows/release-notarized.yml
vendored
65
.github/workflows/release-notarized.yml
vendored
|
|
@ -257,19 +257,70 @@ jobs:
|
|||
sleep 5
|
||||
done
|
||||
|
||||
for dispatch_attempt in {1..5}; do
|
||||
if gh api repos/h3pdesign/homebrew-tap/dispatches \
|
||||
dispatch_homebrew() {
|
||||
gh api repos/h3pdesign/homebrew-tap/dispatches \
|
||||
-f event_type=notarized_release \
|
||||
-f client_payload[tag]="$TAG_NAME"; then
|
||||
echo "homebrew-tap dispatch accepted (attempt ${dispatch_attempt})."
|
||||
-f client_payload[tag]="$TAG_NAME"
|
||||
}
|
||||
|
||||
wait_for_tap_run() {
|
||||
local start_ts="$1"
|
||||
local run_id=""
|
||||
for poll in {1..24}; do
|
||||
run_id="$(gh run list -R h3pdesign/homebrew-tap \
|
||||
--workflow update-cask.yml \
|
||||
--event repository_dispatch \
|
||||
--limit 20 \
|
||||
--json databaseId,displayTitle,createdAt \
|
||||
--jq ".[] | select(.displayTitle == \"notarized_release\") | select(.createdAt >= \"${start_ts}\") | .databaseId" | head -n1 || true)"
|
||||
if [[ -n "${run_id}" ]]; then
|
||||
echo "${run_id}"
|
||||
return 0
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
wait_for_tap_completion() {
|
||||
local run_id="$1"
|
||||
gh run watch -R h3pdesign/homebrew-tap "${run_id}" || true
|
||||
local conclusion
|
||||
conclusion="$(gh run view -R h3pdesign/homebrew-tap "${run_id}" --json conclusion --jq .conclusion || true)"
|
||||
if [[ "${conclusion}" == "success" ]]; then
|
||||
return 0
|
||||
fi
|
||||
echo "homebrew-tap run ${run_id} concluded with '${conclusion:-unknown}'." >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
for dispatch_attempt in {1..3}; do
|
||||
dispatch_start="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
if ! dispatch_homebrew; then
|
||||
echo "homebrew-tap dispatch failed on attempt ${dispatch_attempt}." >&2
|
||||
sleep $((dispatch_attempt * 5))
|
||||
continue
|
||||
fi
|
||||
echo "homebrew-tap dispatch accepted (attempt ${dispatch_attempt})."
|
||||
|
||||
run_id="$(wait_for_tap_run "${dispatch_start}" || true)"
|
||||
if [[ -z "${run_id}" ]]; then
|
||||
echo "No homebrew-tap run appeared after dispatch attempt ${dispatch_attempt}." >&2
|
||||
sleep $((dispatch_attempt * 5))
|
||||
continue
|
||||
fi
|
||||
|
||||
if wait_for_tap_completion "${run_id}"; then
|
||||
echo "homebrew-tap run ${run_id} succeeded."
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$dispatch_attempt" -lt 5 ]]; then
|
||||
sleep $((dispatch_attempt * 5))
|
||||
|
||||
if [[ "${dispatch_attempt}" -lt 3 ]]; then
|
||||
sleep $((dispatch_attempt * 10))
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Failed to dispatch homebrew-tap update after retries." >&2
|
||||
echo "Failed to complete homebrew-tap update after retries." >&2
|
||||
exit 1
|
||||
|
||||
- name: Restore user keychain state
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@
|
|||
CODE_SIGNING_ALLOWED = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 259;
|
||||
CURRENT_PROJECT_VERSION = 260;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = CS727NF72U;
|
||||
ENABLE_APP_SANDBOX = YES;
|
||||
|
|
@ -439,7 +439,7 @@
|
|||
CODE_SIGNING_ALLOWED = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 259;
|
||||
CURRENT_PROJECT_VERSION = 260;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = CS727NF72U;
|
||||
ENABLE_APP_SANDBOX = YES;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ usage() {
|
|||
Run end-to-end release flow in one command.
|
||||
|
||||
Usage:
|
||||
scripts/release_all.sh <tag> [notarized] [--date YYYY-MM-DD] [--skip-notarized] [--self-hosted] [--github-hosted] [--enterprise-selfhosted] [--autostash] [--dry-run]
|
||||
scripts/release_all.sh <tag> [notarized] [--date YYYY-MM-DD] [--skip-notarized] [--self-hosted] [--github-hosted] [--enterprise-selfhosted] [--autostash] [--dry-run] [--from <step>] [--to <step>] [--retag] [--resume-auto]
|
||||
|
||||
Examples:
|
||||
scripts/release_all.sh v0.4.9
|
||||
|
|
@ -17,6 +17,10 @@ Examples:
|
|||
scripts/release_all.sh v0.4.9 --github-hosted
|
||||
scripts/release_all.sh v0.4.9 --autostash
|
||||
scripts/release_all.sh v0.4.9 --dry-run
|
||||
scripts/release_all.sh v0.4.9 --from notarize
|
||||
scripts/release_all.sh v0.4.9 --to preflight
|
||||
scripts/release_all.sh v0.4.9 --retag
|
||||
scripts/release_all.sh v0.4.9 --resume-auto
|
||||
|
||||
What it does:
|
||||
1) Run release preflight checks (docs + build + icon payload + tests)
|
||||
|
|
@ -49,6 +53,51 @@ USE_SELF_HOSTED=0
|
|||
ENTERPRISE_SELF_HOSTED=0
|
||||
AUTOSTASH=0
|
||||
DRY_RUN=0
|
||||
START_FROM="docs"
|
||||
STOP_AFTER="notarize"
|
||||
STOP_AFTER_SET=0
|
||||
START_FROM_SET=0
|
||||
RETAG=0
|
||||
RESUME_AUTO=0
|
||||
|
||||
step_index() {
|
||||
case "$1" in
|
||||
docs) echo 1 ;;
|
||||
preflight) echo 2 ;;
|
||||
prep) echo 3 ;;
|
||||
notarize) echo 4 ;;
|
||||
*)
|
||||
echo "Unknown step: $1. Valid steps: docs, preflight, prep, notarize." >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
step_enabled() {
|
||||
local step="$1"
|
||||
local start_idx stop_idx current_idx
|
||||
start_idx="$(step_index "$START_FROM")"
|
||||
stop_idx="$(step_index "$STOP_AFTER")"
|
||||
current_idx="$(step_index "$step")"
|
||||
(( current_idx >= start_idx && current_idx <= stop_idx ))
|
||||
}
|
||||
|
||||
gh_retry() {
|
||||
local attempts="${GH_RETRY_ATTEMPTS:-5}"
|
||||
local base_sleep="${GH_RETRY_BASE_SLEEP:-2}"
|
||||
local n=1
|
||||
|
||||
while true; do
|
||||
if "$@"; then
|
||||
return 0
|
||||
fi
|
||||
if (( n >= attempts )); then
|
||||
return 1
|
||||
fi
|
||||
sleep $((base_sleep * n))
|
||||
n=$((n + 1))
|
||||
done
|
||||
}
|
||||
|
||||
while [[ "${1:-}" != "" ]]; do
|
||||
case "$1" in
|
||||
|
|
@ -82,6 +131,32 @@ while [[ "${1:-}" != "" ]]; do
|
|||
--dry-run)
|
||||
DRY_RUN=1
|
||||
;;
|
||||
--from)
|
||||
shift
|
||||
if [[ -z "${1:-}" ]]; then
|
||||
echo "Missing value for --from" >&2
|
||||
exit 1
|
||||
fi
|
||||
START_FROM="$1"
|
||||
START_FROM_SET=1
|
||||
step_index "$START_FROM" >/dev/null
|
||||
;;
|
||||
--to)
|
||||
shift
|
||||
if [[ -z "${1:-}" ]]; then
|
||||
echo "Missing value for --to" >&2
|
||||
exit 1
|
||||
fi
|
||||
STOP_AFTER="$1"
|
||||
STOP_AFTER_SET=1
|
||||
step_index "$STOP_AFTER" >/dev/null
|
||||
;;
|
||||
--retag)
|
||||
RETAG=1
|
||||
;;
|
||||
--resume-auto)
|
||||
RESUME_AUTO=1
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument: $1" >&2
|
||||
usage
|
||||
|
|
@ -91,6 +166,46 @@ while [[ "${1:-}" != "" ]]; do
|
|||
shift || true
|
||||
done
|
||||
|
||||
if [[ "$TRIGGER_NOTARIZED" -eq 0 && "$STOP_AFTER_SET" -eq 0 ]]; then
|
||||
STOP_AFTER="prep"
|
||||
fi
|
||||
|
||||
if [[ "$STOP_AFTER" != "notarize" ]]; then
|
||||
TRIGGER_NOTARIZED=0
|
||||
fi
|
||||
|
||||
if [[ "$RESUME_AUTO" -eq 1 ]]; then
|
||||
local_tag_exists=0
|
||||
remote_tag_exists=0
|
||||
if git rev-parse "$TAG" >/dev/null 2>&1; then
|
||||
local_tag_exists=1
|
||||
fi
|
||||
if git ls-remote --tags origin "refs/tags/${TAG}" 2>/dev/null | grep -q "refs/tags/${TAG}$"; then
|
||||
remote_tag_exists=1
|
||||
fi
|
||||
if [[ "$local_tag_exists" -eq 0 && "$remote_tag_exists" -eq 1 ]]; then
|
||||
git fetch origin "refs/tags/${TAG}:refs/tags/${TAG}" >/dev/null 2>&1 || true
|
||||
if git rev-parse "$TAG" >/dev/null 2>&1; then
|
||||
local_tag_exists=1
|
||||
fi
|
||||
fi
|
||||
if [[ "$START_FROM_SET" -eq 0 ]]; then
|
||||
if [[ "$local_tag_exists" -eq 1 && "$remote_tag_exists" -eq 1 && "$TRIGGER_NOTARIZED" -eq 1 ]]; then
|
||||
START_FROM="notarize"
|
||||
elif [[ "$local_tag_exists" -eq 1 ]]; then
|
||||
START_FROM="prep"
|
||||
else
|
||||
START_FROM="docs"
|
||||
fi
|
||||
fi
|
||||
echo "Resume-auto selected: from=${START_FROM} to=${STOP_AFTER} (local_tag=${local_tag_exists}, remote_tag=${remote_tag_exists})"
|
||||
fi
|
||||
|
||||
if (( "$(step_index "$START_FROM")" > "$(step_index "$STOP_AFTER")" )); then
|
||||
echo "--from ${START_FROM} is after --to ${STOP_AFTER}." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v gh >/dev/null 2>&1; then
|
||||
echo "gh CLI is required." >&2
|
||||
exit 1
|
||||
|
|
@ -116,7 +231,12 @@ cleanup_autostash() {
|
|||
}
|
||||
trap cleanup_autostash EXIT
|
||||
|
||||
if [[ "$AUTOSTASH" -eq 1 ]]; then
|
||||
REQUIRES_CLEAN_TREE=0
|
||||
if step_enabled prep; then
|
||||
REQUIRES_CLEAN_TREE=1
|
||||
fi
|
||||
|
||||
if [[ "$AUTOSTASH" -eq 1 && "$REQUIRES_CLEAN_TREE" -eq 1 ]]; then
|
||||
if [[ -n "$(git status --porcelain)" ]]; then
|
||||
STASH_MSG="release_all autostash ${TAG} $(date +%Y-%m-%dT%H:%M:%S)"
|
||||
git stash push --include-untracked -m "$STASH_MSG" >/dev/null
|
||||
|
|
@ -134,11 +254,11 @@ wait_for_pre_release_ci() {
|
|||
echo "Waiting for Pre-release CI on ${sha}..."
|
||||
while (( elapsed <= timeout_seconds )); do
|
||||
local run_line
|
||||
run_line="$(gh run list \
|
||||
run_line="$(gh_retry gh run list \
|
||||
--workflow pre-release-ci.yml \
|
||||
--limit 50 \
|
||||
--json databaseId,status,conclusion,headSha,event,createdAt \
|
||||
--jq ".[] | select(.headSha == \"${sha}\" and .event == \"push\") | \"\(.databaseId)\t\(.status)\t\(.conclusion // \"\")\"" | head -n1)"
|
||||
--jq ".[] | select(.headSha == \"${sha}\" and .event == \"push\") | \"\(.databaseId)\t\(.status)\t\(.conclusion // \"\")\"" | head -n1 || true)"
|
||||
|
||||
if [[ -n "$run_line" ]]; then
|
||||
local run_id run_status run_conclusion
|
||||
|
|
@ -167,38 +287,105 @@ wait_for_pre_release_ci() {
|
|||
return 1
|
||||
}
|
||||
|
||||
if [[ "$AUTOSTASH" -eq 0 && -n "$(git status --porcelain)" ]]; then
|
||||
wait_for_homebrew_tap_update() {
|
||||
local since="$1"
|
||||
local timeout_seconds=1800
|
||||
local interval_seconds=15
|
||||
local elapsed=0
|
||||
|
||||
echo "Waiting for homebrew-tap run (since ${since})..."
|
||||
while (( elapsed <= timeout_seconds )); do
|
||||
local tap_line
|
||||
tap_line="$(gh_retry gh run list -R h3pdesign/homebrew-tap \
|
||||
--workflow update-cask.yml \
|
||||
--event repository_dispatch \
|
||||
--limit 30 \
|
||||
--json databaseId,status,conclusion,displayTitle,createdAt \
|
||||
--jq ".[] | select(.displayTitle == \"notarized_release\" and .createdAt >= \"${since}\") | \"\(.databaseId)\t\(.status)\t\(.conclusion // \"\")\"" | head -n1 || true)"
|
||||
|
||||
if [[ -n "$tap_line" ]]; then
|
||||
local run_id run_status run_conclusion
|
||||
run_id="$(echo "$tap_line" | awk -F '\t' '{print $1}')"
|
||||
run_status="$(echo "$tap_line" | awk -F '\t' '{print $2}')"
|
||||
run_conclusion="$(echo "$tap_line" | awk -F '\t' '{print $3}')"
|
||||
echo "homebrew-tap run ${run_id}: status=${run_status} conclusion=${run_conclusion:-pending}"
|
||||
if [[ "$run_status" == "completed" ]]; then
|
||||
if [[ "$run_conclusion" == "success" ]]; then
|
||||
echo "homebrew-tap update passed."
|
||||
return 0
|
||||
fi
|
||||
echo "homebrew-tap update failed (${run_id})." >&2
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
echo "homebrew-tap run not visible yet; retrying..."
|
||||
fi
|
||||
|
||||
sleep "$interval_seconds"
|
||||
elapsed=$((elapsed + interval_seconds))
|
||||
done
|
||||
|
||||
echo "Timed out waiting for homebrew-tap update run." >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
if [[ "$REQUIRES_CLEAN_TREE" -eq 1 && "$AUTOSTASH" -eq 0 && -n "$(git status --porcelain)" ]]; then
|
||||
echo "Working tree is not clean. Commit/stash changes first, or rerun with --autostash." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Verifying release docs are up to date for ${TAG}..."
|
||||
docs_check_cmd=(scripts/prepare_release_docs.py "$TAG" --check)
|
||||
if [[ ${#DATE_ARG[@]} -gt 0 ]]; then
|
||||
docs_check_cmd+=("${DATE_ARG[@]}")
|
||||
if step_enabled docs; then
|
||||
echo "Verifying release docs are up to date for ${TAG}..."
|
||||
docs_check_cmd=(scripts/prepare_release_docs.py "$TAG" --check)
|
||||
if [[ ${#DATE_ARG[@]} -gt 0 ]]; then
|
||||
docs_check_cmd+=("${DATE_ARG[@]}")
|
||||
fi
|
||||
"${docs_check_cmd[@]}"
|
||||
fi
|
||||
"${docs_check_cmd[@]}"
|
||||
|
||||
echo "Running release preflight for ${TAG}..."
|
||||
scripts/ci/release_preflight.sh "$TAG"
|
||||
if step_enabled preflight; then
|
||||
echo "Running release preflight for ${TAG}..."
|
||||
scripts/ci/release_preflight.sh "$TAG"
|
||||
fi
|
||||
|
||||
if [[ "$DRY_RUN" -eq 1 ]]; then
|
||||
echo "Dry-run requested. Preflight completed; no commits/tags/workflows were created."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Running release prep for ${TAG}..."
|
||||
prep_cmd=(scripts/release_prep.sh "$TAG")
|
||||
if [[ ${#DATE_ARG[@]} -gt 0 ]]; then
|
||||
prep_cmd+=("${DATE_ARG[@]}")
|
||||
if step_enabled prep; then
|
||||
if git rev-parse "$TAG" >/dev/null 2>&1; then
|
||||
if [[ "$RETAG" -eq 1 ]]; then
|
||||
echo "Retag requested. Deleting existing ${TAG} locally and on origin (if present)..."
|
||||
git tag -d "$TAG" >/dev/null 2>&1 || true
|
||||
git push origin ":refs/tags/${TAG}" >/dev/null 2>&1 || true
|
||||
else
|
||||
echo "Tag ${TAG} already exists. Skipping release prep. Use --retag to recreate it."
|
||||
if [[ "$(git branch --show-current)" == "main" ]]; then
|
||||
git push origin main
|
||||
git push origin "$TAG" || true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! git rev-parse "$TAG" >/dev/null 2>&1; then
|
||||
echo "Running release prep for ${TAG}..."
|
||||
prep_cmd=(scripts/release_prep.sh "$TAG")
|
||||
if [[ ${#DATE_ARG[@]} -gt 0 ]]; then
|
||||
prep_cmd+=("${DATE_ARG[@]}")
|
||||
fi
|
||||
prep_cmd+=(--push)
|
||||
"${prep_cmd[@]}"
|
||||
echo "Tag push completed."
|
||||
fi
|
||||
fi
|
||||
prep_cmd+=(--push)
|
||||
"${prep_cmd[@]}"
|
||||
|
||||
echo "Tag push completed."
|
||||
|
||||
if [[ "$TRIGGER_NOTARIZED" -eq 1 ]]; then
|
||||
RELEASE_SHA="$(git rev-parse HEAD)"
|
||||
if [[ "$TRIGGER_NOTARIZED" -eq 1 ]] && step_enabled notarize; then
|
||||
if ! git rev-parse "$TAG" >/dev/null 2>&1; then
|
||||
echo "Tag ${TAG} does not exist. Run prep first or use --from prep." >&2
|
||||
exit 1
|
||||
fi
|
||||
RELEASE_SHA="$(git rev-parse "${TAG}^{commit}")"
|
||||
wait_for_pre_release_ci "$RELEASE_SHA"
|
||||
|
||||
echo "Triggering notarized workflow for ${TAG}..."
|
||||
|
|
@ -206,24 +393,34 @@ if [[ "$TRIGGER_NOTARIZED" -eq 1 ]]; then
|
|||
echo "Enterprise self-hosted mode enabled (expects self-hosted runner labels and GH_HOST if required)."
|
||||
fi
|
||||
if [[ "$USE_SELF_HOSTED" -eq 1 ]]; then
|
||||
gh workflow run release-notarized-selfhosted.yml -f tag="$TAG" -f use_self_hosted=true
|
||||
DISPATCHED_AT="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
gh_retry gh workflow run release-notarized-selfhosted.yml -f tag="$TAG" -f use_self_hosted=true
|
||||
WORKFLOW_NAME="release-notarized-selfhosted.yml"
|
||||
echo "Triggered: ${WORKFLOW_NAME} (tag=${TAG}, use_self_hosted=true)"
|
||||
else
|
||||
gh workflow run release-notarized.yml -f tag="$TAG"
|
||||
DISPATCHED_AT="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
gh_retry gh workflow run release-notarized.yml -f tag="$TAG"
|
||||
WORKFLOW_NAME="release-notarized.yml"
|
||||
echo "Triggered: ${WORKFLOW_NAME} (tag=${TAG})"
|
||||
fi
|
||||
|
||||
echo "Waiting for ${WORKFLOW_NAME} run..."
|
||||
sleep 6
|
||||
RUN_ID="$(gh run list --workflow "$WORKFLOW_NAME" --limit 20 --json databaseId,displayTitle --jq ".[] | select(.displayTitle | contains(\"${TAG}\")) | .databaseId" | head -n1)"
|
||||
RUN_ID=""
|
||||
for _ in {1..20}; do
|
||||
RUN_ID="$(gh_retry gh run list --workflow "$WORKFLOW_NAME" --limit 30 --json databaseId,displayTitle,createdAt --jq ".[] | select((.displayTitle | contains(\"${TAG}\")) and .createdAt >= \"${DISPATCHED_AT}\") | .databaseId" | head -n1 || true)"
|
||||
if [[ -n "$RUN_ID" ]]; then
|
||||
break
|
||||
fi
|
||||
sleep 6
|
||||
done
|
||||
if [[ -z "$RUN_ID" ]]; then
|
||||
echo "Could not find workflow run for ${TAG}." >&2
|
||||
exit 1
|
||||
fi
|
||||
gh run watch "$RUN_ID"
|
||||
gh_retry gh run watch "$RUN_ID"
|
||||
scripts/ci/verify_release_asset.sh "$TAG"
|
||||
wait_for_homebrew_tap_update "$DISPATCHED_AT"
|
||||
fi
|
||||
|
||||
echo
|
||||
|
|
|
|||
|
|
@ -293,19 +293,70 @@ jobs:
|
|||
sleep 5
|
||||
done
|
||||
|
||||
for dispatch_attempt in {1..5}; do
|
||||
if gh api repos/h3pdesign/homebrew-tap/dispatches \
|
||||
dispatch_homebrew() {
|
||||
gh api repos/h3pdesign/homebrew-tap/dispatches \
|
||||
-f event_type=notarized_release \
|
||||
-f client_payload[tag]="$TAG_NAME"; then
|
||||
echo "homebrew-tap dispatch accepted (attempt ${dispatch_attempt})."
|
||||
-f client_payload[tag]="$TAG_NAME"
|
||||
}
|
||||
|
||||
wait_for_tap_run() {
|
||||
local start_ts="$1"
|
||||
local run_id=""
|
||||
for poll in {1..24}; do
|
||||
run_id="$(gh run list -R h3pdesign/homebrew-tap \
|
||||
--workflow update-cask.yml \
|
||||
--event repository_dispatch \
|
||||
--limit 20 \
|
||||
--json databaseId,displayTitle,createdAt \
|
||||
--jq ".[] | select(.displayTitle == \"notarized_release\") | select(.createdAt >= \"${start_ts}\") | .databaseId" | head -n1 || true)"
|
||||
if [[ -n "${run_id}" ]]; then
|
||||
echo "${run_id}"
|
||||
return 0
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
wait_for_tap_completion() {
|
||||
local run_id="$1"
|
||||
gh run watch -R h3pdesign/homebrew-tap "${run_id}" || true
|
||||
local conclusion
|
||||
conclusion="$(gh run view -R h3pdesign/homebrew-tap "${run_id}" --json conclusion --jq .conclusion || true)"
|
||||
if [[ "${conclusion}" == "success" ]]; then
|
||||
return 0
|
||||
fi
|
||||
echo "homebrew-tap run ${run_id} concluded with '${conclusion:-unknown}'." >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
for dispatch_attempt in {1..3}; do
|
||||
dispatch_start="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
if ! dispatch_homebrew; then
|
||||
echo "homebrew-tap dispatch failed on attempt ${dispatch_attempt}." >&2
|
||||
sleep $((dispatch_attempt * 5))
|
||||
continue
|
||||
fi
|
||||
echo "homebrew-tap dispatch accepted (attempt ${dispatch_attempt})."
|
||||
|
||||
run_id="$(wait_for_tap_run "${dispatch_start}" || true)"
|
||||
if [[ -z "${run_id}" ]]; then
|
||||
echo "No homebrew-tap run appeared after dispatch attempt ${dispatch_attempt}." >&2
|
||||
sleep $((dispatch_attempt * 5))
|
||||
continue
|
||||
fi
|
||||
|
||||
if wait_for_tap_completion "${run_id}"; then
|
||||
echo "homebrew-tap run ${run_id} succeeded."
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$dispatch_attempt" -lt 5 ]]; then
|
||||
sleep $((dispatch_attempt * 5))
|
||||
|
||||
if [[ "${dispatch_attempt}" -lt 3 ]]; then
|
||||
sleep $((dispatch_attempt * 10))
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Failed to dispatch homebrew-tap update after retries." >&2
|
||||
echo "Failed to complete homebrew-tap update after retries." >&2
|
||||
exit 1
|
||||
|
||||
- name: Restore user keychain state
|
||||
|
|
|
|||
|
|
@ -257,19 +257,70 @@ jobs:
|
|||
sleep 5
|
||||
done
|
||||
|
||||
for dispatch_attempt in {1..5}; do
|
||||
if gh api repos/h3pdesign/homebrew-tap/dispatches \
|
||||
dispatch_homebrew() {
|
||||
gh api repos/h3pdesign/homebrew-tap/dispatches \
|
||||
-f event_type=notarized_release \
|
||||
-f client_payload[tag]="$TAG_NAME"; then
|
||||
echo "homebrew-tap dispatch accepted (attempt ${dispatch_attempt})."
|
||||
-f client_payload[tag]="$TAG_NAME"
|
||||
}
|
||||
|
||||
wait_for_tap_run() {
|
||||
local start_ts="$1"
|
||||
local run_id=""
|
||||
for poll in {1..24}; do
|
||||
run_id="$(gh run list -R h3pdesign/homebrew-tap \
|
||||
--workflow update-cask.yml \
|
||||
--event repository_dispatch \
|
||||
--limit 20 \
|
||||
--json databaseId,displayTitle,createdAt \
|
||||
--jq ".[] | select(.displayTitle == \"notarized_release\") | select(.createdAt >= \"${start_ts}\") | .databaseId" | head -n1 || true)"
|
||||
if [[ -n "${run_id}" ]]; then
|
||||
echo "${run_id}"
|
||||
return 0
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
wait_for_tap_completion() {
|
||||
local run_id="$1"
|
||||
gh run watch -R h3pdesign/homebrew-tap "${run_id}" || true
|
||||
local conclusion
|
||||
conclusion="$(gh run view -R h3pdesign/homebrew-tap "${run_id}" --json conclusion --jq .conclusion || true)"
|
||||
if [[ "${conclusion}" == "success" ]]; then
|
||||
return 0
|
||||
fi
|
||||
echo "homebrew-tap run ${run_id} concluded with '${conclusion:-unknown}'." >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
for dispatch_attempt in {1..3}; do
|
||||
dispatch_start="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
if ! dispatch_homebrew; then
|
||||
echo "homebrew-tap dispatch failed on attempt ${dispatch_attempt}." >&2
|
||||
sleep $((dispatch_attempt * 5))
|
||||
continue
|
||||
fi
|
||||
echo "homebrew-tap dispatch accepted (attempt ${dispatch_attempt})."
|
||||
|
||||
run_id="$(wait_for_tap_run "${dispatch_start}" || true)"
|
||||
if [[ -z "${run_id}" ]]; then
|
||||
echo "No homebrew-tap run appeared after dispatch attempt ${dispatch_attempt}." >&2
|
||||
sleep $((dispatch_attempt * 5))
|
||||
continue
|
||||
fi
|
||||
|
||||
if wait_for_tap_completion "${run_id}"; then
|
||||
echo "homebrew-tap run ${run_id} succeeded."
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$dispatch_attempt" -lt 5 ]]; then
|
||||
sleep $((dispatch_attempt * 5))
|
||||
|
||||
if [[ "${dispatch_attempt}" -lt 3 ]]; then
|
||||
sleep $((dispatch_attempt * 10))
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Failed to dispatch homebrew-tap update after retries." >&2
|
||||
echo "Failed to complete homebrew-tap update after retries." >&2
|
||||
exit 1
|
||||
|
||||
- name: Restore user keychain state
|
||||
|
|
|
|||
Loading…
Reference in a new issue