diff --git a/release-tools/comment-release-assets-uploaded.sh b/release-tools/comment-release-assets-uploaded.sh index 6c9efef..92c8ff8 100644 --- a/release-tools/comment-release-assets-uploaded.sh +++ b/release-tools/comment-release-assets-uploaded.sh @@ -4,6 +4,8 @@ release_plz_releases_json="${1:?release-plz releases JSON is required}" marker="" commit_sha="${2:-${GITHUB_SHA:-}}" gh_bin="${X52_GH:-gh}" +sleep_bin="${X52_SLEEP:-sleep}" +max_release_lookup_attempts=5 log() { echo "x52-comment-release-assets-uploaded: $*" @@ -32,14 +34,6 @@ if ! release_entries="$( exit 1 fi -log "Fetching releases from /repos/${GITHUB_REPOSITORY}/releases" -if ! releases_json="$( - "$gh_bin" api --paginate "/repos/${GITHUB_REPOSITORY}/releases?per_page=100" -)"; then - log "Failed to fetch releases from /repos/${GITHUB_REPOSITORY}/releases" - exit 1 -fi - pr_number="$( "$gh_bin" api \ "/repos/${GITHUB_REPOSITORY}/commits/${commit_sha}/pulls" \ @@ -53,33 +47,63 @@ fi log "Resolved commit ${commit_sha} to merged PR #${pr_number}" -release_lines="" - -while read -r release; do - tag="$(printf '%s\n' "$release" | jq -r '.tag')" - version="$(printf '%s\n' "$release" | jq -r '.version')" - package_name="$(printf '%s\n' "$release" | jq -r '.package_name')" - log "Resolving release tag ${tag}" - release_info="$( - printf '%s\n' "$releases_json" | jq -s -r --arg tag "$tag" \ - '([.[][] | select(.tag_name == $tag)] | first) as $release - | if $release == null then empty else [$release.html_url, $release.draft] | @tsv end' - )" - - if [[ -z "$release_info" ]]; then - log "No release with tag ${tag} was returned by /repos/${GITHUB_REPOSITORY}/releases" - exit 1 +release_lookup_delay=1 +for ((release_lookup_attempt = 1; release_lookup_attempt <= max_release_lookup_attempts; release_lookup_attempt++)); do + log "Fetching releases from /repos/${GITHUB_REPOSITORY}/releases (attempt ${release_lookup_attempt}/${max_release_lookup_attempts})" + if ! releases_json="$( + "$gh_bin" api --paginate "/repos/${GITHUB_REPOSITORY}/releases?per_page=100" + )"; then + retry_reason="Failed to fetch releases from /repos/${GITHUB_REPOSITORY}/releases" + else + if [[ "${RUNNER_DEBUG:-}" == "1" ]]; then + log "GitHub releases API response:" + printf '%s\n' "$releases_json" | jq -s . + fi + + release_lines="" + missing_tag="" + while read -r release; do + tag="$(printf '%s\n' "$release" | jq -r '.tag')" + version="$(printf '%s\n' "$release" | jq -r '.version')" + package_name="$(printf '%s\n' "$release" | jq -r '.package_name')" + log "Resolving release tag ${tag}" + release_info="$( + printf '%s\n' "$releases_json" | jq -s -r --arg tag "$tag" \ + '([.[][] | select(.tag_name == $tag)] | first) as $release + | if $release == null then empty else [$release.html_url, $release.draft] | @tsv end' + )" + + if [[ -z "$release_info" ]]; then + missing_tag="$tag" + break + fi + + IFS=$'\t' read -r release_url release_draft <<<"$release_info" + release_type="published" + if [[ "$release_draft" == "true" ]]; then + release_type="draft" + fi + log "Resolved tag ${tag} to ${release_type} release ${release_url}" + + release_lines+="- ${package_name} ${version}: ${release_url}"$'\n' + done <<<"$release_entries" + + if [[ -z "$missing_tag" ]]; then + break + fi + + retry_reason="No release with tag ${missing_tag} was returned by /repos/${GITHUB_REPOSITORY}/releases" fi - IFS=$'\t' read -r release_url release_draft <<<"$release_info" - release_type="published" - if [[ "$release_draft" == "true" ]]; then - release_type="draft" + if (( release_lookup_attempt == max_release_lookup_attempts )); then + log "$retry_reason" + exit 1 fi - log "Resolved tag ${tag} to ${release_type} release ${release_url}" - release_lines+="- ${package_name} ${version}: ${release_url}"$'\n' -done <<<"$release_entries" + log "${retry_reason}; retrying in ${release_lookup_delay}s" + "$sleep_bin" "$release_lookup_delay" + release_lookup_delay=$((release_lookup_delay * 2)) +done if [[ -z "$release_lines" ]]; then log "No releases in release-plz output; skipping" diff --git a/release-tools/comment-release-pr.sh b/release-tools/comment-release-pr.sh index 683af8b..99cdde5 100644 --- a/release-tools/comment-release-pr.sh +++ b/release-tools/comment-release-pr.sh @@ -4,6 +4,8 @@ release_plz_releases_json="${1:?release-plz releases JSON is required}" marker="" commit_sha="${2:-${GITHUB_SHA:-}}" gh_bin="${X52_GH:-gh}" +sleep_bin="${X52_SLEEP:-sleep}" +max_release_lookup_attempts=5 log() { echo "x52-comment-release-pr: $*" @@ -32,14 +34,6 @@ if ! release_entries="$( exit 1 fi -log "Fetching releases from /repos/${GITHUB_REPOSITORY}/releases" -if ! releases_json="$( - "$gh_bin" api --paginate "/repos/${GITHUB_REPOSITORY}/releases?per_page=100" -)"; then - log "Failed to fetch releases from /repos/${GITHUB_REPOSITORY}/releases" - exit 1 -fi - pr_number="$( "$gh_bin" api \ "/repos/${GITHUB_REPOSITORY}/commits/${commit_sha}/pulls" \ @@ -53,33 +47,63 @@ fi log "Resolved commit ${commit_sha} to merged PR #${pr_number}" -release_lines="" - -while read -r release; do - tag="$(printf '%s\n' "$release" | jq -r '.tag')" - version="$(printf '%s\n' "$release" | jq -r '.version')" - package_name="$(printf '%s\n' "$release" | jq -r '.package_name')" - log "Resolving release tag ${tag}" - release_info="$( - printf '%s\n' "$releases_json" | jq -s -r --arg tag "$tag" \ - '([.[][] | select(.tag_name == $tag)] | first) as $release - | if $release == null then empty else [$release.html_url, $release.draft] | @tsv end' - )" - - if [[ -z "$release_info" ]]; then - log "No release with tag ${tag} was returned by /repos/${GITHUB_REPOSITORY}/releases" - exit 1 +release_lookup_delay=1 +for ((release_lookup_attempt = 1; release_lookup_attempt <= max_release_lookup_attempts; release_lookup_attempt++)); do + log "Fetching releases from /repos/${GITHUB_REPOSITORY}/releases (attempt ${release_lookup_attempt}/${max_release_lookup_attempts})" + if ! releases_json="$( + "$gh_bin" api --paginate "/repos/${GITHUB_REPOSITORY}/releases?per_page=100" + )"; then + retry_reason="Failed to fetch releases from /repos/${GITHUB_REPOSITORY}/releases" + else + if [[ "${RUNNER_DEBUG:-}" == "1" ]]; then + log "GitHub releases API response:" + printf '%s\n' "$releases_json" | jq -s . + fi + + release_lines="" + missing_tag="" + while read -r release; do + tag="$(printf '%s\n' "$release" | jq -r '.tag')" + version="$(printf '%s\n' "$release" | jq -r '.version')" + package_name="$(printf '%s\n' "$release" | jq -r '.package_name')" + log "Resolving release tag ${tag}" + release_info="$( + printf '%s\n' "$releases_json" | jq -s -r --arg tag "$tag" \ + '([.[][] | select(.tag_name == $tag)] | first) as $release + | if $release == null then empty else [$release.html_url, $release.draft] | @tsv end' + )" + + if [[ -z "$release_info" ]]; then + missing_tag="$tag" + break + fi + + IFS=$'\t' read -r release_url release_draft <<<"$release_info" + release_type="published" + if [[ "$release_draft" == "true" ]]; then + release_type="draft" + fi + log "Resolved tag ${tag} to ${release_type} release ${release_url}" + + release_lines+="- ${package_name} ${version}: ${release_url}"$'\n' + done <<<"$release_entries" + + if [[ -z "$missing_tag" ]]; then + break + fi + + retry_reason="No release with tag ${missing_tag} was returned by /repos/${GITHUB_REPOSITORY}/releases" fi - IFS=$'\t' read -r release_url release_draft <<<"$release_info" - release_type="published" - if [[ "$release_draft" == "true" ]]; then - release_type="draft" + if (( release_lookup_attempt == max_release_lookup_attempts )); then + log "$retry_reason" + exit 1 fi - log "Resolved tag ${tag} to ${release_type} release ${release_url}" - release_lines+="- ${package_name} ${version}: ${release_url}"$'\n' -done <<<"$release_entries" + log "${retry_reason}; retrying in ${release_lookup_delay}s" + "$sleep_bin" "$release_lookup_delay" + release_lookup_delay=$((release_lookup_delay * 2)) +done if [[ -z "$release_lines" ]]; then log "No releases in release-plz output; skipping" diff --git a/release-tools/test.sh b/release-tools/test.sh index 2f02bc2..92960a4 100644 --- a/release-tools/test.sh +++ b/release-tools/test.sh @@ -7,6 +7,7 @@ fixture_root="$test_root/project" fake_bin="$test_root/bin" command_log="$test_root/commands.log" comment_log="$test_root/comments.log" +release_attempts_file="$test_root/release-attempts" bash_bin="${BASH_BIN:?BASH_BIN is required}" mkdir -p "$fixture_root" "$fake_bin" @@ -51,7 +52,15 @@ case "$*" in printf '42\n' ;; *'/releases?per_page=100'*) - if [[ "${RELEASE_FOUND:-true}" == "true" ]]; then + release_attempt=1 + if [[ -n "${RELEASE_ATTEMPTS_FILE:-}" ]]; then + if [[ -f "$RELEASE_ATTEMPTS_FILE" ]]; then + release_attempt="$(<"$RELEASE_ATTEMPTS_FILE")" + release_attempt=$((release_attempt + 1)) + fi + printf '%s\n' "$release_attempt" >"$RELEASE_ATTEMPTS_FILE" + fi + if [[ "${RELEASE_FOUND:-true}" == "true" && "$release_attempt" -ge "${RELEASE_AVAILABLE_AT_ATTEMPT:-1}" ]]; then printf '[{"tag_name":"other-v1.0.0","draft":false,"html_url":"https://github.com/example/demo/releases/tag/other-v1.0.0"}]\n' printf '[{"tag_name":"demo-v1.1.0","draft":true,"html_url":"https://github.com/example/demo/releases/tag/untagged-draft-release"},{"tag_name":"other-v1.1.0","draft":false,"html_url":"https://github.com/example/demo/releases/tag/other-v1.1.0"}]\n' else @@ -64,6 +73,14 @@ case "$*" in esac EOF +printf '#!%s\n' "$bash_bin" >"$fake_bin/sleep" +cat >>"$fake_bin/sleep" <<'EOF' +set -euo pipefail +printf 'sleep' >>"$COMMAND_LOG" +printf ' <%s>' "$@" >>"$COMMAND_LOG" +printf '\n' >>"$COMMAND_LOG" +EOF + printf '#!%s\n' "$bash_bin" >"$fake_bin/git" cat >>"$fake_bin/git" <<'EOF' set -euo pipefail @@ -75,13 +92,14 @@ printf ' <%s>' "$@" >>"$COMMAND_LOG" printf '\n' >>"$COMMAND_LOG" EOF -chmod +x "$fake_bin/cargo" "$fake_bin/gh" "$fake_bin/git" +chmod +x "$fake_bin/cargo" "$fake_bin/gh" "$fake_bin/git" "$fake_bin/sleep" export COMMAND_LOG="$command_log" export FIXTURE_ROOT="$fixture_root" export X52_CARGO="$fake_bin/cargo" export X52_GH="$fake_bin/gh" export X52_GIT="$fake_bin/git" +export X52_SLEEP="$fake_bin/sleep" cd "$fixture_root" @@ -161,7 +179,18 @@ export RELEASE_PLZ_RELEASES_JSON='[{"package_name":"demo","version":"1.1.0","tag x52-comment-release-pr "$RELEASE_PLZ_RELEASES_JSON" deadbeef >>"$comment_log" x52-comment-release-assets-uploaded "$RELEASE_PLZ_RELEASES_JSON" deadbeef >>"$comment_log" -[[ "$(grep -Fc 'gh <--paginate> ' "$command_log")" == 8 ]] +[[ "$(grep -Fc 'gh <--paginate> ' "$command_log")" == 16 ]] + +export RELEASE_ATTEMPTS_FILE="$release_attempts_file" +export RELEASE_AVAILABLE_AT_ATTEMPT=2 +RUNNER_DEBUG=1 x52-comment-release-assets-uploaded "$RELEASE_PLZ_RELEASES_JSON" deadbeef >>"$comment_log" + +[[ "$(<"$release_attempts_file")" == 2 ]] +grep -Fq 'No release with tag demo-v1.1.0 was returned by /repos/example/demo/releases; retrying in 1s' "$comment_log" +grep -Fq 'GitHub releases API response:' "$comment_log" +grep -Fq '"tag_name": "demo-v1.1.0"' "$comment_log" +[[ "$(grep -Fc 'sleep <1>' "$command_log")" == 3 ]] +[[ "$(grep -Fc 'gh <--paginate> ' "$command_log")" == 18 ]] cat >"$fixture_root/CHANGELOG.md" <<'EOF' # Changelog