From c1dc0b38d41f06d2c002c54214ffb81779be6941 Mon Sep 17 00:00:00 2001 From: OvesN Date: Wed, 13 May 2026 15:42:39 +0200 Subject: [PATCH 01/10] Document retiring unsupported branches from merge-flow chain Phase 1.3 of the release checklist previously only described inserting the new release branch into .config/git-merge-flow-config.jsonc. It said nothing about removing retired predecessor VS preview branches, so each release relied on someone noticing the stale entries (e.g. PR #13750 had to retire vs18.4 and vs18.5 manually after vs18.6 opened). Expand step 1.3 into 1.3a (insert new branch), 1.3b (retire unsupported predecessor preview branches), and 1.3c (sanity-check the resulting chain) so the cleanup happens as part of the same PR that adds the new branch. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- documentation/release-checklist.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/documentation/release-checklist.md b/documentation/release-checklist.md index 2f9004896f4..a8fe6bd5c88 100644 --- a/documentation/release-checklist.md +++ b/documentation/release-checklist.md @@ -73,8 +73,10 @@ Use `--configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}}` on every c `darc add-default-channel --channel "VS {{NEXT_VERSION}}" --branch vs{{NEXT_VERSION}} --repo https://github.com/dotnet/msbuild --configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}}` - [ ] **1.2d** Get the maestro-configuration PR reviewed and merged: {{URL_OF_PHASE1_DARC_PR}} - [ ] **1.2e** Ping internal "First Responders" Teams channel to get the new `VS {{NEXT_VERSION}}` channel available as a promotion target: {{URL_OF_CHANNEL_PROMOTION_PR}} -- [ ] **1.3** Update `.config/git-merge-flow-config.jsonc`: \ -Insert `vs{{THIS_RELEASE_VERSION}}` as the last entry before `main` in the merge chain. Add a comment noting the VS/SDK version context. +- [ ] **1.3** Update `.config/git-merge-flow-config.jsonc`: + - [ ] **1.3a** Insert `vs{{THIS_RELEASE_VERSION}}` as the last entry before `main` in the merge chain. Add a comment noting the VS/SDK version context. + - [ ] **1.3b** **Retire any predecessor VS preview branches that are no longer supported.** Identify intermediate `vsX.Y` branches between the previously-shipped LTSC/STS and `vs{{THIS_RELEASE_VERSION}}` whose content has already been merged forward and that will not receive further patches. Remove their `MergeToBranch` entries and rewire the chain to skip them so automation does not open stale forward-merge PRs against retired branches. The branches stay in the repo (for history); they just exit the auto-merge-forward flow. See [#13750](https://github.com/dotnet/msbuild/pull/13750) for an example (vs18.4 and vs18.5 retired when vs18.6 opened). + - [ ] **1.3c** Verify the resulting chain is well-formed: every key still has a single `MergeToBranch` value, the chain has no cycles, and it still terminates at `main`. --- From da7a9749f0d44150ff743cad136e4240a18398be Mon Sep 17 00:00:00 2001 From: OvesN Date: Wed, 13 May 2026 15:48:15 +0200 Subject: [PATCH 02/10] Simplify 1.3b: drop unverified retirement heuristic and 1.3c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the made-up criterion describing exactly when a branch is retired (content merged forward + past LTSC/STS / no future patches). That heuristic was not based on any documented policy and risks being wrong. Leave 1.3b as a prompt to retire predecessor branches that will no longer be supported, with the example PR for context. Reasoning for how to identify a retired branch will be added separately. Also drop 1.3c (chain well-formedness check) — the new sub-step doesn't need that scaffolding. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- documentation/release-checklist.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/documentation/release-checklist.md b/documentation/release-checklist.md index a8fe6bd5c88..87dd3cfc716 100644 --- a/documentation/release-checklist.md +++ b/documentation/release-checklist.md @@ -75,8 +75,7 @@ Use `--configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}}` on every c - [ ] **1.2e** Ping internal "First Responders" Teams channel to get the new `VS {{NEXT_VERSION}}` channel available as a promotion target: {{URL_OF_CHANNEL_PROMOTION_PR}} - [ ] **1.3** Update `.config/git-merge-flow-config.jsonc`: - [ ] **1.3a** Insert `vs{{THIS_RELEASE_VERSION}}` as the last entry before `main` in the merge chain. Add a comment noting the VS/SDK version context. - - [ ] **1.3b** **Retire any predecessor VS preview branches that are no longer supported.** Identify intermediate `vsX.Y` branches between the previously-shipped LTSC/STS and `vs{{THIS_RELEASE_VERSION}}` whose content has already been merged forward and that will not receive further patches. Remove their `MergeToBranch` entries and rewire the chain to skip them so automation does not open stale forward-merge PRs against retired branches. The branches stay in the repo (for history); they just exit the auto-merge-forward flow. See [#13750](https://github.com/dotnet/msbuild/pull/13750) for an example (vs18.4 and vs18.5 retired when vs18.6 opened). - - [ ] **1.3c** Verify the resulting chain is well-formed: every key still has a single `MergeToBranch` value, the chain has no cycles, and it still terminates at `main`. + - [ ] **1.3b** **Retire predecessor branches that will no longer be supported.** Remove their `MergeToBranch` entries and rewire the chain to skip them so automation does not open stale forward-merge PRs. The branches stay in the repo (for history); they just exit the auto-merge-forward flow. See [#13750](https://github.com/dotnet/msbuild/pull/13750) for an example (vs18.4 and vs18.5 retired when vs18.6 opened). --- From 586445ab6c56626cb6826a353fe95c46ecf61900 Mon Sep 17 00:00:00 2001 From: OvesN Date: Wed, 13 May 2026 15:49:26 +0200 Subject: [PATCH 03/10] Trim 1.3b: drop trailing context sentences Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- documentation/release-checklist.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/release-checklist.md b/documentation/release-checklist.md index 87dd3cfc716..e43bdcce4e0 100644 --- a/documentation/release-checklist.md +++ b/documentation/release-checklist.md @@ -75,7 +75,7 @@ Use `--configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}}` on every c - [ ] **1.2e** Ping internal "First Responders" Teams channel to get the new `VS {{NEXT_VERSION}}` channel available as a promotion target: {{URL_OF_CHANNEL_PROMOTION_PR}} - [ ] **1.3** Update `.config/git-merge-flow-config.jsonc`: - [ ] **1.3a** Insert `vs{{THIS_RELEASE_VERSION}}` as the last entry before `main` in the merge chain. Add a comment noting the VS/SDK version context. - - [ ] **1.3b** **Retire predecessor branches that will no longer be supported.** Remove their `MergeToBranch` entries and rewire the chain to skip them so automation does not open stale forward-merge PRs. The branches stay in the repo (for history); they just exit the auto-merge-forward flow. See [#13750](https://github.com/dotnet/msbuild/pull/13750) for an example (vs18.4 and vs18.5 retired when vs18.6 opened). + - [ ] **1.3b** **Retire predecessor branches that will no longer be supported.** Remove their `MergeToBranch` entries and rewire the chain to skip them so automation does not open stale forward-merge PRs. --- From 5406275703f9cd7671199dbf532234f3dbbc268c Mon Sep 17 00:00:00 2001 From: OvesN Date: Wed, 13 May 2026 16:45:50 +0200 Subject: [PATCH 04/10] Add guidance for identifying retired branches For SDK releases, refer to the lifecycle table in the SDK/MSBuild/VS versioning doc. For VS releases, the retired branch is always the immediate predecessor of the one being released. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- documentation/release-checklist.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/documentation/release-checklist.md b/documentation/release-checklist.md index e43bdcce4e0..f79dc4f18f1 100644 --- a/documentation/release-checklist.md +++ b/documentation/release-checklist.md @@ -75,7 +75,10 @@ Use `--configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}}` on every c - [ ] **1.2e** Ping internal "First Responders" Teams channel to get the new `VS {{NEXT_VERSION}}` channel available as a promotion target: {{URL_OF_CHANNEL_PROMOTION_PR}} - [ ] **1.3** Update `.config/git-merge-flow-config.jsonc`: - [ ] **1.3a** Insert `vs{{THIS_RELEASE_VERSION}}` as the last entry before `main` in the merge chain. Add a comment noting the VS/SDK version context. - - [ ] **1.3b** **Retire predecessor branches that will no longer be supported.** Remove their `MergeToBranch` entries and rewire the chain to skip them so automation does not open stale forward-merge PRs. + - [ ] **1.3b** **Retire predecessor branches that will no longer be supported.** Remove their `MergeToBranch` entries and rewire the chain to skip them so automation does not open stale forward-merge PRs. \ + How to identify a retired branch: + - **SDK releases** — check the lifecycle table at https://learn.microsoft.com/dotnet/core/porting/versioning-sdk-msbuild-vs#lifecycle; any branch tied to an SDK band that is past its support end date is retired. + - **VS releases** — the retired branch is always the version directly preceding the one being released (i.e. `vs{{THIS_RELEASE_VERSION}} - 1`). --- From 214adab11113ae6c71c413a43aa8434e61b82dc0 Mon Sep 17 00:00:00 2001 From: OvesN Date: Thu, 14 May 2026 10:10:41 +0200 Subject: [PATCH 05/10] Add Phase 5.4b: bump global.json tools.dotnet monthly The release checklist already covers BootstrapSdkVersion (the SDK that hosts bootstrap test runs) but not the tools.dotnet pin in global.json (the SDK that builds MSBuild itself, surfaced as DotNetCliVersion in eng/Versions.props and required to match per the comment there). Add 5.4b so the build-side SDK is refreshed on the same monthly cadence as new SDK releases. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- documentation/release-checklist.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/release-checklist.md b/documentation/release-checklist.md index f79dc4f18f1..164361ac1b2 100644 --- a/documentation/release-checklist.md +++ b/documentation/release-checklist.md @@ -200,6 +200,7 @@ Click *Request – Reference Publishing*. Use [existing ticket](https://dev.azur ``` Create release at https://github.com/dotnet/msbuild/releases/new — use `Generate Release Notes` to prepopulate. - [ ] **5.4** Update `BootstrapSdkVersion` in [`eng/Versions.props`](https://github.com/dotnet/msbuild/blob/main/eng/Versions.props) if a fresh SDK was released. Check https://dotnet.microsoft.com/download/visual-studio-sdks — always verify the details for the targeted .NET version. +- [ ] **5.4b** Update `tools.dotnet` in [`global.json`](https://github.com/dotnet/msbuild/blob/main/global.json) to the latest released SDK in the targeted band. `DotNetCliVersion` in `eng/Versions.props` is derived from this and **must** match (see the comment on `DotNetCliVersion`). This bump should happen monthly as new SDKs release. - [ ] **5.5** Extend OptProf data expiration for `vs{{THIS_RELEASE_VERSION}}` branch if the release is LTSC: - Find the drop at `OptimizationData/DotNet-msbuild-Trusted/vs{{THIS_RELEASE_VERSION}}/...` (in MSBuild CI logs: Build task, or OptProf pipeline: "Publish OptimizationInputs drop" task) - Get [drop.exe](https://eng.ms/docs/cloud-ai-platform/devdiv/one-engineering-system-1es/1es-docs/azure-artifacts/drop-service/azure-artifacts-drop) CLI From 72f3ed5e132fb9ab2936629adc104cb802235ae4 Mon Sep 17 00:00:00 2001 From: Veronika Ovsyannikova Date: Wed, 27 May 2026 11:49:04 +0200 Subject: [PATCH 06/10] update checklist --- documentation/release-checklist.md | 88 +++++++++++++++++++----------- 1 file changed, 55 insertions(+), 33 deletions(-) diff --git a/documentation/release-checklist.md b/documentation/release-checklist.md index 164361ac1b2..b82ba5b656d 100644 --- a/documentation/release-checklist.md +++ b/documentation/release-checklist.md @@ -125,20 +125,19 @@ Use `--configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}}-main-bump` `darc update-subscription --id --channel "VS {{NEXT_VERSION}}" --configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}}-main-bump --no-pr` - [ ] **3.3d** If release branch association was missing in 3.2, add it: \ `darc add-default-channel --channel "VS {{THIS_RELEASE_VERSION}}" --branch vs{{THIS_RELEASE_VERSION}} --repo https://github.com/dotnet/msbuild --configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}}-main-bump --no-pr` - - [ ] **3.3e** _If any subscriptions need fixing (from 3.4–3.6 below), include them here with `--no-pr`._ + - [ ] **3.3e** _If the Arcade subscription from 3.4 below is missing or pointed at the wrong channel, include the fix here with `--no-pr`._ - [ ] **3.3f** **Create the PR** — re-run step 3.3b (or whichever was the last write command executed) without `--no-pr` to open the PR on the configuration branch. - [ ] **3.3g** Get the maestro-configuration PR reviewed and merged: {{URL_OF_PHASE3_DARC_PR}} Verifications (**parallel** — read-only, no ordering dependency): -- [ ] **3.4** Verify Arcade subscription (based on .NET version channel — rarely changes): \ +- [ ] **3.4** Verify Arcade subscription — **and add it if missing**. \ `darc get-subscriptions --exact --target-repo https://github.com/dotnet/msbuild --source-repo https://github.com/dotnet/arcade` -- [ ] **3.5** Verify NuGet client subscription (based on VS version channel): \ -`darc get-subscriptions --exact --target-repo https://github.com/dotnet/msbuild --source-repo https://github.com/nuget/nuget.client` -- [ ] **3.6** Verify Roslyn subscription (based on VS version channel): \ -`darc get-subscriptions --exact --target-repo https://github.com/dotnet/msbuild --source-repo https://github.com/dotnet/roslyn` -- [ ] **3.7** Confirm Roslyn and NuGet subscriptions are **disabled** (`Enabled: False` in output). We do not want to automatically bump them — version updates are driven by SDK or VS. -- [ ] **3.8** Fix any missing or misconfigured subscriptions by adding write commands to the Phase 3 PR branch (step 3.3e) before merging, or with a separate `darc add-subscription` / `darc update-subscription` (run with `--help` for params) + - **Every supported branch must have an Arcade subscription from the matching `.NET Eng` channel.** For an SDK-coupled release this is the single most commonly forgotten piece of configuration — verify a subscription exists from **`.NET Eng`** (the channel matching the .NET version this VS release ships with) into `vs{{THIS_RELEASE_VERSION}}`. + - Expected cadence: weekly Arcade flow into `vs{{THIS_RELEASE_VERSION}}`. If you don't see weekly Arcade-bump PRs after a release, the subscription is missing or pointed at the wrong channel. + - If missing, add it via the configuration branch in **3.3e** (use `darc add-subscription ... --source-repo https://github.com/dotnet/arcade --channel ".NET Eng" --target-repo https://github.com/dotnet/msbuild --target-branch vs{{THIS_RELEASE_VERSION}} --update-frequency EveryWeek`). + +> _Roslyn and NuGet subscription verification intentionally omitted: there is always exactly one Roslyn and NuGet subscription, it targets `main` only, is permanently disabled, and never changes per release — re-verifying it every release adds no signal._ --- @@ -166,6 +165,11 @@ The insertion PR contains the inserted package versions — useful for the nuget **After insiders snap** (only if a backport to insiders is needed): +> 🛑 **4.7 and 4.8 are NOT part of the regular release flow — skip them entirely on a normal release.** \ +> They only apply when **servicing** a previously-shipped release (i.e. you actually have a hotfix commit on `vs{{THIS_RELEASE_VERSION}}` that needs to be inserted into VS's already-snapped `rel/insiders` or `rel/stable` branch). If you have no such commit to service, leave `AutoInsertTargetBranch` untouched and move on to Phase 5. +> +> ⚠️ When you *do* need to service: re-confirm which VS branch you actually want to insert into before flipping `AutoInsertTargetBranch`. The default is `main`, so forgetting to retarget after the snap silently lands your fix in the next VS instead of the one you're servicing. + - [ ] **4.7** Update [`azure-pipelines/vs-insertion.yml`](../azure-pipelines/vs-insertion.yml): retarget `AutoInsertTargetBranch` for `vs{{THIS_RELEASE_VERSION}}` from VS `main` → `rel/insiders`. This enables direct insertion of hotfix commits into the insiders branch. **After stable snap** (only if a backport to stable is needed): @@ -180,34 +184,52 @@ The insertion PR contains the inserted package versions — useful for the nuget Steps are **mostly parallel** unless noted. -- [ ] **5.1** Push packages to nuget.org. Contact dnceng — search "Publish MSBuild {{THIS_RELEASE_VERSION}} to NuGet.org" email subject for template. \ -`THIS_RELEASE_EXACT_VERSION` = `VersionPrefix` from `eng/Versions.props` on the release branch (also visible in the VS insertion PR). Packages to publish taken from the official build https://devdiv.visualstudio.com/DevDiv/_build?definitionId=9434 for the {{THIS_RELEASE_VERSION}} branch; search in artifacts under the Shipping folder for: - - Microsoft.Build.Utilities.Core.{{THIS_RELEASE_EXACT_VERSION}}.nupkg - - Microsoft.Build.{{THIS_RELEASE_EXACT_VERSION}}.nupkg - - Microsoft.Build.Framework.{{THIS_RELEASE_EXACT_VERSION}}.nupkg - - Microsoft.Build.Runtime.{{THIS_RELEASE_EXACT_VERSION}}.nupkg - - Microsoft.Build.Tasks.Core.{{THIS_RELEASE_EXACT_VERSION}}.nupkg - - Microsoft.NET.StringTools.{{THIS_RELEASE_EXACT_VERSION}}.nupkg - - Microsoft.Build.Templates.{{THIS_RELEASE_EXACT_VERSION}}.nupkg - -- [ ] **5.2** Publish docs: submit reference request at https://aka.ms/publishondocs \ -Click *Request – Reference Publishing*. Use [existing ticket](https://dev.azure.com/msft-skilling/Content/_workitems/edit/183613) as a reference. +- [ ] **5.1** Push packages to nuget.org. + + > **How publishing works:** We don't push packages ourselves. We hand a link to the **Shipping** artifacts of the official build to the dnceng release team, and they push to nuget.org. Searching past mail for the subject _"Publish MSBuild {{THIS_RELEASE_VERSION}} to NuGet.org"_ will surface the contact and template; do **not** hard-code the contact's name or email in this checklist — internal ownership rotates and we don't want individual addresses exposed in a public GitHub doc. + + - [ ] **5.1a** Determine the exact MSBuild version that actually shipped to customers — **do not trust `VersionPrefix` in the release branch by itself**, it has been misleading in past releases. + - **If this release is coupled with an SDK release: use the SDK as the source of truth** — it has the highest fidelity, particularly for security-only patches where only some intervals get bumped. Look up the MSBuild version baked into the shipped SDK build. + - Otherwise: look at the MSBuild version inserted into the corresponding VS build. Note this version differs in non-obvious ways between VS major/minor versions, so confirm against the actual VS insertion PR. + - [ ] **5.1b** In the [MSBuild official build pipeline](https://devdiv.visualstudio.com/DevDiv/_build?definitionId=9434), filter to the `vs{{THIS_RELEASE_VERSION}}` branch and locate the build whose output version matches the one identified in 5.1a (e.g. `{{THIS_RELEASE_EXACT_VERSION}}`, such as `18.6.3`). + - [ ] **5.1c** From that build, open the **Publish Artifacts** step and grab the link to the **`artifacts-shipping`** drop. Verify the Shipping folder contains all of: + - `Microsoft.Build.Utilities.Core.{{THIS_RELEASE_EXACT_VERSION}}.nupkg` + - `Microsoft.Build.{{THIS_RELEASE_EXACT_VERSION}}.nupkg` + - `Microsoft.Build.Framework.{{THIS_RELEASE_EXACT_VERSION}}.nupkg` + - `Microsoft.Build.Runtime.{{THIS_RELEASE_EXACT_VERSION}}.nupkg` + - `Microsoft.Build.Tasks.Core.{{THIS_RELEASE_EXACT_VERSION}}.nupkg` + - `Microsoft.NET.StringTools.{{THIS_RELEASE_EXACT_VERSION}}.nupkg` + - `Microsoft.Build.Templates.{{THIS_RELEASE_EXACT_VERSION}}.nupkg` + - [ ] **5.1d** Email the dnceng release team (use the saved _"Publish MSBuild ... to NuGet.org"_ template from your sent mail) with the `artifacts-shipping` link from 5.1c and ask them to publish to nuget.org. Track the reply until publication is confirmed. + +- [ ] **5.2** Publish docs + + > **How publishing works:** The reference-publishing vendor team generates Microsoft Learn reference pages from the shipped MSBuild assemblies/xmldoc and then sends us a docs-repo PR with the regenerated content. + + - [ ] **5.2a** Create a reference-publishing ticket for the new release based on [this existing ticket](https://dev.azure.com/msft-skilling/Content/_workitems/edit/565854) as a template. Then wait for the vendor team to ping you with a link to the generated PR. + - [ ] **5.2b** Review and approve the docs-repo PR the vendor team opens (example: [msbuild-api-docs#61](https://github.com/dotnet/msbuild-api-docs/pull/61)). - [ ] **5.3** Create GitHub release: - ``` - git checkout - git tag v{{THIS_RELEASE_EXACT_VERSION}} - git push upstream v{{THIS_RELEASE_EXACT_VERSION}} - ``` - Create release at https://github.com/dotnet/msbuild/releases/new — use `Generate Release Notes` to prepopulate. + - [ ] **5.3a** **Precondition — confirm the previous release tag exists on `upstream`.** \ + `git fetch upstream --tags && git tag --list 'v{{PREVIOUS_RELEASE_EXACT_VERSION}}'` \ + If the tag is missing (e.g. the previous release was never tagged), create and push it **first**. + - [ ] **5.3b** **Identify the commit to tag.** It is **not always** the final-branding commit from 4.3 — it must be the commit whose bits **actually shipped** in `{{THIS_RELEASE_EXACT_VERSION}}`. \ + If a hotfix was applied to `vs{{THIS_RELEASE_VERSION}}` after final branding and that fix was inserted into the VS build that shipped, tag **that** commit instead. \ + To find it: cross-reference the SHA from the **VS insertion PR that actually shipped** (the package version listed there must equal `{{THIS_RELEASE_EXACT_VERSION}}` from 5.1a) with the commit history on `vs{{THIS_RELEASE_VERSION}}`. + - [ ] **5.3c** Tag this release and push: + ``` + git checkout + git tag v{{THIS_RELEASE_EXACT_VERSION}} + git push upstream v{{THIS_RELEASE_EXACT_VERSION}} + ``` + - [ ] **5.3d** Create release at https://github.com/dotnet/msbuild/releases/new — use `Generate Release Notes` to prepopulate. - [ ] **5.4** Update `BootstrapSdkVersion` in [`eng/Versions.props`](https://github.com/dotnet/msbuild/blob/main/eng/Versions.props) if a fresh SDK was released. Check https://dotnet.microsoft.com/download/visual-studio-sdks — always verify the details for the targeted .NET version. - [ ] **5.4b** Update `tools.dotnet` in [`global.json`](https://github.com/dotnet/msbuild/blob/main/global.json) to the latest released SDK in the targeted band. `DotNetCliVersion` in `eng/Versions.props` is derived from this and **must** match (see the comment on `DotNetCliVersion`). This bump should happen monthly as new SDKs release. -- [ ] **5.5** Extend OptProf data expiration for `vs{{THIS_RELEASE_VERSION}}` branch if the release is LTSC: - - Find the drop at `OptimizationData/DotNet-msbuild-Trusted/vs{{THIS_RELEASE_VERSION}}/...` (in MSBuild CI logs: Build task, or OptProf pipeline: "Publish OptimizationInputs drop" task) - - Get [drop.exe](https://eng.ms/docs/cloud-ai-platform/devdiv/one-engineering-system-1es/1es-docs/azure-artifacts/drop-service/azure-artifacts-drop) CLI - - Set expiration to VS support end date + 3 months per [these instructions](https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/30808/Extend-a-drop's-expiration-date) -- [ ] **5.6** Verify `main` subscriptions point to `VS {{NEXT_VERSION}}` channel (should have been done in Phase 3; confirm): \ -`darc get-subscriptions --exact --target-repo https://github.com/dotnet/msbuild --target-branch main` -- [ ] **5.7** Review this tracking issue for any process deviations. If the process changed, create a PR to update `documentation/release-checklist.md` with the improvements. +- [ ] **5.5** Verify the overall subscription map is correct — not just for `{{THIS_RELEASE_VERSION}}` but for every still-supported branch: + - [ ] **5.5a** `main` subscriptions point to `VS {{NEXT_VERSION}}` channel (should have been done in Phase 3; confirm): \ + `darc get-subscriptions --exact --target-repo https://github.com/dotnet/msbuild --target-branch main` + - [ ] **5.5b** Every supported `vsXX.Y` branch has an Arcade subscription matching its targeted .NET band, and each supported branch's outbound subscriptions land in the right downstream (e.g. SDK band, VMR). \ + Open question (track with Rainer): MSBuild `main` currently flows to *two* downstream targets (VMR and the legacy SDK path) but only one subscription is configured — confirm whether this needs a dual subscription before signing off the release. +- [ ] **5.6** Review this tracking issue for any process deviations. If the process changed, create a PR to update `documentation/release-checklist.md` with the improvements. --- From a4ef989d513bfa72078dc2c49e0aa1867438f8da Mon Sep 17 00:00:00 2001 From: Veronika Ovsyannikova Date: Wed, 27 May 2026 12:42:14 +0200 Subject: [PATCH 07/10] fix --- documentation/release-checklist.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/documentation/release-checklist.md b/documentation/release-checklist.md index b82ba5b656d..2f368fb0cf3 100644 --- a/documentation/release-checklist.md +++ b/documentation/release-checklist.md @@ -133,9 +133,8 @@ Verifications (**parallel** — read-only, no ordering dependency): - [ ] **3.4** Verify Arcade subscription — **and add it if missing**. \ `darc get-subscriptions --exact --target-repo https://github.com/dotnet/msbuild --source-repo https://github.com/dotnet/arcade` - - **Every supported branch must have an Arcade subscription from the matching `.NET Eng` channel.** For an SDK-coupled release this is the single most commonly forgotten piece of configuration — verify a subscription exists from **`.NET Eng`** (the channel matching the .NET version this VS release ships with) into `vs{{THIS_RELEASE_VERSION}}`. - - Expected cadence: weekly Arcade flow into `vs{{THIS_RELEASE_VERSION}}`. If you don't see weekly Arcade-bump PRs after a release, the subscription is missing or pointed at the wrong channel. - - If missing, add it via the configuration branch in **3.3e** (use `darc add-subscription ... --source-repo https://github.com/dotnet/arcade --channel ".NET Eng" --target-repo https://github.com/dotnet/msbuild --target-branch vs{{THIS_RELEASE_VERSION}} --update-frequency EveryWeek`). + - **Every supported branch must have an Arcade subscription** from the matching `.NET Eng` channel. + - The **channel** is determined by the .NET band the branch is paired with (e.g. a branch paired with .NET 10 subscribes to `.NET 10 Eng`). > _Roslyn and NuGet subscription verification intentionally omitted: there is always exactly one Roslyn and NuGet subscription, it targets `main` only, is permanently disabled, and never changes per release — re-verifying it every release adds no signal._ From 8bba2d7d1a6972c462b7fac29e32af4c5b862841 Mon Sep 17 00:00:00 2001 From: Veronika Ovsyannikova Date: Wed, 27 May 2026 12:51:21 +0200 Subject: [PATCH 08/10] update --- documentation/release-checklist.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/documentation/release-checklist.md b/documentation/release-checklist.md index 2f368fb0cf3..ad644b6721f 100644 --- a/documentation/release-checklist.md +++ b/documentation/release-checklist.md @@ -125,17 +125,15 @@ Use `--configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}}-main-bump` `darc update-subscription --id --channel "VS {{NEXT_VERSION}}" --configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}}-main-bump --no-pr` - [ ] **3.3d** If release branch association was missing in 3.2, add it: \ `darc add-default-channel --channel "VS {{THIS_RELEASE_VERSION}}" --branch vs{{THIS_RELEASE_VERSION}} --repo https://github.com/dotnet/msbuild --configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}}-main-bump --no-pr` - - [ ] **3.3e** _If the Arcade subscription from 3.4 below is missing or pointed at the wrong channel, include the fix here with `--no-pr`._ + - [ ] **3.3e** _If any subscriptions need fixing (from 3.4–3.6 below), include them here with `--no-pr`._ - [ ] **3.3f** **Create the PR** — re-run step 3.3b (or whichever was the last write command executed) without `--no-pr` to open the PR on the configuration branch. - [ ] **3.3g** Get the maestro-configuration PR reviewed and merged: {{URL_OF_PHASE3_DARC_PR}} Verifications (**parallel** — read-only, no ordering dependency): -- [ ] **3.4** Verify Arcade subscription — **and add it if missing**. \ +- [ ] **3.4** Verify the Arcade subscription for `vs{{THIS_RELEASE_VERSION}}`: \ `darc get-subscriptions --exact --target-repo https://github.com/dotnet/msbuild --source-repo https://github.com/dotnet/arcade` - - **Every supported branch must have an Arcade subscription** from the matching `.NET Eng` channel. - - The **channel** is determined by the .NET band the branch is paired with (e.g. a branch paired with .NET 10 subscribes to `.NET 10 Eng`). - + - **Every supported branch must have an Arcade subscription** from the matching `.NET Eng` channel (the channel is determined by the .NET band the branch is paired with — e.g. a branch paired with .NET 10 subscribes to `.NET 10 Eng`). > _Roslyn and NuGet subscription verification intentionally omitted: there is always exactly one Roslyn and NuGet subscription, it targets `main` only, is permanently disabled, and never changes per release — re-verifying it every release adds no signal._ --- From 43be9790a2eddb66f686c1729380a78d9859a450 Mon Sep 17 00:00:00 2001 From: Veronika Ovsyannikova Date: Thu, 28 May 2026 12:59:07 +0200 Subject: [PATCH 09/10] Apply Kitten release walkthrough feedback to release checklist - Inputs: fix BRANCH_SNAP_DATE description; add PACKAGE_VALIDATION_BASELINE_VERSION row and 'how to determine' reference section from #13676. - Phase 0: fix invalid 'darc get-channel --name' to 'darc get-channels' + filter; remove inline artifact tracking table. - Phase 1: add 1.0 pre-snap team check; add admin-rights note to 1.1; drop unusable --configuration-branch release/msbuild-... from all darc commands in 1.2; delete 1.2e (First Responders ping); rewrite 1.3b retirement rule as combined SDK + VS lifecycle (only retire when both agree; link VS Servicing wiki). - Phase 2 (was Phase 3) - DARC subscription updates: swapped before bump-main so VMR consumes correct channel; dropped --configuration-branch from all commands; new 2.3e to delete subscriptions for retired branches mirroring 1.3b combined rule; cross-refs updated; Roslyn/NuGet verification removed (steady-state, out-of-band); URL_OF_PHASE3_DARC_PR renamed to URL_OF_PHASE2_DARC_PR. - Phase 3 (was Phase 2) - bump main: 3.2 references PACKAGE_VALIDATION_BASELINE_VERSION; 3.3 marked as fix-up only on pipeline API-compat failure; deleted obsolete AutoInsertTargetBranch retarget step. - Phase 4: 4.4 OptProf rewritten to 2 steps (cancel auto-triggered build; re-run manually with main override); 4.7/4.8 servicing-only callout retained. - Phase 5: 5.5a cross-ref to Phase 2 (post-swap). - New 'Release Output' table at bottom of file replacing the Phase 0 inline tracking table. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- documentation/release-checklist.md | 167 ++++++++++++++++++----------- 1 file changed, 102 insertions(+), 65 deletions(-) diff --git a/documentation/release-checklist.md b/documentation/release-checklist.md index ad644b6721f..be12a48b7e8 100644 --- a/documentation/release-checklist.md +++ b/documentation/release-checklist.md @@ -14,10 +14,38 @@ Fill in these values before starting. Version increments are irregular — they | `{{THIS_RELEASE_VERSION}}` | Version being released now (e.g. `18.6`) | | | `{{THIS_RELEASE_EXACT_VERSION}}` | Full `VersionPrefix` from `eng/Versions.props` on the release branch after final branding (e.g. `18.6.0`). For non-patch releases this is always `{{THIS_RELEASE_VERSION}}.0`. | | | `{{NEXT_VERSION}}` | Version that main will be bumped to (e.g. `18.7`) | | -| `{{BRANCH_SNAP_DATE}}` | Date MSBuild branches `vs*` from `main`. Insertion targets VS `main`. From [VS-Dates wiki](https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/49807/VS-Dates) | | +| `{{BRANCH_SNAP_DATE}}` | Date we create `vs{{THIS_RELEASE_VERSION}}` from `main` (and, if needed, fast-forward it to the exact `main` commit currently inserted into VS `main`). This is **decided by us**, not read from a wiki — it is the date Phase 1.1 actually runs. | | | `{{INSIDERS_SNAP_DATE}}` | Date VS snaps `main` → `rel/insiders`. Final-branded MSBuild must be in VS `main` **before** this date. From [VS-Dates wiki](https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/49807/VS-Dates) | | | `{{STABLE_SNAP_DATE}}` | Date VS snaps `rel/insiders` → `rel/stable`. From [VS-Dates wiki](https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/49807/VS-Dates) | | | `{{VS_SHIP_DATE}}` | Date VS ships publicly (GA). Post-GA tasks (nuget.org, docs) happen after this. | | +| `{{PACKAGE_VALIDATION_BASELINE_VERSION}}` | Latest `{{THIS_RELEASE_VERSION}}.0-preview-NNNNN-NN` MSBuild build produced from the `vs{{THIS_RELEASE_VERSION}}` branch — used as the ApiCompat baseline. See [How to determine `{{PACKAGE_VALIDATION_BASELINE_VERSION}}`](#how-to-determine-package_validation_baseline_version) below. | | + +### How to determine `{{PACKAGE_VALIDATION_BASELINE_VERSION}}` + +**The value is the latest `{{THIS_RELEASE_VERSION}}.0-preview-NNNNN-NN` MSBuild package that is both:** + +1. **Published on the public [dotnet-tools feed](https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-tools)** — this is the feed `darc publish` pushes 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 `vs{{THIS_RELEASE_VERSION}}` commit prior to stabilization, or the `main` commit `vs{{THIS_RELEASE_VERSION}}` was branched from. + +**Two tempting wrong answers — and why they're wrong:** + +| Wrong pick | Why it fails | +|---|---| +| ❌ The `{{THIS_RELEASE_VERSION}}.X` package that actually ships in VS (e.g. `18.7.1`) | After Phase 4.2 `Stabilize-Release.ps1` runs, builds become **final-versioned**. So such package is not resolvable from public CI. | +| ❌ Blindly the most recent `{{THIS_RELEASE_VERSION}}.0-preview-*` on `dotnet-tools` | After `vs{{THIS_RELEASE_VERSION}}` branches, `main` keeps producing `{{THIS_RELEASE_VERSION}}.0-preview-*` 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. | + +**Procedure:** + +1. Open [MSBuild official build pipeline 9434](https://devdiv.visualstudio.com/DevDiv/_build?definitionId=9434). +2. Filter runs to branch `vs{{THIS_RELEASE_VERSION}}`. Find the run that final-branded the release (it produces `{{THIS_RELEASE_VERSION}}.X` — no `-preview-` — corresponding to the commit that ran `Stabilize-Release.ps1`). Anything successful **before** that on `vs{{THIS_RELEASE_VERSION}}` is a candidate. +3. If `vs{{THIS_RELEASE_VERSION}}` has no successful pre-stabilization preview runs (common — the branch sees little churn before stabilization), fall back to the most recent successful `main` run whose commit is the branch-point ancestor: \ +`git merge-base origin/main origin/vs{{THIS_RELEASE_VERSION}}` gives the SHA — find a `main` run at or before that SHA in pipeline 9434. +4. Read the package version from that run's `Pack` step output: `{{THIS_RELEASE_VERSION}}.0-preview-NNNNN-NN` (example: `18.7.0-preview-26230-02`). + - **Decoding tip** (lets you cross-reference feed ↔ build at a glance): `NNNNN` = `YY[Month×50+Day]`, `NN` = revision-of-day. So `26230-02` ↔ build `20260430.02` (year 26, April 30 → 4×50+30 = 230, 2nd run of the day). +5. Verify the exact version is on the [dotnet-tools feed](https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-tools) (search `Microsoft.Build`). If not, fall back to the next-older eligible run. +6. Use that version. Do **not** include any `+sha` suffix. + +**Known gap** (track in your release tracking issue): the procedure is manual because `dotnet-tools` contains both pre- and post-branch-point `main` builds under identical `{{THIS_RELEASE_VERSION}}.0-preview-*` branding. If/when publishing is fixed so `main` builds never carry stale branding, this collapses to "latest `{{THIS_RELEASE_VERSION}}.0-preview-*` on `dotnet-tools`" — programmatically queryable. **Derived values** (do not edit — computed from inputs): - Release branch: `vs{{THIS_RELEASE_VERSION}}` @@ -33,20 +61,10 @@ Fill in these values before starting. Version increments are irregular — they - [ ] Confirm `eng/Versions.props` on `main` has `VersionPrefix` = `{{THIS_RELEASE_VERSION}}.0` — if not, the inputs are wrong - [ ] Confirm branch `vs{{THIS_RELEASE_VERSION}}` does **not** already exist — if it does, this release was already started - [ ] Confirm DARC channel `VS {{THIS_RELEASE_VERSION}}` exists: \ - `darc get-channel --name "VS {{THIS_RELEASE_VERSION}}"` \ + `darc get-channels` _(filter the output for the channel name — there is no `--name` flag on `darc get-channels`)_ \ If missing, it should have been created during the previous release (Phase 1.2b "create next channel" step). Create it now: `darc add-channel --name "VS {{THIS_RELEASE_VERSION}}"` - [ ] Create this tracking issue in dotnet/msbuild with all `{{PLACEHOLDERS}}` replaced -- [ ] Record all tracking URLs in the table below as phases are completed: - -| Artifact | URL | -|---|---| -| Next-version branding PR | {{URL_OF_NEXT_VERSION_BRANDING_PR}} | -| VisualStudio.ChannelName PR | {{URL_OF_CHANNEL_NAME_PR}} | -| Phase 1 DARC config PR | {{URL_OF_PHASE1_DARC_PR}} | -| Phase 3 DARC config PR | {{URL_OF_PHASE3_DARC_PR}} | -| Final branding PR | {{URL_OF_FINAL_BRANDING_PR}} | -| VS insertion PR | {{URL_OF_VS_INSERTION}} | -| Channel promotion PR | {{URL_OF_CHANNEL_PROMOTION_PR}} | +- [ ] As phases complete, record artifact URLs in the **Release Output** table at the bottom of this checklist. --- @@ -56,85 +74,90 @@ Fill in these values before starting. Version increments are irregular — they Steps are **sequential** — complete in order. -- [ ] **1.1** Create branch `vs{{THIS_RELEASE_VERSION}}` from HEAD of `main`: \ +- [ ] **1.0** **Pre-snap team check.** Before snapping the branch, ping the MSBuild team to confirm there is nothing they still need to merge into `main` that should ship in `{{THIS_RELEASE_VERSION}}`. Anything that lands in `main` after Phase 1.1 will go into `{{NEXT_VERSION}}` instead. +- [ ] **1.1** Create branch `vs{{THIS_RELEASE_VERSION}}` from HEAD of `main` (**requires repo admin rights** — `git push` to `refs/heads/vs*` is restricted): \ `git push upstream HEAD:refs/heads/vs{{THIS_RELEASE_VERSION}}` - _If branched too early_ (main has commits that shouldn't be in the release): fast-forward the branch to the correct commit (the one currently inserted into VS main): \ `git push upstream :refs/heads/vs{{THIS_RELEASE_VERSION}}` - [ ] **1.2** DARC configuration — batch all channel/mapping changes into **one PR** on the [maestro-configuration](https://dev.azure.com/dnceng/internal/_git/maestro-configuration) repo. \ -Use `--configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}}` on every command and `--no-pr` on all but the last: +Use `--no-pr` on all but the last command. **Do not pass `--configuration-branch release/msbuild-...`** — pushes to `release/`-prefixed branches in the maestro-configuration repo are not permitted; let darc pick its own configuration branch. - [ ] **1.2a** Ensure branch-to-channel association exists: \ First check: `darc get-default-channels --channel "VS {{THIS_RELEASE_VERSION}}" --branch vs{{THIS_RELEASE_VERSION}} --source-repo https://github.com/dotnet/msbuild` \ If `No matching channels were found.`: \ - `darc add-default-channel --channel "VS {{THIS_RELEASE_VERSION}}" --branch vs{{THIS_RELEASE_VERSION}} --repo https://github.com/dotnet/msbuild --configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}} --no-pr` + `darc add-default-channel --channel "VS {{THIS_RELEASE_VERSION}}" --branch vs{{THIS_RELEASE_VERSION}} --repo https://github.com/dotnet/msbuild --no-pr` - [ ] **1.2b** Create DARC channel for **next** release: \ - `darc add-channel --name "VS {{NEXT_VERSION}}" --configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}} --no-pr` \ + `darc add-channel --name "VS {{NEXT_VERSION}}" --no-pr` \ _(If channel already exists, this is a no-op.)_ - [ ] **1.2c** Pre-create default channel mapping for the **next** release branch (**last command — omit `--no-pr` to create the PR**): \ - `darc add-default-channel --channel "VS {{NEXT_VERSION}}" --branch vs{{NEXT_VERSION}} --repo https://github.com/dotnet/msbuild --configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}}` + `darc add-default-channel --channel "VS {{NEXT_VERSION}}" --branch vs{{NEXT_VERSION}} --repo https://github.com/dotnet/msbuild` - [ ] **1.2d** Get the maestro-configuration PR reviewed and merged: {{URL_OF_PHASE1_DARC_PR}} - - [ ] **1.2e** Ping internal "First Responders" Teams channel to get the new `VS {{NEXT_VERSION}}` channel available as a promotion target: {{URL_OF_CHANNEL_PROMOTION_PR}} - [ ] **1.3** Update `.config/git-merge-flow-config.jsonc`: - [ ] **1.3a** Insert `vs{{THIS_RELEASE_VERSION}}` as the last entry before `main` in the merge chain. Add a comment noting the VS/SDK version context. - [ ] **1.3b** **Retire predecessor branches that will no longer be supported.** Remove their `MergeToBranch` entries and rewire the chain to skip them so automation does not open stale forward-merge PRs. \ How to identify a retired branch: - - **SDK releases** — check the lifecycle table at https://learn.microsoft.com/dotnet/core/porting/versioning-sdk-msbuild-vs#lifecycle; any branch tied to an SDK band that is past its support end date is retired. - - **VS releases** — the retired branch is always the version directly preceding the one being released (i.e. `vs{{THIS_RELEASE_VERSION}} - 1`). + - **The combined rule:** a branch paired with both an SDK band and a VS version is retired **only when both lifecycles agree it is out of support**. If only one side says retired but the other is still supported, **keep the branch** — automation must still flow forward-merges so the still-supported lifecycle keeps receiving fixes. + - **SDK lifecycle** — for branches paired with an SDK band, check https://learn.microsoft.com/dotnet/core/porting/versioning-sdk-msbuild-vs#lifecycle. If the paired SDK band is past its support end date, the branch is SDK-retired. + - **VS lifecycle** — check the [VS Servicing Information wiki](https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/27212/Visual-Studio-Servicing-Information). Rule of thumb: the VS support window covers the current release plus two preceding versions, so the first candidate for VS-retirement is `vs{{THIS_RELEASE_VERSION}} - 3` — **always confirm on the wiki**, since servicing exceptions can extend specific versions beyond the rule of thumb. + - **VS-only branches** (not paired with any active SDK band) are retired purely on the VS lifecycle. --- -## Phase 2: Bump Main & Update Pipelines - -> **Trigger**: `vs{{THIS_RELEASE_VERSION}}` branch exists (Phase 1.1 done). Previous release is in insiders stage. - -Create **one PR in `main`** containing all of the following changes: +## Phase 2: DARC Subscription Updates -- [ ] **2.1** `eng/Versions.props`: Update `VersionPrefix` to `{{NEXT_VERSION}}.0` -- [ ] **2.2** `eng/Versions.props`: Update `PackageValidationBaselineVersion` to the last released version (the `{{PREVIOUS_RELEASE_VERSION}}` GA version published to nuget.org). -- [ ] **2.3** If needed, update `CompatibilitySuppressions.xml` files. Run: \ -`dotnet pack MSBuild.Dev.slnf /p:ApiCompatGenerateSuppressionFile=true` \ -See [API compat documentation](https://learn.microsoft.com/en-us/dotnet/fundamentals/apicompat/overview) for details. -- [ ] **2.4** Update [`azure-pipelines/vs-insertion.yml`](../azure-pipelines/vs-insertion.yml): set `AutoInsertTargetBranch` for `vs{{THIS_RELEASE_VERSION}}` → VS `main`. -- [ ] **2.5** Update [`azure-pipelines/vs-insertion-experimental.yml`](../azure-pipelines/vs-insertion-experimental.yml): \ -Add `rel/insiders` and/or `rel/stable` to `TargetBranch` parameter values if not already present. -- [ ] **2.6** Merge branding PR: {{URL_OF_NEXT_VERSION_BRANDING_PR}} - ---- - -## Phase 3: DARC Subscription Updates - -> **Trigger**: Phase 2 branding PR merged (main now has `{{NEXT_VERSION}}` version). +> **Trigger**: `vs{{THIS_RELEASE_VERSION}}` branch exists (Phase 1 complete). \ +> **Why this runs before bumping `main`:** consumers of MSBuild via `main` (notably the VMR) should start receiving next-version bits from the `VS {{NEXT_VERSION}}` channel **the moment `main` is bumped**. Reassigning `main`'s default channel **before** the Phase 3 branding bump means the first `main` build at the new version is already published to the correct channel; otherwise it lands on the now-stale `VS {{THIS_RELEASE_VERSION}}` channel. First, **gather information** (read-only queries — no PR needed): -- [ ] **3.1** Find the SDK main subscription ID to update: \ +- [ ] **2.1** Find the SDK main subscription ID to update: \ `darc get-subscriptions --exact --source-repo https://github.com/dotnet/msbuild --channel "VS {{THIS_RELEASE_VERSION}}"` \ Note the subscription ID for the SDK `main` branch entry. -- [ ] **3.2** Verify release branch channel association: \ +- [ ] **2.2** Verify release branch channel association: \ `darc get-default-channels --source-repo https://github.com/dotnet/msbuild --branch vs{{THIS_RELEASE_VERSION}}` \ -Note whether the association exists (needed for step 3.3d). +Note whether the association exists (needed for step 2.3d). Then, **batch all write operations into one PR** on the [maestro-configuration](https://dev.azure.com/dnceng/internal/_git/maestro-configuration) repo. \ -Use `--configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}}-main-bump` and `--no-pr` on all but the last command: - -- [ ] **3.3** DARC channel/subscription updates: - - [ ] **3.3a** Remove main → old channel mapping: \ - `darc delete-default-channel --repo https://github.com/dotnet/msbuild --branch main --channel "VS {{THIS_RELEASE_VERSION}}" --configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}}-main-bump --no-pr` - - [ ] **3.3b** Associate main with next channel: \ - `darc add-default-channel --channel "VS {{NEXT_VERSION}}" --branch main --repo https://github.com/dotnet/msbuild --configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}}-main-bump --no-pr` - - [ ] **3.3c** Update SDK main subscription to new channel: \ - `darc update-subscription --id --channel "VS {{NEXT_VERSION}}" --configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}}-main-bump --no-pr` - - [ ] **3.3d** If release branch association was missing in 3.2, add it: \ - `darc add-default-channel --channel "VS {{THIS_RELEASE_VERSION}}" --branch vs{{THIS_RELEASE_VERSION}} --repo https://github.com/dotnet/msbuild --configuration-branch release/msbuild-{{THIS_RELEASE_VERSION}}-main-bump --no-pr` - - [ ] **3.3e** _If any subscriptions need fixing (from 3.4–3.6 below), include them here with `--no-pr`._ - - [ ] **3.3f** **Create the PR** — re-run step 3.3b (or whichever was the last write command executed) without `--no-pr` to open the PR on the configuration branch. - - [ ] **3.3g** Get the maestro-configuration PR reviewed and merged: {{URL_OF_PHASE3_DARC_PR}} +Use `--no-pr` on all but the last command. **Do not pass `--configuration-branch release/msbuild-...`** — pushes to `release/`-prefixed branches in the maestro-configuration repo are not permitted; let darc pick its own configuration branch. + +- [ ] **2.3** DARC channel/subscription updates: + - [ ] **2.3a** Remove main → old channel mapping: \ + `darc delete-default-channel --repo https://github.com/dotnet/msbuild --branch main --channel "VS {{THIS_RELEASE_VERSION}}" --no-pr` + - [ ] **2.3b** Associate main with next channel: \ + `darc add-default-channel --channel "VS {{NEXT_VERSION}}" --branch main --repo https://github.com/dotnet/msbuild --no-pr` + - [ ] **2.3c** Update SDK main subscription to new channel: \ + `darc update-subscription --id --channel "VS {{NEXT_VERSION}}" --no-pr` + - [ ] **2.3d** If release branch association was missing in 2.2, add it: \ + `darc add-default-channel --channel "VS {{THIS_RELEASE_VERSION}}" --branch vs{{THIS_RELEASE_VERSION}} --repo https://github.com/dotnet/msbuild --no-pr` + - [ ] **2.3e** **Delete subscriptions for retired branches.** For each branch identified as retired in step 1.3b (apply the same combined SDK+VS rule — do **not** delete subscriptions for a branch that's retired on only one side, since fixes must keep flowing into the still-supported lifecycle), remove its inbound subscriptions and any default channel associations so they don't linger and confuse future `darc get-subscriptions` runs. \ + List them: `darc get-subscriptions --target-repo https://github.com/dotnet/msbuild --target-branch ` \ + Delete each: `darc delete-subscription --id --no-pr` + - [ ] **2.3f** _If the Arcade subscription from 2.4 below is missing or pointed at the wrong channel, include the fix-up here with `--no-pr`._ + - [ ] **2.3g** **Create the PR** — re-run the final write command without `--no-pr` to open the PR on the configuration branch. + - [ ] **2.3h** Get the maestro-configuration PR reviewed and merged: {{URL_OF_PHASE2_DARC_PR}} Verifications (**parallel** — read-only, no ordering dependency): -- [ ] **3.4** Verify the Arcade subscription for `vs{{THIS_RELEASE_VERSION}}`: \ +- [ ] **2.4** Verify the Arcade subscription for `vs{{THIS_RELEASE_VERSION}}`: \ `darc get-subscriptions --exact --target-repo https://github.com/dotnet/msbuild --source-repo https://github.com/dotnet/arcade` - **Every supported branch must have an Arcade subscription** from the matching `.NET Eng` channel (the channel is determined by the .NET band the branch is paired with — e.g. a branch paired with .NET 10 subscribes to `.NET 10 Eng`). -> _Roslyn and NuGet subscription verification intentionally omitted: there is always exactly one Roslyn and NuGet subscription, it targets `main` only, is permanently disabled, and never changes per release — re-verifying it every release adds no signal._ +> _Roslyn and NuGet subscription verification intentionally omitted from the per-release checklist: there is always exactly one Roslyn and one NuGet subscription, each targeting `main` only. Their configuration is managed out-of-band, not as part of the release flow._ + +--- + +## Phase 3: Bump Main & Update Pipelines + +> **Trigger**: Phase 2 DARC updates merged (`main`'s default channel is now `VS {{NEXT_VERSION}}`). + +Create **one PR in `main`** containing all of the following changes: + +- [ ] **3.1** `eng/Versions.props`: Update `VersionPrefix` to `{{NEXT_VERSION}}.0` +- [ ] **3.2** `eng/Versions.props`: Update `PackageValidationBaselineVersion` to `{{PACKAGE_VALIDATION_BASELINE_VERSION}}` (see [How to determine `{{PACKAGE_VALIDATION_BASELINE_VERSION}}`](#how-to-determine-package_validation_baseline_version) in the Inputs section above). +- [ ] **3.3** If the build pipeline fails on API-compat (only then — this step is a fix-up, not a routine action), update `CompatibilitySuppressions.xml` files. Run: \ +`dotnet pack MSBuild.Dev.slnf /p:ApiCompatGenerateSuppressionFile=true` \ +See [API compat documentation](https://learn.microsoft.com/en-us/dotnet/fundamentals/apicompat/overview) for details. _(Verify the exact pipeline-failure signature with the team if you're unsure whether the failure you're seeing should be suppressed vs. fixed at source.)_ +- [ ] **3.4** Update [`azure-pipelines/vs-insertion-experimental.yml`](../azure-pipelines/vs-insertion-experimental.yml): \ +Add `rel/insiders` and/or `rel/stable` to `TargetBranch` parameter values if not already present. +- [ ] **3.5** Merge branding PR: {{URL_OF_NEXT_VERSION_BRANDING_PR}} --- @@ -152,10 +175,9 @@ Move contents of `PublicAPI.Unshipped.txt` → `PublicAPI.Shipped.txt` for all p Use `-DryRun` first to preview. The script adds `release` on the same line as `VersionPrefix` (creates merge conflict for forward-flow) and changes `PreReleaseVersionLabel` from `preview` to `servicing`. \ _If the script says "already stabilized" — skip (idempotent)._ - [ ] **4.3** Create and merge final branding PR to `vs{{THIS_RELEASE_VERSION}}`: {{URL_OF_FINAL_BRANDING_PR}} -- [ ] **4.4** Bootstrap OptProf for `vs{{THIS_RELEASE_VERSION}}`: - - [ ] Run the [official build](https://devdiv.visualstudio.com/DevDiv/_build?definitionId=9434) for `vs{{THIS_RELEASE_VERSION}}` with `Optional OptProfDrop Override` set to main's latest OptProf drop path. _(Find the path in main CI logs: Windows_NT → Build → search for `OptimizationData`.)_ Alternatively, set `SkipApplyOptimizationData` to `true` in Advanced options. - - [ ] Verify that the [OptProf data collection](https://devdiv.visualstudio.com/DevDiv/_build?definitionId=17389) pipeline triggers for `vs{{THIS_RELEASE_VERSION}}`. If not triggered, run manually ('Run pipeline' in upper right). - - [ ] Run the [official build](https://devdiv.visualstudio.com/DevDiv/_build?definitionId=9434) for `vs{{THIS_RELEASE_VERSION}}` with no overrides — OptProf should succeed now. +- [ ] **4.4** Bootstrap OptProf for `vs{{THIS_RELEASE_VERSION}}`. After the final-branding commit (4.3) merges, the [official build](https://devdiv.visualstudio.com/DevDiv/_build?definitionId=9434) is auto-triggered without OptProf data for the new branch and will fail. To work around: + - [ ] **4.4a** **Cancel** the auto-triggered official build for `vs{{THIS_RELEASE_VERSION}}`. + - [ ] **4.4b** **Re-run the official build manually** for `vs{{THIS_RELEASE_VERSION}}` with the OptProf override from `main` — set `Optional OptProfDrop Override` to `main`'s latest OptProf drop path. _(Find the path in main CI logs: Windows_NT → Build → search for `OptimizationData`.)_ - [ ] **4.5** Get M2 or QB approval as necessary per the VS schedule - [ ] **4.6** Babysit the VS insertion PR from `vs{{THIS_RELEASE_VERSION}}` into VS `main` (auto-generated at https://devdiv.visualstudio.com/DevDiv/_git/VS/pullrequests). The final-branded bits must be in VS `main` **before** `{{INSIDERS_SNAP_DATE}}` so they are included when VS snaps to `rel/insiders`: {{URL_OF_VS_INSERTION}} \ The insertion PR contains the inserted package versions — useful for the nuget.org publishing step. @@ -222,7 +244,7 @@ Steps are **mostly parallel** unless noted. - [ ] **5.4** Update `BootstrapSdkVersion` in [`eng/Versions.props`](https://github.com/dotnet/msbuild/blob/main/eng/Versions.props) if a fresh SDK was released. Check https://dotnet.microsoft.com/download/visual-studio-sdks — always verify the details for the targeted .NET version. - [ ] **5.4b** Update `tools.dotnet` in [`global.json`](https://github.com/dotnet/msbuild/blob/main/global.json) to the latest released SDK in the targeted band. `DotNetCliVersion` in `eng/Versions.props` is derived from this and **must** match (see the comment on `DotNetCliVersion`). This bump should happen monthly as new SDKs release. - [ ] **5.5** Verify the overall subscription map is correct — not just for `{{THIS_RELEASE_VERSION}}` but for every still-supported branch: - - [ ] **5.5a** `main` subscriptions point to `VS {{NEXT_VERSION}}` channel (should have been done in Phase 3; confirm): \ + - [ ] **5.5a** `main` subscriptions point to `VS {{NEXT_VERSION}}` channel (should have been done in Phase 2; confirm): \ `darc get-subscriptions --exact --target-repo https://github.com/dotnet/msbuild --target-branch main` - [ ] **5.5b** Every supported `vsXX.Y` branch has an Arcade subscription matching its targeted .NET band, and each supported branch's outbound subscriptions land in the right downstream (e.g. SDK band, VMR). \ Open question (track with Rainer): MSBuild `main` currently flows to *two* downstream targets (VMR and the legacy SDK path) but only one subscription is configured — confirm whether this needs a dual subscription before signing off the release. @@ -236,3 +258,18 @@ Steps are **mostly parallel** unless noted. - [`src/Shared/BuildEnvironmentHelper.cs`](https://github.com/dotnet/msbuild/blob/main/src/Shared/BuildEnvironmentHelper.cs) - [`src/Shared/Constants.cs`](https://github.com/dotnet/msbuild/blob/main/src/Shared/Constants.cs) - [`src/Framework/Telemetry/TelemetryConstants.cs`](https://github.com/dotnet/msbuild/blob/main/src/Framework/Telemetry/TelemetryConstants.cs) + +--- + +## Release Output + +Artifacts produced over the course of the release. Record each URL here as the corresponding phase completes so this issue serves as the single index back into every PR / build / tag that defines `{{THIS_RELEASE_EXACT_VERSION}}`. + +| Artifact | URL | +|---|---| +| Phase 1.2d — maestro-configuration PR (channels for `{{THIS_RELEASE_VERSION}}` / `{{NEXT_VERSION}}`) | {{URL_OF_PHASE1_DARC_PR}} | +| Phase 2.3h — maestro-configuration PR (main subscriptions retargeted to `VS {{NEXT_VERSION}}`, retired-branch cleanup) | {{URL_OF_PHASE2_DARC_PR}} | +| Phase 3.5 — `main` next-version branding PR | {{URL_OF_NEXT_VERSION_BRANDING_PR}} | +| Phase 4.3 — `vs{{THIS_RELEASE_VERSION}}` final branding PR | {{URL_OF_FINAL_BRANDING_PR}} | +| Phase 4.6 — VS insertion PR | {{URL_OF_VS_INSERTION}} | +| Phase 5.3 — GitHub release tag | https://github.com/dotnet/msbuild/releases/tag/v{{THIS_RELEASE_EXACT_VERSION}} | From cc0fb8043167d66257053814e41b17241e2e7af5 Mon Sep 17 00:00:00 2001 From: Veronika Ovsyannikova Date: Thu, 28 May 2026 13:52:15 +0200 Subject: [PATCH 10/10] update --- documentation/release-checklist.md | 74 +++++++++++++----------------- 1 file changed, 32 insertions(+), 42 deletions(-) diff --git a/documentation/release-checklist.md b/documentation/release-checklist.md index be12a48b7e8..494561646ec 100644 --- a/documentation/release-checklist.md +++ b/documentation/release-checklist.md @@ -10,22 +10,22 @@ Fill in these values before starting. Version increments are irregular — they | Placeholder | Description | Value | |---|---|---| -| `{{PREVIOUS_RELEASE_VERSION}}` | Version being replaced as latest (e.g. `18.5`) | | -| `{{THIS_RELEASE_VERSION}}` | Version being released now (e.g. `18.6`) | | +| `{{PREVIOUS_RELEASE_VERSION}}` | Version being replaced as latest | | +| `{{THIS_RELEASE_VERSION}}` | Version being released now | | | `{{THIS_RELEASE_EXACT_VERSION}}` | Full `VersionPrefix` from `eng/Versions.props` on the release branch after final branding (e.g. `18.6.0`). For non-patch releases this is always `{{THIS_RELEASE_VERSION}}.0`. | | -| `{{NEXT_VERSION}}` | Version that main will be bumped to (e.g. `18.7`) | | -| `{{BRANCH_SNAP_DATE}}` | Date we create `vs{{THIS_RELEASE_VERSION}}` from `main` (and, if needed, fast-forward it to the exact `main` commit currently inserted into VS `main`). This is **decided by us**, not read from a wiki — it is the date Phase 1.1 actually runs. | | +| `{{NEXT_VERSION}}` | Version that main will be bumped to | | +| `{{BRANCH_SNAP_DATE}}` | Date we create `vs{{THIS_RELEASE_VERSION}}` from `main`. | | | `{{INSIDERS_SNAP_DATE}}` | Date VS snaps `main` → `rel/insiders`. Final-branded MSBuild must be in VS `main` **before** this date. From [VS-Dates wiki](https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/49807/VS-Dates) | | | `{{STABLE_SNAP_DATE}}` | Date VS snaps `rel/insiders` → `rel/stable`. From [VS-Dates wiki](https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/49807/VS-Dates) | | | `{{VS_SHIP_DATE}}` | Date VS ships publicly (GA). Post-GA tasks (nuget.org, docs) happen after this. | | -| `{{PACKAGE_VALIDATION_BASELINE_VERSION}}` | Latest `{{THIS_RELEASE_VERSION}}.0-preview-NNNNN-NN` MSBuild build produced from the `vs{{THIS_RELEASE_VERSION}}` branch — used as the ApiCompat baseline. See [How to determine `{{PACKAGE_VALIDATION_BASELINE_VERSION}}`](#how-to-determine-package_validation_baseline_version) below. | | +| `{{PACKAGE_VALIDATION_BASELINE_VERSION}}` | Latest `{{THIS_RELEASE_VERSION}}.0-preview-NNNNN-NN` MSBuild build whose source commit in in history of `vs{{THIS_RELEASE_VERSION}}` branch. Used as the ApiCompat baseline for the bumped `main`. See [How to determine `{{PACKAGE_VALIDATION_BASELINE_VERSION}}`](#how-to-determine-package_validation_baseline_version) below. | | ### How to determine `{{PACKAGE_VALIDATION_BASELINE_VERSION}}` **The value is the latest `{{THIS_RELEASE_VERSION}}.0-preview-NNNNN-NN` MSBuild package that is both:** 1. **Published on the public [dotnet-tools feed](https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-tools)** — this is the feed `darc publish` pushes 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 `vs{{THIS_RELEASE_VERSION}}` commit prior to stabilization, or the `main` commit `vs{{THIS_RELEASE_VERSION}}` was branched from. +2. **Produced from a commit reachable from `vs{{THIS_RELEASE_VERSION}}`** — i.e. a `vs{{THIS_RELEASE_VERSION}}` commit prior to [stabilization (Phase 4.2)](#phase-4-final-branding--vs-insertion), or the `main` commit `vs{{THIS_RELEASE_VERSION}}` was branched from. **Two tempting wrong answers — and why they're wrong:** @@ -37,16 +37,13 @@ Fill in these values before starting. Version increments are irregular — they **Procedure:** 1. Open [MSBuild official build pipeline 9434](https://devdiv.visualstudio.com/DevDiv/_build?definitionId=9434). -2. Filter runs to branch `vs{{THIS_RELEASE_VERSION}}`. Find the run that final-branded the release (it produces `{{THIS_RELEASE_VERSION}}.X` — no `-preview-` — corresponding to the commit that ran `Stabilize-Release.ps1`). Anything successful **before** that on `vs{{THIS_RELEASE_VERSION}}` is a candidate. +2. Filter runs to branch `vs{{THIS_RELEASE_VERSION}}`. Find the run that final-branded the release (it produces `{{THIS_RELEASE_VERSION}}.X` — no `-preview-` — corresponding to the commit that ran `Stabilize-Release.ps1`; see [Phase 4.2 + 4.3](#phase-4-final-branding--vs-insertion)). Anything successful **before** that on `vs{{THIS_RELEASE_VERSION}}` is a candidate. 3. If `vs{{THIS_RELEASE_VERSION}}` has no successful pre-stabilization preview runs (common — the branch sees little churn before stabilization), fall back to the most recent successful `main` run whose commit is the branch-point ancestor: \ `git merge-base origin/main origin/vs{{THIS_RELEASE_VERSION}}` gives the SHA — find a `main` run at or before that SHA in pipeline 9434. 4. Read the package version from that run's `Pack` step output: `{{THIS_RELEASE_VERSION}}.0-preview-NNNNN-NN` (example: `18.7.0-preview-26230-02`). - - **Decoding tip** (lets you cross-reference feed ↔ build at a glance): `NNNNN` = `YY[Month×50+Day]`, `NN` = revision-of-day. So `26230-02` ↔ build `20260430.02` (year 26, April 30 → 4×50+30 = 230, 2nd run of the day). 5. Verify the exact version is on the [dotnet-tools feed](https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-tools) (search `Microsoft.Build`). If not, fall back to the next-older eligible run. 6. Use that version. Do **not** include any `+sha` suffix. -**Known gap** (track in your release tracking issue): the procedure is manual because `dotnet-tools` contains both pre- and post-branch-point `main` builds under identical `{{THIS_RELEASE_VERSION}}.0-preview-*` branding. If/when publishing is fixed so `main` builds never carry stale branding, this collapses to "latest `{{THIS_RELEASE_VERSION}}.0-preview-*` on `dotnet-tools`" — programmatically queryable. - **Derived values** (do not edit — computed from inputs): - Release branch: `vs{{THIS_RELEASE_VERSION}}` - DARC channel: `VS {{THIS_RELEASE_VERSION}}` @@ -61,7 +58,7 @@ Fill in these values before starting. Version increments are irregular — they - [ ] Confirm `eng/Versions.props` on `main` has `VersionPrefix` = `{{THIS_RELEASE_VERSION}}.0` — if not, the inputs are wrong - [ ] Confirm branch `vs{{THIS_RELEASE_VERSION}}` does **not** already exist — if it does, this release was already started - [ ] Confirm DARC channel `VS {{THIS_RELEASE_VERSION}}` exists: \ - `darc get-channels` _(filter the output for the channel name — there is no `--name` flag on `darc get-channels`)_ \ + `darc get-channels`\ If missing, it should have been created during the previous release (Phase 1.2b "create next channel" step). Create it now: `darc add-channel --name "VS {{THIS_RELEASE_VERSION}}"` - [ ] Create this tracking issue in dotnet/msbuild with all `{{PLACEHOLDERS}}` replaced - [ ] As phases complete, record artifact URLs in the **Release Output** table at the bottom of this checklist. @@ -80,16 +77,16 @@ Steps are **sequential** — complete in order. - _If branched too early_ (main has commits that shouldn't be in the release): fast-forward the branch to the correct commit (the one currently inserted into VS main): \ `git push upstream :refs/heads/vs{{THIS_RELEASE_VERSION}}` - [ ] **1.2** DARC configuration — batch all channel/mapping changes into **one PR** on the [maestro-configuration](https://dev.azure.com/dnceng/internal/_git/maestro-configuration) repo. \ -Use `--no-pr` on all but the last command. **Do not pass `--configuration-branch release/msbuild-...`** — pushes to `release/`-prefixed branches in the maestro-configuration repo are not permitted; let darc pick its own configuration branch. +Use `--configuration-branch msbuild-{{THIS_RELEASE_VERSION}}` on every command and `--no-pr` on all but the last: - [ ] **1.2a** Ensure branch-to-channel association exists: \ First check: `darc get-default-channels --channel "VS {{THIS_RELEASE_VERSION}}" --branch vs{{THIS_RELEASE_VERSION}} --source-repo https://github.com/dotnet/msbuild` \ If `No matching channels were found.`: \ - `darc add-default-channel --channel "VS {{THIS_RELEASE_VERSION}}" --branch vs{{THIS_RELEASE_VERSION}} --repo https://github.com/dotnet/msbuild --no-pr` + `darc add-default-channel --channel "VS {{THIS_RELEASE_VERSION}}" --branch vs{{THIS_RELEASE_VERSION}} --repo https://github.com/dotnet/msbuild --configuration-branch msbuild-{{THIS_RELEASE_VERSION}} --no-pr` - [ ] **1.2b** Create DARC channel for **next** release: \ - `darc add-channel --name "VS {{NEXT_VERSION}}" --no-pr` \ + `darc add-channel --name "VS {{NEXT_VERSION}}" --configuration-branch msbuild-{{THIS_RELEASE_VERSION}} --no-pr` \ _(If channel already exists, this is a no-op.)_ - [ ] **1.2c** Pre-create default channel mapping for the **next** release branch (**last command — omit `--no-pr` to create the PR**): \ - `darc add-default-channel --channel "VS {{NEXT_VERSION}}" --branch vs{{NEXT_VERSION}} --repo https://github.com/dotnet/msbuild` + `darc add-default-channel --channel "VS {{NEXT_VERSION}}" --branch vs{{NEXT_VERSION}} --repo https://github.com/dotnet/msbuild --configuration-branch msbuild-{{THIS_RELEASE_VERSION}}` - [ ] **1.2d** Get the maestro-configuration PR reviewed and merged: {{URL_OF_PHASE1_DARC_PR}} - [ ] **1.3** Update `.config/git-merge-flow-config.jsonc`: - [ ] **1.3a** Insert `vs{{THIS_RELEASE_VERSION}}` as the last entry before `main` in the merge chain. Add a comment noting the VS/SDK version context. @@ -117,20 +114,20 @@ Note the subscription ID for the SDK `main` branch entry. Note whether the association exists (needed for step 2.3d). Then, **batch all write operations into one PR** on the [maestro-configuration](https://dev.azure.com/dnceng/internal/_git/maestro-configuration) repo. \ -Use `--no-pr` on all but the last command. **Do not pass `--configuration-branch release/msbuild-...`** — pushes to `release/`-prefixed branches in the maestro-configuration repo are not permitted; let darc pick its own configuration branch. +Use `--configuration-branch msbuild-{{THIS_RELEASE_VERSION}}-main-bump` and `--no-pr` on all but the last command: - [ ] **2.3** DARC channel/subscription updates: - [ ] **2.3a** Remove main → old channel mapping: \ - `darc delete-default-channel --repo https://github.com/dotnet/msbuild --branch main --channel "VS {{THIS_RELEASE_VERSION}}" --no-pr` + `darc delete-default-channel --repo https://github.com/dotnet/msbuild --branch main --channel "VS {{THIS_RELEASE_VERSION}}" --configuration-branch msbuild-{{THIS_RELEASE_VERSION}} --no-pr` - [ ] **2.3b** Associate main with next channel: \ - `darc add-default-channel --channel "VS {{NEXT_VERSION}}" --branch main --repo https://github.com/dotnet/msbuild --no-pr` + `darc add-default-channel --channel "VS {{NEXT_VERSION}}" --branch main --repo https://github.com/dotnet/msbuild --configuration-branch msbuild-{{THIS_RELEASE_VERSION}} --no-pr` - [ ] **2.3c** Update SDK main subscription to new channel: \ - `darc update-subscription --id --channel "VS {{NEXT_VERSION}}" --no-pr` + `darc update-subscription --id --channel "VS {{NEXT_VERSION}}" --configuration-branch msbuild-{{THIS_RELEASE_VERSION}} --no-pr` - [ ] **2.3d** If release branch association was missing in 2.2, add it: \ - `darc add-default-channel --channel "VS {{THIS_RELEASE_VERSION}}" --branch vs{{THIS_RELEASE_VERSION}} --repo https://github.com/dotnet/msbuild --no-pr` - - [ ] **2.3e** **Delete subscriptions for retired branches.** For each branch identified as retired in step 1.3b (apply the same combined SDK+VS rule — do **not** delete subscriptions for a branch that's retired on only one side, since fixes must keep flowing into the still-supported lifecycle), remove its inbound subscriptions and any default channel associations so they don't linger and confuse future `darc get-subscriptions` runs. \ + `darc add-default-channel --channel "VS {{THIS_RELEASE_VERSION}}" --branch vs{{THIS_RELEASE_VERSION}} --repo https://github.com/dotnet/msbuild --configuration-branch msbuild-{{THIS_RELEASE_VERSION}} --no-pr` + - [ ] **2.3e** **Delete subscriptions for retired branches.** For each branch identified as retired in step 1.3b (apply the same combined SDK+VS rule — do **not** delete subscriptions for a branch that's retired on only one side, since fixes must keep flowing into the still-supported lifecycle), remove its inbound subscriptions and any default channel associations. List them: `darc get-subscriptions --target-repo https://github.com/dotnet/msbuild --target-branch ` \ - Delete each: `darc delete-subscription --id --no-pr` + Delete each: `darc delete-subscription --id --configuration-branch msbuild-{{THIS_RELEASE_VERSION}} --no-pr` - [ ] **2.3f** _If the Arcade subscription from 2.4 below is missing or pointed at the wrong channel, include the fix-up here with `--no-pr`._ - [ ] **2.3g** **Create the PR** — re-run the final write command without `--no-pr` to open the PR on the configuration branch. - [ ] **2.3h** Get the maestro-configuration PR reviewed and merged: {{URL_OF_PHASE2_DARC_PR}} @@ -140,7 +137,7 @@ Verifications (**parallel** — read-only, no ordering dependency): - [ ] **2.4** Verify the Arcade subscription for `vs{{THIS_RELEASE_VERSION}}`: \ `darc get-subscriptions --exact --target-repo https://github.com/dotnet/msbuild --source-repo https://github.com/dotnet/arcade` - **Every supported branch must have an Arcade subscription** from the matching `.NET Eng` channel (the channel is determined by the .NET band the branch is paired with — e.g. a branch paired with .NET 10 subscribes to `.NET 10 Eng`). -> _Roslyn and NuGet subscription verification intentionally omitted from the per-release checklist: there is always exactly one Roslyn and one NuGet subscription, each targeting `main` only. Their configuration is managed out-of-band, not as part of the release flow._ +> _Roslyn and NuGet subscription verification intentionally omitted from the per-release checklist: there is always exactly one Roslyn and one NuGet subscription, each targeting `main` only._ --- @@ -154,10 +151,8 @@ Create **one PR in `main`** containing all of the following changes: - [ ] **3.2** `eng/Versions.props`: Update `PackageValidationBaselineVersion` to `{{PACKAGE_VALIDATION_BASELINE_VERSION}}` (see [How to determine `{{PACKAGE_VALIDATION_BASELINE_VERSION}}`](#how-to-determine-package_validation_baseline_version) in the Inputs section above). - [ ] **3.3** If the build pipeline fails on API-compat (only then — this step is a fix-up, not a routine action), update `CompatibilitySuppressions.xml` files. Run: \ `dotnet pack MSBuild.Dev.slnf /p:ApiCompatGenerateSuppressionFile=true` \ -See [API compat documentation](https://learn.microsoft.com/en-us/dotnet/fundamentals/apicompat/overview) for details. _(Verify the exact pipeline-failure signature with the team if you're unsure whether the failure you're seeing should be suppressed vs. fixed at source.)_ -- [ ] **3.4** Update [`azure-pipelines/vs-insertion-experimental.yml`](../azure-pipelines/vs-insertion-experimental.yml): \ -Add `rel/insiders` and/or `rel/stable` to `TargetBranch` parameter values if not already present. -- [ ] **3.5** Merge branding PR: {{URL_OF_NEXT_VERSION_BRANDING_PR}} +See [API compat documentation](https://learn.microsoft.com/en-us/dotnet/fundamentals/apicompat/overview) for details. +- [ ] **3.4** Merge branding PR: {{URL_OF_NEXT_VERSION_BRANDING_PR}} --- @@ -178,7 +173,8 @@ _If the script says "already stabilized" — skip (idempotent)._ - [ ] **4.4** Bootstrap OptProf for `vs{{THIS_RELEASE_VERSION}}`. After the final-branding commit (4.3) merges, the [official build](https://devdiv.visualstudio.com/DevDiv/_build?definitionId=9434) is auto-triggered without OptProf data for the new branch and will fail. To work around: - [ ] **4.4a** **Cancel** the auto-triggered official build for `vs{{THIS_RELEASE_VERSION}}`. - [ ] **4.4b** **Re-run the official build manually** for `vs{{THIS_RELEASE_VERSION}}` with the OptProf override from `main` — set `Optional OptProfDrop Override` to `main`'s latest OptProf drop path. _(Find the path in main CI logs: Windows_NT → Build → search for `OptimizationData`.)_ -- [ ] **4.5** Get M2 or QB approval as necessary per the VS schedule +- [ ] **4.5** Get M2 or QB approval as necessary per the VS schedule. \ +_**Only required if we are behind the VS schedule** — i.e. the insertion didn't land in VS `main` before `{{INSIDERS_SNAP_DATE}}` (4.6 was missed) and a milestone-gate approval is now needed. If the insertion made the schedule, **skip this step**._ - [ ] **4.6** Babysit the VS insertion PR from `vs{{THIS_RELEASE_VERSION}}` into VS `main` (auto-generated at https://devdiv.visualstudio.com/DevDiv/_git/VS/pullrequests). The final-branded bits must be in VS `main` **before** `{{INSIDERS_SNAP_DATE}}` so they are included when VS snaps to `rel/insiders`: {{URL_OF_VS_INSERTION}} \ The insertion PR contains the inserted package versions — useful for the nuget.org publishing step. @@ -205,11 +201,11 @@ Steps are **mostly parallel** unless noted. - [ ] **5.1** Push packages to nuget.org. - > **How publishing works:** We don't push packages ourselves. We hand a link to the **Shipping** artifacts of the official build to the dnceng release team, and they push to nuget.org. Searching past mail for the subject _"Publish MSBuild {{THIS_RELEASE_VERSION}} to NuGet.org"_ will surface the contact and template; do **not** hard-code the contact's name or email in this checklist — internal ownership rotates and we don't want individual addresses exposed in a public GitHub doc. + > **How publishing works:** We don't push packages ourselves. We hand a link to the **Shipping** artifacts of the official build to the dnceng release team, and they push to nuget.org. Searching past mail for the subject _"Publish MSBuild {{THIS_RELEASE_VERSION}} to NuGet.org" for the template. - - [ ] **5.1a** Determine the exact MSBuild version that actually shipped to customers — **do not trust `VersionPrefix` in the release branch by itself**, it has been misleading in past releases. - - **If this release is coupled with an SDK release: use the SDK as the source of truth** — it has the highest fidelity, particularly for security-only patches where only some intervals get bumped. Look up the MSBuild version baked into the shipped SDK build. - - Otherwise: look at the MSBuild version inserted into the corresponding VS build. Note this version differs in non-obvious ways between VS major/minor versions, so confirm against the actual VS insertion PR. + - [ ] **5.1a** Determine the exact MSBuild version that actually shipped to customers. + - **If this release is coupled with an SDK release: use the SDK as the source of truth**. Look up the MSBuild version baked into the shipped SDK build. + - Otherwise: look at the MSBuild version inserted into the corresponding VS build. Confirm against the actual VS insertion PR. - [ ] **5.1b** In the [MSBuild official build pipeline](https://devdiv.visualstudio.com/DevDiv/_build?definitionId=9434), filter to the `vs{{THIS_RELEASE_VERSION}}` branch and locate the build whose output version matches the one identified in 5.1a (e.g. `{{THIS_RELEASE_EXACT_VERSION}}`, such as `18.6.3`). - [ ] **5.1c** From that build, open the **Publish Artifacts** step and grab the link to the **`artifacts-shipping`** drop. Verify the Shipping folder contains all of: - `Microsoft.Build.Utilities.Core.{{THIS_RELEASE_EXACT_VERSION}}.nupkg` @@ -219,7 +215,7 @@ Steps are **mostly parallel** unless noted. - `Microsoft.Build.Tasks.Core.{{THIS_RELEASE_EXACT_VERSION}}.nupkg` - `Microsoft.NET.StringTools.{{THIS_RELEASE_EXACT_VERSION}}.nupkg` - `Microsoft.Build.Templates.{{THIS_RELEASE_EXACT_VERSION}}.nupkg` - - [ ] **5.1d** Email the dnceng release team (use the saved _"Publish MSBuild ... to NuGet.org"_ template from your sent mail) with the `artifacts-shipping` link from 5.1c and ask them to publish to nuget.org. Track the reply until publication is confirmed. + - [ ] **5.1d** Email the dnceng release team with the `artifacts-shipping` link from 5.1c and ask them to publish to nuget.org. - [ ] **5.2** Publish docs @@ -231,9 +227,7 @@ Steps are **mostly parallel** unless noted. - [ ] **5.3a** **Precondition — confirm the previous release tag exists on `upstream`.** \ `git fetch upstream --tags && git tag --list 'v{{PREVIOUS_RELEASE_EXACT_VERSION}}'` \ If the tag is missing (e.g. the previous release was never tagged), create and push it **first**. - - [ ] **5.3b** **Identify the commit to tag.** It is **not always** the final-branding commit from 4.3 — it must be the commit whose bits **actually shipped** in `{{THIS_RELEASE_EXACT_VERSION}}`. \ - If a hotfix was applied to `vs{{THIS_RELEASE_VERSION}}` after final branding and that fix was inserted into the VS build that shipped, tag **that** commit instead. \ - To find it: cross-reference the SHA from the **VS insertion PR that actually shipped** (the package version listed there must equal `{{THIS_RELEASE_EXACT_VERSION}}` from 5.1a) with the commit history on `vs{{THIS_RELEASE_VERSION}}`. + - [ ] **5.3b** **Identify the commit to tag.** It is the source commit of the build identified in **5.1b** (the build that produced `{{THIS_RELEASE_EXACT_VERSION}}`). Find the SHA in that build run's "Source version" field on the pipeline page. - [ ] **5.3c** Tag this release and push: ``` git checkout @@ -242,12 +236,8 @@ Steps are **mostly parallel** unless noted. ``` - [ ] **5.3d** Create release at https://github.com/dotnet/msbuild/releases/new — use `Generate Release Notes` to prepopulate. - [ ] **5.4** Update `BootstrapSdkVersion` in [`eng/Versions.props`](https://github.com/dotnet/msbuild/blob/main/eng/Versions.props) if a fresh SDK was released. Check https://dotnet.microsoft.com/download/visual-studio-sdks — always verify the details for the targeted .NET version. -- [ ] **5.4b** Update `tools.dotnet` in [`global.json`](https://github.com/dotnet/msbuild/blob/main/global.json) to the latest released SDK in the targeted band. `DotNetCliVersion` in `eng/Versions.props` is derived from this and **must** match (see the comment on `DotNetCliVersion`). This bump should happen monthly as new SDKs release. -- [ ] **5.5** Verify the overall subscription map is correct — not just for `{{THIS_RELEASE_VERSION}}` but for every still-supported branch: - - [ ] **5.5a** `main` subscriptions point to `VS {{NEXT_VERSION}}` channel (should have been done in Phase 2; confirm): \ - `darc get-subscriptions --exact --target-repo https://github.com/dotnet/msbuild --target-branch main` - - [ ] **5.5b** Every supported `vsXX.Y` branch has an Arcade subscription matching its targeted .NET band, and each supported branch's outbound subscriptions land in the right downstream (e.g. SDK band, VMR). \ - Open question (track with Rainer): MSBuild `main` currently flows to *two* downstream targets (VMR and the legacy SDK path) but only one subscription is configured — confirm whether this needs a dual subscription before signing off the release. +- [ ] **5.4b** Update `tools.dotnet` in [`global.json`](https://github.com/dotnet/msbuild/blob/main/global.json) to the latest released SDK in the targeted band. +- [ ] **5.5** Verify the overall subscription map across **every still-supported branch** — each `vsXX.Y` branch has an Arcade subscription matching its targeted .NET band, and each supported branch's outbound subscriptions land in the right downstream (e.g. SDK band, VMR). \ - [ ] **5.6** Review this tracking issue for any process deviations. If the process changed, create a PR to update `documentation/release-checklist.md` with the improvements. ---