Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Tools/windows/Tests/Packaging.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ try {
& $zig0152 build `
"-Dwinghostty-dir=$wingRoot" `
"-Dwinghostty-lib=$(Join-Path $wingRoot 'zig-out\lib\winghostty-win32-host.lib')" `
"-Dversion=1.2.3" -Doptimize=ReleaseSafe
"-Dversion=1.2.3" -Dworktrees-deferred=true -Doptimize=ReleaseSafe
} finally { Pop-Location }
if ($LASTEXITCODE -ne 0) { throw "could not build versioned GraphCode Windows artifact" }
$fixtureBin = Join-Path $fixture "nested space\unicode-日本\bin"
Expand Down Expand Up @@ -161,6 +161,7 @@ try {
$metadata.sourceProvenance.tagMatchesSource -ne $true -or
$metadata.sourceProvenance.tagMismatchAllowed -ne $false -or
$metadata.packageKind -ne "release-candidate" -or
$metadata.previewFeatures.worktreesDeferred -ne $true -or
$metadata.sourceProvenance.kind -ne "release-tag") {
throw "package metadata did not preserve explicit source provenance: $($metadata | ConvertTo-Json -Compress)"
}
Expand Down Expand Up @@ -192,6 +193,7 @@ try {
ConvertFrom-Json
if ($localMetadata.version -ne $localVersion -or
$localMetadata.packageKind -ne "local-development" -or
$localMetadata.previewFeatures.worktreesDeferred -ne $false -or
$localMetadata.signing -notmatch "^UNSIGNED LOCAL DEVELOPMENT PACKAGE" -or
$localMetadata.sourceProvenance.kind -ne "local" -or
$localMetadata.sourceProvenance.sourceCommit -ne $localCommit -or
Expand Down
116 changes: 116 additions & 0 deletions Tools/windows/Tests/WorktreePreviewGuard.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
[CmdletBinding()]
param()

$ErrorActionPreference = "Stop"
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\..\..")).Path
$appPath = Join-Path $repoRoot "graphcode-windows\src\App.zig"
$mainPath = Join-Path $repoRoot "graphcode-windows\src\main.zig"
$buildPath = Join-Path $repoRoot "graphcode-windows\build.zig"
$packagePath = Join-Path $repoRoot "Tools\windows\package.ps1"
$app = Get-Content -LiteralPath $appPath -Raw
$main = Get-Content -LiteralPath $mainPath -Raw
$build = Get-Content -LiteralPath $buildPath -Raw
$package = Get-Content -LiteralPath $packagePath -Raw
$checks = 0

function Require([bool] $condition, [string] $message) {
if (-not $condition) { throw $message }
$script:checks++
}

function Get-FunctionBody([string] $source, [string] $name) {
$match = [regex]::Match(
$source,
"(?m)^\s*(?:pub\s+)?fn\s+$([regex]::Escape($name))\s*\("
)
if (-not $match.Success) { throw "production function '$name' was not found" }
$next = [regex]::Match(
$source.Substring($match.Index + $match.Length),
"(?m)^\s*(?:pub\s+)?fn\s+[A-Za-z0-9_]+\s*\("
)
$end = if ($next.Success) {
$match.Index + $match.Length + $next.Index
} else {
$source.Length
}
return $source.Substring($match.Index, $end - $match.Index)
}

$message = "Worktrees are deferred for this preview"
Require ($app.Contains($message)) `
"RED: production Worktrees routes do not expose the required preview deferral message"

$guardedFunctions = @(
"inspectWorktrees",
"inspectWorktreesImpl",
"presentWorktreeSweep",
"reclaimWorktrees",
"reclaimWorktreeOffer",
"keepWorktreeOffer",
"editWorktreePolicy",
"saveCurrentWorktreePolicy",
"toggleAllowReclaim",
"toggleConfirmReclaim",
"revealSelectedWorktree",
"selectWorktreeRow",
"toggleWorktreeRow",
"moveWorktreeSelection",
"applyUiaWorktreeSelection"
)
foreach ($name in $guardedFunctions) {
$body = Get-FunctionBody $app $name
Require ($body.Contains("guardWorktreesPreview")) `
"RED: production Worktrees route '$name' bypasses the centralized preview guard"
}

$routeContracts = @(
"if (action == .inspect_worktrees)",
".inspect_project_worktrees => if (selected) self.inspectWorktrees()",
".inspect_project_worktrees => if (graph.project.isLocalFilesystem()) self.inspectWorktrees()",
".inspect_worktrees => self.inspectWorktrees()",
".reclaim_worktrees => self.reclaimWorktrees()",
".edit_worktree_policy => self.editWorktreePolicy()",
".save_worktree_policy => self.saveCurrentWorktreePolicy()",
".header_worktree => return self.invokeHeader(.inspect_worktrees)",
".inspect_worktrees => self.inspectWorktrees(),",
"6 => app.inspectWorktrees()",
"7 => app.reclaimWorktrees()",
"12 => app.toggleAllowReclaim()",
"13 => app.toggleConfirmReclaim()",
".reclaim => self.reclaimWorktreeOffer(offer.path)"
)
foreach ($route in $routeContracts) {
Require ($app.Contains($route)) `
"production Worktrees route no longer funnels through the guarded action: '$route'"
}

$inspection = Get-FunctionBody $app "inspectWorktreesImpl"
$guardIndex = $inspection.IndexOf("guardWorktreesPreview")
$inspectIndex = $inspection.IndexOf("WorktreeStatus.inspect")
Require ($guardIndex -ge 0 -and $inspectIndex -gt $guardIndex) `
"RED: WorktreeStatus.inspect is reachable before the preview guard"
Require ($app.Contains("worktree_inspection_attempt_count")) `
"RED: guarded-route inspection call count is not observable"
Require ($build -match 'b\.option\(\s*bool,\s*"worktrees-deferred"') `
"RED: the Windows build has no explicit Worktrees preview option"
Require ($build.Contains('addOption(bool, "worktrees_deferred"')) `
"RED: the Worktrees preview option is not compiled into the product"
Require ($package.Contains('"-Dworktrees-deferred=$worktreesDeferred"')) `
"RED: release packaging does not pass the Worktrees preview option"
Require ($package.Contains("--worktrees-preview-state")) `
"RED: packaging does not verify the built product's Worktrees preview state"
Require ($main.Contains('"--worktrees-preview-state"')) `
"RED: the packaged product cannot report its compiled Worktrees preview state"

foreach ($unchanged in @(
'New Quick Chat\tCtrl+Q',
"Open Global Overview",
'Jump to Loop...\tCtrl+J',
'Settings...\tCtrl+Shift+,'
)) {
$mainWindow = Get-Content -LiteralPath (Join-Path $repoRoot "graphcode-windows\src\MainWindow.zig") -Raw
Require ($mainWindow.Contains($unchanged)) `
"non-Worktrees menu contract changed: '$unchanged'"
}

