diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 96c2e16a..608da74c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -10,6 +10,17 @@ concurrency: permissions: id-token: write + contents: read + +# The aspect-launcher and bazelisk resolve their versions via the GitHub +# releases API. Unauthenticated that API is capped at 60 req/hr by source IP, +# which the macOS legs blow through on a cold cache (all presets stampede the +# API at once on the first-ever macOS run) → "403 API rate limit exceeded". +# Authenticate those calls with the job token to get the 5000 req/hr limit. +env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BAZELISK_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: # Render every preset from the local template tree (via the shared renderer the @@ -33,7 +44,12 @@ jobs: - ruby - scala - kitchen-sink - runs-on: ubuntu-latest + # macOS runners are billed at 10x Linux on GHA, so only exercise them + # on main pushes (where Apple-Silicon-only breakage like the + # distroless linux/arm64/v8 manifest bug would otherwise slip through); + # PRs stay Linux-only. + os: ${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') && fromJSON('["ubuntu-latest","macos-latest"]') || fromJSON('["ubuntu-latest"]') }} + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v6 @@ -61,10 +77,10 @@ jobs: git -c user.email=ci@aspect.build -c user.name=CI commit -q -m "rendered ${{ matrix.preset }}" # Normalize (buildifier + gazelle + format), mirroring the publish job. bazel run --run_in_cwd @buildifier_prebuilt//buildifier -- -r . || true - aspect gazelle --task:name gazelle-${{ matrix.preset }} --check-only=false || true + aspect gazelle --task:name gazelle-${{ matrix.preset }}-${{ matrix.os }} --github-status-comments:enabled=false --github-status-checks:enabled=false --check-only=false || true case "${{ matrix.preset }}" in minimal|scala|ruby) ;; - *) aspect format --task:name format-${{ matrix.preset }} --scope=all || true ;; + *) aspect format --task:name format-${{ matrix.preset }}-${{ matrix.os }} --github-status-comments:enabled=false --github-status-checks:enabled=false --scope=all || true ;; esac git add -A git -c user.email=ci@aspect.build -c user.name=CI commit -q --amend --no-edit || true @@ -78,15 +94,23 @@ jobs: env: ACTIONLINT_VERSION: 1.7.7 run: | + case "$(uname -s)" in + Darwin) os=darwin ;; + *) os=linux ;; + esac + case "$(uname -m)" in + arm64|aarch64) arch=arm64 ;; + *) arch=amd64 ;; + esac curl -fsSL -o actionlint.tar.gz \ - "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz" + "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_${os}_${arch}.tar.gz" tar -xzf actionlint.tar.gz actionlint ./actionlint -color .github/workflows/*.yaml # No separate build step: `aspect test` builds everything it needs. - name: Test working-directory: ${{ env.WS }} - run: aspect test --task:name test-${{ matrix.preset }} -- //... + run: aspect test --task:name test-${{ matrix.preset }}-${{ matrix.os }} --github-status-comments:enabled=false --github-status-checks:enabled=false -- //... # The steps below run the SAME tasks the generated project's CI # (template/.github/workflows/ci.yaml) runs, with the same per-preset @@ -97,34 +121,41 @@ jobs: # buildifier always runs (Starlark; only needs buildifier_prebuilt). - name: Buildifier working-directory: ${{ env.WS }} - run: aspect buildifier --task:name buildifier-${{ matrix.preset }} --scope=all + run: aspect buildifier --task:name buildifier-${{ matrix.preset }}-${{ matrix.os }} --github-status-comments:enabled=false --github-status-checks:enabled=false --scope=all # gazelle runs for every preset (the stamped CI always has a gazelle job). - name: Gazelle (no changes expected) working-directory: ${{ env.WS }} - run: aspect gazelle --task:name gazelle-check-${{ matrix.preset }} + run: aspect gazelle --task:name gazelle-check-${{ matrix.preset }}-${{ matrix.os }} --github-status-comments:enabled=false --github-status-checks:enabled=false # Lint runs only for presets with a wired rules_lint aspect (matches the # stamped CI's lint-job gating and .aspect/config.axl's aspects list). # go/scala have no linter; rust lints via clippy (aspect_rules_lint_rust). + # + # The clang-tidy aspect (cpp, and cpp-in-kitchen-sink) is skipped on macOS: + # rules_lint's _update_flag strips absolute `-isystem` paths as if they were + # MSVC `/flags`, so the macOS SDK libc++ include is dropped and clang-tidy + # can't find /. Build/test/format still run on macOS for + # cpp. Re-enable once https://github.com/aspect-build/rules_lint/issues/924 + # ships (PR #779). - name: Lint - if: ${{ !contains(fromJSON('["minimal","go","scala"]'), matrix.preset) }} + if: ${{ !contains(fromJSON('["minimal","go","scala"]'), matrix.preset) && !(matrix.os == 'macos-latest' && contains(fromJSON('["cpp","kitchen-sink"]'), matrix.preset)) }} working-directory: ${{ env.WS }} - run: aspect lint --task:name lint-${{ matrix.preset }} -- //... + run: aspect lint --task:name lint-${{ matrix.preset }}-${{ matrix.os }} --github-status-comments:enabled=false --github-status-checks:enabled=false -- //... # format runs for every preset with a wired source formatter. scala/ruby # have none; minimal has no languages (buildifier covers its Starlark). - name: Format (no changes expected) if: ${{ !contains(fromJSON('["minimal","scala","ruby"]'), matrix.preset) }} working-directory: ${{ env.WS }} - run: aspect format --task:name format-${{ matrix.preset }} --scope=all + run: aspect format --task:name format-${{ matrix.preset }}-${{ matrix.os }} --github-status-comments:enabled=false --github-status-checks:enabled=false --scope=all # delivery runs for presets whose stamped CI has a delivery job (oci/stamp). # --track-state=false --mode=always mirrors the stamped delivery job. - name: Delivery if: ${{ contains(fromJSON('["go","kitchen-sink"]'), matrix.preset) }} working-directory: ${{ env.WS }} - run: aspect delivery --task:name delivery-${{ matrix.preset }} --track-state=false --mode=always + run: aspect delivery --task:name delivery-${{ matrix.preset }}-${{ matrix.os }} --github-status-comments:enabled=false --github-status-checks:enabled=false --track-state=false --mode=always # Execute the preset's user story — an executable-Markdown tutorial that # builds/tests/extends the generated project. Run with `sh` (the ~~~ alias diff --git a/template/MODULE.bazel b/template/MODULE.bazel index dd46dbce..35d84802 100644 --- a/template/MODULE.bazel +++ b/template/MODULE.bazel @@ -60,8 +60,13 @@ bazel_dep(name = "aspect_rules_swc", version = "2.7.2") {% if python %} bazel_dep(name = "aspect_rules_py", version = "2.0.0-alpha.3") {% endif %} -{% if cpp %} -bazel_dep(name = "rules_cc", version = "0.2.19") +{% if cpp or (rust and lint) %} +# Pinned to match the LLVM toolchain below (registered for the same condition). +# toolchains_llvm 1.8.0's generated cc_toolchain selects on the rules_cc target +# `//cc/toolchains/args/archiver_flags:use_libtool_on_macos_setting`, which +# rules_cc 0.2.19 renamed away — so 0.2.18 is the newest compatible version. +# Without this, macOS analysis fails: "no such target ...use_libtool_on_macos_setting". +bazel_dep(name = "rules_cc", version = "0.2.18") {% endif %} {% if cpp or (rust and lint) %} # Hermetic C++ toolchain. Also needed by rust+lint: it links rules_rust's @@ -193,11 +198,11 @@ register_toolchains("@uv//:all") # fuller toolchain from the root module takes priority and fixes that link. llvm = use_extension("@toolchains_llvm//toolchain/extensions:llvm.bzl", "llvm") llvm.toolchain( - # NB: llvm doesn't release for all platforms on every patch release + # clang 19 — clang 15 can't parse the macOS 15 SDK's libc++ headers + # ("unknown type name '__remove_cv'"). 19.1.7 is the last 19.1.x patch that + # ships linux-x64 + darwin-arm64 + darwin-x64, so one entry covers all. llvm_versions = { - "": "15.0.6", - "darwin-aarch64": "15.0.7", - "darwin-x86_64": "15.0.7", + "": "19.1.7", }, ) use_repo(llvm, "llvm_toolchain", "llvm_toolchain_llvm")