CaiWuXiTong/scripts/test-release-inclusion.ps1

72 lines
4.0 KiB
PowerShell

param([string]$BashPath='bash')
$ErrorActionPreference='Stop'
$repoRoot=Split-Path $PSScriptRoot -Parent
$psSource=[IO.File]::ReadAllText((Join-Path $repoRoot 'scripts/deploy-from-workstation.ps1'))
$parseErrors=$null; $tokens=$null
$ast=[Management.Automation.Language.Parser]::ParseInput($psSource,[ref]$tokens,[ref]$parseErrors)
if($parseErrors.Count){throw 'Deployment PowerShell syntax invalid'}
$function=$ast.Find({param($node) $node -is [Management.Automation.Language.FunctionDefinitionAst] -and $node.Name -eq 'Test-CaiwuReleaseIncludesCommit'},$true)
if(-not $function){throw 'PowerShell inclusion guard missing'}
. ([ScriptBlock]::Create($function.Extent.Text))
$bashSource=[IO.File]::ReadAllText((Join-Path $repoRoot 'scripts/deploy-from-mac.sh')).Replace("`r`n","`n")
$bashFunction=[regex]::Match($bashSource,'(?ms)^release_includes_commit\(\) \{\n.*?^\}').Value
if(-not $bashFunction){throw 'Bash inclusion guard missing'}
$fixture=Join-Path ([IO.Path]::GetTempPath()) ('caiwu-release-inclusion-'+[guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $fixture | Out-Null
$expectedFixture=[IO.Path]::GetFullPath($fixture)
function Invoke-FixtureGit {
param([Parameter(ValueFromRemainingArguments=$true)][string[]]$GitArgs)
$output=@(git @GitArgs 2>&1)
if($LASTEXITCODE -ne 0){throw "Fixture Git failed: $($GitArgs[0])"}
return $output
}
function New-FixtureCommit {
param([string]$Value,[string]$Message)
[IO.File]::WriteAllText((Join-Path $fixture 'value.txt'),$Value)
Invoke-FixtureGit add value.txt | Out-Null
Invoke-FixtureGit commit -m $Message | Out-Null
return (Invoke-FixtureGit rev-parse HEAD) -join ''
}
Push-Location $fixture
try {
Invoke-FixtureGit init -b main | Out-Null
Invoke-FixtureGit config user.name 'Release guard fixture' | Out-Null
Invoke-FixtureGit config user.email 'release-guard@example.invalid' | Out-Null
$base=New-FixtureCommit 'base' 'base'
Invoke-FixtureGit switch -c hotfix | Out-Null
$hotfix=New-FixtureCommit 'hotfix content' 'hotfix'
Invoke-FixtureGit switch main | Out-Null
$squashed=New-FixtureCommit 'hotfix content' 'squashed identity'
$release=New-FixtureCommit 'next authorized change' 'new release'
Invoke-FixtureGit switch -c unrelated $base | Out-Null
$unrelated=New-FixtureCommit 'different hotfix content' 'hotfix'
$cases=@(
@{name='direct ancestor';previous=$base;release=$release;expected=$true},
@{name='same commit';previous=$hotfix;release=$hotfix;expected=$true},
@{name='identical squash tree at head';previous=$hotfix;release=$squashed;expected=$true},
@{name='identical squash tree in release ancestry';previous=$hotfix;release=$release;expected=$true},
@{name='real unmerged change';previous=$unrelated;release=$release;expected=$false},
@{name='rollback to before hotfix';previous=$hotfix;release=$base;expected=$false},
@{name='missing deployed commit';previous=('0'*40);release=$release;expected=$false},
@{name='missing release commit';previous=$hotfix;release=('0'*40);expected=$false}
)
foreach($case in $cases){
$actual=Test-CaiwuReleaseIncludesCommit -PreviousSha $case.previous -ReleaseSha $case.release
if($actual -ne $case.expected){throw "PowerShell failed: $($case.name)"}
$code=$bashFunction+"`nrelease_includes_commit "+'"$1" "$2"'
& $BashPath --noprofile --norc -c $code guard $case.previous $case.release
$bashActual=$LASTEXITCODE -eq 0
if($bashActual -ne $case.expected){throw "Bash failed: $($case.name)"}
}
"PASS: $($cases.Count) real Git cases for both PowerShell and Bash guards"
} finally {
Pop-Location
$resolved=(Resolve-Path -LiteralPath $fixture).Path
if([IO.Path]::GetFullPath($resolved) -ne $expectedFixture -or (Get-Item -LiteralPath $resolved).Attributes.HasFlag([IO.FileAttributes]::ReparsePoint)){
throw 'Refusing cleanup outside the exact generated fixture directory'
}
Remove-Item -LiteralPath $resolved -Recurse -Force
}
exit 0