Skip to content
Merged
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
118 changes: 115 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,134 @@ name: CI

on:
push:
branches: [main]
pull_request:

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

jobs:
# --- primary build + unit/golden tests ---
build-and-test:
name: build + test (node ${{ matrix.node }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [20, 22]
name: Node ${{ matrix.node-version }}
node: [20, 22]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
node-version: ${{ matrix.node }}
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm build
- run: pnpm test

# --- create-dql-app smoke test ---
# Guards the "5 minutes to first dashboard" demo gate.
scaffold-smoke:
name: create-dql-app smoke
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: node packages/create-dql-app/test/smoke.mjs

# --- docs build + internal link check ---
docs:
name: docs build + link check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: node apps/docs/scripts/link-check.mjs
- run: pnpm -F @duckcodeailabs/docs build

# --- dql fmt --check across the repo ---
# Gates canonical .dql serialization — catches whitespace churn before
# it reaches main.
format-check:
name: dql fmt --check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm -F @duckcodeailabs/dql-cli build
- name: dql fmt --check
run: |
set -e
shopt -s globstar nullglob
files=(packages/create-dql-app/templates/**/*.dql)
if [ ${#files[@]} -eq 0 ]; then
echo "no .dql files to check — skipping"
exit 0
fi
for f in "${files[@]}"; do
node apps/cli/dist/index.js fmt --check "$f"
done

# --- 4,000-model stress test (perf gate) ---
# Gates: cold <30s, warm <2s. See docs.duckcode.ai/contribute/testing.
stress-test:
name: stress (4k-model synthetic project)
runs-on: ubuntu-latest
# Only run on main branch pushes — expensive.
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm build
- name: generate 4,000-model synthetic dbt project
run: node scripts/bench/gen-dbt-project.mjs --models 4000 --out /tmp/stress
- name: run benchmark (gates cold <30s, warm <2s)
run: DQL_CLI="node $PWD/apps/cli/dist/index.js" node scripts/bench/run-bench.mjs /tmp/stress

# --- E2E Playwright (notebook happy path) ---
# Runs the Jaffle Shop path in a headless browser. On PRs that don't
# touch the notebook app, we skip to keep CI fast.
e2e:
name: playwright e2e
runs-on: ubuntu-latest
if: github.event_name == 'push' || contains(github.event.pull_request.changed_files, 'apps/dql-notebook')
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm build
- run: pnpm -F @duckcodeailabs/dql-notebook-app exec playwright install --with-deps chromium
continue-on-error: true
- run: pnpm -F @duckcodeailabs/dql-notebook-app test:e2e
continue-on-error: true # gate hardens to `false` once the suite lands

# --- summary gate for branch protection ---
ci-ok:
name: ci-ok
runs-on: ubuntu-latest
needs: [build-and-test, scaffold-smoke, docs, format-check]
steps:
- run: echo "All required CI gates passed."
54 changes: 54 additions & 0 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Deploy docs

on:
push:
branches: [main]
paths:
- 'apps/docs/**'
- '.github/workflows/deploy-docs.yml'
workflow_dispatch:

concurrency:
group: deploy-docs
cancel-in-progress: true

jobs:
deploy:
name: Vercel production
runs-on: ubuntu-latest
if: github.repository == 'duckcode-ai/dql'
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_DOCS_PROJECT_ID }}
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with: { version: 9 }
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm

- name: Guard — secrets present
run: |
if [ -z "$VERCEL_TOKEN" ] || [ -z "$VERCEL_ORG_ID" ] || [ -z "$VERCEL_PROJECT_ID" ]; then
echo "::warning::Vercel secrets not configured; skipping deploy."
exit 0
fi

- run: pnpm install --frozen-lockfile
- run: pnpm -F @duckcodeailabs/docs build

- name: Install Vercel CLI
run: pnpm add -g vercel@latest

- name: Pull Vercel env
working-directory: apps/docs
run: vercel pull --yes --environment=production --token="$VERCEL_TOKEN"

- name: Deploy
working-directory: apps/docs
run: |
vercel build --prod --token="$VERCEL_TOKEN"
vercel deploy --prebuilt --prod --token="$VERCEL_TOKEN"
75 changes: 75 additions & 0 deletions .github/workflows/release-desktop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Release (desktop binaries)

on:
push:
tags: ['v*.*.*']
workflow_dispatch:

jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- { os: macos-14, target: aarch64-apple-darwin, rust_target: aarch64-apple-darwin }
- { os: macos-13, target: x86_64-apple-darwin, rust_target: x86_64-apple-darwin }
- { os: ubuntu-22.04, target: x86_64-unknown-linux-gnu, rust_target: x86_64-unknown-linux-gnu }
- { os: windows-latest, target: x86_64-pc-windows-msvc, rust_target: x86_64-pc-windows-msvc }
runs-on: ${{ matrix.os }}
name: desktop (${{ matrix.target }})
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with: { version: 9 }
- uses: actions/setup-node@v4
with: { node-version: 20, cache: pnpm }
- uses: dtolnay/rust-toolchain@stable
with: { targets: ${{ matrix.rust_target }} }

- name: Install Linux deps
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev patchelf

- run: pnpm install --frozen-lockfile

- name: Build notebook frontend
run: pnpm -F @duckcodeailabs/dql-notebook-app build

- name: Build Tauri bundle
working-directory: apps/desktop
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: pnpm tauri build --target ${{ matrix.rust_target }}

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: desktop-${{ matrix.target }}
path: |
apps/desktop/src-tauri/target/${{ matrix.rust_target }}/release/bundle/**/*.dmg
apps/desktop/src-tauri/target/${{ matrix.rust_target }}/release/bundle/**/*.AppImage
apps/desktop/src-tauri/target/${{ matrix.rust_target }}/release/bundle/**/*.deb
apps/desktop/src-tauri/target/${{ matrix.rust_target }}/release/bundle/**/*.rpm
apps/desktop/src-tauri/target/${{ matrix.rust_target }}/release/bundle/**/*.msi

publish:
name: attach to GitHub Release
needs: build
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
permissions:
contents: write
steps:
- uses: actions/download-artifact@v4
with: { path: artifacts }
- uses: softprops/action-gh-release@v2
with:
files: artifacts/**/*
fail_on_unmatched_files: false
34 changes: 34 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,37 @@ jobs:
path: apps/vscode-extension/*.vsix
- if: ${{ env.VSCE_PAT != '' && (startsWith(github.ref, 'refs/tags/v') || inputs.publish_extension == true) }}
run: pnpm --filter dql-language-support publish:vsce

publish-homebrew:
# Open a PR against the tap repo with the regenerated formula. We don't
# push directly — the tap repo gets human review.
if: github.repository == 'duckcode-ai/dql' && startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
needs: publish-packages
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Resolve version from tag
id: v
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
- name: Render Homebrew formula
run: node packaging/homebrew/publish.mjs "${{ steps.v.outputs.version }}"
- name: Open PR on tap repo
env:
GH_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
if: env.GH_TOKEN != ''
run: |
set -e
git clone https://x-access-token:${GH_TOKEN}@github.com/duckcode-ai/homebrew-dql.git /tmp/tap
cp packaging/homebrew/dql.rb /tmp/tap/Formula/dql.rb
cd /tmp/tap
git config user.name "duckcode-release-bot"
git config user.email "release@duckcode.ai"
branch="release/v${{ steps.v.outputs.version }}"
git checkout -b "$branch"
git add Formula/dql.rb
git commit -m "dql ${{ steps.v.outputs.version }}"
git push -u origin "$branch"
gh pr create --title "dql ${{ steps.v.outputs.version }}" --body "Automated release PR for \`dql@${{ steps.v.outputs.version }}\`."
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ dist
npm-debug.log*
pnpm-debug.log*
jaffle-shop/
!packages/create-dql-app/templates/jaffle-shop/
.claude/worktrees/
2 changes: 1 addition & 1 deletion apps/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@duckcodeailabs/dql-cli",
"version": "0.10.1",
"version": "1.0.1",
"description": "Public CLI for parsing, formatting, testing, and certifying DQL blocks",
"license": "Apache-2.0",
"type": "module",
Expand Down
4 changes: 4 additions & 0 deletions apps/cli/src/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface CLIFlags {
template: string;
connection: string;
skipTests: boolean;
force?: boolean;
}

export interface ParsedArgs {
Expand Down Expand Up @@ -42,6 +43,7 @@ export function parseArgs(argv: string[]): ParsedArgs {
template: '',
connection: '',
skipTests: false,
force: false,
};

let command: string | null = null;
Expand Down Expand Up @@ -88,6 +90,8 @@ export function parseArgs(argv: string[]): ParsedArgs {
flags.queryOnly = true;
} else if (arg === '--skip-tests') {
flags.skipTests = true;
} else if (arg === '--force' || arg === '-f') {
flags.force = true;
} else if (!command) {
command = arg;
} else if (!file) {
Expand Down
Loading
Loading