Skip to content
Open
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
185 changes: 185 additions & 0 deletions .github/workflows/alternative-runtimes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
name: Alternative Runtimes (Bun & Deno)

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
bun-test:
name: Bun ${{ matrix.bun-version }} on ${{ matrix.os }}
# Skip this job for version bump commits (binary won't exist yet)
if: "!contains(github.event.head_commit.message, 'Release')"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]
bun-version: [ '1.0.0', 'latest' ]

steps:
- uses: actions/checkout@v3

- name: Setup Bun ${{ matrix.bun-version }}
uses: oven-sh/setup-bun@v1
with:
bun-version: ${{ matrix.bun-version }}

- name: Verify Bun installation
run: bun --version

- name: Build docker-compose services for integration tests
run: docker compose -f docker-compose.yml up -d
env:
MYSQL_VERSION: 8
PG_VERSION: 16
MYSQL_MIGRATION_FILE: 'mysql_migration.sql'

- name: Wait for databases to be ready
uses: GuillaumeFalourd/wait-sleep-action@v1
with:
Comment on lines +39 to +45
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow runs docker compose ... on macOS and Windows too. Elsewhere in this repo (e.g., .github/workflows/compatibility.yaml:74-90) docker-compose steps are gated to runner.os == 'Linux'. Consider applying the same gating here or restricting the OS matrix, otherwise non-Linux runners may fail if Docker isn’t available.

Copilot uses AI. Check for mistakes.
time: '10'

- name: Check docker-compose services
run: docker ps -a

- name: Install dependencies (npm install via postinstall)
working-directory: ./node
run: bun install

- name: Test CLI wrapper with Bun (--version)
working-directory: ./node
run: bun run cli.js --version

- name: Test CLI wrapper with Bun (--help)
working-directory: ./node
run: bun run cli.js --help

- name: Add happy.ts test file
shell: bash
run: |
cat << 'EOF' > tests/staging/happy.ts
import { sql } from 'sqlx-ts'

const selectSql4 = sql`
SELECT items.*
FROM items;
`
EOF

- name: Run happy test
working-directory: ./node
shell: bash
run: bun run cli.js --config=../.sqlxrc.sample.json ../tests/staging

Comment on lines +63 to +79
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The happy test file is created under ./node/tests/staging/happy.ts (because the job default working-directory is ./node), but the CLI is invoked against ../tests/staging (repo root). Since tests/staging doesn’t exist in the repo by default, this path mismatch will make the test run against an empty/missing directory. Create ../tests/staging (like compatibility.yaml does) or change the CLI argument to ./tests/staging to match where the file is written.

Copilot uses AI. Check for mistakes.
- name: Verify CLI wrapper is JavaScript (not binary)
working-directory: ./node
shell: bash
run: |
if file cli.js | grep -q "script\|text\|ASCII"; then
echo "✅ cli.js is a JavaScript file"
else
echo "❌ cli.js is not a text file!"
file cli.js
exit 1
fi

deno-test:
name: Deno ${{ matrix.deno-version }} on ${{ matrix.os }}
# Skip this job for version bump commits (binary won't exist yet)
if: "!contains(github.event.head_commit.message, 'Release')"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]
deno-version: [ 'v1.x', 'v2.x' ]

steps:
- uses: actions/checkout@v3

- name: Setup Deno ${{ matrix.deno-version }}
uses: denoland/setup-deno@v1
with:
deno-version: ${{ matrix.deno-version }}

- name: Verify Deno installation
run: deno --version

- name: Setup Node.js (for npm install to download binary)
uses: actions/setup-node@v3
with:
node-version: 20

- name: Build docker-compose services for integration tests
run: docker compose -f docker-compose.yml up -d
env:
MYSQL_VERSION: 8
PG_VERSION: 16
MYSQL_MIGRATION_FILE: 'mysql_migration.sql'

- name: Wait for databases to be ready
uses: GuillaumeFalourd/wait-sleep-action@v1
with:
time: '10'

- name: Check docker-compose services
run: docker ps -a

- name: Install dependencies (npm install via postinstall)
working-directory: ./node
run: bun install

Comment on lines +136 to +137
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The step name says "npm install" but the command is bun install. Renaming this step (or switching the install command) would avoid confusion when diagnosing CI failures, especially since other steps in this job are Deno-specific.

Copilot uses AI. Check for mistakes.
- name: Test CLI wrapper with Bun (--version)
working-directory: ./node
run: bun run cli.js --version

