Skip to content

Commit 110508e

Browse files
docs refresh release feature overview
1 parent 1b5cdc2 commit 110508e

9 files changed

Lines changed: 137 additions & 163 deletions

File tree

README.md

Lines changed: 71 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,96 @@
1-
<div align="center">
2-
31
# OTF Release
42

5-
</div>
6-
7-
<div align="right">
8-
9-
Part of Open Tech Foundation ecosystem.
10-
11-
</div>
3+
> Manual-bump, changelog-aware release CLI for polyglot monorepos.
124
13-
> Curated-changelog, manual-bump release CLI for polyglot monorepos.
5+
`otf-release` is a single Rust binary that helps a repo move from curated release notes to a
6+
release PR, then to CI-driven publishing. It supports npm workspaces, Cargo workspaces, and
7+
generic manifest-based packages through a committed `release.toml`.
148

15-
A single-binary release tool for polyglot monorepos. You write your release notes in each package's `[Unreleased]` changelog section and pick the bumps — `otf-release` handles the rest: dependency-aware version cascades, topological publishing across multiple ecosystems (**npm, cargo, generic/JSR**), and a matrix-gated cross-platform GitHub release via a single generated `release.yml`.
9+
The core rule is simple: humans choose what to release and how much to bump; the tool handles
10+
dependency cascades, manifest edits, changelog updates, tags, publishing order, and generated
11+
GitHub workflows.
1612

17-
Unlike commit-driven tools, your hand-written notes are the strict source of truth.
13+
## ⚙️ Installation
1814

19-
## Installation
15+
**macOS / Linux**
2016

21-
You can easily install `otf-release` using our automated installation scripts:
22-
23-
**macOS / Linux:**
2417
```bash
2518
curl -fsSL https://raw.githubusercontent.com/Open-Tech-Foundation/release/main/install.sh | bash
2619
```
2720

28-
**Windows (PowerShell):**
21+
**Windows PowerShell**
22+
2923
```powershell
3024
irm https://raw.githubusercontent.com/Open-Tech-Foundation/release/main/install.ps1 | iex
3125
```
3226

33-
Alternatively, you can compile from source using Cargo:
27+
**From source**
28+
3429
```bash
3530
cargo install --git https://github.com/Open-Tech-Foundation/release
3631
```
3732

