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
232 changes: 232 additions & 0 deletions .github/workflows/publish-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ env:
jobs:
publish-packages:
name: Publish crates and core npm package
# Forks may use this workflow to test CLI release assets, but must never
# publish packages to the public registries.
if: ${{ github.repository == 'pondpilot/flowscope' }}
runs-on: ubuntu-latest
environment: prod
env:
Expand Down Expand Up @@ -147,3 +150,232 @@ jobs:
fi
env:
NODE_AUTH_TOKEN: ''

build-cli-linux-binaries:
name: Build CLI (${{ matrix.platform.name }})
runs-on: ${{ matrix.platform.runs-on }}
# Build against an older glibc so the published binaries run on common
# long-term-support distributions. The image supports both amd64 and arm64.
container:
image: rust:1.95-bullseye@sha256:28afaeb8445f2a2e7d878bd34ed39ba02bb517efb29986188cbd59b7cf4f2fdf
permissions:
contents: read
strategy:
fail-fast: false
matrix:
platform:
- name: Linux x86_64
runs-on: ubuntu-24.04
target: x86_64-unknown-linux-gnu
- name: Linux aarch64
runs-on: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu

steps:
- uses: actions/checkout@v4

- name: Resolve CLI version
id: cli_version
shell: bash
run: |
python3 - <<'PY' >> "$GITHUB_OUTPUT"
import pathlib
import re

data = pathlib.Path('Cargo.toml').read_text()
match = re.search(r'^version\s*=\s*"([^"]+)"', data, re.MULTILINE)
if not match:
raise SystemExit('Could not find workspace version in Cargo.toml')
print(f"version={match.group(1)}")
PY

- name: Verify release tag
if: ${{ github.ref_type == 'tag' }}
shell: bash
env:
CLI_VERSION: ${{ steps.cli_version.outputs.version }}
run: |
set -euo pipefail
expected_tag="v${CLI_VERSION}"
if [[ "$GITHUB_REF_NAME" != "$expected_tag" ]]; then
echo "Release tag '$GITHUB_REF_NAME' does not match CLI version '$CLI_VERSION'."
exit 1
fi

- name: Build CLI binary
run: |
cargo build -p flowscope-cli --release --locked
strip target/release/flowscope

- name: Smoke test CLI on glibc 2.31
run: target/release/flowscope --version

- name: Package CLI archive
uses: houseabsolute/actions-rust-release@9e126fd5fc18f4cecf358b3909f3991ad59663dc # v1 branch, 2026-09-24
with:
executable-name: flowscope
archive-name: flowscope-v${{ steps.cli_version.outputs.version }}-${{ matrix.platform.target }}
changes-file: ''
extra-files: |
README.md
LICENSE

build-cli-other-binaries:
name: Build CLI (${{ matrix.platform.name }})
runs-on: ${{ matrix.platform.runs-on }}
permissions:
contents: read
strategy:
fail-fast: false
matrix:
platform:
- name: macOS x86_64
runs-on: macos-15-intel
target: x86_64-apple-darwin
- name: macOS aarch64
runs-on: macos-15
target: aarch64-apple-darwin
- name: Windows x86_64
runs-on: windows-2022
target: x86_64-pc-windows-msvc

steps:
- uses: actions/checkout@v4

- name: Resolve CLI version
id: cli_version
shell: bash
run: |
python - <<'PY' >> "$GITHUB_OUTPUT"
import pathlib
import re

data = pathlib.Path('Cargo.toml').read_text()
match = re.search(r'^version\s*=\s*"([^"]+)"', data, re.MULTILINE)
if not match:
raise SystemExit('Could not find workspace version in Cargo.toml')
print(f"version={match.group(1)}")
PY

- name: Verify release tag
if: ${{ github.ref_type == 'tag' }}
shell: bash
env:
CLI_VERSION: ${{ steps.cli_version.outputs.version }}
run: |
set -euo pipefail
expected_tag="v${CLI_VERSION}"
if [[ "$GITHUB_REF_NAME" != "$expected_tag" ]]; then
echo "Release tag '$GITHUB_REF_NAME' does not match CLI version '$CLI_VERSION'."
exit 1
fi

- name: Build CLI binary
uses: houseabsolute/actions-rust-cross@85826e468eac832e251ac58f6191ba784db237c8 # v1 branch, 2026-09-24
with:
command: build
target: ${{ matrix.platform.target }}
args: '--package flowscope-cli --locked --release'
strip: true

- name: Smoke test CLI
shell: bash
env:
TARGET: ${{ matrix.platform.target }}
run: |
set -euo pipefail
executable="target/${TARGET}/release/flowscope"
if [[ "$RUNNER_OS" == 'Windows' ]]; then
executable="${executable}.exe"
fi
"$executable" --version

- name: Package CLI archive
uses: houseabsolute/actions-rust-release@9e126fd5fc18f4cecf358b3909f3991ad59663dc # v1 branch, 2026-09-24
with:
executable-name: flowscope
target: ${{ matrix.platform.target }}
archive-name: flowscope-v${{ steps.cli_version.outputs.version }}-${{ matrix.platform.target }}
changes-file: ''
extra-files: |
README.md
LICENSE

