Skip to content

Releasing

A release makes new functionality available to customers as a pinned version of the code repository. Customers upgrade when they choose; see What to do when a new version is released. The release history and the upgrade guides are in Releases and upgrade guidance.

Versioning

Versions are calculated by GitVersion (.GitVersion.yml, workflow GitHubFlow/v1, mode ContinuousDelivery):

Branch Pattern Label Increment
main ^main$ alpha Minor
Release release/v<major>.<minor> beta Patch
Feature feature/<name> or features/<name> <name> Inherited
  • Releases are tagged v<major>.<minor>.<patch> on the release branch (for example v4.12.2 on release/v4.12).
  • Bumps come only from merge messages (commit-message-incrementing: MergeMessageOnly):

    Merge message contains Bump
    +semver: major or +semver: breaking major
    +semver: minor or +semver: feature minor
    +semver: patch or +semver: fix patch
    +semver: none or +semver: skip none
  • Customers pin a release branch (release/v4.12), so they get patch releases on that branch automatically on their next run. They change the pin to move to a new minor or major version.

A pinned release branch moves

Because entry pipelines pin release/vX.Y and not a tag, a patch merged to that branch reaches customers on their next container + hub run. Treat every merge to a release branch as a release to all customers on that minor version.

Container image tags

Get-XebiaMcpContainerTags.ps1 tags every mcp image:

Build of Tags
any commit the semantic version, and sha-<short sha>
main + alpha
a release branch + beta
a tagged release commit + latest
a feature branch + latest-<label>

Entry pipelines run on imageRef: mcp:latest. The image is built in each customer's own ACR by their container pipeline, from the code version they pin.

Release steps

flowchart LR
    m["main<br/>(features merged)"] --> rb["1. Cut release/vX.Y"]
    rb --> v["2. Validate<br/>Demo + customer canary"]
    v --> g["3. Upgrade guide"]
    g --> t["4. Tag vX.Y.0"]
    t --> s["5. Sync to remotes"]
    s --> n["6. Release notes"]
    n --> c["7. Communicate"]

1. Cut the release branch

Create release/v<major>.<minor> from main when the features for the version are merged. From now on, only fixes go to this branch.

2. Validate

  1. Run container, then hub and spoke in Plan mode from the release branch against the Demo canary configuration, without changing the configuration. Expect no changes for existing resources (see Backwards compatibility).
  2. Apply on Demo canary and check the new features with their flags on.
  3. Plan against at least one customer canary. Note every manual step you needed: those go in the upgrade guide.

Earlier releases used release-candidate tags (rc<version>, for example rc4.8.0) for this stage. Use one if you need a fixed reference for testing.

3. Write the upgrade guide

Write a version-specific upgrade guide when any customer action is needed beyond bumping the version: new required variables, files to delete or rename in the configuration repository, resources or policy assignments to remove in the Azure portal, migration flags to flip, or a required order of steps.

Use this structure:

# Version <X.Y>.x – release-specific upgrade steps

## From v<previous X.Y>.x

### <Step title>

1. What to change, with the exact file path in the configuration repository
1. What to remove or check in the Azure portal, with the scope
1. Commit and push

## Expected plan

- Layer <layer>: <what you should see>, e.g. "replace of azurerm_… is expected"

Add the guide to the platform upgrade guides, under a heading Version <X.Y>.x, and add a row to its summary table and to the table of manual steps in the release history. Existing guides are the best examples. For how readers use them, see What to do when a new version is released. If no guide exists for a version, nothing special is needed.

Write the guide from what you needed during validation (step 2), not from memory: every manual step on the Demo or customer canary is a step for every customer. Keep each step concrete (file path, name of the object, scope) and say which pipeline layout it applies to if it differs.

4. Tag the release

Tag the release commit v<major>.<minor>.<patch> on the release branch. The tagged build gets the latest image tag.

5. Sync to customer remotes

