feat: add a CLI release binary (#4751)

Package the standalone lancedb CLI with every stable and beta GitHub
release. Publish archives for Linux x86_64, Linux ARM64, and Apple
Silicon macOS, along with SHA-256 checksums, licenses, and third-party
notices.

Synchronize the CLI version with the SDKs and validate that release tags
match both manifests. Add PR and manual packaging dry runs, runtime
compatibility checks, and smoke tests of extracted executables. GitHub
release creation now waits for all three archives to pass validation;
SDK registry publishing remains independent.

Update installation instructions and the release checklist. Linux
binaries target glibc 2.28, retaining existing x86_64 CPU requirements;
macOS binaries target macOS 14 or newer.
This commit is contained in:
Colin Patrick McCabe
2026-10-30 12:54:54 -07:00
committed by GitHub
parent 9b543c3848
commit 2044179a8b
15 changed files with 895 additions and 14 deletions
+8
View File
@@ -9,6 +9,10 @@ on:
- python/pyproject.toml
- ci/check_cargo_lock.py
- ci/check_sdist.py
- ci/build_cli_linux.sh
- ci/package_cli.py
- .bumpversion.toml
- rust/lancedb/cli/Cargo.toml
- ci/set_lance_version.py
- ci/tests/**
- .github/workflows/ci-scripts.yml
@@ -18,6 +22,10 @@ on:
- python/pyproject.toml
- ci/check_cargo_lock.py
- ci/check_sdist.py
- ci/build_cli_linux.sh
- ci/package_cli.py
- .bumpversion.toml
- rust/lancedb/cli/Cargo.toml
- ci/set_lance_version.py
- ci/tests/**
- .github/workflows/ci-scripts.yml
+167
View File
@@ -0,0 +1,167 @@
name: CLI release packages
on:
workflow_call:
workflow_dispatch:
pull_request:
paths:
- 'rust/lancedb/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'rust-toolchain.toml'
- '.cargo/config.toml'
- '.bumpversion.toml'
- 'LICENSE'
- 'RUST_THIRD_PARTY_LICENSES.html'
- 'ci/build_cli_linux.sh'
- 'ci/package_cli.py'
- 'ci/tests/test_package_cli.py'
- '.github/actions/setup-protoc/**'
- '.github/workflows/cli-release.yml'
- '.github/workflows/gh-release.yml'
permissions:
contents: read
concurrency:
group: cli-packages-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
version:
runs-on: ubuntu-24.04
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Validate release version before building
id: version
run: |
version=$(python ci/package_cli.py version)
echo "version=$version" >> "$GITHUB_OUTPUT"
build:
needs: version
timeout-minutes: 180
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
runner: ubuntu-2404-8x-x64
image: quay.io/pypa/manylinux_2_28_x86_64
protoc: linux-x86_64
- target: aarch64-unknown-linux-gnu
runner: ubuntu-2404-8x-arm64
image: quay.io/pypa/manylinux_2_28_aarch64
protoc: linux-aarch_64
- target: aarch64-apple-darwin
runner: warp-macos-14-arm64-6x
runs-on: ${{ matrix.runner }}
env:
CLI_TARGET: ${{ matrix.target }}
CLI_VERSION: ${{ needs.version.outputs.version }}
MACOSX_DEPLOYMENT_TARGET: '14.0'
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1
with:
# Leave .cargo/config.toml's CPU/feature flags in effect.
rustflags: ''
cache: false
- uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2
with:
key: cli-release-${{ matrix.target }}
save-if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/main' }}
- uses: ./.github/actions/setup-protoc
id: protoc
with:
install: ${{ runner.os == 'macOS' }}
- name: Add swap for Arm fat LTO
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
swap_file="$RUNNER_TEMP/lancedb-cli-swap"
sudo fallocate --length 16G "$swap_file"
sudo chmod 600 "$swap_file"
sudo mkswap "$swap_file"
sudo swapon "$swap_file"
- name: Build Linux CLI against glibc 2.28
if: runner.os == 'Linux'
env:
MANYLINUX_IMAGE: ${{ matrix.image }}
PROTOC_PLATFORM: ${{ matrix.protoc }}
PROTOC_VERSION: ${{ steps.protoc.outputs.version }}
PROTOC_SHA256: ${{ matrix.protoc == 'linux-x86_64' && steps.protoc.outputs.linux-x86_64-sha256 || steps.protoc.outputs.linux-aarch_64-sha256 }}
run: |
docker run --rm \
--volume "$PWD:/workspace" --workdir /workspace \
--volume "$HOME/.cargo:/cargo" --env CARGO_HOME=/cargo \
--volume "$HOME/.rustup:/rustup" --env RUSTUP_HOME=/rustup \
--env CLI_TARGET --env PROTOC_PLATFORM --env PROTOC_VERSION --env PROTOC_SHA256 \
"$MANYLINUX_IMAGE" bash ci/build_cli_linux.sh
- name: Build macOS CLI
if: runner.os == 'macOS'
run: |
cargo build --locked --release -p lancedb-cli --bin lancedb --target "$CLI_TARGET"
strip -S "target/$CLI_TARGET/release/lancedb"
# Stripping can invalidate the linker's ad-hoc signature on Apple Silicon.
codesign --force --sign - "target/$CLI_TARGET/release/lancedb"
- name: Package, inspect runtime dependencies, and smoke-test archive
run: |
python ci/package_cli.py package \
--binary "target/$CLI_TARGET/release/lancedb" --target "$CLI_TARGET" --output dist
- name: Smoke-test Linux archive on a clean glibc 2.28 system
if: runner.os == 'Linux'
run: |
docker run --rm --volume "$PWD/dist:/artifacts:ro" \
--env CLI_TARGET --env CLI_VERSION almalinux:8 bash -euo pipefail -c '
dnf install -y libstdc++
mkdir -p /tmp/check /tmp/cli-home
export HOME=/tmp/cli-home XDG_CONFIG_HOME=/tmp/cli-home/.config
stem="lancedb-v${CLI_VERSION}-${CLI_TARGET}"
tar -xzf "/artifacts/${stem}.tar.gz" -C /tmp/check
cli="/tmp/check/${stem}/lancedb"
"$cli" --help
test "$("$cli" --version)" = "lancedb ${CLI_VERSION}"
"$cli" profile list
'
- uses: actions/upload-artifact@v7
with:
name: cli-archive-${{ matrix.target }}
path: dist/*.tar.gz
if-no-files-found: error
assemble:
needs: [version, build]
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- uses: actions/download-artifact@v8
with:
pattern: cli-archive-*
merge-multiple: true
path: dist
- name: Require all three archives and generate checksums
run: |
python ci/package_cli.py checksums --output dist
python ci/package_cli.py verify --output dist
- uses: actions/upload-artifact@v7
with:
name: cli-release
path: dist/*
if-no-files-found: error
+34 -2
View File
@@ -1,8 +1,8 @@
name: GitHub Release
# All SDKs share one version, so a single `vX.Y.Z` tag produces a single GitHub
# release covering all of them. The per-package publish workflows (PyPI, NPM,
# Cargo, Maven) trigger off the same tag independently.
# release covering all of them, including CLI binaries. The per-package publish
# workflows (PyPI, NPM, Cargo, Maven) trigger off the same tag independently.
on:
push:
@@ -13,7 +13,11 @@ permissions:
contents: read
jobs:
cli:
uses: ./.github/workflows/cli-release.yml
gh-release:
needs: cli
runs-on: ubuntu-latest
permissions:
contents: write
@@ -22,6 +26,15 @@ jobs:
with:
fetch-depth: 0
lfs: true
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- uses: actions/download-artifact@v8
with:
name: cli-release
path: dist
- name: Verify CLI release assets
run: python ci/package_cli.py verify --output dist
- name: Extract version
id: extract_version
env:
@@ -83,3 +96,22 @@ jobs:
generate_release_notes: false
name: LanceDB v${{ steps.extract_version.outputs.version }}
body: ${{ steps.release_notes.outputs.changelog }}
files: |
dist/lancedb-*.tar.gz
dist/SHA256SUMS
fail_on_unmatched_files: true
overwrite_files: true
report-failure:
runs-on: ubuntu-24.04
needs: [cli, gh-release]
if: always() && failure()
permissions:
contents: read
issues: write
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/create-failure-issue
with:
job-results: ${{ toJSON(needs) }}
workflow-name: ${{ github.workflow }}
+5 -4
View File
@@ -14,6 +14,7 @@ on:
- docs/web-tests/blob-v2/rs/**
- nodejs/Cargo.toml
- python/Cargo.toml
- .github/actions/setup-protoc/**
- .github/workflows/rust.yml
permissions:
@@ -324,8 +325,8 @@ jobs:
# unreadable outside their own branch anyway, since GitHub scopes
# caches to the creating ref.
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Install Protoc v21.12
run: choco install --no-progress protoc
- name: Install protoc
uses: ./.github/actions/setup-protoc
- name: Build
run: |
$env:VCPKG_ROOT = $env:VCPKG_INSTALLATION_ROOT
@@ -361,8 +362,8 @@ jobs:
# unreadable outside their own branch anyway, since GitHub scopes
# caches to the creating ref.
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Install Protoc v21.12
run: choco install --no-progress protoc
- name: Install protoc
uses: ./.github/actions/setup-protoc
- name: Build
run: |
$env:VCPKG_ROOT = $env:VCPKG_INSTALLATION_ROOT