#!/usr/bin/env bash set -euo pipefail root=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd) source "$root/.github/scripts/release_helpers.sh" export RELEASE_RETRY_COUNT=5 RELEASE_RETRY_DELAY=0 delete_attempts=0 deleted_path= gh() { if [[ $* == *'--paginate --slurp'* ]]; then printf '%s\n' '[[ {"id": 11, "name": "sha256:correct", "metadata": {"container": {"tags": ["rollback-other"]}}}, {"id": 22, "name": "sha256:wrong", "metadata": {"container": {"tags": ["rollback-123-1"]}}}, {"id": 33, "name": "sha256:correct", "metadata": {"container": {"tags": ["rollback-123-1"]}}} ]]' return fi ((++delete_attempts)) deleted_path=${4:-} ((delete_attempts >= 3)) } delete_package_version /users/owner/packages/container/repo/versions rollback-123-1 sha256:correct [[ $delete_attempts -eq 3 ]] [[ $deleted_path == /users/owner/packages/container/repo/versions/33 ]] counter_file=$(mktemp) trap 'rm -f "$counter_file"' EXIT printf '0\n' > "$counter_file" crane() { local count count=$(< "$counter_file") ((++count)) printf '%s\n' "$count" > "$counter_file" if ((count < 3)); then printf '%s\n' sha256:rollback return fi echo MANIFEST_UNKNOWN >&2 return 1 } wait_for_tag_absent ghcr.io/owner/repo:1.2.3 [[ $(< "$counter_file") -eq 3 ]] python3 - "$root/.github/workflows/ci.yml" <<'PY' import re import sys from pathlib import Path workflow = Path(sys.argv[1]).read_text() release = re.search(r"(?ms)^ release:\n(.*?)(?=^ [a-zA-Z0-9_-]+:\n|\Z)", workflow) assert release, "release job missing" body = release.group(1) assert re.search( r"(?m)^ concurrency:\n group: release-promotion\n cancel-in-progress: false$", body, ), "all release tags must share one non-cancelling promotion lock" assert "github.ref" not in re.search(r"(?ms)^ concurrency:\n(.*?)(?=^ \S)", body).group(1) PY echo "release promotion checks passed"