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
111 changes: 106 additions & 5 deletions .github/workflows/windows-smoke-test.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Windows Smoke Test
name: Smoke Tests

on:
pull_request:
Expand All @@ -15,10 +15,20 @@ concurrency:

jobs:
smoke-test:
name: Windows Smoke Test
runs-on: windows-latest
name: Smoke Test (${{ matrix.os }})
runs-on: ${{ matrix.runner }}
timeout-minutes: 15
if: github.event.pull_request.draft == false
strategy:
fail-fast: false
matrix:
include:
- os: Windows
runner: windows-latest
binary_name: archgate.exe
- os: Linux
runner: ubuntu-latest
binary_name: archgate
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand All @@ -33,21 +43,26 @@ jobs:
run: bun install --frozen-lockfile

- name: Lint
if: matrix.os == 'Windows'
run: bun run lint

- name: Typecheck
if: matrix.os == 'Windows'
run: bun run typecheck

- name: Format check
if: matrix.os == 'Windows'
run: bun run format:check

- name: Tests
if: matrix.os == 'Windows'
run: bun test --timeout 60000

- name: Build Windows binary
- name: Build binary
run: bun build src/cli.ts --compile --bytecode --outfile dist/archgate-smoke-test

- name: Smoke test binary
- name: Smoke test binary (Windows)
if: matrix.os == 'Windows'
shell: pwsh
run: |
$binary = "dist/archgate-smoke-test.exe"
Expand All @@ -61,3 +76,89 @@ jobs:
Write-Error "Binary exited with code $LASTEXITCODE"
exit 1
}

- name: Smoke test binary (Linux)
if: matrix.os == 'Linux'
run: |
binary="dist/archgate-smoke-test"
if [ ! -f "$binary" ]; then
echo "::error::Binary not found at $binary"
exit 1
fi
chmod +x "$binary"
output=$("$binary" --version 2>&1)
echo "archgate version: $output"

- name: Build old-version binary for upgrade test (Windows)
if: matrix.os == 'Windows'
shell: pwsh
run: |
$pkg = Get-Content package.json -Raw | ConvertFrom-Json
$originalVersion = $pkg.version
$pkg.version = "0.0.1"
$pkg | ConvertTo-Json -Depth 10 | Set-Content package.json
bun build src/cli.ts --compile --bytecode --outfile dist/archgate-upgrade-test
$pkg.version = $originalVersion
$pkg | ConvertTo-Json -Depth 10 | Set-Content package.json

- name: Build old-version binary for upgrade test (Linux)
if: matrix.os == 'Linux'
run: |
original_version=$(jq -r .version package.json)
jq '.version = "0.0.1"' package.json > package.json.tmp && mv package.json.tmp package.json
bun build src/cli.ts --compile --bytecode --outfile dist/archgate-upgrade-test
jq --arg v "$original_version" '.version = $v' package.json > package.json.tmp && mv package.json.tmp package.json

- name: Smoke test upgrade (Windows)
if: matrix.os == 'Windows'
shell: pwsh
run: |
$binDir = "$HOME\.archgate\bin"
New-Item -ItemType Directory -Path $binDir -Force | Out-Null
Copy-Item "dist/archgate-upgrade-test.exe" "$binDir\archgate.exe" -Force

$before = & "$binDir\archgate.exe" --version 2>&1
Write-Host "Before upgrade: $before"
if ($before -ne "0.0.1") {
Write-Error "Expected version 0.0.1, got $before"
exit 1
}

& "$binDir\archgate.exe" upgrade 2>&1
if ($LASTEXITCODE -ne 0) {
Write-Error "Upgrade failed with exit code $LASTEXITCODE"
exit 1
}

$after = & "$binDir\archgate.exe" --version 2>&1
Write-Host "After upgrade: $after"
if ($after -eq "0.0.1") {
Write-Error "Binary was not replaced — still reports 0.0.1"
exit 1
}
Write-Host "Upgrade smoke test passed: $before -> $after"

- name: Smoke test upgrade (Linux)
if: matrix.os == 'Linux'
run: |
bin_dir="$HOME/.archgate/bin"
mkdir -p "$bin_dir"
cp dist/archgate-upgrade-test "$bin_dir/archgate"
chmod +x "$bin_dir/archgate"

before=$("$bin_dir/archgate" --version 2>&1)
echo "Before upgrade: $before"
if [ "$before" != "0.0.1" ]; then
echo "::error::Expected version 0.0.1, got $before"
exit 1
fi

"$bin_dir/archgate" upgrade 2>&1

after=$("$bin_dir/archgate" --version 2>&1)
echo "After upgrade: $after"
if [ "$after" = "0.0.1" ]; then
echo "::error::Binary was not replaced — still reports 0.0.1"
exit 1
fi
echo "Upgrade smoke test passed: $before -> $after"
5 changes: 4 additions & 1 deletion src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ async function main() {
registerUpgradeCommand(program);
registerCleanCommand(program);

const updateCheckPromise = checkForUpdatesIfNeeded(packageJson.version);
const isUpgrade = process.argv.includes("upgrade");
const updateCheckPromise = isUpgrade
? Promise.resolve(null)
: checkForUpdatesIfNeeded(packageJson.version);
await program.parseAsync(process.argv);
const notice = await updateCheckPromise;
if (notice) console.log(notice);
Expand Down
31 changes: 27 additions & 4 deletions src/commands/clean.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import { existsSync } from "node:fs";
import { rmSync } from "node:fs";
import { existsSync, readdirSync, rmSync } from "node:fs";
import { join } from "node:path";

import type { Command } from "@commander-js/extra-typings";

import { logError } from "../helpers/log";
import { internalPath } from "../helpers/paths";

/**
* Check whether the running binary lives under ~/.archgate/bin/.
* When true, the bin/ directory must be preserved during clean.
*/
function shouldPreserveBinDir(): boolean {
const binDir = internalPath("bin");
return process.execPath.startsWith(binDir);
}

export function registerCleanCommand(program: Command) {
program
.command("clean")
Expand All @@ -18,9 +27,23 @@ export function registerCleanCommand(program: Command) {
return;
}

const preserveBin = shouldPreserveBinDir();

try {
rmSync(destinationPath, { recursive: true, force: true });
console.log(`${destinationPath} cleaned up`);
if (preserveBin) {
// Remove everything except bin/ to avoid deleting the running binary
for (const entry of readdirSync(destinationPath)) {
if (entry === "bin") continue;
rmSync(join(destinationPath, entry), {
recursive: true,
force: true,
});
}
console.log(`${destinationPath} cleaned up (bin/ preserved)`);
} else {
rmSync(destinationPath, { recursive: true, force: true });
console.log(`${destinationPath} cleaned up`);
}
} catch (error) {
logError(
`Failed to clean ${destinationPath}.`,
Expand Down
Loading
Loading