CtrlK
BlogDocsLog inGet started
Tessl Logo
SkillPublic

release

Orchestrate an MSBuild release: create the tracking issue, branch, configure DARC channels and subscriptions, bump version in main, final-brand the release branch, insert into VS, and publish post-GA. Covers the full monthly release lifecycle aligned with VS shipping cadence.

Quality

80%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Medium

Suggest reviewing before use

Fix and improve this skill with Tessl

tessl review fix ./.github/skills/release/SKILL.md
SKILL.md
Quality
Evals
Security

MSBuild Release Orchestration

This skill guides an agent through the MSBuild release process defined in documentation/release-checklist.md. The checklist is the single source of truth — this skill provides context on how to execute it.

Overview

MSBuild is a component that gets inserted into Visual Studio. VS ships monthly; MSBuild must branch and prepare its bits before VS is ready to take them. See the release process doc for the full timeline diagram.

The insertion pipeline routes MSBuild branches to VS branches:

  • main → VS main (daily canary)
  • vs* release branch → VS main (replaces main → main after branch snap)

VS handles the progression from main → rel/insiders → rel/stable on its own schedule. MSBuild's responsibility is to have final-branded bits in VS main before the insiders snap date.

Each monthly VS release produces:

  • A new vs* branch from main
  • Final branding on that branch
  • A version bump in main
  • DARC channel/subscription updates
  • A VS insertion
  • Post-GA publishing to nuget.org and docs

The process is organized into 6 timeline-gated phases (0–5), each with an explicit trigger.

Execution model: This skill is designed for an interactive Copilot session. The agent walks through each phase step-by-step, but every command that modifies state (git push, DARC writes, pipeline changes, PR creation) requires user approval before execution. Read-only queries (DARC get-*, git log, etc.) can run without approval.

Required Inputs

Before starting any phase, ensure you have these values (the user must provide them — version increments are irregular and cannot be computed):

InputExampleHow to determine
PREVIOUS_RELEASE_VERSION18.9Previous release branch version: the highest vs* version lower than THIS_RELEASE_VERSION (list candidates with git branch -r --list 'origin/vs*').
PREVIOUS_RELEASE_EXACT_VERSION18.9.6The version the previous release actually shipped as. From the previous release's tracking issue, or git tag --list 'v18.9.*'. Used by Phase 5.3a.
THIS_RELEASE_VERSION18.10Current VersionPrefix in eng/Versions.props (drop .0)
NEXT_VERSION18.11User-provided — not computable from current version
BRANCH_SNAP_DATEYYYY-MM-DDFrom VS-Dates wiki — when MSBuild branches vs* from main, insertion targets VS main
INSIDERS_SNAP_DATEYYYY-MM-DDFrom VS-Dates wiki — when VS snaps main → rel/insiders; final-branded bits must be in VS main before this
STABLE_SNAP_DATEYYYY-MM-DDFrom VS-Dates wiki — when VS promotes rel/insiders → rel/stable
VS_SHIP_DATEYYYY-MM-DDWhen VS ships publicly (GA) — triggers post-release tasks
PACKAGE_VALIDATION_BASELINE_VERSION18.10.0-1.26378.2See How to determine PACKAGE_VALIDATION_BASELINE_VERSION below — non-trivial: most "obvious" picks are wrong.

Version examples above track the current cycle (eng/Versions.props VersionPrefix is 18.10.0). Dates are intentionally shown as a format only — always read the real ones from the VS-Dates wiki.

How to determine PACKAGE_VALIDATION_BASELINE_VERSION

The value is the latest {{THIS_RELEASE_VERSION}}.0-<label>.<shortDate>.<rev> MSBuild package that is both:

<label> is PreReleaseVersionLabel from eng/Versions.props (currently 1), so the versions look like 18.11.0-1.26426.2. Do not assume the legacy -preview-NNNNN-NN shape — MSBuild no longer produces it.

  1. Published on the public dotnet-tools feed — this is the feed the official build publishes to and that ApiCompat restores baselines from. If the version isn't here, ApiCompat fails with NU1102.
  2. Produced from a commit reachable from vs{{THIS_RELEASE_VERSION}} — i.e. a commit on vs{{THIS_RELEASE_VERSION}}, or the main commit vs{{THIS_RELEASE_VERSION}} was branched from.

Two tempting wrong answers — and why they're wrong:

Wrong pickWhy it fails
❌ The release-versioned {{THIS_RELEASE_VERSION}}.X package that ships in VS / on nuget.orgSince #14277 release branches build and insert prerelease versions, exactly like main; the release-versioned variants are produced by NuGetRepack at manual publish time. They never exist on the public CI feed, so ApiCompat cannot restore them.
❌ Blindly the most recent {{THIS_RELEASE_VERSION}}.0-* on dotnet-toolsAfter vs{{THIS_RELEASE_VERSION}} branches, main keeps producing {{THIS_RELEASE_VERSION}}.0-* until this main-bump PR merges — so the most recent feed entries may be {{NEXT_VERSION}}-content builds wearing {{THIS_RELEASE_VERSION}} branding. Picking one drifts the API baseline forward and silently hides real compat breaks.

