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
38 changes: 34 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ on:
push:
branches:
- main
- beta

permissions:
contents: write
id-token: write
pull-requests: read

concurrency:
group: release-${{ github.ref }}
Expand All @@ -32,16 +32,46 @@ jobs:
- name: Install
run: npm ci

- name: Plan Release
id: plan
env:
GITHUB_TOKEN: ${{ github.token }}
run: npm run release:plan

- name: Skip Release
if: steps.plan.outputs.should_release != 'true'
run: 'echo "Skipping release: ${{ steps.plan.outputs.reason }}"'

- name: Stamp Release Version
if: steps.plan.outputs.should_release == 'true'
run: npm version --no-git-tag-version ${{ steps.plan.outputs.version }}

- name: Check
if: steps.plan.outputs.should_release == 'true'
run: npm run check

- name: Test
if: steps.plan.outputs.should_release == 'true'
run: npm test

- name: Build
if: steps.plan.outputs.should_release == 'true'
run: npm run build

- name: Release
- name: Publish to npm
if: steps.plan.outputs.should_release == 'true'
run: npm publish --provenance

- name: Create Git Tag
if: steps.plan.outputs.should_release == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git tag "${{ steps.plan.outputs.tag }}"
git push origin "refs/tags/${{ steps.plan.outputs.tag }}"

- name: Create GitHub Release
if: steps.plan.outputs.should_release == 'true'
env:
GITHUB_TOKEN: ${{ github.token }}
run: npm run release
GH_TOKEN: ${{ github.token }}
run: 'gh release create "${{ steps.plan.outputs.tag }}" --title "${{ steps.plan.outputs.tag }}" --generate-notes'
108 changes: 0 additions & 108 deletions .releaserc.json

This file was deleted.

151 changes: 49 additions & 102 deletions docs/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,132 +2,79 @@

## Current policy

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

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.
There is no manual version bump, no manual tag step, and no `semantic-release`.
When a PR lands on `main`, GitHub Actions decides the next version, stamps that
version into `package.json` and `package-lock.json` on the runner only,
publishes to npm with trusted publishing, 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.
The repo keeps a development version in git. Published versions are derived in
CI from the latest release tag plus the merged PR's release level.

Release automation expects npm trusted publishing to be configured for this repo
so GitHub Actions can publish without a long-lived npm token.
Do not set `NPM_TOKEN` for the release workflow. Trusted publishing should use
GitHub OIDC only.
`main` is protected. Releases are expected to come from merged PRs, not local
machines and not direct pushes.

Why:
## Release levels

- the project is still early
- release judgment still matters
- package contents and release cadence are still settling
Release level comes from PR labels:

## Stable release flow
- `release:major`
- `release:minor`
- `release:patch`
- `release:none`

1. Run the code validation checks on the intended release candidate:
Default behavior:

```bash
npm run check
npm test
npm run build
```
- if no release label is present, the PR is released as a patch

2. Open a pull request with the code changes only. Do not manually bump
`package.json` or `package-lock.json` for releases.
Examples:

3. Merge the pull request after the required checks pass.
- latest tag `v0.1.14` + unlabeled merged PR -> `v0.1.15`
- latest tag `v0.1.14` + `release:minor` -> `v0.2.0`
- latest tag `v0.1.14` + `release:major` -> `v1.0.0`
- `release:none` -> skip publish, tag, and GitHub release

4. The `Release` workflow runs on the merged branch commit and:
Conflicting release labels fail the workflow.

- 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
## Release flow

This repo intentionally does not use a separate tag-triggered `npm publish`
workflow. `semantic-release` is the component that decides the version,
publishes from the merged commit, and then creates the matching tag and GitHub
release.
1. Open a PR with code changes only.
2. Run the normal validation checks:

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.

### Commit types
```bash
npm run check
npm test
npm run build
```

Release automation follows conventional commit semantics:
3. Optionally add one release label to the PR.
4. Merge the PR into `main`.
5. The `Release` workflow:

- `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
- resolves the merged PR for the pushed commit
- reads the release label, defaulting to patch
- computes the next version from the latest `v*` tag
- updates package files in the workflow workspace only
- reruns `npm run check`, `npm test`, and `npm run build`
- publishes with npm trusted publishing
- pushes the new `v*` tag
- creates the GitHub release

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.
Do not manually publish, tag, or bump package versions in a PR.

Example:
## npm auth

```bash
# in the release PR
npm run check
npm test
npm run build
Publishing is handled by npm trusted publishing with GitHub OIDC.

# use a conventional PR title / squash commit title like:
# feat: add direct action runs
# fix: handle missing credential env vars
```
- keep `id-token: write` in the release workflow
- do not set `NPM_TOKEN`
- do not publish from local machines for normal releases

## Package identity

- npm package: `dispatchkit`
- installed binary: `dispatch`

This is intentional because the `dispatch` package name is already taken on npm.

## Beta releases

Use semver prereleases and the npm `beta` dist-tag.

Examples:

- `0.1.0-beta.1`
- `0.1.0-beta.2`

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:

```bash
npm install -g dispatchkit@beta
```

Stable users continue to get the `latest` tag.

Current automation:

- CI workflow on pull requests and `main`:
- `npm run check`
- `npm test`
- `npm run build`
- 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