Repository navigation
fix(destroy): say the stack is remote instead of calling it absent #1125
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Docker CICD | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - testing | |
| - dev | |
| pull_request: | |
| branches: | |
| - main | |
| - dev | |
| release: | |
| types: [published] | |
| jobs: | |
| cicd-docker: | |
| name: Cargo and npm build | |
| runs-on: ubuntu-latest | |
| #runs-on: [self-hosted, linux] | |
| # Build inside the same image the Dockerfile builds in, so the binaries | |
| # produced here can be copied into the runtime image instead of being | |
| # compiled a second time. They are dynamically linked against glibc, and | |
| # glibc is forward- but not backward-compatible: a binary built on the | |
| # runner (Ubuntu 24.04, glibc 2.39) would not start on debian:bookworm-slim | |
| # (glibc 2.36). Building in rust:bookworm makes the two match exactly. | |
| container: | |
| image: rust:bookworm | |
| services: | |
| postgres: | |
| image: postgres:16 | |
| env: | |
| POSTGRES_USER: postgres | |
| POSTGRES_PASSWORD: postgres | |
| POSTGRES_DB: postgres | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd "pg_isready -U postgres" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| env: | |
| SQLX_OFFLINE: true | |
| steps: | |
| - name: Checkout sources | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.ref }} | |
| - name: Export PostgreSQL connection env | |
| run: | | |
| # Inside a job container, services resolve by name on the shared | |
| # network — 127.0.0.1 is the container itself. | |
| echo "PGHOST=postgres" >> "$GITHUB_ENV" | |
| echo "PGPORT=5432" >> "$GITHUB_ENV" | |
| echo "PGUSER=postgres" >> "$GITHUB_ENV" | |
| echo "PGPASSWORD=postgres" >> "$GITHUB_ENV" | |
| # No apt step here: `rust:bookworm` already carries pkg-config, libssl-dev | |
| # and a C toolchain, and protoc never comes from the system — `build.rs` | |
| # points PROTOC at a vendored binary unless one is already set. The step | |
| # that used to be here called `sudo`, which the image does not have, and | |
| # does not need: the job runs as root. | |
| - name: Verify .sqlx cache exists | |
| run: | | |
| ls -lh .sqlx/ || echo ".sqlx directory not found" | |
| find .sqlx -type f 2>/dev/null | wc -l | |
| - name: Install stable toolchain | |
| uses: actions-rs/toolchain@v1 | |
| with: | |
| toolchain: stable | |
| profile: minimal | |
| override: true | |
| components: rustfmt, clippy | |
| # Registry and git only — not `target`. Caching the target directory here | |
| # filled the runner's disk: `restore-keys: docker-` pulled in an older, | |
| # already-bloated cache, the build added to it, and the post-job step | |
| # saved a larger one still, so every run grew the next one's starting | |
| # point. A 33-minute job that passed every check then died in cleanup | |
| # with "No space left on device". | |
| # | |
| # rust.yml reached the same conclusion for the same reason; this keeps | |
| # both workflows on one rule. | |
| - name: Cache Cargo registry/git (no target — it grows without bound here) | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| cache-targets: "false" | |
| key: docker-cicd | |
| - name: Generate Secret Key | |
| run: | | |
| head -c16 /dev/urandom > src/secret.key | |
| - name: Wait for PostgreSQL | |
| run: | | |
| for _ in $(seq 1 60); do | |
| if bash -lc "exec 3<>/dev/tcp/${PGHOST}/${PGPORT}" 2>/dev/null; then | |
| exit 0 | |
| fi | |
| sleep 1 | |
| done | |
| echo "PostgreSQL did not become ready in time" >&2 | |
| exit 1 | |
| - name: Cargo check | |
| uses: actions-rs/cargo@v1 | |
| with: | |
| command: check | |
| - name: Install cargo-nextest | |
| uses: taiki-e/install-action@nextest | |
| # nextest runs each test in its own process, so tests that mutate global | |
| # env vars no longer race and the suite runs in parallel (no more | |
| # RUST_TEST_THREADS=1 serialization, no 25-minute timeout). The `bdd` | |
| # target uses a custom harness nextest cannot run, so it runs separately. | |
| # Both suites run even if one of them fails, so a single broken test does | |
| # not hide the state of the other. Not `always()`: that also runs them | |
| # after an earlier *setup* step fails, and then reports something | |
| # unrelated — a missing apt package once surfaced as "no such command: | |
| # nextest", because the install step had been skipped. | |
| - name: Cargo test | |
| run: cargo nextest run --tests -E 'not binary(bdd)' | |
| - name: Cargo test (bdd suite) | |
| if: success() || failure() | |
| run: cargo test --test bdd | |
| - name: Rustfmt | |
| uses: actions-rs/toolchain@v1 | |
| with: | |
| toolchain: stable | |
| profile: minimal | |
| override: true | |
| components: rustfmt | |
| command: fmt | |
| args: --all -- --check | |
| - name: Rustfmt | |
| uses: actions-rs/toolchain@v1 | |
| with: | |
| toolchain: stable | |
| profile: minimal | |
| override: true | |
| components: clippy | |
| command: clippy | |
| args: -- -D warnings | |
| # One invocation, so the four binaries share a single compilation of the | |
| # workspace instead of four sequential ones. These are the binaries the | |
| # runtime image needs; the Docker job copies them rather than rebuilding. | |
| # Two invocations, not one: `--features` applies to the whole command, not | |
| # to the `--bin` it follows. Listing them together builds `server` with | |
| # `explain` too — a differently configured binary from the one the image | |
| # has always shipped. The second call is nearly free; only `console` and | |
| # the re-featured casbin dependency recompile. | |
| - name: Build release binaries | |
| run: | | |
| cargo build --release \ | |
| --bin server \ | |
| --bin cleanup-notify \ | |
| --bin backfill_field_policy | |
| cargo build --release --bin console --features explain | |
| - name: Set up Node.js | |
| if: ${{ hashFiles('web/package.json') != '' }} | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'npm' | |
| cache-dependency-path: web/package-lock.json | |
| - name: npm install, build, and test | |
| if: ${{ hashFiles('web/package.json') != '' }} | |
| working-directory: ./web | |
| run: | | |
| npm install | |
| npm run build | |
| # npm test | |
| - name: Archive production artifacts | |
| if: ${{ hashFiles('web/package.json') != '' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: dist-without-markdown | |
| path: | | |
| web/dist | |
| !web/dist/**/*.md | |
| - name: Display structure of downloaded files | |
| if: ${{ hashFiles('web/package.json') != '' }} | |
| run: ls -R web/dist | |
| - name: Copy app files and zip | |
| run: | | |
| mkdir -p app/stacker/dist | |
| cp target/release/server app/stacker/server | |
| cp target/release/console app/stacker/console | |
| cp target/release/cleanup-notify app/stacker/cleanup-notify | |
| cp target/release/backfill_field_policy app/stacker/backfill_field_policy | |
| if [ -d web/dist ]; then cp -a web/dist/. app/stacker; fi | |
| cp Dockerfile app/Dockerfile | |
| cp access_control.conf.dist app/access_control.conf.dist | |
| cd app | |
| touch .env | |
| tar -czvf ../app.tar.gz . | |
| cd .. | |
| - name: Upload app archive for Docker job | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: artifact-linux-docker | |
| path: app.tar.gz | |
| cicd-linux-docker: | |
| name: CICD Docker | |
| runs-on: ubuntu-latest | |
| #runs-on: [self-hosted, linux] | |
| needs: cicd-docker | |
| steps: | |
| - name: Checkout sources | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref }} | |
| - name: Verify shared pipe fixtures | |
| run: | | |
| test -d "${GITHUB_WORKSPACE}/tests/fixtures/pipe-contract" | |
| # The test job already compiled these, in the same rust:bookworm image the | |
| # runtime stage is based on. Without this the Dockerfile compiles the whole | |
| # workspace a second time — around fourteen minutes of the run. | |
| - name: Download binaries built by the test job | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: artifact-linux-docker | |
| # Unpacked outside the workspace: `.dockerignore` is empty, so anything | |
| # left here is sent to buildkit as part of `context: .` — hundreds of | |
| # megabytes of release binaries, twice, eating back the time this change | |
| # exists to save. | |
| - name: Unpack binaries | |
| run: | | |
| mkdir -p "${{ runner.temp }}/prebuilt" | |
| tar -xzf app.tar.gz -C "${{ runner.temp }}/prebuilt" | |
| cd "${{ runner.temp }}/prebuilt" | |
| mv stacker/server stacker/console stacker/cleanup-notify \ | |
| stacker/backfill_field_policy . | |
| chmod +x server console cleanup-notify backfill_field_policy | |
| rm -f "${GITHUB_WORKSPACE}/app.tar.gz" | |
| - | |
| name: Set up QEMU | |
| uses: docker/setup-qemu-action@v3 | |
| - | |
| name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - | |
| name: Login to Docker Hub | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_PASSWORD }} | |
| - name: Set Docker tags | |
| id: docker_tags | |
| run: | | |
| if [ "${{ github.event_name }}" = "release" ]; then | |
| echo "tags=trydirect/stacker:${{ github.ref_name }}" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "tags=trydirect/stacker:latest" >> "$GITHUB_OUTPUT" | |
| fi | |
| - | |
| name: Build and push | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| build-args: | | |
| BINARIES=prebuilt | |
| build-contexts: | | |
| shared_fixtures=${{ github.workspace }}/tests/fixtures | |
| prebuilt_binaries=${{ runner.temp }}/prebuilt | |
| push: ${{ github.event_name != 'pull_request' }} | |
| tags: ${{ steps.docker_tags.outputs.tags }} | |
| stackerdb-docker: | |
| name: StackerDB Docker | |
| runs-on: ubuntu-latest | |
| #runs-on: [self-hosted, linux] | |
| steps: | |
| - name: Checkout sources | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.ref }} | |
| - | |
| name: Set up QEMU | |
| uses: docker/setup-qemu-action@v3 | |
| - | |
| name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - | |
| name: Login to Docker Hub | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_PASSWORD }} | |
| - name: Set Docker tags | |
| id: stackerdb_tags | |
| run: | | |
| echo "tags<<EOF" >> "$GITHUB_OUTPUT" | |
| echo "trydirect/stackerdb:build-${{ github.run_number }}" >> "$GITHUB_OUTPUT" | |
| echo "trydirect/stackerdb:latest" >> "$GITHUB_OUTPUT" | |
| if [ "${{ github.event_name }}" = "release" ]; then | |
| echo "trydirect/stackerdb:${{ github.ref_name }}" >> "$GITHUB_OUTPUT" | |
| fi | |
| echo "EOF" >> "$GITHUB_OUTPUT" | |
| - name: Build and push | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: ./stackerdb | |
| file: ./stackerdb/Dockerfile | |
| push: true | |
| tags: ${{ steps.stackerdb_tags.outputs.tags }} | |
| cache-from: type=gha,scope=stackerdb | |
| cache-to: type=gha,mode=max,scope=stackerdb |