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
48 changes: 37 additions & 11 deletions .github/workflows/npm_release.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
name: npm release

# Publishes the classic runtime — @nativescript/windows — and the four engine variants —
# @nativescript/windows-{hermes,jsc,quickjs,v8} — to npm via OIDC trusted publishing. npm matches
# a trusted publisher on repository + workflow FILENAME + environment, so `npm_release.yml` and the
# `npm-publish` environment below are part of the credential: renaming either breaks publishing for
# all five packages, and every package needs its own trusted-publisher entry on npmjs.com.
# Publishes the classic runtime — @nativescript/windows — the four engine variants —
# @nativescript/windows-{hermes,jsc,quickjs,v8} — and the Node-API addon — @nativescript/windows-napi
# — to npm via OIDC trusted publishing. npm matches a trusted publisher on repository + workflow
# FILENAME + environment, so `npm_release.yml` and the `npm-publish` environment below are part of
# the credential: renaming either breaks publishing for all six packages, and every package needs
# its own trusted-publisher entry on npmjs.com.
#
# NOTE: `paths` filters deliberately do NOT accompany the tag trigger — a tag push can have an
# empty changed-file set, and paths+tags together silently skip the run.
on:
push:
tags:
- "v*" # -> all five packages at the tag's version
- "v*" # -> all six packages at the tag's version
workflow_dispatch:
inputs:
engine:
description: "Which package to release"
type: choice
required: true
default: all
options: [all, classic, hermes, jsc, quickjs, v8]
options: [all, classic, hermes, jsc, quickjs, v8, napi]
version:
description: "Release version to cut, e.g. 0.1.0-alpha.2 (dist-tag follows the prerelease id; a plain version publishes 'latest'). Leave empty for a rolling 'next' build."
required: false
Expand All @@ -30,7 +31,7 @@ on:
required: false
default: false
skip_arm64:
description: "Classic only: build x64-only, skipping the arm64 cross-compiles (the engine variants are x64-only regardless)."
description: "Classic and napi: build x64-only, skipping the arm64 cross-compiles (the engine variants are x64-only regardless)."
type: boolean
required: false
default: false
Expand All @@ -50,6 +51,10 @@ permissions:
# template/framework and builds the engine cdylib into packages/windows-<engine>/framework
# as framework/libs/x64/nativescript.dll (x64 only, no devtools).
#
# napi `napi build --target <triple>` for each of `rust_targets` puts a
# windows-napi/windows.<triple>.node per arch into the one package; its loader picks
# the one for the running CPU.
#
# A release is: setup (resolve version + package matrix) -> build (one Windows job per package,
# npm pack) -> publish (npm, OIDC). Everything the variants need is committed under
# template/framework, so a variant build only compiles the engine; `rebuild_framework` regenerates
Expand Down Expand Up @@ -118,7 +123,7 @@ jobs:
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
with:
toolchain: stable
# classic cross-compiles the arm64 runtime and tools; the variants build for the host.
# classic and napi cross-compile arm64 as well; the variants build for the host.
targets: ${{ matrix.rust_targets }}
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
Expand All @@ -134,6 +139,7 @@ jobs:
# profile dir is target/release for a host build and target/<triple>/<profile> for the
# classic cross builds, so every v8 build dir under the target roots is checked.
- name: Re-fetch rusty_v8's static lib when the cache pruned it
if: ${{ matrix.engine != 'napi' }}
shell: pwsh
run: |
foreach ($root in @('target', (Join-Path $env:PACKAGE_DIR 'target'))) {
Expand Down Expand Up @@ -169,14 +175,14 @@ jobs:
# The classic build publishes ManifestMerger and dotnet-typings-gen with `dotnet publish`
# every time; a variant only needs the SDK when it regenerates the shared framework.
- name: Setup .NET
if: ${{ matrix.engine == 'classic' || github.event_name == 'push' || inputs.rebuild_framework }}
if: ${{ matrix.engine == 'classic' || (matrix.engine != 'napi' && (github.event_name == 'push' || inputs.rebuild_framework)) }}
uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
# dotnet-typings-gen targets net10.0; ManifestMerger is netstandard2.0 and builds on it.
dotnet-version: "10.x"
- name: Rebuild shared framework
# Tag releases always rebuild, so a published variant never ships binaries built off CI.
if: ${{ matrix.engine != 'classic' && (github.event_name == 'push' || inputs.rebuild_framework) }}
if: ${{ matrix.engine != 'classic' && matrix.engine != 'napi' && (github.event_name == 'push' || inputs.rebuild_framework) }}
shell: pwsh
# -SkipRelease -SkipDevtools: the classic V8 nativescript.dll is not staged into a variant
# (the engine cdylib takes its place), so building it here would be thrown away.
Expand Down Expand Up @@ -210,7 +216,27 @@ jobs:
shell: pwsh
working-directory: ${{ matrix.dir }}
run: npm version $env:NPM_VERSION --no-git-tag-version --allow-same-version
- name: Build windows-napi
if: ${{ matrix.engine == 'napi' }}
shell: pwsh
working-directory: windows-napi
env:
RUST_TARGETS: ${{ matrix.rust_targets }}
run: |
$ErrorActionPreference = 'Stop'
npm ci
if ($LASTEXITCODE -ne 0) { throw "npm ci failed" }
foreach ($target in $env:RUST_TARGETS.Split(',')) {
npx napi build --platform --release --target $target
if ($LASTEXITCODE -ne 0) { throw "napi build failed for $target" }
}
$nodes = @(Get-ChildItem windows.*.node)
if ($nodes.Count -ne $env:RUST_TARGETS.Split(',').Count) {
throw "Expected one .node per target, found: $($nodes.Name -join ', ')"
}
$nodes | Format-Table Name, Length
- name: Build ${{ matrix.engine }} framework
if: ${{ matrix.engine != 'napi' }}
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
Expand Down
40 changes: 1 addition & 39 deletions .github/workflows/windows-napi.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
name: windows-napi

# NOTE: `paths` filters deliberately do NOT accompany the tag trigger — a tag push can have an
# empty changed-file set, and paths+tags together silently skip the run.
# Builds and tests the addon on pull requests. Releases publish it from npm_release.yml.
on:
push:
tags:
- 'windows-napi-v*'
pull_request:
paths:
- 'windows-napi/**'
Expand Down Expand Up @@ -60,37 +56,3 @@ jobs:
name: bindings-${{ matrix.settings.target }}
path: windows-napi/windows.*.node
if-no-files-found: error

publish:
name: publish to npm
if: startsWith(github.ref, 'refs/tags/windows-napi-v')
needs: build
runs-on: windows-latest
permissions:
contents: read
id-token: write # npm provenance
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 20
registry-url: https://registry.npmjs.org
- name: Install npm dependencies
working-directory: windows-napi
run: npm ci
- name: Download all binding artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: windows-napi/artifacts
- name: Distribute artifacts into npm/<triple> sub-packages
working-directory: windows-napi
run: npx napi artifacts
- name: Publish
working-directory: windows-napi
# `napi prepublish` (prepublishOnly script) publishes each npm/<triple> sub-package,
# then the root package publishes with them as optionalDependencies.
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
# Applies to the sub-package publishes `napi prepublish` runs as well.
NPM_CONFIG_PROVENANCE: "true"
18 changes: 7 additions & 11 deletions packages/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,10 @@ for the engine (above), then `npm publish` the package (each is `os:["win32"], c
classic package also ships arm64 + devtools). The CLI picks one, like android's `jsEngine` — and
because the packages are interchangeable, switching is a dependency swap.

**`@nativescript/windows-napi` — the Node/Bun/Deno `.node`** (`../windows-napi`):
napi-rs flow, **implemented in `.github/workflows/windows-napi.yml`**: a build matrix per triple
(`x86_64-pc-windows-msvc`, `aarch64-pc-windows-msvc`) runs `napi build --platform --release
--target <triple>` → `windows.<triple>.node` artifacts (the x64 job also runs the 366-check test
suite, non-blocking on server SKUs); pushing a **`windows-napi-v*` tag** triggers the publish job:
`napi artifacts` distributes the .node files into the committed `windows-napi/npm/<triple>/`
sub-packages, `napi prepublish` (the `prepublishOnly` script) publishes those, then the root
package publishes with them as `optionalDependencies`. Needs the `NPM_TOKEN` repo secret.
`index.js`/`index.d.ts`/`package-lock.json` are generated but committed (the publish job doesn't
build). If arm64 proves unbuildable (rusty_v8/libffi cross), drop the triple from the workflow
matrix, `napi.triples`, `optionalDependencies`, and `npm/win32-arm64-msvc/`.
**`@nativescript/windows-napi` — the Node/Bun/Deno `.node`** (`../windows-napi`): released by
`.github/workflows/npm_release.yml` with the packages above (`engine: napi`, also part of `all`).
The build runs `napi build --platform --release --target <triple>` for `x86_64-pc-windows-msvc`
and `aarch64-pc-windows-msvc` and packs both `windows.<triple>.node` files into the one package;
the generated loader picks the one for the running CPU. `.github/workflows/windows-napi.yml`
builds both triples and runs the test suite on pull requests. `index.js`/`index.d.ts`/
`package-lock.json` are generated but committed.
23 changes: 13 additions & 10 deletions scripts/resolve-release.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//
// One version covers every package in a run: the classic runtime and the four engine variants are
// the same framework built from the same commit and differ only in the runtime DLL, so they
// release in lockstep.
// release in lockstep. The windows-napi addon is built from the same runtime crate and follows.
//
// The repo has no root package.json, so this stays dependency-free — no semver/dayjs, and no
// `npm install` step in front of it.
Expand All @@ -32,6 +32,8 @@ const PACKAGES = {
jsc: { dir: "packages/windows-jsc", name: "@nativescript/windows-jsc" },
quickjs: { dir: "packages/windows-quickjs", name: "@nativescript/windows-quickjs" },
v8: { dir: "packages/windows-v8", name: "@nativescript/windows-v8" },
// The Node-API addon: one package carrying a `windows.<triple>.node` per target.
napi: { dir: "windows-napi", name: "@nativescript/windows-napi" },
};
const ENGINES = Object.keys(PACKAGES);

Expand All @@ -40,7 +42,8 @@ const USAGE = `Usage: node scripts/resolve-release.mjs [--version <version>] [--
--version release version to cut (leading "v" allowed); empty or omitted resolves from
GITHUB_REF (v* tag) or falls back to a rolling "next" prerelease
--engine all (default) | ${ENGINES.join(" | ")}
--skip-arm64 build the classic package x64-only (the engine variants are x64-only regardless)
--skip-arm64 build classic and windows-napi x64-only (the engine variants are x64-only
regardless)
-h, --help show this help`;

let values;
Expand Down Expand Up @@ -141,24 +144,24 @@ const tag = npmTag(parseVersion(version, "Release version"), version);
// dir where package.json lives (npm version / npm pack run there)
// npm_name the published name
// tarball what `npm pack` emits ("@scope/name" -> "scope-name-<version>.tgz")
// rust_targets extra Rust targets the toolchain must install (classic cross-compiles arm64)
// rust_targets Rust targets to install and build: classic and napi also build arm64, and
// napi builds one `.node` per target
// rust_workspaces the Swatinem/rust-cache `workspaces` mapping; the engine packages are excluded
// from the root workspace and build into their own target/ dir
const allArchs = values["skip-arm64"]
? "x86_64-pc-windows-msvc"
: "x86_64-pc-windows-msvc,aarch64-pc-windows-msvc";
const matrix = {
include: engines.map((e) => {
const pkg = PACKAGES[e];
const classic = e === "classic";
const inRootWorkspace = e === "classic" || e === "napi";
return {
engine: e,
dir: pkg.dir,
npm_name: pkg.name,
tarball: `${pkg.name.replace(/^@/, "").replace("/", "-")}-${version}.tgz`,
rust_targets: classic
? values["skip-arm64"]
? "x86_64-pc-windows-msvc"
: "x86_64-pc-windows-msvc,aarch64-pc-windows-msvc"
: "",
rust_workspaces: classic ? ". -> target" : `. -> target\n${pkg.dir} -> target`,
rust_targets: inRootWorkspace ? allArchs : "",
rust_workspaces: inRootWorkspace ? ". -> target" : `. -> target\n${pkg.dir} -> target`,
};
}),
};
Expand Down
2 changes: 1 addition & 1 deletion windows-napi/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
node_modules/
# napi-rs binary outputs (CI builds per-triple; npm/<triple>/ receives them at publish time)
# napi-rs binary outputs (the release build packs one per triple)
*.node
artifacts/
# index.js / index.d.ts / package-lock.json are generated but COMMITTED: the publish CI job
Expand Down
3 changes: 0 additions & 3 deletions windows-napi/npm/win32-arm64-msvc/README.md

This file was deleted.

18 changes: 0 additions & 18 deletions windows-napi/npm/win32-arm64-msvc/package.json

This file was deleted.

3 changes: 0 additions & 3 deletions windows-napi/npm/win32-x64-msvc/README.md

This file was deleted.

18 changes: 0 additions & 18 deletions windows-napi/npm/win32-x64-msvc/package.json

This file was deleted.

4 changes: 2 additions & 2 deletions windows-napi/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 1 addition & 7 deletions windows-napi/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,14 @@
"scripts": {
"build": "napi build --platform --release",
"build:debug": "napi build --platform",
"artifacts": "napi artifacts",
"prepublishOnly": "napi prepublish -t npm --skip-gh-release",
"test": "node test/run-tests.js"
},
"repository": {
"type": "git",
"url": "https://github.com/triniwiz/windows-runtime.git",
"url": "https://github.com/NativeScript/windows",
"directory": "windows-napi"
},
"devDependencies": {
"@napi-rs/cli": "^2.18.0"
},
"optionalDependencies": {
"@nativescript/windows-napi-win32-x64-msvc": "0.1.0",
"@nativescript/windows-napi-win32-arm64-msvc": "0.1.0"
}
}