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
28 changes: 28 additions & 0 deletions .github/actions/setup-rust/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Setup Rust
description: Install pinned Rust and optional native dependencies, then restore the Rust cache.
inputs:
native:
description: Install native build dependencies.
default: "true"
cache-key:
description: Cache partition for this workload; empty disables caching.
default: ""
runs:
using: composite
steps:
- uses: extractions/setup-just@f8a3cce218d9f83db3a2ecd90e41ac3de6cdfd9b # v3
with:
just-version: 1.58.0
- name: Install pinned Rust
shell: bash
run: rustup toolchain install --no-self-update --profile minimal --component rustfmt --component clippy
- name: Install native dependencies
if: inputs.native == 'true'
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y clang libclang-dev pkg-config
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
if: inputs.cache-key != ''
with:
shared-key: ${{ inputs.cache-key }}
18 changes: 18 additions & 0 deletions .github/actions/setup-sdk/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Setup SDK tools
description: Install pinned Node, TypeScript and the prebuilt openapi-nexus binary.
runs:
using: composite
steps:
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 24.15.0
- name: Install TypeScript
shell: bash
run: |
npm install --prefix "$RUNNER_TEMP/sqlrest-typescript" --ignore-scripts typescript@6.0.3
echo "$RUNNER_TEMP/sqlrest-typescript/node_modules/.bin" >> "$GITHUB_PATH"
- name: Download openapi-nexus binary
shell: bash
run: |
just download-openapi-nexus "$RUNNER_TEMP/openapi-nexus"
echo "OPENAPI_NEXUS_BIN=$RUNNER_TEMP/openapi-nexus/openapi-nexus" >> "$GITHUB_ENV"
66 changes: 22 additions & 44 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,57 +1,35 @@
name: contracts

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
quality:
uses: ./.github/workflows/quality.yml
tests:
uses: ./.github/workflows/tests.yml
sdk:
uses: ./.github/workflows/sdk.yml
package:
uses: ./.github/workflows/package.yml

# A stable required check: failed, cancelled or skipped lanes cannot pass.
delivery:
# The artifact must be compatible with the Docker runtime's glibc 2.36.
if: ${{ always() }}
needs: [quality, tests, sdk, package]
runs-on: ubuntu-22.04
timeout-minutes: 45
services:
postgres:
image: postgres:18-alpine@sha256:54451ecb8ab38c24c3ec123f2fd501303a3a1856a5c66e98cecf2460d5e1e9d7
env:
POSTGRES_PASSWORD: sqlrest
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 5s
--health-timeout 5s
--health-retries 20
timeout-minutes: 5
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 24.15.0
- name: Install pinned tools
run: |
rustup toolchain install 1.98.0 --profile minimal --component rustfmt --component clippy
sudo apt-get update
sudo apt-get install -y clang libclang-dev pkg-config postgresql-client curl xz-utils
npm install --prefix "$RUNNER_TEMP/sqlrest-typescript" --ignore-scripts typescript@6.0.3
echo "$RUNNER_TEMP/sqlrest-typescript/node_modules/.bin" >> "$GITHUB_PATH"
- name: Download pinned openapi-nexus binary
run: |
bash scripts/download-openapi-nexus.sh "$RUNNER_TEMP/openapi-nexus"
echo "OPENAPI_NEXUS_BIN=$RUNNER_TEMP/openapi-nexus/openapi-nexus" >> "$GITHUB_ENV"
- name: Create empty example database
env:
PGPASSWORD: sqlrest
run: createdb -h 127.0.0.1 -U postgres sqlrest_examples
- name: Format, lint, unit, both backends, binary, restart and SDK contracts
- name: Require every lane to succeed
env:
SQLREST_TEST_POSTGRES: postgresql://postgres:sqlrest@127.0.0.1:5432/postgres
SQLREST_EXAMPLES_POSTGRES: postgresql://postgres:sqlrest@127.0.0.1:5432/sqlrest_examples
run: bash scripts/check.sh
- name: Package verified release artifact and run container lifecycle
run: |
cargo build --release --locked
docker build --tag sqlrest:ci .
python3 scripts/e2e.py --image sqlrest:ci
RESULTS: ${{ toJSON(needs) }}
run: jq -e 'all(.[]; .result == "success")' <<< "$RESULTS"
47 changes: 47 additions & 0 deletions .github/workflows/package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Package
on:
workflow_call:

permissions:
contents: read

jobs:
release:
name: Release binary
# Keep the build compatible with the container's glibc 2.36.
runs-on: ubuntu-22.04
timeout-minutes: 40
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- uses: ./.github/actions/setup-rust
with:
cache-key: release
- run: just release
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: sqlrest-linux-x86_64
path: target/release/sqlrest
if-no-files-found: error
retention-days: 7

container:
name: Container lifecycle
needs: [release]
runs-on: ubuntu-22.04
timeout-minutes: 15
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: sqlrest-linux-x86_64
path: target/release
- name: Restore executable permission
run: chmod +x target/release/sqlrest
- uses: extractions/setup-just@f8a3cce218d9f83db3a2ecd90e41ac3de6cdfd9b # v3
with:
just-version: 1.58.0
- run: just container
33 changes: 33 additions & 0 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Quality
on:
workflow_call:

permissions:
contents: read

jobs:
fmt:
name: Format
runs-on: ubuntu-22.04
timeout-minutes: 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- uses: ./.github/actions/setup-rust
with:
native: "false"
- run: just fmt

