From 36fe3bab2c21a5f31fc08ccd5e49a40180eea571 Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Sun, 4 Oct 2026 12:59:13 +0300 Subject: [PATCH] feat: share the scheduled-failure report as a reusable workflow --- .github/workflows/links.yml | 2 +- .../workflows/report-scheduled-failure.yml | 33 +++++++++++++++++++ docs/standard.md | 18 ++++++++-- 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/report-scheduled-failure.yml diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index cbb559f..e9e8b55 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -35,7 +35,7 @@ jobs: fail: false # create-issue-from-file does not deduplicate — it calls issues.create # unconditionally, so six weeks of one dead link is six identical issues. This is - # the same find-or-comment shape every repo's report-scheduled-failure.sh uses. + # the same find-or-comment shape as the shared report-scheduled-failure.yml. - name: Open or update the tracking issue if: steps.lychee.outputs.exit_code != 0 env: diff --git a/.github/workflows/report-scheduled-failure.yml b/.github/workflows/report-scheduled-failure.yml new file mode 100644 index 0000000..8e55b24 --- /dev/null +++ b/.github/workflows/report-scheduled-failure.yml @@ -0,0 +1,33 @@ +name: report-scheduled-failure + +# Called by every repo's scheduled.yml when its scheduled checks fail (standard CI2). +on: + workflow_call: {} + +jobs: + report: + runs-on: ubuntu-latest + steps: + - name: Open or update the tracking issue + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + run: | + set -euo pipefail + LABEL="scheduled-failure" + # --force makes this idempotent: it creates the label, or updates it in place. + gh label create "$LABEL" \ + --color "FBCA04" \ + --description "Scheduled dependency check failures" \ + --force + existing=$(gh issue list --label "$LABEL" --state open --json number --jq '.[0].number // empty') + if [ -z "$existing" ]; then + gh issue create --title "Scheduled dependency check failed" --label "$LABEL" --body "$(printf '%s\n\n%s\n\n%s\n\n%s' \ + "The scheduled dependency check failed." \ + "First failing run: ${RUN_URL}" \ + "Likely cause: a new release of a dependency or of Python broke the build; the failing job in the run shows where. Reproduce locally with \`just install\`, then \`just lint\` and \`just test\`." \ + "Close this issue once fixed. The next scheduled failure will open a fresh issue.")" + else + gh issue comment "$existing" --body "Failed again: ${RUN_URL}" + fi diff --git a/docs/standard.md b/docs/standard.md index 9ac1e6f..353a363 100644 --- a/docs/standard.md +++ b/docs/standard.md @@ -181,10 +181,24 @@ superseded runs. `scheduled.yml` MUST run daily and on `workflow_dispatch`, running the same checks as `ci.yml` except `floors` ([CI6](#CI6)). On a scheduled failure it MUST open or update a tracking issue in the -repo. +repo with this job, byte for byte, and a repo MUST NOT keep its own report script: + +```yaml + report-failure: + needs: checks + if: failure() && github.event_name == 'schedule' + permissions: + issues: write + uses: modern-python/.github/.github/workflows/report-scheduled-failure.yml@main +``` *Why:* a dependency release or a new Python that breaks the build becomes a ticket without anyone -watching. +watching. The report is shared because the per-repo copies drifted: each named its own list of +likely culprits, and several listed a dependency the repo does not have. The issue links the failing +run, which shows the failing job, so the shared text stays generic. It takes no inputs, +so it does not hit what sank a shared `_checks.yml` ([CI3](#CI3)). Like the ADR check +([CI9](#CI9)), it tracks `main` unpinned, so a change reaches every repo's next scheduled failure at +once. ### CI3 · Per-repo `_checks.yml` { #CI3 }