diff --git a/.github/workflows/MainDistributionPipeline.yml b/.github/workflows/MainDistributionPipeline.yml index 0da6476..3af1d56 100644 --- a/.github/workflows/MainDistributionPipeline.yml +++ b/.github/workflows/MainDistributionPipeline.yml @@ -16,7 +16,7 @@ jobs: name: Build extension binaries uses: duckdb/extension-ci-tools/.github/workflows/_extension_distribution.yml@v1.5-variegata with: - duckdb_version: v1.5.2 + duckdb_version: v1.5.3 ci_tools_version: v1.5-variegata extension_name: quackscale extra_toolchains: 'go' @@ -27,7 +27,7 @@ jobs: name: Code Quality Check uses: duckdb/extension-ci-tools/.github/workflows/_extension_code_quality.yml@v1.5-variegata with: - duckdb_version: v1.5.2 + duckdb_version: v1.5.3 ci_tools_version: v1.5-variegata extension_name: quackscale format_checks: 'format;tidy' diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index b37cb86..0f9a9b6 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -1,28 +1,164 @@ -# Build a Linux DuckDB binary with quackscale embedded and attach it to the GitHub release. -# E2e workflows download this artifact instead of compiling from source. +# Publish unsigned quackscale loadable binaries to GitHub Pages (INSTALL FROM …) +# and attach a linux QuackTail tarball (duckdb + extension) to GitHub Releases. +# +# One-time setup: repo Settings → Pages → Build and deployment → Source: GitHub Actions. +# +# Layout after deploy: +# https://quackscience.github.io/duckdb-quackscale/v1.5.3/linux_amd64/quackscale.duckdb_extension.gz +# +# Users: +# SET allow_unsigned_extensions = true; +# INSTALL quackscale FROM 'https://quackscience.github.io/duckdb-quackscale'; +# LOAD quackscale; +# +# Note: deploy-pages replaces the whole site each run (one DuckDB version hosted). name: Release on: release: types: [published] + workflow_dispatch: + inputs: + release_tag: + description: 'Git tag for QuackTail linux tarball (manual runs; optional)' + required: false + type: string + skip_pages: + description: 'Skip GitHub Pages packaging and deploy' + required: false + default: false + type: boolean + skip_tarball: + description: 'Skip QuackTail linux tarball upload' + required: false + default: false + type: boolean -permissions: - contents: write +concurrency: + group: pages + cancel-in-progress: false env: + EXT_NAME: quackscale DUCKDB_VERSION: v1.5.3 RELEASE_ASSET: quacktail-linux-amd64 + PAGES_BASE_URL: https://quackscience.github.io/duckdb-quackscale jobs: - build-linux: - name: Build QuackTail linux amd64 + build: + name: Build extension binaries + uses: duckdb/extension-ci-tools/.github/workflows/_extension_distribution.yml@v1.5-variegata + with: + duckdb_version: v1.5.3 + ci_tools_version: v1.5-variegata + extension_name: quackscale + extra_toolchains: go + exclude_archs: 'windows_amd64;windows_arm64;windows_amd64_mingw;wasm_mvp;wasm_eh;wasm_threads;osx_amd64' + + package-pages: + name: Package extension repository + runs-on: ubuntu-latest + needs: build + if: github.event_name == 'release' || inputs.skip_pages != true + steps: + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + pattern: ${{ env.EXT_NAME }}-${{ env.DUCKDB_VERSION }}-extension-* + + - name: Assemble GitHub Pages tree + shell: bash + run: | + set -euo pipefail + shopt -s nullglob + prefix="${EXT_NAME}-${DUCKDB_VERSION}-extension-" + found=0 + mkdir -p _site + for dir in artifacts/${prefix}*/; do + arch="$(basename "$dir")" + arch="${arch#${prefix}}" + src="${dir}${EXT_NAME}.duckdb_extension" + if [[ ! -f "$src" ]]; then + echo "::warning::no ${EXT_NAME}.duckdb_extension in ${dir}, skipping ${arch}" + continue + fi + out="_site/${DUCKDB_VERSION}/${arch}" + mkdir -p "$out" + cp "$src" work.bin + truncate -s -256 work.bin + dd if=/dev/zero bs=256 count=1 status=none >> work.bin + gzip -n < work.bin > "${out}/${EXT_NAME}.duckdb_extension.gz" + rm -f work.bin + echo "packaged ${arch}" + found=$((found + 1)) + done + if [[ "$found" -eq 0 ]]; then + echo "::error::no extension binaries found to package" + exit 1 + fi + echo "Packaged ${found} platform(s) for ${DUCKDB_VERSION}" + + - name: Write landing page + shell: bash + env: + PAGES_BASE_URL: ${{ env.PAGES_BASE_URL }} + EXT_NAME: ${{ env.EXT_NAME }} + DUCKDB_VERSION: ${{ env.DUCKDB_VERSION }} + run: | + set -euo pipefail + { + echo '' + echo 'quackscale extension repository' + echo '

quackscale

' + echo "

Unsigned DuckDB extension repository. Requires DuckDB ${DUCKDB_VERSION}.

" + echo '
SET allow_unsigned_extensions = true;'
+            echo "INSTALL ${EXT_NAME} FROM '${PAGES_BASE_URL}';"
+            echo "LOAD ${EXT_NAME};
" + echo '

Available binaries