.github/workflows/trigger-sync.yaml runs on pushes to main, release/** and v* tags in xmms/xms-cloud-platform-code and calls xmms/xms-code-sync (sync-dispatcher.yaml). Check that the sync ran, and spot-check a customer remote for the new branch or tag (history of the branch updated, tag present). How the sync works, how targets are prepared and locked down, and what to check when it fails: Code synchronisation.

6. Write the release notes

Release notes tell the people who take the release what changed for them. They are not a change log of the code. Compare the new tag with the previous one, check the actual changes and not only the commit titles, and group what you find. Use the work items linked to the commits for detail. Leave out internal-only work.

# Release notes for version <version>

## New features
## Improvements
## Bug fixes
## Breaking changes
## Known issues

Link the upgrade guide from the release notes when there is one. Add a short entry for the version to the release history when it is a major or minor release, or when it needed manual steps. The conventions for the text are in Release note conventions.

7. Communicate

Send the release notes to the people who take the release:

  • Managed customers: the product owner of each customer, and the XMMS engineers who run those platforms. Until now this was done by e-mail from the product team, with the release notes attached.
  • Self-managed customers: the customer's platform team, through the channel agreed at hand-over (for example the release notes in the code repository they sync, plus a notice to their contact).

Release note conventions

The spoke canvas, when it was a separate product, kept a short and strict format for its release notes. The same conventions work for the platform notes, and they are a good base for a self-managed platform team that writes its own notes.

Rule Why
Write for the person who takes the release, in plain language The readers are product owners and engineers of the platform team, not the authors of the code
Say what changed for the user, not how it was built. No code references, no internal names Implementation details do not help the reader decide or act
Group related changes into one line Ten commits for one feature are one new feature
Keep every item short: one line, one change The notes must be scannable
Sort under New features, Improvements and Bug fixes Readers look first for what is new, then what is fixed
Name the version and the bump in the title, for example Spoke Canvas version 2.6.0 - Minor Release The reader sees at once how much to expect
Leave out a heading that has no items A patch release normally has only bug fixes
If you are unsure what a change does for the user, ask the author A wrong note is worse than a late one
Do not change files of the repository while you draft them Notes are output, not code. Review the draft and then publish it where your team keeps the notes

How to prepare the notes:

  1. Decide the version: take the number from the release plan, or derive it from the latest tag and the type of release (major, minor or patch).
  2. Make sure you are on the release branch and have fetched the latest tags.
  3. Find the latest release tag (v*) and compare it with the current head.
  4. Read the changes themselves. Titles and messages are a start, not the source.
  5. Draft the notes in the format below, in the voice of the examples.

A draft for a minor release of the spoke canvas looked like this. The items are short and describe a result:

# Spoke Canvas version 2.6.0 - Minor Release

## New features

- Support federated credentials using Workload Identity Federation
- Support checking out a different repository for spoke configuration

## Improvements

- Use server pool for approval job
- Create the Azure storage container for the Terraform state files if it does not exist

A patch release has only the sections that apply:

# Spoke Canvas version 2.8.2 - Patch Release

## Bug fixes

- Changes to `required_resource_access` for the spoke service principal are now ignored to prevent unnecessary updates

Let an assistant draft, and a person decide

The spoke canvas repository used a prompt for an AI assistant that produced the draft as a snippet in chat from the difference between the latest tag and main. This is a useful time saver, but the author still checks every item against the real change, and decides what is a breaking change or a known issue. Those two sections of the platform format need a human judgement.

Patch releases

  1. Fix on a branch from main, merge with +semver: patch.
  2. Cherry-pick the fix to each supported release/vX.Y branch (via a pull request to that branch).
  3. Validate on Demo canary from the release branch, and tag vX.Y.<patch+1>.
  4. Add a line to the release notes of that version, under Bug fixes, in the style of the release note conventions.

Release state today

Observed in the repositories on 15 October 2026:

Item State
Latest tags v4.12.2, v4.12.1, v4.12.0, v4.11.4
Release branches release/v4.9, release/v4.10, release/v4.11, release/v4.12
Reference configuration repository (XDEV) pins release/v4.11
Release notes Kept as notes up to v4.6.1; the overview page of those notes says "current stable v4.4.0" (out of date). Condensed in the release history. No notes exist for v4.7 and later
Upgrade guides Up to v4.12.x, in Platform upgrade guides