diff --git a/.github/workflows/docker-gradle-build-push.yml b/.github/workflows/docker-gradle-build-push.yml index 40919f0..e92aeee 100644 --- a/.github/workflows/docker-gradle-build-push.yml +++ b/.github/workflows/docker-gradle-build-push.yml @@ -36,13 +36,14 @@ jobs: # happened to grounds-forge 4.3.0 in its migrate init container. Building # an amd64 image on an arm64 runner would mean QEMU for the whole build. # Public fork PRs remain on GitHub-hosted runners; private repositories - # use their own ARC scale set. Missing repository payloads safely fall - # back to GitHub-hosted rather than the unavailable Blacksmith pool. + # use the shared self-hosted pool `grounds-runners` (org-level ARC; the + # org's Default runner group refuses public repositories). Missing + # repository payloads safely fall back to GitHub-hosted. runs-on: >- ${{ inputs.runner != '' && inputs.runner || (github.event.repository.visibility == 'public' && 'ubuntu-24.04') - || github.event.repository.name + || (github.event.repository.name && 'grounds-runners') || 'ubuntu-24.04' }} # Cold ARC builds can exceed 30m downloading builder/runtime base images # even after Gradle succeeds. Keep the default repo-ARC path bounded at diff --git a/.github/workflows/gradle-ci.yml b/.github/workflows/gradle-ci.yml index 42e2670..a7007ff 100644 --- a/.github/workflows/gradle-ci.yml +++ b/.github/workflows/gradle-ci.yml @@ -7,11 +7,10 @@ on: description: > Runner label. Leave unset and the job picks one by repository visibility: GitHub's arm64 hosted runner in public repos, where it - is free and has 4 vCPUs, and a 2 vCPU arm64 Blacksmith runner in - private repos, where GitHub-hosted arm64 is not offered. Set it - explicitly to override — an amd64 label if a test image has no - arm64 variant, or a larger Blacksmith label for a build that is - measurably CPU-bound and on someone's critical path. + is free and has 4 vCPUs, and the shared self-hosted `grounds-runners` + pool (amd64) in private repos, where GitHub-hosted arm64 is not + offered. Set it explicitly to override, e.g. `grounds-runners-large` + for a build that needs more memory than the shared pool gives. required: false type: string default: "" @@ -33,26 +32,21 @@ concurrency: jobs: build: - # Falls back to Blacksmith whenever `visibility` is absent from the event - # payload, because GitHub-hosted arm64 does not exist for private repos and - # guessing wrong there means "no runner matches" rather than a bigger bill. - # Self-hosted ARC runners on hbr1. The label is the calling repository's - # own name, which is how each repo reaches its own scale set without - # passing anything. - # # Read the three branches in order. A public repo keeps a GitHub-hosted # runner: on a self-hosted pool a fork PR would run arbitrary code on - # hbr1, which also hosts production containers. A private repo goes to - # its own runner. And if `repository` is missing from the event payload - # -- which is why this used to fall back to Blacksmith -- the name is - # empty and Blacksmith still catches it, because an empty label matches - # no runner at all and the job would queue until someone cancels it. + # hbr1, which also hosts production containers (the org's Default runner + # group refuses public repositories as a second line). A private repo goes + # to `grounds-runners`, the shared self-hosted ARC pool (org-level, on + # hbr1 today). And if `repository` is missing from the event payload, the + # job lands on hosted amd64 `ubuntu-24.04`, which exists for public and + # private repos alike -- hosted arm64 does not exist for private ones, and + # a label no runner matches queues until someone cancels the job. runs-on: >- ${{ inputs.runner != '' && inputs.runner || (github.event.repository.visibility == 'public' && 'ubuntu-24.04-arm') - || github.event.repository.name - || 'blacksmith-2vcpu-ubuntu-2404-arm' }} + || (github.event.repository.name && 'grounds-runners') + || 'ubuntu-24.04' }} timeout-minutes: 30 steps: - name: Check out diff --git a/.github/workflows/gradle-publish.yml b/.github/workflows/gradle-publish.yml index b0061dd..2330e7d 100644 --- a/.github/workflows/gradle-publish.yml +++ b/.github/workflows/gradle-publish.yml @@ -7,11 +7,10 @@ on: description: > Runner label. Leave unset and the job picks one by repository visibility: GitHub's arm64 hosted runner in public repos, where it - is free and has 4 vCPUs, and a 2 vCPU arm64 Blacksmith runner in - private repos, where GitHub-hosted arm64 is not offered. Set it - explicitly to override — an amd64 label if a test image has no - arm64 variant, or a larger Blacksmith label for a build that is - measurably CPU-bound and on someone's critical path. + is free and has 4 vCPUs, and the shared self-hosted `grounds-runners` + pool (amd64) in private repos, where GitHub-hosted arm64 is not + offered. Set it explicitly to override, e.g. `grounds-runners-large` + for a build that needs more memory than the shared pool gives. required: false type: string default: "" @@ -33,26 +32,21 @@ concurrency: jobs: release: - # Falls back to Blacksmith whenever `visibility` is absent from the event - # payload, because GitHub-hosted arm64 does not exist for private repos and - # guessing wrong there means "no runner matches" rather than a bigger bill. - # Self-hosted ARC runners on hbr1. The label is the calling repository's - # own name, which is how each repo reaches its own scale set without - # passing anything. - # # Read the three branches in order. A public repo keeps a GitHub-hosted # runner: on a self-hosted pool a fork PR would run arbitrary code on - # hbr1, which also hosts production containers. A private repo goes to - # its own runner. And if `repository` is missing from the event payload - # -- which is why this used to fall back to Blacksmith -- the name is - # empty and Blacksmith still catches it, because an empty label matches - # no runner at all and the job would queue until someone cancels it. + # hbr1, which also hosts production containers (the org's Default runner + # group refuses public repositories as a second line). A private repo goes + # to `grounds-runners`, the shared self-hosted ARC pool (org-level, on + # hbr1 today). And if `repository` is missing from the event payload, the + # job lands on hosted amd64 `ubuntu-24.04`, which exists for public and + # private repos alike -- hosted arm64 does not exist for private ones, and + # a label no runner matches queues until someone cancels the job. runs-on: >- ${{ inputs.runner != '' && inputs.runner || (github.event.repository.visibility == 'public' && 'ubuntu-24.04-arm') - || github.event.repository.name - || 'blacksmith-2vcpu-ubuntu-2404-arm' }} + || (github.event.repository.name && 'grounds-runners') + || 'ubuntu-24.04' }} timeout-minutes: 30 steps: - name: Checkout diff --git a/.github/workflows/label-sync.yml b/.github/workflows/label-sync.yml index 10b7aac..18b1f05 100644 --- a/.github/workflows/label-sync.yml +++ b/.github/workflows/label-sync.yml @@ -9,27 +9,25 @@ concurrency: jobs: sync-labels: - # Free GitHub-hosted runner in public repos; Blacksmith in private ones, + # Free GitHub-hosted runner in public repos; `grounds-runners` in private ones, # where GitHub-hosted arm64 is not offered. Tests `visibility` rather than # `repository.private` because GitHub coerces `==` operands to numbers, so # an absent `private` field would compare equal to false and hand a private # repo a label that does not exist there. - # Self-hosted ARC runners on hbr1. The label is the calling repository's - # own name, which is how each repo reaches its own scale set without - # passing anything. - # # Read the three branches in order. A public repo keeps a GitHub-hosted # runner: on a self-hosted pool a fork PR would run arbitrary code on - # hbr1, which also hosts production containers. A private repo goes to - # its own runner. And if `repository` is missing from the event payload - # -- which is why this used to fall back to Blacksmith -- the name is - # empty and Blacksmith still catches it, because an empty label matches - # no runner at all and the job would queue until someone cancels it. + # hbr1, which also hosts production containers (the org's Default runner + # group refuses public repositories as a second line). A private repo goes + # to `grounds-runners`, the shared self-hosted ARC pool (org-level, on + # hbr1 today). And if `repository` is missing from the event payload, the + # job lands on hosted amd64 `ubuntu-24.04`, which exists for public and + # private repos alike -- hosted arm64 does not exist for private ones, and + # a label no runner matches queues until someone cancels the job. runs-on: >- ${{ (github.event.repository.visibility == 'public' && 'ubuntu-24.04-arm') - || github.event.repository.name - || 'blacksmith-2vcpu-ubuntu-2404-arm' }} + || (github.event.repository.name && 'grounds-runners') + || 'ubuntu-24.04' }} timeout-minutes: 10 steps: - name: Download labels.yml diff --git a/.github/workflows/platform-test-preview-slashcmd.yml b/.github/workflows/platform-test-preview-slashcmd.yml index 52ab393..d935228 100644 --- a/.github/workflows/platform-test-preview-slashcmd.yml +++ b/.github/workflows/platform-test-preview-slashcmd.yml @@ -52,22 +52,20 @@ jobs: # `if: github.event.issue.pull_request != null`, but we double-up # here because reusable workflows shouldn't trust their callers. if: github.event.issue.pull_request != null - # Self-hosted ARC runners on hbr1. The label is the calling repository's - # own name, which is how each repo reaches its own scale set without - # passing anything. - # # Read the three branches in order. A public repo keeps a GitHub-hosted # runner: on a self-hosted pool a fork PR would run arbitrary code on - # hbr1, which also hosts production containers. A private repo goes to - # its own runner. And if `repository` is missing from the event payload - # -- which is why this used to fall back to Blacksmith -- the name is - # empty and Blacksmith still catches it, because an empty label matches - # no runner at all and the job would queue until someone cancels it. + # hbr1, which also hosts production containers (the org's Default runner + # group refuses public repositories as a second line). A private repo goes + # to `grounds-runners`, the shared self-hosted ARC pool (org-level, on + # hbr1 today). And if `repository` is missing from the event payload, the + # job lands on hosted amd64 `ubuntu-24.04`, which exists for public and + # private repos alike -- hosted arm64 does not exist for private ones, and + # a label no runner matches queues until someone cancels the job. runs-on: >- ${{ (github.event.repository.visibility == 'public' && 'ubuntu-24.04-arm') - || github.event.repository.name - || 'blacksmith-2vcpu-ubuntu-2404-arm' }} + || (github.event.repository.name && 'grounds-runners') + || 'ubuntu-24.04' }} timeout-minutes: 10 permissions: issues: write diff --git a/.github/workflows/platform-test-preview.yml b/.github/workflows/platform-test-preview.yml index 29e0f5e..0eb469a 100644 --- a/.github/workflows/platform-test-preview.yml +++ b/.github/workflows/platform-test-preview.yml @@ -87,7 +87,7 @@ jobs: runs-on: >- ${{ (github.event.repository.visibility == 'public' && 'ubuntu-24.04') - || github.event.repository.name + || (github.event.repository.name && 'grounds-runners') || 'ubuntu-24.04' }} timeout-minutes: 30 outputs: @@ -171,22 +171,20 @@ jobs: mint: if: github.event.action != 'closed' needs: build - # Self-hosted ARC runners on hbr1. The label is the calling repository's - # own name, which is how each repo reaches its own scale set without - # passing anything. - # # Read the three branches in order. A public repo keeps a GitHub-hosted # runner: on a self-hosted pool a fork PR would run arbitrary code on - # hbr1, which also hosts production containers. A private repo goes to - # its own runner. And if `repository` is missing from the event payload - # -- which is why this used to fall back to Blacksmith -- the name is - # empty and Blacksmith still catches it, because an empty label matches - # no runner at all and the job would queue until someone cancels it. + # hbr1, which also hosts production containers (the org's Default runner + # group refuses public repositories as a second line). A private repo goes + # to `grounds-runners`, the shared self-hosted ARC pool (org-level, on + # hbr1 today). And if `repository` is missing from the event payload, the + # job lands on hosted amd64 `ubuntu-24.04`, which exists for public and + # private repos alike -- hosted arm64 does not exist for private ones, and + # a label no runner matches queues until someone cancels the job. runs-on: >- ${{ (github.event.repository.visibility == 'public' && 'ubuntu-24.04-arm') - || github.event.repository.name - || 'blacksmith-2vcpu-ubuntu-2404-arm' }} + || (github.event.repository.name && 'grounds-runners') + || 'ubuntu-24.04' }} timeout-minutes: 20 permissions: pull-requests: write @@ -386,22 +384,20 @@ jobs: # ── Evict on PR close ───────────────────────────────────────────── evict: if: github.event.action == 'closed' - # Self-hosted ARC runners on hbr1. The label is the calling repository's - # own name, which is how each repo reaches its own scale set without - # passing anything. - # # Read the three branches in order. A public repo keeps a GitHub-hosted # runner: on a self-hosted pool a fork PR would run arbitrary code on - # hbr1, which also hosts production containers. A private repo goes to - # its own runner. And if `repository` is missing from the event payload - # -- which is why this used to fall back to Blacksmith -- the name is - # empty and Blacksmith still catches it, because an empty label matches - # no runner at all and the job would queue until someone cancels it. + # hbr1, which also hosts production containers (the org's Default runner + # group refuses public repositories as a second line). A private repo goes + # to `grounds-runners`, the shared self-hosted ARC pool (org-level, on + # hbr1 today). And if `repository` is missing from the event payload, the + # job lands on hosted amd64 `ubuntu-24.04`, which exists for public and + # private repos alike -- hosted arm64 does not exist for private ones, and + # a label no runner matches queues until someone cancels the job. runs-on: >- ${{ (github.event.repository.visibility == 'public' && 'ubuntu-24.04-arm') - || github.event.repository.name - || 'blacksmith-2vcpu-ubuntu-2404-arm' }} + || (github.event.repository.name && 'grounds-runners') + || 'ubuntu-24.04' }} timeout-minutes: 10 steps: - name: Mint forge access token diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 1bdd54b..6579baf 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -14,27 +14,25 @@ concurrency: jobs: release-please: name: Create Release - # Free GitHub-hosted runner in public repos; Blacksmith in private ones, + # Free GitHub-hosted runner in public repos; `grounds-runners` in private ones, # where GitHub-hosted arm64 is not offered. Tests `visibility` rather than # `repository.private` because GitHub coerces `==` operands to numbers, so # an absent `private` field would compare equal to false and hand a private # repo a label that does not exist there. - # Self-hosted ARC runners on hbr1. The label is the calling repository's - # own name, which is how each repo reaches its own scale set without - # passing anything. - # # Read the three branches in order. A public repo keeps a GitHub-hosted # runner: on a self-hosted pool a fork PR would run arbitrary code on - # hbr1, which also hosts production containers. A private repo goes to - # its own runner. And if `repository` is missing from the event payload - # -- which is why this used to fall back to Blacksmith -- the name is - # empty and Blacksmith still catches it, because an empty label matches - # no runner at all and the job would queue until someone cancels it. + # hbr1, which also hosts production containers (the org's Default runner + # group refuses public repositories as a second line). A private repo goes + # to `grounds-runners`, the shared self-hosted ARC pool (org-level, on + # hbr1 today). And if `repository` is missing from the event payload, the + # job lands on hosted amd64 `ubuntu-24.04`, which exists for public and + # private repos alike -- hosted arm64 does not exist for private ones, and + # a label no runner matches queues until someone cancels the job. runs-on: >- ${{ (github.event.repository.visibility == 'public' && 'ubuntu-24.04-arm') - || github.event.repository.name - || 'blacksmith-2vcpu-ubuntu-2404-arm' }} + || (github.event.repository.name && 'grounds-runners') + || 'ubuntu-24.04' }} timeout-minutes: 10 steps: - name: Checkout code diff --git a/tests/test_docker_workflow.py b/tests/test_docker_workflow.py index 6de4510..d9cf7f1 100644 --- a/tests/test_docker_workflow.py +++ b/tests/test_docker_workflow.py @@ -74,7 +74,7 @@ def test_build_and_cache_contract_for_public_and_private_events(self): self.assertEqual(len(pushes), 1) self.assertEqual(len(cache_writes), 1) self.assertEqual(cache_writes[0]['with']['cache-to'], '${{ steps.layer_cache.outputs.to }}') - expected_runner = 'ubuntu-24.04' if visibility == 'public' else 'plugin-notifications' + expected_runner = 'ubuntu-24.04' if visibility == 'public' else 'grounds-runners' self.assertEqual(resolve(job['runs-on'], context).strip(), expected_runner) expected_budget = 30 if visibility == 'public' else 60 self.assertEqual(int(resolve(job['timeout-minutes'], context)), expected_budget) @@ -149,6 +149,34 @@ def test_cold_arc_budget_preserves_hosted_override_and_fallback_limits(self): self.assertEqual(budget, expected) self.assertLessEqual(budget, 60) + def test_every_central_workflow_routes_private_repos_to_the_shared_pool(self): + """Public -> GitHub-hosted, private -> grounds-runners, no payload -> hosted amd64. + + The last case matters: hosted arm64 does not exist for private repos, and a + public repo sent to the self-hosted pool is refused by the org's runner group, + so either wrong guess queues a job forever. + """ + checked = 0 + for path in sorted(WORKFLOW.parent.glob('*.yml')): + jobs = (yaml.safe_load(path.read_text()) or {}).get('jobs', {}) + for name, job in jobs.items(): + runs_on = job.get('runs-on') + if not isinstance(runs_on, str) or 'grounds-runners' not in runs_on: + continue + checked += 1 + base = {'inputs.runner': ''} + with self.subTest(workflow=path.name, job=name): + private = resolve(runs_on, {**base, 'github.event.repository.visibility': 'private', + 'github.event.repository.name': 'plugin-match'}).strip() + self.assertEqual(private, 'grounds-runners') + public = resolve(runs_on, {**base, 'github.event.repository.visibility': 'public', + 'github.event.repository.name': 'service-maps'}).strip() + self.assertTrue(public.startswith('ubuntu-24.04'), public) + missing = resolve(runs_on, {**base, 'github.event.repository.visibility': '', + 'github.event.repository.name': ''}).strip() + self.assertEqual(missing, 'ubuntu-24.04') + self.assertEqual(checked, 9, 'every repo-routed job should target the shared pool') + def test_runner_override_and_missing_event_payload(self): job = yaml.safe_load(WORKFLOW.read_text())['jobs']['docker-build-push'] context = {'inputs.runner': '', 'github.event.repository.visibility': '', 'github.event.repository.name': ''}