Write-Host "Worktree preview guard contracts: $checks passed"
36 changes: 35 additions & 1 deletion Tools/windows/package.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ $required = @("graphcoded.exe", "graphcode.exe", "zmx.exe")
$packageManifest = Get-Content (Join-Path $shellRoot "build.zig.zon") -Raw
$localSourceCommit = $null
$localSourceTreeDirty = $false
$worktreesDeferred = if ($Local) { "false" } else { "true" }
if ($Local) {
if ($Command -ne "Build") {
throw "GraphCode packaging: -Local is only valid with -Command Build"
Expand Down Expand Up @@ -76,6 +77,28 @@ function Resolve-Input([string] $path) {
if (-not (Test-Path -LiteralPath $path -PathType Container)) { Fail "input directory does not exist: $path" }
return (Resolve-Path -LiteralPath $path).Path
}
function Invoke-ShellQuery([string] $root, [string] $argument) {
$stdout = Join-Path ([IO.Path]::GetTempPath()) "graphcode-shell-$([guid]::NewGuid()).out"
$stderr = Join-Path ([IO.Path]::GetTempPath()) "graphcode-shell-$([guid]::NewGuid()).err"
try {
$process = Start-Process -FilePath (Join-Path $root "bin\graphcode-windows.exe") `
-ArgumentList $argument -Wait -PassThru `
-RedirectStandardOutput $stdout -RedirectStandardError $stderr
$errorText = if (Test-Path -LiteralPath $stderr) {
$rawError = Get-Content -LiteralPath $stderr -Raw
if ($null -eq $rawError) { "" } else { $rawError.Trim() }
} else {
""
}
Require ($process.ExitCode -eq 0) `
"graphcode-windows.exe $argument failed with exit code $($process.ExitCode): $errorText"
$rawOutput = Get-Content -LiteralPath $stdout -Raw
Require ($null -ne $rawOutput) "graphcode-windows.exe $argument produced no output"
return $rawOutput.Trim()
} finally {
Remove-Item -LiteralPath $stdout, $stderr -Force -ErrorAction SilentlyContinue
}
}
function Get-Manifest([string] $root) {
@(Get-ChildItem -LiteralPath $root -File -Recurse -Force |
Where-Object {
Expand Down Expand Up @@ -122,6 +145,9 @@ function Write-Metadata([string] $root, [string] $version) {
product = "GraphCode Windows"
version = $version
packageKind = if ($Local) { "local-development" } else { "release-candidate" }
previewFeatures = [ordered]@{
worktreesDeferred = ($worktreesDeferred -eq "true")
}
platform = "windows-x86_64"
executables = [ordered]@{ shell = "bin/graphcode-windows.exe"; daemon = "bin/graphcoded.exe"; cli = "bin/graphcode.exe"; zmx = "bin/zmx.exe" }
hostAssets = @(Get-ChildItem -LiteralPath (Join-Path $root "bin") -File -ErrorAction SilentlyContinue |
Expand Down Expand Up @@ -261,6 +287,7 @@ function Build-Package {
"-Dwinghostty-dir=$WinghosttyRoot" `
"-Dwinghostty-lib=$(Join-Path $WinghosttyRoot 'zig-out\lib\winghostty-win32-host.lib')" `
"-Dversion=$Version" `
"-Dworktrees-deferred=$worktreesDeferred" `
-Doptimize=ReleaseSafe
Require ($LASTEXITCODE -eq 0) "GraphCode Windows release build failed"
} finally { Pop-Location }
Expand All @@ -271,8 +298,12 @@ function Build-Package {
foreach ($name in $required + "graphcode-windows.exe") {
Require (Test-Path (Join-Path $root "bin\$name")) "$name was not found; pass -InputDirectory with release outputs"
}
$reportedVersion = (& (Join-Path $root "bin\graphcode-windows.exe") --version 2>$null | Select-Object -First 1).Trim()
$reportedVersion = Invoke-ShellQuery $root "--version"
Require ($reportedVersion -eq $Version) "graphcode-windows.exe reports $reportedVersion, expected $Version"
$reportedWorktreeState = Invoke-ShellQuery $root "--worktrees-preview-state"
$expectedWorktreeState = if ($worktreesDeferred -eq "true") { "deferred" } else { "available" }
Require ($reportedWorktreeState -eq $expectedWorktreeState) `
"graphcode-windows.exe reports Worktrees $reportedWorktreeState, expected $expectedWorktreeState"
Require (@(Get-ChildItem (Join-Path $root "bin") -Filter *.dll).Count -gt 0) "Swift runtime DLLs were not found"
Copy-Item (Join-Path $repoRoot "LICENSE") (Join-Path $root "LICENSE") -Force
Require ($WinghosttyRoot -and $ZmxRoot) "trusted provider roots are required for license attribution"
Expand Down Expand Up @@ -345,6 +376,9 @@ switch ($Command) {
$root = Open-Package $Package
Verify-PackageContents $root | Out-Null
$metadata = Get-Content -LiteralPath (Join-Path $root "metadata.json") -Raw | ConvertFrom-Json
$expectedWorktreesDeferred = [string] $metadata.packageKind -eq "release-candidate"
Require ([bool] $metadata.previewFeatures.worktreesDeferred -eq $expectedWorktreesDeferred) `
"package metadata contradicts its Worktrees preview policy"
if ([string] $metadata.packageKind -eq "local-development") {
$provenance = $metadata.sourceProvenance
$commit = [string] $provenance.sourceCommit
Expand Down
8 changes: 7 additions & 1 deletion graphcode-windows/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ pub fn build(b: *std.Build) !void {
});
const optimize = b.standardOptimizeOption(.{});
const package_version = b.option([]const u8, "version", "Packaged GraphCode release version") orelse "dev";
const worktrees_deferred = b.option(
bool,
"worktrees-deferred",
"Defer all Worktrees actions with the Windows preview message",
) orelse false;

const winghostty_dir = b.option(
[]const u8,
Expand Down Expand Up @@ -61,6 +66,7 @@ pub fn build(b: *std.Build) !void {
module.addIncludePath(.{ .cwd_relative = winghostty_include });
const build_options = b.addOptions();
build_options.addOption([]const u8, "version", package_version);
build_options.addOption(bool, "worktrees_deferred", worktrees_deferred);
module.addOptions("build_options", build_options);

const exe = b.addExecutable(.{
Expand All @@ -78,7 +84,7 @@ pub fn build(b: *std.Build) !void {
});
exe.addCSourceFile(.{
.file = b.path("src/AccessibilityProvider.cpp"),
.flags = &.{ "-Wno-unused-command-line-argument" },
.flags = &.{"-Wno-unused-command-line-argument"},
});
exe.addObjectFile(.{ .cwd_relative = winghostty_lib });
exe.addObjectFile(vt_library);
Expand Down
Loading
Loading