chore: CI badge, mirror PR explainer, and the tag-pin release step (#47) #66

Merged
jared merged 1 commits from chore/release-47-badges-mirror-pr into main 2026-08-11 09:44:34 -04:00
Owner

The three items #47 absorbed from #46. Held back deliberately so a dead badge would not
sit next to an unresolved r-universe one — both resolve now that v0.4.0 is tagged and
mirrored.

R-CMD-check badge

Points at the GitHub mirror's workflow, which is where the 4-platform matrix runs.
The Gitea CI is single-platform and not publicly reachable, so it would be the wrong
badge for a public README.

Mirror PR explainer

A pull_request_target workflow that comments on every incoming PR.

The problem it solves is specific: a PR opened on the mirror is landed on Gitea and syncs
back, and because that merge preserves the contributor's commits at their original SHAs,
GitHub marks the PR "Merged" on its own — no visible merge click, possibly no review
comment first. To a first-time contributor that is indistinguishable from being ignored
and closed. The comment says so before it happens.

pull_request_target, not pull_request, and the reason matters: a fork PR under
pull_request gets a read-only token, so it cannot post a comment — which is the entire
job. pull_request_target runs in the base repo's context with a writable token.

That is only safe because the job never checks out or executes contributor code — it
posts a fixed string, and the only dynamic value is the PR number (an integer, used as a
JS value, never interpolated into a shell). The file carries a comment saying not to add
a checkout of head.sha, since that combination is the standard pull_request_target
privilege-escalation hole. permissions: is narrowed to pull-requests: write.

CONTRIBUTING release checklist

Two things learned doing this release, now written down:

  • The tag goes on Gitea; the mirror workflow carries it to GitHub. Verified end to
    end for the first time with v0.4.0 — tag present on the mirror, HEADs identical.
  • r-universe does not pick up a release until packages.json's branch pin is
    edited.
    The pin is a tag deliberately, so a mid-refactor main is never published as
    a release. "branch": "*release" would automate it, but it requires a GitHub Release
    object and the mirror pushes tags only — so it would silently never update. That is
    a trap worth one sentence now rather than a confused hour later.

Verification

README-asserting tests pass 34/34, 0 failures. Both workflow files parse as valid YAML.
pr-welcome.yaml contains no run: step, no checkout, and no ${{ }} interpolation at
all — confirmed by grep, not by eye.

The three items #47 absorbed from #46. Held back deliberately so a dead badge would not sit next to an unresolved r-universe one — both resolve now that `v0.4.0` is tagged and mirrored. ## R-CMD-check badge Points at the **GitHub mirror's** workflow, which is where the 4-platform matrix runs. The Gitea CI is single-platform and not publicly reachable, so it would be the wrong badge for a public README. ## Mirror PR explainer A `pull_request_target` workflow that comments on every incoming PR. The problem it solves is specific: a PR opened on the mirror is landed on Gitea and syncs back, and because that merge preserves the contributor's commits at their original SHAs, **GitHub marks the PR "Merged" on its own** — no visible merge click, possibly no review comment first. To a first-time contributor that is indistinguishable from being ignored and closed. The comment says so before it happens. **`pull_request_target`, not `pull_request`, and the reason matters:** a fork PR under `pull_request` gets a read-only token, so it cannot post a comment — which is the entire job. `pull_request_target` runs in the base repo's context with a writable token. That is only safe because the job **never checks out or executes contributor code** — it posts a fixed string, and the only dynamic value is the PR number (an integer, used as a JS value, never interpolated into a shell). The file carries a comment saying not to add a checkout of `head.sha`, since that combination is the standard `pull_request_target` privilege-escalation hole. `permissions:` is narrowed to `pull-requests: write`. ## CONTRIBUTING release checklist Two things learned doing this release, now written down: - The tag goes on **Gitea**; the mirror workflow carries it to GitHub. Verified end to end for the first time with `v0.4.0` — tag present on the mirror, HEADs identical. - **r-universe does not pick up a release until `packages.json`'s `branch` pin is edited.** The pin is a tag deliberately, so a mid-refactor `main` is never published as a release. `"branch": "*release"` would automate it, but it requires a GitHub *Release* object and the mirror pushes **tags** only — so it would silently never update. That is a trap worth one sentence now rather than a confused hour later. ## Verification README-asserting tests pass 34/34, 0 failures. Both workflow files parse as valid YAML. `pr-welcome.yaml` contains no `run:` step, no checkout, and no `${{ }}` interpolation at all — confirmed by grep, not by eye.
jared added 1 commit 2026-08-10 19:47:48 -04:00
chore: CI badge, mirror PR explainer, and the tag-pin release step (#47)
R-CMD-check / check (pull_request) Successful in 3m49s
R-CMD-check / check (push) Successful in 3m52s
5f81ae386b
Three items #47 absorbed from #46, held back so a dead badge would not sit
beside an unresolved r-universe one. Both resolve now that v0.4.0 is tagged.

- R-CMD-check badge pointing at the GitHub mirror's workflow, where the
  4-platform matrix actually runs.

- A pull_request_target workflow explaining the mirror flow on every incoming
  PR. A PR here is landed on Gitea and syncs back, and because the merge
  preserves the contributor's commits at their original SHAs, GitHub marks the
  PR 'Merged' with nobody visibly clicking Merge. To a first-time contributor
  that reads as rejection. Say so before it happens.

  pull_request_target rather than pull_request because a fork PR's token is
  read-only under the latter -- it could not comment, which is the entire job.
  That is only safe because this never checks out or runs contributor code; the
  file says so and says not to add a checkout.

- CONTRIBUTING's release checklist now spells out that the tag goes on Gitea and
  the mirror carries it, and that r-universe does NOT pick up a release until
  packages.json's branch pin is edited. '*release' would automate it but needs a
  GitHub Release object, and the mirror pushes tags only -- so it would silently
  never update. Learned while doing this release.
jared merged commit 224e5d0530 into main 2026-08-11 09:44:34 -04:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Civilytics/uscogdata#66