clippy:
name: Clippy
runs-on: ubuntu-22.04
timeout-minutes: 30
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- uses: ./.github/actions/setup-rust
with:
cache-key: clippy
- run: just clippy
42 changes: 42 additions & 0 deletions .github/workflows/sdk.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: SDK contracts
on:
workflow_call:

permissions:
contents: read

jobs:
sdk:
name: ${{ matrix.contract }}
runs-on: ubuntu-22.04
timeout-minutes: 35
strategy:
fail-fast: false
matrix:
contract: [turso, postgres, schema]
services:
postgres:
image: ${{ matrix.contract == 'postgres' && 'postgres:18-alpine@sha256:54451ecb8ab38c24c3ec123f2fd501303a3a1856a5c66e98cecf2460d5e1e9d7' || '' }}
env:
POSTGRES_PASSWORD: sqlrest
POSTGRES_DB: sqlrest_examples
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 5s
--health-timeout 5s
--health-retries 20
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- uses: ./.github/actions/setup-rust
with:
cache-key: tests
- uses: ./.github/actions/setup-sdk
- name: Run SDK contract
env:
SQLREST_EXAMPLES_POSTGRES: postgresql://postgres:sqlrest@127.0.0.1:5432/sqlrest_examples
CHECK_GROUP: sdk-${{ matrix.contract }}
run: just "$CHECK_GROUP"
40 changes: 40 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Database contracts
on:
workflow_call:

permissions:
contents: read

jobs:
contracts:
name: ${{ matrix.backend }}
runs-on: ubuntu-22.04
timeout-minutes: 35
strategy:
fail-fast: false
matrix:
backend: [turso, postgres]
services:
postgres:
image: ${{ matrix.backend == 'postgres' && 'postgres:18-alpine@sha256:54451ecb8ab38c24c3ec123f2fd501303a3a1856a5c66e98cecf2460d5e1e9d7' || '' }}
env:
POSTGRES_PASSWORD: sqlrest
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 5s
--health-timeout 5s
--health-retries 20
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- uses: ./.github/actions/setup-rust
with:
cache-key: tests
- name: Run database contracts
env:
SQLREST_TEST_POSTGRES: postgresql://postgres:sqlrest@127.0.0.1:5432/postgres
CHECK_GROUP: ${{ matrix.backend }}
run: just "$CHECK_GROUP"
62 changes: 62 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
set shell := ["bash", "-euo", "pipefail", "-c"]

# Run the complete local contract gates (release/container are separate).
default: all

all: _all-inputs fmt clippy turso postgres sdk-postgres sdk-turso sdk-schema

[private]
_all-inputs:
: "${SQLREST_TEST_POSTGRES:?Set a disposable PostgreSQL URL for core contracts}"
: "${SQLREST_EXAMPLES_POSTGRES:?Set a DIFFERENT empty PostgreSQL database URL for examples}"
: "${OPENAPI_NEXUS_BIN:?Set the pinned openapi-nexus binary path}"
test "$SQLREST_TEST_POSTGRES" != "$SQLREST_EXAMPLES_POSTGRES" || { echo "Core and example database URLs must be different" >&2; exit 2; }

# Check Rust formatting and whitespace.
fmt:
just --fmt --check
cargo fmt --check
git diff --check

clippy:
cargo clippy --locked --all-targets -- -D warnings

# Includes backend-neutral contracts, doctests and real Turso.
turso:
cargo test --locked

# Never run blanket --ignored: restart_worker is a subprocess fixture and
# the old upstream high-level Turso CPU timeout probe is intentionally skipped.
postgres:
: "${SQLREST_TEST_POSTGRES:?Set a disposable PostgreSQL URL for core contracts}"
cargo test --locked --lib postgres_tests:: -- --ignored
cargo test --locked --test migration_contract postgres_ -- --ignored
cargo test --locked --test postgres_contract --test execution_contract --test commit_contract --test registry_postgres -- --ignored
cargo test --locked --test http_contract postgres_http_lifecycle -- --ignored

sdk-turso:
: "${OPENAPI_NEXUS_BIN:?Set the pinned openapi-nexus binary path}"
cargo test --locked --test examples_contract generated_sdks_call_real_examples -- --ignored

sdk-postgres:
: "${SQLREST_EXAMPLES_POSTGRES:?Set an empty disposable PostgreSQL database URL for examples}"
: "${OPENAPI_NEXUS_BIN:?Set the pinned openapi-nexus binary path}"
SQLREST_TEST_POSTGRES="$SQLREST_EXAMPLES_POSTGRES" cargo test --locked --test examples_contract postgres_examples_and_process_restart -- --ignored

sdk-schema:
: "${OPENAPI_NEXUS_BIN:?Set the pinned openapi-nexus binary path}"
cargo test --locked --test sdk_contract -- --ignored

release:
cargo build --release --locked

# Package an existing release binary and exercise its container lifecycle.
container:
docker build --tag sqlrest:ci .
python3 scripts/e2e.py --image sqlrest:ci

# Download the pinned Linux x86_64 musl binary; never build the generator.
download-openapi-nexus destination:
mkdir -p -- {{ quote(destination) }}
curl -fsSL https://github.com/rust-codegen-group/openapi-nexus/releases/download/0.2.3/openapi-nexus-x86_64-unknown-linux-musl.tar.xz | tar -xJ --strip-components=1 -C {{ quote(destination) }}
{{ quote(destination + "/openapi-nexus") }} --version
Loading
Loading