verbump-cli 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- verbump_cli-1.0.0/LICENSE +21 -0
- verbump_cli-1.0.0/PKG-INFO +312 -0
- verbump_cli-1.0.0/README.md +285 -0
- verbump_cli-1.0.0/pyproject.toml +43 -0
- verbump_cli-1.0.0/setup.cfg +4 -0
- verbump_cli-1.0.0/src/verbump/__init__.py +3 -0
- verbump_cli-1.0.0/src/verbump/__main__.py +3 -0
- verbump_cli-1.0.0/src/verbump/changelog.py +53 -0
- verbump_cli-1.0.0/src/verbump/cli.py +237 -0
- verbump_cli-1.0.0/src/verbump/config.py +158 -0
- verbump_cli-1.0.0/src/verbump/demo.py +101 -0
- verbump_cli-1.0.0/src/verbump/files.py +149 -0
- verbump_cli-1.0.0/src/verbump/gitutil.py +39 -0
- verbump_cli-1.0.0/src/verbump/release.py +152 -0
- verbump_cli-1.0.0/src/verbump/semver.py +50 -0
- verbump_cli-1.0.0/src/verbump_cli.egg-info/PKG-INFO +312 -0
- verbump_cli-1.0.0/src/verbump_cli.egg-info/SOURCES.txt +23 -0
- verbump_cli-1.0.0/src/verbump_cli.egg-info/dependency_links.txt +1 -0
- verbump_cli-1.0.0/src/verbump_cli.egg-info/entry_points.txt +2 -0
- verbump_cli-1.0.0/src/verbump_cli.egg-info/top_level.txt +1 -0
- verbump_cli-1.0.0/tests/test_config.py +43 -0
- verbump_cli-1.0.0/tests/test_demo.py +37 -0
- verbump_cli-1.0.0/tests/test_files.py +117 -0
- verbump_cli-1.0.0/tests/test_release.py +107 -0
- verbump_cli-1.0.0/tests/test_semver_changelog.py +64 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gonçalo Faria
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: verbump-cli
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Version and changelog bumps for repos
|
|
5
|
+
Author: Gonçalo Faria
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Action, https://github.com/TheKathan/verbump-action
|
|
8
|
+
Project-URL: Source, https://github.com/TheKathan/verbump
|
|
9
|
+
Project-URL: Changelog, https://github.com/TheKathan/verbump/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: version,semver,changelog,release,monorepo,bump,cli
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: MacOS
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
<h1 align="center">verbump</h1>
|
|
29
|
+
|
|
30
|
+
<p align="center">
|
|
31
|
+
<a href="https://github.com/TheKathan/verbump/actions/workflows/test.yml"><img alt="tests" src="https://github.com/TheKathan/verbump/actions/workflows/test.yml/badge.svg"></a>
|
|
32
|
+
<a href="https://pypi.org/project/verbump-cli/"><img alt="PyPI" src="https://img.shields.io/pypi/v/verbump-cli"></a>
|
|
33
|
+
<img alt="license" src="https://img.shields.io/github/license/TheKathan/verbump">
|
|
34
|
+
<img alt="Python 3.11+" src="https://img.shields.io/badge/python-%E2%89%A5%203.11-3776AB">
|
|
35
|
+
<img alt="dependencies: none" src="https://img.shields.io/badge/dependencies-none-brightgreen">
|
|
36
|
+
</p>
|
|
37
|
+
|
|
38
|
+
**Version and changelog bumps for repos: only the packages that changed move.**
|
|
39
|
+
|
|
40
|
+
verbump finds the packages in your repo that changed since their own last tag, writes each one's new version into its files, and turns its changelog's `## [Unreleased]` notes into the release. One package or fifty, Python, Node, .NET, Java, Rust, Go or anything with a version in a file. One CLI, one `verbump.toml`, no dependencies.
|
|
41
|
+
|
|
42
|
+
**Try it in one command:** `uvx --from verbump-cli verbump demo`
|
|
43
|
+
|
|
44
|
+
<p align="center"><img alt="verbump in a repo with two packages. verbump status shows api at 1.4.0 with 0 changed files and web at 0.3.0 with 2 changed files. git log shows a commit feat(web): checkout page that touched apps/web. verbump apply --branch feat/checkout prints web: 0.3.0 -> 0.4.0 (minor, tag web/v0.4.0) and writes apps/web/package.json and apps/web/CHANGELOG.md. git diff shows the version going from 0.3.0 to 0.4.0, and verbump notes web prints the release notes: Added, Checkout page." src="https://raw.githubusercontent.com/TheKathan/verbump/main/assets/demo.gif" width="800"><br><sub>A PR from <code>feat/checkout</code> changed only <code>apps/web</code>: web gets a minor bump and its release notes, api stays at 1.4.0.</sub></p>
|
|
45
|
+
|
|
46
|
+
## Try it in 60 seconds
|
|
47
|
+
|
|
48
|
+
With verbump [installed](#quick-start), this builds the repo from the recording in a scratch folder and releases it:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
verbump demo --dir verbump-try --setup-only && cd verbump-try
|
|
52
|
+
verbump status # api and web, both tagged; web has changes
|
|
53
|
+
verbump plan --branch feat/checkout # web: 0.3.0 -> 0.4.0 (minor, tag web/v0.4.0)
|
|
54
|
+
verbump apply --branch feat/checkout # writes apps/web/package.json and CHANGELOG.md
|
|
55
|
+
verbump notes web # the notes for the GitHub release
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Or run `verbump demo` for a narrated replay in a temporary folder.
|
|
59
|
+
|
|
60
|
+
## Why verbump
|
|
61
|
+
|
|
62
|
+
- **Only what changed moves.** Each package is released from its own last tag, so a fix in one service doesn't bump the other nine.
|
|
63
|
+
- **Release notes you already wrote.** The `Unreleased` notes become the version's section and the GitHub release body; with no notes, the commit subjects that touched the package.
|
|
64
|
+
- **Any stack.** It reads and writes versions in `package.json`, `pyproject.toml`, `Cargo.toml`, `.csproj`, `pom.xml`, Gradle, Helm charts, Dockerfiles and more, or any file you give a pattern. Go-style tags work too.
|
|
65
|
+
- **You choose the bump.** A flag, the PR's branch name, or [trunk-semver](https://github.com/TheKathan/trunk-semver)'s outputs. A `release/<package>/X.Y.Z` branch cuts an exact version.
|
|
66
|
+
- **Safe to re-run.** Tags are created once and never moved; a second run finds nothing to release.
|
|
67
|
+
- **Nothing to run.** Python 3.11+ and the standard library; no server, no plugins per language.
|
|
68
|
+
|
|
69
|
+
## What it's for
|
|
70
|
+
|
|
71
|
+
| Use | What you get |
|
|
72
|
+
|---|---|
|
|
73
|
+
| **A repo with several services or libraries** | Per-package versions, tags (`api/v1.5.0`) and changelogs, from one config. [Example](https://github.com/TheKathan/verbump/blob/main/examples/monorepo/verbump.toml) |
|
|
74
|
+
| **A single package** | `tag_format = "v{version}"` and one package at `.`; verbump releases itself this way. [Its config](https://github.com/TheKathan/verbump/blob/main/verbump.toml) |
|
|
75
|
+
| **GitHub Actions** | [verbump-action](https://github.com/TheKathan/verbump-action) bumps, commits, tags, pushes and publishes a GitHub release per package, on any stack. |
|
|
76
|
+
| **Any other CI** | Four commands: `apply`, `check`, `tag`, `notes`. [Recipe](#using-it-in-ci) |
|
|
77
|
+
|
|
78
|
+
## Quick start
|
|
79
|
+
|
|
80
|
+
Install it. The PyPI package is `verbump-cli`, because the name `verbump` belongs to an unrelated project. The command it installs is `verbump`.
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pipx install verbump-cli # or: uv tool install verbump-cli, pip install verbump-cli
|
|
84
|
+
verbump --version
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Declare your packages in `verbump.toml` at the repo root. `verbump init` writes a starter file. A minimal one looks like this:
|
|
88
|
+
|
|
89
|
+
```toml
|
|
90
|
+
tag_format = "{name}/v{version}"
|
|
91
|
+
|
|
92
|
+
[packages.api]
|
|
93
|
+
path = "services/api"
|
|
94
|
+
files = ["pyproject.toml", "src/api/__init__.py"]
|
|
95
|
+
|
|
96
|
+
[packages.web]
|
|
97
|
+
path = "apps/web"
|
|
98
|
+
files = ["package.json"]
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
See what would release. Here a commit changed `services/api` since its last tag `api/v1.4.0`, and nothing changed in `apps/web`:
|
|
102
|
+
|
|
103
|
+
```console
|
|
104
|
+
$ verbump plan --bump minor
|
|
105
|
+
api: 1.4.0 -> 1.5.0 (minor, tag api/v1.5.0)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Write the new versions and changelogs. `apply` changes files only. It does not commit or tag.
|
|
109
|
+
|
|
110
|
+
```console
|
|
111
|
+
$ verbump apply --bump minor --plan-out plan.json
|
|
112
|
+
api: 1.4.0 -> 1.5.0 (minor, tag api/v1.5.0)
|
|
113
|
+
wrote services/api/pyproject.toml
|
|
114
|
+
wrote services/api/src/api/__init__.py
|
|
115
|
+
wrote services/api/CHANGELOG.md
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The `wrote` lines go to stderr. Commit the changes, then `verbump tag --plan plan.json` creates the tags. For a full CI recipe, see [Using it in CI](#using-it-in-ci).
|
|
119
|
+
|
|
120
|
+
## How it works
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
merge PR feat/orders ─► trunk-semver: v0.4.0 → v0.5.0 ─► bump = minor
|
|
124
|
+
│
|
|
125
|
+
verbump: which packages changed since their last tag?
|
|
126
|
+
services/api (api/v1.4.0..HEAD touches it) → 1.5.0
|
|
127
|
+
apps/web (no changes) → stays 0.3.0
|
|
128
|
+
libs/shared (watched by api) → counted for api
|
|
129
|
+
│
|
|
130
|
+
writes pyproject.toml, __init__.py, services/api/CHANGELOG.md
|
|
131
|
+
commit "chore(release): api 1.5.0" → tag api/v1.5.0 → GitHub release "api 1.5.0"
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The bump can come from trunk-semver, as drawn, or from `--bump` or a branch name. The commit, tag and release steps are your CI's job; verbump plans them and writes the files.
|
|
135
|
+
|
|
136
|
+
- **What counts as a change.** A package changed if any file under its `path` or its `watch` paths changed since the package's last tag, other than files that match `exclude`. A package with no tag yet counts every tracked file under those paths.
|
|
137
|
+
- **Version source.** Each package's version files are the source of truth. If the files and the last tag disagree, verbump bumps from the higher of the two. If a package's version files disagree with each other, verbump stops with an error.
|
|
138
|
+
- **First release.** A package with no tag yet is released at the version its files already have. A package with no version files starts from `initial_version` (`0.0.0`) and is bumped.
|
|
139
|
+
- **Changelog.** The notes under `## [Unreleased]` become `## [X.Y.Z] - <date>`. If nobody wrote notes, the section lists the subjects of the commits that touched the package since its last tag, leaving out `chore(release)` and merge commits. A missing `CHANGELOG.md` is created. A section for that version that already exists is left alone.
|
|
140
|
+
- **Exact versions.** A PR from `release/<package>/X.Y.Z` releases that package at exactly X.Y.Z, changed or not. In a single-package repo, `release/X.Y.Z` is enough. Use this for a new major, which bumps can't reach. An exact version must be newer than the package's last release.
|
|
141
|
+
- **Safe to re-run.** Tags point at the release commit, so a second run finds nothing new to release. If the planned tag already exists, verbump stops instead of moving it. Only the optional major tag (`vX`) is moved.
|
|
142
|
+
|
|
143
|
+
## Configuration
|
|
144
|
+
|
|
145
|
+
`verbump.toml` at the repo root. Use `-c <file>` for another path.
|
|
146
|
+
|
|
147
|
+
```toml
|
|
148
|
+
tag_format = "{name}/v{version}" # default for every package
|
|
149
|
+
changelog = "CHANGELOG.md" # relative to the package path; "" for none
|
|
150
|
+
|
|
151
|
+
[packages.api]
|
|
152
|
+
path = "services/api"
|
|
153
|
+
files = ["pyproject.toml", "src/api/__init__.py"]
|
|
154
|
+
watch = ["libs/shared"] # other repo paths whose changes release this package
|
|
155
|
+
exclude = ["*.md", "docs/*"] # changes only here don't release it
|
|
156
|
+
|
|
157
|
+
[packages.web]
|
|
158
|
+
path = "apps/web"
|
|
159
|
+
files = ["package.json"]
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Package names use letters, digits, `.`, `_` and `-`. verbump rejects unknown keys.
|
|
163
|
+
|
|
164
|
+
### Keys
|
|
165
|
+
|
|
166
|
+
`tag_format`, `changelog` and `major_tag` can be set at the top level as defaults for every package, and again per package.
|
|
167
|
+
|
|
168
|
+
| Key | Where | Default | Meaning |
|
|
169
|
+
|---|---|---|---|
|
|
170
|
+
| `tag_format` | top level, package | `{name}/v{version}` | Tag name. Uses `{name}`, `{path}` and `{version}`; `{version}` appears exactly once. `{path}` can't be used at the repo root. Two packages can't share a tag. |
|
|
171
|
+
| `changelog` | top level, package | `CHANGELOG.md` | Changelog file, relative to the package `path`. `""` turns it off. |
|
|
172
|
+
| `major_tag` | top level, package | `false` | Also move a major tag, such as `api/v1`, on each release. |
|
|
173
|
+
| `commit_message` | top level | `chore(release): {releases}` | Commit message in the plan. `{releases}` becomes `api 1.5.0, web 0.3.1`. |
|
|
174
|
+
| `path` | package | `.` | The package folder, relative to the repo root. It must stay inside the repo. |
|
|
175
|
+
| `files` | package | none | Files that carry the version, relative to `path`. See [Supported files](#supported-files). |
|
|
176
|
+
| `watch` | package | none | Other repo paths whose changes also release this package. |
|
|
177
|
+
| `exclude` | package | none | Glob patterns. Changes only to matching files don't release the package. Patterns match the repo path or the path relative to the package. |
|
|
178
|
+
| `initial_version` | package | `0.0.0` | Where a package with no tag and no version files starts. |
|
|
179
|
+
|
|
180
|
+
For a single-package repo, use `tag_format = "v{version}"` and one package at `path = "."`. This repo's own [`verbump.toml`](https://github.com/TheKathan/verbump/blob/main/verbump.toml) is an example. [`examples/monorepo/verbump.toml`](https://github.com/TheKathan/verbump/blob/main/examples/monorepo/verbump.toml) is a monorepo with Python, Node, .NET, Maven, Go and Helm packages.
|
|
181
|
+
|
|
182
|
+
### Files as tables
|
|
183
|
+
|
|
184
|
+
A file can be a table, to pick a kind for any file name or to give your own pattern:
|
|
185
|
+
|
|
186
|
+
```toml
|
|
187
|
+
files = [
|
|
188
|
+
{ path = "chart/Chart.yaml", kind = "helm" }, # a kind for any file name
|
|
189
|
+
{ path = "deploy/values.yaml", # or your own pattern
|
|
190
|
+
pattern = 'tag:\s*"(?P<version>\d+\.\d+\.\d+)"',
|
|
191
|
+
after = "image:", # search only after this text
|
|
192
|
+
replace_all = true }, # rewrite every match, not just the first
|
|
193
|
+
]
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
| Key | Meaning |
|
|
197
|
+
|---|---|
|
|
198
|
+
| `path` | The file, relative to the package `path`. Required. |
|
|
199
|
+
| `kind` | A built-in matcher: `json`, `toml`, `yaml`, `helm`, `plain`, `python`, `msbuild`, `assemblyinfo`, `maven`, `properties`, `gradle`, `ruby`, `elixir` or `dockerfile`. |
|
|
200
|
+
| `pattern` | Your own regex. It needs a `(?P<version>...)` group. It wins over `kind`. |
|
|
201
|
+
| `after` | Search only after the first occurrence of this text. |
|
|
202
|
+
| `replace_all` | Rewrite every match. By default only the first match is rewritten, and when there are several matches the first is read. |
|
|
203
|
+
|
|
204
|
+
## Supported files
|
|
205
|
+
|
|
206
|
+
verbump picks the kind of a file from its name, so most configs only list paths. Any other file needs a `kind` or a `pattern`.
|
|
207
|
+
|
|
208
|
+
| Stack | Files | Matches |
|
|
209
|
+
|---|---|---|
|
|
210
|
+
| Node, PHP, Deno | `package.json`, `composer.json`, `deno.json`, `jsr.json`, `manifest.json` | `"version": "X.Y.Z"` |
|
|
211
|
+
| Python | `pyproject.toml` | `version = "X.Y.Z"` at the start of a line |
|
|
212
|
+
| Python | `setup.cfg` | `version = X.Y.Z` |
|
|
213
|
+
| Python | `*.py` | `__version__ = "X.Y.Z"` |
|
|
214
|
+
| Rust | `Cargo.toml` | `version = "X.Y.Z"` at the start of a line |
|
|
215
|
+
| .NET | `*.csproj`, `*.fsproj`, `*.vbproj`, `*.props` | `<Version>` or `<VersionPrefix>` |
|
|
216
|
+
| .NET | `AssemblyInfo.cs` | every `Assembly[File\|Informational]Version("X.Y.Z...")` |
|
|
217
|
+
| Java, Kotlin | `pom.xml` | the project's `<version>`, after `</parent>` when there is one |
|
|
218
|
+
| Java, Kotlin | `build.gradle`, `build.gradle.kts` | `version = "X.Y.Z"` or `version 'X.Y.Z'` |
|
|
219
|
+
| Java, Kotlin | `gradle.properties` | `version=X.Y.Z` |
|
|
220
|
+
| Ruby | `version.rb`, `*.gemspec` | `VERSION = "X.Y.Z"`, `.version = "X.Y.Z"` |
|
|
221
|
+
| Elixir | `mix.exs` | `version: "X.Y.Z"` |
|
|
222
|
+
| Dart, Flutter | `pubspec.yaml` | `version: X.Y.Z` (a `+build` suffix is kept) |
|
|
223
|
+
| Helm | `Chart.yaml` | `version: X.Y.Z`. Set `kind = "helm"` to move `appVersion` too. |
|
|
224
|
+
| Docker | `Dockerfile` | `LABEL ... version="X.Y.Z"` |
|
|
225
|
+
| Any | `VERSION`, `VERSION.txt`, `version.txt`, `.version` | the whole file |
|
|
226
|
+
| Go, Swift, ... | no file | the version lives only in the tags; use `tag_format = "{path}/v{version}"` for Go modules |
|
|
227
|
+
|
|
228
|
+
A `v` prefix is read in `Chart.yaml` with `kind = "helm"` and in plain version files. Versions are always `X.Y.Z`.
|
|
229
|
+
|
|
230
|
+
## Commands
|
|
231
|
+
|
|
232
|
+
```
|
|
233
|
+
verbump [-C ROOT] [-c CONFIG] <command>
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
| Command | What it does |
|
|
237
|
+
|---|---|
|
|
238
|
+
| `status [--json]` | Lists each package with its file version, last tag and number of changed files. |
|
|
239
|
+
| `plan [options]` | Shows what would release. Changes nothing. |
|
|
240
|
+
| `apply [options] [--date YYYY-MM-DD]` | Writes versions and changelogs, and prints the plan. Doesn't commit or tag. `--date` defaults to today, UTC. |
|
|
241
|
+
| `tag --plan FILE` | Creates the annotated tags in a saved plan, and moves its major tags. Doesn't push. |
|
|
242
|
+
| `notes <package> [<version>]` | Prints a version's changelog section, for a release body. Without a version, it uses the package's file version. |
|
|
243
|
+
| `set <package> <version> [--date D]` | Writes an exact version into one package's files and changelog. |
|
|
244
|
+
| `check` | Prints each package's file version. Exits 1 if a package's version files disagree. |
|
|
245
|
+
| `init` | Writes a starter `verbump.toml`. It won't overwrite an existing one. |
|
|
246
|
+
| `demo [--dir D] [--setup-only]` | A narrated release in a throwaway repo with a Python and a Node package. `--dir` keeps the repo; `--setup-only` only builds it and prints its path. |
|
|
247
|
+
|
|
248
|
+
Global options: `-C <repo root>` (default `.`) and `-c <config file>` (default `<root>/verbump.toml`).
|
|
249
|
+
|
|
250
|
+
### Choosing the bump
|
|
251
|
+
|
|
252
|
+
`plan` and `apply` take the bump from one of these sources:
|
|
253
|
+
|
|
254
|
+
- `--bump major|minor|patch`.
|
|
255
|
+
- `--previous` and `--version-from`, which are trunk-semver's `previous-version` and `version` outputs. verbump works out the bump from the two. They go together.
|
|
256
|
+
- `--branch <name>`, which applies trunk-semver's branch rule without trunk-semver.
|
|
257
|
+
- Nothing, which means a patch.
|
|
258
|
+
|
|
259
|
+
`--bump` and `--branch` can't be combined. If you pass several sources, `--bump` wins, then `--previous` with `--version-from`, then `--branch`.
|
|
260
|
+
|
|
261
|
+
### Other options for `plan` and `apply`
|
|
262
|
+
|
|
263
|
+
| Option | Meaning |
|
|
264
|
+
|---|---|
|
|
265
|
+
| `--exact NAME=X.Y.Z` | Release a package at exactly this version, changed or not. Repeatable. |
|
|
266
|
+
| `--release-branch <branch>` | If the branch is `release/<package>/X.Y.Z` (or `release/X.Y.Z` with one package), it sets `--exact`. Other branches are ignored. |
|
|
267
|
+
| `--only NAME` | Limit the run to this package. Repeatable. |
|
|
268
|
+
| `--json` | Print the plan as JSON instead of text. |
|
|
269
|
+
| `--plan-out FILE` | Also write the plan as JSON to this file. |
|
|
270
|
+
|
|
271
|
+
### Output
|
|
272
|
+
|
|
273
|
+
`plan` and `apply` print one line per release, as `name: previous -> new (reason, tag T)`. The previous version is `-` for a package with no tag. With nothing to release they print `nothing to release`. The reason is the bump, `first release` or `exact`.
|
|
274
|
+
|
|
275
|
+
The plan JSON has the shape `{"bump", "commit_message", "releases": [{"name", "path", "previous", "version", "tag", "major_tag", "changelog", "reason", "changed"}]}`.
|
|
276
|
+
|
|
277
|
+
## Using it in CI
|
|
278
|
+
|
|
279
|
+
In GitHub Actions, use [TheKathan/verbump-action](https://github.com/TheKathan/verbump-action). It installs `verbump-cli` from PyPI, then:
|
|
280
|
+
|
|
281
|
+
1. applies the bump;
|
|
282
|
+
2. commits, tags and pushes;
|
|
283
|
+
3. publishes a GitHub release per package.
|
|
284
|
+
|
|
285
|
+
It takes the bump as an input, from any source (trunk-semver, a branch name or a fixed value). It doesn't run trunk-semver itself.
|
|
286
|
+
|
|
287
|
+
Anywhere else, the CLI does the same work. This recipe takes the bump from the merged PR's branch name:
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
verbump apply --branch "$PR_BRANCH" --release-branch "$PR_BRANCH" --plan-out plan.json
|
|
291
|
+
verbump check
|
|
292
|
+
git commit -am "$(jq -r .commit_message plan.json)"
|
|
293
|
+
verbump tag --plan plan.json
|
|
294
|
+
git push origin HEAD:main --follow-tags
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
`--follow-tags` pushes the annotated tags. Major tags are lightweight and moved, so push them yourself, for example with `git push --force origin <major_tag>`. To create a GitHub release for each package, loop over the plan and use `verbump notes <name> <version>` as the release body.
|
|
298
|
+
|
|
299
|
+
This repo releases itself with [`.github/workflows/release.yml`](https://github.com/TheKathan/verbump/blob/main/.github/workflows/release.yml), running verbump from its own source. It runs in this order:
|
|
300
|
+
|
|
301
|
+
1. Run trunk-semver against a local mirror, so its repo-wide tag never reaches GitHub, and take the bump from its `previous-version` and `version`. When it gives no previous version, use the PR's branch name.
|
|
302
|
+
2. Run `verbump apply` and `verbump check`.
|
|
303
|
+
3. Commit, tag and push.
|
|
304
|
+
4. Publish the GitHub release.
|
|
305
|
+
5. Build the sdist and the wheel.
|
|
306
|
+
6. Upload them to PyPI, when the `PUBLISH_PYPI` variable is `true`.
|
|
307
|
+
|
|
308
|
+
## Contribute
|
|
309
|
+
|
|
310
|
+
Bugs, questions and ideas go to [issues](https://github.com/TheKathan/verbump/issues), and pull requests are welcome: see [CONTRIBUTING](https://github.com/TheKathan/verbump/blob/main/CONTRIBUTING.md) and the [code of conduct](https://github.com/TheKathan/verbump/blob/main/CODE_OF_CONDUCT.md). Issues about the GitHub Action go to [verbump-action](https://github.com/TheKathan/verbump-action/issues). If verbump saves you a release chore, a star helps others find it.
|
|
311
|
+
|
|
312
|
+
[CHANGELOG](https://github.com/TheKathan/verbump/blob/main/CHANGELOG.md) · [SECURITY](https://github.com/TheKathan/verbump/blob/main/SECURITY.md) · [Publishing](https://github.com/TheKathan/verbump/blob/main/docs/publishing.md) · [LICENSE](https://github.com/TheKathan/verbump/blob/main/LICENSE) (MIT)
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
<h1 align="center">verbump</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://github.com/TheKathan/verbump/actions/workflows/test.yml"><img alt="tests" src="https://github.com/TheKathan/verbump/actions/workflows/test.yml/badge.svg"></a>
|
|
5
|
+
<a href="https://pypi.org/project/verbump-cli/"><img alt="PyPI" src="https://img.shields.io/pypi/v/verbump-cli"></a>
|
|
6
|
+
<img alt="license" src="https://img.shields.io/github/license/TheKathan/verbump">
|
|
7
|
+
<img alt="Python 3.11+" src="https://img.shields.io/badge/python-%E2%89%A5%203.11-3776AB">
|
|
8
|
+
<img alt="dependencies: none" src="https://img.shields.io/badge/dependencies-none-brightgreen">
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
**Version and changelog bumps for repos: only the packages that changed move.**
|
|
12
|
+
|
|
13
|
+
verbump finds the packages in your repo that changed since their own last tag, writes each one's new version into its files, and turns its changelog's `## [Unreleased]` notes into the release. One package or fifty, Python, Node, .NET, Java, Rust, Go or anything with a version in a file. One CLI, one `verbump.toml`, no dependencies.
|
|
14
|
+
|
|
15
|
+
**Try it in one command:** `uvx --from verbump-cli verbump demo`
|
|
16
|
+
|
|
17
|
+
<p align="center"><img alt="verbump in a repo with two packages. verbump status shows api at 1.4.0 with 0 changed files and web at 0.3.0 with 2 changed files. git log shows a commit feat(web): checkout page that touched apps/web. verbump apply --branch feat/checkout prints web: 0.3.0 -> 0.4.0 (minor, tag web/v0.4.0) and writes apps/web/package.json and apps/web/CHANGELOG.md. git diff shows the version going from 0.3.0 to 0.4.0, and verbump notes web prints the release notes: Added, Checkout page." src="https://raw.githubusercontent.com/TheKathan/verbump/main/assets/demo.gif" width="800"><br><sub>A PR from <code>feat/checkout</code> changed only <code>apps/web</code>: web gets a minor bump and its release notes, api stays at 1.4.0.</sub></p>
|
|
18
|
+
|
|
19
|
+
## Try it in 60 seconds
|
|
20
|
+
|
|
21
|
+
With verbump [installed](#quick-start), this builds the repo from the recording in a scratch folder and releases it:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
verbump demo --dir verbump-try --setup-only && cd verbump-try
|
|
25
|
+
verbump status # api and web, both tagged; web has changes
|
|
26
|
+
verbump plan --branch feat/checkout # web: 0.3.0 -> 0.4.0 (minor, tag web/v0.4.0)
|
|
27
|
+
verbump apply --branch feat/checkout # writes apps/web/package.json and CHANGELOG.md
|
|
28
|
+
verbump notes web # the notes for the GitHub release
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Or run `verbump demo` for a narrated replay in a temporary folder.
|
|
32
|
+
|
|
33
|
+
## Why verbump
|
|
34
|
+
|
|
35
|
+
- **Only what changed moves.** Each package is released from its own last tag, so a fix in one service doesn't bump the other nine.
|
|
36
|
+
- **Release notes you already wrote.** The `Unreleased` notes become the version's section and the GitHub release body; with no notes, the commit subjects that touched the package.
|
|
37
|
+
- **Any stack.** It reads and writes versions in `package.json`, `pyproject.toml`, `Cargo.toml`, `.csproj`, `pom.xml`, Gradle, Helm charts, Dockerfiles and more, or any file you give a pattern. Go-style tags work too.
|
|
38
|
+
- **You choose the bump.** A flag, the PR's branch name, or [trunk-semver](https://github.com/TheKathan/trunk-semver)'s outputs. A `release/<package>/X.Y.Z` branch cuts an exact version.
|
|
39
|
+
- **Safe to re-run.** Tags are created once and never moved; a second run finds nothing to release.
|
|
40
|
+
- **Nothing to run.** Python 3.11+ and the standard library; no server, no plugins per language.
|
|
41
|
+
|
|
42
|
+
## What it's for
|
|
43
|
+
|
|
44
|
+
| Use | What you get |
|
|
45
|
+
|---|---|
|
|
46
|
+
| **A repo with several services or libraries** | Per-package versions, tags (`api/v1.5.0`) and changelogs, from one config. [Example](https://github.com/TheKathan/verbump/blob/main/examples/monorepo/verbump.toml) |
|
|
47
|
+
| **A single package** | `tag_format = "v{version}"` and one package at `.`; verbump releases itself this way. [Its config](https://github.com/TheKathan/verbump/blob/main/verbump.toml) |
|
|
48
|
+
| **GitHub Actions** | [verbump-action](https://github.com/TheKathan/verbump-action) bumps, commits, tags, pushes and publishes a GitHub release per package, on any stack. |
|
|
49
|
+
| **Any other CI** | Four commands: `apply`, `check`, `tag`, `notes`. [Recipe](#using-it-in-ci) |
|
|
50
|
+
|
|
51
|
+
## Quick start
|
|
52
|
+
|
|
53
|
+
Install it. The PyPI package is `verbump-cli`, because the name `verbump` belongs to an unrelated project. The command it installs is `verbump`.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pipx install verbump-cli # or: uv tool install verbump-cli, pip install verbump-cli
|
|
57
|
+
verbump --version
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Declare your packages in `verbump.toml` at the repo root. `verbump init` writes a starter file. A minimal one looks like this:
|
|
61
|
+
|
|
62
|
+
```toml
|
|
63
|
+
tag_format = "{name}/v{version}"
|
|
64
|
+
|
|
65
|
+
[packages.api]
|
|
66
|
+
path = "services/api"
|
|
67
|
+
files = ["pyproject.toml", "src/api/__init__.py"]
|
|
68
|
+
|
|
69
|
+
[packages.web]
|
|
70
|
+
path = "apps/web"
|
|
71
|
+
files = ["package.json"]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
See what would release. Here a commit changed `services/api` since its last tag `api/v1.4.0`, and nothing changed in `apps/web`:
|
|
75
|
+
|
|
76
|
+
```console
|
|
77
|
+
$ verbump plan --bump minor
|
|
78
|
+
api: 1.4.0 -> 1.5.0 (minor, tag api/v1.5.0)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Write the new versions and changelogs. `apply` changes files only. It does not commit or tag.
|
|
82
|
+
|
|
83
|
+
```console
|
|
84
|
+
$ verbump apply --bump minor --plan-out plan.json
|
|
85
|
+
api: 1.4.0 -> 1.5.0 (minor, tag api/v1.5.0)
|
|
86
|
+
wrote services/api/pyproject.toml
|
|
87
|
+
wrote services/api/src/api/__init__.py
|
|
88
|
+
wrote services/api/CHANGELOG.md
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The `wrote` lines go to stderr. Commit the changes, then `verbump tag --plan plan.json` creates the tags. For a full CI recipe, see [Using it in CI](#using-it-in-ci).
|
|
92
|
+
|
|
93
|
+
## How it works
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
merge PR feat/orders ─► trunk-semver: v0.4.0 → v0.5.0 ─► bump = minor
|
|
97
|
+
│
|
|
98
|
+
verbump: which packages changed since their last tag?
|
|
99
|
+
services/api (api/v1.4.0..HEAD touches it) → 1.5.0
|
|
100
|
+
apps/web (no changes) → stays 0.3.0
|
|
101
|
+
libs/shared (watched by api) → counted for api
|
|
102
|
+
│
|
|
103
|
+
writes pyproject.toml, __init__.py, services/api/CHANGELOG.md
|
|
104
|
+
commit "chore(release): api 1.5.0" → tag api/v1.5.0 → GitHub release "api 1.5.0"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The bump can come from trunk-semver, as drawn, or from `--bump` or a branch name. The commit, tag and release steps are your CI's job; verbump plans them and writes the files.
|
|
108
|
+
|
|
109
|
+
- **What counts as a change.** A package changed if any file under its `path` or its `watch` paths changed since the package's last tag, other than files that match `exclude`. A package with no tag yet counts every tracked file under those paths.
|
|
110
|
+
- **Version source.** Each package's version files are the source of truth. If the files and the last tag disagree, verbump bumps from the higher of the two. If a package's version files disagree with each other, verbump stops with an error.
|
|
111
|
+
- **First release.** A package with no tag yet is released at the version its files already have. A package with no version files starts from `initial_version` (`0.0.0`) and is bumped.
|
|
112
|
+
- **Changelog.** The notes under `## [Unreleased]` become `## [X.Y.Z] - <date>`. If nobody wrote notes, the section lists the subjects of the commits that touched the package since its last tag, leaving out `chore(release)` and merge commits. A missing `CHANGELOG.md` is created. A section for that version that already exists is left alone.
|
|
113
|
+
- **Exact versions.** A PR from `release/<package>/X.Y.Z` releases that package at exactly X.Y.Z, changed or not. In a single-package repo, `release/X.Y.Z` is enough. Use this for a new major, which bumps can't reach. An exact version must be newer than the package's last release.
|
|
114
|
+
- **Safe to re-run.** Tags point at the release commit, so a second run finds nothing new to release. If the planned tag already exists, verbump stops instead of moving it. Only the optional major tag (`vX`) is moved.
|
|
115
|
+
|
|
116
|
+
## Configuration
|
|
117
|
+
|
|
118
|
+
`verbump.toml` at the repo root. Use `-c <file>` for another path.
|
|
119
|
+
|
|
120
|
+
```toml
|
|
121
|
+
tag_format = "{name}/v{version}" # default for every package
|
|
122
|
+
changelog = "CHANGELOG.md" # relative to the package path; "" for none
|
|
123
|
+
|
|
124
|
+
[packages.api]
|
|
125
|
+
path = "services/api"
|
|
126
|
+
files = ["pyproject.toml", "src/api/__init__.py"]
|
|
127
|
+
watch = ["libs/shared"] # other repo paths whose changes release this package
|
|
128
|
+
exclude = ["*.md", "docs/*"] # changes only here don't release it
|
|
129
|
+
|
|
130
|
+
[packages.web]
|
|
131
|
+
path = "apps/web"
|
|
132
|
+
files = ["package.json"]
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Package names use letters, digits, `.`, `_` and `-`. verbump rejects unknown keys.
|
|
136
|
+
|
|
137
|
+
### Keys
|
|
138
|
+
|
|
139
|
+
`tag_format`, `changelog` and `major_tag` can be set at the top level as defaults for every package, and again per package.
|
|
140
|
+
|
|
141
|
+
| Key | Where | Default | Meaning |
|
|
142
|
+
|---|---|---|---|
|
|
143
|
+
| `tag_format` | top level, package | `{name}/v{version}` | Tag name. Uses `{name}`, `{path}` and `{version}`; `{version}` appears exactly once. `{path}` can't be used at the repo root. Two packages can't share a tag. |
|
|
144
|
+
| `changelog` | top level, package | `CHANGELOG.md` | Changelog file, relative to the package `path`. `""` turns it off. |
|
|
145
|
+
| `major_tag` | top level, package | `false` | Also move a major tag, such as `api/v1`, on each release. |
|
|
146
|
+
| `commit_message` | top level | `chore(release): {releases}` | Commit message in the plan. `{releases}` becomes `api 1.5.0, web 0.3.1`. |
|
|
147
|
+
| `path` | package | `.` | The package folder, relative to the repo root. It must stay inside the repo. |
|
|
148
|
+
| `files` | package | none | Files that carry the version, relative to `path`. See [Supported files](#supported-files). |
|
|
149
|
+
| `watch` | package | none | Other repo paths whose changes also release this package. |
|
|
150
|
+
| `exclude` | package | none | Glob patterns. Changes only to matching files don't release the package. Patterns match the repo path or the path relative to the package. |
|
|
151
|
+
| `initial_version` | package | `0.0.0` | Where a package with no tag and no version files starts. |
|
|
152
|
+
|
|
153
|
+
For a single-package repo, use `tag_format = "v{version}"` and one package at `path = "."`. This repo's own [`verbump.toml`](https://github.com/TheKathan/verbump/blob/main/verbump.toml) is an example. [`examples/monorepo/verbump.toml`](https://github.com/TheKathan/verbump/blob/main/examples/monorepo/verbump.toml) is a monorepo with Python, Node, .NET, Maven, Go and Helm packages.
|
|
154
|
+
|
|
155
|
+
### Files as tables
|
|
156
|
+
|
|
157
|
+
A file can be a table, to pick a kind for any file name or to give your own pattern:
|
|
158
|
+
|
|
159
|
+
```toml
|
|
160
|
+
files = [
|
|
161
|
+
{ path = "chart/Chart.yaml", kind = "helm" }, # a kind for any file name
|
|
162
|
+
{ path = "deploy/values.yaml", # or your own pattern
|
|
163
|
+
pattern = 'tag:\s*"(?P<version>\d+\.\d+\.\d+)"',
|
|
164
|
+
after = "image:", # search only after this text
|
|
165
|
+
replace_all = true }, # rewrite every match, not just the first
|
|
166
|
+
]
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
| Key | Meaning |
|
|
170
|
+
|---|---|
|
|
171
|
+
| `path` | The file, relative to the package `path`. Required. |
|
|
172
|
+
| `kind` | A built-in matcher: `json`, `toml`, `yaml`, `helm`, `plain`, `python`, `msbuild`, `assemblyinfo`, `maven`, `properties`, `gradle`, `ruby`, `elixir` or `dockerfile`. |
|
|
173
|
+
| `pattern` | Your own regex. It needs a `(?P<version>...)` group. It wins over `kind`. |
|
|
174
|
+
| `after` | Search only after the first occurrence of this text. |
|
|
175
|
+
| `replace_all` | Rewrite every match. By default only the first match is rewritten, and when there are several matches the first is read. |
|
|
176
|
+
|
|
177
|
+
## Supported files
|
|
178
|
+
|
|
179
|
+
verbump picks the kind of a file from its name, so most configs only list paths. Any other file needs a `kind` or a `pattern`.
|
|
180
|
+
|
|
181
|
+
| Stack | Files | Matches |
|
|
182
|
+
|---|---|---|
|
|
183
|
+
| Node, PHP, Deno | `package.json`, `composer.json`, `deno.json`, `jsr.json`, `manifest.json` | `"version": "X.Y.Z"` |
|
|
184
|
+
| Python | `pyproject.toml` | `version = "X.Y.Z"` at the start of a line |
|
|
185
|
+
| Python | `setup.cfg` | `version = X.Y.Z` |
|
|
186
|
+
| Python | `*.py` | `__version__ = "X.Y.Z"` |
|
|
187
|
+
| Rust | `Cargo.toml` | `version = "X.Y.Z"` at the start of a line |
|
|
188
|
+
| .NET | `*.csproj`, `*.fsproj`, `*.vbproj`, `*.props` | `<Version>` or `<VersionPrefix>` |
|
|
189
|
+
| .NET | `AssemblyInfo.cs` | every `Assembly[File\|Informational]Version("X.Y.Z...")` |
|
|
190
|
+
| Java, Kotlin | `pom.xml` | the project's `<version>`, after `</parent>` when there is one |
|
|
191
|
+
| Java, Kotlin | `build.gradle`, `build.gradle.kts` | `version = "X.Y.Z"` or `version 'X.Y.Z'` |
|
|
192
|
+
| Java, Kotlin | `gradle.properties` | `version=X.Y.Z` |
|
|
193
|
+
| Ruby | `version.rb`, `*.gemspec` | `VERSION = "X.Y.Z"`, `.version = "X.Y.Z"` |
|
|
194
|
+
| Elixir | `mix.exs` | `version: "X.Y.Z"` |
|
|
195
|
+
| Dart, Flutter | `pubspec.yaml` | `version: X.Y.Z` (a `+build` suffix is kept) |
|
|
196
|
+
| Helm | `Chart.yaml` | `version: X.Y.Z`. Set `kind = "helm"` to move `appVersion` too. |
|
|
197
|
+
| Docker | `Dockerfile` | `LABEL ... version="X.Y.Z"` |
|
|
198
|
+
| Any | `VERSION`, `VERSION.txt`, `version.txt`, `.version` | the whole file |
|
|
199
|
+
| Go, Swift, ... | no file | the version lives only in the tags; use `tag_format = "{path}/v{version}"` for Go modules |
|
|
200
|
+
|
|
201
|
+
A `v` prefix is read in `Chart.yaml` with `kind = "helm"` and in plain version files. Versions are always `X.Y.Z`.
|
|
202
|
+
|
|
203
|
+
## Commands
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
verbump [-C ROOT] [-c CONFIG] <command>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
| Command | What it does |
|
|
210
|
+
|---|---|
|
|
211
|
+
| `status [--json]` | Lists each package with its file version, last tag and number of changed files. |
|
|
212
|
+
| `plan [options]` | Shows what would release. Changes nothing. |
|
|
213
|
+
| `apply [options] [--date YYYY-MM-DD]` | Writes versions and changelogs, and prints the plan. Doesn't commit or tag. `--date` defaults to today, UTC. |
|
|
214
|
+
| `tag --plan FILE` | Creates the annotated tags in a saved plan, and moves its major tags. Doesn't push. |
|
|
215
|
+
| `notes <package> [<version>]` | Prints a version's changelog section, for a release body. Without a version, it uses the package's file version. |
|
|
216
|
+
| `set <package> <version> [--date D]` | Writes an exact version into one package's files and changelog. |
|
|
217
|
+
| `check` | Prints each package's file version. Exits 1 if a package's version files disagree. |
|
|
218
|
+
| `init` | Writes a starter `verbump.toml`. It won't overwrite an existing one. |
|
|
219
|
+
| `demo [--dir D] [--setup-only]` | A narrated release in a throwaway repo with a Python and a Node package. `--dir` keeps the repo; `--setup-only` only builds it and prints its path. |
|
|
220
|
+
|
|
221
|
+
Global options: `-C <repo root>` (default `.`) and `-c <config file>` (default `<root>/verbump.toml`).
|
|
222
|
+
|
|
223
|
+
### Choosing the bump
|
|
224
|
+
|
|
225
|
+
`plan` and `apply` take the bump from one of these sources:
|
|
226
|
+
|
|
227
|
+
- `--bump major|minor|patch`.
|
|
228
|
+
- `--previous` and `--version-from`, which are trunk-semver's `previous-version` and `version` outputs. verbump works out the bump from the two. They go together.
|
|
229
|
+
- `--branch <name>`, which applies trunk-semver's branch rule without trunk-semver.
|
|
230
|
+
- Nothing, which means a patch.
|
|
231
|
+
|
|
232
|
+
`--bump` and `--branch` can't be combined. If you pass several sources, `--bump` wins, then `--previous` with `--version-from`, then `--branch`.
|
|
233
|
+
|
|
234
|
+
### Other options for `plan` and `apply`
|
|
235
|
+
|
|
236
|
+
| Option | Meaning |
|
|
237
|
+
|---|---|
|
|
238
|
+
| `--exact NAME=X.Y.Z` | Release a package at exactly this version, changed or not. Repeatable. |
|
|
239
|
+
| `--release-branch <branch>` | If the branch is `release/<package>/X.Y.Z` (or `release/X.Y.Z` with one package), it sets `--exact`. Other branches are ignored. |
|
|
240
|
+
| `--only NAME` | Limit the run to this package. Repeatable. |
|
|
241
|
+
| `--json` | Print the plan as JSON instead of text. |
|
|
242
|
+
| `--plan-out FILE` | Also write the plan as JSON to this file. |
|
|
243
|
+
|
|
244
|
+
### Output
|
|
245
|
+
|
|
246
|
+
`plan` and `apply` print one line per release, as `name: previous -> new (reason, tag T)`. The previous version is `-` for a package with no tag. With nothing to release they print `nothing to release`. The reason is the bump, `first release` or `exact`.
|
|
247
|
+
|
|
248
|
+
The plan JSON has the shape `{"bump", "commit_message", "releases": [{"name", "path", "previous", "version", "tag", "major_tag", "changelog", "reason", "changed"}]}`.
|
|
249
|
+
|
|
250
|
+
## Using it in CI
|
|
251
|
+
|
|
252
|
+
In GitHub Actions, use [TheKathan/verbump-action](https://github.com/TheKathan/verbump-action). It installs `verbump-cli` from PyPI, then:
|
|
253
|
+
|
|
254
|
+
1. applies the bump;
|
|
255
|
+
2. commits, tags and pushes;
|
|
256
|
+
3. publishes a GitHub release per package.
|
|
257
|
+
|
|
258
|
+
It takes the bump as an input, from any source (trunk-semver, a branch name or a fixed value). It doesn't run trunk-semver itself.
|
|
259
|
+
|
|
260
|
+
Anywhere else, the CLI does the same work. This recipe takes the bump from the merged PR's branch name:
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
verbump apply --branch "$PR_BRANCH" --release-branch "$PR_BRANCH" --plan-out plan.json
|
|
264
|
+
verbump check
|
|
265
|
+
git commit -am "$(jq -r .commit_message plan.json)"
|
|
266
|
+
verbump tag --plan plan.json
|
|
267
|
+
git push origin HEAD:main --follow-tags
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
`--follow-tags` pushes the annotated tags. Major tags are lightweight and moved, so push them yourself, for example with `git push --force origin <major_tag>`. To create a GitHub release for each package, loop over the plan and use `verbump notes <name> <version>` as the release body.
|
|
271
|
+
|
|
272
|
+
This repo releases itself with [`.github/workflows/release.yml`](https://github.com/TheKathan/verbump/blob/main/.github/workflows/release.yml), running verbump from its own source. It runs in this order:
|
|
273
|
+
|
|
274
|
+
1. Run trunk-semver against a local mirror, so its repo-wide tag never reaches GitHub, and take the bump from its `previous-version` and `version`. When it gives no previous version, use the PR's branch name.
|
|
275
|
+
2. Run `verbump apply` and `verbump check`.
|
|
276
|
+
3. Commit, tag and push.
|
|
277
|
+
4. Publish the GitHub release.
|
|
278
|
+
5. Build the sdist and the wheel.
|
|
279
|
+
6. Upload them to PyPI, when the `PUBLISH_PYPI` variable is `true`.
|
|
280
|
+
|
|
281
|
+
## Contribute
|
|
282
|
+
|
|
283
|
+
Bugs, questions and ideas go to [issues](https://github.com/TheKathan/verbump/issues), and pull requests are welcome: see [CONTRIBUTING](https://github.com/TheKathan/verbump/blob/main/CONTRIBUTING.md) and the [code of conduct](https://github.com/TheKathan/verbump/blob/main/CODE_OF_CONDUCT.md). Issues about the GitHub Action go to [verbump-action](https://github.com/TheKathan/verbump-action/issues). If verbump saves you a release chore, a star helps others find it.
|
|
284
|
+
|
|
285
|
+
[CHANGELOG](https://github.com/TheKathan/verbump/blob/main/CHANGELOG.md) · [SECURITY](https://github.com/TheKathan/verbump/blob/main/SECURITY.md) · [Publishing](https://github.com/TheKathan/verbump/blob/main/docs/publishing.md) · [LICENSE](https://github.com/TheKathan/verbump/blob/main/LICENSE) (MIT)
|