Skip to content
This repository was archived by the owner on Aug 25, 2026. It is now read-only.

TML-2501: declare Supabase roles via a standalone PSL role block (#957) #1208

TML-2501: declare Supabase roles via a standalone PSL role block (#957)

TML-2501: declare Supabase roles via a standalone PSL role block (#957) #1208

Workflow file for this run

name: Publish to npm
# Source-of-truth model:
# The version comes from the root `package.json` `version` field.
# Maintainers advance it via `pnpm bump-minor` (see
# docs/oss/versioning.md). This workflow can never publish a version
# other than what is committed at HEAD.
#
# Trigger model:
# - push to `main` with the root `version` unchanged → publish
# `<base>-dev.N` under dist-tag `dev`.
# - push to `main` with the root `version` changed → publish `<base>`
# under dist-tag `latest` and create a GitHub Release. This is how a
# merged `chore(release): ...` PR auto-ships.
# - workflow_dispatch → publish `<base>`
# under the chosen dist-tag (default `latest`); also the dry-run path.
on:
push:
branches: [main]
tags: ["!**"]
workflow_dispatch:
inputs:
dist-tag:
description: "npm dist-tag (e.g., latest, dev, beta)"
required: true
default: "latest"
type: string
dry-run:
description: "Dry-run only (build + pack + lint, no npm publish, no GitHub Release)."
required: false
default: true
type: boolean
concurrency:
group: npm-publish
cancel-in-progress: false
jobs:
publish:
name: Publish packages to npm
runs-on: ubuntu-latest
# Only `main` may produce a real publish. A dry-run dispatch is permitted
# from any branch so maintainers can validate the pipeline (build + pack +
# publish-dep gate + `pnpm publish --dry-run`) before merging changes that
# touch publishing. The dry-run path performs no registry writes and skips
# the GitHub Release step, so non-main runs cannot affect production state.
if: ${{ github.ref == 'refs/heads/main' || (github.event_name == 'workflow_dispatch' && github.event.inputs.dry-run == 'true') }}
permissions:
contents: write # Required to create the GitHub Release + tag for stable publishes
id-token: write # Required for npm OIDC Trusted Publishing
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
# Need history reaching `github.event.before` so `determine-version.ts`
# can compare the root `package.json` version at that ref to HEAD and
# decide whether this push is a release bump (publish `latest`) or a
# routine commit (publish `dev`). A multi-commit push can place
# `before` arbitrarily far back, so fetch the full history.
fetch-depth: 0
- name: Setup mise
uses: jdx/mise-action@e6a8b3978addb5a52f2b4cd9d91eafa7f0ab959d # v4.2.0
with:
cache: true
- name: Setup pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
- name: Configure npm
run: pnpm config set registry https://registry.npmjs.org
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Determine version
id: version
env:
GITHUB_EVENT_NAME: ${{ github.event_name }}
INPUT_DIST_TAG: ${{ github.event.inputs.dist-tag }}
# `before` is the ref `main` pointed at before this push.
# `determine-version.ts` reads the root `package.json` at that ref
# to detect release bumps. Empty for `workflow_dispatch`, which
# the script also handles.
PUSH_BEFORE_SHA: ${{ github.event.before }}
run: node scripts/determine-version.ts
- name: Set package versions
run: node scripts/set-version.ts "${{ steps.version.outputs.version }}"
- name: Build packages
run: pnpm build
# Publish-time gate: packs every publishable workspace package and
# verifies the resolved package.json contains no `workspace:*` or
# `catalog:` dependency specifiers. `pnpm publish` rewrites these on
# its own, but `npm publish` (and some CI flows) don't — and a single
# leaked specifier breaks downstream installs. This gate fails the
# publish before anything reaches the registry.
- name: Check publish dependency specifiers
run: pnpm check:publish-deps
# Publish-time gate: ensures every substrate change since the previous
# `v[0-9]*` tag is accompanied by a matching upgrade-instructions
# directory in the user-skill / extension-upgrade-skill packages, and
# that any newly added entries land in the in-flight transition
# directory. See `scripts/check-upgrade-coverage.mjs`.
- name: Check upgrade-instruction coverage
run: pnpm check:upgrade-coverage --mode publish
# Both publish paths fan out across `PUBLISH_CONCURRENCY` workers
# (default 8) via `scripts/publish-packages.mjs`. `pnpm -r publish` is
# intentionally serialized (it rejects `--workspace-concurrency`
# outright), and the per-package npm upload + Sigstore signing
# round-trips dominate wall-clock time, so serial publish of ~60
# packages takes 5–10 minutes on CI. Fanning out brings it down by
# close to the concurrency factor while staying well below npm's
# informal abuse thresholds.
# Dry-run path: exercises the full publish pipeline (pack, validate
# tarball contents, dependency rewriting) without touching the npm
# registry. Use from any branch via `workflow_dispatch` to validate
# changes that affect publishing before merging.
- name: Publish packages (dry-run)
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.dry-run == 'true' }}
run: node scripts/publish-packages.mjs --tag "${{ steps.version.outputs.tag }}" --dry-run
# NODE_AUTH_TOKEN is intentionally NOT set. npm detects the OIDC environment
# (id-token: write) and authenticates via Trusted Publishing automatically.
# Setting NODE_AUTH_TOKEN to any value -- even empty string -- would block OIDC.
#
# Enable npm provenance attestations for each published package.
# This requires a public source repository (npm rejects provenance from private repos).
- name: Publish packages
if: ${{ github.event_name != 'workflow_dispatch' || github.event.inputs.dry-run != 'true' }}
env:
NPM_CONFIG_PROVENANCE: "true"
run: node scripts/publish-packages.mjs --tag "${{ steps.version.outputs.tag }}"
# Lightweight git tag for non-stable publishes (dev / beta / …). Stable
# publishes get a tag implicitly via `gh release create` below; dev-channel
# builds need one too because `prisma-next init` resolves its skill-cluster
# URL via `#v<cliVersion>` (see packages/1-framework/3-tooling/cli/src/
# commands/init/skill-install.ts), which 404s without a matching git ref.
# Tag-only is intentional — a full Release per dev build would drown out
# the changelog signal. (TML-2696)
#
# Idempotent on workflow rerun: if `v$VERSION` already exists, skip.
- name: Create lightweight git tag for non-stable publishes
if: ${{ steps.version.outputs.tag != 'latest' && (github.event_name != 'workflow_dispatch' || github.event.inputs.dry-run != 'true') }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ steps.version.outputs.version }}
run: |
if gh api "repos/$GITHUB_REPOSITORY/git/ref/tags/v$VERSION" >/dev/null 2>&1; then
echo "Tag v$VERSION already exists; skipping"
else
gh api "repos/$GITHUB_REPOSITORY/git/refs" \
-X POST \
-f ref="refs/tags/v$VERSION" \
-f "sha=$GITHUB_SHA"
fi
# Publish-time gate (stable only): a `latest` Release publishes the
# committed notes file as its body, so that file must exist before the
# Release step runs. There is no auto-generated fallback — a release
# bump without docs/releases/v$VERSION.md fails here rather than
# shipping flat notes. Dev/beta builds create no Release, so the gate is
# scoped to `latest`, matching the Release step's own condition.
- name: Check release notes
if: ${{ steps.version.outputs.tag == 'latest' && (github.event_name != 'workflow_dispatch' || github.event.inputs.dry-run != 'true') }}
env:
VERSION: ${{ steps.version.outputs.version }}
run: pnpm check:release-notes --mode publish --version "$VERSION"
# Emit a GitHub Release for stable publishes only (dist-tag `latest`).
# Dev / PR / beta builds publish to npm but do not produce a Release —
# those would drown out the changelog signal. The Release is created at
# $GITHUB_SHA so the tag points at the same commit the publish ran from.
# The body is the committed `docs/releases/v$VERSION.md` (its presence is
# enforced by the "Check release notes" gate above); there is no
# auto-generated fallback.
#
# Idempotent on workflow rerun: if a Release for `v$VERSION` already exists
# (e.g. a previous run published to npm but failed before this step), edit
# it in place rather than re-creating it. The edit sets title/target only
# and preserves the already-published body rather than re-pushing the
# file — the right trade-off versus clobbering a hand-edited body or
# failing the rerun outright.
- name: Create GitHub Release for stable publishes
if: ${{ steps.version.outputs.tag == 'latest' && (github.event_name != 'workflow_dispatch' || github.event.inputs.dry-run != 'true') }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ steps.version.outputs.version }}
run: |
if gh release view "v$VERSION" >/dev/null 2>&1; then
gh release edit "v$VERSION" \
--target "$GITHUB_SHA" \
--title "v$VERSION"
else
gh release create "v$VERSION" \
--target "$GITHUB_SHA" \
--title "v$VERSION" \
--notes-file "docs/releases/v$VERSION.md"
fi