Repository navigation
Releasing
Releases are cut by merging pull requests. Nothing is tagged or published by hand.
The Release workflow (.github/workflows/release.yml) runs on every merge into main and releases whatever the PR changed:
| The PR… | On merge |
|---|---|
has a release:* label |
the CLI is released |
| changes the extension package | the extension is published to the Marketplace |
| does both | the CLI is released first, then the extension is published |
| does neither | nothing is released |
Either way, the PR gets a comment saying what was released, or what failed.
Before merging a PR, label it with exactly one of:
| Label | Bump | For |
|---|---|---|
release:patch |
v1.2.3 → v1.2.4
|
fixes |
release:minor |
v1.2.3 → v1.3.0
|
new flags, task inputs, report fields |
release:major |
v1.2.3 → v2.0.0
|
anything a pipeline has to change for |
Merging it:
- works out the next version from the newest stable
vX.Y.Ztag - tags the merge commit, re-runs vet and tests on it, builds the Linux and Windows binaries, and publishes a GitHub Release marked latest, with notes listing the PRs merged since the previous release
- updates the README's release badge
A PR without a label releases no CLI, so several PRs can land and go out together under the next labelled one.
No label is needed. If a merged PR changed anything that goes into the extension package, the extension is published:
-
extension/tab/,extension/images/and the task folders underextension/tasks/ -
extension/vss-extension.jsonandextension/overview.md(the Marketplace listing) -
extension/package.jsonandpackage-lock.json
Changes to the extension's READMEs, tools/, dev/ and configs/ don't count, since none of them are packaged.
Order matters. When a PR releases both, the extension waits for the CLI release, because the install task installs the newest stable release: tasks must never reach agents before the binary they install. If the CLI release fails, the extension is not published.
Version. The extension's version is independent of the CLI's: 0.<minor>.<patch>, with the patch one past the newest version already on the Marketplace. The major stays 0 because pipelines reference the tasks as tf-snag@0. Bump the minor in extension/vss-extension.json for a deliberate step.
Visibility. The extension publishes privately, shared with the organisation in the ADO_ORG variable, until the repo variable EXTENSION_PUBLIC is set to true. The Marketplace only accepts public extensions from a verified publisher.
CI packages the extension on every PR exactly as a release would, so a manifest the Marketplace would reject fails before the merge.
Details, including the manual dev channel, are in the extension README.
Run Release from the Actions tab on main, and choose the CLI bump (or none) and whether to publish the extension.
To publish only the extension, or to the dev channel for testing before a merge, run Publish ADO extension instead.
Push a hyphenated tag by hand. CI builds it and publishes a GitHub pre-release; nothing goes to the Marketplace.
git tag v1.3.0-dev.1 && git push origin v1.3.0-dev.1A plain vX.Y.Z tag pushed by hand fails CI and publishes nothing, so every stable release goes through a PR. Delete one with git push origin :refs/tags/vX.Y.Z.
The README's release badge is a shields.io endpoint badge that reads tf-snag-release.json from a public gist, which the Release workflow rewrites after each CLI release. It needs the repo variable GIST_ID and the secret GIST_TOKEN, a fine-grained token with Gists: Read and write. Without GIST_ID the step is skipped.
Start here
How it works
Integrations
Project