@@ -39,24 +39,47 @@ official release builds for Node.js, hosted on <https://nodejs.org/>. |
39 | 39 |
|
40 | 40 | ## Who can make a release? |
41 | 41 |
|
42 | | -Release authorization is given by the Node.js TSC. Once authorized, an |
43 | | -individual must have the following: |
| 42 | +There is a distinction between individuals who can "prepare" a release by |
| 43 | +adding the commits to the branches in GitHub and those who can "publish" the |
| 44 | +releases to nodejs.org. |
| 45 | + |
| 46 | +Individuals who are Members of the |
| 47 | +[backporters team](https://github.com/orgs/nodejs/teams/backporters) |
| 48 | +(restricted link) can land things on the staging branches and prepare |
| 49 | +releases including creating the proposal branches which will be discussed |
| 50 | +later in this document. |
| 51 | + |
| 52 | +Authorization to publish releases is given by the Node.js TSC. This is |
| 53 | +required to publish a release after it has been prepared. If you are working |
| 54 | +on preparing a release for the first time you will be able to do most of the |
| 55 | +steps as a member of the backporters team and have someone else who is |
| 56 | +already onboarded promote the release on your behalf. Once authorized by the |
| 57 | +TSC as a releaser, an individual will require the following to publish |
| 58 | +releases themselves: |
44 | 59 |
|
45 | 60 | ### 1. Jenkins release access |
46 | 61 |
|
47 | | -There are three relevant Jenkins jobs that should be used for a release flow: |
| 62 | +There are four relevant Jenkins jobs that should be used for a release flow: |
48 | 63 |
|
49 | 64 | **a.** **Test runs:** |
50 | 65 | **[node-test-pull-request](https://ci.nodejs.org/job/node-test-pull-request/)** |
51 | 66 | is used for a final full-test run to ensure that the current _HEAD_ is stable. |
52 | 67 |
|
53 | | -**b.** **Nightly builds:** (optional) |
| 68 | +**b.** **CitGM:** |
| 69 | +**[citgm-smoker](https://ci.nodejs.org/job/citgm-smoker/)** is used to run |
| 70 | +the [CitGM](https://github.com/nodejs/citgm/) tool which tests a build of |
| 71 | +Node.js against a defined set of community modules. This is used during a |
| 72 | +release process to ensure that none of the commonly used modules which are |
| 73 | +tested by CitGM show functional regressions with the new Node.js version |
| 74 | +which could impact users. |
| 75 | + |
| 76 | +**c.** **Nightly builds:** (optional) |
54 | 77 | **[iojs+release](https://ci-release.nodejs.org/job/iojs+release/)** can be used |
55 | 78 | to create a nightly release for the current _HEAD_ if public test releases are |
56 | 79 | required. Builds triggered with this job are published straight to |
57 | 80 | <https://nodejs.org/download/nightly/> and are available for public download. |
58 | 81 |
|
59 | | -**c.** **Release builds:** |
| 82 | +**d.** **Release builds:** |
60 | 83 | **[iojs+release](https://ci-release.nodejs.org/job/iojs+release/)** does all of |
61 | 84 | the work to build all required release assets. Promotion of the release files is |
62 | 85 | a manual step once they are ready (see below). |
@@ -66,8 +89,8 @@ this access to individuals authorized by the TSC. |
66 | 89 |
|
67 | 90 | ### 2. \<nodejs.org> access |
68 | 91 |
|
69 | | -The _dist_ user on nodejs.org controls the assets available in |
70 | | -<https://nodejs.org/download/>. <https://nodejs.org/dist/> is an alias for |
| 92 | +The _dist_ user on the `nodejs.org` host controls the assets available in |
| 93 | +<https://nodejs.org/download/>. <https://nodejs.org/dist/> is an alias for |
71 | 94 | <https://nodejs.org/download/release/>. |
72 | 95 |
|
73 | 96 | The Jenkins release build workers upload their artifacts to the web server as |
@@ -90,6 +113,12 @@ responsible for that release. In order to be able to verify downloaded binaries, |
90 | 113 | the public should be able to check that the `SHASUMS256.txt` file has been |
91 | 114 | signed by someone who has been authorized to create a release. |
92 | 115 |
|
| 116 | +If you do not currently have a key then you should create one with a |
| 117 | +suitable strength with `gpg --full-generate-key`. The default options |
| 118 | +(currently "ECC sign and encrypt" and "Curve 25519") are good choices and |
| 119 | +consistent with the |
| 120 | +[ssh key recommendations in the GOVERNANCE.md file](https://github.com/nodejs/Release/blob/main/GOVERNANCE.md#ssh-key-guidance). |
| 121 | + |
93 | 122 | The public keys should be fetchable from a known third-party keyserver. |
94 | 123 | The OpenPGP keyserver at <https://keys.openpgp.org/> is recommended. |
95 | 124 | Use the [submission](https://keys.openpgp.org/upload) form to submit |
@@ -108,11 +137,30 @@ gpg --keyserver hkps://keys.openpgp.org --recv-keys <FINGERPRINT> |
108 | 137 |
|
109 | 138 | The key you use may be a child/subkey of an existing key. |
110 | 139 |
|
| 140 | +If you wish to also upload your key to the commonly used Ubuntu keyservers |
| 141 | +you can do so with |
| 142 | + |
| 143 | +```bash |
| 144 | +gpg --keyserver keyserver.ubuntu.com --send-keys <FINGERPRINT> |
| 145 | +``` |
| 146 | + |
| 147 | +and check it by switching the server name in the `--recv-keys` operation |
| 148 | +list above to the Ubuntu keyserver. For more information take a look at the |
| 149 | +[Ubuntu GPG howto wiki page](https://help.ubuntu.com/community/GnuPrivacyGuardHowto). |
| 150 | + |
111 | 151 | Additionally, full GPG key fingerprints for individuals authorized to release |
112 | 152 | should be listed in the Node.js GitHub README.md file. |
113 | 153 |
|
114 | | -> It is recommended to sign all commits under the Node.js repository. |
115 | | -> Run: `git config commit.gpgsign true` inside the `node` folder. |
| 154 | +> All commits to branches in `nodejs/node` other than `main` and `actions/*` MUST be signed |
| 155 | +> otherwise pushing to those branches will be rejected by the GitHub rules |
| 156 | +> enforced by the Node.js project. |
| 157 | +> Run: `git config commit.gpgsign true` inside the `node` folder or use the |
| 158 | +> `-S` flag on your git operations (The examples in this document will |
| 159 | +> include `-S` expliticlty) |
| 160 | +
|
| 161 | +While GitHub allows signing individual commits using an ssh key, |
| 162 | +that is not covered here as this will not allow you to sign releases, so you |
| 163 | +will need to set up a GPG signing key in GitHub. |
116 | 164 |
|
117 | 165 | ## How to create a release |
118 | 166 |
|
@@ -123,7 +171,7 @@ Notes: |
123 | 171 | * Version strings are listed below as _"vx.y.z"_ or _"x.y.z"_. Substitute for |
124 | 172 | the release version. |
125 | 173 | * Examples will use the fictional release version `1.2.3`. |
126 | | -* When preparing a security release, follow the security steps in the details |
| 174 | +* When preparing a _security release_, follow the security steps in the details |
127 | 175 | sections. |
128 | 176 |
|
129 | 177 | ### 0. Pre-release steps |
@@ -136,13 +184,6 @@ and the release blog post is available on the project website. |
136 | 184 | Build can be contacted best by opening up an issue on the [Build issue |
137 | 185 | tracker][]. |
138 | 186 |
|
139 | | -When preparing a security release, contact Build at least two weekdays in |
140 | | -advance of the expected release. To ensure that the security patch(es) can be |
141 | | -properly tested, run a `node-test-pull-request` job against the `main` branch |
142 | | -of the `nodejs-private/node-private` repository a day or so before the |
143 | | -[CI lockdown procedure][] begins. This is to confirm that Jenkins can properly |
144 | | -access the private repository. |
145 | | - |
146 | 187 | ### 1. Update the staging branch |
147 | 188 |
|
148 | 189 | Checkout the staging branch locally. |
@@ -174,11 +215,11 @@ When landing the PR add the `Backport-PR-URL:` line to each commit. Close the |
174 | 215 | backport PR with `Landed in ...`. Update the label on the original PR from |
175 | 216 | `backport-requested-vN.x` to `backported-to-vN.x`. |
176 | 217 |
|
177 | | -You can add the `Backport-PR-URL` metadata by using `--backport` with |
178 | | -`git node land` |
| 218 | +You can add the `Backport-PR-URL` metadata automatically when landing by |
| 219 | +using `--backport` with `git node land`: |
179 | 220 |
|
180 | 221 | ```bash |
181 | | -git node land --backport $PR-NUMBER |
| 222 | +git node land -S --backport $PR-NUMBER |
182 | 223 | ``` |
183 | 224 |
|
184 | 225 | To determine the relevant commits, use |
@@ -189,16 +230,32 @@ metadata, as well as the GitHub labels such as `semver-minor` and |
189 | 230 | omitted from a commit, the commit will show up because it's unsure if it's a |
190 | 231 | duplicate or not. |
191 | 232 |
|
| 233 | +A `branch-diff` run can use a lot of credits and users are |
| 234 | +[limited by default to 5000 per hour](https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2026-03-10). |
| 235 | +It is not unusual for a run of branch-diff to |
| 236 | +use around 1000 of these. For this reason it is recommended that when you |
| 237 | +run branch-diff you redirect the output to a file and then process it. You |
| 238 | +can check your current usage with `gh rate_limit` if you have the GitHub CLI |
| 239 | +installed and configured, or using the curl command from |
| 240 | +[this link](https://docs.github.com/en/rest/rate-limit/rate-limit?apiVersion=2026-03-10) |
| 241 | +with authentication e.g. |
| 242 | + |
| 243 | +```bash |
| 244 | +curl -H "Authorization: token $YOURGITHUBTOKEN" -X GET https://api.github.com/rate_limit |
| 245 | +``` |
| 246 | + |
192 | 247 | For a list of commits that could be landed in a minor release on v1.x: |
193 | 248 |
|
194 | 249 | ```bash |
195 | 250 | N=1 sh -c 'branch-diff v$N.x-staging upstream/main --exclude-label=semver-major,dont-land-on-v$N.x,backport-requested-v$N.x,backport-blocked-v$N.x,backport-open-v$N.x,backported-to-v$N.x --filter-release --format=simple' |
196 | 251 | ``` |
197 | 252 |
|
198 | | -If the target branch is an LTS line, you should also exclude the `baking-for-lts`: |
| 253 | +If the target branch is an LTS line, you should also exclude the |
| 254 | +`baking-for-lts` and use a Current version released at least two weeks before the expected release date. |
| 255 | +In this example we use 25.5.0 as the base version to prepare a release for Node.js 24: |
199 | 256 |
|
200 | 257 | ```bash |
201 | | -N=1 sh -c 'branch-diff v$N.x-staging upstream/main --exclude-label=semver-major,dont-land-on-v$N.x,backport-requested-v$N.x,backport-blocked-v$N.x,backport-open-v$N.x,backported-to-v$N.x,baking-for-lts --filter-release --format=simple' |
| 258 | +N=24 sh -c 'branch-diff v$N.x-staging v26.5.0 --exclude-label=semver-major,dont-land-on-v$N.x,backport-requested-v$N.x,backport-blocked-v$N.x,backport-open-v$N.x,backported-to-v$N.x,baking-for-lts --filter-release --format=simple' |
202 | 259 | ``` |
203 | 260 |
|
204 | 261 | Previously released commits and version bumps do not need to be |
@@ -216,6 +273,11 @@ Carefully review the list of commits: |
216 | 273 | When you are ready to cherry-pick commits, you can automate with the following |
217 | 274 | command. |
218 | 275 |
|
| 276 | +Since this is slightly different from the previous branch-diff output - it |
| 277 | +contains only the commit SHAs and in revert order - you may wish to save |
| 278 | +this before piping it directly to `git cherry-pick` in case it does not go |
| 279 | +cleanly. |
| 280 | + |
219 | 281 | ```bash |
220 | 282 | N=1 sh -c 'branch-diff v$N.x-staging upstream/main --exclude-label=semver-major,dont-land-on-v$N.x,backport-requested-v$N.x,backport-blocked-v$N.x,backport-open-v$N.x,backported-to-v$N.x --filter-release --format=sha --reverse' | xargs git cherry-pick -S |
221 | 283 | ``` |
@@ -351,6 +413,8 @@ This will ensure they are included in the "Notable Changes" section of the CHANG |
351 | 413 |
|
352 | 414 | ### 3. Update `src/node_version.h` |
353 | 415 |
|
| 416 | +_(This step will be done automatically if you are using `create-release-proposal` or `git node release --prepare`)_ |
| 417 | + |
354 | 418 | Set the version for the proposed release using the following macros, which are |
355 | 419 | already defined in `src/node_version.h`: |
356 | 420 |
|
@@ -369,6 +433,8 @@ be produced with a version string that does not have a trailing pre-release tag: |
369 | 433 |
|
370 | 434 | ### 4. Update the changelog |
371 | 435 |
|
| 436 | +_(This step will be done automatically if you are using `create-release-proposal` or `git node release --prepare`)_ |
| 437 | + |
372 | 438 | #### Step 1: Collect the formatted list of changes |
373 | 439 |
|
374 | 440 | Collect a formatted list of commits since the last release. Use |
@@ -484,14 +550,16 @@ are formatted correctly. |
484 | 550 |
|
485 | 551 | If this release includes new APIs then it is necessary to document that they |
486 | 552 | were first added in this version. The relevant commits should already include |
487 | | -`REPLACEME` tags as per the example in the |
488 | | -[docs README](../../tools/doc/README.md). Check for these tags with |
| 553 | +`REPLACEME` tags (see [Writing Documentation](./api-documentation.md#writing-documentation)). |
489 | 554 |
|
490 | 555 | ```bash |
491 | 556 | grep REPLACEME doc/api/*.md |
492 | 557 | ``` |
493 | 558 |
|
494 | | -and substitute this node version with |
| 559 | +The above command will check for the presence of the tags and show you which |
| 560 | +files need to be updated. You can then perform the replacements with one of |
| 561 | +the following commands using either `sed` or `perl`. In these examples |
| 562 | +`$VERSION` must be prefixed with a `v`: |
495 | 563 |
|
496 | 564 | ```bash |
497 | 565 | sed -i "s/REPLACEME/$VERSION/g" doc/api/*.md |
|
509 | 577 | perl -pi -e "s/REPLACEME/$VERSION/g" doc/api/*.md |
510 | 578 | ``` |
511 | 579 |
|
512 | | -`$VERSION` should be prefixed with a `v`. |
513 | | - |
514 | 580 | If this release includes any new deprecations it is necessary to ensure that |
515 | 581 | those are assigned a proper static deprecation code. These are listed in the |
516 | 582 | docs (see `doc/api/deprecations.md`) and in the source as `DEP00XX`. The code |
|
520 | 586 |
|
521 | 587 | ### 5. Create release commit |
522 | 588 |
|
| 589 | +_(This step will be done automatically if you are using `create-release-proposal` or `git node release --prepare`)_ |
| 590 | + |
523 | 591 | The `CHANGELOG.md`, `doc/changelogs/CHANGELOG_Vx.md`, `src/node_version.h`, and |
524 | 592 | `REPLACEME` changes should be the final commit that will be tagged for the |
525 | 593 | release. When committing these to git, use the following message format: |
@@ -561,6 +629,8 @@ Otherwise, you will leak the commits before the security release. |
561 | 629 |
|
562 | 630 | ### 6. Propose release on GitHub |
563 | 631 |
|
| 632 | +_(This step will be done automatically if you are using `create-release-proposal` or `git node release --prepare`)_ |
| 633 | + |
564 | 634 | Push the release branch to `nodejs/node`, not to your own fork. This allows |
565 | 635 | release branches to more easily be passed between members of the release team if |
566 | 636 | necessary. |
@@ -612,13 +682,18 @@ purpose. Run it once with the base `vx.x` branch as a reference and with the |
612 | 682 | proposal branch to check if new regressions could be introduced in the |
613 | 683 | ecosystem. |
614 | 684 |
|
615 | | -Use `ncu-ci` to compare `vx.x` run (10) and proposal branch (11) |
| 685 | +Use `ncu-ci` with the two build numbers from the `citgm-smoker` job to |
| 686 | +compare the base `vx.x` run (10) and the new proposal branch (11). |
616 | 687 |
|
617 | 688 | ```bash |
618 | 689 | npm i -g @node-core/utils |
619 | 690 | ncu-ci citgm 10 11 |
620 | 691 | ``` |
621 | 692 |
|
| 693 | +A number of the modules tested by CitGM are not completely |
| 694 | +reliable so differences shown by the comparison are not immediately cause |
| 695 | +for concern. |
| 696 | + |
622 | 697 | <details> |
623 | 698 | <summary>Security release</summary> |
624 | 699 |
|
@@ -744,7 +819,7 @@ Once you have produced builds that you're happy with you can either run |
744 | 819 | `git node release --promote`: |
745 | 820 |
|
746 | 821 | ```bash |
747 | | -git node release --promote https://github.com/nodejs/node/pull/XXXX -S |
| 822 | +git node release -S --promote https://github.com/nodejs/node/pull/XXXX |
748 | 823 | ``` |
749 | 824 |
|
750 | 825 | to automate the remaining steps until step 16 or you can perform it manually |
@@ -760,11 +835,10 @@ fetch the proposal from using the `--fetch-from` flag. |
760 | 835 | When promoting several releases, you can pass multiple URLs: |
761 | 836 |
|
762 | 837 | ```bash |
763 | | -git node release --promote \ |
| 838 | +git node release -S --promote \ |
764 | 839 | |
765 | 840 | https://github.com/nodejs-private/node-private/pull/XXXX \ |
766 | | - https://github.com/nodejs-private/node-private/pull/XXXX \ |
767 | | - -S |
| 841 | + https://github.com/nodejs-private/node-private/pull/XXXX |
768 | 842 | ``` |
769 | 843 |
|
770 | 844 | </details> |
@@ -1494,7 +1568,6 @@ Typical resolution: sign the release again. |
1494 | 1568 | ``` |
1495 | 1569 |
|
1496 | 1570 | [Build issue tracker]: https://github.com/nodejs/build/issues/new |
1497 | | -[CI lockdown procedure]: https://github.com/nodejs/build/blob/HEAD/doc/jenkins-guide.md#restricting-access-for-security-releases |
1498 | 1571 | [Node.js Snap management repository]: https://github.com/nodejs/snap |
1499 | 1572 | [Snap]: https://snapcraft.io/node |
1500 | 1573 | [`create-release-post.yml`]: https://github.com/nodejs/nodejs.org/actions/workflows/create-release-post.yml |
|