' + } > _site/index.html + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: _site + + deploy-pages: + name: Deploy to GitHub Pages + runs-on: ubuntu-latest + needs: package-pages + if: github.event_name == 'release' || inputs.skip_pages != true + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 + + build-quacktail-bundle: + name: Build QuackTail linux amd64 tarball runs-on: ubuntu-latest timeout-minutes: 90 + if: >- + (github.event_name == 'release') || + (github.event_name == 'workflow_dispatch' && inputs.skip_tarball != true && inputs.release_tag != '') + permissions: + contents: write + env: + RELEASE_TAG: ${{ github.event.release.tag_name || inputs.release_tag }} steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.release.tag_name }} + ref: ${{ github.event.release.tag_name || inputs.release_tag || github.ref }} submodules: recursive - uses: actions/setup-go@v5 @@ -51,15 +187,15 @@ jobs: cp build/release/extension/quackscale/quackscale.duckdb_extension \ "dist/${RELEASE_ASSET}/extension/quackscale/" { - echo "tag=${{ github.event.release.tag_name }}" + echo "tag=${RELEASE_TAG}" echo "duckdb=${{ env.DUCKDB_VERSION }}" echo "commit=${{ github.sha }}" } > "dist/${RELEASE_ASSET}/VERSION" - tar -czf "dist/${RELEASE_ASSET}-${{ github.event.release.tag_name }}.tar.gz" -C dist "${RELEASE_ASSET}" + tar -czf "dist/${RELEASE_ASSET}-${RELEASE_TAG}.tar.gz" -C dist "${RELEASE_ASSET}" ls -lh dist/ - name: Upload release assets uses: softprops/action-gh-release@v2 with: - tag_name: ${{ github.event.release.tag_name }} + tag_name: ${{ env.RELEASE_TAG }} files: dist/*.tar.gz diff --git a/README.md b/README.md index 26169ec..8cc19f2 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,34 @@ Do **not** copy the random `auth_token` from each `CALL quack_serve`. Use a flee --- +## Install + +QuackScale ships in two forms: a **loadable extension** (stock DuckDB + `INSTALL`) and a **QuackTail release bundle** (prebuilt `duckdb` binary for Linux CI and compose). + +### Loadable extension (GitHub Pages) + +Published on each [release](https://github.com/quackscience/duckdb-quackscale/releases) to a DuckDB custom extension repository. Requires **DuckDB v1.5.3** and unsigned extension support: + +```sql +SET allow_unsigned_extensions = true; +INSTALL quackscale FROM 'https://quackscience.github.io/duckdb-quackscale'; +LOAD quackscale; +``` + +CLI equivalent: `duckdb -unsigned` then `LOAD quackscale;` + +Install [Quack](https://duckdb.org/docs/current/quack/overview) from core separately (`INSTALL quack FROM core; LOAD quack;`) for `quack_serve`, `ATTACH`, and `quack_query`. + +### QuackTail release bundle (GitHub Releases) + +Linux amd64 tarball with `duckdb` and `extension/quackscale/quackscale.duckdb_extension` — used by [Headscale e2e CI](.github/workflows/headscale-e2e.yml) and `examples/` with `BUILD_FROM_SOURCE=0`. Download from [Releases](https://github.com/quackscience/duckdb-quackscale/releases) (`quacktail-linux-amd64-*.tar.gz`). + +### Build from source + +See [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) for submodules, Go/libtailscale, and `make release`. + +--- + ## Quick start ### Server diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 82d5a47..13d40bc 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -72,12 +72,28 @@ When bumping the DuckDB target: |----------|---------|---------| | [headscale-e2e.yml](../.github/workflows/headscale-e2e.yml) | **Manual only** | Release-binary two-node e2e (no source build) | | [headscale-integration.yml](../.github/workflows/headscale-integration.yml) | PR | Source build + Headscale smoke | -| [Release.yml](../.github/workflows/Release.yml) | Release published | Build linux release tarball | +| [Release.yml](../.github/workflows/Release.yml) | Release published / manual | Extension repo → GitHub Pages; linux QuackTail tarball → Releases | | [libtailscale-integration.yml](../.github/workflows/libtailscale-integration.yml) | PR | libtailscale `go test` | | [MainDistributionPipeline.yml](../.github/workflows/MainDistributionPipeline.yml) | PR | Extension distribution CI | **E2e never runs on push/PR** and never compiles DuckDB in CI — use `workflow_dispatch` on `headscale-e2e` with a release tag. Full DuckLake compose demo is local dev only (`scripts/ci_compose_e2e.sh`). +### Release and GitHub Pages + +On **Release published** (or manual **Release** workflow): + +1. **build** — extension-ci-tools matrix (`quackscale` per platform, same exclusions as MainDistributionPipeline). +2. **package-pages** + **deploy-pages** — unsigned `.duckdb_extension.gz` under `v1.5.3/{arch}/` at `https://quackscience.github.io/duckdb-quackscale`. +3. **build-quacktail-bundle** — linux amd64 `quacktail-linux-amd64-{tag}.tar.gz` attached to the GitHub Release. + +**One-time repo setup:** Settings → Pages → Build and deployment → **Source: GitHub Actions**. + +**Manual Pages-only test:** Actions → Release → Run workflow → leave `release_tag` empty, uncheck skip_pages. + +**Manual tarball test:** provide an existing git tag in `release_tag`, uncheck skip_tarball. + +Each Pages deploy replaces the whole site (one DuckDB version hosted). To host multiple DuckDB versions, accumulate version directories in a follow-up change. + ## Roadmap (selected) | Item | Status | @@ -88,7 +104,7 @@ When bumping the DuckDB target: | `ATTACH … TYPE quacktail_lake` (Tier 3 native catalog) | Planned | | `ducklake_discover()` enriched discovery | Planned | | `quackscale_serve()` one-call server bootstrap | Planned | -| Community extension descriptor publish | Planned | +| Community extension descriptor publish | Done (GitHub Pages on release) | ## Risks