Release workflow
This page describes how a new FL-Net version is released
All FL-Net repositories containing components of either the Client or the Platform share one version and are released together. A Client running 1.0.0 therefore runs 1.0.0 images of every local server component.
Version scheme
A version has one of two forms:
| Version | Meaning | Branch | Example |
|---|---|---|---|
X.Y.Z.dev | Work in progress towards X.Y.Z | develop | 1.1.0.dev |
X.Y.Z | Release | main | 1.1.0 |
The order is 1.1.0.dev < 1.1.0 < 1.1.1 < 1.2.0.dev.
Pick the next number like this:
- Major
X: incompatible changes, for example when Clients and Platforms of different major versions can no longer work together. - Minor
Y: new features. This is the usual step after a release, e.g.1.0.0→1.1.0.dev. - Patch
Z: bug fixes only, typically a hotfix onmain.
Where the version is stored
Each repository stores the version in the place specific for the programming language used by the repository, e.g. pom.xml for Java, package.json for Node.js.
To release a new version each repository contains the .github/scripts/version.sh script which is a helper to easily set the version in the right place as this differs per repo.
The CI/CD then automatically applies validation and creates concrete realeases.
What CI does automatically
On every push to main or develop, the image workflows (docker.yml, in the CLI release.yml) first run the shared actions/version. That step checks the version and decides what gets published:
| Version on the branch | Image tags | Git tag and GitHub release |
|---|---|---|
develop, X.Y.Z.dev | staging, X.Y.Z.dev (both move with every build) | none |
main, X.Y.Z, first build | latest, X.Y.Z (Learning-APIs also prod) | tag X.Y.Z, release |
main, X.Y.Z that already has a tag | only latest, plus a warning | none |
Releases are published once and then stay fixed. As long as the version is not raised, later builds keep updating latest, but X.Y.Z keeps pointing to the build that was released. To publish fixes, raise the (patch) version, see Hotfix.
The CI also:
- Writes the release notes: the GitHub release lists the pull requests merged since the previous tag.
- Cleans up the registry every Monday (Image cleanup workflow, shared from FedLearnNet/.github): images without any tag left, i.e. old builds that
staging,latestor a.devtag moved away from, are deleted. Released versions keep their tag and are never deleted. - Labels the images with
org.opencontainers.image.versionand the commit inorg.opencontainers.image.revision, sodocker inspectshows what a running container was built from. - Guards the branches:
- The Version workflow runs on every pull request into
mainordevelop. mainonly takes a release versionX.Y.Zthat has no tag yet.developonly takesX.Y.Z.dev. A release version would publish the staging build under the release tag.- A push that breaks these rules fails the image workflow.
- The Version workflow runs on every pull request into
What stays manual: choosing and setting the version number, opening the pull requests that change it, and testing develop on staging before a release.
The version at runtime
- Both learning APIs report their version at
GET /info, publicly, as it contains nothing secret. The Local Learning API also asks the Platform for its version and caches the answer for a day. If the Platform is not reachable,globalVersionstays empty and the next call asks again. It returnsglobalVersionNewer: trueif the Platform runs a newer version, plusglobalWebUrl, the address of the Platform frontend. - The Client and Platform frontends show the version in the footer. Both load it right at the start, before the login, and show a one-line skeleton until it arrives. The Client frontend adds a hint when the Platform is newer.
- The Orchestration API starts the Tool-Build-Pipeline image of its own version (
pipeline.image-tag, default: its version). The tag sent by the Global API is ignored. For a locally built pipeline image, setPIPELINE_IMAGE_TAG.
Releasing step by step
The examples release 1.1.0; replace the numbers with yours. Do every step in all repositories listed above, so the whole network stays on the same version.
1. Develop
develop carries 1.1.0.dev. Nothing to do: features are merged as described in the Development workflow, and every build is published as staging and 1.1.0.dev.
2. Release
When develop passes the tests on staging:
- Create a branch
release/1.1.0fromdevelop. - Run
.github/scripts/version.sh set 1.1.0and commit. - Open a pull request into
main. The Version check confirms that1.1.0is not released yet. - Merge it.
The CI publishes the 1.1.0 and latest images, the tag 1.1.0 and the GitHub release. Check the generated release notes on GitHub and complete them if needed.
3. Back to develop
Start the next version on develop, so it also contains the release commit:
- Create a branch from
develop, e.g.chore/1.2.0.dev. - Merge
maininto it (git merge origin/main). - Run
.github/scripts/version.sh set 1.2.0.devand commit. - Open a pull request into
developand merge it.
Until this is done, develop still carries 1.1.0.dev. That is fine, it just keeps updating staging.
Hotfix
A bug in a release (1.1.0) that cannot wait for the next one can be fixed by just updating the patch version of the relevant repository and not updating all repositories:
- Create a branch
hotfix/1.1.1frommain. - Fix the bug, run
.github/scripts/version.sh set 1.1.1and commit. - Open a pull request into
mainand merge it. The CI publishes1.1.1like a release. - Bring the fix to
develop: mergemaininto a branch fromdevelopand open a pull request. If the version line conflicts, keep the version ofdevelop.
Please do this with ALL repositiories. For repositories without any changes you can create a new branch from main, change the version and then merge it back into main.
The CLI deploys with all services using the tag of the version the CLI uses. E.g. CLI of 1.1.1 deploys orch-api:1.1.1, local-learning-api:1.1.1, global-learning-api:1.1.1, etc.
Troubleshooting
develop takes X.Y.Z.dev: a release version reached develop, usually by merging main without step 3. Set the next .dev version.
main only takes release versions: the pull request into main still carries a .dev version. Release via a release/X.Y.Z branch as in step 2.
X.Y.Z is already released. Raise the version: there is already a tag for this version. Use the next patch version for a fix.
Warning … was already released from <sha>: changes reached the branch without a new version. They are published as staging/latest, but not under the version tag. Raise the version to publish them.
A wrong release was published: don't move the tag. Publish the next patch version instead, e.g. 1.1.1. Deleting a GitHub release and its tag lets the next build publish the same version again, which may confuse deployments that already pulled it.