38-
## Commands
39-
40-
| Command | Usage | Description |
41-
|---------|-------|-------------|
42-
| **`init`** | `otf-release init` | Interactive setup: configure ecosystems, build matrices, and artifacts. Generates `release.toml` and `release.yml`. |
43-
| **`version`** | `otf-release version` | Interactive local release: choose bumps, cascade dependencies, write changelogs, and automatically open a Release PR. |
44-
| **`publish`** | `otf-release publish` | Non-interactive CI flow: publishes changed packages in topological order, attaching staged build artifacts. |
45-
| **`config`** | `otf-release config` | Interactively edit your `release.toml` file without manually typing out OS architecture strings or workflow targets. |
46-
| **`snapshot`** | `otf-release snapshot` | Non-interactive CI flow: completely automates an ephemeral snapshot release powered by a short git hash (e.g. `1.0.0-snapshot.a1b2c3d`) |
47-
| **`self-update`** | `otf-release self-update` | Updates your local `otf-release` binary to the latest version published on GitHub Releases. |
48-
| **`upgrade`** | `otf-release upgrade` | Upgrades your local `release.toml` and regenerates your CI pipeline to match the latest CLI version features. |
49-
50-
## Workflow
33+
## 🧭 Command Surface
34+
35+
| Command | Status | What it does |
36+
| --- | --- | --- |
37+
| `otf-release init` | ✅ Supported | Interactive setup. Writes `release.toml`, `.github/workflows/release.yml`, and `.github/workflows/snapshot.yml`. |
38+
| `otf-release version` | ✅ Supported | Interactive local release flow. Select packages, choose bumps, cascade dependents, update manifests/changelogs, push a release branch, and open a PR. |
39+
| `otf-release publish` | ✅ Supported | CI-oriented publish flow. Publishes in dependency order, skips already-published versions, creates `name@version` tags, and creates package releases from notes. |
40+
| `otf-release snapshot` | 🧪 Experimental | Creates hash-based prerelease versions such as `1.2.3-snapshot.a1b2c3d` and publishes them from CI. |
41+
| `otf-release config` | ◐ Partial | Interactive editor for common `release.toml` fields such as hooks, enabled ecosystems, and build targets. |
42+
| `otf-release upgrade` | ◐ Partial | Regenerates `release.yml` from the current `release.toml`. |
43+
| `otf-release self-update` | ✅ Supported | Checks GitHub Releases and reruns the install script when a newer CLI version exists. |
44+
45+
## ✅ Feature Matrix
46+
47+
| Area | Supported now | Notes |
48+
| --- | --- | --- |
49+
| npm adapter || Discovers npm workspaces, preserves dependency range operators, resolves `workspace:*`, checks `npm view`, publishes with `npm publish --access public --no-workspaces`. |
50+
| Cargo adapter || Discovers Cargo workspaces, supports concrete crate versions and `version.workspace = true`, updates path dependency versions, checks `cargo info`, publishes with `cargo publish -p`. |
51+
| Generic adapter || Versions a configured manifest field and optionally runs a configured publish command for registries such as JSR. Idempotency is tag-based. |
52+
| Polyglot versioning || `version` runs as one release transaction across all enabled adapters. |
53+
| Polyglot publishing || `publish` loops enabled adapters and publishes each ecosystem in dependency order. |
54+
| Dependency cascades || Adapter-owned rules. npm peer dependencies mirror the dependency bump; normal deps patch dependents. Cargo/generic dependents patch. |
55+
| Private packages/apps || Never versioned or published; internal ranges are still updated so apps remain buildable. |
56+
| Curated changelog mode || Uses each package's `[Unreleased]` section as the release-note source. |
57+
| Generated changelog mode || Builds notes from git commit messages since the last package tag and prepends generated notes to `CHANGELOG.md`. |
58+
| Prereleases || Supports stable bumps, channel entry (`alpha`, `beta`, `rc`), channel iteration, channel switching, and graduation to stable. |
59+
| Build-only packages || CI can build artifacts and attach them to a GitHub Release instead of publishing to a registry. |
60+
| Lifecycle hooks || `pre_version`, `post_version`, `pre_publish`, and `post_publish` run from `release.toml`. |
61+
| GitHub workflow generation || Generates release and snapshot workflows from `release.toml`; intended as editable scaffolds. |
62+
| Git providers | GitHub only | Config has a `provider` field, but only GitHub PR/release behavior is implemented. |
63+
64+
## ⚠️ Known Gaps
65+
66+
| Gap | Impact |
67+
| --- | --- |
68+
| `--first-release` is not wired through the version flow yet. | First-release ergonomics are still stricter than the CLI help implies. |
69+
| `publish` lifecycle hooks run per adapter, not once per full command. | Polyglot repos may run global `pre_publish` / `post_publish` hooks more than intended. |
70+
| `snapshot` is experimental. | Multi-adapter semantics, generated notes, rollback expectations, and workflow polish need more hardening. |
71+
| Generated `release.yml` still needs stronger validation. | It is useful scaffolding, but complex monorepos may need hand edits. |
72+
| Build-only GitHub releases use `vX.Y.Z` while package publish tags use `name@X.Y.Z`. | Independent build-only packages can be awkward when multiple packages release at different versions. |
73+
| `config` does not edit every `release.toml` field. | Users still need to hand-edit package mode, commands, artifacts, generic fields, provider, snapshot tag, and changelog strategy. |
74+
| Generic manifest parsing is intentionally simple. | Works for common JSON/TOML-style version fields, but is not a full structured parser. |
75+
| Only GitHub is implemented. | GitLab, Bitbucket, Gitea, and Codeberg are future work. |
76+
77+
## 🔁 Release Flow
5178

