验收20%
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$root = Split-Path -Parent $PSScriptRoot
|
||||
$manifestRelativePath = 'design-pipeline/manifests/a01.json'
|
||||
$requiredFiles = @(
|
||||
'design-pipeline/package.json',
|
||||
$manifestRelativePath,
|
||||
'design-pipeline/scripts/build-a01.mjs'
|
||||
)
|
||||
|
||||
foreach ($relativePath in $requiredFiles) {
|
||||
$absolutePath = Join-Path $root $relativePath
|
||||
if (-not (Test-Path -LiteralPath $absolutePath -PathType Leaf)) {
|
||||
throw "Missing A01 code pipeline file: $relativePath"
|
||||
}
|
||||
}
|
||||
|
||||
$manifest = Get-Content -LiteralPath (Join-Path $root $manifestRelativePath) -Raw -Encoding UTF8 | ConvertFrom-Json
|
||||
if ($manifest.schemaVersion -ne 1) {
|
||||
throw "Expected A01 pipeline schemaVersion 1, found $($manifest.schemaVersion)."
|
||||
}
|
||||
if ($manifest.canvas.width -ne 412 -or $manifest.canvas.height -ne 915) {
|
||||
throw 'A01 logical canvas must be 412x915.'
|
||||
}
|
||||
|
||||
$requiredStates = @('password-hidden', 'password-visible', 'sms-default', 'sms-countdown')
|
||||
foreach ($stateName in $requiredStates) {
|
||||
if ($manifest.states.name -notcontains $stateName) {
|
||||
throw "Missing A01 preview state: $stateName"
|
||||
}
|
||||
}
|
||||
|
||||
$workspacePrefix = [IO.Path]::GetFullPath($root).TrimEnd([IO.Path]::DirectorySeparatorChar) + [IO.Path]::DirectorySeparatorChar
|
||||
$runtimePrefix = 'static/assets/modules/auth/'
|
||||
$assetIds = @{}
|
||||
foreach ($asset in $manifest.assets) {
|
||||
if (-not $asset.id -or $assetIds.ContainsKey($asset.id)) {
|
||||
throw "A01 asset id must be present and unique: $($asset.id)"
|
||||
}
|
||||
$assetIds[$asset.id] = $true
|
||||
|
||||
foreach ($propertyName in @('source', 'output', 'width', 'height', 'alpha', 'maxBytes')) {
|
||||
if ($null -eq $asset.$propertyName -or "$($asset.$propertyName)" -eq '') {
|
||||
throw "A01 asset '$($asset.id)' is missing property: $propertyName"
|
||||
}
|
||||
}
|
||||
if (-not $asset.output.StartsWith($runtimePrefix, [StringComparison]::OrdinalIgnoreCase)) {
|
||||
throw "A01 runtime asset must stay in ${runtimePrefix}: $($asset.output)"
|
||||
}
|
||||
if ($asset.source -ne $asset.output) {
|
||||
throw "A01 portable pipeline must use the committed runtime asset as its stable source: $($asset.id)"
|
||||
}
|
||||
if ($asset.source -match '(?i)candidates|review|generated|node_modules|\.psd$') {
|
||||
throw "A01 portable pipeline source must not depend on local intermediate files: $($asset.source)"
|
||||
}
|
||||
if ($asset.output -match '(?i)review|page-v2|\.psd$') {
|
||||
throw "A01 runtime asset must not use a preview, full-page image, or PSD: $($asset.output)"
|
||||
}
|
||||
|
||||
$sourcePath = [IO.Path]::GetFullPath((Join-Path $root $asset.source))
|
||||
$outputPath = [IO.Path]::GetFullPath((Join-Path $root $asset.output))
|
||||
foreach ($path in @($sourcePath, $outputPath)) {
|
||||
if (-not $path.StartsWith($workspacePrefix, [StringComparison]::OrdinalIgnoreCase)) {
|
||||
throw "A01 pipeline path escaped the workspace: $path"
|
||||
}
|
||||
}
|
||||
if (-not (Test-Path -LiteralPath $sourcePath -PathType Leaf)) {
|
||||
throw "Missing A01 source asset: $($asset.source)"
|
||||
}
|
||||
if (-not (Test-Path -LiteralPath $outputPath -PathType Leaf)) {
|
||||
throw "Missing generated A01 runtime asset: $($asset.output)"
|
||||
}
|
||||
|
||||
$bytes = [IO.File]::ReadAllBytes($outputPath)
|
||||
if ($bytes.Length -lt 24 -or $bytes[0] -ne 0x89 -or $bytes[1] -ne 0x50 -or $bytes[2] -ne 0x4E -or $bytes[3] -ne 0x47) {
|
||||
throw "Generated A01 asset is not a PNG: $($asset.output)"
|
||||
}
|
||||
$width = [Net.IPAddress]::NetworkToHostOrder([BitConverter]::ToInt32($bytes, 16))
|
||||
$height = [Net.IPAddress]::NetworkToHostOrder([BitConverter]::ToInt32($bytes, 20))
|
||||
if ($width -ne $asset.width -or $height -ne $asset.height) {
|
||||
throw "Generated A01 asset has wrong dimensions: $($asset.output) expected $($asset.width)x$($asset.height), found ${width}x${height}."
|
||||
}
|
||||
if ($bytes.Length -gt $asset.maxBytes) {
|
||||
throw "Generated A01 asset exceeds maxBytes: $($asset.output) has $($bytes.Length), limit $($asset.maxBytes)."
|
||||
}
|
||||
$pngColorType = $bytes[25]
|
||||
$hasAlpha = $pngColorType -in @(4, 6)
|
||||
if ([bool]$asset.alpha -ne $hasAlpha) {
|
||||
throw "Generated A01 asset Alpha contract mismatch: $($asset.output)"
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($preview in $manifest.previews) {
|
||||
$previewPath = Join-Path $root $preview.output
|
||||
if (-not (Test-Path -LiteralPath $previewPath -PathType Leaf)) {
|
||||
throw "Missing generated A01 preview: $($preview.output)"
|
||||
}
|
||||
}
|
||||
|
||||
$buildReport = Join-Path $root 'design-pipeline/generated/a01/build-report.json'
|
||||
if (-not (Test-Path -LiteralPath $buildReport -PathType Leaf)) {
|
||||
throw 'Missing A01 code pipeline build report.'
|
||||
}
|
||||
|
||||
$builder = Get-Content -LiteralPath (Join-Path $root 'design-pipeline/scripts/build-a01.mjs') -Raw -Encoding UTF8
|
||||
foreach ($forbidden in @('Photoshop.Application', '.psd', 'scripts/photoshop')) {
|
||||
if ($builder -match [regex]::Escape($forbidden)) {
|
||||
throw "A01 code pipeline must not depend on Photoshop or PSD: $forbidden"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Output 'A01-CODE-PIPELINE-CONTRACT PASS'
|
||||
Reference in New Issue
Block a user