Skip to content

Commit 41298a6

Browse files
Add Stabilize-Release.ps1 script for release process
Co-authored-by: GitHub Copilot <175728472+github-copilot[bot]@users.noreply.github.com>
1 parent 149f796 commit 41298a6

File tree

3 files changed

+100
-1
lines changed

3 files changed

+100
-1
lines changed

documentation/release-checklist.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ if it is not, `darc add-default-channel --channel "VS {{THIS_RELEASE_VERSION}}"
8888

8989
### Final branding
9090
- [ ] Prepare final branding PR for `vs{{THIS_RELEASE_VERSION}}`: {{URL_OF_FINAL_BRANDING_PR}} \
91-
Edit Version.props file - add `<DotNetFinalVersionKind>release</DotNetFinalVersionKind>` as a suffix (on same line! - to intentionaly make it merge conflict on flows to main) after the `VersionPrefix` \
91+
Run `scripts/Stabilize-Release.ps1` to update `eng/Versions.props` (adds `<DotNetFinalVersionKind>release</DotNetFinalVersionKind>` on same line as `VersionPrefix` and changes `PreReleaseVersionLabel` to `servicing`). Use `-DryRun` to preview changes. \
9292
e.g.: #11130, #10697
9393
- [ ] Merge final branding to `vs{{THIS_RELEASE_VERSION}}` branch
9494
- [ ] Update perfstar MSBuild insertions configuration: [example PR](https://dev.azure.com/devdiv/DevDiv/_git/dotnet-perfstar/pullrequest/522843): {{URL_OF_PERFSTAR_PR}}

documentation/release.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ This is a description of the steps required to release MSBuild. It is **incomple
66

77
To produce packages without a `-prerelease` suffix, we need to specify `<DotNetFinalVersionKind>release</DotNetFinalVersionKind>` (see the [Arcade versioning docs]). This is ideally done on the same line as the version specification so that it causes a Git merge conflict when merging to the next release's branch. See [#6902](https://github.com/dotnet/msbuild/pull/6902) for an example.
88

9+
Run `scripts/Stabilize-Release.ps1` to automate this process. The script modifies `eng/Versions.props` to add `DotNetFinalVersionKind` and change `PreReleaseVersionLabel` from `preview` to `servicing`. Use `-DryRun` to preview changes before applying them.
10+
911
[Arcade versioning docs]: https://github.com/dotnet/arcade/blob/31cecde14e1512ecf60d2d8afb71fd240919f4a8/Documentation/CorePackages/Versioning.md
1012

1113
## Public API

scripts/Stabilize-Release.ps1

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<#
2+
.SYNOPSIS
3+
Performs the stabilization portion of the MSBuild release process.
4+
5+
.DESCRIPTION
6+
This script modifies eng/Versions.props to:
7+
1. Add <DotNetFinalVersionKind>release</DotNetFinalVersionKind> on the same line as VersionPrefix
8+
(to create a merge conflict in forward-flow, as per release documentation)
9+
2. Change PreReleaseVersionLabel from 'preview' to 'servicing'
10+
11+
See documentation/release.md and documentation/release-checklist.md for details.
12+
13+
.PARAMETER DryRun
14+
If specified, shows what changes would be made without actually modifying the file.
15+
16+
.EXAMPLE
17+
.\Stabilize-Release.ps1
18+
Performs the stabilization changes to eng/Versions.props.
19+
20+
.EXAMPLE
21+
.\Stabilize-Release.ps1 -DryRun
22+
Shows what changes would be made without modifying any files.
23+
#>
24+
25+
[CmdletBinding()]
26+
param(
27+
[switch]$DryRun
28+
)
29+
30+
$ErrorActionPreference = 'Stop'
31+
32+
# Find repo root by looking for eng/Versions.props
33+
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
34+
$repoRoot = Split-Path -Parent $scriptDir
35+
36+
$versionsPropsPath = Join-Path $repoRoot 'eng\Versions.props'
37+
38+
if (-not (Test-Path $versionsPropsPath)) {
39+
Write-Error "Could not find eng/Versions.props. Please run this script from the repository root or scripts directory."
40+
exit 1
41+
}
42+
43+
Write-Host "Processing: $versionsPropsPath" -ForegroundColor Cyan
44+
45+
$content = Get-Content $versionsPropsPath -Raw
46+
47+
# Pattern 1: Add DotNetFinalVersionKind on the same line as VersionPrefix
48+
# Match: <VersionPrefix>X.Y.Z</VersionPrefix>
49+
# Replace with: <VersionPrefix>X.Y.Z</VersionPrefix><DotNetFinalVersionKind>release</DotNetFinalVersionKind><!-- Keep next to VersionPrefix to create a conflict in forward-flow -->
50+
$versionPrefixPattern = '(<VersionPrefix>[^<]+</VersionPrefix>)(\s*\r?\n)'
51+
52+
if ($content -match '<DotNetFinalVersionKind>release</DotNetFinalVersionKind>') {
53+
Write-Error "DotNetFinalVersionKind is already set to 'release'. Has stabilization already been done?"
54+
exit 1
55+
} elseif ($content -match $versionPrefixPattern) {
56+
$newVersionPrefixLine = '$1<DotNetFinalVersionKind>release</DotNetFinalVersionKind><!-- Keep next to VersionPrefix to create a conflict in forward-flow -->$2'
57+
$content = $content -replace $versionPrefixPattern, $newVersionPrefixLine
58+
Write-Host " Added DotNetFinalVersionKind=release on VersionPrefix line." -ForegroundColor Green
59+
} else {
60+
Write-Error "Could not find VersionPrefix element in expected format. Expected pattern like: <VersionPrefix>X.Y.Z</VersionPrefix>"
61+
exit 1
62+
}
63+
64+
# Pattern 2: Change PreReleaseVersionLabel from 'preview' to 'servicing'
65+
# Match: <PreReleaseVersionLabel>preview</PreReleaseVersionLabel>
66+
# Replace with: <PreReleaseVersionLabel>servicing</PreReleaseVersionLabel>
67+
$preReleasePattern = '<PreReleaseVersionLabel>preview</PreReleaseVersionLabel>'
68+
69+
if ($content -match '<PreReleaseVersionLabel>servicing</PreReleaseVersionLabel>') {
70+
Write-Error "PreReleaseVersionLabel is already 'servicing'. Has stabilization already been done?"
71+
exit 1
72+
} elseif ($content -match $preReleasePattern) {
73+
$content = $content -replace $preReleasePattern, '<PreReleaseVersionLabel>servicing</PreReleaseVersionLabel>'
74+
Write-Host " Changed PreReleaseVersionLabel from 'preview' to 'servicing'." -ForegroundColor Green
75+
} else {
76+
Write-Error "Could not find PreReleaseVersionLabel with value 'preview'. Current value may not be 'preview'."
77+
exit 1
78+
}
79+
80+
# Extract version for commit message (e.g., "18.4" from "18.4.0")
81+
$versionForCommit = ""
82+
if ($content -match '<VersionPrefix>(\d+\.\d+)\.\d+</VersionPrefix>') {
83+
$versionForCommit = $Matches[1]
84+
}
85+
86+
if ($DryRun) {
87+
Write-Host "`n=== DRY RUN - No changes written ===" -ForegroundColor Magenta
88+
Write-Host "`nResulting content of eng/Versions.props (first 30 lines):" -ForegroundColor Cyan
89+
$content -split "`n" | Select-Object -First 30 | ForEach-Object { Write-Host $_ }
90+
} else {
91+
Set-Content -Path $versionsPropsPath -Value $content -NoNewline
92+
Write-Host "`nStabilization complete. Changes written to: $versionsPropsPath" -ForegroundColor Green
93+
Write-Host "`nNext steps:" -ForegroundColor Cyan
94+
Write-Host " 1. Review the changes: git diff eng/Versions.props"
95+
Write-Host " 2. Commit: git commit -am 'Stable branding for $versionForCommit release'"
96+
Write-Host " 3. Create PR to the release branch (e.g., vs$versionForCommit)"
97+
}

0 commit comments

Comments
 (0)