Skip to content

Commit 03402db

Browse files
authored
Merge branch 'main' into bugfix/delivery_queue_v2
2 parents a7d793a + 335ecbc commit 03402db

20 files changed

Lines changed: 2635 additions & 1066 deletions
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
name: Bump main to next major preview
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
next_major:
7+
description: 'Next major version (e.g., 10) for the new preview line on main'
8+
required: true
9+
type: string
10+
discard_current_preview:
11+
description: 'Allow orphaning the current major''s preview work (no release branch will ever ship for it). Check this only when intentionally abandoning the current X.Y-preview line.'
12+
required: false
13+
type: boolean
14+
default: false
15+
16+
permissions:
17+
contents: write
18+
pull-requests: write
19+
20+
concurrency:
21+
group: main-version-mutator
22+
cancel-in-progress: false
23+
24+
jobs:
25+
bump:
26+
runs-on: ubuntu-latest
27+
env:
28+
NEXT_MAJOR_INPUT: ${{ inputs.next_major }}
29+
DISCARD_PREVIEW_INPUT: ${{ inputs.discard_current_preview }}
30+
steps:
31+
- name: Checkout
32+
uses: actions/checkout@v6
33+
with:
34+
ref: main
35+
fetch-depth: 0
36+
37+
- name: Configure git
38+
run: |
39+
git config user.email "github-actions[bot]@users.noreply.github.com"
40+
git config user.name "github-actions[bot]"
41+
42+
- name: Validate inputs
43+
shell: pwsh
44+
run: |
45+
$ErrorActionPreference = 'Stop'
46+
47+
$next = $env:NEXT_MAJOR_INPUT
48+
if ($next -notmatch '^(0|[1-9]\d*)$') {
49+
throw "next_major must be a positive integer with no leading zeros (got: '$next')"
50+
}
51+
$nextInt = [int]$next
52+
53+
git fetch --tags --force origin
54+
if ($LASTEXITCODE -ne 0) { throw "git fetch --tags failed (exit $LASTEXITCODE); cannot validate sequential-major rule." }
55+
56+
$mainHeadSha = (git rev-parse origin/main).Trim()
57+
if ($LASTEXITCODE -ne 0 -or -not $mainHeadSha) { throw "git rev-parse origin/main failed (exit $LASTEXITCODE)." }
58+
59+
$versionJson = git show "${mainHeadSha}:version.json" | ConvertFrom-Json
60+
if ($LASTEXITCODE -ne 0) { throw "Failed to read version.json from origin/main." }
61+
$ver = $versionJson.version
62+
if ($ver -notmatch '^(0|[1-9]\d*)\.(0|[1-9]\d*)-preview') {
63+
throw "main's version is '$ver' but should be '<major>.<minor>-preview.{height}'"
64+
}
65+
$currentMajor = [int]$matches[1]
66+
$currentMinor = [int]$matches[2]
67+
if ($nextInt -le $currentMajor) {
68+
throw "next_major ($nextInt) must be greater than current major ($currentMajor)"
69+
}
70+
71+
# Pre-flight: detect whether the current major's preview work would be orphaned.
72+
# The only workflow that creates release branches is cut-major.yml, and it requires
73+
# main to be on <major>.0-preview. If main has moved past .0-preview without the
74+
# major ever being cut (or has accumulated minor work past the existing release
75+
# branch's stable minor), bumping to the next major silently loses that work.
76+
$discardOverride = $env:DISCARD_PREVIEW_INPUT -eq 'true'
77+
$releaseBranch = "release/$currentMajor.x"
78+
$releaseExists = git ls-remote --heads origin "refs/heads/$releaseBranch"
79+
if ($LASTEXITCODE -ne 0) { throw "git ls-remote for $releaseBranch failed (exit $LASTEXITCODE); cannot verify orphan state." }
80+
81+
if (-not $releaseExists) {
82+
$msg = "main is on $currentMajor.$currentMinor-preview but '$releaseBranch' does not exist. Bumping main to $nextInt would orphan ALL '$currentMajor.x' work (no stable '$currentMajor.*' would ever ship). To ship $currentMajor.0 stable first, run 'Cut major release' with major_version=$currentMajor and next_main_version=$nextInt.0. To intentionally discard the $currentMajor preview line, re-run this workflow with 'discard_current_preview' checked."
83+
if (-not $discardOverride) { throw $msg }
84+
Write-Host "WARNING (discard_current_preview=true): release/$currentMajor.x does not exist. All $currentMajor.x work is being orphaned."
85+
} else {
86+
$releaseVerJson = git show "origin/${releaseBranch}:version.json" | ConvertFrom-Json
87+
if ($LASTEXITCODE -ne 0) { throw "Failed to read version.json from origin/$releaseBranch." }
88+
$releaseVer = $releaseVerJson.version
89+
if ($releaseVer -notmatch '^(0|[1-9]\d*)\.(0|[1-9]\d*)$') {
90+
throw "'$releaseBranch' version is '$releaseVer'; expected stable '<major>.<minor>' form. Cannot verify orphan state."
91+
}
92+
$releaseMinor = [int]$matches[2]
93+
if ($currentMinor -gt $releaseMinor) {
94+
$msg = "main is on $currentMajor.$currentMinor-preview but '$releaseBranch' is at $currentMajor.$releaseMinor stable. Bumping main to $nextInt would orphan the $currentMajor.$currentMinor preview work (never shipped as stable). To ship $currentMajor.$currentMinor stable first, run 'Promote main to stable minor' with target_release_branch=$releaseBranch and stable_version=$currentMajor.$currentMinor. To intentionally discard $currentMajor.$currentMinor preview, re-run this workflow with 'discard_current_preview' checked."
95+
if (-not $discardOverride) { throw $msg }
96+
Write-Host "WARNING (discard_current_preview=true): orphaning $currentMajor.$currentMinor preview work (release/$currentMajor.x is at $currentMajor.$releaseMinor)."
97+
} else {
98+
Write-Host "OK: $releaseBranch is at $currentMajor.$releaseMinor stable and main is on $currentMajor.$currentMinor-preview ($currentMinor <= $releaseMinor); no orphaning."
99+
}
100+
}
101+
102+
$latestStable = git tag --list --sort=-v:refname |
103+
Where-Object { $_ -match '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$' } |
104+
Select-Object -First 1
105+
106+
if ($latestStable) {
107+
if ($latestStable -notmatch '^(\d+)\.') {
108+
throw "Could not parse latest stable tag: '$latestStable'"
109+
}
110+
$latestStableMajor = [int]$matches[1]
111+
$expectedMajor = $latestStableMajor + 1
112+
if ($nextInt -ne $expectedMajor) {
113+
throw "next_major ($nextInt) must be exactly one greater than the latest stable major ($latestStableMajor; tag '$latestStable'). Expected: $expectedMajor. Major versions must be incremented sequentially."
114+
}
115+
Write-Host "OK: next_major ($nextInt) is exactly one greater than latest stable major ($latestStableMajor)."
116+
} else {
117+
$expectedMajor = $currentMajor + 1
118+
if ($nextInt -ne $expectedMajor) {
119+
throw "No stable tags found; falling back to comparing against main's current major ($currentMajor). next_major ($nextInt) must be exactly $expectedMajor."
120+
}
121+
Write-Host "No stable tags found; next_major ($nextInt) matches currentMajor+1 ($expectedMajor)."
122+
}
123+
124+
$newVersion = "$next.0-preview.{height}"
125+
$runId = $env:GITHUB_RUN_ID
126+
$runAttempt = $env:GITHUB_RUN_ATTEMPT
127+
Add-Content -Path $env:GITHUB_ENV -Value "NEW_VERSION=$newVersion"
128+
Add-Content -Path $env:GITHUB_ENV -Value "NEXT_MAJOR=$next"
129+
Add-Content -Path $env:GITHUB_ENV -Value "BUMP_BRANCH=bot/bump-major-$next-$runId-$runAttempt"
130+
Add-Content -Path $env:GITHUB_ENV -Value "MAIN_HEAD_SHA=$mainHeadSha"
131+
132+
- name: Create bump branch (from validated main SHA)
133+
shell: pwsh
134+
run: |
135+
$ErrorActionPreference = 'Stop'
136+
git checkout "$env:MAIN_HEAD_SHA"
137+
if ($LASTEXITCODE -ne 0) { throw "git checkout failed (exit $LASTEXITCODE)." }
138+
git checkout -b "$env:BUMP_BRANCH"
139+
if ($LASTEXITCODE -ne 0) { throw "git checkout -b failed (exit $LASTEXITCODE)." }
140+
141+
- name: Bump version.json
142+
shell: pwsh
143+
run: |
144+
$ErrorActionPreference = 'Stop'
145+
$path = 'version.json'
146+
$content = [System.IO.File]::ReadAllText($path)
147+
$content = [regex]::Replace($content, '"version":\s*"[^"]+"', "`"version`": `"$env:NEW_VERSION`"")
148+
$content = [regex]::Replace($content, '(?m)^\s*"versionHeightOffset"\s*:\s*-?\d+\s*,?\s*(//[^\r\n]*)?\s*(\r?\n|$)', '')
149+
$content = [regex]::Replace($content, ',(\s*[}\]])', '$1')
150+
[System.IO.File]::WriteAllText($path, $content)
151+
$obj = $content | ConvertFrom-Json
152+
if ($obj.PSObject.Properties.Name -contains 'versionHeightOffset') {
153+
throw "Failed to strip versionHeightOffset from version.json. Manual edit required."
154+
}
155+
156+
- name: Commit and push
157+
shell: pwsh
158+
run: |
159+
$ErrorActionPreference = 'Stop'
160+
git add version.json
161+
if ($LASTEXITCODE -ne 0) { throw "git add failed (exit $LASTEXITCODE)." }
162+
git commit -m "Bump main to $env:NEW_VERSION (next major preview line)"
163+
if ($LASTEXITCODE -ne 0) { throw "git commit failed (exit $LASTEXITCODE)." }
164+
git push --force-with-lease -u origin "$env:BUMP_BRANCH"
165+
if ($LASTEXITCODE -ne 0) { throw "git push failed (exit $LASTEXITCODE)." }
166+
167+
- name: Verify main hasn't moved since validation
168+
shell: pwsh
169+
run: |
170+
$ErrorActionPreference = 'Stop'
171+
git fetch origin main --quiet
172+
if ($LASTEXITCODE -ne 0) { throw "git fetch failed (exit $LASTEXITCODE)." }
173+
$currentMainSha = (git rev-parse origin/main).Trim()
174+
if ($currentMainSha -ne $env:MAIN_HEAD_SHA) {
175+
throw "main moved during bump-major-preview (was $env:MAIN_HEAD_SHA, now $currentMainSha). The bump branch was pushed but no PR was created. Delete the bump branch and re-run."
176+
}
177+
Write-Host "OK: main is still at $env:MAIN_HEAD_SHA."
178+
179+
- name: Open PR
180+
env:
181+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
182+
shell: pwsh
183+
run: |
184+
$ErrorActionPreference = 'Stop'
185+
$nextMajor = $env:NEXT_MAJOR
186+
$body = @"
187+
Bumps ``main`` from its current preview to ``$env:NEW_VERSION`` ahead of upcoming breaking changes for ``${nextMajor}.0``.
188+
189+
Merge this **before** any PR labeled ``breaking-change`` so the prereleases are correctly versioned as ``${nextMajor}.0.0-preview.N``.
190+
"@
191+
try {
192+
$url = (gh pr create `
193+
--base main `
194+
--head "$env:BUMP_BRANCH" `
195+
--title "Bump main to $env:NEW_VERSION (next major preview)" `
196+
--body $body | Select-Object -Last 1).Trim()
197+
} catch {
198+
throw "gh pr create failed: $($_.Exception.Message)"
199+
}
200+
if ($LASTEXITCODE -ne 0 -or -not $url -or $url -notmatch '^https?://') {
201+
throw "gh pr create did not return a valid URL (exit $LASTEXITCODE; got: '$url')"
202+
}
203+
Add-Content -Path $env:GITHUB_ENV -Value "PR_URL=$url"
204+
205+
- name: Summary
206+
shell: pwsh
207+
run: |
208+
$summary = @"
209+
## Major preview bump
210+
211+
- **PR**: $env:PR_URL
212+
- Merge this before landing the first breaking-change PR.
213+
"@
214+
Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value $summary

.github/workflows/ci-build.yml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@ name: Build
22

33
on:
44
pull_request:
5-
branches: [ main ]
5+
branches: [ main, 'release/*.x' ]
66

77
env:
88
configuration: Release
9-
productNamespacePrefix: "DynamicData"
109

1110
jobs:
1211
build:
@@ -40,7 +39,7 @@ jobs:
4039
4140
- name: NBGV
4241
id: nbgv
43-
uses: dotnet/nbgv@master
42+
uses: dotnet/nbgv@v0.5.1
4443
with:
4544
setAllVars: true
4645

@@ -61,7 +60,7 @@ jobs:
6160
working-directory: src
6261

6362
- name: Create NuGet Artifacts
64-
uses: actions/upload-artifact@master
63+
uses: actions/upload-artifact@v4.6.2
6564
with:
6665
name: nuget
67-
path: '**/*.nupkg'
66+
path: 'src/**/bin/Release/*.nupkg'

0 commit comments

Comments
 (0)