Skip to content

Commit ee43637

Browse files
authored
fix(release-script): guard the list that stages the showcase, and put back what the post-release pass rewrote (#703)
Two holes around web/showcase, both surfaced by cutting v2.4.1. The release commit's staging list is now built by Get-ReleaseCommitPathspecs rather than inline, and release-script-check.yml lifts it by AST and runs it for real: a list carrying any :(exclude), one that stops naming web/showcase, or one whose `git add --dry-run` leaves a rewritten showcase file out now fails the check. The step that already owned these pathspecs runs Get-GeneratedPagePathspecs on its own, where the exclusion is correct - which is why it stayed green while the release commit was losing 133 files. Proven against three sabotages: the exclusion put back as :(exclude)web/showcase, caught by the pattern; the entry narrowed to web/showcase/pdf, caught by the name; and the exclusion written :(exclude,glob)web/showcase/**, which the pattern does not match and the dry run catches. -PostReleaseOnly rebuilt every preview through Sync-ShowcaseSite and committed none of them - those belong to the tag - but nothing put them back, so the documented last step of every release left ~125 modified files behind, which the runbook reads as the signature of a bumped-but-unstaged file. Restore-CommittedShowcase restores them, tracked files only, so a preview for an example added since the tag survives. The post-release `add` is split the same way as the release one. Nothing in its list stands under the showcase today, so its exclusion cancels nothing - but a path added there later would be dropped in silence, which is the defect above. ReleaseAssetStepGuardTest compared the source offset of the `knowledge` staging literal against Step 5c. That literal now sits in the extracted function, above the flow, so the comparison is against the call that builds the list - where the staging actually happens.
1 parent 3815fe8 commit ee43637

3 files changed

Lines changed: 200 additions & 98 deletions

File tree

‎.github/workflows/release-script-check.yml‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,50 @@ jobs:
530530
if (git status --porcelain -- web) { throw 'the probe left the web/ tree changed' }
531531
Write-Host 'page staging: the documentation page and a rewritten, a deleted and an added card page are staged, and nothing under web/showcase/.'
532532
533+
- name: The cut stages the showcase assets its own regeneration rewrote
534+
shell: pwsh
535+
run: |
536+
# The step above proves the page globs are right on their own - which they were
537+
# throughout. This one proves the list they used to stand in stages what it names.
538+
# Get-ReleaseCommitPathspecs builds every path of the release commit bar the pages, and
539+
# goes to one `git add`. The page globs carry :(exclude)web/showcase, and git applies an
540+
# exclude to the WHOLE invocation rather than to the pathspecs beside it: while the two
541+
# lists were one, the exclude cancelled the explicit web/showcase entry, and the v2.4.1
542+
# release commit carried none of the 133 showcase files its own Step 4c had just
543+
# rewritten. Lifted by AST and run for real - a list that stages nothing under
544+
# web/showcase fails here, before a cut can tag it.
545+
$path = (Resolve-Path scripts/cut-release.ps1).Path
546+
$ast = [System.Management.Automation.Language.Parser]::ParseFile($path, [ref]$null, [ref]$null)
547+
$fn = $ast.FindAll({
548+
param($n)
549+
$n -is [System.Management.Automation.Language.FunctionDefinitionAst] -and $n.Name -eq 'Get-ReleaseCommitPathspecs'
550+
}, $true) | Select-Object -First 1
551+
if (-not $fn) { throw 'cut-release.ps1 no longer defines Get-ReleaseCommitPathspecs' }
552+
Invoke-Expression $fn.Extent.Text
553+
$repoRoot = (Get-Location).Path
554+
$list = @(Get-ReleaseCommitPathspecs $true $false)
555+
556+
# An exclude anywhere in this list reaches every path in the same add, whatever it was
557+
# written to narrow, so none may stand in it at all.
558+
$excludes = @($list | Where-Object { $_ -like '*:(exclude*' -or $_ -like ':!*' })
559+
if ($excludes) { throw "the release staging list carries an exclude pathspec: $($excludes -join ', ')" }
560+
if ($list -notcontains 'web/showcase') { throw 'the release staging list no longer names web/showcase' }
561+
562+
$showcaseFile = @(git ls-files -- web/showcase)[0]
563+
if (-not $showcaseFile) { throw 'expected committed files under web/showcase' }
564+
try {
565+
Add-Content -Path $showcaseFile -Value 'touched'
566+
$staged = @(git add --dry-run -- @($list))
567+
if ($LASTEXITCODE -ne 0) { throw 'git add --dry-run refused the release staging list' }
568+
if (-not ($staged -contains "add '$showcaseFile'")) {
569+
throw "the release staging list leaves $showcaseFile out; a regenerated showcase would miss the release commit"
570+
}
571+
} finally {
572+
git checkout -- $showcaseFile
573+
}
574+
if (git status --porcelain -- web/showcase) { throw 'the probe left web/showcase changed' }
575+
Write-Host 'release staging: a rewritten showcase file is staged, and the list carries no exclude pathspec.'
576+
533577
- name: Unit-check the roadmap promotion (refusals and the real rewrite)
534578
shell: pwsh
535579
run: |

‎core/src/test/java/com/demcha/documentation/ReleaseAssetStepGuardTest.java‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,10 @@ void theCutRegeneratesTheKnowledgeSurfacesBeforeStagingThem() throws IOException
183183

184184
int regen = script.indexOf("Step \"5c\" \"Regenerate the knowledge pack surfaces");
185185
int staged = script.indexOf("$commitFiles += 'knowledge'");
186+
// The list is built by Get-ReleaseCommitPathspecs, declared with the other functions near
187+
// the top of the script, so where the literal above sits no longer says when the staging
188+
// happens — its call does. Read against that call, this is the order the cut executes in.
189+
int stagingCall = script.indexOf("$commitFiles = @(Get-ReleaseCommitPathspecs");
186190

187191
assertThat(regen)
188192
.describedAs("the cut no longer regenerates the knowledge surfaces, so the release "
@@ -193,10 +197,14 @@ void theCutRegeneratesTheKnowledgeSurfacesBeforeStagingThem() throws IOException
193197
.describedAs("the release commit no longer stages knowledge/, so a regen would happen "
194198
+ "and never reach the tag")
195199
.isNotNegative();
200+
assertThat(stagingCall)
201+
.describedAs("the release commit no longer builds its staging list through "
202+
+ "Get-ReleaseCommitPathspecs, so this ordering reads nothing")
203+
.isNotNegative();
196204
assertThat(regen)
197205
.describedAs("the surfaces are regenerated after the commit that stages them, so the "
198206
+ "tag carries the previous version's pack")
199-
.isLessThan(staged);
207+
.isLessThan(stagingCall);
200208
}
201209

202210
@Test

0 commit comments

Comments
 (0)