diff --git a/.github/workflows/ci-check-app.yml b/.github/workflows/ci-check-app.yml index e247418..4356600 100644 --- a/.github/workflows/ci-check-app.yml +++ b/.github/workflows/ci-check-app.yml @@ -36,9 +36,23 @@ on: type: boolean default: true use-sccache: - description: 'Run sccache-cache before running tests' + # DEPRECATED / no-op: sccache had no persistent backend configured here + # (its object store was never cached), so it provided no cross-run + # benefit and disabled incremental compilation, which fights the + # Swatinem/rust-cache target/ cache. The input is kept so existing + # callers (and ci.yml) don't break; it no longer wires anything. + description: '(deprecated, no-op) Run sccache-cache before running tests' type: boolean default: true + use-mold: + # Opt-in (default false): mold is a linker, so it only helps jobs that + # link a binary — i.e. tests / tests-suites, not clippy (check-only) or + # fmt (no compile). Keep this OFF for `cargo test --release` / LTO test + # builds: mold can't read ThinLTO bitcode objects without the LLVM + # plugin and the final link fails. + description: 'Use the mold linker (clang driver) for the test jobs. Only for non-LTO debug test builds.' + type: boolean + default: false use-postgresql: description: 'Run postgresql before running tests' type: boolean @@ -83,22 +97,12 @@ jobs: toolchain: ${{ inputs.rust-toolchain }} components: clippy - - name: Restore Cargo cache - id: cache-restore - uses: actions/cache/restore@v4 + - name: Rust cache + uses: Swatinem/rust-cache@23869a5bd66c73db3c0ac40331f3206eb23791dc # v2.9.1 with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/ - ~/.cargo/git/ - target/ - key: ${{ inputs.rust-cache-prefix }}-${{ runner.os }}-cargo-clippy-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ inputs.rust-cache-prefix }}-${{ runner.os }}-cargo-clippy- - - - name: Clean target if Cargo.lock changed - if: steps.cache-restore.outputs.cache-hit != 'true' - run: rm -rf target/ + prefix-key: ${{ inputs.rust-cache-prefix }} + shared-key: clippy + save-if: ${{ inputs.rust-cache-save }} - name: Install Protoc if: ${{ inputs.install-protoc == true }} @@ -106,24 +110,9 @@ jobs: with: repo-token: ${{ secrets.GITHUB_TOKEN }} - - name: Run sccache-cache - if: ${{ inputs.use-sccache == true }} - uses: mozilla-actions/sccache-action@v0.0.4 - - name: Clippy run: cargo clippy --workspace --all-features --all-targets -- -D warnings - - name: Save Cargo cache - if: ${{ inputs.rust-cache-save }} - uses: actions/cache/save@v4 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/ - ~/.cargo/git/ - target/ - key: ${{ inputs.rust-cache-prefix }}-${{ runner.os }}-cargo-clippy-${{ hashFiles('**/Cargo.lock') }} - formatting: name: Formatting runs-on: ${{ inputs.run-label }} @@ -139,41 +128,11 @@ jobs: toolchain: ${{ inputs.rust-toolchain-formatting }} components: rustfmt - - name: Restore Cargo cache - id: cache-restore - uses: actions/cache/restore@v4 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/ - ~/.cargo/git/ - target/ - key: ${{ inputs.rust-cache-prefix }}-${{ runner.os }}-cargo-formatting-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ inputs.rust-cache-prefix }}-${{ runner.os }}-cargo-formatting- - - - name: Clean target if Cargo.lock changed - if: steps.cache-restore.outputs.cache-hit != 'true' - run: rm -rf target/ - - - name: Run sccache-cache - if: ${{ inputs.use-sccache == true }} - uses: mozilla-actions/sccache-action@v0.0.4 - + # `cargo fmt -- --check` does not compile anything, so there is no target/ + # or dependency cache to restore here. - name: Check Formatting run: cargo fmt -- --check - - name: Save Cargo cache - if: ${{ inputs.rust-cache-save }} - uses: actions/cache/save@v4 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/ - ~/.cargo/git/ - target/ - key: ${{ inputs.rust-cache-prefix }}-${{ runner.os }}-cargo-formatting-${{ hashFiles('**/Cargo.lock') }} - tests: name: Unit Tests runs-on: ${{ inputs.run-label }} @@ -189,22 +148,20 @@ jobs: with: toolchain: ${{ inputs.rust-toolchain }} - - name: Restore Cargo cache - id: cache-restore - uses: actions/cache/restore@v4 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/ - ~/.cargo/git/ - target/ - key: ${{ inputs.rust-cache-prefix }}-${{ runner.os }}-cargo-tests-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ inputs.rust-cache-prefix }}-${{ runner.os }}-cargo-tests- + # Before the cache step so RUSTFLAGS is part of the Swatinem cache key. + - name: Set up mold linker + if: ${{ inputs.use-mold }} + run: | + sudo apt-get update -qq + sudo apt-get install -y --no-install-recommends mold clang + echo "RUSTFLAGS=${RUSTFLAGS:+$RUSTFLAGS }-C linker=clang -C link-arg=-fuse-ld=mold" >> "$GITHUB_ENV" - - name: Clean target if Cargo.lock changed - if: steps.cache-restore.outputs.cache-hit != 'true' - run: rm -rf target/ + - name: Rust cache + uses: Swatinem/rust-cache@23869a5bd66c73db3c0ac40331f3206eb23791dc # v2.9.1 + with: + prefix-key: ${{ inputs.rust-cache-prefix }} + shared-key: tests + save-if: ${{ inputs.rust-cache-save }} - name: Install Protoc if: ${{ inputs.install-protoc == true }} @@ -212,24 +169,9 @@ jobs: with: repo-token: ${{ secrets.GITHUB_TOKEN }} - - name: Run sccache-cache - if: ${{ inputs.use-sccache == true }} - uses: mozilla-actions/sccache-action@v0.0.4 - - name: Unit Tests run: cargo test ${{ inputs.test-args }} - - name: Save Cargo cache - if: ${{ inputs.rust-cache-save }} - uses: actions/cache/save@v4 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/ - ~/.cargo/git/ - target/ - key: ${{ inputs.rust-cache-prefix }}-${{ runner.os }}-cargo-tests-${{ hashFiles('**/Cargo.lock') }} - tests-suites: name: Tests Suite "${{ matrix.element }}" if: (inputs.test-suites != '') && (inputs.test-suites != '[]') @@ -258,22 +200,20 @@ jobs: with: toolchain: ${{ inputs.rust-toolchain }} - - name: Restore Cargo cache - id: cache-restore - uses: actions/cache/restore@v4 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/ - ~/.cargo/git/ - target/ - key: ${{ inputs.rust-cache-prefix }}-${{ runner.os }}-cargo-tests-suites-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ inputs.rust-cache-prefix }}-${{ runner.os }}-cargo-tests-suites- + # Before the cache step so RUSTFLAGS is part of the Swatinem cache key. + - name: Set up mold linker + if: ${{ inputs.use-mold }} + run: | + sudo apt-get update -qq + sudo apt-get install -y --no-install-recommends mold clang + echo "RUSTFLAGS=${RUSTFLAGS:+$RUSTFLAGS }-C linker=clang -C link-arg=-fuse-ld=mold" >> "$GITHUB_ENV" - - name: Clean target if Cargo.lock changed - if: steps.cache-restore.outputs.cache-hit != 'true' - run: rm -rf target/ + - name: Rust cache + uses: Swatinem/rust-cache@23869a5bd66c73db3c0ac40331f3206eb23791dc # v2.9.1 + with: + prefix-key: ${{ inputs.rust-cache-prefix }} + shared-key: tests-suites + save-if: ${{ inputs.rust-cache-save }} - name: Install Protoc if: ${{ inputs.install-protoc == true }} @@ -281,24 +221,9 @@ jobs: with: repo-token: ${{ secrets.GITHUB_TOKEN }} - - name: Run sccache-cache - if: ${{ inputs.use-sccache == true }} - uses: mozilla-actions/sccache-action@v0.0.4 - - name: Test Suite run: cargo test --test ${{ matrix.element }} - - name: Save Cargo cache - if: ${{ inputs.rust-cache-save }} - uses: actions/cache/save@v4 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/ - ~/.cargo/git/ - target/ - key: ${{ inputs.rust-cache-prefix }}-${{ runner.os }}-cargo-tests-suites-${{ hashFiles('**/Cargo.lock') }} - unused-dependencies: name: Unused Dependencies runs-on: ${{ inputs.run-label }} @@ -315,26 +240,12 @@ jobs: with: toolchain: ${{ inputs.rust-toolchain-udeps }} - - name: Restore Cargo cache - id: cache-restore - uses: actions/cache/restore@v4 + - name: Rust cache + uses: Swatinem/rust-cache@23869a5bd66c73db3c0ac40331f3206eb23791dc # v2.9.1 with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/ - ~/.cargo/git/ - target/ - key: ${{ inputs.rust-cache-prefix }}-${{ runner.os }}-cargo-unused-deps-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ inputs.rust-cache-prefix }}-${{ runner.os }}-cargo-unused-deps- - - - name: Clean target if Cargo.lock changed - if: steps.cache-restore.outputs.cache-hit != 'true' - run: rm -rf target/ - - - name: Run sccache-cache - if: ${{ inputs.use-sccache == true }} - uses: mozilla-actions/sccache-action@v0.0.4 + prefix-key: ${{ inputs.rust-cache-prefix }} + shared-key: unused-deps + save-if: ${{ inputs.rust-cache-save }} - name: Install cargo-udeps run: cargo install cargo-udeps@0.1.43 --locked @@ -342,17 +253,6 @@ jobs: - name: Check Dependencies run: cargo udeps --all-targets - - name: Save Cargo cache - if: ${{ inputs.rust-cache-save }} - uses: actions/cache/save@v4 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/ - ~/.cargo/git/ - target/ - key: ${{ inputs.rust-cache-prefix }}-${{ runner.os }}-cargo-unused-deps-${{ hashFiles('**/Cargo.lock') }} - license: name: Licenses runs-on: ${{ inputs.run-label }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 680d18f..20a7090 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,6 +47,10 @@ on: description: 'Run `sccache-cache` before running rust tests' type: boolean default: true + rust-use-mold: + description: 'Use the mold linker for the rust test jobs (opt-in; non-LTO debug builds only)' + type: boolean + default: false rust-use-postgresql: description: 'Run postgresql before running rust tests' type: boolean @@ -133,6 +137,7 @@ jobs: rust-backtrace: ${{ inputs.rust-backtrace }} install-protoc: ${{ inputs.rust-install-protoc }} use-sccache: ${{ inputs.rust-use-sccache }} + use-mold: ${{ inputs.rust-use-mold }} use-postgresql: ${{ inputs.rust-use-postgresql }} test-env-vars: ${{ inputs.rust-test-env-vars }} run-label: ${{ inputs.run-label }} diff --git a/.github/workflows/release-app.yml b/.github/workflows/release-app.yml index 3253f09..e358931 100644 --- a/.github/workflows/release-app.yml +++ b/.github/workflows/release-app.yml @@ -17,7 +17,7 @@ on: type: string default: ${{ vars.AWS_REGION }} run-label: - description: 'The run label to use for the actions' + description: 'The run label to use for the build job (the heavy compile). Push jobs always use ubuntu-latest.' type: string default: 'ubuntu-latest' secrets: @@ -44,7 +44,7 @@ jobs: submodules: recursive token: ${{ secrets.PRIVATE_SUBMODULE_ACCESS_TOKEN || github.token }} fetch-depth: 0 - # Don't persist the credentials because we are using the token to fetch the + # Don't persist the credentials because we are using the token to fetch the # private submodule and then we are using different token to create a release persist-credentials: false @@ -63,18 +63,114 @@ jobs: steps: - run: echo "Version = ${{ needs.update_version.outputs.version }}" + # Build the image ONCE (one compile) and export it as a tarball artifact. The + # per-env publish jobs below load this tarball and push to each environment's + # ECR, so staging + prod no longer each recompile the identical image. Same + # build-once / push-per-env pattern as pay-core's canary image. + build: + name: Build ${{ needs.update_version.outputs.version }} + needs: [ update_version ] + runs-on: ${{ inputs.run-label }} + permissions: + contents: read + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + ref: ${{ needs.update_version.outputs.version }} + token: ${{ secrets.PRIVATE_SUBMODULE_ACCESS_TOKEN || github.token }} + submodules: recursive + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build image to tarball + uses: docker/build-push-action@v5 + with: + context: . + tags: release-image:${{ needs.update_version.outputs.version }} + cache-from: type=gha + cache-to: type=gha,mode=max + outputs: type=docker,dest=/tmp/image.tar + + - name: Upload image artifact + uses: actions/upload-artifact@v7 + with: + name: release-image + path: /tmp/image.tar + retention-days: 1 + publish: name: Publish ${{ needs.update_version.outputs.version }} ❱❱ ${{ matrix.env.name }} - needs: [ update_version ] + needs: [ update_version, build ] strategy: fail-fast: false matrix: env: ${{ fromJson(inputs.publish-envs) }} - secrets: inherit - uses: ./.github/workflows/build-publish.yml - with: - version: ${{ needs.update_version.outputs.version }} - image-name: ${{ inputs.image-name }} - aws-region: ${{ inputs.aws-region }} - aws-role-arn: ${{ matrix.env.role }} - run-label: ${{ inputs.run-label }} + # Push-only: no compile here, so a small runner is enough regardless of the + # build runner. + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + packages: write + steps: + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ matrix.env.role }} + aws-region: ${{ inputs.aws-region }} + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v2 + with: + mask-password: 'true' + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + logout: false + + - name: Download image artifact + uses: actions/download-artifact@v8 + with: + name: release-image + path: /tmp + + - name: Load image + run: docker load -i /tmp/image.tar + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ghcr.io/${{ github.repository }} + ${{ steps.login-ecr.outputs.registry }}/${{ inputs.image-name }} + walletconnect/${{ inputs.image-name }},enable=false + flavor: | + latest=auto + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=${{ needs.update_version.outputs.version }} + # Tag immutability prevents usage of `latest` + # type=raw,value=latest,enable={{is_default_branch}} + + - name: Tag and push image + env: + SRC: release-image:${{ needs.update_version.outputs.version }} + TAGS: ${{ steps.meta.outputs.tags }} + run: | + set -euo pipefail + printf '%s\n' "$TAGS" | while IFS= read -r tag; do + [ -z "$tag" ] && continue + echo "Pushing $tag" + docker tag "$SRC" "$tag" + docker push "$tag" + done