Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/actions/release-check/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ inputs:
version:
description: Exact mobile version required for manual prerelease requests
default: ''
upstream_snapshot:
description: Explicit full SHA opt-in for an unreleased upstream proposal prerelease
default: ''
token:
description: Token with contents:read on this repository, for the tag probe.
required: true
Expand Down Expand Up @@ -38,4 +41,5 @@ runs:
GH_TOKEN: ${{ inputs.token }}
RELEASE_OPERATION: ${{ inputs.operation }}
RELEASE_VERSION: ${{ inputs.version }}
UPSTREAM_SNAPSHOT: ${{ inputs.upstream_snapshot }}
run: python3 scripts/release-control.py check
98 changes: 69 additions & 29 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ on:
description: Exact mobile version for prerelease/dryrun (24.21.0-1); empty for build
type: string
default: ''
upstream_snapshot:
description: Optional full upstream SHA; explicitly publish an unreleased proposal prerelease
type: string
default: ''

# One run per PR/branch. cancel-in-progress ONLY for pull_request: a push to
# recipe may be carrying the release gate chain and must never be cancelled
Expand Down Expand Up @@ -159,6 +163,7 @@ jobs:
token: ${{ github.token }}
operation: ${{ inputs.operation || 'build' }}
version: ${{ inputs.version || '' }}
upstream_snapshot: ${{ inputs.upstream_snapshot || '' }}

- uses: ./.github/actions/materialize

Expand Down Expand Up @@ -342,6 +347,7 @@ jobs:
token: ${{ github.token }}
operation: ${{ inputs.operation || 'build' }}
version: ${{ inputs.version || '' }}
upstream_snapshot: ${{ inputs.upstream_snapshot || '' }}

- uses: ./.github/actions/materialize

Expand Down Expand Up @@ -729,6 +735,7 @@ jobs:
token: ${{ github.token }}
operation: ${{ inputs.operation || 'build' }}
version: ${{ inputs.version || '' }}
upstream_snapshot: ${{ inputs.upstream_snapshot || '' }}

- uses: ./.github/actions/materialize

Expand Down Expand Up @@ -990,6 +997,7 @@ jobs:
token: ${{ github.token }}
operation: ${{ inputs.operation || 'build' }}
version: ${{ inputs.version || '' }}
upstream_snapshot: ${{ inputs.upstream_snapshot || '' }}
- name: Validate publishable notes before compiling
if: steps.d.outputs.cold == 'true'
env:
Expand Down Expand Up @@ -1249,6 +1257,7 @@ jobs:
env:
DRY: ${{ needs.release-check.outputs.dryrun == 'true' && '1' || '0' }}
V: ${{ needs.release-check.outputs.version }}
UPSTREAM_SNAPSHOT: ${{ inputs.upstream_snapshot || '' }}
GH_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@v7
Expand All @@ -1270,30 +1279,6 @@ jobs:

- uses: ./.github/actions/materialize

# Note: the materialized tree is a SHALLOW clone of nodejs/node (prepare.sh
# uses --depth 1), so this pushes a tag whose history is grafted at the
# upstream base, and git sends only the commits above that boundary. The
# remote accepts it only because the base and its ancestry are already
# there, on the upstream-base branch that the upstream-base job (needs:,
# above) has verified.
- name: Tag the materialized tree
run: |
git config user.name "nodejs-mobile-bot"
git config user.email "bot@users.noreply.github.com"
TAG="v${V}"
# Recipe-Commit records which recipe-branch commit generated this
# release. The tag object is the durable home for that link: the run
# that knows it expires, and the materialized commit itself carries
# only the generic overlay message.
git tag -a "$TAG" -m "nodejs-mobile ${V}" -m "Recipe-Commit: ${GITHUB_SHA}"
git remote add fork "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
if [ "$DRY" = "1" ]; then
echo "DRY RUN: would push tag $TAG (materialized tree $(git rev-parse 'HEAD^{tree}'))"
else
git push fork "refs/tags/$TAG"
echo "Pushed tag $TAG"
fi

- name: Download + package this run's artifacts
run: |
mkdir -p dl out
Expand Down Expand Up @@ -1321,21 +1306,76 @@ jobs:
pack nodejs-mobile-android-lite nodejs-mobile-android-lite
pack nodejs-mobile-ios nodejs-mobile-ios
pack nodejs-mobile-ios-lite nodejs-mobile-ios-lite
(cd out && sha256sum nodejs-mobile-*.zip > SHA256SUMS)
ls -la out

