diff --git a/.github/workflows/deploy-kotlin-v2.yml b/.github/workflows/deploy-kotlin-v2.yml index db37f84..c382099 100644 --- a/.github/workflows/deploy-kotlin-v2.yml +++ b/.github/workflows/deploy-kotlin-v2.yml @@ -16,8 +16,8 @@ on: use-arc-runners: required: false type: boolean - default: false - description: "Run on the self-hosted ARC arm64 runners (takes precedence over use-blacksmith-runners). Applies to the test, image build and service profile jobs." + default: true + description: "Run on the self-hosted ARC arm64 runners (default; takes precedence over use-blacksmith-runners). Never used in public repositories: the ARC runner group rejects them, so they keep the Blacksmith/GitHub-hosted runners. Applies to the test, image build and service profile jobs." # DEPRECATED (no-op): all builds and CI run on arm64. Retained for backwards # compatibility with callers still passing it; the value is ignored and this # input will be removed in a future release. @@ -250,7 +250,7 @@ jobs: with: runner-size: ${{ inputs.runner-size }} use-blacksmith-runners: ${{ inputs.use-blacksmith-runners }} - use-arc-runners: ${{ inputs.use-arc-runners }} + use-arc-runners: ${{ (inputs.use-arc-runners && github.event.repository.private) }} service-name: ${{ inputs.service-name }} service-emoji: ${{ inputs.service-emoji }} gradle-module: ${{ inputs.gradle-module }} @@ -265,7 +265,7 @@ jobs: with: runner-size: ${{ inputs.runner-size }} use-blacksmith-runners: ${{ inputs.use-blacksmith-runners }} - use-arc-runners: ${{ inputs.use-arc-runners }} + use-arc-runners: ${{ (inputs.use-arc-runners && github.event.repository.private) }} stage: ${{ inputs.stage }} service-name: ${{ inputs.service-name }} service-emoji: ${{ inputs.service-emoji }} @@ -319,7 +319,7 @@ jobs: gradle-module: ${{ inputs.gradle-module }} java-version: ${{ inputs.java-version }} openapi-max-workers: ${{ inputs.openapi-max-workers }} - use-arc-runners: ${{ inputs.use-arc-runners }} + use-arc-runners: ${{ (inputs.use-arc-runners && github.event.repository.private) }} secrets: GHL_USERNAME: ${{ secrets.GHL_USERNAME }} GHL_PASSWORD: ${{ secrets.GHL_PASSWORD }} diff --git a/.github/workflows/deploy-kotlin.yml b/.github/workflows/deploy-kotlin.yml index 8829ca2..c49b94d 100644 --- a/.github/workflows/deploy-kotlin.yml +++ b/.github/workflows/deploy-kotlin.yml @@ -16,8 +16,8 @@ on: use-arc-runners: required: false type: boolean - default: false - description: "Run on the self-hosted ARC arm64 runners (takes precedence over use-blacksmith-runners). Applies to the test, image build and service profile jobs." + default: true + description: "Run on the self-hosted ARC arm64 runners (default; takes precedence over use-blacksmith-runners). Never used in public repositories: the ARC runner group rejects them, so they keep the Blacksmith/GitHub-hosted runners. Applies to the test, image build and service profile jobs." # DEPRECATED (no-op): all builds and CI run on arm64. Retained for backwards # compatibility with callers still passing it; the value is ignored and this # input will be removed in a future release. @@ -238,7 +238,7 @@ jobs: with: runner-size: ${{ inputs.runner-size }} use-blacksmith-runners: ${{ inputs.use-blacksmith-runners }} - use-arc-runners: ${{ inputs.use-arc-runners }} + use-arc-runners: ${{ (inputs.use-arc-runners && github.event.repository.private) }} service-name: ${{ inputs.service-name }} service-emoji: ${{ inputs.service-emoji }} gradle-module: ${{ inputs.gradle-module }} @@ -253,7 +253,7 @@ jobs: with: runner-size: ${{ inputs.runner-size }} use-blacksmith-runners: ${{ inputs.use-blacksmith-runners }} - use-arc-runners: ${{ inputs.use-arc-runners }} + use-arc-runners: ${{ (inputs.use-arc-runners && github.event.repository.private) }} stage: ${{ inputs.stage }} service-name: ${{ inputs.service-name }} service-emoji: ${{ inputs.service-emoji }} @@ -304,7 +304,7 @@ jobs: gradle-module: ${{ inputs.gradle-module }} java-version: ${{ inputs.java-version }} openapi-max-workers: ${{ inputs.openapi-max-workers }} - use-arc-runners: ${{ inputs.use-arc-runners }} + use-arc-runners: ${{ (inputs.use-arc-runners && github.event.repository.private) }} secrets: GHL_USERNAME: ${{ secrets.GHL_USERNAME }} GHL_PASSWORD: ${{ secrets.GHL_PASSWORD }} diff --git a/.github/workflows/pull-request-kotlin.yml b/.github/workflows/pull-request-kotlin.yml index f6a1834..1576c52 100644 --- a/.github/workflows/pull-request-kotlin.yml +++ b/.github/workflows/pull-request-kotlin.yml @@ -15,8 +15,8 @@ on: use-arc-runners: required: false type: boolean - default: false - description: "Run on the self-hosted ARC arm64 runners (takes precedence over use-blacksmith-runners). Caches go to S3 and SonarQube is reached in-cluster without Tailscale. Requires the GH_ACTION_ACCESS_KEY_ID and GH_ACTION_SECRET_ACCESS_KEY secrets." + default: true + description: "Run on the self-hosted ARC arm64 runners (default; takes precedence over use-blacksmith-runners). Never used in public repositories: the ARC runner group rejects them, so they keep the Blacksmith/GitHub-hosted runners. SonarQube is reached in-cluster without Tailscale, and caches go to S3 when the GH_ACTION_ACCESS_KEY_ID and GH_ACTION_SECRET_ACCESS_KEY secrets are passed (GitHub cache otherwise). Set to false to opt out." # DEPRECATED (no-op): all builds and CI run on arm64. Retained for backwards # compatibility with callers still passing it; the value is ignored and this # input will be removed in a future release. @@ -76,10 +76,10 @@ on: secrets: GH_ACTION_ACCESS_KEY_ID: required: false - description: "AWS access key for the S3 cache bucket. Required with use-arc-runners." + description: "AWS access key for the S3 cache bucket, used on ARC. Without it ARC jobs use the GitHub cache." GH_ACTION_SECRET_ACCESS_KEY: required: false - description: "AWS secret key for the S3 cache bucket. Required with use-arc-runners." + description: "AWS secret key for the S3 cache bucket, used on ARC. Without it ARC jobs use the GitHub cache." TAILSCALE_AUTHKEY: required: false description: "Tailscale auth key. When set, the runner joins the tailnet so it can reach the self-hosted SonarQube. Leave unset to keep scanning SonarCloud." @@ -94,11 +94,13 @@ on: description: "SonarQube token" env: # Test names with non-ASCII characters become report file names; the ARC runner image defaults to a POSIX locale. - LC_ALL: ${{ inputs.use-arc-runners && 'C.UTF-8' || '' }} + LC_ALL: ${{ (inputs.use-arc-runners && github.event.repository.private) && 'C.UTF-8' || '' }} + # On ARC the caches use S3 when the caller passes the bucket credentials, and the GitHub cache otherwise. + S3_CACHE: ${{ (inputs.use-arc-runners && github.event.repository.private) && secrets.GH_ACTION_ACCESS_KEY_ID != '' }} jobs: setup: name: Setup - runs-on: ${{ inputs.use-arc-runners && 'arc-arm64-2cpu-4gb' || 'linux-arm64' }} + runs-on: ${{ (inputs.use-arc-runners && github.event.repository.private) && 'arc-arm64-2cpu-4gb' || 'linux-arm64' }} timeout-minutes: 5 outputs: runner-name: ${{ steps.runner.outputs.runner-name }} @@ -113,10 +115,10 @@ jobs: with: runner-size: ${{ inputs.runner-size }} use-blacksmith-runners: ${{ inputs.use-blacksmith-runners }} - use-arc-runners: ${{ inputs.use-arc-runners }} + use-arc-runners: ${{ (inputs.use-arc-runners && github.event.repository.private) }} check-migration-order: name: Check Migration Order - runs-on: ${{ inputs.use-arc-runners && 'arc-arm64-2cpu-4gb' || 'linux-arm64' }} + runs-on: ${{ (inputs.use-arc-runners && github.event.repository.private) && 'arc-arm64-2cpu-4gb' || 'linux-arm64' }} timeout-minutes: 5 steps: - name: Checkout @@ -150,7 +152,7 @@ jobs: distribution: corretto java-version: ${{ inputs.java-version }} - name: Restore Gradle cache - if: ${{ !inputs.use-arc-runners }} + if: ${{ env.S3_CACHE != 'true' }} uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5 with: &gradle-cache-restore path: | @@ -161,7 +163,7 @@ jobs: ${{ runner.os }}-gradle-${{ github.head_ref }}- ${{ runner.os }}-gradle- - name: Restore Gradle cache (S3) - if: ${{ inputs.use-arc-runners }} + if: ${{ env.S3_CACHE == 'true' }} uses: runs-on/cache/restore@88d90644011a3a9957fd141a106f5a94f9794203 # v5.0.7 env: &s3-cache-env RUNS_ON_S3_BUCKET_CACHE: monta-github-ci-cache @@ -208,18 +210,18 @@ jobs: java-version: ${{ inputs.java-version }} - name: Restore Gradle cache id: gradle-cache - if: ${{ !inputs.use-arc-runners }} + if: ${{ env.S3_CACHE != 'true' }} uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5 with: *gradle-cache-restore - name: Restore Gradle cache (S3) id: gradle-cache-s3 - if: ${{ inputs.use-arc-runners }} + if: ${{ env.S3_CACHE == 'true' }} uses: runs-on/cache/restore@88d90644011a3a9957fd141a106f5a94f9794203 # v5.0.7 env: *s3-cache-env with: *gradle-cache-restore - name: Restore SonarCloud cache id: sonar-cache - if: ${{ !inputs.skip-sonar && !inputs.use-arc-runners }} + if: ${{ !inputs.skip-sonar && env.S3_CACHE != 'true' }} uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5 with: &sonar-cache-restore path: ~/.sonar/cache @@ -227,7 +229,7 @@ jobs: restore-keys: ${{ runner.os }}-sonar - name: Restore SonarCloud cache (S3) id: sonar-cache-s3 - if: ${{ !inputs.skip-sonar && inputs.use-arc-runners }} + if: ${{ !inputs.skip-sonar && env.S3_CACHE == 'true' }} uses: runs-on/cache/restore@88d90644011a3a9957fd141a106f5a94f9794203 # v5.0.7 env: *s3-cache-env with: *sonar-cache-restore @@ -257,7 +259,7 @@ jobs: # automatically for repos still on SonarCloud (no TAILSCALE_AUTHKEY passed). - name: Tailscale id: tailscale - if: ${{ !inputs.skip-sonar && !inputs.use-arc-runners && env.TAILSCALE_AUTHKEY != '' }} + if: ${{ !inputs.skip-sonar && !(inputs.use-arc-runners && github.event.repository.private) && env.TAILSCALE_AUTHKEY != '' }} continue-on-error: ${{ inputs.sonar-non-blocking }} uses: tailscale/github-action@780049a30b6ff5c378a9e7b389d15ece7a204888 # v4.1.3 with: @@ -275,7 +277,7 @@ jobs: # Same reason as the upload step below: an expression here does not survive the step failing. An unreachable # tailnet then fails the scan itself, which the blocking check below re-raises. - name: Wait for SonarQube to be reachable over the tailnet - if: ${{ !inputs.skip-sonar && !inputs.use-arc-runners && steps.tailscale.outcome != 'failure' }} + if: ${{ !inputs.skip-sonar && !(inputs.use-arc-runners && github.event.repository.private) && steps.tailscale.outcome != 'failure' }} continue-on-error: true shell: bash env: @@ -329,7 +331,7 @@ jobs: gradle-module: ${{ inputs.gradle-module }} gradle-tasks: 'sonar' # ARC runs in the same cluster as SonarQube, whose vpn.internal hostname is only reachable over Tailscale. - gradle-args: ${{ inputs.gradle-args }}${{ inputs.use-arc-runners && ' -Dsonar.host.url=http://sonarqube.sonarqube.svc.cluster.local:9000' || '' }} + gradle-args: ${{ inputs.gradle-args }}${{ (inputs.use-arc-runners && github.event.repository.private) && ' -Dsonar.host.url=http://sonarqube.sonarqube.svc.cluster.local:9000' || '' }} # Restores what continue-on-error was meant to express, in an `if` where `inputs` does evaluate. - name: Fail when a blocking Sonar scan failed if: ${{ steps.sonar.outcome == 'failure' && !inputs.sonar-non-blocking }} @@ -356,7 +358,7 @@ jobs: **/build/test-results/**/*.trx **/build/test-results/**/*.json - name: Save Gradle cache - if: ${{ always() && !inputs.use-arc-runners && steps.gradle-cache.outputs.cache-hit != 'true' }} + if: ${{ always() && env.S3_CACHE != 'true' && steps.gradle-cache.outputs.cache-hit != 'true' }} uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5 with: &gradle-cache-save path: | @@ -364,18 +366,18 @@ jobs: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-${{ github.head_ref }}-${{ github.sha }} - name: Save Gradle cache (S3) - if: ${{ always() && inputs.use-arc-runners && steps.gradle-cache-s3.outputs.cache-hit != 'true' }} + if: ${{ always() && env.S3_CACHE == 'true' && steps.gradle-cache-s3.outputs.cache-hit != 'true' }} uses: runs-on/cache/save@88d90644011a3a9957fd141a106f5a94f9794203 # v5.0.7 env: *s3-cache-env with: *gradle-cache-save - name: Save SonarQube cache - if: ${{ always() && !inputs.skip-sonar && !inputs.use-arc-runners && steps.sonar-cache.outputs.cache-hit != 'true' }} + if: ${{ always() && !inputs.skip-sonar && env.S3_CACHE != 'true' && steps.sonar-cache.outputs.cache-hit != 'true' }} uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5 with: &sonar-cache-save path: ~/.sonar/cache key: ${{ runner.os }}-sonar - name: Save SonarQube cache (S3) - if: ${{ always() && !inputs.skip-sonar && inputs.use-arc-runners && steps.sonar-cache-s3.outputs.cache-hit != 'true' }} + if: ${{ always() && !inputs.skip-sonar && env.S3_CACHE == 'true' && steps.sonar-cache-s3.outputs.cache-hit != 'true' }} uses: runs-on/cache/save@88d90644011a3a9957fd141a106f5a94f9794203 # v5.0.7 env: *s3-cache-env with: *sonar-cache-save diff --git a/.github/workflows/sonar-cloud.yml b/.github/workflows/sonar-cloud.yml index 10c0ca2..d41f709 100644 --- a/.github/workflows/sonar-cloud.yml +++ b/.github/workflows/sonar-cloud.yml @@ -15,8 +15,8 @@ on: use-arc-runners: required: false type: boolean - default: false - description: "Run on the self-hosted ARC arm64 runners (takes precedence over use-blacksmith-runners). Caches go to S3 and SonarQube is reached in-cluster without Tailscale. Requires the GH_ACTION_ACCESS_KEY_ID and GH_ACTION_SECRET_ACCESS_KEY secrets." + default: true + description: "Run on the self-hosted ARC arm64 runners (default; takes precedence over use-blacksmith-runners). Never used in public repositories: the ARC runner group rejects them, so they keep the Blacksmith/GitHub-hosted runners. SonarQube is reached in-cluster without Tailscale, and caches go to S3 when the GH_ACTION_ACCESS_KEY_ID and GH_ACTION_SECRET_ACCESS_KEY secrets are passed (GitHub cache otherwise). Set to false to opt out." # DEPRECATED (no-op): all builds and CI run on arm64. Retained for backwards # compatibility with callers still passing it; the value is ignored and this # input will be removed in a future release. @@ -46,10 +46,10 @@ on: secrets: GH_ACTION_ACCESS_KEY_ID: required: false - description: "AWS access key for the S3 cache bucket. Required with use-arc-runners." + description: "AWS access key for the S3 cache bucket, used on ARC. Without it ARC jobs use the GitHub cache." GH_ACTION_SECRET_ACCESS_KEY: required: false - description: "AWS secret key for the S3 cache bucket. Required with use-arc-runners." + description: "AWS secret key for the S3 cache bucket, used on ARC. Without it ARC jobs use the GitHub cache." TAILSCALE_AUTHKEY: required: false description: "Tailscale auth key. When set, the runner joins the tailnet so it can reach the self-hosted SonarQube. Leave unset to keep scanning SonarCloud." @@ -64,11 +64,13 @@ on: description: "Sonar token (Optional, won't publish to sonar if not present)" env: # Test names with non-ASCII characters become report file names; the ARC runner image defaults to a POSIX locale. - LC_ALL: ${{ inputs.use-arc-runners && 'C.UTF-8' || '' }} + LC_ALL: ${{ (inputs.use-arc-runners && github.event.repository.private) && 'C.UTF-8' || '' }} + # On ARC the caches use S3 when the caller passes the bucket credentials, and the GitHub cache otherwise. + S3_CACHE: ${{ (inputs.use-arc-runners && github.event.repository.private) && secrets.GH_ACTION_ACCESS_KEY_ID != '' }} jobs: setup: name: Setup - runs-on: ${{ inputs.use-arc-runners && 'arc-arm64-2cpu-4gb' || 'linux-arm64' }} + runs-on: ${{ (inputs.use-arc-runners && github.event.repository.private) && 'arc-arm64-2cpu-4gb' || 'linux-arm64' }} outputs: runner-name: ${{ steps.runner.outputs.runner-name }} steps: @@ -78,7 +80,7 @@ jobs: with: runner-size: ${{ inputs.runner-size }} use-blacksmith-runners: ${{ inputs.use-blacksmith-runners }} - use-arc-runners: ${{ inputs.use-arc-runners }} + use-arc-runners: ${{ (inputs.use-arc-runners && github.event.repository.private) }} sonar-cloud: name: SonarQube Analysis needs: setup @@ -98,7 +100,7 @@ jobs: java-version: ${{ inputs.java-version }} - name: Restore Gradle cache id: gradle-cache - if: ${{ !inputs.use-arc-runners }} + if: ${{ env.S3_CACHE != 'true' }} uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5 with: &gradle-cache-restore path: | @@ -109,7 +111,7 @@ jobs: ${{ runner.os }}-gradle-main- - name: Restore Gradle cache (S3) id: gradle-cache-s3 - if: ${{ inputs.use-arc-runners }} + if: ${{ env.S3_CACHE == 'true' }} uses: runs-on/cache/restore@88d90644011a3a9957fd141a106f5a94f9794203 # v5.0.7 env: &s3-cache-env RUNS_ON_S3_BUCKET_CACHE: monta-github-ci-cache @@ -119,14 +121,14 @@ jobs: AWS_REGION: eu-west-1 with: *gradle-cache-restore - name: Cache SonarQube packages - if: ${{ !inputs.use-arc-runners }} + if: ${{ env.S3_CACHE != 'true' }} uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 with: &sonar-cache path: ~/.sonar/cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - name: Cache SonarQube packages (S3) - if: ${{ inputs.use-arc-runners }} + if: ${{ env.S3_CACHE == 'true' }} uses: runs-on/cache@88d90644011a3a9957fd141a106f5a94f9794203 # v5.0.7 env: *s3-cache-env with: *sonar-cache @@ -135,7 +137,7 @@ jobs: # automatically for repos still on SonarCloud (no TAILSCALE_AUTHKEY passed). - name: Tailscale id: tailscale - if: ${{ !inputs.use-arc-runners && env.TAILSCALE_AUTHKEY != '' }} + if: ${{ !(inputs.use-arc-runners && github.event.repository.private) && env.TAILSCALE_AUTHKEY != '' }} continue-on-error: ${{ inputs.sonar-non-blocking }} uses: tailscale/github-action@780049a30b6ff5c378a9e7b389d15ece7a204888 # v4.1.3 with: @@ -160,7 +162,7 @@ jobs: # endpoint until it answers both waits out the race AND warms the # relay path, so the scan starts on a connection we know works. - name: Wait for SonarQube to be reachable over the tailnet - if: ${{ !inputs.use-arc-runners && steps.tailscale.outcome != 'failure' && env.TAILSCALE_AUTHKEY != '' }} + if: ${{ !(inputs.use-arc-runners && github.event.repository.private) && steps.tailscale.outcome != 'failure' && env.TAILSCALE_AUTHKEY != '' }} continue-on-error: ${{ inputs.sonar-non-blocking }} shell: bash env: @@ -209,7 +211,7 @@ jobs: gradle-module: ${{ inputs.gradle-module }} gradle-tasks: 'sonar' # ARC runs in the same cluster as SonarQube, whose vpn.internal hostname is only reachable over Tailscale. - gradle-args: ${{ inputs.gradle-args }}${{ inputs.use-arc-runners && ' -Dsonar.host.url=http://sonarqube.sonarqube.svc.cluster.local:9000' || '' }} + gradle-args: ${{ inputs.gradle-args }}${{ (inputs.use-arc-runners && github.event.repository.private) && ' -Dsonar.host.url=http://sonarqube.sonarqube.svc.cluster.local:9000' || '' }} - name: Upload build reports if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 @@ -221,7 +223,7 @@ jobs: if-no-files-found: ignore retention-days: 30 - name: Save Gradle cache - if: ${{ always() && !inputs.use-arc-runners && github.ref == 'refs/heads/main' && steps.gradle-cache.outputs.cache-hit != 'true' }} + if: ${{ always() && env.S3_CACHE != 'true' && github.ref == 'refs/heads/main' && steps.gradle-cache.outputs.cache-hit != 'true' }} uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5 with: &gradle-cache-save path: | @@ -229,7 +231,7 @@ jobs: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-main-${{ github.sha }} - name: Save Gradle cache (S3) - if: ${{ always() && inputs.use-arc-runners && github.ref == 'refs/heads/main' && steps.gradle-cache-s3.outputs.cache-hit != 'true' }} + if: ${{ always() && env.S3_CACHE == 'true' && github.ref == 'refs/heads/main' && steps.gradle-cache-s3.outputs.cache-hit != 'true' }} uses: runs-on/cache/save@88d90644011a3a9957fd141a106f5a94f9794203 # v5.0.7 env: *s3-cache-env with: *gradle-cache-save diff --git a/CLAUDE.md b/CLAUDE.md index def6dd6..afd9194 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,6 +13,7 @@ ## Recent Changes (2026-09-29) 1. **Dockerfile cache mounts persisted on ARC image builds**: when `use-arc-runners` is set, `component-build.yml`'s buildx job restores and saves `RUN --mount=type=cache` contents (all Kotlin service Dockerfiles mount `/root/.gradle` around `./gradlew buildLayers`) via `reproducible-containers/buildkit-cache-dance`, which finds the mounts by parsing the Dockerfile. ARC builders start empty and the ECR registry cache (`cache-to ... mode=max`) does not carry cache mounts, so without this every deploy re-downloads all Gradle dependencies straight from Maven Central (the in-Docker Gradle has neither the runner's CodeArtifact init script nor AWS credentials). Storage follows the PR workflows: `runs-on/cache` on S3 when the caller passes the `GH_ACTION_*` secrets (new optional secrets on `component-build` and `deploy-kotlin(-v2)`), `actions/cache` otherwise. It must be the combined `runs-on/cache`, not `restore`/`save`: cache-dance extracts in its post step, and only a post-step save runs after that. The S3 step blanks `AWS_SESSION_TOKEN`, because the job's `ecr-put-image` credentials are exported into the environment before it. Key: Dockerfile path + hash of the Gradle build files, with a prefix restore-key. +1. **ARC is the default runner for the Kotlin entry-point workflows**: `use-arc-runners` defaults to `true` in `pull-request-kotlin.yml`, `sonar-cloud.yml`, `deploy-kotlin.yml` and `deploy-kotlin-v2.yml`; callers opt out with `use-arc-runners: false`. ARC is only ever used in **private** repos: every read of the input is `(inputs.use-arc-runners && github.event.repository.private)`, so public repos (fork PRs run the fork's own workflow files) keep their current runners instead of queueing on the `ARC` org runner group, which disallows public repositories (kube-manifests#7727). Events without a repository in the payload also fall back to the old runners. It still takes precedence over `use-blacksmith-runners`, so explicit `use-blacksmith-runners: true|false` callers move too. `component-test-kotlin.yml` and `component-build.yml` keep `false` as their default (deploy-kotlin(-v2) pass the value down), so `deploy-generic(-v2)`, `deploy-python` and direct `component-build` callers stay where they are. The PR and Sonar workflows pick the cache backend with a workflow-level `S3_CACHE` env (`use-arc-runners && secrets.GH_ACTION_ACCESS_KEY_ID != ''`): S3 when the caller passes the bucket secrets, `actions/cache` otherwise, because only 2 of 78 callers pass them. Tailscale and the in-cluster Sonar URL still key off `use-arc-runners`. Checked before flipping: no caller passes a `java-version` that conflicts with its Gradle toolchain (the ARC image has no preinstalled JDK); Gradle on the runner resolves through CodeArtifact via the runner image's init script. 1. **`use-arc-runners` for the Kotlin deploy workflows**: `deploy-kotlin.yml` and `deploy-kotlin-v2.yml` accept `use-arc-runners` and pass it to `component-test-kotlin.yml` and `component-build.yml`, which both gained the input. Tests run on the converter's ARC runner, with Setup on `arc-arm64-2cpu-4gb` and `LC_ALL=C.UTF-8`, and keep `setup-java`'s GitHub-backed Gradle cache. The image build runs the existing `build-self-hosted` job (docker buildx + ECR registry layer cache, the ARC README's recommendation) instead of `build-blacksmith`. The deploy, service-profile, release-tag and changelog jobs never used Blacksmith and are unchanged. Callers that don't opt in are unaffected. 2. **`arc-job-report` action**: New composite action at `.github/actions/arc-job-report` that keeps one PR comment with each job's ARC runner, duration, peak memory and CPU, a table of suggested runner-size changes, and a per-run history (commit, wall time, slowest job). Callers run it from a `workflow_run` trigger on their PR workflow (so it reports on the finished run and adds no job to the PR checks) and pass `github-token` + `grafana-token` (e.g. `secrets.GRAFANA_CLOUD_TOKEN`) as inputs; no checkout needed, the action ships its scripts. `job_resources.py` is kube-manifests' `infra/arc/scripts/job-resources.py` plus a `GRAFANA_TOKEN` path through Grafana's datasource proxy (CI has no `gcx`); keep the two in sync. Metrics are scraped every 60 s, so jobs under 2 min are left out of the suggestions and jobs under 1 min show no CPU at all (`rate()` needs two samples); waiting does not help because the pod is deleted when the job ends. Only bot-authored comments are updated, so local `--dry-run` testing never collides with CI. Built and trialled in service-ocpi#2599. 3. **`arc-job-report` suggestion rows link to their dashboard**: the job name in the "Suggested runner changes" table now links to the job's pod on the ARC Job Resources dashboard, like the jobs table, since those are the jobs worth inspecting before resizing. diff --git a/docs/workflow-guide.md b/docs/workflow-guide.md index 9292ccb..23b5d3f 100644 --- a/docs/workflow-guide.md +++ b/docs/workflow-guide.md @@ -367,7 +367,7 @@ This conditional logic ensures the workflow continues properly even when optiona |-------|----------|---------|-------------| | `runner-size` | No | "normal" | Runner size: "normal" or "large" | | `use-blacksmith-runners` | No | true | Run on Blacksmith arm64 cloud runners (default). Set to false to run on self-hosted linux-arm64 | -| `use-arc-runners` | No | false | Run the test, image build and service profile jobs on the self-hosted ARC arm64 runners (the service profile job always uses `arc-arm64-4cpu-12gb`); takes precedence over `use-blacksmith-runners`. Set `java-version` to the Gradle toolchain: the ARC image has no preinstalled JDK. | +| `use-arc-runners` | No | true | Run the test, image build and service profile jobs on the self-hosted ARC arm64 runners (the service profile job always uses `arc-arm64-4cpu-12gb`); the default in private repos (never used in public repos), and takes precedence over `use-blacksmith-runners`; set to `false` to opt out. Set `java-version` to the Gradle toolchain: the ARC image has no preinstalled JDK. | | `stage` | Yes | - | Deployment stage: "dev", "staging", or "production" | | `service-name` | Yes | - | Human-readable service name (e.g., "Charging Service") | | `service-emoji` | Yes | - | Emoji to identify the service in Slack notifications | @@ -556,7 +556,7 @@ jobs: |-------|----------|---------|-------------| | `runner-size` | No | "normal" | Runner size: "normal" or "large" | | `use-blacksmith-runners` | No | true | Run on Blacksmith arm64 cloud runners (default). Set to false to run on self-hosted linux-arm64 | -| `use-arc-runners` | No | false | Run the test, image build and service profile jobs on the self-hosted ARC arm64 runners (the service profile job always uses `arc-arm64-4cpu-12gb`); takes precedence over `use-blacksmith-runners`. Set `java-version` to the Gradle toolchain: the ARC image has no preinstalled JDK. | +| `use-arc-runners` | No | true | Run the test, image build and service profile jobs on the self-hosted ARC arm64 runners (the service profile job always uses `arc-arm64-4cpu-12gb`); the default in private repos (never used in public repos), and takes precedence over `use-blacksmith-runners`; set to `false` to opt out. Set `java-version` to the Gradle toolchain: the ARC image has no preinstalled JDK. | | `stage` | Yes | - | Deployment stage: "dev", "staging", or "production" | | `service-name` | Yes | - | Human-readable service name (e.g., "Charging Service") | | `service-emoji` | Yes | - | Emoji to identify the service in Slack notifications | @@ -807,7 +807,7 @@ jobs: |-------|----------|---------|-------------| | `runner-size` | No | "normal" | Runner size | | `use-blacksmith-runners` | No | true | Run on Blacksmith arm64 cloud runners (default). Set to false to run on self-hosted linux-arm64 | -| `use-arc-runners` | No | false | Run on the self-hosted ARC arm64 runners (`normal` → `arc-arm64-4cpu-12gb`, `large` → `arc-arm64-8cpu-24gb`); takes precedence over `use-blacksmith-runners`. Gradle and Sonar caches go to S3 (`monta-github-ci-cache`) and SonarQube is reached in-cluster without Tailscale. Needs the `GH_ACTION_*` secrets. | +| `use-arc-runners` | No | true | Run on the self-hosted ARC arm64 runners (`normal` → `arc-arm64-4cpu-12gb`, `large` → `arc-arm64-8cpu-24gb`); the default in private repos (never used in public repos), and takes precedence over `use-blacksmith-runners`; set to `false` to opt out. SonarQube is reached in-cluster without Tailscale, and the Gradle and Sonar caches go to S3 (`monta-github-ci-cache`) when the `GH_ACTION_*` secrets are passed, the GitHub cache otherwise. | | `java-version` | No | "21" | Java version | | `gradle-module` | No | - | Gradle module name | | `kover-report-path` | No | "build/reports/kover/report.xml" | Kover report path | @@ -819,8 +819,8 @@ jobs: | Secret | Required | Description | |--------|----------|-------------| | `TAILSCALE_AUTHKEY` | No | Tailscale auth key. When set, the runner joins the tailnet to reach the self-hosted SonarQube; leave unset to scan SonarCloud. | -| `GH_ACTION_ACCESS_KEY_ID` | With `use-arc-runners` | AWS access key for the S3 cache bucket | -| `GH_ACTION_SECRET_ACCESS_KEY` | With `use-arc-runners` | AWS secret key for the S3 cache bucket | +| `GH_ACTION_ACCESS_KEY_ID` | No | AWS access key for the S3 cache bucket on ARC; without it the GitHub cache is used | +| `GH_ACTION_SECRET_ACCESS_KEY` | No | AWS secret key for the S3 cache bucket on ARC; without it the GitHub cache is used | | `GHL_USERNAME` | Yes | GitHub username | | `GHL_PASSWORD` | Yes | GitHub token | | `SONAR_TOKEN` | Yes | SonarQube token | @@ -1001,7 +1001,7 @@ jobs: |-------|----------|---------|-------------| | `runner-size` | No | "normal" | Runner size | | `use-blacksmith-runners` | No | true | Run on Blacksmith arm64 cloud runners (default). Set to false to run on self-hosted linux-arm64 | -| `use-arc-runners` | No | false | Run on the self-hosted ARC arm64 runners (`normal` → `arc-arm64-4cpu-12gb`, `large` → `arc-arm64-8cpu-24gb`); takes precedence over `use-blacksmith-runners`. Gradle and Sonar caches go to S3 (`monta-github-ci-cache`) and SonarQube is reached in-cluster without Tailscale. Needs the `GH_ACTION_*` secrets. | +| `use-arc-runners` | No | true | Run on the self-hosted ARC arm64 runners (`normal` → `arc-arm64-4cpu-12gb`, `large` → `arc-arm64-8cpu-24gb`); the default in private repos (never used in public repos), and takes precedence over `use-blacksmith-runners`; set to `false` to opt out. SonarQube is reached in-cluster without Tailscale, and the Gradle and Sonar caches go to S3 (`monta-github-ci-cache`) when the `GH_ACTION_*` secrets are passed, the GitHub cache otherwise. | | `java-version` | No | "21" | Java version | | `gradle-module` | No | - | Gradle module name | | `sonar-non-blocking` | No | true | When true, a failure of the Tailscale bring-up or the SonarQube analysis step does not fail the job (tests still gate). Set to false to make SonarQube a hard gate. | @@ -1010,8 +1010,8 @@ jobs: | Secret | Required | Description | |--------|----------|-------------| | `TAILSCALE_AUTHKEY` | No | Tailscale auth key. When set, the runner joins the tailnet to reach the self-hosted SonarQube; leave unset to scan SonarCloud. | -| `GH_ACTION_ACCESS_KEY_ID` | With `use-arc-runners` | AWS access key for the S3 cache bucket | -| `GH_ACTION_SECRET_ACCESS_KEY` | With `use-arc-runners` | AWS secret key for the S3 cache bucket | +| `GH_ACTION_ACCESS_KEY_ID` | No | AWS access key for the S3 cache bucket on ARC; without it the GitHub cache is used | +| `GH_ACTION_SECRET_ACCESS_KEY` | No | AWS secret key for the S3 cache bucket on ARC; without it the GitHub cache is used | | `GHL_USERNAME` | Yes | GitHub username | | `GHL_PASSWORD` | Yes | GitHub token | | `SONAR_TOKEN` | Yes | SonarQube token |