diff --git a/.github/actions/setup-self-hosted/action.yml b/.github/actions/setup-self-hosted/action.yml new file mode 100644 index 0000000..543bd13 --- /dev/null +++ b/.github/actions/setup-self-hosted/action.yml @@ -0,0 +1,144 @@ +name: Setup self-hosted Linux runner +description: >- + Install host tools that GitHub-hosted Ubuntu images include and the org + sm-standard runner images do not. Rust still invokes the system linker, and + aws-lc-sys (pulled in by the AWS SDK) builds with CMake. Docker is not + installed here: jobs that need a daemon use the dind-sm-standard-2 label. + +inputs: + profile: + description: >- + Space-separated profiles: rust-build, python, openssl, curl, file, + archive-tools, github-cli, awscli. + required: true + +runs: + using: composite + steps: + - name: Install host tools + shell: bash + env: + PROFILE: ${{ inputs.profile }} + run: | + set -euo pipefail + + if ! command -v sudo >/dev/null 2>&1; then + echo "sudo is required to install host packages on the self-hosted runner" >&2 + exit 1 + fi + + if [[ -z "${PROFILE// /}" ]]; then + echo "setup-self-hosted requires a profile" >&2 + exit 1 + fi + + has() { + [[ " ${PROFILE} " == *" $1 "* ]] + } + + for token in ${PROFILE}; do + case "${token}" in + rust-build|python|openssl|curl|file|archive-tools|github-cli|awscli) ;; + *) + echo "Unknown setup profile: ${token}" >&2 + exit 1 + ;; + esac + done + + packages=() + add_pkg() { + local pkg="$1" + local existing + if ((${#packages[@]} > 0)); then + for existing in "${packages[@]}"; do + if [[ "${existing}" == "${pkg}" ]]; then + return + fi + done + fi + packages+=("${pkg}") + } + + # curl and CA certificates are how rustup and the GitHub CLI apt repo + # are fetched. GitHub-hosted images already have both. + if has rust-build || has curl || has github-cli; then + add_pkg ca-certificates + add_pkg curl + fi + + # sm-standard images ship no C toolchain. rustc needs cc, and + # aws-lc-sys builds its C library with CMake. libssl-dev matches the + # org's other self-hosted lanes (git2/openssl build scripts). + if has rust-build; then + add_pkg build-essential + add_pkg cmake + add_pkg pkg-config + add_pkg libssl-dev + add_pkg perl + add_pkg git + fi + + if has python; then + add_pkg python3 + fi + + if has openssl; then + add_pkg openssl + fi + + # `file` is preinstalled on GitHub-hosted Ubuntu and is how the + # package job checks that release binaries are statically linked. + if has file; then + add_pkg file + fi + + # Release archives are checksummed with shasum, which GitHub-hosted + # images provide via Perl. coreutils sha256sum is not a drop-in: the + # existing release script calls shasum. + if has archive-tools; then + add_pkg libdigest-sha-perl + fi + + # Official AWS CLI v2, matching GitHub-hosted images. The Ubuntu awscli + # apt package is v1 and ignores AWS_REQUEST_CHECKSUM_CALCULATION, which + # the R2 upload steps set for CLI v2.23+. + if has awscli && ! command -v aws >/dev/null 2>&1; then + add_pkg ca-certificates + add_pkg curl + add_pkg unzip + fi + + if ((${#packages[@]} > 0)); then + sudo DEBIAN_FRONTEND=noninteractive apt-get update + sudo DEBIAN_FRONTEND=noninteractive apt-get install -y "${packages[@]}" + fi + + if has awscli && ! command -v aws >/dev/null 2>&1; then + case "$(dpkg --print-architecture)" in + amd64) aws_url="https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" ;; + arm64) aws_url="https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip" ;; + *) + echo "No AWS CLI v2 build for $(dpkg --print-architecture)" >&2 + exit 1 + ;; + esac + aws_tmp="$(mktemp -d)" + curl -fsSL "${aws_url}" -o "${aws_tmp}/awscliv2.zip" + unzip -q "${aws_tmp}/awscliv2.zip" -d "${aws_tmp}" + sudo "${aws_tmp}/aws/install" + rm -rf "${aws_tmp}" + fi + + if has github-cli && ! command -v gh >/dev/null 2>&1; then + # Ubuntu's own gh package is not always present on the minimal + # runner image. Use the upstream GitHub CLI apt repository. + sudo mkdir -p -m 755 /etc/apt/keyrings + curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \ + | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg >/dev/null + sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \ + | sudo tee /etc/apt/sources.list.d/github-cli.list >/dev/null + sudo DEBIAN_FRONTEND=noninteractive apt-get update + sudo DEBIAN_FRONTEND=noninteractive apt-get install -y gh + fi diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cafd2b6..da8e929 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,22 +1,43 @@ name: CI +# Linux jobs run on the org's self-hosted runners (sm-standard-2 / sm-standard-4). +# cargo-deny-action is a container action, so Dependency Advisories uses the +# Docker-capable dind-sm-standard-2 label. +# +# The org has no self-hosted macOS or Windows runners. Those lanes execute +# `cargo test` / `cargo build` on the host OS; cross-compiling them on Linux +# would not run the tests and would not exercise the same linker. They stay on +# GitHub-hosted runners and are limited to workflow_dispatch. + on: push: branches: [ main, develop ] pull_request: branches: [ main, develop ] + workflow_dispatch: env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 + # Self-hosted runner images may still bundle an older Node than current + # JavaScript actions require. + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" permissions: contents: read +# Cancel superseded PR runs. Push, schedule, and manual dispatch are left +# running so a new commit on a PR cannot abort a main or release-related run. +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: advisories: name: Dependency Advisories - runs-on: ubuntu-latest + # Container action: the runner must have a Docker daemon. sm-standard-* does not. + runs-on: dind-sm-standard-2 + timeout-minutes: 20 steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 - uses: EmbarkStudios/cargo-deny-action@bb137d7af7e4fb67e5f82a49c4fce4fad40782fe # v2 @@ -25,9 +46,15 @@ jobs: fmt: name: Format Check - runs-on: ubuntu-latest + runs-on: sm-standard-2 + timeout-minutes: 20 steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + - name: Install host tools + uses: ./.github/actions/setup-self-hosted + with: + # rustup is fetched with curl. cargo fmt does not link. + profile: curl - uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable with: components: rustfmt @@ -36,9 +63,14 @@ jobs: clippy: name: Clippy - runs-on: ubuntu-latest + runs-on: sm-standard-4 + timeout-minutes: 60 steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + - name: Install host tools + uses: ./.github/actions/setup-self-hosted + with: + profile: rust-build - uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable with: components: clippy @@ -47,14 +79,37 @@ jobs: run: cargo clippy --workspace --all-targets -- -D warnings test: - name: Test (${{ matrix.os }}) - runs-on: ${{ matrix.os }} + name: Test (${{ matrix.name }}) + runs-on: ${{ matrix.runner }} + timeout-minutes: 60 + # manual_only lanes are GitHub-hosted and must not run on push or pull_request. + # Compared as a string: a boolean false in a matrix is easy to misread as the + # truthy string "false" once it crosses an expression boundary. + if: ${{ matrix.manual_only != 'yes' || github.event_name == 'workflow_dispatch' }} strategy: fail-fast: false matrix: - os: [ ubuntu-latest, macos-latest, windows-latest ] + include: + - name: linux + runner: sm-standard-4 + manual_only: "no" + - name: macos-latest, manual + runner: macos-latest + manual_only: "yes" + - name: windows-latest, manual + runner: windows-latest + manual_only: "yes" steps: + - name: Flag billed GitHub-hosted runner + if: matrix.manual_only == 'yes' + shell: bash + run: echo "::warning title=GitHub-hosted runner::Manual dispatch only. This job uses billed ${{ matrix.runner }} because the org has no self-hosted macOS or Windows runners. It does not run on push, pull_request, or schedule." - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + - name: Install host tools + if: runner.os == 'Linux' + uses: ./.github/actions/setup-self-hosted + with: + profile: rust-build - uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 - name: Run tests @@ -63,14 +118,34 @@ jobs: run: cargo test --workspace build: - name: Build (${{ matrix.os }}) - runs-on: ${{ matrix.os }} + name: Build (${{ matrix.name }}) + runs-on: ${{ matrix.runner }} + timeout-minutes: 90 + if: ${{ matrix.manual_only != 'yes' || github.event_name == 'workflow_dispatch' }} strategy: fail-fast: false matrix: - os: [ ubuntu-latest, macos-latest, windows-latest ] + include: + - name: linux + runner: sm-standard-4 + manual_only: "no" + - name: macos-latest, manual + runner: macos-latest + manual_only: "yes" + - name: windows-latest, manual + runner: windows-latest + manual_only: "yes" steps: + - name: Flag billed GitHub-hosted runner + if: matrix.manual_only == 'yes' + shell: bash + run: echo "::warning title=GitHub-hosted runner::Manual dispatch only. This job uses billed ${{ matrix.runner }} because the org has no self-hosted macOS or Windows runners. It does not run on push, pull_request, or schedule." - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + - name: Install host tools + if: runner.os == 'Linux' + uses: ./.github/actions/setup-self-hosted + with: + profile: rust-build - uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 - name: Build @@ -78,9 +153,14 @@ jobs: doc: name: Documentation - runs-on: ubuntu-latest + runs-on: sm-standard-4 + timeout-minutes: 40 steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + - name: Install host tools + uses: ./.github/actions/setup-self-hosted + with: + profile: rust-build - uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 - name: Build documentation @@ -91,7 +171,8 @@ jobs: # Ensure protected files are not modified without proper process protected-files: name: Protected Files Check - runs-on: ubuntu-latest + runs-on: sm-standard-2 + timeout-minutes: 10 if: github.event_name == 'pull_request' steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 @@ -104,9 +185,14 @@ jobs: msrv: name: Minimum Supported Rust Version - runs-on: ubuntu-latest + runs-on: sm-standard-4 + timeout-minutes: 60 steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + - name: Install host tools + uses: ./.github/actions/setup-self-hosted + with: + profile: rust-build - uses: dtolnay/rust-toolchain@fa04a1451ff1842e2626ccb99004d0195b455a88 # master with: toolchain: "1.92" diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 89a9134..e4f003d 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -14,10 +14,20 @@ on: permissions: contents: read +# workflow_run is an automatic trigger, so this job cannot use a GitHub-hosted +# runner. Image builds need a Docker daemon, which only the dind label provides. +concurrency: + group: ${{ github.workflow }}-${{ github.event.workflow_run.head_sha || github.sha }} + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" + jobs: build-and-push: if: github.event_name == 'workflow_dispatch' || (github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push') - runs-on: ubuntu-latest + runs-on: dind-sm-standard-2 + timeout-minutes: 60 steps: - name: Checkout code diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 8bd0d73..fd79536 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -15,17 +15,30 @@ env: TEST_S3_ENDPOINT: http://localhost:9000 TEST_S3_ACCESS_KEY: accesskey TEST_S3_SECRET_KEY: secretkey + # Self-hosted runner images may still bundle an older Node than current + # JavaScript actions require. + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" permissions: contents: read +# Cancel superseded PR runs. The nightly schedule uses its own group so a PR +# push cannot abort it. +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: cli-contract: name: CLI Contract (Commands and Options) - runs-on: ubuntu-latest - timeout-minutes: 20 + runs-on: sm-standard-4 + timeout-minutes: 30 steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + - name: Install host tools + uses: ./.github/actions/setup-self-hosted + with: + profile: rust-build python - uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 @@ -39,8 +52,9 @@ jobs: smoke-compatibility: name: Smoke (RustFS ${{ matrix.version }}) - runs-on: ubuntu-latest - timeout-minutes: 30 + # Docker is required to run the RustFS image. Only dind-* runners provide it. + runs-on: dind-sm-standard-2 + timeout-minutes: 45 strategy: fail-fast: false matrix: @@ -51,6 +65,11 @@ jobs: image: rustfs/rustfs:1.0.0-beta.10 steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + - name: Install host tools + uses: ./.github/actions/setup-self-hosted + with: + # curl --aws-sigv4 and openssl are preinstalled on GitHub-hosted Ubuntu. + profile: rust-build python openssl - uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 @@ -196,11 +215,16 @@ jobs: full-target: name: Full Integration (RustFS 1.0.0-beta.10) - runs-on: ubuntu-latest - timeout-minutes: 90 + # Docker is required to run the RustFS image. Only dind-* runners provide it. + runs-on: dind-sm-standard-2 + timeout-minutes: 120 if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + - name: Install host tools + uses: ./.github/actions/setup-self-hosted + with: + profile: rust-build - uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 @@ -253,10 +277,14 @@ jobs: golden: name: Golden Tests - runs-on: ubuntu-latest - timeout-minutes: 20 + runs-on: sm-standard-4 + timeout-minutes: 30 steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + - name: Install host tools + uses: ./.github/actions/setup-self-hosted + with: + profile: rust-build - uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index a362844..c279cd8 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -34,6 +34,11 @@ permissions: contents: write actions: read +env: + # Self-hosted runner images may still bundle an older Node than current + # JavaScript actions require. + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" + concurrency: group: package-${{ inputs.tag || github.run_id }} cancel-in-progress: true @@ -41,7 +46,7 @@ concurrency: jobs: resolve: name: Resolve Build - runs-on: ubuntu-latest + runs-on: sm-standard-2 timeout-minutes: 10 permissions: contents: read @@ -53,6 +58,11 @@ jobs: tag: ${{ steps.resolve.outputs.tag }} head_sha: ${{ steps.resolve.outputs.head_sha }} steps: + - name: Install GitHub CLI + uses: ./.github/actions/setup-self-hosted + with: + # gh is preinstalled on GitHub-hosted runners and missing on sm-standard images. + profile: github-cli - name: Resolve and validate build run id: resolve env: @@ -169,7 +179,7 @@ jobs: package: name: Package (${{ matrix.arch }}) needs: resolve - runs-on: ubuntu-latest + runs-on: sm-standard-2 timeout-minutes: 30 permissions: contents: read @@ -185,6 +195,11 @@ jobs: rpm_arch: aarch64 artifact_name: rustfs-cli-linux-arm64 steps: + - name: Install file(1) + uses: ./.github/actions/setup-self-hosted + with: + # Used to prove the packaged binary is statically linked. + profile: file - name: Checkout exact build source uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: @@ -363,12 +378,16 @@ jobs: name: Publish packages to GitHub Release needs: [resolve, package] if: needs.resolve.result == 'success' && needs.package.result == 'success' - runs-on: ubuntu-latest + runs-on: sm-standard-2 timeout-minutes: 15 permissions: contents: write actions: read steps: + - name: Install GitHub CLI + uses: ./.github/actions/setup-self-hosted + with: + profile: github-cli - name: Download package artifacts uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 with: @@ -445,11 +464,15 @@ jobs: needs: [resolve, package] if: needs.resolve.result == 'success' && needs.package.result == 'success' continue-on-error: true - runs-on: ubuntu-latest + runs-on: sm-standard-2 timeout-minutes: 15 permissions: actions: read steps: + - name: Install AWS CLI + uses: ./.github/actions/setup-self-hosted + with: + profile: awscli - name: Download package artifacts uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 with: @@ -512,7 +535,7 @@ jobs: name: Summary needs: [resolve, package, publish-github, publish-r2] if: always() - runs-on: ubuntu-latest + runs-on: sm-standard-2 timeout-minutes: 5 permissions: contents: read diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 43747f2..f87497c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,15 +13,24 @@ on: env: CARGO_TERM_COLOR: always + # Self-hosted runner images may still bundle an older Node than current + # JavaScript actions require. + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" permissions: contents: read +# Do not cancel an in-progress release. A second run for the same ref waits. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + jobs: # Build strategy check - determine build type and version build-check: name: Build Strategy Check - runs-on: ubuntu-latest + runs-on: sm-standard-2 + timeout-minutes: 15 permissions: contents: read outputs: @@ -106,12 +115,17 @@ jobs: verify: name: Release Verification needs: build-check - runs-on: ubuntu-latest + runs-on: sm-standard-4 + timeout-minutes: 90 steps: - name: Checkout repository uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: ref: ${{ needs.build-check.outputs.source_ref }} + - name: Install host tools + uses: ./.github/actions/setup-self-hosted + with: + profile: rust-build - name: Setup Rust uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable with: @@ -124,76 +138,90 @@ jobs: run: cargo clippy --workspace --all-targets --locked -- -D warnings - name: Run tests run: cargo test --workspace --locked + + # cargo-deny-action is a container action. Kept as its own job so the + # compile/test lane can stay on sm-standard-4, which has no Docker daemon. + release-advisories: + name: Release Advisories + needs: build-check + runs-on: dind-sm-standard-2 + timeout-minutes: 20 + steps: + - name: Checkout repository + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + with: + ref: ${{ needs.build-check.outputs.source_ref }} - name: Check dependency advisories uses: EmbarkStudios/cargo-deny-action@bb137d7af7e4fb67e5f82a49c4fce4fad40782fe # v2 with: command: check advisories + # macOS and Windows release binaries are not cross-compiled. apple-darwin + # needs the Apple SDK, and the published Windows artifact is + # x86_64-pc-windows-msvc (the MSVC linker), which the Linux images do not + # have. A gnu or zig cross build would ship a different binary. Those + # targets are included only for workflow_dispatch, on GitHub-hosted runners. + prepare-build-matrix: + name: Select Build Targets + runs-on: sm-standard-2 + timeout-minutes: 10 + outputs: + matrix: ${{ steps.select.outputs.matrix }} + steps: + - name: Select targets + id: select + shell: bash + env: + EVENT_NAME: ${{ github.event_name }} + run: | + set -euo pipefail + + linux='{"os":"sm-standard-4","target":"x86_64-unknown-linux-gnu","os_name":"linux","arch":"amd64-gnu","artifact_name":"rc","cross":false,"manual_hosted":false},{"os":"dind-sm-standard-2","target":"aarch64-unknown-linux-gnu","os_name":"linux","arch":"arm64-gnu","artifact_name":"rc","cross":true,"manual_hosted":false},{"os":"sm-standard-4","target":"x86_64-unknown-linux-musl","os_name":"linux","arch":"amd64","artifact_name":"rc","cross":false,"manual_hosted":false},{"os":"dind-sm-standard-2","target":"aarch64-unknown-linux-musl","os_name":"linux","arch":"arm64","artifact_name":"rc","cross":true,"manual_hosted":false}' + + hosted='{"os":"macos-latest","target":"x86_64-apple-darwin","os_name":"macos","arch":"amd64","artifact_name":"rc","cross":false,"manual_hosted":true},{"os":"macos-latest","target":"aarch64-apple-darwin","os_name":"macos","arch":"arm64","artifact_name":"rc","cross":false,"manual_hosted":true},{"os":"windows-latest","target":"x86_64-pc-windows-msvc","os_name":"windows","arch":"amd64","artifact_name":"rc.exe","cross":false,"manual_hosted":true}' + + if [[ "${EVENT_NAME}" == "workflow_dispatch" ]]; then + include="${linux},${hosted}" + echo "Including billed GitHub-hosted macOS and Windows targets because this run was dispatched manually." + else + include="${linux}" + echo "Automatic run: Linux self-hosted targets only. macOS and Windows stay on workflow_dispatch." + fi + + { + echo "matrix<> "$GITHUB_OUTPUT" + build: name: Build (${{ matrix.os_name }}-${{ matrix.arch }}) - needs: [build-check, verify] + needs: [build-check, verify, release-advisories, prepare-build-matrix] runs-on: ${{ matrix.os }} + timeout-minutes: 120 permissions: contents: read strategy: fail-fast: false - matrix: - include: - # Linux - - os: ubuntu-latest - target: x86_64-unknown-linux-gnu - os_name: linux - arch: amd64-gnu - artifact_name: rc - cross: false - - - os: ubuntu-latest - target: aarch64-unknown-linux-gnu - os_name: linux - arch: arm64-gnu - artifact_name: rc - cross: true - - - os: ubuntu-latest - target: x86_64-unknown-linux-musl - os_name: linux - arch: amd64 - artifact_name: rc - cross: false - - - os: ubuntu-latest - target: aarch64-unknown-linux-musl - os_name: linux - arch: arm64 - artifact_name: rc - cross: true - - # macOS (both targets built on ARM64 runner with cross-compilation) - - os: macos-latest - target: x86_64-apple-darwin - os_name: macos - arch: amd64 - artifact_name: rc - - - os: macos-latest - target: aarch64-apple-darwin - os_name: macos - arch: arm64 - artifact_name: rc - - # Windows - - os: windows-latest - target: x86_64-pc-windows-msvc - os_name: windows - arch: amd64 - artifact_name: rc.exe - + matrix: ${{ fromJson(needs.prepare-build-matrix.outputs.matrix) }} steps: + - name: Flag billed GitHub-hosted runner + if: matrix.manual_hosted == true + shell: bash + run: echo "::warning title=GitHub-hosted runner::Manual dispatch only. This ${{ matrix.os_name }} target uses billed ${{ matrix.os }} because the org has no self-hosted macOS or Windows runners. Tag pushes do not build it." + - name: Checkout repository uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: ref: ${{ needs.build-check.outputs.source_ref }} + - name: Install host tools + if: runner.os == 'Linux' + uses: ./.github/actions/setup-self-hosted + with: + # shasum is used when packaging Unix release archives. + profile: rust-build archive-tools + - name: Setup Rust uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable with: @@ -292,6 +320,14 @@ jobs: path: artifacts/* if-no-files-found: error + # GitHub-hosted images ship AWS CLI v2. The apt awscli package is v1 and + # does not honor the checksum settings these uploads rely on. + - name: Install AWS CLI + if: needs.build-check.outputs.is_release == 'true' && runner.os == 'Linux' + uses: ./.github/actions/setup-self-hosted + with: + profile: awscli + # Upload to Cloudflare R2 - name: Upload to Cloudflare R2 if: needs.build-check.outputs.is_release == 'true' @@ -334,14 +370,20 @@ jobs: # Generate shell completions completions: name: Generate Shell Completions - needs: [build-check, verify] - runs-on: ubuntu-latest + needs: [build-check, verify, release-advisories] + runs-on: sm-standard-4 + timeout-minutes: 60 steps: - name: Checkout repository uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: ref: ${{ needs.build-check.outputs.source_ref }} + - name: Install host tools + uses: ./.github/actions/setup-self-hosted + with: + profile: rust-build + - name: Setup Rust uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable @@ -370,12 +412,17 @@ jobs: # Upload release assets to GitHub Release upload-release-assets: name: Upload Release Assets - needs: [ build-check, build, completions ] - runs-on: ubuntu-latest + needs: [ build-check, verify, release-advisories, build, completions ] + runs-on: sm-standard-2 + timeout-minutes: 20 if: needs.build-check.outputs.is_release == 'true' permissions: contents: write steps: + - name: Install AWS CLI + uses: ./.github/actions/setup-self-hosted + with: + profile: awscli - name: Download all artifacts uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 with: @@ -481,6 +528,7 @@ jobs: package-deb-rpm: name: Package DEB/RPM needs: [build-check, upload-release-assets] + timeout-minutes: 90 if: needs.build-check.outputs.is_release == 'true' uses: ./.github/workflows/package.yml with: @@ -495,8 +543,9 @@ jobs: # Publish to crates.io publish-crates: name: Publish to crates.io - needs: [build-check, verify, build] - runs-on: ubuntu-latest + needs: [build-check, verify, release-advisories, build] + runs-on: sm-standard-4 + timeout-minutes: 90 if: needs.build-check.outputs.is_release == 'true' && needs.build-check.outputs.has_token == 'true' env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} @@ -506,6 +555,11 @@ jobs: with: ref: ${{ needs.build-check.outputs.source_ref }} + - name: Install host tools + uses: ./.github/actions/setup-self-hosted + with: + profile: rust-build + - name: Setup Rust uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable