| name | release-roslynator |
| description | Use when shipping a roslynator release, rolling CHANGELOG.md [Unreleased], updating the VS Code extension changelog, creating a GitHub v* release, or optionally tagging cli-v*. |
Release Roslynator
Overview
Four hard-gated steps: changelog PR → merge → GitHub release (v*) → optional CLI tag (cli-v*). Versions come from the user. GitVersion derives package versions from tags — do not hardcode in props.
Violating the letter of the gates is violating the spirit of the gates. Do not batch steps or confirm once for the whole release.
Prerequisites
- Analyzer/extension version (e.g.
4.17.0) — required. If missing: STOP. Do NOT proceed. Ask the user.
- CLI version (e.g.
0.15.0 / cli-v0.15.0) — only needed if Step 4 is confirmed.
- Today’s date for changelog headers (
YYYY-MM-DD).
Not for: day-to-day contributor work.
Hard gates
Before each step below: present what you will do, then use interactive confirmation (AskQuestion if available; otherwise ask and wait). Do not use markdown checkboxes.
STOP. Do NOT proceed to the next step until the user explicitly confirms the current step. Providing a CLI version does not skip Step 4 confirmation.
Quick Reference
| Step | Gate | Action |
|---|
| 1 | Confirm before push/PR | Changelog PR (root CHANGELOG.md + VS Code package/CHANGELOG.md) |
| 2 | Confirm before merge | Squash-merge PR; pull main |
| 3 | Confirm before create | GitHub release → creates vX.Y.Z; title same as tag (vX.Y.Z) |
| 4 | Opt-in only | Optional cli-v* tag on a real commit; push |
CI / GitVersion details: references/release-and-ci.md.
Step 1 — Changelog PR
STOP until user confirms Step 1.
- Branch from latest
main (e.g. release/X.Y.Z).
- Root
CHANGELOG.md: under ## [Unreleased], insert ## [X.Y.Z] - YYYY-MM-DD so prior Unreleased bullets become that version’s section (same pattern as bump PR #1785). Leave [Unreleased] empty above it.
src/VisualStudioCode/package/CHANGELOG.md: copy that new version section (header + body) under [Unreleased].
- Commit, push, open PR — title
Bump version to X.Y.Z.
STOP. Wait for Step 2 confirmation.
Step 2 — Merge
STOP until user confirms Step 2.
Squash-merge the bump PR (after CI is acceptable to the user):
gh pr merge <PR_NUMBER> --squash
Pull latest main. Note the squash commit SHA on main.
STOP. Wait for Step 3 confirmation.
Step 3 — GitHub release
STOP until user confirms Step 3.
Create the analyzer/extension release (this creates/pushes tag vX.Y.Z and triggers publish CI):
- Tag:
vX.Y.Z
- Title:
vX.Y.Z (same as tag, with v prefix)
- Notes: body of
## [X.Y.Z] from root CHANGELOG.md (sections under that header, not the heading line alone)
- Target: squash commit on
main (or main after pull)
Example:
gh release create "vX.Y.Z" --title "vX.Y.Z" --notes "..." --target "<sha-or-main>"
STOP. Wait for Step 4 confirmation (or user declines CLI tagging).
Step 4 — Optional CLI tag
STOP until user opts in. If they decline, the release workflow ends here.
If yes (CLI version required — ask if missing):
git checkout main && git pull origin main
- Tag
cli-vA.B.C on a real commit (same commit as vX.Y.Z unless the user specifies otherwise)
git push origin cli-vA.B.C
- Verify both
v* and cli-v* resolve to commits (git rev-parse, git ls-remote)
Do not amend published tags.
Common Mistakes
| Mistake | Fix |
|---|
Title 4.17.0 without v | Title matches tag: v4.17.0 |
| Tag CLI because version was in the prompt | Step 4 is opt-in; still ask |
| Merge + release + CLI in one go | Four separate STOPs |
| Soft “ask later” while editing/pushing | Confirm before push/PR, merge, gh release create, CLI tag push |
| Same tag for CLI and analyzers | v* vs cli-v* |
| Amend published tag | New tag instead |
| Hardcode version in props | GitVersion + tags |