From 875312567e74c83899d0abb7d9e08a54c0a997aa Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 1 Sep 2026 12:33:48 +0000 Subject: [PATCH] fix(desktop): unblock Linux deb/rpm CI and Windows selftest exit Linux .deb packaging failed because electron-builder requires a project homepage in package.json (FpmTarget). Add homepage + repository metadata. Windows CI hung for hours after selftest:tunnel passed: fs.rmSync on the temp userData dir threw ENOTEMPTY before app.exit(), leaving Electron alive. Close servers first, retry cleanup, and always exit via .catch(). Install rpm on ubuntu-latest so the .rpm target can invoke rpmbuild. Bump desktop to 1.0.2 for the next desktop-v* tag. Co-authored-by: Venkat SF --- .github/workflows/desktop-release.yml | 6 ++++++ desktop/README.md | 2 +- desktop/package.json | 8 +++++++- desktop/scripts/tunnel-selftest.js | 26 +++++++++++++++++++++++--- 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/.github/workflows/desktop-release.yml b/.github/workflows/desktop-release.yml index ebc69f5..210ca53 100644 --- a/.github/workflows/desktop-release.yml +++ b/.github/workflows/desktop-release.yml @@ -58,6 +58,12 @@ jobs: run: ${{ matrix.os == 'ubuntu-latest' && 'xvfb-run --auto-servernum npm run selftest:tunnel' || 'npm run selftest:tunnel' }} shell: bash + - name: Install Linux packaging tools + if: matrix.os == 'ubuntu-latest' + # electron-builder's rpm target shells out to rpmbuild; ubuntu-latest + # runners do not ship it by default. + run: sudo apt-get update && sudo apt-get install -y rpm + - name: Build installers working-directory: desktop env: diff --git a/desktop/README.md b/desktop/README.md index 2688185..dd012b6 100644 --- a/desktop/README.md +++ b/desktop/README.md @@ -1,6 +1,6 @@ # DeepSQL Desktop -**Version 1.0.0** — first public Desktop cut (ships with DeepSQL product `v1.3.0`). +**Version 1.0.2** — first public Desktop cut (ships with DeepSQL product `v1.3.0`). A cross-platform desktop client for a self-hosted DeepSQL server. It connects to the VM (or bare metal) running the DeepSQL stack either **directly over TLS** or diff --git a/desktop/package.json b/desktop/package.json index 433e8b9..1cbd03b 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -1,9 +1,15 @@ { "name": "deepsql-desktop", "productName": "DeepSQL", - "version": "1.0.0", + "version": "1.0.2", "private": true, "description": "DeepSQL desktop client \u2014 connect to a self-hosted DeepSQL VM over TLS or an SSH tunnel.", + "homepage": "https://github.com/DeepSQLAI/deepsql", + "repository": { + "type": "git", + "url": "https://github.com/DeepSQLAI/deepsql.git", + "directory": "desktop" + }, "license": "Apache-2.0", "author": { "name": "DeepSQL", diff --git a/desktop/scripts/tunnel-selftest.js b/desktop/scripts/tunnel-selftest.js index 0ea917e..bd2b566 100644 --- a/desktop/scripts/tunnel-selftest.js +++ b/desktop/scripts/tunnel-selftest.js @@ -224,13 +224,23 @@ app.whenReady().then(async () => { check('missing key file is reported clearly', keyError?.code === 'key-unreadable', keyError?.code); // ── 5. Teardown ──────────────────────────────────────────────────────── - sshServer.close(); - upstream.close(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + await closeServer(sshServer); + await closeServer(upstream); + try { + // Windows can still have Electron file handles open on userData when we + // rmSync synchronously; retry briefly so CI doesn't hang after the checks + // pass (observed as ENOTEMPTY + no exit on windows-latest). + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 }); + } catch (err) { + process.stderr.write(`WARN: temp cleanup: ${err.message}\n`); + } const failed = results.filter((r) => !r.ok).length; process.stdout.write(`\n${results.length - failed}/${results.length} checks passed\n`); app.exit(failed === 0 ? 0 : 1); +}).catch((err) => { + process.stderr.write(`${err?.stack || err}\n`); + app.exit(1); }); function makeProfile({ keyPath, sshPort, upstreamPort }) { @@ -291,6 +301,16 @@ function listen(server, port, host) { }); } +function closeServer(server) { + return new Promise((resolve) => { + if (!server || !server.listening) { + resolve(); + return; + } + server.close(() => resolve()); + }); +} + function portIsFree(port) { return new Promise((resolve) => { const socket = net.connect(port, '127.0.0.1');