Skip to content

Publish to npm (v0.2.2, dispatch 30483010223) #4

Publish to npm (v0.2.2, dispatch 30483010223)

Publish to npm (v0.2.2, dispatch 30483010223) #4

Workflow file for this run

name: Publish to npm
# The single npm publishing path: publishes the npm packages for an existing
# GitHub release from the binaries attached to it, without cutting a new
# release. Normally dispatched by release.yml after it publishes the GitHub
# release; run it manually against the same tag to retry a partial or failed
# publish. Only the repository's newest stable vX.Y.Z tag is accepted —
# prereleases, malformed tags, and older releases are refused and must be
# published manually. Per package, already-published versions are skipped
# and the version must be strictly newer than the package's current npm
# `latest`, so a retry publishes exactly the packages a partial earlier run
# missed and the workflow can never move `latest` backwards. Keeping all
# publishing in one workflow file lets npm's trusted publisher config (one
# per package, matched by workflow filename) cover every publish.
on:
workflow_dispatch:
inputs:
tag:
description: "Existing GitHub release tag whose binaries to publish (e.g. v0.2.1)"
required: true
dispatch_id:
description: "Opaque id embedded in the run name so a dispatching workflow can find this exact run (leave empty for manual runs)"
required: false
default: ""
# The dispatch_id in the run name is what release.yml greps for to identify
# the run it dispatched — it matches "dispatch <id>)" including the closing
# paren, so the id must stay immediately before the final ")". Do not reword
# without updating the matching filter there.
run-name: "Publish to npm (${{ inputs.tag }}${{ inputs.dispatch_id != '' && format(', dispatch {0}', inputs.dispatch_id) || '' }})"
env:
TAG: ${{ github.event.inputs.tag }}
jobs:
npm:
name: Publish to npm
runs-on: ubuntu-latest
permissions:
# Publishing authenticates via npm trusted publishing: the job mints a
# GitHub OIDC token that npm verifies against each package's trusted
# publisher config (this repo + this workflow filename). No registry
# token exists anywhere.
id-token: write
contents: read
steps:
- name: Require the newest stable vX.Y.Z tag
run: |
if ! printf '%s' "$TAG" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error::Tag '$TAG' is not a stable vX.Y.Z release tag. Prerelease and other tags must be published manually."
exit 1
fi
# Only the newest stable tag may be published: retrying it fills in
# packages a partial earlier run missed, but older tags are refused
# outright — backpublishing is a manual operation. sort -V is safe
# here because the grep leaves only plain X.Y.Z versions.
NEWEST="$(gh api "repos/${GITHUB_REPOSITORY}/tags" --paginate --jq '.[].name' \
| grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n1)"
if [ "$TAG" != "$NEWEST" ]; then
echo "::error::Tag '$TAG' is not the newest stable release tag ('$NEWEST'). Backpublishing older releases must be done manually."
exit 1
fi
env:
GH_TOKEN: ${{ github.token }}
# The tag's tree is what gets published: packaging scripts and package
# metadata come from the tag itself, so a republish is reproducible.
# Consequence: this only works for tags that contain scripts/build-npm.mjs.
- uses: actions/checkout@v4
with:
ref: ${{ env.TAG }}
# No registry-url here: setup-node would write an .npmrc authToken
# line referencing $NODE_AUTH_TOKEN, and npm hard-fails on any command
# when a referenced env var is unset. Trusted publishing needs no
# token; npm publish detects the OIDC environment on its own.
- uses: actions/setup-node@v4
with:
node-version: "24"
# npm >= 11.5.1 is required for trusted publishing; the runner's
# bundled npm may lag. Both tools installed up front so a fetch
# failure is a loud step failure (npx-on-demand in the publish loop
# would be indistinguishable from "version not newer" and silently
# skip a package), and pinned to exact versions: this is the only
# third-party code fetched into the job that holds publish rights for
# the @provablehq packages, and npm versions are immutable, so a pin
# closes off both drift and package-takeover of new releases.
- name: Install pinned npm and semver CLI
run: npm install -g npm@12.0.1 semver@7.8.5
- name: Download release assets
run: gh release download "$TAG" --pattern '*.zip' --dir artifacts
env:
GH_TOKEN: ${{ github.token }}
- name: Extract binaries by target
run: |
# artifacts/aleo-devnode-<tag>-<target>.zip
# -> bins/<target>/aleo-devnode[.exe]
for zip in artifacts/*.zip; do
base="$(basename "$zip" .zip)"
target="${base#aleo-devnode-${TAG}-}"
mkdir -p "bins/$target"
unzip -o "$zip" -d "bins/$target"
done
- name: Build npm packages
run: node scripts/build-npm.mjs --version "${TAG#v}" --artifacts bins --out dist-npm
- name: Publish
run: |
set -e
VERSION="${TAG#v}"
# Skip already-published packages so a partial earlier publish can
# be resumed. Platform packages first, then the main launcher last,
# so main's exact-pinned optionalDependencies always resolve on
# install.
publish() {
local name latest
name="$(node -p "require('./$1/package.json').name")"
if npm view "${name}@${VERSION}" version >/dev/null 2>&1; then
echo "${name}@${VERSION} already published, skipping"
return
fi
# Never publish backwards: unless this version is strictly newer
# than the package's current npm latest, skip it — publishing
# would move the `latest` dist-tag onto an older version. Real
# semver comparison (not sort -V), so a manually published
# prerelease latest ranks below its release: 0.3.0-rc.1 < 0.3.0.
latest="$(npm view "$name" dist-tags.latest 2>/dev/null || true)"
if [ -n "$latest" ] && ! semver -r ">${latest}" "$VERSION" >/dev/null; then
echo "${name}: npm latest (${latest}) >= ${VERSION}, skipping"
return
fi
npm publish "$1" --access public
}
# The ./ prefix is load-bearing: a bare "dist-npm/<name>" matches
# npm's GitHub owner/repo shorthand and is fetched over git instead
# of being read as a directory.
for pkg in dist-npm/*/; do
[ "$pkg" = "dist-npm/main/" ] && continue
publish "./${pkg%/}"
done
publish ./dist-npm/main