mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-19 05:29:46 +08:00
- packages/compiler/surface-manifest.json is generated (pnpm manifest), committed, and shipped in @scriptc/compiler; entries project mechanically from the diagnostics registry, the unsupported-syntax dispatch tables, the stdlib/builtin lowering tables, and the supported-builtin-module list - every non-static entry carries the SC code the compiler raises for it, and the version spine is the exact published release version - FENCE_CODES joins the diagnostics registry so factory-minted construct fences are enumerable - the sampling harness compiles listed-static probes and asserts each sampled non-static entry refuses with exactly its listed code, beside a byte-identical staleness guard - the release workflow regenerates the manifest, fails on drift, and attaches it to the GitHub release
213 lines
7.7 KiB
YAML
213 lines
7.7 KiB
YAML
name: Release
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
workflow_dispatch:
|
|
|
|
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
|
|
|
jobs:
|
|
check-release:
|
|
name: Check for new version
|
|
# The private mirror carries this file too; only the public repo
|
|
# publishes (the trusted publisher is pinned to it).
|
|
if: github.repository == 'vercel-labs/scriptc'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
permissions:
|
|
contents: read
|
|
outputs:
|
|
should_release: ${{ steps.check.outputs.should_release }}
|
|
version: ${{ steps.check.outputs.version }}
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: "24"
|
|
registry-url: "https://registry.npmjs.org"
|
|
|
|
- name: Compare package.json version to npm
|
|
id: check
|
|
run: |
|
|
LOCAL_VERSION=$(node -p "require('./packages/cli/package.json').version")
|
|
echo "Local version: $LOCAL_VERSION"
|
|
|
|
NPM_VERSION=$(npm view scriptc version 2>/dev/null || echo "0.0.0")
|
|
echo "npm version: $NPM_VERSION"
|
|
|
|
if [ "$LOCAL_VERSION" != "$NPM_VERSION" ]; then
|
|
echo "Version changed: $NPM_VERSION -> $LOCAL_VERSION"
|
|
echo "should_release=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "Version unchanged on npm, skipping publish"
|
|
echo "should_release=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
echo "version=$LOCAL_VERSION" >> "$GITHUB_OUTPUT"
|
|
|
|
publish:
|
|
name: Publish to npm
|
|
needs: check-release
|
|
if: needs.check-release.outputs.should_release == 'true'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
environment: Release
|
|
permissions:
|
|
contents: read
|
|
id-token: write
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup pnpm
|
|
uses: pnpm/action-setup@v4
|
|
with:
|
|
version: 11
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: "24"
|
|
registry-url: "https://registry.npmjs.org"
|
|
|
|
# Publishing uses npm trusted publishing (OIDC): the job's id-token
|
|
# permission lets npm mint short-lived credentials, so no npm token
|
|
# secret exists anywhere in this repo. All three packages —
|
|
# @scriptc/runtime, @scriptc/compiler, scriptc — must each be
|
|
# configured on npmjs.com with a GitHub Actions trusted publisher
|
|
# pointing at repository vercel-labs/scriptc, workflow release.yml,
|
|
# environment Release. A package missing that configuration fails
|
|
# with an OIDC authentication error before anything uploads.
|
|
# Trusted publishing requires npm >= 11.5.1 (bundled with Node 24).
|
|
|
|
- name: Install and build
|
|
run: |
|
|
pnpm install --frozen-lockfile
|
|
pnpm -r build
|
|
|
|
- name: Check version sync
|
|
run: |
|
|
VERSION="${{ needs.check-release.outputs.version }}"
|
|
for pkg in packages/runtime packages/compiler packages/cli; do
|
|
V=$(node -p "require('./$pkg/package.json').version")
|
|
if [ "$V" != "$VERSION" ]; then
|
|
echo "Version mismatch: $pkg is $V, expected $VERSION"
|
|
echo "Run 'node scripts/sync-versions.mjs' to stamp runtime and compiler from the CLI version, then commit"
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
- name: Publish to npm
|
|
run: |
|
|
VERSION="${{ needs.check-release.outputs.version }}"
|
|
|
|
# npm accepts --provenance only from PUBLIC source repositories;
|
|
# while this repo is internal the flag is dropped, and the same
|
|
# step starts attaching provenance the moment the repo goes
|
|
# public — no workflow edit.
|
|
VISIBILITY=$(gh api "repos/${{ github.repository }}" --jq .visibility)
|
|
if [ "$VISIBILITY" = "public" ]; then
|
|
PROVENANCE="--provenance"
|
|
else
|
|
PROVENANCE=""
|
|
echo "repository visibility is '$VISIBILITY': publishing without provenance"
|
|
fi
|
|
|
|
# Dependency order, so each package's deps are resolvable the
|
|
# moment it lands. pnpm pack rewrites workspace:* to the real
|
|
# version; npm publish on the tarball handles OIDC.
|
|
# Re-runs skip anything already on the registry at this version.
|
|
publish_dir() {
|
|
dir="$1"
|
|
name=$(node -p "require('./$dir/package.json').name")
|
|
if npm view "$name@$VERSION" version >/dev/null 2>&1; then
|
|
echo "$name@$VERSION already published, skipping"
|
|
return 0
|
|
fi
|
|
tarball=$(cd "$dir" && pnpm pack --silent | tail -1)
|
|
npm publish "$dir/$tarball" $PROVENANCE --access public
|
|
}
|
|
|
|
publish_dir packages/runtime
|
|
publish_dir packages/compiler
|
|
publish_dir packages/cli
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
# The GitHub release is a tag, notes, and one asset: the surface
|
|
# manifest (packages/compiler/surface-manifest.json — the machine-
|
|
# readable listing of the surface the static tier compiles at this
|
|
# version, regenerated here and verified against the committed file).
|
|
# scriptc has no platform binary assets to stage (programs compile on
|
|
# the user's machine), so the job runs AFTER a successful npm publish
|
|
# and never gates it. The body is the CHANGELOG.md block between the
|
|
# release:start/release:end markers, which RELEASING.md keeps on the
|
|
# latest entry only.
|
|
github-release:
|
|
name: Create GitHub Release
|
|
needs: [check-release, publish]
|
|
if: needs.check-release.outputs.should_release == 'true'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup pnpm
|
|
uses: pnpm/action-setup@v4
|
|
with:
|
|
version: 11
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: "24"
|
|
|
|
# Regenerate the surface manifest from this tree and require it to
|
|
# match the committed file byte-for-byte — the same staleness guard
|
|
# the test suite runs — so the attached asset is provably the
|
|
# manifest of the code being released.
|
|
- name: Generate surface manifest
|
|
run: |
|
|
pnpm install --frozen-lockfile
|
|
pnpm manifest --check
|
|
|
|
- name: Extract changelog entry
|
|
run: |
|
|
VERSION="${{ needs.check-release.outputs.version }}"
|
|
awk '/<!-- release:start -->/{found=1; next} /<!-- release:end -->/{exit} found{print}' CHANGELOG.md > /tmp/release-notes.md
|
|
|
|
LINES=$(wc -l < /tmp/release-notes.md | tr -d ' ')
|
|
if [ "$LINES" -lt 2 ]; then
|
|
echo "Error: No release notes found between <!-- release:start --> and <!-- release:end --> markers in CHANGELOG.md"
|
|
exit 1
|
|
fi
|
|
echo "Extracted release notes for $VERSION ($LINES lines)"
|
|
|
|
- name: Create GitHub Release
|
|
run: |
|
|
VERSION="${{ needs.check-release.outputs.version }}"
|
|
TAG="v$VERSION"
|
|
|
|
if gh release view "$TAG" &>/dev/null; then
|
|
echo "Release $TAG already exists, skipping creation"
|
|
else
|
|
echo "Creating release $TAG..."
|
|
gh release create "$TAG" \
|
|
--target "$GITHUB_SHA" \
|
|
--title "$TAG" \
|
|
--notes-file /tmp/release-notes.md
|
|
fi
|
|
|
|
# Attach the surface manifest (idempotent: --clobber makes
|
|
# re-runs replace the asset instead of failing).
|
|
gh release upload "$TAG" packages/compiler/surface-manifest.json --clobber
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|