5279
```mermaid
5380
flowchart TD
54-
Init["1️⃣ <b>Init</b><br/>Run <code>otf-release init</code> once to generate configs & CI"]
55-
Curate["2️⃣ <b>Curate</b><br/>Write <code>[Unreleased]</code> notes as you develop"]
56-
PreVersion{"🪝 pre_version"}
57-
Version["3️⃣ <b>Version</b><br/>Run <code>otf-release version</code> to bump & open PR"]
58-
PostVersion{"🪝 post_version"}
59-
Merge["4️⃣ <b>Merge</b><br/>Review & merge the Release PR to <code>main</code>"]
60-
PrePublish{"🪝 pre_publish"}
61-
Publish["5️⃣ <b>Publish</b><br/>CI auto-compiles & publishes artifacts natively"]
62-
PostPublish{"🪝 post_publish"}
63-
64-
Init --> Curate --> PreVersion --> Version --> PostVersion --> Merge --> PrePublish --> Publish --> PostPublish
65-
```
66-
67-
## Changelog Strategies
68-
69-
During `otf-release init`, you can select how you want to manage your release notes via the `changelog_strategy` configuration.
70-
71-
- **Curated (Default):** You manually write release notes inside an `[Unreleased]` section within each package's `CHANGELOG.md` as you develop. `otf-release` acts as a strict curator, consuming these exact notes for the release.
72-
- **Generated:** `otf-release` automatically reads the git commit history since the last package tag and generates a list of commit messages. These generated notes are used in the Release PR and automatically prepended to the `CHANGELOG.md` upon release.
73-
74-
## Pre-releases
75-
76-
When running `otf-release version`, the interactive prompt will first ask you to select a release channel. By default, it uses the **stable** channel. If you select an alternative channel (e.g. `alpha`, `beta`, `rc`), `otf-release` will automatically compute valid semantic pre-release versions for your bumps.
77-
78-
For example, choosing a `minor` bump on the `beta` channel will transition `1.0.0` into `1.1.0-beta.0`. Once on a pre-release channel, you can select the new `prerelease` bump option to iterate tags (e.g., `beta.0``beta.1`).
79-
80-
## Snapshot Releases
81-
82-
To avoid polluting your changelog with every single CI run, you can configure an automated `snapshot` workflow. During `otf-release init`, the wizard will ask you for a snapshot tag (like `snapshot`, `canary`, or `edge`).
83-
84-
This will automatically scaffold a `.github/workflows/snapshot.yml` that triggers on `main` branch pushes. It runs `otf-release snapshot`, which generates short-hash ephemeral versions (like `1.0.0-canary.a1b2c3d`) and automatically bumps your ecosystem boundaries and pushes to registries without touching your tags or PRs.
85-
86-
## Git Hosting Providers
87-
88-
During `otf-release init`, you will be prompted to select your Git hosting provider. This determines the format of the Release PRs, release links, and CI workflows generated by the CLI.
89-
90-
Currently, **GitHub** is fully supported as the default provider. Support for GitLab, Bitbucket, Gitea, and Codeberg is planned and will be available in future releases. Your selection is saved as the `provider` field in `release.toml`.
91-
92-
## Lifecycle Hooks
93-
94-
You can define custom shell scripts to run at critical stages of the release process by editing your `release.toml` file. These hooks are executed across all operating systems automatically using your native shell (`sh` on Unix, `powershell` on Windows).
95-
96-
```toml
97-
[hooks]
98-
# Runs before the interactive version prompt starts (e.g. to validate repo state)
99-
pre_version = ["npm run lint", "node scripts/validate.js"]
100-
101-
# Runs after versions and changelogs are updated, but BEFORE they are committed
102-
post_version = ["python3 scripts/sync-docs.py"]
103-
104-
# Runs in CI before the publish loop begins
105-
pre_publish = ["npm run test"]
106-
107-
# Runs in CI after everything is successfully published
108-
post_publish = ["curl -X POST ..."]
81+
Init["⚙️ Init<br/>Generate release.toml and workflows"]
82+
Curate["📝 Prepare notes<br/>Curated CHANGELOG or generated commits"]
83+
PreVersion{"pre_version hooks"}
84+
Version["🏷️ Version<br/>Choose bumps, cascade, update files"]
85+
PostVersion{"post_version hooks"}
86+
PR["🔍 Release PR<br/>Review and merge"]
87+
PrePublish{"pre_publish hooks"}
88+
Publish["🚀 Publish<br/>CI publishes registries and/or artifacts"]
89+
PostPublish{"post_publish hooks"}
90+
91+
Init --> Curate --> PreVersion --> Version --> PostVersion --> PR --> PrePublish --> Publish --> PostPublish
10992
```
11093

111-
## License
94+
## 📄 License
11295

113-
MIT License. See [LICENSE](LICENSE) for details.
96+
MIT. See [LICENSE](LICENSE).

docs/README.md

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
# OTF Release — Documentation
22

3-
Reference documentation for `otf-release`, the curated-changelog, manual-bump release CLI
4-
for the OpenTF monorepo.
3+
Reference documentation for `otf-release`, the manual-bump, changelog-aware release CLI for
4+
polyglot monorepos.
55

6-
> **Status:** v1 is implemented and tested — `version`, `publish`, and `init`, with the **npm**
7-
> and **cargo** adapters. Setup is config-driven: `init` writes [`release.toml`](./configuration.md)
8-
> (the source of truth), with a per-package `publish` vs `build-only` mode. The cargo path supports
9-
> lockstep workspaces and a GitHub-Release binary distribution (how `otf-release` ships itself).
10-
> [`implementation-plan.md`](./implementation-plan.md) tracks the phase-by-phase build.
6+
> **Status:** The implemented command surface includes `init`, `version`, `publish`, `snapshot`,
7+
> `config`, `upgrade`, and `self-update`. The implemented adapters are **npm**, **cargo**, and
8+
> **generic**. GitHub is the only fully implemented forge provider.
119
1210
## Start here
1311

