From a84b460ee23ff0bf4acbedefb4beffec428b9279 Mon Sep 17 00:00:00 2001 From: Felitendo Date: Tue, 29 Sep 2026 09:14:48 +0200 Subject: [PATCH] ci: open an issue when a workflow fails on main Also moves the actions off Node 20. --- .github/workflows/build.yml | 8 +- .github/workflows/notify.yml | 110 +++++++++++++++++++++++++ .github/workflows/upstream-release.yml | 6 +- 3 files changed, 117 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/notify.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6131791..66b1caf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,7 +52,7 @@ jobs: steps: - name: Check out Modrinth Enhanced - uses: actions/checkout@v4 + uses: actions/checkout@v7 # Everything below works on the patched tree in build/upstream, so this # has to come first: a patch that no longer applies fails the build here, @@ -70,7 +70,7 @@ jobs: echo "upstream=$UPSTREAM_REF" >> "$GITHUB_OUTPUT" - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@v7 with: node-version-file: build/upstream/.nvmrc @@ -79,7 +79,7 @@ jobs: run: corepack enable - name: Set up Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v6 with: distribution: temurin java-version: 17 @@ -125,7 +125,7 @@ jobs: run: scripts/check.sh - name: Upload installers - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: modrinth-enhanced-${{ matrix.name }} path: build/artifacts/* diff --git a/.github/workflows/notify.yml b/.github/workflows/notify.yml new file mode 100644 index 0000000..b966303 --- /dev/null +++ b/.github/workflows/notify.yml @@ -0,0 +1,110 @@ +name: Notify + +# Opens an issue when a workflow fails on main, so it reaches GitHub's +# notifications, the mobile app and email, and comments on it for every further +# failure. Closes it again once that workflow passes. + +on: + workflow_run: + workflows: [Build, Upstream release] + types: [completed] + +permissions: + actions: read + issues: write + +concurrency: + group: notify-${{ github.event.workflow_run.name }} + cancel-in-progress: false + +jobs: + notify: + name: Notify + runs-on: ubuntu-latest + # A pull request shows its own checks. + if: >- + github.event.workflow_run.event != 'pull_request' && + github.event.workflow_run.head_branch == github.event.repository.default_branch + steps: + - name: Open, update or close the failure issue + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + OWNER: ${{ github.repository_owner }} + WORKFLOW: ${{ github.event.workflow_run.name }} + CONCLUSION: ${{ github.event.workflow_run.conclusion }} + EVENT: ${{ github.event.workflow_run.event }} + RUN_ID: ${{ github.event.workflow_run.id }} + RUN_URL: ${{ github.event.workflow_run.html_url }} + SHA: ${{ github.event.workflow_run.head_sha }} + run: | + set -euo pipefail + title="$WORKFLOW is failing" + label=ci-failure + issue="$( + gh issue list --state open --label "$label" --json number,title | + jq -r --arg title "$title" '.[] | select(.title == $title) | .number' | + head -1 + )" + + case "$CONCLUSION" in + success) + if [ -n "$issue" ]; then + gh issue close "$issue" --comment "Passing again: $RUN_URL" + fi + exit 0 + ;; + failure | timed_out | startup_failure) ;; + *) exit 0 ;; + esac + + failed="$( + gh api "repos/$GH_REPO/actions/runs/$RUN_ID/jobs?per_page=100" --jq ' + .jobs[] | select(.conclusion == "failure" or .conclusion == "timed_out")' + )" + jobs="$( + jq -r '"- [\(.name)](\(.html_url))" + + ([.steps[]? | select(.conclusion == "failure") | .name] | + if length > 0 then ": " + join(", ") else "" end)' <<<"$failed" + )" + + # The lines leading up to the first error of the first failed job, + # enough to see what broke without opening the log. + excerpt="" + job_id="$(jq -r '.id' <<<"$failed" | head -1)" + if [ -n "$job_id" ]; then + excerpt="$( + curl -fsSL -H "Authorization: Bearer $GH_TOKEN" \ + "$GITHUB_API_URL/repos/$GH_REPO/actions/jobs/$job_id/logs" | + sed -E 's/^[0-9TZ:.-]+ //; s/\x1b\[[0-9;]*m//g' | + awk '{ print } /^##\[error\]/ { exit }' | + tail -40 || true + )" + fi + + body="$(cat <