diff --git a/.github/scripts/create-desktop-update-manifest.mjs b/.github/scripts/create-desktop-update-manifest.mjs index 5b2dc4ecb..af4fda466 100755 --- a/.github/scripts/create-desktop-update-manifest.mjs +++ b/.github/scripts/create-desktop-update-manifest.mjs @@ -23,11 +23,15 @@ const platformArtifacts = [ 'darwin-x86_64', ), ], - ['windows-x86_64', selectArtifact(assets, /-setup\.exe$/i, 'windows-x86_64')], + [ + 'windows-x86_64', + selectArtifact(assets, /-setup\.exe$/i, 'windows-x86_64', true), + ], ['linux-x86_64', selectArtifact(assets, /\.AppImage$/i, 'linux-x86_64')], ]; for (const [platform, artifact] of platformArtifacts) { + if (!artifact) continue; const signatureFile = `${artifact}.sig`; if (!assets.includes(signatureFile)) { throw new Error(`Missing updater signature for ${artifact}`); @@ -47,8 +51,9 @@ const manifest = { }; fs.writeFileSync(options.output, `${JSON.stringify(manifest, null, 2)}\n`); -function selectArtifact(assets, pattern, platform) { +function selectArtifact(assets, pattern, platform, optional = false) { const matches = assets.filter((asset) => pattern.test(asset)); + if (optional && matches.length === 0) return undefined; if (matches.length !== 1) { throw new Error( `Expected one updater artifact for ${platform}, found ${matches.length}: ${matches.join(', ')}`, diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index 284dd6b25..2db5342c0 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -35,21 +35,10 @@ jobs: strategy: fail-fast: false matrix: - include: - - name: 'macOS Apple Silicon' - os: 'macos-15' - target: 'aarch64-apple-darwin' - legacy_arch: 'arm64' - - name: 'macOS Intel' - os: 'macos-15-intel' - target: 'x86_64-apple-darwin' - legacy_arch: 'x64' - - name: 'Windows x64' - os: 'windows-2025' - target: 'x86_64-pc-windows-msvc' - - name: 'Linux x64' - os: 'ubuntu-22.04' - target: 'x86_64-unknown-linux-gnu' + include: >- + ${{ fromJSON(inputs.publish && + '[{"name":"macOS Apple Silicon","os":"macos-15","target":"aarch64-apple-darwin","legacy_arch":"arm64"},{"name":"macOS Intel","os":"macos-15-intel","target":"x86_64-apple-darwin","legacy_arch":"x64"},{"name":"Linux x64","os":"ubuntu-22.04","target":"x86_64-unknown-linux-gnu"}]' || + '[{"name":"macOS Apple Silicon","os":"macos-15","target":"aarch64-apple-darwin","legacy_arch":"arm64"},{"name":"macOS Intel","os":"macos-15-intel","target":"x86_64-apple-darwin","legacy_arch":"x64"},{"name":"Windows x64","os":"windows-2025","target":"x86_64-pc-windows-msvc"},{"name":"Linux x64","os":"ubuntu-22.04","target":"x86_64-unknown-linux-gnu"}]') }} steps: - name: 'Check out source' uses: 'actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10' # v6.0.3 @@ -352,6 +341,9 @@ jobs: for manifest in macos:latest-mac.yml windows:latest.yml linux:latest-linux.yml; do platform="${manifest%%:*}" output="${manifest#*:}" + if [[ "$platform" == 'windows' ]] && ! compgen -G 'release-assets/*-setup.exe' >/dev/null; then + continue + fi node .github/scripts/create-electron-bridge-manifest.mjs --assets release-assets --platform "$platform" --version "$RELEASE_VERSION" --output "release-assets/$output" done fi diff --git a/packages/desktop-shell/scripts/test-release.js b/packages/desktop-shell/scripts/test-release.js index 522dfd608..dbf292f5d 100755 --- a/packages/desktop-shell/scripts/test-release.js +++ b/packages/desktop-shell/scripts/test-release.js @@ -22,6 +22,14 @@ const electronBridgeScript = path.join( 'scripts', 'create-electron-bridge-manifest.mjs', ); +const desktopUpdateScript = path.join( + packageDir, + '..', + '..', + '.github', + 'scripts', + 'create-desktop-update-manifest.mjs', +); const root = fs.mkdtempSync( path.join(os.tmpdir(), 'openwork-desktop-release-test-'), ); @@ -32,6 +40,7 @@ try { testMacosPermissions(); testReleaseWorkflow(); testRuntimePreparationContract(); + testDesktopUpdateManifest(path.join(root, 'desktop-update')); testElectronBridgeManifest(path.join(root, 'electron-bridge')); testChecksumRefresh(path.join(root, 'checksums')); testVersionSynchronization(path.join(root, 'version')); @@ -258,10 +267,54 @@ function testReleaseWorkflow() { /if: '?inputs\.dry_run == false'?[\s\S]*contents: '?write'?/, ); assert.match(publishJob, /secrets: '?inherit'?/); + const matrices = buildWorkflow.match( + /fromJSON\(inputs\.publish &&\s*'([^']+)' \|\|\s*'([^']+)'\)/, + ); + assert.ok(matrices); + assert.equal( + JSON.parse(matrices[1]).some(({ os }) => os.startsWith('windows-')), + false, + ); + assert.equal( + JSON.parse(matrices[2]).some(({ os }) => os.startsWith('windows-')), + true, + ); assert.doesNotMatch(workflow, /uses: [^\n]+@(v\d|stable)\b/); assert.doesNotMatch(workflow, /push --force|force-with-lease/); } +function testDesktopUpdateManifest(directory) { + const assets = path.join(directory, 'assets'); + const output = path.join(directory, 'latest.json'); + fs.mkdirSync(assets, { recursive: true }); + for (const artifact of [ + 'OpenWork-aarch64-apple-darwin.app.tar.gz', + 'OpenWork-x86_64-apple-darwin.app.tar.gz', + 'OpenWork_0.2.1_amd64.AppImage', + ]) { + fs.writeFileSync(path.join(assets, artifact), artifact); + fs.writeFileSync(path.join(assets, `${artifact}.sig`), `signature:${artifact}`); + } + execFileSync(process.execPath, [ + desktopUpdateScript, + '--assets', + assets, + '--repository', + 'modelstudioai/openwork', + '--tag', + 'openwork-v0.2.1', + '--version', + '0.2.1', + '--output', + output, + ]); + assert.deepEqual(Object.keys(JSON.parse(fs.readFileSync(output)).platforms), [ + 'darwin-aarch64', + 'darwin-x86_64', + 'linux-x86_64', + ]); +} + function testElectronBridgeManifest(directory) { const assets = path.join(directory, 'assets'); fs.mkdirSync(assets, { recursive: true });