Timing caveat: the branch-point build publishes to dotnet-tools asynchronously. If you branch and bump on the same day, the script may report the correct candidate as [NOT on feed] — wait for publication and re-run rather than substituting an older build.

Procedure: run the helper — it does the whole resolution mechanically (requires az login with devdiv access):

pwsh ./scripts/Get-PackageValidationBaseline.ps1 -ThisReleaseVersion {{THIS_RELEASE_VERSION}}
# -> prints e.g. 18.11.0-1.26426.2

It computes git merge-base origin/main origin/vs{{THIS_RELEASE_VERSION}}, finds the matching successful build in pipeline 9434, derives the package version from the OfficialBuildId, and verifies it on the dotnet-tools feed. If it fails, read the script's own .DESCRIPTION header for the manual equivalent rather than reproducing it here.

Prerequisites

  • gh cli
  • az cli
  • darc cli — Arcade enforces a minimum version; if darc refuses with a "below the minimum required version" error, run .\eng\common\darc-init.ps1

Phase Summary

PhaseTriggerKey Actions
0: InstantiateUser-initiatedValidate inputs, create GitHub tracking issue
1: Branch & PrepareBRANCH_SNAP_DATECreate vs* branch, DARC channel setup (batched PR), audit all vs* branches for retirement
2: DARC Subscription UpdatesPhase 1 branch exists (vs* created)Retarget main-targeting subs + VMR backflow to next channel, retired-branch cleanup (batched PR), Arcade verify
3: Bump MainPhase 2 ingested and verifiedBranding PR in main (VersionPrefix → next, ApiCompat baseline, refresh OptProf baseline)
4: Final Branding7 days before INSIDERS_SNAP_DATETelemetry evidence checks, package API compatibility review, OptProf bootstrap, VS insertion before Insiders snap
5: Post-GAVS shipped (VS_SHIP_DATE)Resolve the exact shipped version (SDK-coupled? SDK wins over VS rel/stable), nuget.org publish, docs, GitHub release, Change Waves Learn sync, retro

DARC Batching

DARC write commands push to the maestro-configuration repo. Batch related changes into one PR:

  1. Choose a branch name like release/msbuild-{{THIS_RELEASE_VERSION}}
  2. Add --configuration-branch <name> --no-pr to every write command except the last
  3. Last command: use --configuration-branch <name> without --no-pr to create the PR
  4. Review the diff before merging; disable auto-complete if the PR must remain review-only.
  5. After merging, complete DARC configuration PR verification before dependent release steps.

Check existing channels and mappings before writing: the previous release normally pre-created the current release's mapping. Skip satisfied writes rather than constructing a redundant batch.

Read-only commands (get-default-channels, get-subscriptions, get-channel) don't need these flags.

Non-interactive (-q). darc add-default-channel / add-subscription prompt y/n when the target branch does not exist yet (e.g. pre-creating the vs{{NEXT_VERSION}} mapping in Phase 1.2c, or adding the new vs{{THIS_RELEASE_VERSION}} backflow in Phase 2). darc delete-subscriptions always prompts for confirmation. Console input is redirected in an agent session, so the prompt fails or hangs the command — always pass -q for these writes. Note the verb is delete-subscriptions (plural); delete-subscription does not exist.

