ci(ci): published native leaf packages per target in the release flow
- CI now enabled OIDC publishing in the build matrix, installed Node 24/npm, and added a per-target native addon publish step. - The release script now accepts `--native-leaf <tag>` and publishes only the matching generated native leaf package. - Native package generation gained optional tag filtering with validation of requested leaf tags for targeted release publishing.
This commit is contained in:
@@ -368,11 +368,20 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: "1.3"
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "24"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
# Trusted publishing allowed-actions flags require npm >= 11.16.0.
|
||||
- name: Ensure npm supports trusted publishing
|
||||
if: ${{ !inputs.skip_npm }}
|
||||
run: npm install -g npm@latest
|
||||
- name: Cache bun dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
@@ -399,6 +408,14 @@ jobs:
|
||||
runtime_dir="$(mktemp -d)"
|
||||
HOME="$runtime_dir/home" XDG_DATA_HOME="$runtime_dir/xdg" "${{ matrix.binary_path }}" --version
|
||||
HOME="$runtime_dir/home" XDG_DATA_HOME="$runtime_dir/xdg" "${{ matrix.binary_path }}" --smoke-test
|
||||
- name: Publish native addon package
|
||||
if: ${{ !inputs.skip_npm }}
|
||||
env:
|
||||
# Fallback auth: setup-node wrote an .npmrc referencing
|
||||
# NODE_AUTH_TOKEN; npm uses it only when OIDC has no trusted
|
||||
# publisher for the package (or on a first publish).
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
run: bun run ci:release:publish-native-leaf ${{ matrix.target_id }}
|
||||
- name: Upload release binary artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
@@ -457,7 +474,7 @@ jobs:
|
||||
needs.release_binary.result == 'success' &&
|
||||
needs.release_github_verify.result == 'success' &&
|
||||
!inputs.skip_npm }}
|
||||
needs: [release_binary, release_github_verify, rust-hash]
|
||||
needs: [release_binary, release_github_verify]
|
||||
runs-on: ubuntu-22.04
|
||||
# `id-token: write` lets npm mint the GitHub OIDC token it exchanges for a
|
||||
# short-lived publish token (trusted publishing + provenance). When a
|
||||
@@ -484,12 +501,6 @@ jobs:
|
||||
path: ~/.bun/install/cache
|
||||
key: bun-${{ runner.os }}-${{ hashFiles('**/bun.lock') }}
|
||||
- run: bun install --frozen-lockfile
|
||||
- name: Download native addons
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: pi-natives-*-h${{ needs.rust-hash.outputs.hash }}
|
||||
path: packages/natives/native
|
||||
merge-multiple: true
|
||||
- name: Publish to npm
|
||||
env:
|
||||
# Fallback auth: setup-node wrote an .npmrc referencing
|
||||
|
||||
@@ -115,6 +115,7 @@
|
||||
"ci:test:install-methods": "bash scripts/install-tests/run-ci.sh",
|
||||
"ci:release:build-binaries": "bun scripts/ci-release-build-binaries.ts",
|
||||
"ci:release:publish": "bun scripts/ci-release-publish.ts",
|
||||
"ci:release:publish-native-leaf": "bun scripts/ci-release-publish.ts --native-leaf",
|
||||
"bench:gen-fixtures": "bun --cwd=packages/typescript-edit-benchmark run src/generate.ts --typescript-dir /tmp/typescript-source --count-per-type 8",
|
||||
"bench:edit": "bun --cwd=packages/typescript-edit-benchmark run start",
|
||||
"stats:sync": "python3 scripts/session-stats/sync.py",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import * as fs from "node:fs/promises";
|
||||
import * as path from "node:path";
|
||||
|
||||
interface LeafTarget {
|
||||
export interface LeafTarget {
|
||||
tag: string;
|
||||
os: string;
|
||||
cpu: string;
|
||||
@@ -44,6 +44,7 @@ export interface GenerateNpmPackagesInput {
|
||||
packageDir?: string;
|
||||
dryRun?: boolean;
|
||||
version?: string;
|
||||
tags?: readonly string[];
|
||||
}
|
||||
|
||||
export const LEAF_TARGETS: readonly LeafTarget[] = [
|
||||
@@ -108,10 +109,23 @@ function buildReadme(tag: string, manifest: LeafManifest): string {
|
||||
return `# ${manifest.name}\n\nPlatform native addon package for \`@oh-my-pi/pi-natives\` on ${tag}.\n\nThis package is generated during release and installed as an optional dependency of the core package.\n`;
|
||||
}
|
||||
|
||||
function selectTargets(tags: readonly string[] | undefined): readonly LeafTarget[] {
|
||||
if (!tags) return LEAF_TARGETS;
|
||||
const wanted = new Set(tags);
|
||||
const targets = LEAF_TARGETS.filter(target => wanted.has(target.tag));
|
||||
if (targets.length !== wanted.size) {
|
||||
const known = new Set(LEAF_TARGETS.map(target => target.tag));
|
||||
const unknown = tags.filter(tag => !known.has(tag));
|
||||
throw new Error(`Unknown native package tag(s): ${unknown.join(", ")}`);
|
||||
}
|
||||
return targets;
|
||||
}
|
||||
|
||||
export async function generateNpmPackages({
|
||||
packageDir = packageDirDefault,
|
||||
dryRun = false,
|
||||
version,
|
||||
tags,
|
||||
}: GenerateNpmPackagesInput = {}): Promise<GeneratedLeafPackage[]> {
|
||||
const manifestVersion =
|
||||
version ?? ((await Bun.file(path.join(packageDir, "package.json")).json()) as { version: string }).version;
|
||||
@@ -119,7 +133,7 @@ export async function generateNpmPackages({
|
||||
const npmDir = path.join(packageDir, "npm");
|
||||
const leaves: GeneratedLeafPackage[] = [];
|
||||
|
||||
for (const target of LEAF_TARGETS) {
|
||||
for (const target of selectTargets(tags)) {
|
||||
const files = await discoverAddonFiles(nativeDir, target.tag);
|
||||
const manifestFiles = files.length > 0 ? files : [expectedAddonFilenames(target.tag)[0]];
|
||||
const manifest = buildLeafManifest({ ...target, files: manifestFiles, version: manifestVersion });
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
/**
|
||||
* Publish workspace packages.
|
||||
*
|
||||
* The default mode publishes public JS packages and the `@oh-my-pi/pi-natives`
|
||||
* core package. Generated native leaf packages are published separately with
|
||||
* `--native-leaf <tag>` from the release_binary matrix after that matrix entry
|
||||
* downloads the matching `.node` artifacts.
|
||||
*
|
||||
* For each public TypeScript package we:
|
||||
* 1. Emit `.d.ts` declarations into `dist/types/` so consumers get
|
||||
* stable types regardless of their tsconfig `lib`.
|
||||
@@ -54,6 +59,21 @@ interface PackageManifest extends JsonObject {
|
||||
|
||||
const repoRoot = path.join(import.meta.dir, "..");
|
||||
const isDryRun = process.argv.includes("--dry-run");
|
||||
|
||||
function nativeLeafTagFromArgs(argv: readonly string[]): string | null {
|
||||
for (let i = 0; i < argv.length; i++) {
|
||||
const arg = argv[i];
|
||||
if (arg === "--native-leaf") {
|
||||
const tag = argv[i + 1];
|
||||
if (!tag) throw new Error("--native-leaf requires a native target tag");
|
||||
return tag;
|
||||
}
|
||||
if (arg.startsWith("--native-leaf=")) return arg.slice("--native-leaf=".length);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const nativeLeafTag = nativeLeafTagFromArgs(process.argv.slice(2));
|
||||
export const packages: PublishPackage[] = [
|
||||
{ dir: "packages/utils", kind: "typescript" },
|
||||
{ dir: "packages/ai", kind: "typescript" },
|
||||
@@ -216,14 +236,20 @@ async function publishGeneratedLeafPackage(leaf: GeneratedLeafPackage): Promise<
|
||||
await packAndPublish(leaf.dir, leaf.manifest.name);
|
||||
}
|
||||
|
||||
async function publishNativePackage(pkg: PublishPackage): Promise<void> {
|
||||
async function publishNativeLeafPackage(tag: string): Promise<void> {
|
||||
const pkg = packages.find(candidate => candidate.kind === "native");
|
||||
if (!pkg) throw new Error("No native package configured");
|
||||
const pkgDir = path.join(repoRoot, pkg.dir);
|
||||
const coreManifest = (await Bun.file(path.join(pkgDir, "package.json")).json()) as PackageManifest;
|
||||
if (typeof coreManifest.version !== "string") throw new Error(`Missing version in ${pkg.dir}/package.json`);
|
||||
const leaves = await generateNpmPackages({ packageDir: pkgDir, dryRun: isDryRun, version: coreManifest.version });
|
||||
for (const leaf of leaves) {
|
||||
const leaves = await generateNpmPackages({ packageDir: pkgDir, dryRun: isDryRun, version: coreManifest.version, tags: [tag] });
|
||||
const leaf = leaves[0];
|
||||
if (!leaf) throw new Error(`No native leaf generated for ${tag}`);
|
||||
await publishGeneratedLeafPackage(leaf);
|
||||
}
|
||||
|
||||
async function publishNativePackage(pkg: PublishPackage): Promise<void> {
|
||||
const pkgDir = path.join(repoRoot, pkg.dir);
|
||||
const manifest = await prepareNativeCorePackage(pkgDir, !isDryRun);
|
||||
const name = manifest.name ?? path.basename(pkg.dir);
|
||||
if (isDryRun) {
|
||||
@@ -249,7 +275,11 @@ async function publishPackage(pkg: PublishPackage): Promise<void> {
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
if (nativeLeafTag) {
|
||||
await publishNativeLeafPackage(nativeLeafTag);
|
||||
} else {
|
||||
for (const pkg of packages) {
|
||||
await publishPackage(pkg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user