name: CI
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
pull-requests: write
security-events: write
env:
CARGO_TERM_COLOR: always
RUSTC_WRAPPER: ""
CARGO_INCREMENTAL: "0"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
detect-changes:
name: Detect Changes
runs-on: ubuntu-latest
timeout-minutes: 2
outputs:
docs-only: ${{ steps.classify.outputs.docs-only }}
specs-only: ${{ steps.classify.outputs.specs-only }}
run-full-ci: ${{ steps.classify.outputs.run-full-ci }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - name: Filter changed paths
uses: dorny/paths-filter@7b450fff21473bca461d4b92ce414b9d0420d706 id: filter
with:
filters: |
docs:
- 'book/src/**'
- 'docs/**'
- '**.md'
- '.local/testing/**'
specs:
- 'specs/**'
code:
- 'crates/**'
- 'src/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'build.rs'
- 'docker/**'
workflows:
- '.github/workflows/**'
- '.github/nextest.toml'
- '.github/testcontainers-images.txt'
- '.cargo/**'
shell:
- 'install/**'
- name: Classify changes
id: classify
run: |
DOCS="${{ steps.filter.outputs.docs }}"
SPECS="${{ steps.filter.outputs.specs }}"
CODE="${{ steps.filter.outputs.code }}"
WORKFLOWS="${{ steps.filter.outputs.workflows }}"
SHELL_SCRIPTS="${{ steps.filter.outputs.shell }}"
# docs-only: docs or specs changed, nothing that requires building
if [[ "$CODE" == "false" && "$WORKFLOWS" == "false" && "$SHELL_SCRIPTS" == "false" && ("$DOCS" == "true" || "$SPECS" == "true") ]]; then
echo "docs-only=true" >> "$GITHUB_OUTPUT"
else
echo "docs-only=false" >> "$GITHUB_OUTPUT"
fi
# specs-only: specs changed, no code or workflow changes
if [[ "$SPECS" == "true" && "$CODE" == "false" && "$WORKFLOWS" == "false" && "$SHELL_SCRIPTS" == "false" && "$DOCS" == "false" ]]; then
echo "specs-only=true" >> "$GITHUB_OUTPUT"
else
echo "specs-only=false" >> "$GITHUB_OUTPUT"
fi
# run-full-ci: any code, workflow, or shell change triggers full CI
if [[ "$CODE" == "true" || "$WORKFLOWS" == "true" || "$SHELL_SCRIPTS" == "true" ]]; then
echo "run-full-ci=true" >> "$GITHUB_OUTPUT"
else
echo "run-full-ci=false" >> "$GITHUB_OUTPUT"
fi
cla:
name: CLA Check
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: write
pull-requests: write
steps:
- uses: contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08 with:
path-to-signatures: cla-signatures.json
path-to-document: https://github.com/bug-ops/zeph/blob/main/.github/CLA.md
branch: cla-signatures
allowlist: bug-ops,dependabot[bot],github-actions[bot],renovate[bot]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
lint-shellcheck:
name: Lint (shellcheck)
needs: detect-changes
if: needs.detect-changes.outputs.run-full-ci == 'true'
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - name: Run shellcheck
uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 with:
scandir: install
- name: Transcript-integrity audit gate (issue run: bash .github/scripts/check_integrity_audit.sh
- name: ACP permission-gate test-isolation guard (issue run: bash .github/scripts/check_acp_permission_gate.sh
lint-fmt:
name: Lint (fmt)
needs: detect-changes
if: needs.detect-changes.outputs.run-full-ci == 'true'
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - uses: dtolnay/rust-toolchain@4fd1da8b0805d2d2e936788875a7d65dbd677dc2 with:
toolchain: nightly
components: rustfmt
- name: Check formatting
run: cargo +nightly fmt --check
lint-clippy:
name: Lint (clippy, ${{ matrix.label }})
needs: detect-changes
if: needs.detect-changes.outputs.run-full-ci == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
include:
- features: "desktop,ide,server,chat,pdf,scheduler,registry,testing,deep-link"
label: desktop-ide-server-chat-pdf-scheduler
- features: bench
label: bench
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with:
toolchain: stable
components: clippy
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 with:
shared-key: "ci"
- name: Clippy
run: cargo clippy --profile ci --workspace --all-targets --features ${{ matrix.features }} -- -D warnings
msrv:
name: MSRV check (1.97, ${{ matrix.label }})
needs: detect-changes
if: needs.detect-changes.outputs.run-full-ci == 'true'
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
include:
- features: "desktop,ide,server,chat,pdf,scheduler,registry,deep-link"
label: desktop-ide-server-chat-pdf-scheduler
- features: bench
label: bench
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with:
toolchain: "1.97"
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 with:
shared-key: "msrv-${{ matrix.label }}"
- name: cargo check (MSRV, --all-targets)
run: cargo check --workspace --all-targets --features ${{ matrix.features }} --locked
build-tests:
name: Build Tests
needs: detect-changes
if: needs.detect-changes.outputs.run-full-ci == 'true'
runs-on: ubuntu-latest
timeout-minutes: 25
env:
RUSTC_WRAPPER: sccache
SCCACHE_GHA_ENABLED: "true"
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with:
toolchain: stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 with:
cache-targets: "false"
shared-key: "ci"
- uses: mozilla-actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 - uses: taiki-e/install-action@37ba67210166984a515120020147f0b4ae3b8667 - name: Build and archive tests
run: cargo nextest archive --config-file .github/nextest.toml --cargo-profile ci --workspace --features "desktop,ide,server,chat,pdf,scheduler,registry,deep-link" --lib --bins --tests --archive-file nextest-archive.tar.zst
- name: Upload test archive
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with:
name: nextest-archive-ubuntu-latest
path: nextest-archive.tar.zst
retention-days: 1
- name: Upload binary
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with:
name: zeph-binary
path: target/ci/zeph
retention-days: 1
build-tests-postgres:
name: Build Tests (postgres archives)
needs: detect-changes
if: needs.detect-changes.outputs.run-full-ci == 'true'
runs-on: ubuntu-latest
timeout-minutes: 20
env:
RUSTC_WRAPPER: sccache
SCCACHE_GHA_ENABLED: "true"
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with:
toolchain: stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 with:
cache-targets: "false"
shared-key: "ci"
- uses: mozilla-actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 - uses: taiki-e/install-action@37ba67210166984a515120020147f0b4ae3b8667 - name: Build and archive zeph-db postgres integration tests
run: cargo nextest archive --config-file .github/nextest.toml --cargo-profile ci -p zeph-db --no-default-features --features test-utils --tests --archive-file nextest-archive-zeph-db-postgres.tar.zst
- name: Upload zeph-db postgres test archive
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with:
name: nextest-archive-zeph-db-postgres
path: nextest-archive-zeph-db-postgres.tar.zst
retention-days: 1
- name: Build and archive zeph-memory postgres integration tests
run: cargo nextest archive --config-file .github/nextest.toml --cargo-profile ci -p zeph-memory --no-default-features --features test-utils,jsonschema --lib --bins --tests --archive-file nextest-archive-zeph-memory-postgres.tar.zst
- name: Upload zeph-memory postgres test archive
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with:
name: nextest-archive-zeph-memory-postgres
path: nextest-archive-zeph-memory-postgres.tar.zst
retention-days: 1
- name: Build and archive zeph-index postgres integration tests
run: cargo nextest archive --config-file .github/nextest.toml --cargo-profile ci -p zeph-index --no-default-features --features test-utils --tests --archive-file nextest-archive-zeph-index-postgres.tar.zst
- name: Upload zeph-index postgres test archive
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with:
name: nextest-archive-zeph-index-postgres
path: nextest-archive-zeph-index-postgres.tar.zst
retention-days: 1
- name: Build and archive zeph-orchestration postgres integration tests
run: cargo nextest archive --config-file .github/nextest.toml --cargo-profile ci -p zeph-orchestration --no-default-features --features test-utils --tests --archive-file nextest-archive-zeph-orchestration-postgres.tar.zst
- name: Upload zeph-orchestration postgres test archive
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with:
name: nextest-archive-zeph-orchestration-postgres
path: nextest-archive-zeph-orchestration-postgres.tar.zst
retention-days: 1
test:
name: "Test (shard ${{ matrix.partition }})"
needs: [detect-changes, lint-fmt, lint-clippy, build-tests]
if: needs.detect-changes.outputs.run-full-ci == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
partition: ["1/8", "2/8", "3/8", "4/8", "5/8", "6/8", "7/8", "8/8"]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - uses: taiki-e/install-action@37ba67210166984a515120020147f0b4ae3b8667 - name: Download test archive
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with:
name: nextest-archive-ubuntu-latest
- name: "Run tests (shard ${{ matrix.partition }})"
run: |
cargo nextest run \
--config-file .github/nextest.toml \
--archive-file nextest-archive.tar.zst \
--workspace-remap . \
--profile ci-partition \
--partition hash:${{ matrix.partition }}
integration:
name: Integration Tests (${{ matrix.suite }})
needs: [detect-changes, lint-fmt, lint-clippy, build-tests, build-tests-postgres]
if: needs.detect-changes.outputs.run-full-ci == 'true'
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
- suite: qdrant
archive: nextest-archive-ubuntu-latest
file: nextest-archive.tar.zst
run_args: "-E 'binary(qdrant_integration) or binary(document_integration)'"
- suite: zeph-db-postgres
archive: nextest-archive-zeph-db-postgres
file: nextest-archive-zeph-db-postgres.tar.zst
run_args: ""
- suite: zeph-memory-postgres
archive: nextest-archive-zeph-memory-postgres
file: nextest-archive-zeph-memory-postgres.tar.zst
run_args: "-E 'binary(postgres_integration)'"
- suite: zeph-index-postgres
archive: nextest-archive-zeph-index-postgres
file: nextest-archive-zeph-index-postgres.tar.zst
run_args: "-E 'binary(postgres_integration)'"
- suite: zeph-orchestration-postgres
archive: nextest-archive-zeph-orchestration-postgres
file: nextest-archive-zeph-orchestration-postgres.tar.zst
run_args: "-E 'binary(postgres_integration)'"
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - uses: taiki-e/install-action@37ba67210166984a515120020147f0b4ae3b8667 - uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Restore testcontainer image cache
id: tc-image-cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 with:
path: /tmp/testcontainer-images
key: testcontainer-images-${{ hashFiles('.github/testcontainers-images.txt') }}
- name: Pull and save testcontainer images (cache miss)
if: steps.tc-image-cache.outputs.cache-hit != 'true'
run: |
mkdir -p /tmp/testcontainer-images
while IFS= read -r image; do
[ -z "$image" ] && continue
echo "Pulling $image"
docker pull "$image"
fname=$(echo "$image" | tr '/:' '__')
docker save "$image" | zstd -T0 -3 -o /tmp/testcontainer-images/"$fname".tar.zst
done < .github/testcontainers-images.txt
ls -lh /tmp/testcontainer-images/
- name: Load testcontainer images (cache hit)
if: steps.tc-image-cache.outputs.cache-hit == 'true'
run: |
for f in /tmp/testcontainer-images/*.tar.zst; do
echo "Loading $f"
zstd -d -c "$f" | docker load
done
docker image ls
- name: Download test archive
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with:
name: ${{ matrix.archive }}
- name: Run integration tests (testcontainers)
run: cargo nextest run --config-file .github/nextest.toml --archive-file ${{ matrix.file }} --workspace-remap . --profile ci --run-ignored ignored-only ${{ matrix.run_args }}
- name: Run zeph-memory postgres unit tests (#5540)
if: matrix.suite == 'zeph-memory-postgres'
run: cargo nextest run --config-file .github/nextest.toml --archive-file nextest-archive-zeph-memory-postgres.tar.zst --workspace-remap . --profile ci -E 'kind(lib) and test(matches_active_dialect)'
- name: Reap orphaned testcontainers
if: always()
run: docker ps -aq --filter "label=org.testcontainers.managed-by=testcontainers" | xargs -r docker rm -f
coverage:
name: Coverage
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.detect-changes.outputs.run-full-ci == 'true'
needs: [detect-changes, lint-fmt, lint-clippy]
runs-on: ubuntu-latest
timeout-minutes: 20
env:
RUSTC_WRAPPER: sccache
SCCACHE_GHA_ENABLED: "true"
CARGO_BUILD_WARNINGS: "allow"
RUST_MIN_STACK: "33554432"
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with:
toolchain: stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 with:
cache-targets: "false"
shared-key: "coverage"
- uses: mozilla-actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 - uses: taiki-e/install-action@ea361d59ff285fa3ab7cc40dcba421e91017d586 - uses: taiki-e/install-action@37ba67210166984a515120020147f0b4ae3b8667 - name: Generate coverage
run: cargo llvm-cov nextest --config-file .github/nextest.toml --cargo-profile ci --workspace --features full --lib --bins --lcov --output-path lcov.info
- name: Upload coverage
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f with:
token: ${{ secrets.CODECOV_TOKEN }}
files: lcov.info
fail_ci_if_error: false
docker-build-and-scan:
name: Docker Build and Security Scan
needs: [detect-changes, lint-fmt, lint-clippy, build-tests]
if: needs.detect-changes.outputs.run-full-ci == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - name: Download binary
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with:
name: zeph-binary
path: target/ci
- name: Prepare binaries for Docker
run: |
mkdir -p binaries
cp target/ci/zeph binaries/zeph-amd64
cp target/ci/zeph binaries/zeph-arm64
- uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c - name: Build Docker image
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a with:
context: .
file: docker/Dockerfile
load: true
tags: zeph:local
push: false
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 continue-on-error: true
with:
image-ref: zeph:local
format: sarif
output: trivy-results.sarif
severity: CRITICAL,HIGH
exit-code: '1'
limit-severities-for-sarif: true
- name: Upload Trivy results to GitHub Security tab
uses: github/codeql-action/upload-sarif@e0647621c2984b5ed2f768cb892365bf2a616ad1 with:
sarif_file: trivy-results.sarif
bundle-check:
name: Bundle Check (${{ matrix.bundle }})
needs: detect-changes
if: needs.detect-changes.outputs.run-full-ci == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
bundle: [desktop, ide, server, chat, ml, bench, full]
include:
- bundle: ml
allow_failure: true
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with:
toolchain: stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 with:
shared-key: "ci"
- name: Check bundle
continue-on-error: ${{ matrix.allow_failure == true }}
run: cargo check --features ${{ matrix.bundle }}
release-build:
name: Release Build Check
needs: [detect-changes, lint-fmt, lint-clippy]
if: needs.detect-changes.outputs.run-full-ci == 'true' && github.event_name == 'push'
runs-on: ubuntu-latest
timeout-minutes: 45
env:
RUSTC_WRAPPER: sccache
SCCACHE_GHA_ENABLED: "true"
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with:
toolchain: stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 with:
cache-targets: "false"
shared-key: "release-build"
- uses: mozilla-actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 - name: cargo build (release, --all-targets)
run: cargo build --release --workspace --all-targets --features "desktop,ide,server,chat,pdf,scheduler,registry,testing,deep-link"
release-build-full:
name: Release Build Check (full)
needs: [detect-changes, lint-fmt, lint-clippy]
if: needs.detect-changes.outputs.run-full-ci == 'true' && github.event_name == 'push'
runs-on: ubuntu-latest
timeout-minutes: 45
env:
RUSTC_WRAPPER: sccache
SCCACHE_GHA_ENABLED: "true"
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with:
toolchain: stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 with:
cache-targets: "false"
shared-key: "release-build-full"
- uses: mozilla-actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 - name: cargo build (release, --all-targets, full)
continue-on-error: true
run: cargo build --release --workspace --all-targets --features full
build-postgres:
name: Build (postgres)
needs: detect-changes
if: needs.detect-changes.outputs.run-full-ci == 'true'
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with:
toolchain: stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 with:
shared-key: "ci"
- name: Verify sqlite+postgres compile_error guard
run: |
cargo check -p zeph-db --features postgres > /tmp/guard.log 2>&1 || true
if grep -q "mutually exclusive for \`zeph-db\`" /tmp/guard.log; then
echo "guard fired as expected"
else
echo "::error::compile_error! guard did not fire — sqlite+postgres both-enabled regression"
cat /tmp/guard.log
exit 1
fi
- name: Check postgres build (workspace)
run: cargo check --workspace --all-targets --no-default-features --features full,postgres
- name: Check sqlite build (workspace, no-default-features parity)
run: cargo check --workspace --all-targets --no-default-features --features full,sqlite
rustdoc:
name: Rustdoc
needs: detect-changes
if: needs.detect-changes.outputs.run-full-ci == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
env:
RUSTDOCFLAGS: "--deny rustdoc::broken_intra_doc_links --deny rustdoc::private_intra_doc_links --deny rustdoc::redundant_explicit_links"
CARGO_BUILD_WARNINGS: "allow"
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with:
toolchain: stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 with:
shared-key: "ci"
- name: Build docs (all features except candle)
run: cargo doc --no-deps --workspace --features "desktop,ide,server,chat,pdf,scheduler,registry,deep-link"
- name: Doc-tests
run: cargo test --doc --workspace --features "desktop,ide,server,chat,pdf,scheduler,registry,deep-link"
validate-specs:
name: Validate Specs
needs: detect-changes
if: needs.detect-changes.outputs.specs-only == 'true'
runs-on: ubuntu-latest
timeout-minutes: 2
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - name: Check spec structure
run: |
echo "Spec files found:"
find specs -name "*.md" -type f | sort
echo "Total: $(find specs -name "*.md" -type f | wc -l)"
# Verify README index exists
test -f specs/README.md || (echo "::error::specs/README.md index is missing" && exit 1)
ci-status:
name: CI Status
if: always()
needs: [detect-changes, cla, lint-shellcheck, lint-fmt, lint-clippy, msrv, build-tests, build-tests-postgres, test, integration, coverage, docker-build-and-scan, bundle-check, validate-specs, build-postgres, rustdoc, release-build, release-build-full]
runs-on: ubuntu-latest
timeout-minutes: 1
steps:
- name: Check all jobs
run: |
results=(
"${{ needs.detect-changes.result }}"
"${{ needs.cla.result }}"
"${{ needs.lint-shellcheck.result }}"
"${{ needs.lint-fmt.result }}"
"${{ needs.lint-clippy.result }}"
"${{ needs.msrv.result }}"
"${{ needs.build-tests.result }}"
"${{ needs.build-tests-postgres.result }}"
"${{ needs.test.result }}"
"${{ needs.integration.result }}"
"${{ needs.coverage.result }}"
"${{ needs.docker-build-and-scan.result }}"
"${{ needs.bundle-check.result }}"
"${{ needs.validate-specs.result }}"
"${{ needs.build-postgres.result }}"
"${{ needs.rustdoc.result }}"
"${{ needs.release-build.result }}"
"${{ needs.release-build-full.result }}"
)
for r in "${results[@]}"; do
if [[ "$r" != "success" && "$r" != "skipped" ]]; then
echo "::error::One or more jobs failed or were cancelled"
exit 1
fi
done
echo "All jobs passed"