Skip to content

Commit f4fb086

Browse files
PureWeengithub-actions[bot]Copilot
authored
Add preview/RC milestone support with release branch detection (dotnet#34999)
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary Follow-up to dotnet#34686. Adds preview/RC milestone support and release branch detection to the milestone drift fixer. ## Problem PRs merged to \`net11.0\` were not being milestoned because \`Versions.props\` on that branch always has \`PreReleaseVersionIteration=1\` regardless of which preview the PR actually ships in. The iteration is only bumped on release branches. ## Solution ### Release Branch Detection (Primary) New detection step checks release branches first using \`merge-base --is-ancestor\`. For each PR, it finds the **earliest** release branch containing the merge commit: | Release Branch | Milestone | |---|---| | \`release/10.0.1xx\` | \`.NET 10.0 GA\` | | \`release/10.0.1xx-sr5\` | \`.NET 10 SR5\` | | \`release/11.0.1xx-preview1\` | \`.NET 11.0-preview1\` | | \`release/11.0.1xx-preview3\` | \`.NET 11.0-preview3\` | | \`release/12.0.1xx-rc1\` | \`.NET 12.0-rc1\` | ### Detection Order 1. **Explicit \`-Tag\`** — if provided 2. **Release branches** — \`merge-base --is-ancestor\` against \`release/{Major}.0.1xx-*\` branches, earliest match wins 3. **Versions.props** at merge commit — fallback for PRs not yet on any release branch 4. **Tag range search** — last resort ### Preview/RC Milestone Mapping \`ConvertTo-Milestone\` now accepts optional pre-release label and iteration: | Input | Milestone | |---|---| | \`11.0.0 + preview + 3\` | \`.NET 11.0-preview3\` | | \`12.0.0 + rc + 1\` | \`.NET 12.0-rc1\` | | \`10.0.60\` (stable) | \`.NET 10 SR6\` (unchanged) | ## Validated Results | PR | Base | Current Milestone | Script Result | Method | |---|---|---|---|---| | dotnet#33524 | net11.0 | .NET 11.0-preview1 | .NET 11.0-preview1 ✅ | Release branch | | dotnet#33233 | net11.0 | .NET 11.0-preview1 | .NET 11.0-preview1 ✅ | Release branch | | dotnet#30132 | net11.0 | .NET 11.0-preview3 | .NET 11.0-preview3 ✅ | Release branch | | dotnet#33834 | net11.0 | .NET 11.0-preview3 | .NET 11.0-preview3 ✅ | Release branch | | dotnet#34214 | net11.0 | .NET 11.0-preview2 | .NET 11.0-preview3 ✅ | Release branch (drift caught!) | | dotnet#34945 | net11.0 | .NET 11.0-preview4 | preview1 (fallback) | Versions.props (no p4 branch yet) | | dotnet#34620 | main | .NET 10 SR6 | .NET 10 SR6 ✅ | Release branch | | dotnet#34047 | main | .NET 10 SR4.1 | .NET 10 SR5 ✅ | Release branch (drift caught!) | PR dotnet#34214 is a real drift example: milestoned preview2 by a human, but actually on the preview3 release branch. ## Test Suite 88 Pester tests (11 new): - 6 for \`ConvertTo-Milestone\` preview/RC mapping - 5 for \`ConvertBranchToMilestone\` (GA, SR, preview, RC, non-release) --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 3c06583 commit f4fb086

File tree

3 files changed

+260
-40
lines changed

3 files changed

+260
-40
lines changed

.github/scripts/Fix-MilestoneDrift.Tests.ps1

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,21 @@ Describe 'ConvertTo-Milestone' {
5454
) {
5555
ConvertTo-Milestone $Tag | Should -BeNullOrEmpty
5656
}
57+
58+
It 'maps preview "<Tag>" with label "<Label>" iter <Iter> to "<Expected>"' -ForEach @(
59+
@{ Tag = '11.0.0'; Label = 'preview'; Iter = 1; Expected = '.NET 11.0-preview1' }
60+
@{ Tag = '11.0.0'; Label = 'preview'; Iter = 3; Expected = '.NET 11.0-preview3' }
61+
@{ Tag = '11.0.0'; Label = 'preview'; Iter = 7; Expected = '.NET 11.0-preview7' }
62+
@{ Tag = '12.0.0'; Label = 'rc'; Iter = 1; Expected = '.NET 12.0-rc1' }
63+
@{ Tag = '12.0.0'; Label = 'rc'; Iter = 2; Expected = '.NET 12.0-rc2' }
64+
) {
65+
ConvertTo-Milestone $Tag $Label $Iter | Should -Be $Expected
66+
}
67+
68+
It 'maps to GA when no pre-release label' {
69+
ConvertTo-Milestone '11.0.0' $null 0 | Should -Be '.NET 11.0 GA'
70+
ConvertTo-Milestone '11.0.0' | Should -Be '.NET 11.0 GA'
71+
}
5772
}
5873

