109 lines
4.5 KiB
PowerShell
109 lines
4.5 KiB
PowerShell
param(
|
|
[string]$RepositoryRoot = "",
|
|
[string]$ThothctlPath = ""
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
Set-StrictMode -Version Latest
|
|
|
|
if ([string]::IsNullOrWhiteSpace($RepositoryRoot)) {
|
|
$RepositoryRoot = (& git rev-parse --show-toplevel).Trim()
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "git could not resolve the repository root"
|
|
}
|
|
}
|
|
$RepositoryRoot = [System.IO.Path]::GetFullPath($RepositoryRoot)
|
|
|
|
$tracked = @(& git -C $RepositoryRoot ls-files)
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "git ls-files failed"
|
|
}
|
|
|
|
$scriptRelativePath = "scripts/test-windows-clone-contract.ps1"
|
|
$eolAttribute = (& git -C $RepositoryRoot check-attr eol -- $scriptRelativePath).Trim()
|
|
if ($LASTEXITCODE -ne 0 -or -not $eolAttribute.EndsWith("eol: crlf", [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
throw "the Windows contract script must have the repository eol=crlf attribute"
|
|
}
|
|
$scriptBytes = [System.IO.File]::ReadAllBytes((Join-Path $RepositoryRoot $scriptRelativePath))
|
|
if (-not ($scriptBytes -contains [byte]0x0D)) {
|
|
throw "the Windows contract script was not checked out with CRLF bytes"
|
|
}
|
|
|
|
$offenders = [System.Collections.Generic.List[string]]::new()
|
|
foreach ($relativePath in $tracked) {
|
|
$name = [System.IO.Path]::GetFileName($relativePath)
|
|
$mustBeLf = $relativePath.EndsWith(".sh", [System.StringComparison]::OrdinalIgnoreCase) -or
|
|
$relativePath.EndsWith(".yml", [System.StringComparison]::OrdinalIgnoreCase) -or
|
|
$relativePath.EndsWith(".yaml", [System.StringComparison]::OrdinalIgnoreCase) -or
|
|
$name.Equals("Dockerfile", [System.StringComparison]::OrdinalIgnoreCase) -or
|
|
$name.StartsWith("Dockerfile.", [System.StringComparison]::OrdinalIgnoreCase) -or
|
|
$name.EndsWith(".Dockerfile", [System.StringComparison]::OrdinalIgnoreCase)
|
|
if (-not $mustBeLf) {
|
|
continue
|
|
}
|
|
$absolutePath = Join-Path $RepositoryRoot $relativePath
|
|
$bytes = [System.IO.File]::ReadAllBytes($absolutePath)
|
|
if ($bytes -contains [byte]0x0D) {
|
|
$offenders.Add($relativePath)
|
|
}
|
|
}
|
|
if ($offenders.Count -ne 0) {
|
|
throw "CR byte 0x0D found in tracked LF contract files: $($offenders -join ', ')"
|
|
}
|
|
|
|
$temporaryRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("thothii-windows-contract-" + [guid]::NewGuid().ToString("N"))
|
|
$savedEnvironment = @{
|
|
THT_WORKSPACE_GIT_REMOTE = $env:THT_WORKSPACE_GIT_REMOTE
|
|
PI_AUTH_FILE = $env:PI_AUTH_FILE
|
|
THT_SECRETS_FILE = $env:THT_SECRETS_FILE
|
|
}
|
|
try {
|
|
[System.IO.Directory]::CreateDirectory($temporaryRoot) | Out-Null
|
|
$piAuth = Join-Path $temporaryRoot "pi-auth.json"
|
|
$secrets = Join-Path $temporaryRoot "thothii.secrets"
|
|
[System.IO.File]::WriteAllText($piAuth, "{}`n", [System.Text.UTF8Encoding]::new($false))
|
|
[System.IO.File]::WriteAllText($secrets, "THT_MODEL_API_KEY=windows-contract`n", [System.Text.UTF8Encoding]::new($false))
|
|
|
|
$env:THT_WORKSPACE_GIT_REMOTE = "https://git.example.invalid/platform/thoth-workspaces.git"
|
|
$env:PI_AUTH_FILE = $piAuth
|
|
$env:THT_SECRETS_FILE = $secrets
|
|
$composeFiles = @(
|
|
"--project-directory", $RepositoryRoot,
|
|
"-f", (Join-Path $RepositoryRoot "compose.yaml"),
|
|
"-f", (Join-Path $RepositoryRoot "deploy/compose.local.yaml")
|
|
)
|
|
$services = @(& docker compose @composeFiles config --services)
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Docker Compose could not render the Windows clone"
|
|
}
|
|
if ((($services | Sort-Object) -join ",") -ne "core,frontend") {
|
|
throw "rendered Windows stack must contain exactly core and frontend"
|
|
}
|
|
& docker compose @composeFiles config --quiet
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Docker Compose rejected the Windows clone"
|
|
}
|
|
|
|
if ([string]::IsNullOrWhiteSpace($ThothctlPath)) {
|
|
$ThothctlPath = Join-Path $RepositoryRoot "dist/thothctl/thothctl-windows-amd64.exe"
|
|
}
|
|
$ThothctlPath = [System.IO.Path]::GetFullPath($ThothctlPath)
|
|
if (-not [System.IO.File]::Exists($ThothctlPath)) {
|
|
throw "Windows thothctl binary is missing: $ThothctlPath"
|
|
}
|
|
& $ThothctlPath --help | Out-Null
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Windows thothctl invocation failed"
|
|
}
|
|
}
|
|
finally {
|
|
foreach ($name in $savedEnvironment.Keys) {
|
|
[System.Environment]::SetEnvironmentVariable($name, $savedEnvironment[$name], "Process")
|
|
}
|
|
if ([System.IO.Directory]::Exists($temporaryRoot)) {
|
|
Remove-Item -LiteralPath $temporaryRoot -Recurse -Force
|
|
}
|
|
}
|
|
|
|
Write-Output "Windows clone, LF-byte, Compose render, and thothctl invocation contracts passed."
|