From 70f7a08e4fddedd59db9f73546c4b83fd32ee344 Mon Sep 17 00:00:00 2001 From: JasonShin Date: Sun, 11 Oct 2026 21:15:49 +0800 Subject: [PATCH 1/4] WIP --- README.md | 28 +++++++++++++++++++++++++++- book/docs/installation.md | 26 ++++++++++++++++++++++++++ node/bin/sqlx-ts.js | 36 ++++++++++++++++++++++++++++++++++++ node/package-lock.json | 2 +- node/package.json | 9 +++++++-- scripts/install.sh | 14 ++++++++++---- 6 files changed, 107 insertions(+), 8 deletions(-) create mode 100755 node/bin/sqlx-ts.js diff --git a/README.md b/README.md index be5ebd2e..a1e91e7f 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,32 @@ Verify the installation by running $ npx sqlx-ts --version ``` +##### Bun and Deno + +Bun and Deno do not run the npm `postinstall` step that downloads the `sqlx-ts` binary, so install the npm module for +the `sql` tag and [install the binary separately](#installing-binary-separately) to a directory on your PATH + +```bash +# Bun +$ bun add sqlx-ts +# Deno +$ deno add npm:sqlx-ts + +# macOS & ARM CPU, see below for other platforms +$ curl -LSfs https://jasonshin.github.io/sqlx-ts/install.sh | sh -s -- --os darwin --cpu arm64 --to ~/.local/bin +``` + +`bunx sqlx-ts` and `sqlx-ts` in package.json scripts then use the binary from your PATH. If the binary is missing, they +print the command to install it. + +With Bun, you can instead let it run the `postinstall` step by adding sqlx-ts to `trustedDependencies` in package.json + +```json +{ + "trustedDependencies": ["sqlx-ts"] +} +``` + And to use sqlx-ts in your code In TypeScript based projects: @@ -119,7 +145,7 @@ If you're a **Windows** user, then you can install sqlx-ts from via install.sh: # windows & x32 $ curl -LSfs https://jasonshin.github.io/sqlx-ts/install.sh | sh -s -- --os win32 --cpu x32 # windows & x64 -$ curl -LSfs https://jasonshin.github.io/sqlx-ts/install.sh | sh -s -- --os win32 --cpu x32 +$ curl -LSfs https://jasonshin.github.io/sqlx-ts/install.sh | sh -s -- --os win32 --cpu x64 ``` If you're a **Linux** user, then you can install sqlx-ts from via install.sh: diff --git a/book/docs/installation.md b/book/docs/installation.md index fb64c20b..cabaa1b9 100644 --- a/book/docs/installation.md +++ b/book/docs/installation.md @@ -22,4 +22,30 @@ Verify the installation of `sqlx-ts` binary by running $ npx sqlx-ts --version ``` +## Bun and Deno + +Bun and Deno do not run the npm `postinstall` step that downloads the `sqlx-ts` binary. Install the npm module for the +`sql` tag, then install the binary to a directory on your PATH with install.sh + +```bash +# Bun +$ bun add --dev sqlx-ts +# Deno +$ deno add --dev npm:sqlx-ts + +# --os: darwin | linux | win32, --cpu: arm64 | x64 | x32 +$ curl -LSfs https://jasonshin.github.io/sqlx-ts/install.sh | sh -s -- --os darwin --cpu arm64 --to ~/.local/bin +``` + +`bunx sqlx-ts` and `sqlx-ts` in package.json scripts then use the binary from your PATH. If the binary is missing, they +print the command to install it. + +With Bun, you can instead let it run the `postinstall` step by adding sqlx-ts to `trustedDependencies` in package.json + +```json +{ + "trustedDependencies": ["sqlx-ts"] +} +``` + 🚀 you now have `sqlx-ts` installed 🚀 \ No newline at end of file diff --git a/node/bin/sqlx-ts.js b/node/bin/sqlx-ts.js new file mode 100755 index 00000000..a1f1232e --- /dev/null +++ b/node/bin/sqlx-ts.js @@ -0,0 +1,36 @@ +#!/usr/bin/env node +const { spawnSync } = require('child_process') +const fs = require('fs') +const path = require('path') + +const binaryName = process.platform === 'win32' ? 'sqlx-ts.exe' : 'sqlx-ts' +function findOnPath() { + for (const dir of (process.env.PATH || '').split(path.delimiter)) { + const candidate = path.join(dir, binaryName) + if (fs.existsSync(candidate) && !fs.realpathSync(candidate).endsWith('.js')) { + return candidate + } + } +} + +let binary = path.join(__dirname, '..', binaryName) +if (!fs.existsSync(binary)) { + binary = findOnPath() +} + +if (!binary) { + const cpu = process.arch === 'arm64' || process.arch === 'x64' ? process.arch : 'x32' + console.error(`sqlx-ts binary is not installed. +Bun and Deno do not run the npm postinstall step that downloads it. Install it separately to a directory on your PATH: + + curl -LSfs https://jasonshin.github.io/sqlx-ts/install.sh | sh -s -- --os ${process.platform} --cpu ${cpu} --to ~/.local/bin + +See https://jasonshin.github.io/sqlx-ts for other installation options.`) + process.exit(1) +} + +const result = spawnSync(binary, process.argv.slice(2), { stdio: 'inherit' }) +if (result.error) { + throw result.error +} +process.exit(result.status ?? 1) diff --git a/node/package-lock.json b/node/package-lock.json index fd0c7e21..83b7ec3d 100644 --- a/node/package-lock.json +++ b/node/package-lock.json @@ -13,7 +13,7 @@ "adm-zip": "^0.5.16" }, "bin": { - "sqlx-ts": "sqlx-ts" + "sqlx-ts": "bin/sqlx-ts.js" }, "devDependencies": { "@types/jest": "^27.4.1", diff --git a/node/package.json b/node/package.json index c77cb5a7..80e7b2d0 100644 --- a/node/package.json +++ b/node/package.json @@ -36,7 +36,7 @@ "author": "Jason Shin ", "license": "MIT", "bin": { - "sqlx-ts": "sqlx-ts" + "sqlx-ts": "bin/sqlx-ts.js" }, "scripts": { "postinstall": "node postinstall.js", @@ -61,5 +61,10 @@ }, "engines": { "node": ">=16" - } + }, + "files": [ + "dist", + "bin", + "postinstall.js" + ] } diff --git a/scripts/install.sh b/scripts/install.sh index 882db65d..3f54276c 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -195,12 +195,18 @@ td=$(mktemp -d || mktemp -d -t tmp) echo "URL to download $url" curl -LSfs $url --output $td/sqlx-ts.zip -unzip -j $td/sqlx-ts.zip -d $td -if [ "$os" = "win32" ]; then - cp $td/sqlx-ts.exe . +curl -LSfs $url.sha256 --output $td/sqlx-ts.zip.sha256 +expected=$(tr -d '[:space:]' < $td/sqlx-ts.zip.sha256) +if command -v sha256sum > /dev/null 2>&1; then + actual=$(sha256sum $td/sqlx-ts.zip | cut -d' ' -f1) else - cp $td/sqlx-ts . + actual=$(shasum -a 256 $td/sqlx-ts.zip | cut -d' ' -f1) +fi +if [ "$actual" != "$expected" ]; then + err "checksum mismatch for $url: expected $expected, got $actual" fi +rm $td/sqlx-ts.zip.sha256 +unzip -j $td/sqlx-ts.zip -d $td # shellcheck disable=SC2045 for f in $(ls $td); do From 65a0a9364d8480232f5f4a7f83a978aaaaf44e4e Mon Sep 17 00:00:00 2001 From: JasonShin Date: Mon, 12 Oct 2026 16:07:57 +0800 Subject: [PATCH 2/4] adding per platform package --- .github/workflows/release.yaml | 20 ++- README.md | 16 +- book/docs/installation.md | 17 ++- node/bin/sqlx-ts.js | 20 ++- node/package-lock.json | 13 -- node/package.json | 9 +- node/postinstall.js | 194 ------------------------- scripts/build-npm-platform-packages.sh | 36 +++++ 8 files changed, 90 insertions(+), 235 deletions(-) delete mode 100644 node/postinstall.js create mode 100755 scripts/build-npm-platform-packages.sh diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 3fc28be7..e65b8621 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -124,13 +124,31 @@ jobs: node-version: '24' registry-url: 'https://registry.npmjs.org' - run: npm ci + - run: npm run compile + - run: cp ../README.md . - run: npm version "${TAG#v}" --no-git-tag-version env: TAG: ${{ github.event.release.tag_name }} - - run: npm publish --access public + - name: Publish platform packages and sqlx-ts + run: | + [[ "$TAG" == *-* ]] && NPM_TAG=next || NPM_TAG=latest + gh release download "$TAG" -p '*.zip' -D "$RUNNER_TEMP/zips" + ../scripts/build-npm-platform-packages.sh "$TAG" "$RUNNER_TEMP/zips" "$RUNNER_TEMP/platform" + for dir in "$RUNNER_TEMP"/platform/*; do + if [ -n "$(npm view "$(basename "$dir")@${TAG#v}" version 2> /dev/null)" ]; then + echo "$(basename "$dir")@${TAG#v} is already published" + else + npm publish "$dir" --access public --tag "$NPM_TAG" + fi + done + npm publish --access public --tag "$NPM_TAG" --ignore-scripts + env: + TAG: ${{ github.event.release.tag_name }} + GH_TOKEN: ${{ github.token }} bump-version: needs: node + if: ${{ !contains(github.event.release.tag_name, '-') }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 diff --git a/README.md b/README.md index a1e91e7f..c0d36538 100644 --- a/README.md +++ b/README.md @@ -55,23 +55,23 @@ $ npx sqlx-ts --version ##### Bun and Deno -Bun and Deno do not run the npm `postinstall` step that downloads the `sqlx-ts` binary, so install the npm module for -the `sql` tag and [install the binary separately](#installing-binary-separately) to a directory on your PATH +From v0.50.0, the `sqlx-ts` binary comes as an optional dependency for your platform (e.g. `sqlx-ts-darwin-arm64`), so +Bun and Deno install it the same way as npm ```bash # Bun $ bun add sqlx-ts +$ bunx sqlx-ts --version # Deno $ deno add npm:sqlx-ts - -# macOS & ARM CPU, see below for other platforms -$ curl -LSfs https://jasonshin.github.io/sqlx-ts/install.sh | sh -s -- --os darwin --cpu arm64 --to ~/.local/bin +$ deno run -A npm:sqlx-ts --version ``` -`bunx sqlx-ts` and `sqlx-ts` in package.json scripts then use the binary from your PATH. If the binary is missing, they -print the command to install it. +The binary is not installed with `--omit=optional` or `--no-optional`. In that case, or on a platform without a prebuilt +binary, [install the binary separately](#installing-binary-separately) to a directory on your PATH and `sqlx-ts` will use it. -With Bun, you can instead let it run the `postinstall` step by adding sqlx-ts to `trustedDependencies` in package.json +v0.49.0 and older download the binary in a `postinstall` step, which Bun and Deno do not run. For these versions, install +the binary separately, or with Bun add sqlx-ts to `trustedDependencies` in package.json ```json { diff --git a/book/docs/installation.md b/book/docs/installation.md index cabaa1b9..508b5fc8 100644 --- a/book/docs/installation.md +++ b/book/docs/installation.md @@ -24,23 +24,28 @@ $ npx sqlx-ts --version ## Bun and Deno -Bun and Deno do not run the npm `postinstall` step that downloads the `sqlx-ts` binary. Install the npm module for the -`sql` tag, then install the binary to a directory on your PATH with install.sh +From v0.50.0, the `sqlx-ts` binary comes as an optional dependency for your platform (e.g. `sqlx-ts-darwin-arm64`), so +Bun and Deno install it the same way as npm ```bash # Bun $ bun add --dev sqlx-ts +$ bunx sqlx-ts --version # Deno $ deno add --dev npm:sqlx-ts +$ deno run -A npm:sqlx-ts --version +``` + +The binary is not installed with `--omit=optional` or `--no-optional`. In that case, or on a platform without a prebuilt +binary, install the binary to a directory on your PATH with install.sh and `sqlx-ts` will use it +```bash # --os: darwin | linux | win32, --cpu: arm64 | x64 | x32 $ curl -LSfs https://jasonshin.github.io/sqlx-ts/install.sh | sh -s -- --os darwin --cpu arm64 --to ~/.local/bin ``` -`bunx sqlx-ts` and `sqlx-ts` in package.json scripts then use the binary from your PATH. If the binary is missing, they -print the command to install it. - -With Bun, you can instead let it run the `postinstall` step by adding sqlx-ts to `trustedDependencies` in package.json +v0.49.0 and older download the binary in a `postinstall` step, which Bun and Deno do not run. For these versions, install +the binary with install.sh as above, or with Bun add sqlx-ts to `trustedDependencies` in package.json ```json { diff --git a/node/bin/sqlx-ts.js b/node/bin/sqlx-ts.js index a1f1232e..34c305ca 100755 --- a/node/bin/sqlx-ts.js +++ b/node/bin/sqlx-ts.js @@ -3,7 +3,17 @@ const { spawnSync } = require('child_process') const fs = require('fs') const path = require('path') +const platformPackage = `sqlx-ts-${process.platform}-${process.arch}` const binaryName = process.platform === 'win32' ? 'sqlx-ts.exe' : 'sqlx-ts' + +function findInPlatformPackage() { + try { + return require.resolve(`${platformPackage}/${binaryName}`) + } catch { + return undefined + } +} + function findOnPath() { for (const dir of (process.env.PATH || '').split(path.delimiter)) { const candidate = path.join(dir, binaryName) @@ -13,15 +23,13 @@ function findOnPath() { } } -let binary = path.join(__dirname, '..', binaryName) -if (!fs.existsSync(binary)) { - binary = findOnPath() -} +const binary = findInPlatformPackage() || findOnPath() if (!binary) { const cpu = process.arch === 'arm64' || process.arch === 'x64' ? process.arch : 'x32' - console.error(`sqlx-ts binary is not installed. -Bun and Deno do not run the npm postinstall step that downloads it. Install it separately to a directory on your PATH: + console.error(`sqlx-ts binary is not installed. It comes from the optional dependency ${platformPackage}. +If you installed with --omit=optional or --no-optional, or copied node_modules from another OS, reinstall without them. +Otherwise install the binary separately to a directory on your PATH: curl -LSfs https://jasonshin.github.io/sqlx-ts/install.sh | sh -s -- --os ${process.platform} --cpu ${cpu} --to ~/.local/bin diff --git a/node/package-lock.json b/node/package-lock.json index 83b7ec3d..0d1839f2 100644 --- a/node/package-lock.json +++ b/node/package-lock.json @@ -7,11 +7,7 @@ "": { "name": "sqlx-ts", "version": "0.49.0", - "hasInstallScript": true, "license": "MIT", - "dependencies": { - "adm-zip": "^0.5.16" - }, "bin": { "sqlx-ts": "bin/sqlx-ts.js" }, @@ -1436,15 +1432,6 @@ "node": ">=0.4.0" } }, - "node_modules/adm-zip": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz", - "integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==", - "license": "MIT", - "engines": { - "node": ">=12.0" - } - }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", diff --git a/node/package.json b/node/package.json index 80e7b2d0..a17b118e 100644 --- a/node/package.json +++ b/node/package.json @@ -25,7 +25,7 @@ "homepage": "https://jasonshin.github.io/sqlx-ts", "repository": { "type": "git", - "url": "https://github.com/JasonShin/sqlx-ts" + "url": "git+https://github.com/JasonShin/sqlx-ts.git" }, "bugs": { "url": "https://github.com/JasonShin/sqlx-ts/issues" @@ -39,16 +39,12 @@ "sqlx-ts": "bin/sqlx-ts.js" }, "scripts": { - "postinstall": "node postinstall.js", "compile": "npx tsc -p tsconfig.json", "lint": "npx eslint --ext .ts src", "lint:fix": "npx eslint --ext .ts src --fix", "test": "npx jest", "prepublishOnly": "cp ../README.md . && npm i && npm run compile" }, - "dependencies": { - "adm-zip": "^0.5.16" - }, "devDependencies": { "@types/jest": "^27.4.1", "@types/node": "^20.14.8", @@ -64,7 +60,6 @@ }, "files": [ "dist", - "bin", - "postinstall.js" + "bin" ] } diff --git a/node/postinstall.js b/node/postinstall.js deleted file mode 100644 index ff837b4b..00000000 --- a/node/postinstall.js +++ /dev/null @@ -1,194 +0,0 @@ -const { createHash } = require('crypto') -const fs = require('fs') -const https = require('https') -const path = require('path') -const os = require('os') -const tag = require('./package.json').version -const AdmZip = require('adm-zip') - -const platform = process.platform -const cpu = process.arch - -const colors = { - reset: "\x1b[0m", - red: "\x1b[31m", - green: "\x1b[32m", - yellow: "\x1b[33m", - cyan: "\x1b[36m", -} - -const info = (msg) => console.log(`${colors.cyan}INFO: ${msg} ${colors.reset}`) -const success = (msg) => console.log(`${colors.green}SUCCESS: ${msg} ${colors.reset}`) -const warn = (msg) => console.warn(`${colors.yellow}WARNING: ${msg} ${colors.reset}`) -const error = (msg) => console.error(`${colors.red}ERROR: ${msg} ${colors.reset}`) - -function getBinaryInfo() { - let build = '' - if (platform === 'darwin') { - if (cpu === 'arm64') { - build = 'macos-arm' - } else { - build = 'macos-64-bit' - } - } else if (platform === 'win32') { - if (cpu === 'x64') { - build = 'windows-64-bit' - } else { - build = 'windows-32-bit' - } - } else if (platform === 'linux') { - if (cpu === 'x64') { - build = 'linux-64-bit' - } else if (cpu === 'arm64') { - build = 'linux-arm' - } else { - build = 'linux-32-bit' - } - } else { - throw new Error(`Unsupported platform: ${platform}-${cpu}`) - } - - return { - build, - filename: `sqlx-ts-v${tag}-${build}.zip`, - binaryName: platform === 'win32' ? 'sqlx-ts.exe' : 'sqlx-ts' - } -} - -function safeUnlink(filePath) { - try { - if (fs.existsSync(filePath)) { - fs.unlinkSync(filePath) - } - } catch (err) { - warn(`Failed to delete file: filePath: ${filePath}, err: ${err.message}`) - } -} - -// Download file from URL -function downloadFile(url, destination, redirectCount = 0) { - return new Promise((resolve, reject) => { - if (redirectCount > 5) { - return reject(new Error("Too many redirects while downloading file")) - } - - const file = fs.createWriteStream(destination) - https.get(url, (response) => { - if (response.statusCode === 302 || response.statusCode === 301) { - // Handle redirects - // Close the current file and delete it - // Then download from the new location - file.close() - safeUnlink(destination) - return downloadFile(response.headers.location, destination, redirectCount + 1) - .then(resolve) - .catch(reject) - } - - if (response.statusCode !== 200) { - file.close() - safeUnlink(destination) - return reject(new Error(`Failed to download: ${response.statusCode} ${response.statusMessage}`)) - } - - response.pipe(file) - file.on('finish', () => { - file.close(resolve) - }) - }).on('error', (err) => { - safeUnlink(destination) - reject(err) - }) - }) -} - -// Calculate SHA-256 hash of a file -function calculateSHA256(filePath) { - return new Promise((resolve, reject) => { - const hash = createHash('sha256') - const stream = fs.createReadStream(filePath) - - stream.on('data', (data) => hash.update(data)) - stream.on('end', () => resolve(hash.digest('hex'))) - stream.on('error', reject) - }) -} - -async function verifyHash(filePath, expectedHash) { - const actualHash = await calculateSHA256(filePath) - - if (actualHash !== expectedHash) { - throw new Error( - `Hash mismatch!\n` + - `Expected: ${expectedHash}\n` + - `Got: ${actualHash}\n` + - `This could indicate a corrupted download or a security issue.` - ) - } - - return true -} - -function extractBinary(zipPath, binaryName, targetPath) { - const zip = new AdmZip(zipPath) - const zipEntries = zip.getEntries() - - for (const entry of zipEntries) { - if (entry.entryName.endsWith(binaryName)) { - // Extract the entry's content directly - const data = entry.getData() - fs.writeFileSync(targetPath, data) - fs.chmodSync(targetPath, 0o755) - return - } - } - - throw new Error(`Binary ${binaryName} not found in archive`) -} - -async function install() { - try { - const { filename, binaryName } = getBinaryInfo() - const baseUrl = `https://github.com/JasonShin/sqlx-ts/releases/download/v${tag}` - const zipUrl = `${baseUrl}/${filename}` - const checksumUrl = `${zipUrl}.sha256` - - const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'sqlx-ts-')) - const zipPath = path.join(tmpDir, filename) - const checksumPath = path.join(tmpDir, `${filename}.sha256`) - const targetPath = path.join(__dirname, 'sqlx-ts' + (platform === 'win32' ? '.exe' : '')) - - info(`Downloading sqlx-ts v${tag} for ${platform}-${cpu}...`) - info(`URL: ${zipUrl}`) - - // Download the zip file - await downloadFile(zipUrl, zipPath) - success('Download complete') - - // Download and verify the checksum - info('Downloading checksum...') - await downloadFile(checksumUrl, checksumPath) - const expectedHash = fs.readFileSync(checksumPath, 'utf8').trim() - info(`Expected SHA-256: ${expectedHash}`) - - // Verify the hash - info('Verifying checksum...') - await verifyHash(zipPath, expectedHash) - success('Checksum verified successfully') - - // Extract the binary - info('Extracting binary...') - extractBinary(zipPath, binaryName, targetPath) - - // Cleanup - fs.rmSync(tmpDir, { recursive: true, force: true }) - - info('sqlx-ts installation successful') - process.exit(0) - } catch (err) { - error(`Installation failed: ${err.message}`) - process.exit(1) - } -} - -install() diff --git a/scripts/build-npm-platform-packages.sh b/scripts/build-npm-platform-packages.sh new file mode 100755 index 00000000..e9ee4545 --- /dev/null +++ b/scripts/build-npm-platform-packages.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# Usage: build-npm-platform-packages.sh +# Builds one npm package per release zip into and adds them to node/package.json as optionalDependencies +set -euo pipefail + +tag=$1 +zip_dir=$2 +out_dir=$3 +version="${tag#v}" +node_dir="$(cd "$(dirname "$0")/../node" && pwd)" + +for entry in macos-arm:darwin:arm64 macos-64-bit:darwin:x64 linux-64-bit:linux:x64 linux-arm:linux:arm64 \ + linux-32-bit:linux:ia32 windows-64-bit:win32:x64 windows-32-bit:win32:ia32; do + IFS=: read -r build os cpu <<< "$entry" + name="sqlx-ts-$os-$cpu" + dir="$out_dir/$name" + mkdir -p "$dir" + unzip -oqj "$zip_dir/sqlx-ts-$tag-$build.zip" -d "$dir" + chmod 755 "$dir"/sqlx-ts* + cat > "$dir/package.json" < Date: Mon, 12 Oct 2026 17:02:59 +0800 Subject: [PATCH 3/4] Test per-platform npm packages in CI - e2e: replace the postinstall checks with installs of the main package and the runner's platform package built from the current release, via npm and bun, run the launcher with deno, and test install.sh - release: after publishing, run npx, bunx and deno run npm:sqlx-ts@ on Linux, macOS and Windows Co-Authored-By: Claude Opus 5.5 --- .github/workflows/e2e.yaml | 65 ++++++++++++++++++++++++++++------ .github/workflows/release.yaml | 42 ++++++++++++++++++++++ 2 files changed, 96 insertions(+), 11 deletions(-) diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 5f2cefa9..5cd86996 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -33,23 +33,66 @@ jobs: with: node-version: ${{ matrix.node }} - - name: Install dependencies (npm install) - run: npm install + - name: Build npm packages from the current release + shell: bash + run: | + TEMP_DIR="${RUNNER_TEMP//\\//}" + VERSION=$(node -p "require('./package.json').version") + gh release download "v$VERSION" -p '*.zip' -D "$TEMP_DIR/zips" + ../scripts/build-npm-platform-packages.sh "v$VERSION" "$TEMP_DIR/zips" "$TEMP_DIR/platform" + git checkout package.json + npm pack --pack-destination "$TEMP_DIR" + (cd "$TEMP_DIR/platform/sqlx-ts-$(node -p 'process.platform + "-" + process.arch')" && npm pack --pack-destination "$TEMP_DIR") + env: + GH_TOKEN: ${{ github.token }} + + - name: Install sqlx-ts with its platform package + shell: bash + run: | + TEMP_DIR="${RUNNER_TEMP//\\//}" + mkdir "$TEMP_DIR/project" + cd "$TEMP_DIR/project" + npm init -y + npm install "$TEMP_DIR"/sqlx-ts-*.tgz - name: Verify sqlx-ts binary from npm install + working-directory: ${{ runner.temp }}/project + run: | + npx sqlx-ts --version + npx sqlx-ts --help + + - uses: oven-sh/setup-bun@v2 + if: matrix.node == 22 + + - name: Verify sqlx-ts binary from bun install + if: matrix.node == 22 + shell: bash run: | - chmod +x ./sqlx-ts || true - ./sqlx-ts --version - ./sqlx-ts --help + TEMP_DIR="${RUNNER_TEMP//\\//}" + mkdir "$TEMP_DIR/bun-project" + cd "$TEMP_DIR/bun-project" + echo '{ "name": "bun-project" }' > package.json + bun add "$TEMP_DIR"/sqlx-ts-*.tgz + bunx sqlx-ts --version + + - uses: denoland/setup-deno@v2 + if: matrix.node == 22 + with: + deno-version: v2.x - - name: Install using local install.sh - run: node postinstall.js + - name: Verify sqlx-ts launcher with deno + if: matrix.node == 22 + working-directory: ${{ runner.temp }}/project + run: deno run -A node_modules/sqlx-ts/bin/sqlx-ts.js --version - - name: Verify sqlx-ts binary from local install + - name: Install using install.sh + shell: bash run: | - chmod +x ./sqlx-ts || true - ./sqlx-ts --version - ./sqlx-ts --help + OS=$(node -p 'process.platform') + CPU=$(node -p '["arm64", "x64"].includes(process.arch) ? process.arch : "x32"') + TEMP_DIR="${RUNNER_TEMP//\\//}" + sh ../scripts/install.sh --os "$OS" --cpu "$CPU" --to "$TEMP_DIR/bin" + "$TEMP_DIR/bin/sqlx-ts" --version linux-distro-static-binary-test: name: linux distro ${{ matrix.distro }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index e65b8621..d65b426f 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -166,3 +166,45 @@ jobs: git push origin main env: TAG: ${{ github.event.release.tag_name }} + + smoke-test: + needs: node + name: smoke test ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, macos-latest, windows-latest ] + steps: + - uses: actions/setup-node@v6 + with: + node-version: '24' + - uses: oven-sh/setup-bun@v2 + - uses: denoland/setup-deno@v2 + with: + deno-version: v2.x + - name: Wait for npm to make the packages available + shell: bash + run: | + VERSION="${TAG#v}" + PLATFORM_PACKAGE="sqlx-ts-$(node -p 'process.platform + "-" + process.arch')" + for i in $(seq 1 30); do + if [ -n "$(npm view "sqlx-ts@$VERSION" version 2> /dev/null)" ] && [ -n "$(npm view "$PLATFORM_PACKAGE@$VERSION" version 2> /dev/null)" ]; then + exit 0 + fi + sleep 20 + done + echo "sqlx-ts@$VERSION or $PLATFORM_PACKAGE@$VERSION is not available on npm after 10 minutes" + exit 1 + env: + TAG: ${{ github.event.release.tag_name }} + - name: Run sqlx-ts with npx, bunx and deno + shell: bash + run: | + VERSION="${TAG#v}" + cd "$(mktemp -d)" + npx -y "sqlx-ts@$VERSION" --version | grep -F "sqlx-ts $VERSION" + bunx "sqlx-ts@$VERSION" --version | grep -F "sqlx-ts $VERSION" + deno run -A "npm:sqlx-ts@$VERSION" --version | grep -F "sqlx-ts $VERSION" + env: + TAG: ${{ github.event.release.tag_name }} From 114807c59a832d270a322ef7c4aa0c25ad958b10 Mon Sep 17 00:00:00 2001 From: JasonShin Date: Mon, 12 Oct 2026 17:06:34 +0800 Subject: [PATCH 4/4] Fix install.sh latest release lookup and Windows support - Find the latest release from the github.com/releases/latest redirect instead of the unauthenticated GitHub API, which is rate limited per IP and returned an empty tag on CI runners, and fail clearly if no tag is found - Drop the checks for rev and grep, which are not used and rev is missing in Git Bash on Windows; always require cut for the checksum Co-Authored-By: Claude Opus 5.5 --- scripts/install.sh | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/scripts/install.sh b/scripts/install.sh index 3f54276c..84871665 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -103,19 +103,7 @@ need mktemp need unzip need sed - -# Optional dependencies -if [ -z $tag ]; then - need cut -fi - -if [ -z $tag ]; then - need rev -fi - -if [ -z $to ]; then - need grep -fi +need cut ################ url="https://github.com/jasonshin/sqlx-ts" @@ -128,7 +116,11 @@ if [ -z $tag ]; then echo "artifact was given, it will override tag - artifact: $artifact, tag: $tag" fi - tag=$(curl --silent "https://api.github.com/repos/jasonshin/sqlx-ts/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') + tag=$(curl -LSfs -o /dev/null -w '%{url_effective}' "https://github.com/jasonshin/sqlx-ts/releases/latest" | sed 's#.*/tag/##') + case $tag in + v*) ;; + *) err "failed to find the latest release of sqlx-ts, use --tag to choose a version" ;; + esac say_err "Tag: latest ($tag)" else case $tag in