5974
Describe 'Test-MilestoneMatch' {
@@ -157,11 +172,12 @@ Describe 'Find-PreviousTag' {
157172
'10.0.0', '10.0.1', '10.0.10', '10.0.11',
158173
'10.0.20', '10.0.30', '10.0.31',
159174
'10.0.40', '10.0.41', '10.0.50',
160-
'9.0.82', '9.0.90'
175+
'9.0.82', '9.0.90',
176+
'11.0.0-preview.1.26107', '11.0.0-preview.2.26152.10', '11.0.0-preview.3.26203.7'
161177
)
162178
}
163179

164-
It '"<Tag>" → "<Expected>"' -ForEach @(
180+
It 'stable: "<Tag>" → "<Expected>"' -ForEach @(
165181
@{ Tag = '10.0.50'; Expected = '10.0.41' }
166182
@{ Tag = '10.0.41'; Expected = '10.0.40' }
167183
@{ Tag = '10.0.40'; Expected = '10.0.31' }
@@ -173,8 +189,16 @@ Describe 'Find-PreviousTag' {
173189
Find-PreviousTag $Tag $tags | Should -Be $Expected
174190
}
175191

192+
It 'preview: "<Tag>" → "<Expected>"' -ForEach @(
193+
@{ Tag = '11.0.0-preview.3.26203.7'; Expected = '11.0.0-preview.2.26152.10' }
194+
@{ Tag = '11.0.0-preview.2.26152.10'; Expected = '11.0.0-preview.1.26107' }
195+
) {
196+
Find-PreviousTag $Tag $tags | Should -Be $Expected
197+
}
198+
176199
It 'returns $null when no previous exists' {
177200
Find-PreviousTag '10.0.0' $tags | Should -BeNullOrEmpty
201+
Find-PreviousTag '11.0.0-preview.1.26107' $tags | Should -BeNullOrEmpty
178202
}
179203

180204
It 'only considers same major version' {
@@ -245,6 +269,35 @@ Describe 'Get-LinkedIssues' {
245269
}
246270
}
247271

272+
Describe 'ConvertBranchToMilestone' {
273+
It 'maps GA branch' {
274+
ConvertBranchToMilestone 'release/10.0.1xx' | Should -Be '.NET 10.0 GA'
275+
}
276+
277+
It 'maps SR branches' {
278+
ConvertBranchToMilestone 'release/10.0.1xx-sr1' | Should -Be '.NET 10 SR1'
279+
ConvertBranchToMilestone 'release/10.0.1xx-sr5' | Should -Be '.NET 10 SR5'
280+
ConvertBranchToMilestone 'release/10.0.1xx-sr10' | Should -Be '.NET 10 SR10'
281+
}
282+
283+
It 'maps preview branches' {
284+
ConvertBranchToMilestone 'release/11.0.1xx-preview1' | Should -Be '.NET 11.0-preview1'
285+
ConvertBranchToMilestone 'release/11.0.1xx-preview3' | Should -Be '.NET 11.0-preview3'
286+
ConvertBranchToMilestone 'release/11.0.1xx-preview7' | Should -Be '.NET 11.0-preview7'
287+
}
288+
289+
It 'maps RC branches' {
290+
ConvertBranchToMilestone 'release/12.0.1xx-rc1' | Should -Be '.NET 12.0-rc1'
291+
ConvertBranchToMilestone 'release/12.0.1xx-rc2' | Should -Be '.NET 12.0-rc2'
292+
}
293+
294+
It 'returns $null for non-release branches' {
295+
ConvertBranchToMilestone 'main' | Should -BeNullOrEmpty
296+
ConvertBranchToMilestone 'net11.0' | Should -BeNullOrEmpty
297+
ConvertBranchToMilestone 'feature/something' | Should -BeNullOrEmpty
298+
}
299+
}
300+
248301
Describe 'Get-PatchVersion' {
249302
It '"<Tag>" → <Expected>' -ForEach @(
250303
@{ Tag = '10.0.50'; Expected = 50 }
@@ -257,17 +310,22 @@ Describe 'Get-PatchVersion' {
257310
}
258311

259312
Describe 'Test-IsReleaseTag' {
260-
It 'accepts valid .NET 10 SR tags' {
313+
It 'accepts valid .NET 10 stable tags' {
261314
Test-IsReleaseTag '10.0.50' 10 | Should -BeTrue
262315
Test-IsReleaseTag '10.0.0' 10 | Should -BeTrue
263316
}
264317

318+
It 'accepts preview/RC tags for same major' {
319+
Test-IsReleaseTag '11.0.0-preview.3.26203.7' 11 | Should -BeTrue
320+
Test-IsReleaseTag '10.0.0-rc.1.25424.2' 10 | Should -BeTrue
321+
}
322+
265323
It 'rejects wrong major version' {
266324
Test-IsReleaseTag '9.0.82' 10 | Should -BeFalse
325+
Test-IsReleaseTag '11.0.0-preview.3.26203.7' 10 | Should -BeFalse
267326
}
268327

269-
It 'rejects non-SR tags' {
270-
Test-IsReleaseTag '10.0.0-preview.7.25406.3' 10 | Should -BeFalse
328+
It 'rejects non-release tags' {
271329
Test-IsReleaseTag 'not-a-tag' 10 | Should -BeFalse
272330
}
273331
}

0 commit comments

Comments
 (0)