Add preview/RC milestone support with release branch detection#34999
Conversation
Get-VersionFromGitRef now reads PreReleaseVersionLabel and PreReleaseVersionIteration from eng/Versions.props. ConvertTo-Milestone maps these to preview/RC milestone names: 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) Stable labels (ci.main, ci.inflight, servicing) are treated as non-prerelease and continue to use the GA/SR mapping. 6 new tests for preview/RC mapping (83 total, all passing). Backward compatible — .NET 10 stable PRs and tag mode unaffected. Validated: - PR #34252 (net11.0, preview1) → .NET 11.0-preview1 ✅ - PR #34620 (.NET 10 stable) → .NET 10 SR6 ✅ - Tag 10.0.50 → 78 PRs, 90 corrections ✅ Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34999Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34999" |
There was a problem hiding this comment.
Pull request overview
This PR extends the milestone drift fixer script to support preview/RC milestone naming based on additional version metadata in eng/Versions.props, enabling correct milestoning for PRs merged during pre-release phases (e.g., net11.0 previews).
Changes:
- Update
Get-VersionFromGitRefto also readPreReleaseVersionLabelandPreReleaseVersionIterationfromeng/Versions.props. - Extend
ConvertTo-Milestoneto generate.NET X.0-previewN/.NET X.0-rcNmilestone names when appropriate. - Add Pester tests covering preview/RC milestone mapping cases.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| .github/scripts/Fix-MilestoneDrift.ps1 | Adds prerelease metadata detection and preview/RC milestone mapping logic. |
| .github/scripts/Fix-MilestoneDrift.Tests.ps1 | Adds unit tests validating preview/RC milestone name generation. |
| $preLabel = if ($script:_preLabel) { $script:_preLabel } else { $null } | ||
| $preIter = if ($script:_preIter) { $script:_preIter } else { 0 } | ||
| $expectedMs = ConvertTo-Milestone $ReleaseTag $preLabel $preIter |
| if ($joined -match '<PreReleaseVersionLabel[^>]*>([^<]+)</PreReleaseVersionLabel>') { | ||
| $rawLabel = $Matches[1] | ||
| # Only treat "preview" and "rc" as pre-release; "ci.main", "ci.inflight", "servicing" are stable builds | ||
| if ($rawLabel -match '^(preview|rc)$') { | ||
| $preLabel = $rawLabel | ||
| if ($joined -match '<PreReleaseVersionIteration>(\d+)</PreReleaseVersionIteration>') { |
| PreReleaseLabel (e.g. "preview", "rc", or $null for stable), | ||
| and PreReleaseIteration (e.g. 3). |
Instead of relying solely on Versions.props (which has stale PreReleaseVersionIteration on net11.0), check release branches first using merge-base --is-ancestor. Detection order: 1. Explicit -Tag (if provided) 2. Release branches: find earliest release/X.0.1xx-* branch containing the merge commit (GA first, then SR/preview/RC) 3. Versions.props at merge commit (fallback for unreleased PRs) 4. Tag range search (last resort) New functions: - ConvertBranchToMilestone: maps branch names to milestone names (release/11.0.1xx-preview3 → .NET 11.0-preview3) - Find-ReleaseBranchForCommit: checks ancestry against all release branches for a major version, returns earliest match Validated: - Preview 3 PRs (#30132, #33834, etc.) → .NET 11.0-preview3 ✅ - Preview 4 PRs (no release branch yet) → falls back to Versions.props ✅ - .NET 10 SR5/SR6 PRs → found in correct release branch ✅ 88 Pester tests pass (5 new for ConvertBranchToMilestone). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
.NET 10 has both SR branches and legacy preview/RC branches from its pre-GA phase. A commit reachable from both GA and a preview should be milestoned as GA, not preview. Same for SRs vs previews. Sort order: GA (0) → SR1-SRn (100+) → RC1-RCn (200+) → preview1-n (1000+) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previews are cut earlier in the release cycle than RCs. A commit in both preview7 and rc1 should be milestoned preview7. Order: GA (0) → SRs (100+) → previews (200+) → RCs (1000+) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The sort order should match the actual release timeline: preview1 → preview7 → RC1 → RC2 → GA → SR1 → SR5 A commit reachable from both preview7 and GA should be milestoned preview7 (where it first shipped), not GA. Order: previews (100+) → RCs (200+) → GA (500) → SRs (1000+) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
$expectedMs and $script:_preLabel/_preIter were used before being set when a PR's merge commit wasn't on any release branch (e.g. PRs merged to inflight/candidate). Initialize them at function entry. Also improved Major version derivation to parse from the milestone name when $ReleaseTag isn't set (release branch path). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PR #34999 — Multi-Model Code Review (Final — Round 5)CI Status: Review Results
Resolution: Summary Across All Rounds
Test Coverage
Recommended Action✅ Approve — Zero issues across 3 reviewers. All findings from 5 rounds resolved. Production-validated. |
- Set $ReleaseTag from versionInfo when release branch detection succeeds (was null, causing blank report metadata) - Replace $script:_preLabel/_preIter with local variables (no need for script scope — used within single function only) - Fix Find-ReleaseBranchForCommit docstring: says 'GA first' but code sorts previews first (chronological). Doc now matches code. - Fix Get-VersionFromGitRef docstring: key names now match actual hashtable keys (PreLabel/PreIter not PreReleaseLabel/Iteration) - Replace dead $isAncestor variable with $null = git pattern 88 Pester tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tag mode now works with preview tags like -Tag 11.0.0-preview.3.x: - Reads Versions.props at the tag to get PreLabel/PreIter - ConvertTo-Milestone produces '.NET 11.0-preview3' - Find-PreviousTag finds preview2 as the previous tag (was returning null, causing full-history scan of 11K+ commits) New Get-TagSortKey function assigns chronological sort keys: preview1 (101) < preview7 (107) < rc1 (201) < GA (500) < sr5 (505) Test-IsReleaseTag now matches preview/RC tags (was stable-only). Validated: -Tag 11.0.0-preview.3.26203.7 correctly finds 234 PRs in the preview2..preview3 range, filters 180 merge-ups, checks 53 .NET 11 PRs, resolves to .NET 11.0-preview3. 91 Pester tests pass (5 new for preview tag ordering). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Find-TagContainingPr: use Get-TagSortKey instead of Get-PatchVersion (preview tags all returned 0, causing nondeterministic sort order) - Guard $versionInfo.Tag null dereference when release branch succeeds but Versions.props read failed - Explicit preview tag in single-PR mode: read Versions.props at tag to get PreLabel/PreIter (was throwing because ConvertTo-Milestone can't parse preview tag strings directly) - Use clean version tag for ConvertTo-Milestone when $versionInfo is available (e.g. '11.0.0' not '11.0.0-preview.3.26203.7') 91 Pester tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Initialize $versionInfo to $null at function entry (StrictMode crash when neither -Tag nor MergeCommitSha provided) - When Find-TagContainingPr returns a preview tag and $versionInfo is null, read Versions.props at the tag to get clean version + pre-release info (was throwing because ConvertTo-Milestone can't parse preview tags) - Warn when PreLabel is set but PreIter is 0 (would silently fall through to GA mapping) 91 Pester tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Setting milestones on PRs via the Issues API requires pull-requests: write, not just read. Issues worked (issues: write) but PRs returned 403. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🟢 .NET MAUI Code Review — Approved
🟢 Review Session — Approved —
|
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 from this PR and let us know in a comment if this change resolves your issue. Thank you!
Summary
Follow-up to #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:
Detection Order
Preview/RC Milestone Mapping
`ConvertTo-Milestone` now accepts optional pre-release label and iteration:
Validated Results
PR #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):