Skip to content

Commit c2a8364

Browse files
committed
docs(release): document admin-pushed promotion and the one-time repository setup
1 parent 3c687ab commit c2a8364

1 file changed

Lines changed: 42 additions & 9 deletions

File tree

‎CONTRIBUTING.md‎

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -95,18 +95,17 @@ stay unpublished. There are three channels:
9595
- **Nightly** (`npm install -g agent-device@nightly`): every few hours the workflow checks `main`.
9696
It publishes `X.Y.Z-nightly.<YYYYMMDD>.<run>` under the `nightly` dist-tag when `main`'s HEAD has
9797
changed since the last nightly, its CI passed, and no nightly shipped that UTC day. It then tags
98-
the commit `v<nightly version>`. To publish one now, run **Release** with `channel: nightly`.
99-
- **Stable** (`latest`): run **Release** with `channel: stable`. It promotes the latest nightly's
100-
commit, by default as the `X.Y.Z` that nightly previewed. Set `version` to release it under
101-
another number. The run tags that commit `vX.Y.Z` and starts the stable run on the tag. The stable
102-
run waits for approval in the `release` environment, then publishes the packages, drafts the GitHub
103-
release with generated notes, attaches the iOS runner and Android helper assets, publishes the
104-
release and the MCP Registry entry, and commits `main`'s next `-dev` version. Pushing a `vX.Y.Z`
105-
tag yourself starts the same stable run for that commit.
98+
the commit `nightly/v<nightly version>`. To publish one now, run **Release** on `main`.
99+
- **Stable** (`latest`): a repository admin runs `pnpm release:promote`. It pushes `vX.Y.Z` at the
100+
latest nightly's commit, by default as the `X.Y.Z` that nightly previewed; pass a version, such as
101+
`pnpm release:promote 0.22.0`, to release it under another number. The tag's **Release** run waits
102+
for approval in the `release` environment, then publishes the packages, drafts the GitHub release
103+
with generated notes, attaches the iOS runner and Android helper assets, publishes the release and
104+
the MCP Registry entry, and commits `main`'s next `-dev` version.
106105
- **Dry run**: a pull request that changes release tooling builds and verifies every package with a
107106
nightly version, and publishes nothing.
108107

109-
To retry a failed run, re-run its failed jobs. The publisher skips package versions that are already
108+
To retry a failed run, re-run its failed jobs, or run **Release** on the release tag. The publisher skips package versions that are already
110109
on npm, so a partial publish completes on the next attempt. To preview the packages locally, run
111110
`pnpm release:prepare`. It builds, verifies, and packs every public package into `.tmp/release`.
112111

@@ -131,6 +130,40 @@ npm trust github @agent-device/<name> --file release.yml --repository callstack/
131130
npm access set mfa=publish @agent-device/<name>
132131
```
133132

133+
### One-time repository setup
134+
135+
npm trusts every run of `release.yml` that reaches the `npm-publish` environment, so GitHub
136+
settings, not the workflow, decide who can publish. The plan job refuses to publish until the first
137+
three are in place. Apply them before granting npm trust:
138+
139+
1. **Environment `npm-publish`** (Settings → Environments): deployment branches and tags limited to
140+
the branch `main` and the tag pattern `v*`. No reviewers and no secrets, so nightlies run
141+
unattended.
142+
2. **Environment `release`**: required reviewers. Turn on "Prevent self-review" only when another
143+
maintainer can approve, because the admin who pushes the tag cannot approve their own run.
144+
3. **Tag ruleset** (Settings → Rules → Rulesets → New tag ruleset): active, targeting
145+
`refs/tags/v*`, restricting creations, updates, and deletions, with only the Repository admin
146+
role allowed to bypass. Nightly tags live under `nightly/` and stay outside it.
147+
4. **Actions** (Settings → Actions → General): workflow permissions set to read repository contents,
148+
and "Allow GitHub Actions to create and approve pull requests" turned off.
149+
150+
Confirm the result, then grant npm trust to each public package and, once a nightly has published,
151+
refuse token-based publishing:
152+
153+
```bash
154+
gh api repos/callstack/agent-device/environments/npm-publish/deployment-branch-policies \
155+
--jq '.branch_policies[] | "\(.type) \(.name)"' # branch main, tag v*
156+
gh api repos/callstack/agent-device/environments/release \
157+
--jq '.protection_rules[] | select(.type == "required_reviewers")'
158+
gh api repos/callstack/agent-device/rulesets --jq '.[] | select(.target == "tag") | .name'
159+
npm trust github <package> --file release.yml --repository callstack/agent-device \
160+
--environment npm-publish --allow-publish --yes
161+
npm access set mfa=publish <package>
162+
```
163+
164+
Anyone who can push to `main` can still change what the next nightly publishes; `main` does not
165+
require pull requests.
166+
134167
### The version on main never equals a published version
135168

136169
`main` carries `X.Y.Z-dev`, naming the release it is building towards. Nightlies preview it as

0 commit comments

Comments
 (0)