feat(release): warn in Slack about PRs in a release that lack QA verdict#35762
Conversation
Add a standalone TypeScript tool at .github/scripts/release-qa-status that, given a release tag, inspects every PR in the range and reports a QA verdict per PR by reading the labels of its closing-issue references (sourced from GitHub's GraphQL closingIssuesReferences — covers body keywords AND the Development panel). Buckets: - failed: any linked issue carries `QA : Failed` - missing: linked but no recognized QA label - unlinked: no closing-issue reference at all - external: only cross-repo closing refs (cannot verify QA from here) - passed: every linked issue is `QA : Passed` or `QA : Not Needed` - excluded: bots / dependency bumps / release machinery Wire the tool into the release pipeline's Report step (cicd_6-release.yml). The QA section is appended to the existing Slack release announcement only when there is something to flag, and the step is non-blocking — any failure leaves the announcement intact without a QA section. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Claude finished @nollymar's task in 3m 33s —— View job ReviewA few things worth a second look. Bugs / correctness1. Stale "more than 50" warning text — 2. Closing-issue refs are not paginated — 3. Commit pagination + if (response.data.commits.length < perPage) break;fires after the first page (because 100 < 250), even when This mirrors Minor4. 5. 6. Asymmetric error handling between batches — Looks clean
|
Failure isolation: every QA-coverage step in the Report job is now continue-on-error: true so a transient `actions/setup-node` or `npm ci` failure cannot block the Slack release announcement. LTS / CLI skip: the QA steps now bail early on non-standard tags (`_lts_`, `dotcms-cli-`, anything not v-prefixed), matching the existing AI release-notes phase. GraphQL failure handling: closingIssuesReferences batch errors are re-thrown instead of swallowed — silently returning empty refs caused every PR in the failing batch to be misclassified as `unlinked` and spammed the Slack channel with bogus orphan-PR rows. The outer continue-on-error still drops the QA section if anything throws. Bot detection: tightened login matching from .includes() to .startsWith() on a known-prefix list, so accounts like `fan-of-github-actions` are no longer treated as bots. Slack message polish: header emoji escalates to 🚨 when any PR failed QA; titles longer than 140 chars end with an ellipsis; the workflow no longer emits a trailing blank line on healthy releases (empty `qa_warning` round-trips cleanly through the quoted SLACK_MESSAGE). Text output: excluded PRs now render with their reason for easier debugging. Documentation: added comments calling out the squash-merge assumption on `extractPRNumbers` and the GraphQL alias safety constraint. Tests: added jest + ts-jest with unit coverage for `classifyExclusion`, `computePRQA`, and `renderSlack` (26 cases). The pure aggregation rules, bot exclusion edge cases, and Slack rendering are now verified. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Thanks for the thorough review. Addressed in 4750742: Fixed
Tests all green (26/26). |
Tag-list race (#1): when the just-cut release tag isn't yet visible in the GitHub releases API (eventual consistency), fall back to the newest indexed tag as the predecessor instead of exiting 1 silently. The listReleases response is sorted newest-first, so tags[0] is the previous standard release. Also added a guard for an empty tag list. allSettled on issue fetch (#3): switched fetchIssueInfos from Promise.all to Promise.allSettled so a single transient 5xx on an issue lookup can no longer drop the entire QA section. Failed entries are treated the same as notFound — qa.ts already ignores both. Closing-refs page size (#2): bumped first: 50 to first: 100 in closingIssuesReferences. PRs with >100 closing refs still emit the hasNextPage stderr warning but the cap is now generous enough that no real PR will hit it. Squash-merge silent failure (#4): if extractPRNumbers returns zero for a non-empty commit list, emit an explicit stderr warning naming the likely cause (merge strategy change on `main`). Keeps the failure mode visible if dotCMS ever moves off squash-merge. GraphQL alias safety (#5): added a Number.isInteger guard in the alias builder. Type-system-wise nothing stopped a future caller from passing NaN or a negative integer; the guard enforces the trust boundary at fetchClosingIssueRefs rather than relying on the comment. Backtick escape in Slack output (#6): `escapeSlack` now replaces backticks with apostrophes so PR titles like "bump deps to `v1.2.3`" don't render the version as monospace in Slack. Excluded blurb (#9): renderText excluded-section blurb now lists all four exclusion reasons (bot / dependency-bump / version-bump / release-machinery) so it matches what classifyExclusion actually returns. Tests: added cases for same-repo missing winning over coexistent externalRefs (#10) and for backtick replacement in Slack titles. 28/28 pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Second round addressed in 37c1f69:
Not addressed:
Tests: 28/28 pass. |
#35815) Closes #35825 ## Summary Follow-up to #35762. Two issues surfaced from the first real-release Slack notification: 1. The QA section was too tall — Slack collapsed it behind a "Show more" so the per-PR detail was effectively hidden. 2. The `@author` text wasn't real Slack mentions, so the people whose action was needed never got notified. ## Approach **Slack message stays compact.** Just counts + a cc line: ``` :rotating_light: *QA Coverage* — 14 PRs need review <run-url|failed QA: 1> | <run-url|missing QA: 12> | <run-url|Orphan PRs: 1> | <run-url|Not in the core repo: 0> cc <@U05R06D9YSX> @adrianjm-dotCMS @dario-daza <@UCF6CLC6L> ... — please review your PRs in this release. ``` - Each count is a link to the workflow run summary. - Authors of failed / missing / orphan / external PRs are mentioned. Mapped users (via `.github/data/slack-mappings.json`) get real `<@userid>` mentions that actually notify. Unmapped users fall back to plain `@login` so they're still named. - The header escalates to `:rotating_light:` whenever any PR is in the `failed` bucket. **Detail moves to the workflow run summary.** A new `--format markdown` produces a GitHub-flavored markdown report (tables per bucket, links to issues, label cells) written to `\$GITHUB_STEP_SUMMARY`. Reviewers land there by clicking any count in Slack. ## New CLI flags on `release-qa-status` ``` --format markdown GitHub-flavored markdown — for $GITHUB_STEP_SUMMARY --mappings PATH slack-mappings.json for GH → Slack ID resolution --detail-url URL link target for each count in the slack output ``` ## Workflow changes The Report step in `cicd_6-release.yml` now runs the script twice: 1. `--format markdown` → appended to `\$GITHUB_STEP_SUMMARY` 2. `--format slack --mappings ... --detail-url <run-url>` → injected into `SLACK_MESSAGE` Both calls are best-effort (`continue-on-error: true`); a failure leaves the announcement intact. ## Validation End-to-end against `v26.05.22-01` with the real mappings: - Slack snippet renders 14 flagged PRs as 4 count links + 1 cc line — well within Slack's inline-display limit. - Mapped users (`dsilvam`, `hassandotcms`, `fmontes`, ...) become real Slack mentions. - Unmapped users (`adrianjm-dotCMS`, `dario-daza`, `ihoffmann-dot`) fall back to plain `@login`. - Markdown summary renders correctly with bucket tables and inline labels. Tests: **35/35 pass** (previously 28/28). New cases cover detailUrl wrapping, mapped + unmapped + deduped + case-insensitive author resolution, exclusion of passed-bucket authors from the cc, and the markdown format. ## Test plan - [ ] Manual workflow_dispatch run with `notify_slack=true` against a release - [ ] Confirm Slack message renders without truncation and that mentions notify the mapped users - [ ] Confirm workflow run summary contains the full markdown report - [x] (Out of scope here) update `slack-mappings.json` for any newly-contributing authors so they get real mentions next time 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Adds a QA-coverage warning to the Slack notification we send when a release is generated. For every PR in the release, the new tool inspects its closing-issue references and reports whether the linked issue carries a recognized QA label.
Driven by the question: "which changes shipped in this release haven't been tested?"
How it works
New standalone tool at
.github/scripts/release-qa-status/(TypeScript, mirrors the shape ofgather-release-dataso the two can be consolidated later).For each PR between the previous and current release tag:
closingIssuesReferences(catches body keywords and Development-panel links) and bucket:QA : FaileddotCMS/private-issues#N) — cannot verify QA from hereQA : PassedorQA : Not NeededThe release workflow (
.github/workflows/cicd_6-release.yml) Report job now installs and runs the tool with--format slack, capturing the output intoSLACK_MESSAGE. The step iscontinue-on-error: true— any failure leaves the announcement intact without a QA section, never blocking a release.Slack message (when something is flagged)
Healthy releases keep the current short message. Otherwise the announcement gains a section like:
Validation
Ran the tool locally against recent releases:
v26.05.19-01v26.05.18-01v26.05.11-01Spot-checked every verdict against
gh issue view— labels and statuses line up.Dry-ran the new bash step locally with the same logic the workflow will execute; the multi-line
GITHUB_OUTPUTcapture round-trips correctly into the Slack action's env var.Follow-up
Filed #35763 to migrate
gather-release-datato the same GraphQL approach so release-notes bullets stop missing their issue cross-links. Scoped separately to keep this PR focused.Test plan
cicd_6-release.ymlwithnotify_slack=falseagainst a recent release tag — verifies the new steps are correctly gated.notify_slack=trueagainst a release whose previous tag is auto-resolvable — verify the QA section renders in #release Slack channel.🤖 Generated with Claude Code