Release
This commit is contained in:
412
docs/workflow.md
412
docs/workflow.md
@@ -3,87 +3,87 @@
|
||||
`stamp` is a language-agnostic, changesets-style versioning and changelog tool.
|
||||
It works with any project type and supports monorepos.
|
||||
|
||||
---
|
||||
|
||||
## Concepts
|
||||
|
||||
| Term | Description |
|
||||
|------|-------------|
|
||||
| **Stamp file** | A `.stamp/*.md` file describing a change and which projects it affects |
|
||||
| **Bump type** | How to increment a version: `major`, `minor`, `patch`, or pre-release variants |
|
||||
| `stamp version` | Consumes stamp files → bumps versions → updates changelogs |
|
||||
| `stamp publish` | Creates git tags, releases, and uploads artifacts |
|
||||
| Term | Meaning |
|
||||
|------|---------|
|
||||
| **Stamp file** | A `.stamp/*.md` file describing a change and which projects it affects. Committed alongside the code change that caused it. |
|
||||
| **Bump type** | How to increment a version: `major`, `minor`, `patch`, or a pre-release variant. |
|
||||
| **Pending stamps** | Stamp files that have been committed but not yet consumed by a version run. |
|
||||
| `stamp version` | Consumes pending stamp files → bumps versions in `stamp.toml` → prepends entries to `CHANGELOG.md` files → commits the result. |
|
||||
| `stamp release-pr` | Same versioning logic as `stamp version`, but commits the changes onto a dedicated branch and opens (or updates) a pull request. The actual release happens when that PR is merged. |
|
||||
| `stamp publish` | Creates git tags and publishes releases (with optional artifact uploads) to GitHub or Gitea. |
|
||||
|
||||
---
|
||||
|
||||
## Setup
|
||||
## Two Release Workflows
|
||||
|
||||
### 1. Install stamp
|
||||
### Direct release
|
||||
|
||||
Via [Mise](https://mise.jdx.dev/):
|
||||
Run `stamp version` and `stamp publish` directly on the base branch. Good for small projects, CLIs, or repos where a human is doing releases manually.
|
||||
|
||||
```toml
|
||||
# mise.toml
|
||||
[tools]
|
||||
"go:git.thokra.dev/thokra/stamp/cmd/stamp" = "latest"
|
||||
```
|
||||
feature branch ──► merge to main ──► stamp version ──► git push ──► stamp publish
|
||||
```
|
||||
|
||||
Or build from source:
|
||||
### Release PR (recommended for automation)
|
||||
|
||||
```sh
|
||||
go install git.thokra.dev/thokra/stamp/cmd/stamp@latest
|
||||
`stamp release-pr` runs in CI whenever a change is merged to the base branch. It opens a pull request that contains all the version bumps and changelog updates. Merging that PR is the explicit, reviewable release trigger. A second CI job runs `stamp publish` after the merge.
|
||||
|
||||
```
|
||||
feature branch ──► merge to main ──► stamp release-pr ──► release PR
|
||||
│
|
||||
merge to main
|
||||
│
|
||||
stamp publish ──► tags + releases
|
||||
```
|
||||
|
||||
### 2. Create .stamp/stamp.toml
|
||||
|
||||
Inside the `.stamp/` directory at the root of your repository:
|
||||
|
||||
```toml
|
||||
[[projects]]
|
||||
name = "my-app"
|
||||
path = "."
|
||||
version = "0.1.0"
|
||||
|
||||
[projects.publish]
|
||||
tags = true
|
||||
releases = true
|
||||
artifacts = ["dist/my-app-*"]
|
||||
```
|
||||
|
||||
Because `stamp.toml` lives inside `.stamp/`, git will track the directory without needing a `.gitignore` file in it.
|
||||
|
||||
See [`examples/stamp.toml`](../examples/stamp.toml) for a fully annotated example.
|
||||
The two CI jobs (create PR and publish) both run on every push to `main`. They are each no-ops when there is nothing for them to do — `stamp release-pr` exits silently if there are no pending stamp files, and `stamp publish` skips any tag that already exists.
|
||||
|
||||
---
|
||||
|
||||
## Day-to-day Workflow
|
||||
## Day-to-day: Adding a Stamp File
|
||||
|
||||
### Adding a stamp to your PR
|
||||
|
||||
When making a change that should be released, add a stamp file:
|
||||
When making a code change that should result in a release, add a stamp file alongside it:
|
||||
|
||||
```sh
|
||||
# Interactive
|
||||
# Interactive wizard
|
||||
stamp add
|
||||
|
||||
# Non-interactive (useful in scripts or with AI agents)
|
||||
stamp add --project=my-app --bump=minor --message="Added X feature" --no-interactive
|
||||
# Non-interactive — good for scripts and AI agents
|
||||
stamp add --project=my-app --bump=minor --message="Add X feature" --no-interactive
|
||||
```
|
||||
|
||||
This creates a `.stamp/<random-slug>.md` file, e.g.:
|
||||
This creates a file like `.stamp/brave-river.md`:
|
||||
|
||||
```markdown
|
||||
```
|
||||
---
|
||||
bumps:
|
||||
my-app: minor
|
||||
---
|
||||
|
||||
Added X feature
|
||||
Add X feature
|
||||
```
|
||||
|
||||
> Stamp files live alongside `stamp.toml` in the `.stamp/` directory.
|
||||
Commit and push the stamp file together with your code. Your CI PR-check job (see below) will update its comment automatically.
|
||||
|
||||
Commit and push the stamp file alongside your code changes.
|
||||
### Bump type reference
|
||||
|
||||
### Checking pending stamps
|
||||
| Type | What it does | Example |
|
||||
|------|-------------|---------|
|
||||
| `major` | Breaking change | `1.2.3` → `2.0.0` |
|
||||
| `minor` | New feature | `1.2.3` → `1.3.0` |
|
||||
| `patch` | Bug fix | `1.2.3` → `1.2.4` |
|
||||
| `premajor` | Pre-release major | `1.2.3` → `2.0.0-beta.0` |
|
||||
| `preminor` | Pre-release minor | `1.2.3` → `1.3.0-beta.0` |
|
||||
| `prepatch` | Pre-release patch | `1.2.3` → `1.2.4-beta.0` |
|
||||
| `prerelease` | Increment pre-release counter | `1.2.4-rc.0` → `1.2.4-rc.1` |
|
||||
|
||||
---
|
||||
|
||||
## Checking Pending Stamps
|
||||
|
||||
```sh
|
||||
stamp status
|
||||
@@ -95,36 +95,210 @@ stamp status
|
||||
PROJECT CURRENT NEXT BUMP STAMPS
|
||||
------- ------- ---- ---- ------
|
||||
my-app 1.2.3 1.3.0 minor 2
|
||||
my-lib 0.1.0 0.1.0 — 0
|
||||
```
|
||||
|
||||
### Releasing
|
||||
|
||||
On your release branch (e.g. after merging PRs):
|
||||
|
||||
```sh
|
||||
# 1. Bump versions and update changelogs
|
||||
stamp version
|
||||
|
||||
# 2. Publish tags, releases, and artifacts
|
||||
STAMP_REPO=owner/repo stamp publish
|
||||
```
|
||||
|
||||
For a pre-release snapshot:
|
||||
|
||||
```sh
|
||||
stamp version --snapshot=alpha
|
||||
stamp publish
|
||||
my-lib 0.4.1 0.4.1 — 0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PR Commenting (CI)
|
||||
## Workflow A: Direct Release
|
||||
|
||||
Use `stamp comment` in your CI pipeline to automatically comment on PRs:
|
||||
Use this when you release manually or from CI without a release PR.
|
||||
|
||||
- ⚠️ **No stamp file?** → warns the author and explains how to add one
|
||||
- ✅ **Stamps found?** → shows a table of affected projects and next versions
|
||||
```sh
|
||||
# 1. Bump versions, update changelogs, and commit
|
||||
stamp version
|
||||
|
||||
# 2. Push the version commit and tags
|
||||
git push
|
||||
|
||||
# 3. Create GitHub / Gitea releases and upload artifacts
|
||||
STAMP_REPO=owner/repo stamp publish
|
||||
```
|
||||
|
||||
For a pre-release snapshot (does not require `stamp preview`):
|
||||
|
||||
```sh
|
||||
stamp version --snapshot=rc
|
||||
git push
|
||||
stamp publish
|
||||
```
|
||||
|
||||
`--snapshot` overrides the bump type for every affected project so that it produces a pre-release version with the given identifier. It is independent of `stamp preview` mode.
|
||||
|
||||
### Skipping the git commit
|
||||
|
||||
If you want to inspect or further modify the files before committing:
|
||||
|
||||
```sh
|
||||
stamp version --no-commit
|
||||
# review the diff, make additional edits…
|
||||
git add -A && git commit -m "chore: version packages"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Workflow B: Release PR
|
||||
|
||||
Use this for fully automated, reviewable releases in CI.
|
||||
|
||||
### How it works — step by step
|
||||
|
||||
1. **Check for pending stamps.** If none exist, `stamp release-pr` exits immediately with no side effects. This makes it safe to run on every push.
|
||||
|
||||
2. **Fetch origin** and reset the release branch (default: `stamp/release`) from the tip of `origin/<base>`. The branch is always recreated cleanly, so it is always fast-forwardable and never diverges from the base branch.
|
||||
|
||||
3. **Apply version changes** — bump versions in `stamp.toml`, prepend changelog entries, delete consumed stamp files. This is identical to what `stamp version --no-commit` does.
|
||||
|
||||
4. **Commit and force-push** the release branch to `origin`.
|
||||
|
||||
5. **Upsert the pull request.** A hidden marker (`<!-- stamp-release-pr -->`) is embedded in the PR body. On the first run a new PR is opened; on subsequent runs the existing PR's title and body are updated to reflect any newly merged stamp files. Only one stamp release PR is ever open at a time.
|
||||
|
||||
The PR body contains a version table:
|
||||
|
||||
```
|
||||
## 📦 Pending releases
|
||||
|
||||
| Project | Current | Next | Bump |
|
||||
|---------|---------|-------|-------|
|
||||
| my-app | 1.2.3 | 1.3.0 | minor |
|
||||
| my-lib | 0.4.1 | 0.4.2 | patch |
|
||||
```
|
||||
|
||||
6. **Merge the PR.** Merging triggers the publish job (see below) which creates git tags and GitHub/Gitea releases.
|
||||
|
||||
### CI setup — GitHub Actions
|
||||
|
||||
**Job 1: open / update the release PR** — runs on every push to `main`
|
||||
|
||||
```yaml
|
||||
# .github/workflows/stamp-release-pr.yml
|
||||
name: release PR
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
release-pr:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
# Full clone so stamp can fetch and reset the release branch.
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install stamp
|
||||
run: go install git.thokra.dev/thokra/stamp/cmd/stamp@latest
|
||||
|
||||
- name: Create or update release PR
|
||||
run: stamp release-pr --base=main
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
STAMP_REPO: ${{ github.repository }}
|
||||
```
|
||||
|
||||
**Job 2: publish after the release PR is merged** — also runs on every push to `main`
|
||||
|
||||
```yaml
|
||||
# .github/workflows/stamp-publish.yml
|
||||
name: publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install stamp
|
||||
run: go install git.thokra.dev/thokra/stamp/cmd/stamp@latest
|
||||
|
||||
- name: Publish releases
|
||||
run: stamp publish
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
STAMP_REPO: ${{ github.repository }}
|
||||
```
|
||||
|
||||
> Both jobs run on every push to `main`. They are each idempotent and safe to run concurrently: `stamp release-pr` is a no-op when there are no pending stamps; `stamp publish` skips tags that already exist.
|
||||
|
||||
### CI setup — Gitea Actions
|
||||
|
||||
**Job 1: open / update the release PR**
|
||||
|
||||
```yaml
|
||||
# .gitea/workflows/stamp-release-pr.yml
|
||||
name: release PR
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
release-pr:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install stamp
|
||||
run: go install git.thokra.dev/thokra/stamp/cmd/stamp@latest
|
||||
|
||||
- name: Create or update release PR
|
||||
run: stamp release-pr --base=main
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
GITEA_BASE_URL: ${{ gitea.server_url }}
|
||||
STAMP_REPO: ${{ gitea.repository }}
|
||||
```
|
||||
|
||||
**Job 2: publish after the release PR is merged**
|
||||
|
||||
```yaml
|
||||
# .gitea/workflows/stamp-publish.yml
|
||||
name: publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install stamp
|
||||
run: go install git.thokra.dev/thokra/stamp/cmd/stamp@latest
|
||||
|
||||
- name: Publish releases
|
||||
run: stamp publish
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
GITEA_BASE_URL: ${{ gitea.server_url }}
|
||||
STAMP_REPO: ${{ gitea.repository }}
|
||||
```
|
||||
|
||||
> **Note on `GITEA_TOKEN`:** Gitea Actions does not automatically inject a token the way GitHub Actions does. You must create a personal access token (or a bot account token) in your Gitea account settings with repository read/write permissions, then store it as a repository secret named `GITEA_TOKEN`.
|
||||
|
||||
---
|
||||
|
||||
## PR Commenting (stamp comment)
|
||||
|
||||
Use `stamp comment` in CI to post a summary comment on every pull request. It keeps reviewers and contributors informed about what will be released.
|
||||
|
||||
- **No stamp file** → the comment warns the author and shows how to add one.
|
||||
- **Stamps found** → the comment shows a table of affected projects and their projected next versions.
|
||||
|
||||
The comment is created on first run and updated in place on subsequent runs (identified by a hidden marker in the body).
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
@@ -179,20 +353,58 @@ jobs:
|
||||
|
||||
---
|
||||
|
||||
## Stamp File Format
|
||||
## Pre-release Mode (stamp preview)
|
||||
|
||||
Stamp files live in `.stamp/` alongside `stamp.toml`, and use Markdown with either YAML or TOML frontmatter.
|
||||
`stamp preview` lets you put an individual project into **pre-release mode**. While in this mode, every `stamp version` or `stamp release-pr` run produces pre-release versions instead of normal ones, regardless of the bump types in the stamp files.
|
||||
|
||||
```sh
|
||||
# Enter pre-release mode — all future versions for my-app will be pre-releases
|
||||
stamp preview enter my-app beta
|
||||
# → next stamp version will produce e.g. 1.3.0-beta.0
|
||||
|
||||
# If a pre-release version already exists, subsequent runs increment the counter
|
||||
# → 1.3.0-beta.0 → 1.3.0-beta.1 → 1.3.0-beta.2 …
|
||||
|
||||
# Exit pre-release mode — the next stamp version will produce a normal release
|
||||
stamp preview exit my-app
|
||||
# → next stamp version will produce e.g. 1.3.0
|
||||
```
|
||||
|
||||
`stamp preview enter` sets the `pre_tag` field on the project in `stamp.toml` and commits nothing — it is a local config change you commit yourself. `stamp preview exit` clears the field.
|
||||
|
||||
### Typical pre-release workflow
|
||||
|
||||
```sh
|
||||
# 1. Enter beta mode
|
||||
stamp preview enter my-app beta
|
||||
git add .stamp/stamp.toml && git commit -m "chore: enter beta mode for my-app"
|
||||
|
||||
# 2. Normal development — add stamp files as usual, merge PRs
|
||||
# stamp release-pr will produce beta versions automatically
|
||||
|
||||
# 3. When ready to release, exit beta mode
|
||||
stamp preview exit my-app
|
||||
git add .stamp/stamp.toml && git commit -m "chore: exit beta mode for my-app"
|
||||
|
||||
# 4. The next release-pr or stamp version will produce the full release (e.g. 1.3.0)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Stamp File Format Reference
|
||||
|
||||
Stamp files live in `.stamp/` alongside `stamp.toml`, and use Markdown with YAML or TOML frontmatter.
|
||||
|
||||
### YAML frontmatter (default)
|
||||
|
||||
```markdown
|
||||
```
|
||||
---
|
||||
bumps:
|
||||
my-app: minor
|
||||
my-lib: patch
|
||||
---
|
||||
|
||||
Short description of the change used as the changelog entry.
|
||||
Short description used as the changelog entry.
|
||||
|
||||
- Optional bullet points
|
||||
- for more detail
|
||||
@@ -200,7 +412,7 @@ Short description of the change used as the changelog entry.
|
||||
|
||||
### TOML frontmatter
|
||||
|
||||
```markdown
|
||||
```
|
||||
+++
|
||||
[bumps]
|
||||
my-app = "minor"
|
||||
@@ -209,17 +421,35 @@ my-app = "minor"
|
||||
Short description.
|
||||
```
|
||||
|
||||
### Valid bump types
|
||||
A stamp file can affect multiple projects in a single file (as shown above). Each project gets its own changelog entry with the description from the file.
|
||||
|
||||
| Type | Description |
|
||||
|------|-------------|
|
||||
| `major` | Breaking change (1.x.x → 2.0.0) |
|
||||
| `minor` | New feature (1.2.x → 1.3.0) |
|
||||
| `patch` | Bug fix (1.2.3 → 1.2.4) |
|
||||
| `premajor` | Pre-release major (→ 2.0.0-alpha.0) |
|
||||
| `preminor` | Pre-release minor (→ 1.3.0-beta.0) |
|
||||
| `prepatch` | Pre-release patch (→ 1.2.4-rc.0) |
|
||||
| `prerelease` | Increment pre-release (1.2.4-rc.0 → 1.2.4-rc.1) |
|
||||
---
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
```toml
|
||||
# .stamp/stamp.toml
|
||||
|
||||
[config]
|
||||
base_branch = "main" # Base branch targeted by release PRs (default: main)
|
||||
|
||||
[[projects]]
|
||||
name = "my-app"
|
||||
path = "apps/my-app" # Relative to repository root
|
||||
version = "1.2.3" # Current version — managed by stamp, do not edit manually
|
||||
changelog = "CHANGELOG.md" # Relative to `path` (default: CHANGELOG.md)
|
||||
pre_tag = "" # Set by `stamp preview enter`; blank means normal releases
|
||||
|
||||
[projects.publish]
|
||||
tags = true # Create an annotated git tag on publish
|
||||
releases = true # Create a GitHub / Gitea release on publish
|
||||
artifacts = [ # Glob patterns for files to upload to the release
|
||||
"apps/my-app/dist/my-app-linux-amd64",
|
||||
"apps/my-app/dist/my-app-darwin-arm64",
|
||||
]
|
||||
```
|
||||
|
||||
Tag format: `<name>@v<version>` for monorepos (e.g. `my-app@v1.3.0`), or `v<version>` for single-project repositories where `name` is empty.
|
||||
|
||||
---
|
||||
|
||||
@@ -227,7 +457,7 @@ Short description.
|
||||
|
||||
| Variable | Purpose |
|
||||
|----------|---------|
|
||||
| `STAMP_REPO` | Repository slug `owner/repo` used by publish and comment |
|
||||
| `GITHUB_TOKEN` | GitHub token for releases and PR comments — automatically provided by the GitHub Actions runner; no manual setup needed |
|
||||
| `GITEA_TOKEN` | Gitea access token — **must be created manually**; create a token in your Gitea account settings and store it as a repository secret |
|
||||
| `GITEA_BASE_URL` | Gitea instance URL (e.g. `https://gitea.example.com`) — also used to detect Gitea mode |
|
||||
| `STAMP_REPO` | Repository slug `owner/repo` — required for `publish`, `comment`, and `release-pr` |
|
||||
| `GITHUB_TOKEN` | GitHub token — automatically injected by GitHub Actions; no setup needed |
|
||||
| `GITEA_TOKEN` | Gitea access token — must be created manually and stored as a secret |
|
||||
| `GITEA_BASE_URL` | Gitea instance URL (e.g. `https://gitea.example.com`) — presence of this variable also activates Gitea mode |
|
||||
Reference in New Issue
Block a user