Build versioning
Every CI run on a release line stamps a version into app.json and claims a build/<version> branch
for it. This page explains how the four version parts are decided, why the build number no longer
restarts after a version bump, and what a release pipeline reproduces from it.
The versioning work is done by the Stamp Build Version
task (Invoke-BcBuildVersionStamp), driven by the shared CI and CD templates in
businessdev.BC.Pipeline (yaml/v2/ci.yml, yaml/v2/cd.yml).
How the version is built
The version is expressed as a token schema. The CI uses major.minor.increment.0:
| Part | Where it comes from |
|---|---|
| Major | app.json (unchanged) |
| Minor | app.json (unchanged) |
| Build | the build number - seeded from the highest build/* branch, then incremented |
| Revision | 0 in CI; the pipeline build id in a CD release |
A version is only stamped - and only then is a build/<version> branch claimed and a package
published - on the release lines dev and hotfix/*. Every other run (feature/*, PR validation,
schedule) builds and tests without a version, without a build branch and without a package.
The build/<version> branch is the carrier: it is what a later run reads the already-claimed build
number back from, and it is what makes two parallel builds compute different versions.
The build number runs across version bumps
Seeding the counter from the highest build/<Major>.<Minor>.* branch of the current Major.Minor
line has a consequence that only shows up when the version is raised: the new line has no build branch
yet, so the counter starts at 1 again.
Code
While Major.Minor moves with every release that is merely untidy. It becomes a real problem when
Major.Minor stays put: the freshly built version then lands below the version customers already
have installed, and the app can no longer be upgraded.
Code
continuousBuildNumber fixes this. With it enabled the build number is derived from the highest build
branch of the whole repository, across all lines, while Major and Minor still come from app.json:
Code
| Setting | Value | Effect |
|---|---|---|
continuousBuildNumber (CI template parameter) | true (default) | Build number runs on across all build/* branches of the repository |
continuousBuildNumber | false | Old behaviour: the counter restarts per <Major>.<Minor> line |
-ContinuousBuildNumber (Invoke-BcBuildVersionStamp) | switch | Same option at cmdlet level, for a local or hand-written pipeline |
A product that wants its build number to restart with every release line sets it in its own root
ci.yml:
Code
Requires StampBuildVersion 0.2 / module 2.59.0
The CI template passes the continuousBuildNumber input to StampBuildVersion@0, which needs task
version 0.2 of the ALbuild Azure DevOps extension and module 2.59.0 or later.
One-time seeding after the migration from the old pipeline
The counter can only run on as high as a build branch already says it is. A repository whose earlier
versions were produced without build branches therefore needs a single build/<version> branch at
the height it had already reached, otherwise the first v2 build starts under the shipped version.
What the CD does not change
The release pipeline is deliberately untouched by this. It takes the version the CI assigned from the
build branch of its own release line - schema latest.latest.latest.build-id, which reads the
highest build/<Major>.<Minor>.* branch and sets the fourth part to the build id:
Code
That scoping is intentional: a release must reproduce the exact version its CI validated, not the
tallest number somewhere else in the repository. The latest token enables
seedFromBuildBranch automatically, and the read is read-only on the remote - a release never claims
a build branch.
| Pipeline | Build number scope | Reason |
|---|---|---|
CI (StampBuildVersion with continuousBuildNumber) | highest build branch of the repository | the number only has to keep rising |
CD (seedFromBuildBranch) | highest build branch of its own <Major>.<Minor> line | the release must match what CI tested |
Related
- Stamp Build Version task inputs - schema tokens,
seedFromBuildBranch, output variables. - Code coverage & test quality - the coverage granularity the CI captures per test codeunit.
- Invoke-BcBuildVersionStamp - the cmdlet behind the task.
