From de30d30e3417b3053d2a085f4de9efda4c27c671 Mon Sep 17 00:00:00 2001 From: RafaelGSS Date: Fri, 16 Oct 2026 12:38:34 -0300 Subject: [PATCH 1/6] doc: document the alpha release process Document how to prepare, version, tag and promote the Alpha releases introduced by the new release schedule, starting with Node.js 27, and how the first Alpha and semver-major releases are prepared with git node release. Refs: https://github.com/nodejs/Release/issues/1187 Signed-off-by: RafaelGSS --- doc/contributing/releases.md | 130 +++++++++++++++++++++++++++++++---- 1 file changed, 117 insertions(+), 13 deletions(-) diff --git a/doc/contributing/releases.md b/doc/contributing/releases.md index 57bf2dc31bf8..2f141a221ec4 100644 --- a/doc/contributing/releases.md +++ b/doc/contributing/releases.md @@ -499,8 +499,9 @@ The new entry should take the following form: * Include the full list of commits since the last release here. Do not include "Working on X.Y.Z+1" commits. ``` -The release type should be either Current, LTS, or Maintenance, depending on the -type of release being produced. +The release type should be either Alpha, Current, LTS, or Maintenance, depending +on the type of release being produced. Release lines starting with Node.js 27 +do not have a Maintenance phase. By default, the `### Notable changes` section should be populated with the commits in the release that have either the `notable-change` or `semver-minor` @@ -903,13 +904,20 @@ git secure-tag -sm "YYYY-MM-DD Node.js vx.y.z (The commit-sha is the release commit. You can get it easily by running `git rev-parse HEAD` -`release-type` is either "Current" or "LTS". For LTS releases, you should also -include the release code name. +`release-type` is either "Alpha", "Current" or "LTS". For LTS releases, you +should also include the release code name. ```text 2019-10-22 Node.js v10.17.0 'Dubnium' (LTS) Release ``` +For Alpha releases, the tag name includes the full pre-release version (see +[Alpha releases](#alpha-releases-october-to-april)): + +```text +2026-10-28 Node.js v27.0.0-alpha.0.0.0 (Alpha) Release +``` + The tag **must** be signed using the GPG key that's listed for you on the project README. @@ -930,6 +938,9 @@ Working on vx.y.z # where 'z' is the incremented patch number PR-URL: ``` +For Alpha releases, use the full pre-release version, e.g. +`Working on v27.0.0-alpha.1.0.1`. + This sets up the branch so that nightly builds are produced with the next version number _and_ a pre-release tag. @@ -1346,7 +1357,8 @@ The `lts-watch-vN.x` issue label must be created, with the same color as other existing labels for that release line, such as `vN.x`. If the release is transitioning from Active LTS to Maintenance, the -`backport-requested-vN.x` label must be deleted. +`backport-requested-vN.x` label must be deleted. This only applies to release +lines up to Node.js 26, as later release lines do not have a Maintenance phase. ### Add new codename to nodejs-latest-linker @@ -1394,6 +1406,13 @@ announced immediately following the release of 12.0.0). ### Branch-off (October) +#### Tracking issue + +Open an issue in the [Release repository][] titled `Prepare for vN`, listing +the pull requests needed to prepare the release line (e.g. tooling updates or +the expected assets in the Build repository). Keep it updated as pull requests +are opened and land. + #### Release branch Approximately six months before a major release, new `vN.x` and @@ -1427,10 +1446,25 @@ labels of previous releases. #### Initial Alpha release proposal -A draft release proposal should be created before the release. A -separate `vN.x-proposal` branch should be created that tracks the `vN.x` -branch. This branch will contain the draft release commit (with the draft -changelog). +A draft release proposal should be created before the release. Once the +`vN.x-staging` branch exists, use the [`create-release-proposal`][] action with +the first Alpha version: + +```bash +gh workflow run "Create Release Proposal" -f release-line=N -f release-date=YYYY-MM-DD -f release-version=N.0.0-alpha.0.0.0 +``` + +Or run it locally: + +```bash +git node release -S --prepare --newVersion=N.0.0-alpha.0.0.0 +``` + +This creates the `vN.0.0-alpha.0.0.0-proposal` branch with the draft release +commit, which also creates `doc/changelogs/CHANGELOG_V{N}.md`, updates the +navigation headers and the root `CHANGELOG.md`, and generates the changelog +against `vN-1.x`, as described in the sections below. Review those changes +before opening the release proposal. Notify the `@nodejs/npm` team in the release proposal PR to inform them of the upcoming release. @@ -1510,14 +1544,77 @@ version of the release), in the [expected assets][] folder. The change will need to be deployed onto the web server by a member of the [build-infra team][] before the release is promoted. +### Alpha releases (October to April) + +Between the branch-off and the semver-major release, the `vN.x` line is +released as Alpha versions. Unlike Current and LTS lines, Alpha releases may +contain `SEMVER-MAJOR` changes. + +#### Versioning + +Alpha versions use the `vN.0.0-alpha.X.Y.Z` format, where `X.Y.Z` follows +[Semantic Versioning][] relative to the previous Alpha release, so users can +tell the kind of changes between two Alpha releases. The first Alpha release of +a line is `vN.0.0-alpha.0.0.0`. + +Set the `NODE_ALPHA_*_VERSION` macros in `src/node_version.h` as follows, +leaving `NODE_MAJOR_VERSION` at `N` and `NODE_MINOR_VERSION` and +`NODE_PATCH_VERSION` at `0`: + +* If the release contains at least one `SEMVER-MAJOR` commit, increment + `NODE_ALPHA_MAJOR_VERSION` and reset `NODE_ALPHA_MINOR_VERSION` and + `NODE_ALPHA_PATCH_VERSION` to `0`. +* Otherwise, if it contains at least one `SEMVER-MINOR` commit, increment + `NODE_ALPHA_MINOR_VERSION` and reset `NODE_ALPHA_PATCH_VERSION` to `0`. +* Otherwise, increment `NODE_ALPHA_PATCH_VERSION`. + +For example, `v27.0.0-alpha.0.0.0` followed by a release containing a +`SEMVER-MAJOR` commit is `v27.0.0-alpha.1.0.0`. The git tag, the release commit +title and the changelog entries all use this full version: + +```text +2026-10-28, Version 27.0.0-alpha.0.0.0 (Alpha) +``` + +#### Preparing an Alpha release + +Alpha releases pick up commits from `main`, including `SEMVER-MAJOR` ones. To +list the commits to land on `vN.x-staging`, do not exclude the `semver-major` +label: + +```bash +N=27 sh -c 'branch-diff v$N.x-staging upstream/main --exclude-label=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' +``` + +The [`create-release-proposal`][] action and `git node release --prepare` +compute the next Alpha version from the commit labels. The proposal branch is +named after the full version, e.g. `v27.0.0-alpha.1.0.0-proposal`. + +Alpha releases are added to `doc/changelogs/CHANGELOG_V{N}.md`, in the same way +as Current releases, and are labeled "Alpha" in the changelog tables. List all +`SEMVER-MAJOR` commits that are not strictly internal, test, or doc-related as +notable changes. + +Alpha releases are published on GitHub as pre-releases, so they are not marked +as the latest release. + +`REPLACEME` placeholders are replaced with the full Alpha version (e.g. +`v27.0.0-alpha.1.0.0`). + ### Semver-major release (April) #### Release proposal -A draft release proposal should be created 6 weeks before the release. A -separate `vN.x-proposal` branch should be created that tracks the `vN.x` -branch. This branch will contain the draft release commit (with the draft -changelog). +A draft release proposal should be created 6 weeks before the release, using +the [`create-release-proposal`][] action with `-f release-version=N.0.0`, or +locally: + +```bash +git node release -S --prepare --newVersion=N.0.0 +``` + +This creates the `vN.0.0-proposal` branch with the draft release commit (with +the draft changelog). Notify the `@nodejs/npm` team in the release proposal PR to inform them of the upcoming release. @@ -1535,6 +1632,11 @@ To mark a release line as stable, the following changes must be made to * Remove `NODE_ALPHA_MAJOR_VERSION`, `NODE_ALPHA_MINOR_VERSION`, and `NODE_ALPHA_PATCH_VERSION`. +The "Alpha" labels in `doc/changelogs/CHANGELOG_V{N}.md` and `CHANGELOG.md` +must be changed to "Current". `git node release --prepare --newVersion=N.0.0` +does both, and `git node release --promote` bumps `NODE_MAJOR_VERSION` on +`main` when cherry-picking the release commit. + #### Generate the notable changes For a major release, all SEMVER-MAJOR commits that are not strictly internal, @@ -1590,6 +1692,8 @@ Typical resolution: sign the release again. [Build issue tracker]: https://github.com/nodejs/build/issues/new [Node.js Snap management repository]: https://github.com/nodejs/snap +[Release repository]: https://github.com/nodejs/Release +[Semantic Versioning]: https://semver.org/ [Snap]: https://snapcraft.io/node [`create-release-post.yml`]: https://github.com/nodejs/nodejs.org/actions/workflows/create-release-post.yml [`create-release-proposal`]: https://github.com/nodejs/node/actions/workflows/create-release-proposal.yml From 75b2ab964df97a7c38d485a482d4aa74540d2e13 Mon Sep 17 00:00:00 2001 From: RafaelGSS Date: Fri, 16 Oct 2026 12:38:34 -0300 Subject: [PATCH 2/6] build,tools: support alpha versions in release tooling Alpha releases are versioned vN.0.0-alpha.X.Y.Z. Add a --full flag to tools/getnodeversion.py that includes the alpha tag on release builds and use it for the release artifact names on both Unix and Windows, keeping the MSI ProductVersion numeric. Make the tag check in tools/release.sh and the release tests accept alpha versions too. Refs: https://github.com/nodejs/Release/issues/1187 Signed-off-by: RafaelGSS --- Makefile | 2 +- test/parallel/test-release-changelog.js | 19 ++++++++++++++----- test/parallel/test-release-npm.js | 2 +- tools/getnodeversion.py | 24 +++++++++++++++++++++++- tools/release.sh | 5 ++++- vcbuild.bat | 5 ++++- 6 files changed, 47 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 31d7d911c987..018c41bb8234 100644 --- a/Makefile +++ b/Makefile @@ -989,7 +989,7 @@ ifndef DISTTYPE DISTTYPE=release endif ifeq ($(DISTTYPE),release) -FULLVERSION=$(VERSION) +FULLVERSION=v$(shell $(PYTHON) tools/getnodeversion.py --full) else # ifeq ($(DISTTYPE),release) ifeq ($(DISTTYPE),custom) ifndef CUSTOMTAG diff --git a/test/parallel/test-release-changelog.js b/test/parallel/test-release-changelog.js index 6b8e6ece43af..1775d7afc7c4 100644 --- a/test/parallel/test-release-changelog.js +++ b/test/parallel/test-release-changelog.js @@ -27,7 +27,16 @@ if (!release) { const major = getDefine(versionText, 'NODE_MAJOR_VERSION'); const minor = getDefine(versionText, 'NODE_MINOR_VERSION'); const patch = getDefine(versionText, 'NODE_PATCH_VERSION'); -const versionForRegex = RegExp.escape(`${major}.${minor}.${patch}`); +let version = `${major}.${minor}.${patch}`; +const alpha = /#define\s+NODE_ALPHA_MAJOR_VERSION\s/.test(versionText); +if (alpha) { + const alphaMajor = getDefine(versionText, 'NODE_ALPHA_MAJOR_VERSION'); + const alphaMinor = getDefine(versionText, 'NODE_ALPHA_MINOR_VERSION'); + const alphaPatch = getDefine(versionText, 'NODE_ALPHA_PATCH_VERSION'); + version += `-alpha.${alphaMajor}.${alphaMinor}.${alphaPatch}`; +} +const versionForRegex = RegExp.escape(version); +const releaseType = alpha ? 'Alpha' : 'Current'; const lts = getDefine(versionText, 'NODE_VERSION_IS_LTS') !== '0'; const codename = getDefine(versionText, 'NODE_VERSION_LTS_CODENAME').slice(1, -1); @@ -47,7 +56,7 @@ const changelogPath = `doc/changelogs/CHANGELOG_V${major}.md`; if (lts) { tableHeader = new RegExp(`LTS '${RegExp.escape(codename)}'`); } else { - tableHeader = /Current<\/th>/; + tableHeader = new RegExp(`${releaseType}`); } assert.match(changelog, tableHeader); // Check table contains link to this release. @@ -59,7 +68,7 @@ const changelogPath = `doc/changelogs/CHANGELOG_V${major}.md`; if (lts) { title = new RegExp(`## \\d{4}-\\d{2}-\\d{2}, Version ${versionForRegex} '${RegExp.escape(codename)}' \\(LTS\\), @\\S+`); } else { - title = new RegExp(`## \\d{4}-\\d{2}-\\d{2}, Version ${versionForRegex} \\(Current\\), @\\S+`); + title = new RegExp(`## \\d{4}-\\d{2}-\\d{2}, Version ${versionForRegex} \\(${releaseType}\\), @\\S+`); } assert.match(changelog, title); } @@ -72,7 +81,7 @@ const changelogPath = `doc/changelogs/CHANGELOG_V${major}.md`; if (lts) { linkToChangelog = new RegExp(`\\[Node\\.js ${major}\\]\\(${RegExp.escape(changelogPath)}\\) \\*\\*Long Term Support\\*\\*`); } else { - linkToChangelog = new RegExp(`\\[Node\\.js ${major}\\]\\(${RegExp.escape(changelogPath)}\\) \\*\\*Current\\*\\*`); + linkToChangelog = new RegExp(`\\[Node\\.js ${major}\\]\\(${RegExp.escape(changelogPath)}\\) \\*\\*${releaseType}\\*\\*`); } assert.match(mainChangelog, linkToChangelog); // Check table header. @@ -80,7 +89,7 @@ const changelogPath = `doc/changelogs/CHANGELOG_V${major}.md`; if (lts) { tableHeader = new RegExp(`${major} \\(LTS\\)`); } else { - tableHeader = new RegExp(`${major} \\(Current\\)`); + tableHeader = new RegExp(`${major} \\(${releaseType}\\)`); } assert.match(mainChangelog, tableHeader); // Check the table contains a link to the release in the appropriate CHANGELOG_V*.md file. diff --git a/test/parallel/test-release-npm.js b/test/parallel/test-release-npm.js index 5544ef79313a..72ef4c7c6fb3 100644 --- a/test/parallel/test-release-npm.js +++ b/test/parallel/test-release-npm.js @@ -5,7 +5,7 @@ const assert = require('assert'); const child_process = require('child_process'); const path = require('path'); -const releaseReg = /^v\d+\.\d+\.\d+$/; +const releaseReg = /^v\d+\.\d+\.\d+(?:-alpha\.\d+\.\d+\.\d+)?$/; // Npm requires crypto support. if (!releaseReg.test(process.version) || !common.hasCrypto) { diff --git a/tools/getnodeversion.py b/tools/getnodeversion.py index b362950dd366..d66c5d5e2fa4 100644 --- a/tools/getnodeversion.py +++ b/tools/getnodeversion.py @@ -1,5 +1,6 @@ from __future__ import print_function import os +import sys def get_major_minor_patch(text): @@ -13,9 +14,30 @@ def get_major_minor_patch(text): return major, minor, patch +def get_alpha_tag(text): + is_release = False + alpha = {} + for line in text.splitlines(): + if line.startswith('#define NODE_VERSION_IS_RELEASE'): + is_release = line.split()[2] == '1' + elif line.startswith('#define NODE_ALPHA_MAJOR_VERSION'): + alpha['major'] = line.split()[2] + elif line.startswith('#define NODE_ALPHA_MINOR_VERSION'): + alpha['minor'] = line.split()[2] + elif line.startswith('#define NODE_ALPHA_PATCH_VERSION'): + alpha['patch'] = line.split()[2] + if not is_release or 'major' not in alpha: + return '' + return '-alpha.' + '.'.join((alpha['major'], alpha['minor'], alpha['patch'])) + + node_version_h = os.path.join(os.path.dirname(__file__), '..', 'src', 'node_version.h') with open(node_version_h) as in_file: - print('.'.join(get_major_minor_patch(in_file.read()))) + text = in_file.read() + version = '.'.join(get_major_minor_patch(text)) + if '--full' in sys.argv[1:]: + version += get_alpha_tag(text) + print(version) diff --git a/tools/release.sh b/tools/release.sh index a40035cb7427..f11d5790ee8c 100755 --- a/tools/release.sh +++ b/tools/release.sh @@ -115,7 +115,10 @@ sign() { # local version=$1 ghtaggedversion=$(curl -sL "https://raw.githubusercontent.com/nodejs/node/$1/src/node_version.h" \ - | awk '/define NODE_(MAJOR|MINOR|PATCH)_VERSION/{ v = v "." $3 } END{ v = "v" substr(v, 2); print v }') + | awk '/define NODE_(MAJOR|MINOR|PATCH)_VERSION/{ v = v "." $3 } + /define NODE_VERSION_IS_RELEASE/{ r = $3 } + /define NODE_ALPHA_(MAJOR|MINOR|PATCH)_VERSION/{ a = a "." $3 } + END{ v = "v" substr(v, 2); if (r == 1 && a != "") v = v "-alpha" a; print v }') if [ "$1" != "${ghtaggedversion}" ]; then echo "Could not find tagged version on github.com/nodejs/node, did you push your tag?" exit 1 diff --git a/vcbuild.bat b/vcbuild.bat index d1a6d8fb7f30..c18b572cecbe 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -946,16 +946,19 @@ rem *************** set NODE_VERSION= set TAG= set FULLVERSION= +set NODE_FULL_VERSION= for /F "usebackq tokens=*" %%i in (`python "%~dp0tools\getnodeversion.py"`) do set NODE_VERSION=%%i if not defined NODE_VERSION ( echo Cannot determine current version of Node.js exit /b 1 ) +@rem NODE_VERSION stays numeric as it is used as the MSI ProductVersion. +for /F "usebackq tokens=*" %%i in (`python "%~dp0tools\getnodeversion.py" --full`) do set NODE_FULL_VERSION=%%i if not defined DISTTYPE set DISTTYPE=release if "%DISTTYPE%"=="release" ( - set FULLVERSION=%NODE_VERSION% + set FULLVERSION=%NODE_FULL_VERSION% goto distexit ) if "%DISTTYPE%"=="custom" ( From 3f1fadea8b1faedbdd112890ebcce07fe16e5b8b Mon Sep 17 00:00:00 2001 From: RafaelGSS Date: Fri, 16 Oct 2026 12:38:34 -0300 Subject: [PATCH 3/6] tools: support alpha releases in workflows - Lint alpha release proposal branches and expect the "(Alpha)" release commit title. - Accept alpha anchors and SEMVER-MAJOR commits when checking the proposal commit list. - Add an optional release-version input to create-release-proposal, passed to git node release as --newVersion. - Check the documented versions against the changelogs on alpha release lines too. - Skip the post-release actions for alpha releases. - Only create the major release reminder in February, as there is a single major release per year now. Refs: https://github.com/nodejs/Release/issues/1187 Signed-off-by: RafaelGSS --- .github/workflows/create-release-proposal.yml | 7 ++++++- .github/workflows/lint-release-proposal.yml | 6 +++++- .github/workflows/linters.yml | 9 +++++++-- .github/workflows/major-release.yml | 2 +- .github/workflows/post-release.yml | 2 +- tools/actions/create-release-proposal.sh | 6 ++++-- tools/actions/lint-release-proposal-commit-list.mjs | 3 ++- 7 files changed, 26 insertions(+), 9 deletions(-) diff --git a/.github/workflows/create-release-proposal.yml b/.github/workflows/create-release-proposal.yml index 735b15ffd12f..84300d8a1695 100644 --- a/.github/workflows/create-release-proposal.yml +++ b/.github/workflows/create-release-proposal.yml @@ -14,6 +14,10 @@ on: required: true type: string description: The release date in YYYY-MM-DD format + release-version: + required: false + type: string + description: 'The version to release, if it cannot be inferred. e.g: 27.0.0-alpha.0.0.0' concurrency: ${{ github.workflow }} @@ -31,6 +35,7 @@ jobs: RELEASE_BRANCH: v${{ inputs.release-line }}.x RELEASE_DATE: ${{ inputs.release-date }} RELEASE_LINE: ${{ inputs.release-line }} + RELEASE_VERSION: ${{ inputs.release-version }} runs-on: ubuntu-slim steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -74,7 +79,7 @@ jobs: # The curl command is to make sure we run the version of the script corresponding to the current workflow. run: | curl -fsSL https://github.com/${GITHUB_REPOSITORY}/raw/${GITHUB_SHA}/tools/actions/create-release-proposal.sh |\ - sh -s -- "${RELEASE_DATE}" "${RELEASE_LINE}" "${GITHUB_ACTOR}" + sh -s -- "${RELEASE_DATE}" "${RELEASE_LINE}" "${GITHUB_ACTOR}" "${RELEASE_VERSION}" env: GH_TOKEN: ${{ github.token }} # We want the bot to push the push the release commit so CI runs on it. diff --git a/.github/workflows/lint-release-proposal.yml b/.github/workflows/lint-release-proposal.yml index 9652eea91b89..989a57cd8851 100644 --- a/.github/workflows/lint-release-proposal.yml +++ b/.github/workflows/lint-release-proposal.yml @@ -4,6 +4,7 @@ on: push: branches: - v[0-9]+.[0-9]+.[0-9]+-proposal + - v[0-9]+.0.0-alpha.[0-9]+.[0-9]+.[0-9]+-proposal concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} @@ -34,8 +35,11 @@ jobs: $2 == "NODE_MAJOR_VERSION" { maj = $3 } $2 == "NODE_MINOR_VERSION" { min = $3 } $2 == "NODE_PATCH_VERSION" { pat = $3 } + $2 == "NODE_ALPHA_MAJOR_VERSION" { amaj = $3 } + $2 == "NODE_ALPHA_MINOR_VERSION" { amin = $3 } + $2 == "NODE_ALPHA_PATCH_VERSION" { apat = $3 } $2 == "NODE_VERSION_LTS_CODENAME" { gsub(/^"|"$/, "'"'"'",$3); lts = $3 } - END { if (maj) print maj "\\." min "\\." pat " " (lts != "'"''"'" ? lts " \\(LTS" : "\\(Current" ) "\\)" } + END { if (maj) print maj "\\." min "\\." pat (amaj != "" ? "-alpha\\." amaj "\\." amin "\\." apat " \\(Alpha" : " " (lts != "'"''"'" ? lts " \\(LTS" : "\\(Current" )) "\\)" } ') MAJOR=${VERSION%%\\.*} EXPECTED_TITLE='^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}, Version '"$VERSION"'$' diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index a4997b3d4ccd..5424eb43f5c7 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -146,9 +146,14 @@ jobs: exit "$EXIT_CODE" fi - name: Get release version numbers - if: ${{ github.event.pull_request && github.event.pull_request.base.ref == github.event.pull_request.base.repo.default_branch }} id: get-released-versions - run: ./tools/lint-md/list-released-versions-from-changelogs.mjs >> $GITHUB_OUTPUT + run: | + # Changelogs are only complete on the default branch and on Alpha lines. + if [ "$IS_PR_TO_DEFAULT_BRANCH" = true ] || grep -q '^#define NODE_ALPHA_MAJOR_VERSION' src/node_version.h; then + ./tools/lint-md/list-released-versions-from-changelogs.mjs >> "$GITHUB_OUTPUT" + fi + env: + IS_PR_TO_DEFAULT_BRANCH: ${{ github.event.pull_request && github.event.pull_request.base.ref == github.event.pull_request.base.repo.default_branch }} - name: Lint markdown files run: | echo "::add-matcher::.github/workflows/remark-lint-problem-matcher.json" diff --git a/.github/workflows/major-release.yml b/.github/workflows/major-release.yml index 1b15a00c8df1..6641571aecc9 100644 --- a/.github/workflows/major-release.yml +++ b/.github/workflows/major-release.yml @@ -21,7 +21,7 @@ jobs: MONTH=$(date +'%m') DAY=$(date +'%d') # We'll create the reminder issue two months prior the release - if [[ "$MONTH" == "02" || "$MONTH" == "08" ]] && [[ "$DAY" == "15" ]]; then + if [[ "$MONTH" == "02" ]] && [[ "$DAY" == "15" ]]; then echo "create_issue=true" >> "$GITHUB_ENV" fi - name: Retrieve next major release info from nodejs/Release diff --git a/.github/workflows/post-release.yml b/.github/workflows/post-release.yml index 2fb374e912d1..527e791a0b99 100644 --- a/.github/workflows/post-release.yml +++ b/.github/workflows/post-release.yml @@ -15,7 +15,7 @@ permissions: jobs: post-release-actions: - if: github.repository == 'nodejs/node' + if: github.repository == 'nodejs/node' && !contains(github.event.release.tag_name, '-alpha.') runs-on: ubuntu-slim steps: - name: Trigger update-links workflow on nodejs/release-cloudflare-worker diff --git a/tools/actions/create-release-proposal.sh b/tools/actions/create-release-proposal.sh index 9240fa2ad7f7..673fd070b67a 100755 --- a/tools/actions/create-release-proposal.sh +++ b/tools/actions/create-release-proposal.sh @@ -6,9 +6,10 @@ BOT_TOKEN=${BOT_TOKEN:-} RELEASE_DATE=$1 RELEASE_LINE=$2 RELEASER=$3 +RELEASE_VERSION=$4 if [ -z "$RELEASE_DATE" ] || [ -z "$RELEASE_LINE" ]; then - echo "Usage: $0 " + echo "Usage: $0 [ []]" exit 1 fi @@ -28,7 +29,8 @@ done set -xe -git node release --prepare --skipBranchDiff --yes --releaseDate "$RELEASE_DATE" +git node release --prepare --skipBranchDiff --yes --releaseDate "$RELEASE_DATE" \ + ${RELEASE_VERSION:+--newVersion "$RELEASE_VERSION"} HEAD_BRANCH="$(git rev-parse --abbrev-ref HEAD)" HEAD_SHA="$(git rev-parse HEAD^)" diff --git a/tools/actions/lint-release-proposal-commit-list.mjs b/tools/actions/lint-release-proposal-commit-list.mjs index a51f0c590026..7b54cf5a44c7 100755 --- a/tools/actions/lint-release-proposal-commit-list.mjs +++ b/tools/actions/lint-release-proposal-commit-list.mjs @@ -30,7 +30,7 @@ if (commitListingStart === -1) { } else { // We can't assume the Commits section is the one for this release in case of // a release to transition to LTS (i.e. with no commits). - const releaseStart = /\n<\/a>\n\n## \d+-\d+-\d+, Version \1/.exec(changelog); + const releaseStart = /\n<\/a>\n\n## \d+-\d+-\d+, Version \1/.exec(changelog); assert.ok(releaseStart, 'Could not determine the start of the release section'); const releaseEnd = changelog.indexOf('\n\n Date: Fri, 16 Oct 2026 18:52:36 -0300 Subject: [PATCH 4/6] fixup! doc: document the alpha release process --- .github/workflows/linters.yml | 9 ++------- .github/workflows/post-release.yml | 2 +- doc/contributing/releases.md | 11 +++++------ 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index 5424eb43f5c7..a4997b3d4ccd 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -146,14 +146,9 @@ jobs: exit "$EXIT_CODE" fi - name: Get release version numbers + if: ${{ github.event.pull_request && github.event.pull_request.base.ref == github.event.pull_request.base.repo.default_branch }} id: get-released-versions - run: | - # Changelogs are only complete on the default branch and on Alpha lines. - if [ "$IS_PR_TO_DEFAULT_BRANCH" = true ] || grep -q '^#define NODE_ALPHA_MAJOR_VERSION' src/node_version.h; then - ./tools/lint-md/list-released-versions-from-changelogs.mjs >> "$GITHUB_OUTPUT" - fi - env: - IS_PR_TO_DEFAULT_BRANCH: ${{ github.event.pull_request && github.event.pull_request.base.ref == github.event.pull_request.base.repo.default_branch }} + run: ./tools/lint-md/list-released-versions-from-changelogs.mjs >> $GITHUB_OUTPUT - name: Lint markdown files run: | echo "::add-matcher::.github/workflows/remark-lint-problem-matcher.json" diff --git a/.github/workflows/post-release.yml b/.github/workflows/post-release.yml index 527e791a0b99..2fb374e912d1 100644 --- a/.github/workflows/post-release.yml +++ b/.github/workflows/post-release.yml @@ -15,7 +15,7 @@ permissions: jobs: post-release-actions: - if: github.repository == 'nodejs/node' && !contains(github.event.release.tag_name, '-alpha.') + if: github.repository == 'nodejs/node' runs-on: ubuntu-slim steps: - name: Trigger update-links workflow on nodejs/release-cloudflare-worker diff --git a/doc/contributing/releases.md b/doc/contributing/releases.md index 2f141a221ec4..e5e93c77ca93 100644 --- a/doc/contributing/releases.md +++ b/doc/contributing/releases.md @@ -499,9 +499,9 @@ The new entry should take the following form: * Include the full list of commits since the last release here. Do not include "Working on X.Y.Z+1" commits. ``` -The release type should be either Alpha, Current, LTS, or Maintenance, depending -on the type of release being produced. Release lines starting with Node.js 27 -do not have a Maintenance phase. +The release type should be either Alpha, Current, or LTS, depending +on the type of release being produced. Release lines before Node.js 27 +also have a Maintenance phase. By default, the `### Notable changes` section should be populated with the commits in the release that have either the `notable-change` or `semver-minor` @@ -1357,8 +1357,7 @@ The `lts-watch-vN.x` issue label must be created, with the same color as other existing labels for that release line, such as `vN.x`. If the release is transitioning from Active LTS to Maintenance, the -`backport-requested-vN.x` label must be deleted. This only applies to release -lines up to Node.js 26, as later release lines do not have a Maintenance phase. +`backport-requested-vN.x` label must be deleted. ### Add new codename to nodejs-latest-linker @@ -1605,7 +1604,7 @@ as the latest release. #### Release proposal -A draft release proposal should be created 6 weeks before the release, using +A draft release proposal should be created 2 weeks before the release, using the [`create-release-proposal`][] action with `-f release-version=N.0.0`, or locally: From 77bb5f74bfc11dabc72203fc63e329960ebb585d Mon Sep 17 00:00:00 2001 From: RafaelGSS Date: Fri, 16 Oct 2026 18:52:37 -0300 Subject: [PATCH 5/6] fixup! build,tools: support alpha versions in release tooling --- test/parallel/test-release-npm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parallel/test-release-npm.js b/test/parallel/test-release-npm.js index 72ef4c7c6fb3..a9aff0b75794 100644 --- a/test/parallel/test-release-npm.js +++ b/test/parallel/test-release-npm.js @@ -5,7 +5,7 @@ const assert = require('assert'); const child_process = require('child_process'); const path = require('path'); -const releaseReg = /^v\d+\.\d+\.\d+(?:-alpha\.\d+\.\d+\.\d+)?$/; +const releaseReg = /^v\d+(?:\.0\.0-alpha\.\d+)?\.\d+\.\d+$/; // Npm requires crypto support. if (!releaseReg.test(process.version) || !common.hasCrypto) { From 83198bcf516f6f162e8bb1b6fb0801ad3190a5f3 Mon Sep 17 00:00:00 2001 From: RafaelGSS Date: Fri, 16 Oct 2026 18:52:37 -0300 Subject: [PATCH 6/6] fixup! tools: support alpha releases in workflows --- tools/actions/lint-release-proposal-commit-list.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/actions/lint-release-proposal-commit-list.mjs b/tools/actions/lint-release-proposal-commit-list.mjs index 7b54cf5a44c7..fa5ebf79cdfe 100755 --- a/tools/actions/lint-release-proposal-commit-list.mjs +++ b/tools/actions/lint-release-proposal-commit-list.mjs @@ -30,7 +30,7 @@ if (commitListingStart === -1) { } else { // We can't assume the Commits section is the one for this release in case of // a release to transition to LTS (i.e. with no commits). - const releaseStart = /\n<\/a>\n\n## \d+-\d+-\d+, Version \1/.exec(changelog); + const releaseStart = /\n<\/a>\n\n## \d+-\d+-\d+, Version \1/.exec(changelog); assert.ok(releaseStart, 'Could not determine the start of the release section'); const releaseEnd = changelog.indexOf('\n\n