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.
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.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
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.0is tagged andmirrored.
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_targetworkflow 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, notpull_request, and the reason matters: a fork PR underpull_requestgets a read-only token, so it cannot post a comment — which is the entirejob.
pull_request_targetruns 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 standardpull_request_targetprivilege-escalation hole.
permissions:is narrowed topull-requests: write.CONTRIBUTING release checklist
Two things learned doing this release, now written down:
end for the first time with
v0.4.0— tag present on the mirror, HEADs identical.packages.json'sbranchpin isedited. The pin is a tag deliberately, so a mid-refactor
mainis never published asa release.
"branch": "*release"would automate it, but it requires a GitHub Releaseobject 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.yamlcontains norun:step, no checkout, and no${{ }}interpolation atall — confirmed by grep, not by eye.