Skip to content

Commit e54ff0e

Browse files
authored
ci(release): automate branch-driven npm publishing (#73)
Add release workflow triggered on push to main/dev. Channel is derived from branch + version: main + clean version -> latest dev + -beta.x -> beta any + -next.x -> next Skips when the version is already on npm, so no-bump merges are no-ops. Publishing uses npm Trusted Publishing (OIDC) with provenance — no NPM_TOKEN is stored in the repo. On publish, CI tags v<version> and generates GitHub release notes via changelogithub. Add `pnpm release` (bumpp) for version bumps and document the full release flow in CONTRIBUTING.md. Contributor PRs now target dev.
1 parent 3cc38ca commit e54ff0e

4 files changed

Lines changed: 763 additions & 4 deletions

File tree

.github/workflows/release.yml

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
name: Release
2+
3+
# Release channel is driven by the branch you merge into:
4+
# main -> production (dist-tag: latest)
5+
# dev -> beta (dist-tag: beta) version must be a -beta.x prerelease
6+
# any -> next (dist-tag: next) whenever the version contains -next.x
7+
# A merge only publishes when the version in package.json is NOT already on npm,
8+
# so ordinary merges that don't bump the version are no-ops.
9+
on:
10+
push:
11+
branches: [main, dev]
12+
13+
concurrency:
14+
group: release-${{ github.ref }}
15+
cancel-in-progress: false
16+
17+
# No secrets. Publishing uses npm Trusted Publishing (OIDC) — there is no
18+
# NPM_TOKEN in this repo to steal. id-token mints a short-lived identity npm
19+
# verifies against the trusted publisher configured on npmjs.com for this exact
20+
# repo + workflow. contents:write is only for the tag + GitHub release notes.
21+
permissions: {}
22+
23+
jobs:
24+
release:
25+
runs-on: ubuntu-latest
26+
permissions:
27+
contents: write
28+
id-token: write
29+
steps:
30+
- uses: actions/checkout@v4
31+
with:
32+
fetch-depth: 0
33+
34+
- uses: pnpm/action-setup@v4
35+
36+
- uses: actions/setup-node@v4
37+
with:
38+
node-version: 22
39+
registry-url: https://registry.npmjs.org
40+
41+
# Trusted Publishing needs npm >= 11.5.1; Node 22 ships an older npm.
42+
- run: npm install -g npm@latest
43+
44+
- run: pnpm install --frozen-lockfile
45+
46+
# Decide the dist-tag from branch + version, or skip if this channel/version
47+
# combination is not allowed. Enforces: production only from main, beta only
48+
# from dev, next from anywhere.
49+
- name: Resolve release channel
50+
id: channel
51+
working-directory: packages/sveltekit-og
52+
run: |
53+
NAME=$(node -p "require('./package.json').name")
54+
VERSION=$(node -p "require('./package.json').version")
55+
BRANCH="${GITHUB_REF_NAME}"
56+
echo "name=$NAME"; echo "version=$VERSION"; echo "branch=$BRANCH"
57+
58+
if [[ "$VERSION" == *-next.* ]]; then
59+
TAG=next
60+
elif [[ "$BRANCH" == "dev" && "$VERSION" == *-beta.* ]]; then
61+
TAG=beta
62+
elif [[ "$BRANCH" == "main" && "$VERSION" != *-* ]]; then
63+
TAG=latest
64+
else
65+
echo "No release: version '$VERSION' is not valid for branch '$BRANCH'." >> "$GITHUB_STEP_SUMMARY"
66+
echo "publish=false" >> "$GITHUB_OUTPUT"
67+
exit 0
68+
fi
69+
70+
# Skip if this exact version is already on npm (merge didn't bump it).
71+
if npm view "$NAME@$VERSION" version >/dev/null 2>&1; then
72+
echo "$NAME@$VERSION already published — skipping." >> "$GITHUB_STEP_SUMMARY"
73+
echo "publish=false" >> "$GITHUB_OUTPUT"
74+
exit 0
75+
fi
76+
77+
echo "publish=true" >> "$GITHUB_OUTPUT"
78+
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
79+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
80+
81+
# Build runs via the package's prepublishOnly. --provenance signs a build attestation.
82+
- name: Publish to npm
83+
if: steps.channel.outputs.publish == 'true'
84+
working-directory: packages/sveltekit-og
85+
run: |
86+
echo "Publishing ${{ steps.channel.outputs.version }} with dist-tag: ${{ steps.channel.outputs.tag }}"
87+
npm publish --provenance --tag "${{ steps.channel.outputs.tag }}"
88+
89+
# Tag the release commit and generate GitHub release notes from conventional commits.
90+
- name: Tag + GitHub release notes
91+
if: steps.channel.outputs.publish == 'true'
92+
env:
93+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
94+
run: |
95+
TAG="v${{ steps.channel.outputs.version }}"
96+
git tag "$TAG"
97+
git push origin "$TAG"
98+
npx changelogithub

CONTRIBUTING.md

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ If you have an idea for a new feature or an improvement to an existing one, plea
2525

2626
If you would like to contribute code to the project, please follow these steps:
2727

28-
1. Fork the repository and create a `new branch` from `main`.
28+
1. Fork the repository and create a `new branch` from `dev`.
2929
2. Make your changes and commit them with a clear and descriptive commit message.
3030
3. Push your changes to your fork.
31-
4. Open a pull request to the `main` branch of the SvelteKit OG repository.
31+
4. Open a pull request to the `dev` branch of the SvelteKit OG repository. (`main` is the release branch — see [Releasing](#releasing).)
3232

3333
Please make sure your pull request includes:
3434

@@ -55,6 +55,75 @@ npm run lint
5555
npm run format
5656
```
5757

58+
## Releasing
59+
60+
> For maintainers. Releases are automated by `.github/workflows/release.yml` and published to npm via **Trusted Publishing (OIDC)** — there is no `NPM_TOKEN` stored in the repo.
61+
62+
**The version string in `packages/sveltekit-og/package.json` decides the npm dist-tag; the branch decides whether that release is allowed:**
63+
64+
| Branch | Version | Published to |
65+
| ------ | ----------------- | ---------------- |
66+
| `main` | clean (`4.4.0`) | `latest` (prod) |
67+
| `dev` | `-beta.x` | `beta` |
68+
| any | `-next.x` | `next` |
69+
70+
Any other branch/version combination does **not** publish. A push/merge only publishes when the version is not already on npm — merges that don't bump the version are no-ops.
71+
72+
Bump the version with the interactive helper (it commits and pushes to the current branch; the CI creates the git tag):
73+
74+
```bash
75+
pnpm release
76+
```
77+
78+
### Beta
79+
80+
```bash
81+
git checkout dev
82+
pnpm release # pick a -beta version, e.g. 4.4.0-beta.0
83+
```
84+
85+
Pushing to `dev` publishes `@beta`. Install with `npm i @ethercorps/sveltekit-og@beta`.
86+
87+
### Next (experimental preview)
88+
89+
```bash
90+
pnpm release # pick a -next version, e.g. 4.4.0-next.0
91+
```
92+
93+
Publishes `@next` from any branch. Use for throwaway previews you don't want on `@beta`.
94+
95+
### Production
96+
97+
Bump to a clean version on `dev` (this is a no-op publish), then merge `dev``main`:
98+
99+
```bash
100+
git checkout dev
101+
pnpm release # pick the clean release, e.g. 4.4.0
102+
git push origin dev
103+
104+
git checkout main
105+
git merge --ff-only dev # or merge the dev → main PR
106+
git push origin main
107+
```
108+
109+
Pushing the clean version to `main` publishes `@latest`.
110+
111+
> Do **not** bump the clean version directly on `main` during a beta cycle — bump on `dev` and merge, so `main` always matches what's on `@latest`.
112+
113+
### Hotfix
114+
115+
```bash
116+
git checkout -b hotfix main
117+
# fix, then:
118+
pnpm release # e.g. 4.4.1
119+
git checkout main && git merge --ff-only hotfix && git push origin main
120+
git checkout dev && git merge main && git push origin dev # keep dev in sync
121+
```
122+
123+
### One-time setup
124+
125+
Trusted Publishing must be configured once on npmjs.com → the package → **Settings → Trusted Publishing**: add a GitHub Actions publisher for repo `ethercorps/sveltekit-og`, workflow `release.yml`. Without it, publishing fails (by design — npm only trusts that exact repo + workflow).
126+
58127
## Code of Conduct
59128

60129
This project and everyone participating in it is governed by the [SvelteKit OG Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [ethercorps@gmail.com](mailto:ethercorps@gmail.com).

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@
1616
"docs:build": "pnpm -F @svecodocs/docs build",
1717
"check": "pnpm -r check",
1818
"lint": "pnpm -r lint",
19-
"format": "pnpm -r format"
19+
"format": "pnpm -r format",
20+
"release": "bumpp --no-tag packages/sveltekit-og/package.json"
21+
},
22+
"devDependencies": {
23+
"bumpp": "^10.4.0",
24+
"changelogithub": "^13.16.0"
2025
},
2126
"pnpm": {
2227
"onlyBuiltDependencies": [

0 commit comments

Comments
 (0)