Versioning the Templates¶
Workload teams must decide when they upgrade to a new version of a module. Therefore the library is versioned, and every release is a tag that a team can pin. The decision is in Decision summaries.
One version per module¶
Each module has its own version line, with semantic versioning (MAJOR.MINOR.PATCH). A git tag
holds the technology, the module name and the version, for example bicep/storage_account/1.0.1 or
terraform/storage_account/1.1.0.
| Option | Why it was not chosen |
|---|---|
| One version for the whole solution | The number is misleading for a team that uses only some modules, or only Bicep or only Terraform. |
| One version per technology (Bicep, Terraform) | Still misleading: a change in one module bumps the version of all. |
| One version per module | Chosen. The number says something about the module a team really uses. The release process is more complex. |
The strategy was chosen with limited experience of mixed Terraform and Bicep libraries in one repository, and it is tested in practice.
Tags¶
| Technology | Git tag | How a consumer refers to it |
|---|---|---|
| Terraform | terraform/<module>/<version> |
The full tag name as ref in the module source |
| Bicep | bicep/<module>/<version> |
Only the version number, in the registry reference .../modules/bicep/<module>:<version> |
Both ways are shown in Reference a module. The tags are listed in the repository, and in the read-only copy of the consumer. To read the documentation of a version, switch to its tag first.
Who changes which number¶
The process is semi-automatic:
| Part | Who changes it | How |
|---|---|---|
MAJOR and MINOR |
The contributor | By hand, in the version.json file of the module |
PATCH |
The release pipeline | Automatic: the pipeline sets the number and creates the tag when required |
The version.json file has two properties: version (the MAJOR.MINOR number) and pathFilters (the files that count). The
version of a module changes when a file that the filter selects changes in the merged commit, or when version.json itself
changes. A change outside the module (for example in the pipelines) does not bump it. Documentation-only changes do not either.
| Technology | Files that trigger a release |
|---|---|
| Terraform | The .tf files directly in the module folder (not in subfolders), and version.json |
| Bicep | The compiled main.json, and version.json. The main.json is generated from main.bicep by the documentation job, so a change of the Bicep code reaches a release through it. |
The PATCH number is calculated: it starts at 0 when MAJOR.MINOR changed, and otherwise it is the highest existing patch
number for that MAJOR.MINOR plus one. A tag that already exists for the commit is not created again.
The pipeline must run from the main branch, and changes must reach main through a squash commit, so that the changes
since the previous commit can be read as one change (Release and documentation).
When to change what¶
| Change | Number |
|---|---|
| A fix that does not change the interface | PATCH (automatic) |
| A new optional parameter or output | MINOR |
| A change that breaks existing calls: a removed or renamed parameter, a changed default that changes the behaviour, a new fixed value that is not compatible | MAJOR |
This table applies the rules of semantic versioning to a module. The same principles as for the platform itself apply: announce a change of a default before you make it (Backwards compatibility).
Changes that were a MAJOR change in practice:
- A setting that a policy requires became enforced, so its parameter was removed (for example
enableAllLogsin diagnostics). - A default changed to the compliant value (for example public network access of the Bicep storage account module).
- A module switched to another provider resource, or changed the shape of an object parameter.
The changelog¶
Each module has its own changelog file (CHANGELOG.md in the module folder), so a team can see what changed between two
versions without reading the whole history of the repository. A line in the changelog is part of every change that changes
the version. An entry has the version, a link that compares it with the previous tag, the date, and the headings
Features and Bug Fixes. A Known limitations heading is used when a release has a caveat the team should know before
upgrading, for example a provider that needs a second run after the update. The pull request template of the repository asks
for the changelog, for the version file when MAJOR or MINOR changes, and for tests of a new module.
Upgrade notes¶
A module with a breaking change can have upgrade notes in its upgrade/ folder, one file per major version
(notes-v<major>.md). They list the steps for your code, and for the Terraform state where needed. Read them before you
change the tag, and test the upgrade in dev first.
| Module | Technology | Major version | What changes for you |
|---|---|---|---|
storage_account |
Terraform | 1 | Object parameters for queue properties and static websites become maps. The single Data Lake Gen2 file system becomes a map of file systems. |
storage_account |
Bicep | 1 | Public network access is disabled by default. Network rules default to deny, with the Azure services bypass. Set publicNetworkAccess explicitly when you relied on the old behaviour. |
sql_server |
Bicep | 1 | Availability zone values become integers. The enableAllLogs and enableAllMetrics diagnostic properties are removed. The key parameters become a customerManagedKey object. The identity parameter is renamed. The system-assigned identity property is removed because it is enforced. |
container_registry |
Terraform | 1 | retention_policy becomes retention_policy_in_days. The enable_allLogs and enable_allMetrics diagnostic properties are removed. |
network_security_group |
Terraform and Bicep | 1 | The flow log parameter is removed, because flow logs are no longer supported on this level. In Terraform the diagnostic setting parameter is renamed, and a plan shows the move. In Bicep the log categories are enforced and the parameter is removed. |
postgresql_flexibleserver |
Terraform | 1 | The customer-managed key object is replaced by key and identity IDs, including those for the geo backup. |
container_app |
Terraform | 1 | The module moves from azurerm_container_app to the azapi provider. Declare azapi, review the state moves in the plan, rename some variables (timeouts, custom domains, IP restrictions). |
container_app |
Terraform | 2 | The module owns its resource logic instead of wrapping another module. Inputs and outputs are unchanged. The plan shows moves, and the first apply can fail with an inconsistent result error that a second apply resolves. |
The table is a summary. The notes in the module folder are the source.
What a consuming team does¶
The team pins a tag in the module call, and moves the tag when it has read the changelog and tested the new version (Use Managed Templates). The module also declares the provider versions it supports: a module that still limits a provider to an older major version blocks an upgrade of the provider in the team's own code (Provider versions). A bot can propose new versions for you (Keep modules up to date).