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
79 changes: 74 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
name: release

# Publishes both workspace packages when a `v*` tag is pushed. The dist-tag
# is derived from the tag name: pre-releases (`v1.2.3-alpha.1`, `-beta.x`,
# `-rc.x`) ship under `next`; everything else under `latest`.
#
# Setup the first time:
# 1. `gh secret set NPM_TOKEN` with an "Automation" token from npmjs.com
# (Automation tokens bypass 2FA in CI; granular tokens scoped to the
# `@modernrelay` packages are fine if your account has Automation
# disabled).
# 2. Repo Settings → Environments → create `release` → require manual
# approval. Without this gate, any push of a `v*` tag publishes.
#
# To cut a release (note: the tag MUST be annotated so `git push --follow-tags`
# actually pushes it — lightweight tags are skipped by --follow-tags):
# pnpm --filter @modernrelay/omnigraph version 0.4.0-alpha.1
# pnpm --filter @modernrelay/omnigraph-mcp version 0.4.0-alpha.1
# git commit -am "Release 0.4.0-alpha.1"
# git tag -a v0.4.0-alpha.1 -m "Release 0.4.0-alpha.1"
# git push --follow-tags
# # then approve the `release` environment in the Actions UI.

on:
push:
tags:
Expand All @@ -8,22 +29,70 @@ on:
jobs:
publish:
runs-on: ubuntu-latest
environment: release
permissions:
contents: read
id-token: write
id-token: write # npm provenance attestation
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
registry-url: 'https://registry.npmjs.org'

- run: pnpm install --frozen-lockfile

# Gates — same bar as ci.yml, run again on the exact tag SHA so a stale
# CI run cannot bless a release.
- run: pnpm run check-drift
- run: pnpm run check-coverage
- run: pnpm run build
- name: Publish @modernrelay/omnigraph
working-directory: packages/sdk
run: pnpm publish --no-git-checks --access public
- run: pnpm run typecheck
- run: pnpm run test

- name: Verify tag matches package versions
run: |
set -euo pipefail
tag_version="${GITHUB_REF_NAME#v}"
for pkg in packages/sdk packages/mcp; do
pkg_version=$(node -p "require('./${pkg}/package.json').version")
if [ "$tag_version" != "$pkg_version" ]; then
echo "Tag ${GITHUB_REF_NAME} does not match ${pkg}/package.json version (${pkg_version})"
exit 1
fi
done

- name: Derive npm dist-tag
id: tag
# SemVer 2.0: a `-` after the version is a prerelease, regardless of
# the label (`-alpha`, `-rc.1`, `-0`, `-next`, etc.). Any prerelease
# ships under `next`; only plain `X.Y.Z` (and `X.Y.Z+meta`) → `latest`.
# Strip build metadata first so a stray `+sha` doesn't confuse the
# check.
run: |
set -euo pipefail
ver="${GITHUB_REF_NAME#v}"
ver_no_meta="${ver%%+*}"
if [[ "$ver_no_meta" == *-* ]]; then
echo "dist=next" >> "$GITHUB_OUTPUT"
else
echo "dist=latest" >> "$GITHUB_OUTPUT"
fi

- name: Configure npm auth
# `setup-node`'s registry-url doesn't reliably propagate the auth
# token to pnpm publish; write the token explicitly.
run: echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" > "$HOME/.npmrc"
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

# SDK first — MCP's workspace:* dependency resolves to the just-published
# version once pnpm rewrites the manifest at publish time.
- name: Publish @modernrelay/omnigraph
working-directory: packages/sdk
run: pnpm publish --no-git-checks --access public --provenance --tag ${{ steps.tag.outputs.dist }}

- name: Publish @modernrelay/omnigraph-mcp
working-directory: packages/mcp
run: pnpm publish --no-git-checks --access public --provenance --tag ${{ steps.tag.outputs.dist }}
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,22 @@ The SDK is built against a specific `omnigraph-server` release. The pin lives in
3. `pnpm run generate` — regenerates `packages/sdk/src/generated/` and `packages/sdk/src/version.gen.ts`.
4. Commit `spec/openapi.json`, `packages/sdk/src/generated/`, `packages/sdk/src/version.gen.ts`, and the bumped `package.json`. The PR shows the full upstream change.
5. Bump `packages/sdk/package.json#version` (and `packages/mcp/package.json#version`) to match.
6. Tag `vX.Y.Z`. `release.yml` publishes both packages to npm.
6. Tag `vX.Y.Z`. `release.yml` publishes both packages to npm (see [Releasing](#releasing)).

## Releasing

Pushing a `v*` tag triggers `.github/workflows/release.yml`, which runs the full gate (drift, coverage, build, typecheck, test) on the tag SHA and then publishes both `@modernrelay/omnigraph` and `@modernrelay/omnigraph-mcp` with npm provenance. The dist-tag is derived from the tag name: `v1.2.3-alpha.1`, `-beta.x`, `-rc.x` ship under `next`; everything else under `latest`.

```sh
pnpm --filter @modernrelay/omnigraph version 0.4.0-alpha.1
pnpm --filter @modernrelay/omnigraph-mcp version 0.4.0-alpha.1
git commit -am "Release 0.4.0-alpha.1"
git tag -a v0.4.0-alpha.1 -m "Release 0.4.0-alpha.1"
git push --follow-tags
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
# then approve the `release` environment in the Actions UI.
```

One-time setup: add an npm `NPM_TOKEN` repo secret (use an Automation token to bypass 2FA in CI) and create a `release` GitHub Environment with required reviewers so a stray tag push cannot ship.

## Local dev

Expand Down
Loading