From bb2c7915eec4d55eb7aae77c00c3fbdd5d12f47e Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Mon, 9 Nov 2026 16:19:14 +0000 Subject: [PATCH] ci: Track release pipeline failures and stuck releases in an issue Co-Authored-By: BYK <126780+BYK@users.noreply.github.com> --- .github/scripts/check-release-staleness.sh | 66 +++++++++++++++++ .github/scripts/pipeline-issue.sh | 54 ++++++++++++++ .github/workflows/release-pipeline-health.yml | 74 +++++++++++++++++++ 3 files changed, 194 insertions(+) create mode 100755 .github/scripts/check-release-staleness.sh create mode 100755 .github/scripts/pipeline-issue.sh create mode 100644 .github/workflows/release-pipeline-health.yml diff --git a/.github/scripts/check-release-staleness.sh b/.github/scripts/check-release-staleness.sh new file mode 100755 index 0000000..5204011 --- /dev/null +++ b/.github/scripts/check-release-staleness.sh @@ -0,0 +1,66 @@ +#!/bin/sh +# Reports a stuck @sentry/api release through pipeline-issue.sh. A release is +# stuck when a "Generated" schema commit on main has waited more than a day to +# reach npm, or when a publish request has had failed CI for more than a day. +# +# Run from a checkout of main with full history and tags. +# +# Environment: +# GH_TOKEN Token that can read this repository's and the publish +# repository's issues, and write this repository's issues. +# GITHUB_REPOSITORY, GITHUB_REPOSITORY_OWNER and GITHUB_SERVER_URL come from +# GitHub Actions. +set -eu + +max_age=86400 +here=$(dirname "$0") +repo_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" +# Craft files publish requests in /publish by default. +publish_repo="$GITHUB_REPOSITORY_OWNER/publish" +now=$(date +%s) +problems= + +package=$(jq -er .name package.json) +latest=$(npm view "$package" version) + +if ! git rev-parse -q --verify "refs/tags/$latest^{commit}" >/dev/null; then + problems="$problems +- \`$package@$latest\` is the newest version on npm, but this repository has no \`$latest\` tag." +else + # Oldest first, so the first line is the commit that has waited longest. + waiting=$(git log --no-merges --reverse --grep='^Generated$' --format='%H %ct' "$latest..HEAD") + read -r sha committed <&2 + exit 2 + ;; +esac + +open_issues=$(gh issue list -R "$GITHUB_REPOSITORY" --state open --limit 1000 --json number,title) +number=$(jq -r --arg t "$title" '[.[] | select(.title == $t)] | first | .number // empty' <- + github.event_name == 'workflow_run' && + github.event.workflow_run.head_repository.full_name == github.repository && + (github.event.workflow_run.name == 'Release' || github.event.workflow_run.event == 'push') && + ( + github.event.workflow_run.conclusion == 'failure' || + (github.event.workflow_run.name == 'Release' && github.event.workflow_run.conclusion == 'success') + ) + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ github.token }} + RUN_LINK: "[${{ github.event.workflow_run.name }} run #${{ github.event.workflow_run.run_number }}](${{ github.event.workflow_run.html_url }})" + COMMIT_LINK: "[`${{ github.event.workflow_run.head_sha }}`](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.event.workflow_run.head_sha }})" + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + + - name: Report the failure + if: github.event.workflow_run.conclusion == 'failure' + env: + MESSAGE: ${{ env.RUN_LINK }} failed on `main` at ${{ env.COMMIT_LINK }}. + run: .github/scripts/pipeline-issue.sh report + + - name: Close the issue + if: github.event.workflow_run.conclusion == 'success' + env: + MESSAGE: ${{ env.RUN_LINK }} succeeded on `main` at ${{ env.COMMIT_LINK }}. + run: .github/scripts/pipeline-issue.sh resolve + + # Catch releases that are stuck without a failing run, such as a release + # branch that never merged. + check-staleness: + name: Check for a stuck release + if: github.event_name != 'workflow_run' + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ github.token }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + ref: main + # The check needs history and tags, but not the schema blobs. + fetch-depth: 0 + filter: blob:none + + - run: .github/scripts/check-release-staleness.sh