- name: Tag the materialized tree
run: |
git config user.name "nodejs-mobile-bot"
git config user.email "bot@users.noreply.github.com"
TAG="v${V}"
# Recipe-Commit records which recipe-branch commit generated this
# release. The tag object is the durable home for that link: the run
# that knows it expires, and the materialized commit itself carries
# only the generic overlay message.
# This mirror need not hold upstream's entire commit ancestry.
# A source snapshot commit preserves the verified tree without
# publishing a shallow history whose parents the remote lacks.
TREE=$(git rev-parse 'HEAD^{tree}')
BASE=$(awk '/^#define NODE_MAJOR_VERSION / {ma=$3} /^#define NODE_MINOR_VERSION / {mi=$3} /^#define NODE_PATCH_VERSION / {pa=$3} END {print "v" ma "." mi "." pa}' src/node_version.h)
git remote add fork "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
EXISTING=$(git ls-remote fork "refs/tags/$TAG")
if [ -n "$EXISTING" ]; then
git fetch fork "refs/tags/$TAG:refs/tags/$TAG"
[ "$(git rev-parse "$TAG^{tree}")" = "$TREE" ] &&
git cat-file tag "$TAG" | grep -Fxq "Recipe-Commit: ${GITHUB_SHA}" || {
echo "::error::Existing $TAG belongs to a different source tree or recipe commit"
exit 1
}
else
SOURCE_COMMIT=$(printf '%s\n\n%s\n%s\n%s\n' "nodejs-mobile ${V} source snapshot" "Upstream: ${BASE}" "Upstream-Snapshot: ${UPSTREAM_SNAPSHOT:-none}" "Recipe-Commit: ${GITHUB_SHA}" | git commit-tree "$TREE")
git tag -a "$TAG" "$SOURCE_COMMIT" -m "nodejs-mobile ${V}" -m "Recipe-Commit: ${GITHUB_SHA}" -m "Source-Tree: ${TREE}" -m "Upstream-Snapshot: ${UPSTREAM_SNAPSHOT:-none}"
fi
if [ "$DRY" = "1" ]; then
echo "DRY RUN: would push tag $TAG (materialized tree $(git rev-parse 'HEAD^{tree}'))"
else
git push fork "refs/tags/$TAG"
echo "Pushed tag $TAG"
fi

