self_review #2714
This file contains 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: Bencher | |
on: | |
workflow_dispatch: | |
push: | |
branches: [main, cloud, devel] | |
tags: [v**] | |
pull_request: | |
branches: [main, cloud, devel] | |
env: | |
# General | |
CARGO_TERM_COLOR: always | |
MOLD_VERSION: 2.34.1 | |
GITHUB_REGISTRY: ghcr.io | |
DOCKER_HUB_ORGANIZATION: bencherdev | |
# API | |
API_DOCKER_IMAGE: bencher-api | |
LITESTREAM_VERSION: 0.3.13 | |
LITESTREAM_ARCH: amd64 | |
FLY_REGISTRY: registry.fly.io | |
# CLI | |
CLI_BIN_NAME: bencher | |
ZIG_VERSION: 0.13.0 | |
ZIG_BUILD_VERSION: 0.19.3 | |
# Use minimum supported glibc version for Rust Tier 1 | |
# https://doc.rust-lang.org/nightly/rustc/platform-support.html#tier-1-with-host-tools | |
GLIBC_VERSION: 2.17 | |
# WASM | |
WASM_BENCHER_VALID: bencher-valid-pkg | |
# Console | |
CONSOLE_DOCKER_IMAGE: bencher-console | |
# Dev Container | |
DEV_CONTAINER_DOCKER_IMAGE: bencher-dev-container | |
# Cache | |
CACHE_NAME: ${{ ((github.ref == 'refs/heads/main' || github.ref == 'refs/heads/cloud' || github.ref == 'refs/heads/devel' || startsWith(github.ref, 'refs/tags/')) && github.ref_name) || (github.event_name == 'pull_request' && github.event.number) }} | |
jobs: | |
# Bencher CLI GitHub Action | |
build_github_action: | |
name: Build GitHub Action | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Install Bencher CLI GitHub Action Dependencies | |
working-directory: ./services/action | |
run: npm install --include=dev | |
- name: Build Bencher CLI GitHub Action | |
working-directory: ./services/action | |
run: npm run build | |
- name: Check for changes | |
continue-on-error: ${{ !startsWith(github.ref, 'refs/tags/') }} | |
run: git diff --exit-code | |
test_cli_install: | |
name: Test CLI Install | |
strategy: | |
fail-fast: false | |
matrix: | |
include: | |
# Linux | |
- os: ubuntu-latest | |
source: action-main | |
- os: ubuntu-latest | |
source: action-devel | |
- os: ubuntu-latest | |
source: script-cloud | |
- os: ubuntu-latest | |
source: script-gen | |
- os: ubuntu-latest | |
source: cargo-main | |
- os: ubuntu-latest | |
source: cargo-devel | |
# MacOS | |
- os: macos-latest | |
source: action-main | |
- os: macos-latest | |
source: action-devel | |
- os: macos-latest | |
source: script-cloud | |
- os: macos-latest | |
source: script-gen | |
- os: macos-latest | |
source: cargo-main | |
- os: macos-latest | |
source: cargo-devel | |
# Windows | |
- os: windows-latest | |
source: action-main | |
- os: windows-latest | |
source: action-devel | |
- os: windows-latest | |
source: script-cloud | |
- os: windows-latest | |
source: script-gen | |
- os: windows-latest | |
source: cargo-main | |
- os: windows-latest | |
source: cargo-devel | |
runs-on: ${{ matrix.os }} | |
# This is expected to fail when tagging a new release | |
continue-on-error: ${{ startsWith(github.ref, 'refs/tags/') && ( matrix.source == 'action-devel' || matrix.source == 'cargo-devel' || matrix.source == 'cargo-main' ) }} | |
steps: | |
- uses: bencherdev/bencher@main | |
if: matrix.source == 'action-main' | |
- uses: bencherdev/bencher@devel | |
if: matrix.source == 'action-devel' | |
- name: Unix CLI Download Install Script | |
if: matrix.source == 'script-cloud' && matrix.os != 'windows-latest' | |
run: curl --proto '=https' --tlsv1.2 -sSfL https://bencher.dev/download/install-cli.sh | sh | |
- name: Windows CLI Download Install Script | |
if: matrix.source == 'script-cloud' && matrix.os == 'windows-latest' | |
run: irm https://bencher.dev/download/install-cli.ps1 | iex | |
- uses: actions/checkout@v4 | |
if: matrix.source == 'script-gen' | |
- name: Unix CLI Install Script | |
if: matrix.source == 'script-gen' && matrix.os != 'windows-latest' | |
run: cat services/cli/templates/output/install-cli.sh | sh | |
- name: Windows CLI Install Script | |
if: matrix.source == 'script-gen' && matrix.os == 'windows-latest' | |
run: gc -Raw services/cli/templates/output/install-cli.ps1 | iex | |
- name: Cargo CLI Install main | |
if: matrix.source == 'cargo-main' | |
run: cargo install --git https://github.com/bencherdev/bencher --branch main --locked bencher_cli | |
- name: Cargo CLI Install devel | |
if: matrix.source == 'cargo-devel' | |
run: cargo install --git https://github.com/bencherdev/bencher --branch devel --locked bencher_cli | |
- name: Run current Bencher CLI GitHub Action | |
run: bencher run --project bencher --token ${{ secrets.BENCHER_API_TOKEN }} --dry-run "bencher mock" | |
# Pretty Rust | |
cargo_fmt: | |
name: Cargo Format | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Add fmt | |
run: rustup component add rustfmt | |
- name: Run fmt | |
run: cargo fmt -- --check | |
cargo_clippy: | |
name: Cargo Clippy | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/cache@v4 | |
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/cloud' || github.ref == 'refs/heads/devel' || startsWith(github.ref, 'refs/tags/') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) | |
with: | |
path: | | |
~/.cargo/bin/ | |
~/.cargo/registry/index/ | |
~/.cargo/registry/cache/ | |
~/.cargo/git/db/ | |
target/ | |
key: ${{ runner.os }}-cargo-all-features | |
- uses: rui314/setup-mold@v1 | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- name: Add clippy | |
run: rustup component add clippy | |
- name: Run clippy | |
run: cargo clippy --no-deps --all-features -- -Dwarnings | |
check_generated: | |
name: Check Generated | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: rui314/setup-mold@v1 | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- name: Generate OpenAPI Spec | |
run: cargo gen-spec | |
- name: Check OpenAPI Spec for changes | |
run: git diff --exit-code | |
- name: Generate Unix CLI install scripts | |
run: cargo gen-installer sh | |
- name: Check Unix CLI install script for changes | |
run: git diff --exit-code | |
- name: Generate Windows CLI install scripts | |
run: cargo gen-installer ps1 | |
- name: Check Windows CLI install script for changes | |
run: git diff --exit-code | |
# Cargo Test | |
cargo_test: | |
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/cloud' || github.ref == 'refs/heads/devel' || startsWith(github.ref, 'refs/tags/') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) | |
name: Cargo Test | |
runs-on: ubuntu-latest | |
env: | |
TEST_BILLING_KEY: ${{ secrets.TEST_BILLING_KEY }} | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/cache@v4 | |
with: | |
path: | | |
~/.cargo/bin/ | |
~/.cargo/registry/index/ | |
~/.cargo/registry/cache/ | |
~/.cargo/git/db/ | |
target/ | |
key: ${{ runner.os }}-cargo-all-features | |
- uses: rui314/setup-mold@v1 | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- name: cargo test | |
run: RUST_BACKTRACE=1 cargo test --all-features -- --nocapture | |
- name: Upload Perf JPEG | |
uses: actions/upload-artifact@v4 | |
with: | |
name: perf.jpeg | |
path: ./lib/bencher_plot/perf.jpeg | |
if-no-files-found: error | |
cargo_test_pr: | |
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository | |
name: Cargo Test PR | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: rui314/setup-mold@v1 | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- name: cargo test | |
run: RUST_BACKTRACE=1 cargo test --all-features -- --nocapture | |
- name: Upload Perf JPEG | |
uses: actions/upload-artifact@v4 | |
with: | |
name: perf.jpeg | |
path: ./lib/bencher_plot/perf.jpeg | |
if-no-files-found: error | |
# API Smoke Test | |
api_smoke_test: | |
name: API Smoke Test | |
runs-on: ubuntu-latest | |
steps: | |
- uses: jlumbroso/free-disk-space@main | |
with: | |
large-packages: false | |
- uses: actions/checkout@v4 | |
- uses: actions/cache@v4 | |
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/cloud' || github.ref == 'refs/heads/devel' || startsWith(github.ref, 'refs/tags/') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) | |
with: | |
path: | | |
~/.cargo/bin/ | |
~/.cargo/registry/index/ | |
~/.cargo/registry/cache/ | |
~/.cargo/git/db/ | |
target/ | |
key: ${{ runner.os }}-cargo-api | |
- uses: rui314/setup-mold@v1 | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- name: Run Smoke Test | |
run: cargo test-api smoke ci | |
release_api_smoke_test: | |
name: Release API Smoke Test | |
strategy: | |
fail-fast: false | |
matrix: | |
include: | |
- os: ubuntu-latest | |
- os: macos-latest | |
- os: windows-latest | |
runs-on: ${{ matrix.os }} | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: rui314/setup-mold@v1 | |
if: matrix.os == 'ubuntu-latest' | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- name: Run Smoke Test | |
run: cargo test-api smoke localhost | |
docker_api_smoke_test: | |
name: Docker API Smoke Test | |
strategy: | |
fail-fast: false | |
matrix: | |
include: | |
- os: ubuntu-latest | |
# https://github.com/actions/runner-images/issues/17#issuecomment-614726536 | |
# - os: macos-latest | |
# https://github.com/orgs/community/discussions/25491#discussioncomment-3248089 | |
# - os: windows-latest | |
runs-on: ${{ matrix.os }} | |
steps: | |
- uses: jlumbroso/free-disk-space@main | |
with: | |
large-packages: false | |
- uses: actions/checkout@v4 | |
- uses: rui314/setup-mold@v1 | |
if: matrix.os == 'ubuntu-latest' | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- name: Run Smoke Test | |
run: cargo test-api smoke docker | |
# Cargo Check (Minus) | |
cargo_check_api_minus: | |
name: Cargo Check API (Minus) | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: rui314/setup-mold@v1 | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- name: cargo check | |
working-directory: ./services/api | |
run: cargo check --no-default-features | |
cargo_check_cli_minus: | |
name: Cargo Check CLI (Minus) | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: rui314/setup-mold@v1 | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- name: cargo check | |
working-directory: ./services/cli | |
run: cargo check --no-default-features | |
# Cargo Benchmark | |
cargo_bench: | |
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/cloud' || github.ref == 'refs/heads/devel' || startsWith(github.ref, 'refs/tags/') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) | |
name: Cargo Bench | |
runs-on: ubuntu-latest | |
# This will fail whenever Bencher Cloud is down | |
# or there are any breaking changes to the report format | |
continue-on-error: true | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/cache@v4 | |
with: | |
path: | | |
~/.cargo/bin/ | |
~/.cargo/registry/index/ | |
~/.cargo/registry/cache/ | |
~/.cargo/git/db/ | |
target/ | |
key: ${{ runner.os }}-cargo-cli | |
- uses: rui314/setup-mold@v1 | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- name: Install `bencher` CLI | |
run: cargo install --debug --path services/cli --locked --force | |
- name: Dogfooding Benchmarks with Bencher | |
run: | | |
bencher run \ | |
--host https://api.bencher.dev \ | |
--project bencher \ | |
--token '${{ secrets.BENCHER_API_TOKEN }}' \ | |
--branch "$GITHUB_REF_NAME" \ | |
--start-point "$GITHUB_BASE_REF" \ | |
--testbed ubuntu-latest \ | |
--adapter rust_criterion \ | |
--err \ | |
--github-actions ${{ secrets.GITHUB_TOKEN }} \ | |
cargo bench --package bencher_adapter | |
# Cargo Audit | |
cargo_audit: | |
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/cloud' || github.ref == 'refs/heads/devel' || startsWith(github.ref, 'refs/tags/') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) | |
name: Cargo Audit | |
runs-on: ubuntu-latest | |
continue-on-error: true | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/cache@v4 | |
with: | |
path: | | |
~/.cargo/bin/ | |
~/.cargo/registry/index/ | |
~/.cargo/registry/cache/ | |
~/.cargo/git/db/ | |
target/ | |
key: ${{ runner.os }}-cargo-audit | |
- uses: rui314/setup-mold@v1 | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- run: cargo audit | |
# Cargo Unused Deps | |
cargo_udeps: | |
name: Cargo Unused Deps | |
runs-on: ubuntu-latest | |
continue-on-error: ${{ !startsWith(github.ref, 'refs/tags/') }} | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/cache@v4 | |
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/cloud' || github.ref == 'refs/heads/devel' || startsWith(github.ref, 'refs/tags/') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) | |
with: | |
path: | | |
~/.cargo/bin/ | |
~/.cargo/registry/index/ | |
~/.cargo/registry/cache/ | |
~/.cargo/git/db/ | |
target/ | |
key: ${{ runner.os }}-cargo-nightly | |
- uses: rui314/setup-mold@v1 | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- name: Install nightly toolchain | |
run: rustup toolchain install nightly | |
- name: Install udeps | |
run: cargo install --version 0.1.50 --locked --force cargo-udeps | |
- name: Run API udeps | |
continue-on-error: true | |
working-directory: ./services/api | |
run: cargo +nightly udeps --all-targets | |
- name: Run CLI udeps | |
continue-on-error: true | |
working-directory: ./services/cli | |
run: cargo +nightly udeps --all-targets | |
# Pretty JS | |
npx_biome_format: | |
name: Biome Format | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Biome format Action | |
working-directory: ./services/action | |
run: | | |
npm install --include=dev | |
npx biome ci --linter-enabled false --organize-imports-enabled false . | |
- name: Biome format Console UI | |
working-directory: ./services/console | |
run: | | |
npm install --include=dev | |
npx biome ci --linter-enabled false --organize-imports-enabled false . | |
npx_biome_lint: | |
name: Biome Lint | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Biome check Action | |
working-directory: ./services/action | |
run: | | |
npm install --include=dev | |
npx biome ci --formatter-enabled false --organize-imports-enabled false . | |
- name: Biome check Console UI | |
working-directory: ./services/console | |
run: | | |
npm install --include=dev | |
npx biome ci --formatter-enabled false --organize-imports-enabled false . | |
# UI WASM | |
build_bencher_valid_wasm: | |
name: Build `bencher_valid` WASM | |
runs-on: ubuntu-latest | |
env: | |
WASM_PACK_BUILD: "wasm-pack build --target web --no-default-features --features plus,wasm" | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/cache@v4 | |
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/cloud' || github.ref == 'refs/heads/devel' || startsWith(github.ref, 'refs/tags/') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) | |
with: | |
path: | | |
~/.cargo/bin/ | |
~/.cargo/registry/index/ | |
~/.cargo/registry/cache/ | |
~/.cargo/git/db/ | |
target/ | |
key: ${{ runner.os }}-cargo-wasm | |
- run: cargo install wasm-pack --version 0.12.1 --locked --force | |
- name: WASM pack `bencher_valid` | |
working-directory: ./lib/bencher_valid | |
run: | | |
$WASM_PACK_BUILD || \ | |
$WASM_PACK_BUILD || \ | |
$WASM_PACK_BUILD || \ | |
$WASM_PACK_BUILD || \ | |
$WASM_PACK_BUILD | |
- name: Upload Artifact | |
uses: actions/upload-artifact@v4 | |
with: | |
name: ${{ env.WASM_BENCHER_VALID }} | |
path: ./lib/bencher_valid/pkg | |
if-no-files-found: error | |
test_bencher_valid_wasm: | |
name: Test `bencher_valid` WASM | |
runs-on: ubuntu-latest | |
needs: build_bencher_valid_wasm | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/cache@v4 | |
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/cloud' || github.ref == 'refs/heads/devel' || startsWith(github.ref, 'refs/tags/') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) | |
with: | |
path: | | |
~/.cargo/bin/ | |
~/.cargo/registry/index/ | |
~/.cargo/registry/cache/ | |
~/.cargo/git/db/ | |
target/ | |
key: ${{ runner.os }}-cargo-wasm | |
- uses: rui314/setup-mold@v1 | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- name: cargo test `bencher_valid` WASM | |
working-directory: ./lib/bencher_valid | |
run: cargo test --no-default-features --features plus,wasm | |
# NPM Test | |
npx_vitest: | |
name: vitest | |
runs-on: ubuntu-latest | |
needs: build_bencher_valid_wasm | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Download `bencher_valid` Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ env.WASM_BENCHER_VALID }} | |
path: ./lib/bencher_valid/pkg | |
- name: npx vitest | |
working-directory: ./services/console | |
run: | | |
npm install --include=dev | |
npx vitest run | |
# API Docker | |
# https://docs.docker.com/build/ci/github-actions/named-contexts/#using-with-a-container-builder | |
# https://www.kenmuse.com/blog/implementing-docker-layer-caching-in-github-actions/ | |
build_api_docker: | |
name: Build API Docker | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Set up QEMU | |
uses: docker/setup-qemu-action@v3 | |
- name: Setup Docker buildx | |
uses: docker/setup-buildx-action@v3 | |
- name: Log in to the Container registry | |
uses: docker/login-action@v3 | |
with: | |
registry: ${{ env.GITHUB_REGISTRY }} | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Build API Docker Image | |
uses: docker/build-push-action@v5 | |
with: | |
context: . | |
file: ./services/api/Dockerfile | |
tags: ${{ env.API_DOCKER_IMAGE }} | |
build-args: | | |
MOLD_VERSION=${{ env.MOLD_VERSION }} | |
LITESTREAM_VERSION=${{ env.LITESTREAM_VERSION }} | |
LITESTREAM_ARCH=${{ env.LITESTREAM_ARCH }} | |
cache-from: type=registry,ref=${{ env.GITHUB_REGISTRY }}/${{ github.repository_owner }}/${{ env.API_DOCKER_IMAGE }}:cache-${{ env.CACHE_NAME }} | |
cache-to: type=registry,ref=${{ env.GITHUB_REGISTRY }}/${{ github.repository_owner }}/${{ env.API_DOCKER_IMAGE }}:cache-${{ env.CACHE_NAME }},mode=max | |
load: true | |
push: false | |
- name: Save API Docker Image | |
run: | | |
docker save ${{ env.API_DOCKER_IMAGE }} \ | |
| gzip > ${{ env.API_DOCKER_IMAGE }}.tar.gz | |
- name: Upload API Docker Image Artifact | |
uses: actions/upload-artifact@v4 | |
with: | |
name: ${{ env.API_DOCKER_IMAGE }}.tar.gz | |
path: ./${{ env.API_DOCKER_IMAGE }}.tar.gz | |
if-no-files-found: error | |
# CLI | |
build_cli: | |
name: Build CLI | |
strategy: | |
fail-fast: false | |
matrix: | |
include: | |
# Linux | |
- build: linux-x86-64 | |
os: ubuntu-latest | |
target: x86_64-unknown-linux-gnu | |
- build: linux-arm-64 | |
os: ubuntu-latest | |
target: aarch64-unknown-linux-gnu | |
# MacOS | |
- build: macos-x86-64 | |
os: macos-latest | |
target: x86_64-apple-darwin | |
- build: macos-arm-64 | |
os: macos-latest | |
target: aarch64-apple-darwin | |
# Windows | |
- build: windows-x86-64 | |
os: windows-latest | |
target: x86_64-pc-windows-msvc | |
- build: windows-arm-64 | |
os: windows-latest | |
target: aarch64-pc-windows-msvc | |
runs-on: ${{ matrix.os }} | |
steps: | |
- uses: actions/checkout@v4 | |
# Install | |
- name: Install Rust target | |
run: rustup target add ${{ matrix.target }} | |
- uses: mlugg/setup-zig@v1 | |
if: startsWith(matrix.build, 'linux') | |
with: | |
version: ${{ env.ZIG_VERSION }} | |
- name: Install zigbuild | |
if: startsWith(matrix.build, 'linux') | |
run: cargo install --version ${{ env.ZIG_BUILD_VERSION }} --locked --force cargo-zigbuild | |
# Build | |
- name: cargo zigbuild Linux CLI | |
if: startsWith(matrix.build, 'linux') | |
working-directory: ./services/cli | |
run: cargo zigbuild --profile release-small --target ${{ matrix.target }}.${{ env.GLIBC_VERSION }} | |
- name: cargo zigbuild macos CLI | |
if: startsWith(matrix.build, 'macos') | |
working-directory: ./services/cli | |
run: cargo build --profile release-small --target ${{ matrix.target }} | |
- name: cargo build Windows CLI | |
if: startsWith(matrix.build, 'windows') | |
working-directory: ./services/cli | |
run: cargo build --profile release-small --target ${{ matrix.target }} | |
# Rename | |
- name: Rename Unix CLI bin | |
if: (!startsWith(matrix.build, 'windows')) | |
run: mv ./target/${{ matrix.target }}/release-small/${{ env.CLI_BIN_NAME }} ${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ matrix.build }} | |
- name: Rename Windows CLI bin | |
if: startsWith(matrix.build, 'windows') | |
run: mv ./target/${{ matrix.target }}/release-small/${{ env.CLI_BIN_NAME }}.exe ${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ matrix.build }}.exe | |
# Upload | |
- name: Upload Unix CLI Artifact | |
if: (!startsWith(matrix.build, 'windows')) | |
uses: actions/upload-artifact@v4 | |
with: | |
name: ${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ matrix.build }} | |
path: ${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ matrix.build }} | |
if-no-files-found: error | |
- name: Upload Windows CLI Artifact | |
if: startsWith(matrix.build, 'windows') | |
uses: actions/upload-artifact@v4 | |
with: | |
name: ${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ matrix.build }}.exe | |
path: ${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ matrix.build }}.exe | |
if-no-files-found: error | |
package_cli: | |
name: Package CLI | |
strategy: | |
fail-fast: false | |
matrix: | |
include: | |
# Linux | |
- build: linux-x86-64 | |
os: ubuntu-latest | |
target: x86_64-unknown-linux-gnu | |
arch: amd64 | |
- build: linux-arm-64 | |
os: ubuntu-latest | |
target: aarch64-unknown-linux-gnu | |
arch: arm64 | |
runs-on: ${{ matrix.os }} | |
needs: build_cli | |
env: | |
CLI_DEB_DIR: deb | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Download CLI Artifact | |
if: (!startsWith(matrix.build, 'windows')) | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ matrix.build }} | |
- uses: rui314/setup-mold@v1 | |
if: startsWith(matrix.build, 'linux') | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
# Debian .deb | |
- name: Build .deb package | |
if: startsWith(matrix.build, 'linux') | |
run: cargo gen-pkg deb --dir ${{ env.CLI_DEB_DIR }} --arch ${{ matrix.arch }} ${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ matrix.build }} | |
- name: Test install .deb package | |
if: matrix.build == 'linux-x86-64' | |
run: sudo dpkg -i ${{ env.CLI_DEB_DIR }}/${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ matrix.build }}.deb | |
- name: Sanity test .deb package installation | |
if: matrix.build == 'linux-x86-64' | |
run: | | |
bencher --version | |
bencher mock | |
man bencher | |
- name: Upload .deb Artifact | |
if: startsWith(matrix.build, 'linux') | |
uses: actions/upload-artifact@v4 | |
with: | |
name: ${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ matrix.build }}.deb | |
path: ${{ env.CLI_DEB_DIR }}/${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ matrix.build }}.deb | |
if-no-files-found: error | |
build_console_docker: | |
name: Build Console Docker | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Set up QEMU | |
uses: docker/setup-qemu-action@v3 | |
- name: Setup Docker buildx | |
uses: docker/setup-buildx-action@v3 | |
- name: Log in to the Container registry | |
uses: docker/login-action@v3 | |
with: | |
registry: ${{ env.GITHUB_REGISTRY }} | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Build Console Docker Image | |
uses: docker/build-push-action@v5 | |
with: | |
context: . | |
file: ./services/console/Dockerfile | |
tags: ${{ env.CONSOLE_DOCKER_IMAGE }} | |
cache-from: type=registry,ref=${{ env.GITHUB_REGISTRY }}/${{ github.repository_owner }}/${{ env.CONSOLE_DOCKER_IMAGE }}:cache-${{ env.CACHE_NAME }} | |
cache-to: type=registry,ref=${{ env.GITHUB_REGISTRY }}/${{ github.repository_owner }}/${{ env.CONSOLE_DOCKER_IMAGE }}:cache-${{ env.CACHE_NAME }},mode=max | |
load: true | |
push: false | |
- name: Save Console Docker Image | |
run: | | |
docker save ${{ env.CONSOLE_DOCKER_IMAGE }} \ | |
| gzip > ${{ env.CONSOLE_DOCKER_IMAGE }}.tar.gz | |
- name: Upload Console Docker Image Artifact | |
uses: actions/upload-artifact@v4 | |
with: | |
name: ${{ env.CONSOLE_DOCKER_IMAGE }}.tar.gz | |
path: ./${{ env.CONSOLE_DOCKER_IMAGE }}.tar.gz | |
if-no-files-found: error | |
build_console: | |
if: (!startsWith(github.ref, 'refs/tags/')) | |
name: Build Console UI | |
runs-on: ubuntu-latest | |
needs: build_bencher_valid_wasm | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Download `bencher_valid` Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ env.WASM_BENCHER_VALID }} | |
path: ./lib/bencher_valid/pkg | |
- name: Build Console UI | |
working-directory: ./services/console | |
run: npm run netlify | |
- name: Test Links | |
continue-on-error: true | |
uses: lycheeverse/[email protected] | |
with: | |
args: --config ./services/console/lychee.toml ./services/console/dist | |
# API Fly.io | |
deploy_api_fly_dev: | |
if: github.ref == 'refs/heads/devel' | |
name: Deploy API to Fly.io Dev | |
runs-on: ubuntu-latest | |
needs: | |
- build_api_docker | |
- build_console | |
env: | |
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Download Local Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ env.API_DOCKER_IMAGE }}.tar.gz | |
- name: Load & Tag Local Image | |
run: | | |
docker load < ${{ env.API_DOCKER_IMAGE }}.tar.gz | |
docker tag ${{ env.API_DOCKER_IMAGE }} ${{ env.FLY_REGISTRY }}/bencher-api-dev | |
- uses: superfly/flyctl-actions/setup-flyctl@master | |
- name: Deploy Local API to Fly.io | |
working-directory: ./services/api | |
run: flyctl deploy --local-only --config fly/fly.dev.toml --wait-timeout 300 | |
- uses: actions/cache@v4 | |
with: | |
path: | | |
~/.cargo/bin/ | |
~/.cargo/registry/index/ | |
~/.cargo/registry/cache/ | |
~/.cargo/git/db/ | |
target/ | |
key: ${{ runner.os }}-cargo-cli | |
- uses: rui314/setup-mold@v1 | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- name: Run Smoke Test | |
run: cargo test-api smoke dev | |
deploy_api_fly_test: | |
if: github.ref == 'refs/heads/cloud' || github.ref == 'refs/heads/devel' | |
name: Deploy API to Fly.io Test | |
runs-on: ubuntu-latest | |
needs: build_api_docker | |
env: | |
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Download Litestream Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ env.API_DOCKER_IMAGE }}.tar.gz | |
- name: Load & Tag Litestream Image | |
run: | | |
docker load < ${{ env.API_DOCKER_IMAGE }}.tar.gz | |
docker tag ${{ env.API_DOCKER_IMAGE }} ${{ env.FLY_REGISTRY }}/bencher-api-test | |
- uses: superfly/flyctl-actions/setup-flyctl@master | |
- name: Deploy Litestream API to Fly.io Test | |
working-directory: ./services/api | |
run: flyctl deploy --local-only --config fly/fly.test.toml --wait-timeout 300 | |
- uses: rui314/setup-mold@v1 | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- name: Run Smoke Test | |
run: cargo test-api smoke test | |
backup_database: | |
if: github.ref == 'refs/heads/cloud' | |
name: Backup Database | |
runs-on: ubuntu-latest | |
# This will fail whenever Bencher Cloud is down | |
continue-on-error: true | |
timeout-minutes: 5 | |
needs: | |
# Lint | |
- cargo_fmt | |
- cargo_clippy | |
- npx_biome_format | |
- npx_biome_lint | |
- check_generated | |
# Test | |
- cargo_test | |
- api_smoke_test | |
- cargo_bench | |
- test_bencher_valid_wasm | |
- npx_vitest | |
# Build | |
- build_api_docker | |
- build_console | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/cache@v4 | |
with: | |
path: | | |
~/.cargo/bin/ | |
~/.cargo/registry/index/ | |
~/.cargo/registry/cache/ | |
~/.cargo/git/db/ | |
target/ | |
key: ${{ runner.os }}-cargo-cli | |
- uses: rui314/setup-mold@v1 | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- name: Install `bencher` CLI | |
run: cargo install --debug --path services/cli --locked --force | |
- name: Backup API Server Database | |
run: | | |
bencher server backup \ | |
--host https://api.bencher.dev \ | |
--token ${{ secrets.BENCHER_API_TOKEN_ADMIN }} \ | |
--compress \ | |
--data-store aws_s3 \ | |
--rm | |
deploy_api_fly: | |
name: Deploy API to Fly.io Prod | |
runs-on: ubuntu-latest | |
needs: | |
- deploy_api_fly_test | |
- backup_database | |
env: | |
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Download Litestream Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ env.API_DOCKER_IMAGE }}.tar.gz | |
- name: Load & Tag Litestream Image | |
run: | | |
docker load < ${{ env.API_DOCKER_IMAGE }}.tar.gz | |
docker tag ${{ env.API_DOCKER_IMAGE }} ${{ env.FLY_REGISTRY }}/bencher-api | |
- uses: superfly/flyctl-actions/setup-flyctl@master | |
- name: Deploy API to Fly.io Prod | |
working-directory: ./services/api | |
run: flyctl deploy --local-only --config fly/fly.toml --wait-timeout 300 | |
- name: Rebase main on cloud | |
run: | | |
git fetch origin cloud | |
git checkout cloud | |
git pull | |
git fetch origin main | |
git checkout main | |
git pull | |
git rebase origin/cloud | |
git push | |
# UI Netlify | |
deploy_console_netlify_dev: | |
name: Deploy Console UI to Netlify Dev | |
runs-on: ubuntu-latest | |
needs: deploy_api_fly_dev | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Download `bencher_valid` Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ env.WASM_BENCHER_VALID }} | |
path: ./lib/bencher_valid/pkg | |
- name: Build Console UI | |
working-directory: ./services/console | |
run: npm run netlify | |
- name: Install Netlify CLI | |
run: npm install --save-dev [email protected] | |
- name: Deploy Console UI to Netlify Dev | |
env: | |
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} | |
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} | |
DEPLOY_MESSAGE: "${{ github.event.head_commit.message }}" | |
run: | | |
npx netlify-cli \ | |
deploy \ | |
--alias ${GITHUB_REF#refs/*/} \ | |
--message "$DEPLOY_MESSAGE" \ | |
--json \ | |
| tee netlify.json | |
- uses: rui314/setup-mold@v1 | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- name: Run Netlify Dev Test | |
run: cargo test-netlify dev ${{ github.ref_name }} | |
deploy_console_netlify: | |
name: Deploy Console UI to Netlify Prod | |
runs-on: ubuntu-latest | |
needs: deploy_api_fly | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Download `bencher_valid` Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ env.WASM_BENCHER_VALID }} | |
path: ./lib/bencher_valid/pkg | |
- name: Build Console UI | |
working-directory: ./services/console | |
run: npm run netlify | |
- name: Install Netlify CLI | |
run: npm install --save-dev [email protected] | |
- name: Deploy Console UI to Netlify | |
env: | |
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} | |
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} | |
DEPLOY_MESSAGE: "${{ github.event.head_commit.message }}" | |
run: | | |
npx netlify-cli \ | |
deploy \ | |
--prod \ | |
--alias ${GITHUB_REF#refs/*/} \ | |
--message "$DEPLOY_MESSAGE" \ | |
--json \ | |
| tee netlify.json | |
- uses: rui314/setup-mold@v1 | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- name: Run Netlify Test | |
run: cargo test-netlify prod ${{ github.ref_name }} | |
# Release | |
release_bencher: | |
if: startsWith(github.ref, 'refs/tags/') | |
name: Release Bencher | |
runs-on: ubuntu-latest | |
needs: | |
# Lint | |
- cargo_fmt | |
- cargo_clippy | |
- npx_biome_format | |
- npx_biome_lint | |
- check_generated | |
# Test | |
- cargo_test | |
- api_smoke_test | |
- release_api_smoke_test | |
- cargo_check_api_minus | |
- cargo_check_cli_minus | |
- cargo_bench | |
- cargo_audit | |
- cargo_udeps | |
- test_bencher_valid_wasm | |
- npx_vitest | |
# Integrations | |
- build_github_action | |
# Build | |
- build_api_docker | |
- build_console_docker | |
- package_cli | |
env: | |
BUILD_LINUX_X86_64: linux-x86-64 | |
BUILD_LINUX_ARM_64: linux-arm-64 | |
BUILD_MACOS_X86_64: macos-x86-64 | |
BUILD_MACOS_ARM_64: macos-arm-64 | |
BUILD_WINDOWS_X86_64: windows-x86-64 | |
BUILD_WINDOWS_ARM_64: windows-arm-64 | |
steps: | |
- uses: actions/checkout@v4 | |
# Download Docker | |
- name: Download API Docker Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ env.API_DOCKER_IMAGE }}.tar.gz | |
- name: Download Console Docker Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ env.CONSOLE_DOCKER_IMAGE }}.tar.gz | |
# Download CLI | |
- name: Download CLI Linux x86_64 Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ env.BUILD_LINUX_X86_64 }} | |
- name: Download CLI Linux ARM64 Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ env.BUILD_LINUX_ARM_64 }} | |
- name: Download CLI MacOS x86_64 Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ env.BUILD_MACOS_X86_64 }} | |
- name: Download CLI MacOS ARM64 Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ env.BUILD_MACOS_ARM_64 }} | |
- name: Download CLI Windows x86_64 Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ env.BUILD_WINDOWS_X86_64 }}.exe | |
- name: Download CLI Windows ARM64 Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ env.BUILD_WINDOWS_ARM_64 }}.exe | |
# Download CLI Packages | |
- name: Download CLI Linux x86_64 .deb Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ env.BUILD_LINUX_X86_64 }}.deb | |
- name: Download CLI Linux ARM64 .deb Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ env.BUILD_LINUX_ARM_64 }}.deb | |
# Load | |
- name: Load API Image | |
run: docker load < ${{ env.API_DOCKER_IMAGE }}.tar.gz | |
- name: Load Console Image | |
run: docker load < ${{ env.CONSOLE_DOCKER_IMAGE }}.tar.gz | |
# Login GHCR | |
- name: Log in to the Container registry | |
uses: docker/login-action@v3 | |
with: | |
registry: ${{ env.GITHUB_REGISTRY }} | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
# Tag & Push | |
- name: Tag & Push API Image | |
run: | | |
export GITHUB_IMAGE=${{ env.GITHUB_REGISTRY }}/${{ github.repository_owner }}/${{ env.API_DOCKER_IMAGE }} | |
docker tag ${{ env.API_DOCKER_IMAGE }} ${GITHUB_IMAGE}:latest | |
docker tag ${{ env.API_DOCKER_IMAGE }} ${GITHUB_IMAGE}:${GITHUB_REF#refs/*/} | |
docker push ${GITHUB_IMAGE}:latest | |
docker push ${GITHUB_IMAGE}:${GITHUB_REF#refs/*/} | |
- name: Tag & Push Console Image | |
run: | | |
export GITHUB_IMAGE=${{ env.GITHUB_REGISTRY }}/${{ github.repository_owner }}/${{ env.CONSOLE_DOCKER_IMAGE }} | |
docker tag ${{ env.CONSOLE_DOCKER_IMAGE }} ${GITHUB_IMAGE}:latest | |
docker tag ${{ env.CONSOLE_DOCKER_IMAGE }} ${GITHUB_IMAGE}:${GITHUB_REF#refs/*/} | |
docker push ${GITHUB_IMAGE}:latest | |
docker push ${GITHUB_IMAGE}:${GITHUB_REF#refs/*/} | |
# Mirror to Docker Hub | |
- name: Login to Docker Hub | |
uses: docker/login-action@v3 | |
with: | |
username: ${{ secrets.DOCKER_HUB_USERNAME }} | |
password: ${{ secrets.DOCKER_HUB_TOKEN }} | |
- name: Tag & Push API Image to Docker Hub | |
run: | | |
export DOCKER_HUB_IMAGE=${{ env.DOCKER_HUB_ORGANIZATION }}/${{ env.API_DOCKER_IMAGE }} | |
docker tag ${{ env.API_DOCKER_IMAGE }} ${DOCKER_HUB_IMAGE}:latest | |
docker tag ${{ env.API_DOCKER_IMAGE }} ${DOCKER_HUB_IMAGE}:${GITHUB_REF#refs/*/} | |
docker push ${DOCKER_HUB_IMAGE}:latest | |
docker push ${DOCKER_HUB_IMAGE}:${GITHUB_REF#refs/*/} | |
- name: Tag & Push Console Image to Docker Hub | |
run: | | |
export DOCKER_HUB_IMAGE=${{ env.DOCKER_HUB_ORGANIZATION }}/${{ env.CONSOLE_DOCKER_IMAGE }} | |
docker tag ${{ env.CONSOLE_DOCKER_IMAGE }} ${DOCKER_HUB_IMAGE}:latest | |
docker tag ${{ env.CONSOLE_DOCKER_IMAGE }} ${DOCKER_HUB_IMAGE}:${GITHUB_REF#refs/*/} | |
docker push ${DOCKER_HUB_IMAGE}:latest | |
docker push ${DOCKER_HUB_IMAGE}:${GITHUB_REF#refs/*/} | |
- uses: rui314/setup-mold@v1 | |
with: | |
mold-version: ${{ env.MOLD_VERSION }} | |
- name: Generate Release Notes | |
run: cargo gen-notes | |
- name: GitHub Release | |
uses: softprops/action-gh-release@v2 | |
with: | |
prerelease: ${{ endsWith(github.ref, '-rc*') }} | |
body_path: release-notes.md | |
files: | | |
${{ env.API_DOCKER_IMAGE }}.tar.gz | |
${{ env.CONSOLE_DOCKER_IMAGE }}.tar.gz | |
${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ env.BUILD_LINUX_X86_64 }} | |
${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ env.BUILD_LINUX_ARM_64 }} | |
${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ env.BUILD_MACOS_X86_64 }} | |
${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ env.BUILD_MACOS_ARM_64 }} | |
${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ env.BUILD_WINDOWS_X86_64 }}.exe | |
${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ env.BUILD_WINDOWS_ARM_64 }}.exe | |
${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ env.BUILD_LINUX_X86_64 }}.deb | |
${{ env.CLI_BIN_NAME }}-${{ github.ref_name }}-${{ env.BUILD_LINUX_ARM_64 }}.deb | |
# Dev Container | |
build_dev_container: | |
if: github.ref == 'refs/heads/devel' | |
name: Build dev container | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Set up QEMU | |
uses: docker/setup-qemu-action@v3 | |
- name: Setup Docker buildx | |
uses: docker/setup-buildx-action@v3 | |
- name: Log in to the Container registry | |
uses: docker/login-action@v3 | |
with: | |
registry: ${{ env.GITHUB_REGISTRY }} | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Pre-build dev container image | |
uses: devcontainers/[email protected] | |
with: | |
imageName: ${{ env.GITHUB_REGISTRY }}/${{ github.repository_owner }}/${{ env.DEV_CONTAINER_DOCKER_IMAGE }} | |
cacheFrom: ${{ env.GITHUB_REGISTRY }}/${{ github.repository_owner }}/${{ env.DEV_CONTAINER_DOCKER_IMAGE }} | |
push: always |