- name: Test CLI wrapper with Bun (--help)
working-directory: ./node
Comment on lines +136 to +143
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In deno-test, Bun is used (bun install, bun run ...) but Bun is never set up in this job (no oven-sh/setup-bun step). This will fail on runners where Bun isn’t preinstalled. Either add Bun setup to this job or replace these steps with npm install/node equivalents.

Copilot uses AI. Check for mistakes.
run: bun run cli.js --help

- name: Add happy.ts test file
shell: bash
run: |
cat << 'EOF' > tests/staging/happy.ts
import { sql } from 'sqlx-ts'

const selectSql4 = sql`
SELECT items.*
FROM items;
`
EOF

- name: Run happy test
working-directory: ./node
shell: bash
Comment on lines +145 to +160
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same path mismatch in the Deno job: happy.ts is written to ./node/tests/staging, but the CLI is run with ../tests/staging. Align the creation path and the CLI target path (either create/write to ../tests/staging or run the CLI against ./tests/staging).

Copilot uses AI. Check for mistakes.
run: deno run --allow-read --allow-run cli.js --config=../.sqlxrc.sample.json ../tests/staging

- name: Install dependencies and download binary
working-directory: ./node
run: npm install

- name: Test CLI wrapper with Deno (--version)
working-directory: ./node
run: deno run --allow-read --allow-run cli.js --version

- name: Test CLI wrapper with Deno (--help)
working-directory: ./node
run: deno run --allow-read --allow-run cli.js --help

- name: Verify CLI wrapper is JavaScript (not binary)
working-directory: ./node
shell: bash
run: |
if file cli.js | grep -q "script\|text\|ASCII"; then
echo "✅ cli.js is a JavaScript file"
else
echo "❌ cli.js is not a text file!"
file cli.js
exit 1
fi
14 changes: 6 additions & 8 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,18 @@ jobs:
- name: Install dependencies (npm install)
run: npm install

- name: Verify sqlx-ts binary from npm install
- name: Verify sqlx-ts CLI wrapper from npm install
run: |
chmod +x ./sqlx-ts || true
./sqlx-ts --version
./sqlx-ts --help
node cli.js --version
node cli.js --help
Comment on lines +39 to +42
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These e2e checks invoke the wrapper directly via node cli.js, which doesn’t validate that the published npm bin entry (sqlx-ts) works end-to-end (shim creation, path resolution, etc.). Consider executing ./node_modules/.bin/sqlx-ts (or npx sqlx-ts) here to test the actual installed CLI entrypoint.

Copilot uses AI. Check for mistakes.

- name: Install using local install.sh
run: node postinstall.js

- name: Verify sqlx-ts binary from local install
- name: Verify sqlx-ts CLI wrapper from local install
run: |
chmod +x ./sqlx-ts || true
./sqlx-ts --version
./sqlx-ts --help
node cli.js --version
node cli.js --help
Comment on lines +47 to +50
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as above: this verifies node cli.js rather than the installed npm bin (sqlx-ts). Running ./node_modules/.bin/sqlx-ts/npx sqlx-ts here would ensure the bin mapping works after the local install step too.

Copilot uses AI. Check for mistakes.

linux-distro-static-binary-test:
name: linux distro ${{ matrix.distro }}
Expand Down
38 changes: 38 additions & 0 deletions node/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env node

const { spawn } = require('child_process');
const path = require('path');
const fs = require('fs');

// Determine the binary name based on platform
const platform = process.platform;
const binaryName = platform === 'win32' ? 'sqlx-ts.exe' : 'sqlx-ts';
const binaryPath = path.join(__dirname, binaryName);

// Check if binary exists
if (!fs.existsSync(binaryPath)) {
console.error(`ERROR: sqlx-ts binary not found at ${binaryPath}`);
console.error('Please ensure the package was installed correctly (postinstall script should have downloaded it).');
process.exit(1);
}

// Spawn the binary with all arguments passed through
const child = spawn(binaryPath, process.argv.slice(2), {
stdio: 'inherit',
windowsHide: true
});

// Handle exit
child.on('exit', (code, signal) => {
if (signal) {
process.kill(process.pid, signal);
} else {
process.exit(code || 0);
}
});