publish-cli-binaries:
name: Publish CLI binaries
needs:
- publish-packages
- build-cli-linux-binaries
- build-cli-other-binaries
if: >-
${{
always() &&
github.ref_type == 'tag' &&
(github.event_name == 'push' || inputs.dry_run != 'true') &&
needs['build-cli-linux-binaries'].result == 'success' &&
needs['build-cli-other-binaries'].result == 'success' &&
(
github.repository != 'pondpilot/flowscope' ||
needs['publish-packages'].result == 'success'
)
}}
runs-on: ubuntu-24.04
permissions:
actions: read
attestations: write
contents: write
id-token: write
steps:
- uses: actions/checkout@v4

- name: Download packaged CLI assets
uses: actions/download-artifact@v4
with:
pattern: flowscope-v*
path: release-assets
merge-multiple: true

- name: Generate aggregate SHA-256 checksums
shell: bash
env:
RELEASE_TAG: ${{ github.ref_name }}
run: |
set -euo pipefail
mapfile -t archives < <(
find release-assets -maxdepth 1 -type f \
\( -name 'flowscope-*.tar.gz' -o -name 'flowscope-*.zip' \) \
-printf '%f\n' | sort
)
if [[ "${#archives[@]}" -ne 5 ]]; then
echo "Expected five CLI archives, found ${#archives[@]}."
printf '%s\n' "${archives[@]}"
exit 1
fi
(
cd release-assets
sha256sum "${archives[@]}" > "flowscope-${RELEASE_TAG}-SHA256SUMS"
)

- name: Upload aggregate checksum artifact
uses: actions/upload-artifact@v4
with:
name: flowscope-${{ github.ref_name }}-SHA256SUMS
path: release-assets/flowscope-${{ github.ref_name }}-SHA256SUMS
if-no-files-found: error

- name: Attest CLI release assets
uses: actions/attest-build-provenance@v4
with:
subject-path: |
release-assets/*.tar.gz
release-assets/*.zip
release-assets/*.sha256
release-assets/*SHA256SUMS

- name: Publish CLI release
uses: houseabsolute/actions-rust-release/publish@9e126fd5fc18f4cecf358b3909f3991ad59663dc # v1 branch, 2026-09-24
with:
executable-name: flowscope
artifact-regex: '\Aflowscope-v.*(\.tar\.gz|\.zip|-SHA256SUMS)\Z'
changes-file: ''
generate-release-notes: true
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Added prebuilt CLI release archives for five Linux, macOS, and Windows targets, with SHA-256 checksums and build provenance ([#65](https://github.com/pondpilot/flowscope/issues/65)).

## [0.9.1] - 2026-09-24

### Fixed
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ When Librarian is used, its request includes the active SQL snippet, formatted l

For scripting and CI/CD integration, install the CLI:

Future [GitHub Releases](https://github.com/pondpilot/flowscope/releases) will include prebuilt
CLI archives for Linux (x86_64 and aarch64), macOS (Intel and Apple Silicon),
and Windows (x86_64).
Each archive has a SHA-256 checksum file. See the [CLI installation guide](crates/flowscope-cli/README.md#prebuilt-binaries)
for download and verification steps.

To build from source instead:

```bash
# Core CLI (analysis, linting, fixing, exports)
cargo install flowscope-cli
Expand Down
36 changes: 36 additions & 0 deletions crates/flowscope-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,43 @@ Command-line interface for the FlowScope SQL lineage analyzer.

## Installation

### Prebuilt binaries

For releases that include prebuilt binaries, download an archive from
[GitHub Releases](https://github.com/pondpilot/flowscope/releases) for one of these targets:

| System | Target | Archive |
| --- | --- | --- |
| Linux x86_64 | `x86_64-unknown-linux-gnu` | `.tar.gz` |
| Linux aarch64 | `aarch64-unknown-linux-gnu` | `.tar.gz` |
| macOS Intel | `x86_64-apple-darwin` | `.tar.gz` |
| macOS Apple Silicon | `aarch64-apple-darwin` | `.tar.gz` |
| Windows x86_64 | `x86_64-pc-windows-msvc` | `.zip` |

Archive names follow `flowscope-v<version>-<target>.<extension>`. Download the matching
`<archive>.sha256` file, then verify it before extracting the `flowscope` executable
(`flowscope.exe` on Windows). On Linux, for example:

```bash
TAG=vX.Y.Z # Replace with a release tag that includes binaries.
ARCHIVE="flowscope-${TAG}-x86_64-unknown-linux-gnu.tar.gz"
sha256sum --check "${ARCHIVE}.sha256"
tar -xzf "$ARCHIVE"
./flowscope --version
```

The release also includes a `flowscope-v<version>-SHA256SUMS` manifest for all five archives.
Build provenance is available through [GitHub artifact attestations](https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/use-artifact-attestations)
and can be verified with `gh attestation verify <archive> --repo pondpilot/flowscope`.
Prebuilt binaries include the default CLI features. Build with the `serve` feature to run
the bundled local web server. Linux binaries require glibc 2.31 or later.

### Build from source

```bash
cargo install flowscope-cli

# From a local checkout
cargo install --path crates/flowscope-cli
```

Expand Down
Loading