Cut a release
A Product ships through deployments and is announced through releases. This page is about the second: what a release is, what cutting one does, and how to cut one from the UI or with ir.
A release and a deployment
A deployment (the Release resource) is one build of a Product moving through its zones: built, tagged, promoted zone by zone through a pull request each, checked, held under the release guard, rolled back if it fails. A merged Change starts one on its own, and New deployment starts one by hand. Deployments are how code reaches production, and there can be many of them in a day.
A release is what people read. It gathers every deployment that reached production since the last release under one version, tags the commit and the image running in production with that version, and publishes two write-ups: release notes for engineers and a post for everyone else. The ReleaseCut resource; its phase is Pending, Tagging, Publishing, Released or Failed. An org-admin cuts one when the Product has something worth telling.
| Deployment | Release | |
|---|---|---|
| What it is | One build moving through the zones | The deployments in production since the last release, under one version |
| Started by | A merged Change, or a person | A person who cuts it |
| Version | The next patch: v1.6.1, v1.6.2 | The next minor or major: v1.7.0, v2.0.0 |
| Tags | A git tag on the commit | A git tag on the commit, and the image's digest tagged with the version |
| On the forge | Nothing | A GitHub release on the tag, with the notes, marked latest |
release.cut | Not sent | Sent once, so the release AgentWorkflow runs once per release |
| Phases | Pending, Building, Tagged, Promoting, AwaitingApproval, Released, Failed | Pending, Tagging, Publishing, Released, Failed |
Version numbers
A deployment bumps only the patch, counting from the newer of the last deployment's version and the last release's. After release v1.6.0, the next deployment is v1.6.1, then v1.6.2. The first deployment of a Product with no tag at all is v0.1.0. Pre-release tracks (-rc.N) are unchanged.
A release takes the next minor or major of the version running in production. The draft suggests major when a deployment since the last release holds a breaking change and the Product is at 1.0 or later, and minor otherwise. The choice is yours when you cut. A release is never a patch.
What cutting does
Cutting a release of zippy at v1.7.0, with zippy-7kq2m running in production:
- Tags the commit. The git tag
v1.7.0lands on the commit the production deployment shipped. Nothing is built: the release is exactly what runs. - Tags the image. The image digest running in production gets the tag
v1.7.0in the Product's registry, beside the tag its deployment gave it. - Creates the GitHub release. On the tag, with the release notes as its body, marked latest. Deployments make no GitHub release, so a Product's GitHub releases are its releases and nothing else.
- Sends
release.cutonce. Every enabled AgentWorkflow with arelease.cuttrigger starts one run, with the release's version and notes. ThereleaseAgentWorkflow, which announces, runs once per release, not once per deployment.
Each step is done once: a cut that fails partway, for instance because the forge did not answer, resumes from the step that failed, and never repeats a tag it made.
A cut covers the deployments that reached production Healthy after the last release, in the order they got there; the one in production now is the newest of them. With no release yet, it covers every deployment in production since the Product's last GitHub release, or all of them when it has none. A cut with nothing new is refused, and so is a second cut while one is still Tagging or Publishing.
Who may cut
An org-admin, or a platform admin. Members see the Releases tab, the draft and every release, and can read the notes and the post, but Cut a release is not theirs. A cut records who made it, as Infrared names people, never by an email address.
The nudge
A Product's Releases tab says when there is enough in production to be worth a release: at least one feature, or one breaking change, or ten fixes since the last release. It counts the commits the deployments shipped by their conventional commit subjects: feat is a feature, fix a fix, a ! or a BREAKING CHANGE footer a breaking change, and anything else is other. The nudge is a suggestion; you can cut a release with one fix in it, or let twenty features wait.
Cut a release in the UI
Open the Product and its Releases tab.
- In production, not in a release yet lists the deployments a cut would cover, oldest first, each with its version, when it reached production, who asked for it, how its release guard ended, and the commits it shipped by kind. Above it, the nudge and its counts.
- Cut a release opens the drawer. It proposes the version, minor or major, and says why in a sentence ("12 changes since v1.6.0, none breaking"). Switch to the other if you disagree.
- The title is
<product> <version>unless you change it. - The notes are drafted for engineers, in Markdown: Breaking changes, Features, Fixes and Other, a section only when it has items, each item its title, pull request, issue and who asked for it, and which deployment shipped it. A footer names the covered deployments. Edit them as you like.
- The post is drafted for everyone else: a few plain lines, a breaking change first, then each feature in a short paragraph, then "and N fixes". Edit it too. Nothing in either draft is written by an agent.
- Cut release v1.7.0 cuts it. The drawer closes and the release appears on the tab, Tagging, then Publishing, then Released, with a message at each step and the reason if it fails.
The tab lists the releases so far, newest first: version, title, who cut it and when, how many deployments and commits it covers, and the GitHub release once it exists.
The release's page and its post
A release has a page, /releases/<product>/<version>, and the org's releases are listed at Releases in the rail. The page shows the version, the title, who cut it and when, the commit and the image it tagged, the GitHub release, the notes as published, every change by kind, and the deployments it covers with their changes. The post has a page of its own, /releases/<product>/<version>/post, which reads as it was written, without the engineering detail, for anyone in the org to read or to pass on.
The deployments it covers keep their own pages under Deployments. An old link to /releases/<deployment> opens the deployment.
With ir
ir release cut --product zippy
ir release cut --product zippy --major --title "zippy v2.0.0" --notes-file notes.md --post-file post.md
ir release cuts --product zippy
ir release cut get zippy-1-7-0
| Command | What it does |
|---|---|
ir release cut --product <p> [--major] [--title <t>] [--notes-file <f>] [--post-file <f>] | Cut a release of the Product at the next minor, or the next major with --major. The title, notes and post are the draft's unless you pass your own |
ir release cuts [--product <p>] | The org's releases, newest first, or one Product's |
ir release cut get <name> | One release: its tags, the GitHub release, the notes and the post, and the deployments it covers |
ir release new and ir release promote start and promote a deployment, as before. They are not a release.
With the API
| Operation | What it does |
|---|---|
GET /v1/orgs/{org}/products/{product}/releasecut-draft?bump=minor|major | The draft: what is in production and not in a release yet, the versions to choose from, the nudge, the title, the notes and the post. Members and up |
POST /v1/orgs/{org}/releasecuts | Cut a release: product, bump (minor or major), and optionally title, notes and post, the draft's where empty. 201 with the release; 403 below org-admin; 409 when there is nothing new or a cut is in progress; 422 on a bad bump |
GET /v1/orgs/{org}/releasecuts?product=<p> | The org's releases, newest first |
GET /v1/orgs/{org}/releasecuts/{name} | One release, with its notes, its post, every change by kind and the deployments it covers |
A release is named <product>-<major>-<minor>-<patch>: zippy-1-7-0.