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
120 changes: 120 additions & 0 deletions .github/workflows/publish-sdk.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
name: Publish SDK to npm

# Publishes @raintree-technology/docpull-sdk with npm trusted publishing.
# Configure the package publisher for this repository and workflow filename;
# no npm token is stored in GitHub.

on:
workflow_dispatch:
inputs:
version:
description: "Version to publish, matching sdk/js/package.json"
required: true
push:
tags:
- "v*.*.*"

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false

jobs:
publish:
runs-on: ubuntu-24.04
timeout-minutes: 15
permissions:
contents: read
id-token: write
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
persist-credentials: false

- name: Set up Node 24
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: "24"

- name: Set up Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6
with:
bun-version: "1.3.11"

- name: Verify release version
id: meta
env:
REQUESTED_VERSION: ${{ github.event.inputs.version || '' }}
run: |
set -euo pipefail
SDK_VERSION=$(node -p "require('./sdk/js/package.json').version")
if [ "${GITHUB_REF_TYPE}" = "tag" ]; then
TAG_VERSION="${GITHUB_REF_NAME#v}"
if [ "$TAG_VERSION" != "$SDK_VERSION" ]; then
echo "::error::Tag $TAG_VERSION does not match SDK version $SDK_VERSION"
exit 1
fi
elif [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then
if [ "${GITHUB_REF_NAME}" != "main" ]; then
echo "::error::Manual publish must run from main, got ${GITHUB_REF_NAME}"
exit 1
fi
if [ "$REQUESTED_VERSION" != "$SDK_VERSION" ]; then
echo "::error::Requested version $REQUESTED_VERSION does not match SDK version $SDK_VERSION"
exit 1
fi
else
echo "::error::SDK publish only runs from vX.Y.Z tags or manual main dispatch"
exit 1
fi
echo "version=$SDK_VERSION" >> "$GITHUB_OUTPUT"

- name: Install locked dependencies
run: bun install --frozen-lockfile

- name: Test, typecheck, and build SDK
run: |
bun run --cwd sdk/js test
bun run --cwd sdk/js typecheck
bun run --cwd sdk/js build

- name: Verify package contents
working-directory: sdk/js
run: npm pack --dry-run

- name: Publish with provenance
id: publish
env:
VERSION: ${{ steps.meta.outputs.version }}
run: |
set -euo pipefail
if npm view "@raintree-technology/docpull-sdk@${VERSION}" version >/dev/null 2>&1; then
echo "@raintree-technology/docpull-sdk@${VERSION} is already published."
echo "published=false" >> "$GITHUB_OUTPUT"
exit 0
fi
cd sdk/js
npx --yes npm@11.7.0 publish --access public --provenance
echo "published=true" >> "$GITHUB_OUTPUT"

- name: Smoke install from npm
env:
VERSION: ${{ steps.meta.outputs.version }}
run: |
set -euo pipefail
smoke_dir=$(mktemp -d)
cd "$smoke_dir"
npm init --yes >/dev/null
for attempt in 1 2 3 4 5; do
if npm install "@raintree-technology/docpull-sdk@${VERSION}"; then
break
fi
if [ "$attempt" = 5 ]; then
exit 1
fi
sleep 10
done
node --input-type=module -e "import('@raintree-technology/docpull-sdk').then((sdk) => { if (typeof sdk.readPack !== 'function') process.exit(1) })"
15 changes: 11 additions & 4 deletions docs/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,15 @@ make release-publish VERSION=6.0.0

This verifies `origin/main` has the requested `pyproject.toml` version, puts
`vX.Y.Z` on the merged `origin/main` commit, and pushes the tag to start the
PyPI workflow. After the PyPI trusted-publish step succeeds on a tag push, the
workflow creates or updates the GitHub Release for that tag and marks it as the
latest release. It uses `docs/release-post-vX.Y.md` when present and otherwise
falls back to generated notes.
PyPI and npm workflows. After the PyPI trusted-publish step succeeds on a tag
push, the workflow creates or updates the GitHub Release for that tag and marks
it as the latest release. The npm workflow publishes
`@raintree-technology/docpull-sdk` with provenance when `sdk/js/package.json`
has the same version. It uses no npm token: configure npm trusted publishing
for organization `raintree-technology`, repository `docpull`, and workflow
`publish-sdk.yml` before the next version is released. The GitHub Release uses
`docs/release-post-vX.Y.md` when present and otherwise falls back to generated
notes.

Verify both public release surfaces:

Expand All @@ -70,6 +75,7 @@ import json, urllib.request
with urllib.request.urlopen("https://pypi.org/pypi/docpull/json", timeout=20) as r:
print(json.load(r)["info"]["version"])
PY
npm view @raintree-technology/docpull-sdk version
```

The helper refuses to move an existing remote tag by default.
Expand All @@ -88,6 +94,7 @@ the merged `main` commit:

```bash
make release-dispatch VERSION=6.0.0
gh workflow run publish-sdk.yml --ref main -f version=6.0.0
```

The workflow refuses manual dispatch from any branch other than `main`, and the
Expand Down
Loading