-
Notifications
You must be signed in to change notification settings - Fork 20
chore(release): add release tools to mage #254
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| # Changelog | ||
|
|
||
| <!-- markdownlint-disable-file MD013 MD024 --> | ||
|
|
||
| All notable changes to `azldev` are documented in this file. | ||
|
|
||
| The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), | ||
| and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||
|
|
||
| ## [0.1.0] - 2026-03-18 | ||
|
|
||
| First tagged preview release of `azldev`, the developer CLI for the | ||
| [Azure Linux](https://github.com/microsoft/azurelinux) distro. | ||
|
|
||
| ### Added | ||
|
|
||
| - **Project and metadata management.** Scaffold a project with `azldev project | ||
| init` or `project new`, then parse, resolve, and query the TOML metadata | ||
| (`azldev.toml`) that defines Azure Linux. Configuration merges built-in | ||
| defaults with project and user-level (XDG) files, is fully validated, and is | ||
| published as a JSON Schema via `azldev config generate-schema`. | ||
| - **Component inspection and locking.** List and inspect components with `azldev | ||
| component list` and `component query`, and import new ones with `component | ||
| add`. Deterministic component fingerprints and per-component lock files keep | ||
| builds reproducible; `component update` refreshes them with `--check-only`, | ||
| `--bump`, freshness-based skipping, a progress bar, and upstream-staleness | ||
| detection. `component changed` and `component diff-sources` report what moved. | ||
| - **Source preparation and spec rendering.** `component prepare-sources` and | ||
| `component render` produce build-ready sources and specs through a | ||
| `mock`-based batch pipeline, synthesizing the git history that `rpmautospec` | ||
| needs and constructing dist-git from lock-file history. A rich overlay system | ||
| (spec search/replace, prepend/append lines, remove section or subpackage, file | ||
| and source replacement, per-file overlay files, and inline metadata) | ||
| customizes specs, with explicit release-calculation modes (`autorelease`, | ||
| `static`, and automatic). Source archives are fetched from lookaside caches. | ||
| - **Local package and image builds.** Build individual packages with `mock` | ||
| using `component build`, emitting RPMs and SRPMs into structured, | ||
| publish-channel-aware output directories. `azldev image` builds, customizes, | ||
| injects files into, boots, and runs LISA tests against Azure Linux images on a | ||
| local QEMU VM. | ||
| - **Package and repository queries.** Inspect binary package configuration with | ||
| `azldev package list` (including `--rpm-file`, debug-package synthesis, and | ||
| separate package/component group columns), and inspect or manage RPM | ||
| repositories with `azldev repo query`, backed by repo resources and repo-set | ||
| templates. | ||
| - **Command-line experience.** Shell completions for bash, zsh, fish, and | ||
| PowerShell; actionable hints on errors; global `--quiet`, `--verbose`, and | ||
| `--dry-run` flags with `table`, `json`, `csv`, and `markdown` output formats; | ||
| an embedded MCP server (`azldev advanced mcp`); and auto-generated CLI | ||
| reference documentation. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| # Copyright (c) Microsoft Corporation. | ||
| # Licensed under the MIT License. | ||
| # | ||
| # git-cliff configuration for generating azldev's CHANGELOG.md from Conventional | ||
| # Commits. Run it via `mage changelog`; see docs/developer/how-to/releasing.md. | ||
| # Reference: https://git-cliff.org | ||
| # | ||
| # The generated entries are a *draft*: a human (or Copilot) prunes and rewords | ||
| # them into user-facing notes before a release. Internal commit types (docs, | ||
| # test, chore, build, ci, style, refactor, and dependency bumps) are skipped so | ||
| # the draft starts close to user-facing. | ||
|
|
||
| [changelog] | ||
| # The markdownlint-disable-file comment scopes two relaxations to CHANGELOG.md | ||
| # only (no repo-wide markdownlint config): MD013 because auto-generated entries | ||
| # are one line per commit and can exceed the line length, and MD024 because the | ||
| # Keep a Changelog format repeats '### Added'/'### Fixed' under every version. | ||
| header = """ | ||
| # Changelog | ||
|
|
||
| <!-- markdownlint-disable-file MD013 MD024 --> | ||
|
|
||
| All notable changes to `azldev` are documented in this file. | ||
|
|
||
| The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), | ||
| and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||
| """ | ||
| # Per-version section in Keep a Changelog style. `version` is unset when | ||
| # rendering unreleased commits, which yields an `## [Unreleased]` heading. The | ||
| # leading blank line keeps a blank line above each version heading (markdownlint | ||
| # MD022) when the section is prepended below the file header or another version. | ||
| body = """ | ||
|
|
||
| {% if version %}\ | ||
| ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} | ||
| {% else %}\ | ||
| ## [Unreleased] | ||
| {% endif %}\ | ||
| {% for group, commits in commits | group_by(attribute="group") %} | ||
| ### {{ group | striptags | trim | upper_first }} | ||
| {% for commit in commits %} | ||
| - {{ commit.message | split(pat="\n") | first | upper_first | trim }}\ | ||
| {% endfor %} | ||
| {% endfor %}\ | ||
| """ | ||
| # Collapse any run of 3+ newlines left by the template into a single blank line | ||
| # so the rendered changelog has no double blank lines (markdownlint MD012). | ||
| postprocessors = [{ pattern = '\n{3,}', replace = "\n\n" }] | ||
| trim = true | ||
| footer = "" | ||
|
|
||
| [git] | ||
| conventional_commits = true | ||
| # Keep non-conventional commits (e.g. early "README.md committed" bootstrap | ||
| # commits) instead of treating them as parse errors. They fall through to the | ||
| # catch-all `.*` skip parser below, so they're dropped quietly rather than | ||
| # emitting a "commit(s) skipped due to parse error(s)" warning during the | ||
| # full-history version bump. | ||
| filter_unconventional = false | ||
| # Drop commits that don't match a kept parser below (cuts internal noise). | ||
| filter_commits = true | ||
| # ...but never drop a breaking change, even if its type is skipped above. | ||
| protect_breaking_commits = true | ||
| # Only consider release tags of the form `vX.Y.Z`. | ||
| tag_pattern = '^v[0-9]+\.[0-9]+\.[0-9]+$' | ||
| sort_commits = "oldest" | ||
| commit_parsers = [ | ||
| { message = "^feat", group = "Added" }, | ||
| { message = "^fix", group = "Fixed" }, | ||
| { message = "^perf", group = "Changed" }, | ||
| { message = "^revert", group = "Removed" }, | ||
| { message = "^refactor", skip = true }, | ||
| { message = "^docs", skip = true }, | ||
| { message = "^test", skip = true }, | ||
| { message = "^chore", skip = true }, | ||
| { message = "^build", skip = true }, | ||
| { message = "^ci", skip = true }, | ||
| { message = "^style", skip = true }, | ||
| # Skip anything that didn't match a kept type above. | ||
| { message = ".*", skip = true }, | ||
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,143 @@ | ||
| # How to: cut a release | ||
|
|
||
| This guide covers releasing the `azldev` Go module so that | ||
| `go install ...@version` and the [pkg.go.dev][pkgsite] reference page work. | ||
|
|
||
| ## TL;DR | ||
|
|
||
| ```console | ||
| # One-time: install the changelog generator (git-cliff) | ||
| cargo binstall git-cliff # or: cargo install git-cliff --locked, or: brew install git-cliff | ||
|
|
||
| # 1. Draft the changelog, curate it into user-facing notes, then PR + merge to main | ||
| mage changelog # prepends a draft ## [X.Y.Z] section to CHANGELOG.md | ||
|
|
||
| # 2. Tag the release from the changelog version, then publish by pushing the tag | ||
| mage release # creates annotated tag vX.Y.Z on HEAD (does not push) | ||
|
|
||
| # Undo a local tag created by mistake (before pushing) | ||
| git tag -d vX.Y.Z | ||
|
|
||
| git push origin vX.Y.Z # pushing the tag is what publishes the release | ||
| ``` | ||
|
|
||
| Each step is explained in full under [Cut a release](#cut-a-release) below. | ||
|
|
||
| ## Versioning policy | ||
|
|
||
| We follow [Semantic Versioning][semver] with a `v` prefix on tags | ||
| (`vMAJOR.MINOR.PATCH`). | ||
|
|
||
| * **`v0.x.y` (current).** The pre-1.0 phase: the CLI and any exported Go API may | ||
| change in breaking ways on a *minor* bump. Use this while the surface is still | ||
| settling. | ||
| * **`v1.0.0` and later.** Commits to SemVer stability: breaking changes require a | ||
| major bump. | ||
| * **Major versions `>= 2`** require a `/vN` suffix on the module path | ||
| (e.g. `github.com/microsoft/azure-linux-dev-tools/v2`). Staying on `v0`/`v1` | ||
| avoids that. Don't cut a `v2.0.0` tag without first updating the module path. | ||
|
|
||
| ## How publishing actually works | ||
|
|
||
| There is no separate "upload" step. The public [Go module proxy][proxy] and | ||
| pkg.go.dev fetch directly from this repository's Git tags: | ||
|
|
||
| * `go install .../cmd/azldev@vX.Y.Z` resolves the tag through the proxy. | ||
| * `azldev version` reports the right version automatically for proxy installs — | ||
| Go embeds the module version into the binary's build info. | ||
| * pkg.go.dev renders the package doc comments plus this repo's `README.md`. Our | ||
| `LICENSE` (MIT) marks the module redistributable so docs are shown. Only the | ||
| public `cmd/` and `pkg/` packages appear; `internal/` is hidden by design. | ||
|
|
||
| ## Cut a release | ||
|
|
||
| 1. Make sure `main` is green and up to date locally. | ||
|
|
||
| 2. Generate and curate the changelog. Run `mage changelog` to prepend a draft | ||
| section for the next version to [`CHANGELOG.md`](../../../CHANGELOG.md), then | ||
| edit it down into user-facing notes. See [Changelog](#changelog) below. | ||
|
|
||
| 3. Tag the release. Once the changelog change is on `main`, run `mage release`: | ||
| it reads the version from the top `## [X.Y.Z]` heading in | ||
| [`CHANGELOG.md`](../../../CHANGELOG.md) and creates a matching annotated tag | ||
| (`vX.Y.Z`), so the tag and the changelog can't disagree. Then push the tag: | ||
|
|
||
| ```console | ||
| mage release | ||
| git push origin vX.Y.Z | ||
| ``` | ||
|
|
||
| `mage release` creates the tag locally but never pushes — pushing the tag is | ||
| what publishes the release. The version lives only in the git tag (there is no | ||
| version file); `azldev version` reads it from the build. To sign the tag, | ||
| create it manually with `git tag -s` instead. | ||
|
|
||
| `mage release` is idempotent: if that version is already tagged it does | ||
| nothing, so the same command is safe to automate on every merge to `main`. | ||
|
|
||
| 4. Warm the proxy and pkg.go.dev so the new version is discoverable promptly. | ||
| This is harmless and only triggers indexing of an already-public tag: | ||
|
|
||
| ```console | ||
| GOPROXY=https://proxy.golang.org go list \ | ||
| -m github.com/microsoft/azure-linux-dev-tools@v0.1.1 | ||
| ``` | ||
|
|
||
| Then visit | ||
| `https://pkg.go.dev/github.com/microsoft/azure-linux-dev-tools@v0.1.1` once to | ||
| prompt the docs build. | ||
|
|
||
| 5. (Optional, recommended) Create a GitHub Release for the tag and paste the new | ||
| `CHANGELOG.md` section as the release notes. A GitHub Release is separate from | ||
| the Git tag, so you can add notes even to a tag that already exists. | ||
|
|
||
| ## Changelog | ||
|
|
||
| [`CHANGELOG.md`](../../../CHANGELOG.md) at the repo root follows the | ||
| [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format. New sections are | ||
| drafted from the Conventional Commit history with | ||
| [git-cliff](https://git-cliff.org) and then curated by hand. Generate a draft | ||
| with: | ||
|
|
||
| ```console | ||
| mage changelog | ||
| ``` | ||
|
|
||
| This prepends a `## [X.Y.Z]` section (the version is inferred from the commits) | ||
| above the previous release, skipping internal commit types — docs, test, chore, | ||
| build, ci, style, refactor, and dependency bumps — per | ||
| [`cliff.toml`](../../../cliff.toml). The result is a **draft**: git-cliff emits | ||
| commit subjects, not release prose, so prune and reword the entries into | ||
| user-facing notes before committing. | ||
|
|
||
| `mage changelog` is the single changelog flow — it runs identically locally and | ||
| in CI (CI just installs git-cliff first), so there is nothing to keep in sync | ||
| between the two. It needs git-cliff on your `PATH`; the version is pinned in | ||
| [`tools/git-cliff/Cargo.toml`](../../../tools/git-cliff/Cargo.toml) so Dependabot | ||
| and security scanners track it. Install it once: | ||
|
|
||
| ```console | ||
| cargo binstall git-cliff # or: cargo install git-cliff --locked, or: brew install git-cliff | ||
| ``` | ||
|
|
||
| > Tip: the generated draft is a natural place to let Copilot help rewrite commit | ||
| > subjects into concise, user-facing notes before you commit. | ||
|
|
||
| ## Fixing a bad release | ||
|
|
||
| Proxy versions are immutable — you cannot delete or move a published version. | ||
| To withdraw one, [retract][retract] it: add a `retract` directive to `go.mod` | ||
| describing the bad version(s) and release a new patch. `go get` will then skip | ||
| the retracted versions. | ||
|
|
||
| ```go | ||
| // in go.mod | ||
| retract ( | ||
| v0.1.1 // contains a build-breaking bug; use v0.1.2. | ||
| ) | ||
| ``` | ||
|
|
||
| [pkgsite]: https://pkg.go.dev/github.com/microsoft/azure-linux-dev-tools | ||
| [semver]: https://semver.org/ | ||
| [proxy]: https://proxy.golang.org/ | ||
| [retract]: https://go.dev/ref/mod#go-mod-file-retract |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Were this file's contents actually generated by
git cliff? They look more massaged than that. Won't they get overwritten when git cliff gets run?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it will leave hand-edited content alone.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did just update with a linter directive though.