name: Build permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true on: push: paths: - ".github/workflows/build.yml" - "src/**" - "migrations/**" - "Cargo.*" - "build.rs" - "rust-toolchain.toml" - "rustfmt.toml" - "diesel.toml" - "docker/Dockerfile.j2" - "docker/DockerSettings.yaml" - "macros/**" pull_request: paths: - ".github/workflows/build.yml" - "src/**" - "migrations/**" - "Cargo.*" - "build.rs" - "rust-toolchain.toml" - "rustfmt.toml" - "diesel.toml" - "docker/Dockerfile.j2" - "docker/DockerSettings.yaml" - "macros/**" defaults: run: shell: bash jobs: build: name: Build and Test ${{ matrix.channel }} runs-on: ubuntu-24.04 timeout-minutes: 120 # Make warnings errors, this is to prevent warnings slipping through. # This is done globally to prevent rebuilds when the RUSTFLAGS env variable changes. env: RUSTFLAGS: "-Dwarnings" strategy: fail-fast: false matrix: channel: - "rust-toolchain" # The version defined in rust-toolchain - "msrv" # The supported MSRV steps: # Install dependencies - name: "Install dependencies Ubuntu" run: | # Separate commands, so a failing update fails the step. The image already has Oracle's MySQL client # library, so a skipped install would otherwise go unnoticed and build against that one. sudo apt-get update sudo apt-get install -y --no-install-recommends openssl build-essential libmariadb-dev-compat libpq-dev libssl-dev pkg-config # Pass the MariaDB client library to mysqlclient-sys through its environment variables. # When it finds the library with pkg-config, its build script makes cargo rerun it whenever # anything in the library directory changes, and the install above changes that directory on # every run. So every MySQL build recompiled mysqlclient-sys, diesel and diesel_migrations, # even with a cached build. Cargo compares environment variables by their value instead. lib_dir="$(pkg-config --variable=libdir mysqlclient)" version="$(pkg-config --modversion mysqlclient)" { echo "MYSQLCLIENT_NO_PKG_CONFIG=1" echo "LIBMARIADB_NO_PKG_CONFIG=1" echo "MYSQLCLIENT_LIB_DIR=${lib_dir}" echo "MYSQLCLIENT_VERSION=${version}" } | tee -a "${GITHUB_ENV}" # End Install dependencies # Checkout the repo - name: "Checkout" uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false fetch-depth: 0 # End Checkout the repo # Determine rust-toolchain version - name: Init Variables id: toolchain env: CHANNEL: ${{ matrix.channel }} run: | if [[ "${CHANNEL}" == 'rust-toolchain' ]]; then RUST_TOOLCHAIN="$(grep -m1 -oP 'channel.*"(\K.*?)(?=")' rust-toolchain.toml)" elif [[ "${CHANNEL}" == 'msrv' ]]; then RUST_TOOLCHAIN="$(grep -m1 -oP 'rust-version\s.*"(\K.*?)(?=")' Cargo.toml)" else RUST_TOOLCHAIN="${CHANNEL}" fi echo "RUST_TOOLCHAIN=${RUST_TOOLCHAIN}" | tee -a "${GITHUB_OUTPUT}" # End Determine rust-toolchain version - name: "Install toolchain ${{steps.toolchain.outputs.RUST_TOOLCHAIN}} as default" env: CHANNEL: ${{ matrix.channel }} RUST_TOOLCHAIN: ${{steps.toolchain.outputs.RUST_TOOLCHAIN}} run: | # Remove the rust-toolchain.toml rm rust-toolchain.toml # Install the correct toolchain version rustup toolchain install "${RUST_TOOLCHAIN}" --profile minimal --no-self-update # If this matrix is the `rust-toolchain` flow, also install rustfmt and clippy if [[ "${CHANNEL}" == 'rust-toolchain' ]]; then rustup component add --toolchain "${RUST_TOOLCHAIN}" rustfmt clippy fi # Set as the default toolchain rustup default "${RUST_TOOLCHAIN}" # Show environment - name: "Show environment" run: | rustc -vV cargo -vV # End Show environment # Enable Rust Caching - name: Rust Caching uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 with: # Use a custom prefix-key to force a fresh start. This is sometimes needed with bigger changes. # Like changing the build host from Ubuntu 20.04 to 22.04 for example. # Only update when really needed! Use a .[.] format. prefix-key: "v2026.11-rust" # Only main saves caches. The repository can keep 10 GB of caches, and the ones saved by pull # requests and other branches were mostly copies of main's that pushed other caches out. save-if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/ci/build-speed' }} # End Enable Rust Caching # Run cargo tests # First test all features together, afterwards test them separately. # enable_mimalloc only selects the allocator, so it is tested on and off, not with every combination. - name: "test features: sqlite,mysql,postgresql,enable_mimalloc,s3" id: test_sqlite_mysql_postgresql_mimalloc_s3 if: ${{ !cancelled() }} run: | cargo test --profile ci --features sqlite,mysql,postgresql,enable_mimalloc,s3 - name: "test features: sqlite,mysql,postgresql" id: test_sqlite_mysql_postgresql if: ${{ !cancelled() }} run: | cargo test --profile ci --features sqlite,mysql,postgresql - name: "test features: sqlite" id: test_sqlite if: ${{ !cancelled() }} run: | cargo test --profile ci --features sqlite - name: "test features: mysql" id: test_mysql if: ${{ !cancelled() }} run: | cargo test --profile ci --features mysql - name: "test features: postgresql" id: test_postgresql if: ${{ !cancelled() }} run: | cargo test --profile ci --features postgresql # The test seeder only exists with this feature, which no release build has - name: "test features: sqlite,unsafe_test_mode" id: test_unsafe_test_mode if: ${{ !cancelled() }} run: | cargo test --profile ci --features sqlite,unsafe_test_mode # End Run cargo tests # Run cargo clippy, and fail on warnings - name: "clippy features: sqlite,mysql,postgresql,enable_mimalloc,s3" id: clippy if: ${{ !cancelled() && matrix.channel == 'rust-toolchain' }} run: | cargo clippy --profile ci --features sqlite,mysql,postgresql,enable_mimalloc,s3 - name: "clippy features: sqlite,unsafe_test_mode" id: clippy_unsafe_test_mode if: ${{ !cancelled() && matrix.channel == 'rust-toolchain' }} run: | cargo clippy --profile ci --features sqlite,unsafe_test_mode # End Run cargo clippy # Run cargo fmt (Only run on rust-toolchain defined version) - name: "check formatting" id: formatting if: ${{ !cancelled() && matrix.channel == 'rust-toolchain' }} run: | cargo fmt --all -- --check # End Run cargo fmt # Check for any previous failures, if there are stop, else continue. # This is useful so all test/clippy/fmt actions are done, and they can all be addressed - name: "Some checks failed" if: ${{ failure() }} env: TEST_DB_M_S3: ${{ steps.test_sqlite_mysql_postgresql_mimalloc_s3.outcome }} TEST_DB: ${{ steps.test_sqlite_mysql_postgresql.outcome }} TEST_SQLITE: ${{ steps.test_sqlite.outcome }} TEST_MYSQL: ${{ steps.test_mysql.outcome }} TEST_POSTGRESQL: ${{ steps.test_postgresql.outcome }} TEST_UNSAFE_TEST_MODE: ${{ steps.test_unsafe_test_mode.outcome }} CLIPPY: ${{ steps.clippy.outcome }} CLIPPY_UNSAFE_TEST_MODE: ${{ steps.clippy_unsafe_test_mode.outcome }} FMT: ${{ steps.formatting.outcome }} run: | echo "### :x: Checks Failed!" >> "${GITHUB_STEP_SUMMARY}" echo "" >> "${GITHUB_STEP_SUMMARY}" echo "|Job|Status|" >> "${GITHUB_STEP_SUMMARY}" echo "|---|------|" >> "${GITHUB_STEP_SUMMARY}" echo "|test (sqlite,mysql,postgresql,enable_mimalloc,s3)|${TEST_DB_M_S3}|" >> "${GITHUB_STEP_SUMMARY}" echo "|test (sqlite,mysql,postgresql)|${TEST_DB}|" >> "${GITHUB_STEP_SUMMARY}" echo "|test (sqlite)|${TEST_SQLITE}|" >> "${GITHUB_STEP_SUMMARY}" echo "|test (mysql)|${TEST_MYSQL}|" >> "${GITHUB_STEP_SUMMARY}" echo "|test (postgresql)|${TEST_POSTGRESQL}|" >> "${GITHUB_STEP_SUMMARY}" echo "|test (sqlite,unsafe_test_mode)|${TEST_UNSAFE_TEST_MODE}|" >> "${GITHUB_STEP_SUMMARY}" echo "|clippy (sqlite,mysql,postgresql,enable_mimalloc,s3)|${CLIPPY}|" >> "${GITHUB_STEP_SUMMARY}" echo "|clippy (sqlite,unsafe_test_mode)|${CLIPPY_UNSAFE_TEST_MODE}|" >> "${GITHUB_STEP_SUMMARY}" echo "|fmt|${FMT}|" >> "${GITHUB_STEP_SUMMARY}" echo "" >> "${GITHUB_STEP_SUMMARY}" echo "Please check the failed jobs and fix where needed." >> "${GITHUB_STEP_SUMMARY}" echo "" >> "${GITHUB_STEP_SUMMARY}" exit 1 # Check for any previous failures, if there are stop, else continue. # This is useful so all test/clippy/fmt actions are done, and they can all be addressed - name: "All checks passed" if: ${{ success() }} run: | echo "### :tada: Checks Passed!" >> "${GITHUB_STEP_SUMMARY}" echo "" >> "${GITHUB_STEP_SUMMARY}"