diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b11d28e3..895c35f8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -152,11 +152,11 @@ jobs: if: ${{ steps.meta.outputs.kind == 'npm-cli' }} uses: dtolnay/rust-toolchain@stable with: - targets: aarch64-apple-darwin,x86_64-apple-darwin + targets: aarch64-apple-darwin,x86_64-apple-darwin,x86_64-unknown-linux-gnu,x86_64-pc-windows-gnu - name: Install native build dependencies if: ${{ steps.meta.outputs.kind == 'npm-cli' }} - run: brew install pkg-config x264 + run: brew install pkg-config x264 mingw-w64 - name: Install root dependencies run: npm ci @@ -265,7 +265,7 @@ jobs: # ---------- Build (kind-specific) ---------- - - name: Build root simdeck (macOS arm64+x64 binaries + client + simdeck-test) + - name: Build root simdeck (macOS + Linux + Windows native artifacts + client + simdeck-test) if: ${{ steps.meta.outputs.kind == 'npm-cli' }} run: | SIMDECK_BUILD_TARGET=aarch64-apple-darwin npm run build:cli @@ -279,20 +279,31 @@ jobs: build/simdeck-bin-darwin-arm64 \ build/simdeck-bin-darwin-x64 + SIMDECK_DISABLE_X264=1 SIMDECK_BUILD_TARGET=x86_64-unknown-linux-gnu npm run build:cli + cp build/simdeck-bin build/simdeck-bin-linux-x64 + + SIMDECK_DISABLE_X264=1 SIMDECK_BUILD_TARGET=x86_64-pc-windows-gnu npm run build:cli + cp build/simdeck-bin.exe build/simdeck-bin-win32-x64.exe + npm run build:client npm run build:simdeck-test - - name: Verify CLI artifacts are macOS arm64+x64 binaries + - name: Verify CLI artifacts are published for all supported hosts if: ${{ steps.meta.outputs.kind == 'npm-cli' }} run: | test -x build/simdeck-bin test -x build/simdeck-bin-darwin-arm64 test -x build/simdeck-bin-darwin-x64 + test -x build/simdeck-bin-linux-x64 + test -x build/simdeck-bin-win32-x64.exe + file build/simdeck-bin file build/simdeck-bin | grep -q 'arm64' file build/simdeck-bin | grep -q 'x86_64' file build/simdeck-bin-darwin-arm64 | grep -q 'arm64' file build/simdeck-bin-darwin-x64 | grep -q 'x86_64' + file build/simdeck-bin-linux-x64 | grep -q 'ELF' + file build/simdeck-bin-win32-x64.exe | grep -Eq 'PE32|PE32\+' # ---------- Apple codesign + notarize (root simdeck only) ---------- diff --git a/package.json b/package.json index 93affbf5..d7f0eef8 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "scripts/studio-provider-bridge.mjs", "scripts/postinstall.mjs", "build/simdeck-bin", + "build/simdeck-bin.exe", "build/camera/", "build/simdeck-bin-darwin-arm64", "build/simdeck-bin-darwin-x64", diff --git a/packages/cli/bin/simdeck.mjs b/packages/cli/bin/simdeck.mjs index 5ad856fa..aab6fa2e 100755 --- a/packages/cli/bin/simdeck.mjs +++ b/packages/cli/bin/simdeck.mjs @@ -29,8 +29,21 @@ if (!existsSync(binaryPath)) { function findPackageRoot(startDir) { let current = path.resolve(startDir); + const buildMarkers = [ + "simdeck-bin", + "simdeck-bin.exe", + "simdeck-bin-darwin-arm64", + "simdeck-bin-darwin-x64", + "simdeck-bin-linux-arm64", + "simdeck-bin-linux-x64", + "simdeck-bin-win32-x64.exe", + ]; + while (true) { - if (existsSync(path.join(current, "build", "simdeck-bin"))) { + if ( + existsSync(path.join(current, "package.json")) || + buildMarkers.some((marker) => existsSync(path.join(current, "build", marker))) + ) { return current; } const parent = path.dirname(current); @@ -57,18 +70,21 @@ function resolveBinaryPath(rootDir) { return null; } - const platformBinaryPath = path.join(rootDir, "build", binary); - if (existsSync(platformBinaryPath)) { - return platformBinaryPath; - } - - for (const fallback of ["simdeck-bin.exe", "simdeck-bin"]) { - const fallbackBinaryPath = path.join(rootDir, "build", fallback); - if (existsSync(fallbackBinaryPath)) { - return fallbackBinaryPath; + const candidateNames = [ + binary, + "simdeck-bin.exe", + "simdeck-bin", + ...Object.values(binaryByHost), + ]; + + for (const candidate of candidateNames) { + const candidatePath = path.join(rootDir, "build", candidate); + if (existsSync(candidatePath)) { + return candidatePath; } } - return platformBinaryPath; + + return path.join(rootDir, "build", binary); } let child; diff --git a/scripts/github-actions.test.mjs b/scripts/github-actions.test.mjs index fe10f1d7..8bd6c1c8 100644 --- a/scripts/github-actions.test.mjs +++ b/scripts/github-actions.test.mjs @@ -25,6 +25,10 @@ const ciWorkflow = readFileSync( new URL("../.github/workflows/ci.yml", import.meta.url), "utf8", ); +const releaseWorkflow = readFileSync( + new URL("../.github/workflows/release.yml", import.meta.url), + "utf8", +); const packageJson = JSON.parse( readFileSync(new URL("../package.json", import.meta.url), "utf8"), ); @@ -65,6 +69,14 @@ test("npm CLI wrapper resolves Windows x64 native binary", () => { assert.match(cliWrapper, /simdeck-bin-win32-x64\.exe/); }); +test("release workflow builds all supported native CLI artifacts", () => { + assert.match(releaseWorkflow, /x86_64-pc-windows-gnu/); + assert.match(releaseWorkflow, /simdeck-bin-win32-x64\.exe/); + assert.match(releaseWorkflow, /x86_64-unknown-linux-gnu/); + assert.match(releaseWorkflow, /simdeck-bin-linux-x64/); + assert.match(releaseWorkflow, /mingw-w64/); +}); + test("CI runs Android emulator integration on Linux and Windows", () => { assert.match(ciWorkflow, /integration-android:/); assert.match(ciWorkflow, /os:\s*\[\s*ubuntu-latest,\s*windows-latest\s*\]/);