Skip to content
Closed
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
48 changes: 48 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Release

on:
push:
branches:
- main
- beta

permissions:
contents: write
id-token: write

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

jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '24'
cache: 'npm'
registry-url: 'https://registry.npmjs.org'

- name: Install
run: npm ci

- name: Check
run: npm run check

- name: Test
run: npm test

- name: Build
run: npm run build

- name: Release
env:
GITHUB_TOKEN: ${{ github.token }}
run: npm run release
108 changes: 108 additions & 0 deletions .releaserc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
{
"branches": [
"main",
{
"name": "beta",
"prerelease": "beta"
}
],
"tagFormat": "v${version}",
"plugins": [
[
"@semantic-release/commit-analyzer",
{
"preset": "conventionalcommits",
"releaseRules": [
{
"type": "feat",
"release": "minor"
},
{
"type": "fix",
"release": "patch"
},
{
"type": "perf",
"release": "patch"
},
{
"type": "revert",
"release": "patch"
},
{
"type": "update",
"release": "patch"
}
]
}
],
[
"@semantic-release/release-notes-generator",
{
"preset": "conventionalcommits",
"presetConfig": {
"types": [
{
"type": "feat",
"section": "Features",
"hidden": false
},
{
"type": "fix",
"section": "Fixes",
"hidden": false
},
{
"type": "perf",
"section": "Performance",
"hidden": false
},
{
"type": "update",
"section": "Updates",
"hidden": false
},
{
"type": "docs",
"section": "Documentation",
"hidden": false
},
{
"type": "refactor",
"section": "Maintenance",
"hidden": false
},
{
"type": "test",
"section": "Maintenance",
"hidden": false
},
{
"type": "build",
"section": "Maintenance",
"hidden": false
},
{
"type": "ci",
"section": "Maintenance",
"hidden": false
},
{
"type": "chore",
"section": "Maintenance",
"hidden": false
}
]
}
}
],
"@semantic-release/npm",
[
"@semantic-release/github",
{
"successComment": false,
"failComment": false
}
]
]
}
96 changes: 61 additions & 35 deletions docs/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@

## Current policy

At this stage, `dispatchkit` releases are published manually.
`dispatchkit` releases are PR-first, merge-triggered, and versioned by commit
history rather than manual `package.json` edits.

We use GitHub Actions for verification later, but we do not auto-publish from CI yet.
When code lands on `main`, GitHub Actions runs `semantic-release` from the
merged commit. It decides whether to release, computes the next version from
the commits since the previous tag, publishes the npm package, pushes the
matching `v*` tag, and creates the GitHub release.

`main` is protected. Release changes must land through a pull request and pass
the required `validate` check before the release workflow runs.

Release automation expects npm trusted publishing to be configured for this repo
so GitHub Actions can publish without a long-lived npm token.

Why:

Expand All @@ -22,36 +32,50 @@ Why:
npm run build
```

2. Update `package.json` and `package-lock.json` to the target version.
2. Open a pull request with the code changes only. Do not manually bump
`package.json` or `package-lock.json` for releases.

3. Run the registry-aware publish dry-run on the bumped version:
3. Merge the pull request after the required checks pass.

```bash
npm publish --dry-run
```
4. The `Release` workflow runs on the merged branch commit and:

Note: `npm publish --dry-run` still checks whether the version can be
published. If you run it before bumping off an already-published version, it
will fail even when the code is otherwise release-ready.
- installs dependencies with `npm ci`
- reruns `npm run check`, `npm test`, and `npm run build`
- decides whether the merged commits justify a release
- computes the next version from commit messages and tags
- publishes the package to npm
- pushes the matching `v<version>` tag
- creates the GitHub release notes

4. Publish:
Never publish or tag from an unmerged local-only commit. The published package,
the release tag, and the GitHub release should all come from the same merged
commit on the release branch.

```bash
npm publish
```
### Commit types

5. Tag and push:
Release automation follows conventional commit semantics:

```bash
git tag v<version>
git push origin main --tags
```
- `feat:` -> minor release
- `fix:` -> patch release
- `update:` -> patch release
- `perf:` -> patch release
- `type!:` or `BREAKING CHANGE:` -> major release
- other commit types do not trigger a release by default

If you use squash merges, the final PR title becomes the release-driving commit
message, so it needs to use the intended conventional commit type.

Example:

```bash
git tag v0.0.2
git push origin main --tags
# in the release PR
npm run check
npm test
npm run build

# use a conventional PR title / squash commit title like:
# feat: add direct action runs
# fix: handle missing credential env vars
```

## Package identity
Expand All @@ -70,11 +94,9 @@ Examples:
- `0.1.0-beta.1`
- `0.1.0-beta.2`

Publish betas with:

```bash
npm publish --tag beta
```
Follow the same PR-first flow as stable releases. Versions with a prerelease
suffix like `0.1.0-beta.1` are published automatically from the `beta` branch
with the npm `beta` dist-tag by the release workflow.

Users who want beta builds can install:

Expand All @@ -84,17 +106,21 @@ npm install -g dispatchkit@beta

Stable users continue to get the `latest` tag.

## Future automation

When the release process is more settled, the preferred automation model is:
Current automation:

- CI workflow on pull requests and `main`:
- `npm run check`
- `npm test`
- `npm run build`
- release-candidate workflow after the version bump:
- `npm publish --dry-run`
- release workflow on pushed tags like `v0.1.0`
- publish to npm

We should avoid publishing on every push to `main`.
- release workflow on pushed `main` and `beta` commits:
- rerun `npm run check`
- rerun `npm test`
- rerun `npm run build`
- analyze commit messages since the previous tag
- compute the next release version automatically
- publish to npm from the merged commit
- push the matching `v*` tag
- create the GitHub release

Ordinary merges that do not contain release-worthy commit types complete
successfully and produce no new version.
Loading
Loading