Files
MeshTerm/.github/workflows/issue-trailers.yml
T
Jean-Pierre MartineauandClaude Opus 5 cf934e781f The form stops asking for what the tool already writes down
Nine of the bug form's fourteen fields were transcription: version, host, OS,
terminal, size, platform, device model, firmware, transport. `meshterm
diagnostics --out` writes every one of them, correctly, from the machine that
has the problem, and the form went on asking a tired person to copy them out by
hand.

A field that demands precision from someone who does not have it does not
produce precision. It produces an abandoned form, or an invented answer -- a
reporter guessing at their radio's chip name because the form would not let them
past without one. A guess is worse than a blank, because it reads as a fact.

So the required set drops from nine fields to five, and not one of the five asks
for something the reporter has to look up: what happened, how often, how to
repeat it, whether `--mock` changes it, and the diagnostics block itself.

Two of the cut fields came back as optional, because the block genuinely cannot
know them. It reads the model and firmware off the radio, so a report about a
radio that will not connect -- the most common first-run report there is -- has
nothing to read them from. And `platform` only separates PicoCalc from regular,
so a uConsole and a laptop look alike to it. Both fields now say exactly when
they apply, which is rarely.

The command itself lands in 0.9.0 and the released build is 0.3.7, so both the
form and the forum say what to do when it is not recognised: name your version
and send what you can. That line comes out once nobody is running an older one.

The trailer workflow inverts the obvious design. It does not nag about commits
with no issue trailer, because most commits here legitimately close nothing and
a workflow that complains about all of them gets muted within a week. It checks
the trailers that are there: `Fixes: #42` against an issue that does not exist
is not an error in GitHub's eyes, it is silence -- the issue stays open, the
reporter is never told, and the commit looks like it did the job. That is the
failure worth a comment.

Four labels join the stock set for the states a report actually passes through:
needs-diagnostics, confirmed, needs-hardware, cannot-reproduce. They say what
state a thing is in. The hardware goes in the title, where it does not
multiply.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 13:13:39 -04:00

85 lines
3.3 KiB
YAML

name: Issue trailers
# A commit that names an issue is the only thing connecting a fix to the person
# who reported it. GitHub resolves that link silently: `Fixes: #42` against an
# issue that does not exist is not an error, it is nothing at all -- the issue
# stays open, the reporter is never told, and the commit looks like it did the
# job. A typo costs a whole loop and announces itself nowhere.
#
# So this checks the trailers that ARE there rather than nagging about the ones
# that are not. Most commits here are internal work that legitimately closes
# nothing, and a workflow that complains about all of them gets muted in a week.
#
# Cross-repo trailers (`Fixes: owner/repo#12`) are reported but not verified:
# GITHUB_TOKEN only reaches this repository.
on:
push:
branches: [main]
permissions:
contents: write # to leave a comment on the offending commit
issues: read
jobs:
check:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[skip ci]')"
steps:
- name: Verify every issue named in a trailer exists
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
COMMITS: ${{ toJSON(github.event.commits) }}
run: |
set -euo pipefail
echo "$COMMITS" > /tmp/commits.json
count=$(jq 'length' /tmp/commits.json)
echo "checking $count commit(s)"
problems=0
for i in $(seq 0 $((count - 1))); do
sha=$(jq -r ".[$i].id" /tmp/commits.json)
msg=$(jq -r ".[$i].message" /tmp/commits.json)
short="${sha:0:8}"
# Trailers only: a line that starts with the keyword. A bare "#12"
# in prose is a reference someone wrote on purpose, not a claim
# that this commit closes anything.
refs=$(printf '%s\n' "$msg" \
| grep -oiE '^(fixes|closes|resolves|refs|see):[[:space:]]*([A-Za-z0-9._-]+/[A-Za-z0-9._-]+)?#[0-9]+' \
|| true)
[ -z "$refs" ] && continue
while IFS= read -r ref; do
[ -z "$ref" ] && continue
target=$(printf '%s' "$ref" | sed -E 's/^[A-Za-z]+:[[:space:]]*//')
num="${target##*#}"
if [ "$target" != "#${num}" ]; then
repo="${target%%#*}"
echo " $short -> $target (other repository, not verified here)"
continue
fi
if state=$(gh api "repos/$REPO/issues/$num" --jq .state 2>/dev/null); then
echo " $short -> #$num ($state)"
else
echo "::error::commit $short names #$num, which does not exist in $REPO"
problems=$((problems + 1))
gh api "repos/$REPO/commits/$sha/comments" \
-f body="This commit's trailer names **#$num**, which does not exist in \`$REPO\`.
GitHub resolves a closing keyword silently, so nothing failed and nothing was linked — the issue this was meant to close is still open, and whoever reported it has not been told. Worth a follow-up commit with the right number, or a note on the issue itself." \
>/dev/null
fi
done <<< "$refs"
done
if [ "$problems" -gt 0 ]; then
echo "::warning::$problems trailer(s) pointed at issues that do not exist"
fi