// Handle errors
child.on('error', (err) => {
console.error(`ERROR: Failed to execute sqlx-ts binary: ${err.message}`);
process.exit(1);
});
Comment on lines +3 to +38
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cli.js is written as a Node/CommonJS entrypoint (#!/usr/bin/env node, require(...), process.platform). In this PR you run it via deno run ... cli.js, which will fail unless Deno Node-compat/CommonJS handling is explicitly enabled. To actually support Deno, consider providing a Deno-compatible wrapper (e.g., using Deno.Command) or switching this wrapper to an ESM module that uses node: imports and updating the Deno invocation accordingly.

Suggested change
const { spawn } = require('child_process');
const path = require('path');
const fs = require('fs');
// Determine the binary name based on platform
const platform = process.platform;
const binaryName = platform === 'win32' ? 'sqlx-ts.exe' : 'sqlx-ts';
const binaryPath = path.join(__dirname, binaryName);
// Check if binary exists
if (!fs.existsSync(binaryPath)) {
console.error(`ERROR: sqlx-ts binary not found at ${binaryPath}`);
console.error('Please ensure the package was installed correctly (postinstall script should have downloaded it).');
process.exit(1);
}
// Spawn the binary with all arguments passed through
const child = spawn(binaryPath, process.argv.slice(2), {
stdio: 'inherit',
windowsHide: true
});
// Handle exit
child.on('exit', (code, signal) => {
if (signal) {
process.kill(process.pid, signal);
} else {
process.exit(code || 0);
}
});
// Handle errors
child.on('error', (err) => {
console.error(`ERROR: Failed to execute sqlx-ts binary: ${err.message}`);
process.exit(1);
});
// Deno-compatible launcher path
if (typeof Deno !== 'undefined') {
const isWindows = Deno.build.os === 'windows';
const binaryName = isWindows ? 'sqlx-ts.exe' : 'sqlx-ts';
// Resolve binary path relative to this script using import.meta.url
const binaryUrl = new URL(`./${binaryName}`, import.meta.url);
// On Windows, strip leading slash from pathname to get a proper filesystem path
const binaryPath = isWindows ? binaryUrl.pathname.replace(/^\\//, '') : binaryUrl.pathname;
async function main() {
// Check if binary exists
try {
const info = Deno.statSync(binaryPath);
if (!info.isFile) {
console.error(`ERROR: sqlx-ts binary not found at ${binaryPath}`);
console.error('Please ensure the package was installed correctly (postinstall script should have downloaded it).');
Deno.exit(1);
}
} catch (_err) {
console.error(`ERROR: sqlx-ts binary not found at ${binaryPath}`);
console.error('Please ensure the package was installed correctly (postinstall script should have downloaded it).');
Deno.exit(1);
}
const cmd = new Deno.Command(binaryPath, {
args: Deno.args,
stdin: 'inherit',
stdout: 'inherit',
stderr: 'inherit',
});
const child = cmd.spawn();
const status = await child.status;
if (status.signal !== null && status.signal !== undefined) {
// Deno does not expose a direct equivalent of process.kill(process.pid, signal),
// so approximate by exiting with non-zero status if signaled.
Deno.exit(1);
}
Deno.exit(status.code ?? 0);
}
main().catch((err) => {
console.error(`ERROR: Failed to execute sqlx-ts binary: ${err && err.message ? err.message : String(err)}`);
Deno.exit(1);
});
}
// Node.js/CommonJS launcher path (original behavior)
if (typeof Deno === 'undefined') {
const { spawn } = require('child_process');
const path = require('path');
const fs = require('fs');
// Determine the binary name based on platform
const platform = process.platform;
const binaryName = platform === 'win32' ? 'sqlx-ts.exe' : 'sqlx-ts';
const binaryPath = path.join(__dirname, binaryName);
// Check if binary exists
if (!fs.existsSync(binaryPath)) {
console.error(`ERROR: sqlx-ts binary not found at ${binaryPath}`);
console.error('Please ensure the package was installed correctly (postinstall script should have downloaded it).');
process.exit(1);
}
// Spawn the binary with all arguments passed through
const child = spawn(binaryPath, process.argv.slice(2), {
stdio: 'inherit',
windowsHide: true
});
// Handle exit
child.on('exit', (code, signal) => {
if (signal) {
process.kill(process.pid, signal);
} else {
process.exit(code || 0);
}
});
// Handle errors
child.on('error', (err) => {
console.error(`ERROR: Failed to execute sqlx-ts binary: ${err.message}`);
process.exit(1);
});
}

Copilot uses AI. Check for mistakes.
2 changes: 1 addition & 1 deletion node/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,19 @@
"version": "0.40.0",
"description": "sqlx-ts ensures your raw SQLs are compile-time checked",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"maintainers": [
"visualbbasic@gmail.com"
],
"author": "Jason Shin <visualbbasic@gmail.com>",
"license": "MIT",
"bin": "./sqlx-ts",
"bin": "./cli.js",
"scripts": {
"postinstall": "node postinstall.js",
"compile": "npx tsc -p tsconfig.json",
Expand Down
Loading