@@ -34,8 +32,8 @@ for the OpenTF monorepo.
3432
| [changelog-format.md](./changelog-format.md) | Keep a Changelog conventions and rewrite rules. |
3533
| [preflight.md](./preflight.md) | The strict, all-or-nothing compliance gate. |
3634
| [ci-workflow.md](./ci-workflow.md) | The single `release.yml` model. |
37-
| [roadmap.md](./roadmap.md) | Deferred / out-of-scope items. |
38-
| [implementation-plan.md](./implementation-plan.md) | Phased build plan with acceptance criteria. |
35+
| [roadmap.md](./roadmap.md) | Known gaps and upcoming work. |
36+
| [implementation-plan.md](./implementation-plan.md) | Historical phased build plan; useful context, not the current source of truth. |
3937

4038
## Glossary
4139

@@ -47,12 +45,12 @@ for the OpenTF monorepo.
4745
(cross-compiled in CI and attached at publish time). A first-class package, **not** a
4846
guarded special case.
4947
- **Cascade** — propagating a bump from a package to its internal dependents, transitively.
50-
- **Adapter** — the ecosystem-specific backend (npm in v1) behind which all registry and
51-
manifest knowledge lives.
48+
- **Adapter** — the ecosystem-specific backend behind which registry and manifest knowledge
49+
lives.
5250

5351
## Conventions used in these docs
5452

5553
- The invoked binary is `otf-release`; the published npm package is `@opentf/release`.
5654
- Code/identifier references point at `crates/<crate>/src/<module>.rs`.
57-
- "v1" = the current milestone: **npm + cargo** adapters, config-driven via `release.toml`, no
58-
pre-releases, local `version`manual PR.
55+
- "Current" = npm + cargo + generic adapters, config-driven via `release.toml`, local
56+
`version`release PR → CI `publish`.

docs/adapters/npm.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
# npm adapter
22

3-
The only implemented adapter in v1. Implemented in `crates/adapters/src/npm.rs`. The rules and
4-
gotchas below are **already battle-tested** in the existing OpenTF release workflow — they are
5-
baked in, not to be rediscovered.
3+
Implemented in `crates/adapters/src/npm/`. The rules and gotchas below are baked into the npm
4+
adapter so the core release flow can stay ecosystem-agnostic.
65

76
## Cascade rule (`dependent_bump`)
87

docs/architecture.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
`otf-release` is a single static binary (Rust) split into a registry-agnostic **core** and
44
one or more **adapters**. The core orchestrates a release; an adapter knows how one ecosystem
5-
(npm, in v1) reads manifests, formats version ranges, talks to a registry, and publishes.
5+
reads manifests, formats version ranges, talks to a registry, and publishes.
66

77
## Design rules
88

@@ -15,8 +15,8 @@ one or more **adapters**. The core orchestrates a release; an adapter knows how
1515
`version`, `publish`, and the generated `release.yml` all derive from. Everything else is
1616
read from disk (manifests, changelogs, `.artifacts/`) and the registry/git (tags); no other
1717
state is persisted between runs.
18-
4. **Notes are curated, never inferred.** The hand-written `[Unreleased]` changelog section
19-
is the source of truth for release notes. Bumps are chosen by a human.
18+
4. **Bumps are chosen by a human.** Release notes can be curated from `[Unreleased]` sections
19+
or generated from commit history, depending on `release.toml`.
2020

2121
## Crate layout
2222

@@ -37,7 +37,9 @@ crates/
3737
adapters/ opentf-release-adapters # registry adapters (lib)
3838
src/
3939
lib.rs
40-
npm.rs # the only implemented adapter in v1
40+
npm/ # npm workspace adapter
41+
cargo.rs # Cargo workspace adapter
42+
generic.rs # manifest + user-command adapter
4143
cli/ opentf-release # binary `otf-release` (clap)
4244
src/
4345
main.rs
@@ -52,10 +54,10 @@ cli ──▶ core ◀── adapters
5254

5355
- `core` defines the `Adapter` trait and all domain types. It depends on nothing internal.
5456
- `adapters` depends on `core` (it implements the trait).
55-
- `cli` depends on both: it constructs the concrete `NpmAdapter` and hands it to the core
56-
command functions as `&dyn Adapter`.
57+
- `cli` depends on both: it constructs the concrete adapters and hands them to the core command
58+
functions as `&dyn Adapter`.
5759

58-
This direction means a new adapter is added **without touching `core`**.
60+
This direction means a new adapter can usually be added **without touching `core`**.
5961

6062
## Domain types
6163

0 commit comments

Comments
 (0)