- name: Create GitHub Release (prerelease)
run: |
TAG="v${V}"
RELEASE_TITLE="Node.js 24 LTS · nodejs-mobile v${V}(预发布)"
MAJOR="${V%%.*}"
if [ "$MAJOR" = 24 ]; then
LINE="Node.js 24 LTS"
else
LINE="Node.js ${MAJOR}"
fi
RELEASE_TITLE="${LINE} · nodejs-mobile v${V} (Prerelease)"
if [ -n "$UPSTREAM_SNAPSHOT" ]; then
RELEASE_TITLE="${LINE} · nodejs-mobile v${V} (Upstream PR Snapshot Prerelease)"
python3 - <<'PY'
import os
from pathlib import Path
path = Path(os.environ['RUNNER_TEMP']) / 'release-notes.md'
sha = os.environ['UPSTREAM_SNAPSHOT']
notice = ("**Upstream proposal snapshot:** this prerelease is built from an "
"unreleased Node.js proposal, not an official Node.js release tag. "
f"Pinned upstream commit: [{sha}](https://github.com/nodejs/node/commit/{sha}). "
"The final upstream release may differ.\n\n")
path.write_text(notice + path.read_text())
PY
fi
NOTES=$(cat "$RUNNER_TEMP/release-notes.md")
# Human-visible copy of the tag's Recipe-Commit trailer.
PROV="Generated from [\`recipe@${GITHUB_SHA:0:10}\`](https://github.com/${GITHUB_REPOSITORY}/commit/${GITHUB_SHA})."
PROV="Generated from [\`${GITHUB_REF_NAME}@${GITHUB_SHA:0:10}\`](https://github.com/${GITHUB_REPOSITORY}/commit/${GITHUB_SHA})."
if [ "$DRY" = "1" ]; then
echo "DRY RUN: would publish prerelease $TAG with:"
ls -la out
printf '%s\n' "--- notes ---" "$NOTES" "" "$PROV"
else
BODY="$(printf '%s\n\n%s' "${NOTES:-Release ${V}. See https://github.com/${GITHUB_REPOSITORY}/blob/recipe/docs/CHANGELOG.md}" "$PROV")"
printf '%s\n\n%s\n' "$NOTES" "$PROV" > "$RUNNER_TEMP/publish-notes.md"
# Draft first, flip live once the assets are attached: with
# immutable releases enabled a release rejects asset uploads the
# moment it is published, and `gh release create` publishes
Expand All @@ -1347,13 +1387,13 @@ jobs:
gh release delete "$TAG" --yes --repo "$GITHUB_REPOSITORY"
echo "Deleted leftover draft for $TAG"
fi
gh release create "$TAG" out/*.zip \
gh release create "$TAG" out/*.zip out/SHA256SUMS \
--repo "$GITHUB_REPOSITORY" \
--title "$RELEASE_TITLE" \
--draft \
--prerelease \
--latest=false \
--notes "$BODY"
--notes-file "$RUNNER_TEMP/publish-notes.md"
gh release edit "$TAG" --repo "$GITHUB_REPOSITORY" --draft=false
echo "Published prerelease $TAG"
fi
13 changes: 12 additions & 1 deletion .github/workflows/cut-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ on:
type: string
default: auto
required: true
upstream_snapshot:
description: Optional full upstream SHA; explicitly prepare an unreleased proposal prerelease
type: string
default: ''
operation:
description: Preview the plan, or open a release review PR
type: choice
Expand Down Expand Up @@ -52,9 +56,11 @@ jobs:
env:
RELEASE_LINE: ${{ inputs.release_line }}
REQUESTED_VERSION: ${{ inputs.version }}
UPSTREAM_SNAPSHOT: ${{ inputs.upstream_snapshot }}
run: |
python3 scripts/release-control.py plan --root release-source \
--line "$RELEASE_LINE" --version "$REQUESTED_VERSION" \
--upstream-snapshot "$UPSTREAM_SNAPSHOT" \
--out "$RUNNER_TEMP/release-plan.json"
python3 - <<'PY'
import json, os, subprocess
Expand All @@ -69,6 +75,7 @@ jobs:
f"- Line: `{data['line']}`\n"
f"- Source: `{data['source_commit']}`\n"
f"- Upstream: `{data['upstream']}`\n"
f"- Unreleased upstream snapshot: `{data['upstream_snapshot'] or 'none'}`\n"
f"- Tag: `{data['tag']}`\n"
"- GitHub prerelease: **yes**, latest: **no**\n\n"
"Plan only: no tag, release or source mutation. "
Expand Down Expand Up @@ -103,18 +110,21 @@ jobs:
RELEASE_LINE: ${{ steps.v.outputs.line }}
RELEASE_BRANCH: ${{ steps.v.outputs.release_branch }}
V: ${{ steps.v.outputs.version }}
UPSTREAM_SNAPSHOT: ${{ steps.v.outputs.upstream_snapshot }}
run: |
set -euo pipefail
git config user.name "nodejs-mobile-bot"
git config user.email "bot@users.noreply.github.com"
git checkout -b "$RELEASE_BRANCH"
git add mobile-src/src/node_mobile_version.h docs/CHANGELOG.md expected-tree.txt release-ready.txt
git add mobile-src/src/node_mobile_version.h docs/CHANGELOG.md expected-tree.txt release-ready.txt release-upstream-snapshot.txt
git commit -m "release: prepare nodejs-mobile ${V} prerelease"
# No force push; existing release branches are reserved in plan.
git push origin "$RELEASE_BRANCH"
cat > "$RUNNER_TEMP/release-pr.md" <<EOF
Prepare **nodejs-mobile ${V}** on **${RELEASE_LINE}** for manual prerelease publication.

Unreleased upstream snapshot: **${UPSTREAM_SNAPSHOT:-none}**.

- [x] The chosen version matches this line's upstream source.
- [x] The tag/revision and release branch are unused.
- [x] Source checksum reconstructed with prepare.sh.
Expand All @@ -123,6 +133,7 @@ jobs:
Existing notes for this version are preserved; fill any TODO before publication.
Merge this PR, then run **Build** on **${RELEASE_LINE}**, choose
**prerelease** (or **prerelease-dryrun**) and version **${V}**.
For a snapshot, also supply this exact **upstream_snapshot** SHA again.
A merge alone does not publish. Every build and device gate must pass;
the release is a GitHub prerelease with latest=false. This mirror does
not claim physical-device validation. See docs/RELEASING.md.
Expand Down
32 changes: 24 additions & 8 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,30 @@
<a id="24.22.0-0"></a>
## Unreleased, Version 24.22.0-0 (Current)

### Notable Changes

- **Engine:** preview Node.js 24.22.0 LTS release proposal [nodejs/node#66667](https://github.com/nodejs/node/pull/66667), pinned to `a5d0eb95dd03b90986ad1a7c0cd3f2de1a0f383c`. This is an upstream proposal snapshot, not an official Node.js release tag.
- **Lite:** retain the reviewed danmu ICU data profile, feature omissions, Android 64-bit pointer compression and ABI-preserving SDK symbol stripping. Both flavors keep the full ICU API; iOS keeps jitless V8 and polywasm without pointer compression.
- **Mobile compatibility:** use upstream's new `V8_ENABLE_WEBASSEMBLY` guard for JSPI and preserve the remaining platform patches.
- **Tests/builds:** add 26 in-process upstream regressions to the curated gate, triage new child-process/permission cases, and build both iOS flavors on upgrade PRs. Reuse the bounded Android emulator shards already validated on the Node 26 line.
- **Artifacts:** successful upgrade builds package Android/iOS full/lite previews with source metadata and `SHA256SUMS`. Ordinary builds do not publish a release.
- **Device regressions:** preserve Intl and SQLite backup in-process coverage while skipping only unsupported child probes; use the observed mobile filesystem error and exclude a native WASM flag test only on iOS. These three runnable regressions also join the curated gate.
This prerelease updates the mobile runtime from Node.js 24.21.0 to the
Node.js 24.22.0 LTS release proposal [nodejs/node#66667](https://github.com/nodejs/node/pull/66667),
pinned to `a5d0eb95dd03b90986ad1a7c0cd3f2de1a0f383c`. It is built from an
upstream proposal snapshot; the final official Node.js release may differ.

### Runtime and flavor changes

- **Full:** embed complete ICU data for locale formatting, collation and legacy text decoding. The previous 24.21.0-0 full release used small-ICU; complete ICU data accounts for most of the increased binary size.
- **Lite:** retain the reviewed `danmu_api` ICU data profile. Both flavors keep the complete ICU API; lite preserves all Node TextDecoder web encodings (including GBK, GB2312 and Big5), English/Chinese/Cantonese/Japanese/Korean locale families, Unicode normalization, IDNA, time zones and segmentation. Other locale-specific formatting may fall back to a retained locale.
- **Lite omissions:** omit Amaro TypeScript stripping, Inspector, SQLite/Web Storage, single-executable application support and native V8 object-print helpers. Keep HTTP/HTTPS/TLS, crypto, fetch/Undici, filesystem and module loading, streams, compression and WebAssembly support.
- **Android:** retain JIT and native WebAssembly. Lite uses V8 pointer compression on 64-bit targets and strips its SDK libraries only after verifying that dynamic exports remain unchanged. Direct V8 native addons must match the selected flavor's ABI.
- **iOS:** retain jitless V8 and the polywasm WebAssembly implementation, without pointer compression. Both packages include arm64 device and arm64 simulator slices.
- **Mobile compatibility:** rebase the platform patches onto the proposed LTS source and adopt upstream's `V8_ENABLE_WEBASSEMBLY` guard.

### Validation and downloads

- Build Android arm64-v8a, armeabi-v7a and x86_64 libraries and iOS device/simulator frameworks in both full and lite flavors.
- Require host checks, boot and native-addon smokes, full/lite ICU checks, curated device tests and complete runnable Android/iOS suites in the publication workflow. Runtime validation uses Android emulators and iOS simulators; this release does not claim physical-device validation.
- Fix Android launch failures before Node starts and improve iOS smoke launch and verdict collection. Preserve in-process Intl and SQLite regression coverage while skipping unsupported mobile child-process probes.
- Provide four SDK archives with headers: `nodejs-mobile-android-24.22.0-0.zip`, `nodejs-mobile-android-lite-24.22.0-0.zip`, `nodejs-mobile-ios-24.22.0-0.zip` and `nodejs-mobile-ios-lite-24.22.0-0.zip`, plus `SHA256SUMS`.

For `danmu_api`, use the lite package when its retained feature and locale
profile matches your application. Verify the selected archive against
`SHA256SUMS` before integration.

This source upgrade does not arm publication.

Expand Down
16 changes: 16 additions & 0 deletions docs/RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,22 @@ have FFI and no ICU; the older 26.1 release disables both features.
iOS uses jitless V8 and the bundled WebAssembly polyfill. See
[VERSION-LINES.md](VERSION-LINES.md) for compatibility limits.

## Upstream proposal snapshot prereleases

An unreleased upstream proposal can be published as a GitHub prerelease only
with explicit `upstream_snapshot` input in both manual workflows. Supply the
full SHA already pinned in `upstream-base.txt`; it cannot select a different
commit. The controller reads `src/node_version.h` from official `nodejs/node`
to verify the selected version and line.

Cut release records both the version and exact snapshot SHA in the reviewed
release PR. After merging it, dispatch Build on the same maintained line with
`operation=prerelease`, that exact version, and the same `upstream_snapshot`.
All ordinary build and release gates still apply. The release title and English
body identify the upstream proposal snapshot and link the immutable commit.
The final official upstream release may differ. This does not alter the other
maintained Node major line.

## Source tags and provenance

Tags point at full-source snapshot commits whose tree matches
Expand Down
Loading