Phase 2 — forward-flow rotation. Move subscriptions targeting main (dotnet/dotnet @ main, dotnet/fsharp @ main) to the next channel so those consumers receive next-version builds. Keep VMR release/* targets, including .NET-next preview bands, on VS {{THIS_RELEASE_VERSION}} so the release branch continues to feed its SDK bands.

Phase 2 — VMR backflow rotation. Backflow (dotnet/dotnet → msbuild, source-enabled) keeps each MSBuild branch's dependencies aligned with its SDK band. When the new vs{{THIS_RELEASE_VERSION}} is paired with an SDK band, repoint the → main backflow to the next SDK band channel and add backflow from the outgoing band channel into the release branch. Skip this for a VS-only release. See checklist steps 2.2b / 2.3f / 2.3g.

Branch retirement (Phase 1.3)

Audit every release branch to keep required SDK/VS servicing flows active and remove unused dependency automation.

Branch inventory: Maintained branches is the static list. Update its branch rows, SDK/VS sources, and support deadlines when cutting or retiring branches; cross-check the live DARC mappings, subscriptions, and repository branches in checklist step 1.3a.

Check both lifecycles because either the SDK or Visual Studio can require a branch:

LifecycleSource
SDK bandsupported .NET versions table — maps each feature band to its VS version and support end date
Visual StudioVS Product Lifecycle and Servicing — annual releases and the LTSC table

VS 2026 and later: non-LTSC releases are serviced through Insiders and for one month after Stable release. A new Stable promotion ends VS support for the previous release. LTSC baselines receive one year of servicing after release; use the published LTSC table to identify them.

Use published SDK and VS deadlines for lifecycle decisions, and DARC channels and subscriptions for dependency routing.

Apply the combined rule: retire a branch paired with an SDK band and a VS version only when both lifecycles agree it is out of support. Check these candidates for automation cleanup:

SignalMeaning
Branch's VS X.Y channel has no MSBuild outbound subscriptionNo downstream consumes MSBuild builds from that branch.
Default channel exists for a branch that isn't in the repoPure orphan — delete the mapping.

Retirement cleanup (2.3e): remove inbound subscriptions, unused MSBuild outbound subscriptions, and branch-to-channel associations, including disabled subscriptions. Preserve shared channels and flows still needed by other branches or producers; verify removals after merge and ingestion.

Executing a Phase

When asked to execute a specific phase:

  1. Read the full phase from documentation/release-checklist.md
  2. Verify the trigger condition is met (previous phases completed, including ingestion and live verification of prerequisite DARC changes)
  3. Execute steps in order — respect sequential/parallel annotations
  4. For DARC commands: batch writes into one configuration PR per phase
  5. Record all output URLs in the tracking issue's artifact table
  6. Mark checkboxes as completed in the tracking issue
  7. In Phase 4, complete telemetry checkpoints 4.0 and 4.4a using the shared evidence procedure in documentation/release-checklist.md.
  8. In Phase 4 (step 4.7): if documentation/wiki/ChangeWaves.md is changed for this release, update the public Learn page at https://learn.microsoft.com/visualstudio/msbuild/change-waves. Sync the Change Waves Learn page from documentation/wiki/ChangeWaves.md on the vsXX.Y branch that is live in VS Insiders / the latest preview SDK. PR goes to MicrosoftDocs/visualstudio-docs-pr (docs/msbuild/change-waves.md); example: https://github.com/MicrosoftDocs/visualstudio-docs-pr/pull/15662.

Key Files

FilePurpose
documentation/release-checklist.mdOperational checklist — the source of truth
documentation/release.mdMaintained-branch inventory and release process
documentation/wiki/ChangeWaves.mdSource doc for the Learn page sync — always sync the vsXX.Y (Insiders/preview-SDK) copy, not main
MSBuild Change Waves Learn pagePublic docs target to MicrosoftDocs/visualstudio-docs-pr (docs/msbuild/change-waves.md)
eng/Versions.propsVersionPrefix, PackageValidationBaselineVersion, BootstrapSdkVersion
azure-pipelines/vs-insertion.ymlVS insertion pipeline — TargetBranch parameter and InsertTargetBranch routing
azure-pipelines/vs-insertion-experimental.ymlExperimental insertion — TargetBranch parameter values
scripts/Get-PackageValidationBaseline.ps1Phase 3.3 — resolves PackageValidationBaselineVersion deterministically (merge-base → pipeline 9434 → dotnet-tools feed)
scripts/Get-LatestOptProfDrop.ps1Phase 3.4 — resolves the latest main OptProf drop (MSBuild-OptProf pipeline 17389) to refresh OptProfBaselineDrop in .vsts-dotnet.yml
.vsts-dotnet.ymlBuild pipeline entry point — OptProfBaselineDrop (hardcoded OptProf seed for new vs* branches)
azure-pipelines/.vsts-dotnet-build-jobs.ymlBuild jobs — VisualStudio.ChannelName is release-agnostic (int.main); no per-release edit

Validation

After completing all phases, verify:

  1. Branch vs{{THIS_RELEASE_VERSION}} exists and has final branding
  2. Main has VersionPrefix = {{NEXT_VERSION}}.0
  3. DARC: main → VS {{NEXT_VERSION}} channel, release branch → VS {{THIS_RELEASE_VERSION}} channel
  4. VS insertion PR merged
  5. Packages published to nuget.org
  6. GitHub release created with tag v{{THIS_RELEASE_EXACT_VERSION}}
  7. The Learn page https://learn.microsoft.com/visualstudio/msbuild/change-waves lists exactly the waves present in vsXX.Y (the version in VS Insiders / the latest released preview SDK), or the sync is explicitly tracked

Error Recovery

  • Branch already exists: Release was partially started — check the tracking issue for progress
  • DARC channel already exists: Safe to continue — add-channel is idempotent
  • OptProf fails on first build: Expected — that's why we use main's OptProf data as fallback
  • DARC configuration PR conflicts: Rebase the configuration branch on production and force-push

Major Version Releases

If NEXT_VERSION is a new major version (e.g., 18.x → 19.0), additional steps are needed after Phase 5. See release.md for:

  • src/Shared/BuildEnvironmentHelper.cs — VS major version constants
  • src/Shared/Constants.cs — version constants
  • src/Framework/Telemetry/TelemetryConstants.cs — telemetry version
Repository

dotnet/msbuild

Path

.github/skills/release/SKILL.md

Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.