Files
unleashed-firmware/.github
Mykhailo ShevchukandClaude Opus 5 c21c79bfba CI: guard PRs and their linked issues against the Backlog milestone (#1162)
* CI: guard PRs and their linked issues against the Backlog milestone

Anything with an implementation belongs in the release it ships in. A PR
parked on Backlog - or on no milestone at all - drops out of the release
notes and out of the milestone-per-release tracking, and so does an issue
that is actively being implemented.

The check fails when the PR has no milestone or sits on Backlog, and when
any issue the PR closes does the same. Linked issues come from GitHub's own
closingIssuesReferences rather than from grepping the description, so it
sees exactly what the merge will close; a PR that closes nothing is fine.
Issues nobody is implementing are never looked at - they may stay in
Backlog or be closed with a reason.

Nothing is checked out and every permission is read-only, so plain
pull_request stays safe for fork PRs. milestoned/demilestoned are in the
trigger list so setting the milestone re-runs the check by itself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* CI: close the fail-open paths in the milestone guard

Review of #1162 found three ways the guard could pass a PR it had not
actually checked.

grep read the milestone title as its own options when the title started
with a dash, exited 2, and is_blocked reported "not blocked" - a guard
failing open. The blocklist is now normalised once, with blank lines
stripped (an empty line made is_blocked "" return true, harmless only
because both callers tested for empty first) and matched with `--`. An
empty list now refuses to run instead of silently passing everything.

closingIssuesReferences was capped at 50 with nothing reading totalCount,
so references past the cap vanished. The count is now fetched and
exceeding it fails. A row the loop cannot parse used to be skipped
silently; it now reports. Merging stderr into the captured data meant a
stray gh warning became a data row and suppressed the "closes nothing"
line, so stderr goes to its own file - which also lets the annotation lead
with gh's one-line reason instead of 400 characters of raw JSON body.

Cross-repo issues warn rather than notice: skipping one is a real pass for
an unchecked issue. The PR and issue branches were identical bar their
wording and are now one helper.

Comments: the security note credited the permissions block for fork-PR
safety. A fork ships its own copy of this file - what protects us is
GitHub capping the token read-only, as pr-build.yml already says. Also
corrected the claim that only Closes/Fixes are seen (every closing keyword
and sidebar links are) and documented the cross-repo carve-out.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* CI: run the milestone guard through github-script

Most of the step was transport, not logic: build a query string, shell out
to gh, flatten objects to TSV, smuggle totalCount in as the first output
line, capture stderr to a temp file, reverse-engineer gh's error layout for
a readable reason, check that line one is a number, re-split TSV in a read
loop. actions/github-script is already a dependency here (pr-comment.yml)
and hands back an object, so all of that goes.

It also deletes the row contract that lived in three places at once - the
jq projection, the head/tail split and the field unpacking. Adding a field
to the query and forgetting the unpacking would have shifted a column into
the milestone variable, where an unrecognised title reads as "not blocked"
and the check passes a PR it should fail, green and silent.

Three things that were awkward in bash and are now cheap:

The PR's own milestone comes from the API rather than the event payload, so
both halves of the check are equally fresh. A re-run from the Checks tab
replays the original payload, which is the one workflow the file tells
people to use for a changed issue milestone.

The call is retried twice on a 5xx or a dropped connection. It runs on
every push, so at roughly a thousand calls per release cycle even a rare
transient becomes a red X no contributor can clear. A GraphQL error is the
server answering rather than failing, so those are not retried.

A milestone that is neither blocked nor unlshd-NNN now warns. A deny-list
cannot tell a new release from a new parking lot, and a typo'd unlshd-94
passed silently before. Warning rather than failing keeps the policy where
it was: contributors cannot set milestones, so a red X they are not allowed
to clear is worse than a leaked unusual milestone.

Error text now addresses the maintainer, since triage permission is what
setting a milestone needs. Documented that none of this gates anything
until "Release milestone" is a required status check.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 13:05:57 +03:00
..
2023-08-24 04:51:44 +03:00