Skip to content

Commit da56246

Browse files
chore(ci): add CI_PROVIDER toggle between Blacksmith and GitHub-hosted runners (#5808)
* chore(ci): add CI_PROVIDER toggle between Blacksmith and GitHub-hosted runners * chore(ci): fail unrecognized CI_PROVIDER values over to GitHub-hosted runners
1 parent 5be35b5 commit da56246

9 files changed

Lines changed: 178 additions & 57 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Cache Mount
2+
description: Mount a build cache directory using Blacksmith sticky disks, or the GitHub Actions cache when running on GitHub-hosted runners.
3+
4+
inputs:
5+
provider:
6+
description: Empty or 'blacksmith' selects sticky disks. Any other value selects actions/cache. Must stay byte-identical to the runs-on predicate in the calling workflow.
7+
required: false
8+
default: ''
9+
key:
10+
description: Cache key. Shared by both backends, so callers keep one key regardless of provider.
11+
required: true
12+
path:
13+
description: Filesystem path the cache is mounted at.
14+
required: true
15+
16+
# The two conditions are exact complements of the runs-on expression the caller
17+
# uses. They must be inverted together: a job placed on ubuntu-latest that then
18+
# took the sticky-disk branch would hard-fail, since stickydisk hot-mounts an
19+
# ext4 volume from Blacksmith's storage agents and cannot run anywhere else.
20+
runs:
21+
using: composite
22+
steps:
23+
- name: Mount sticky disk
24+
if: inputs.provider == '' || inputs.provider == 'blacksmith'
25+
uses: useblacksmith/stickydisk@4c034ba57b706cf0e3b4b0ce098c2a3b1071580c # v1
26+
with:
27+
key: ${{ inputs.key }}
28+
path: ${{ inputs.path }}
29+
30+
# Sticky disks always re-commit the mounted path, so the cache rolls forward
31+
# every run. actions/cache skips its save step on an exact key hit, which
32+
# would freeze the cache at whatever the first run wrote — the run-scoped
33+
# suffix plus a prefix restore-key reproduces the rolling behaviour.
34+
- name: Restore and save cache
35+
if: inputs.provider != '' && inputs.provider != 'blacksmith'
36+
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
37+
with:
38+
key: ${{ inputs.key }}-${{ github.run_id }}
39+
restore-keys: ${{ inputs.key }}-
40+
path: ${{ inputs.path }}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: Docker Build and Push
2+
description: Set up a buildx builder and build/push an image, using Blacksmith's builder or the upstream Docker actions on GitHub-hosted runners.
3+
4+
inputs:
5+
provider:
6+
description: Empty or 'blacksmith' selects Blacksmith's builder. Any other value selects the upstream docker/* actions. Must stay byte-identical to the runs-on predicate in the calling workflow.
7+
required: false
8+
default: ''
9+
context:
10+
description: Build context.
11+
required: false
12+
default: .
13+
file:
14+
description: Path to the Dockerfile.
15+
required: true
16+
platforms:
17+
description: Target platforms, e.g. linux/amd64.
18+
required: true
19+
tags:
20+
description: Comma-separated list of tags to push.
21+
required: true
22+
23+
# Registry logins must already have run in the calling job — both backends read
24+
# the same ~/.docker/config.json. provenance/sbom stay off everywhere: the
25+
# attestation manifests they add break `imagetools create` retagging in the
26+
# promote-images and create-ghcr-manifests jobs.
27+
runs:
28+
using: composite
29+
steps:
30+
- name: Set up Blacksmith builder
31+
if: inputs.provider == '' || inputs.provider == 'blacksmith'
32+
uses: useblacksmith/setup-docker-builder@ab5c1da94f53f5cd75c1038092aa276dddfccbba # v1
33+
34+
- name: Build and push (Blacksmith)
35+
if: inputs.provider == '' || inputs.provider == 'blacksmith'
36+
uses: useblacksmith/build-push-action@fb9e3e6a9299c78462bfadd0d93352c316adc9b8 # v2
37+
with:
38+
context: ${{ inputs.context }}
39+
file: ${{ inputs.file }}
40+
platforms: ${{ inputs.platforms }}
41+
push: true
42+
tags: ${{ inputs.tags }}
43+
provenance: false
44+
sbom: false
45+
46+
- name: Set up Docker Buildx
47+
if: inputs.provider != '' && inputs.provider != 'blacksmith'
48+
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4
49+
50+
# No layer cache here. Blacksmith caches layers on the builder itself;
51+
# the GitHub equivalent (cache-to: type=gha) shares the same 10 GB repo
52+
# cache quota as the bun/node_modules/turbo mounts, and four images of
53+
# layers would evict them. Fallback builds are cold by design.
54+
- name: Build and push (GitHub)
55+
if: inputs.provider != '' && inputs.provider != 'blacksmith'
56+
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
57+
with:
58+
context: ${{ inputs.context }}
59+
file: ${{ inputs.file }}
60+
platforms: ${{ inputs.platforms }}
61+
push: true
62+
tags: ${{ inputs.tags }}
63+
provenance: false
64+
sbom: false

.github/workflows/ci.yml

Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,33 @@
11
name: CI
22

3+
# Runner provider toggle. Every job here and in the reusable workflows reads the
4+
# CI_PROVIDER repository variable:
5+
#
6+
# gh variable set CI_PROVIDER --body github # fall back to GitHub-hosted
7+
# gh variable delete CI_PROVIDER # back to Blacksmith (default)
8+
#
9+
# It is a repo variable rather than a committed value on purpose: during a
10+
# Blacksmith outage there is no working CI to merge a switchover commit through,
11+
# and the variable takes effect on the next run with nothing to land.
12+
#
13+
# Only unset or the exact value 'blacksmith' selects Blacksmith; everything else
14+
# selects GitHub-hosted. The unrecognized case resolves toward GitHub on purpose,
15+
# because that is the provider that is always available: a typo'd or whitespace-
16+
# padded break-glass value then yields slow-but-working CI instead of jobs queued
17+
# forever against the provider you were trying to escape. `==` is case-insensitive
18+
# in Actions expressions, so 'GitHub' and 'Blacksmith' both work. Every runs-on
19+
# expression and both composite actions use this same predicate — they must be
20+
# changed together, since a job on ubuntu-latest that took a Blacksmith-only
21+
# branch would hard-fail.
22+
#
23+
# GitHub mode is a break-glass fallback, not a peer. Public-repo ubuntu-latest is
24+
# 4 vCPU with no free 8-core tier, the 10 GB repo cache quota will thrash across
25+
# the bun/node_modules/turbo mounts, and image builds start from cold layers — so
26+
# expect slower runs, not different results. Blacksmith-only actions are reached
27+
# exclusively through .github/actions/cache-mount and .github/actions/docker-build,
28+
# which branch internally; a bare useblacksmith/* step added anywhere else will
29+
# hard-fail in GitHub mode rather than silently degrade.
30+
331
on:
432
push:
533
branches: [main, staging, dev]
@@ -28,7 +56,7 @@ jobs:
2856
# Detect if this is a version release commit (e.g., "v0.5.24: ...")
2957
detect-version:
3058
name: Detect Version
31-
runs-on: blacksmith-4vcpu-ubuntu-2404
59+
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }}
3260
timeout-minutes: 5
3361
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging' || github.ref == 'refs/heads/dev')
3462
outputs:
@@ -81,7 +109,7 @@ jobs:
81109
name: Build Dev ECR
82110
needs: [detect-version, migrate-dev]
83111
if: github.event_name == 'push' && github.ref == 'refs/heads/dev'
84-
runs-on: blacksmith-8vcpu-ubuntu-2404
112+
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-latest' }}
85113
timeout-minutes: 30
86114
permissions:
87115
contents: read
@@ -118,25 +146,19 @@ jobs:
118146
username: ${{ secrets.DOCKERHUB_USERNAME }}
119147
password: ${{ secrets.DOCKERHUB_TOKEN }}
120148

121-
- name: Set up Docker Buildx
122-
uses: useblacksmith/setup-docker-builder@ab5c1da94f53f5cd75c1038092aa276dddfccbba # v1
123-
124149
- name: Resolve ECR repo name
125150
id: ecr-repo
126151
run: echo "name=$ECR_REPO" >> $GITHUB_OUTPUT
127152
env:
128153
ECR_REPO: ${{ matrix.ecr_repo_secret == 'ECR_APP' && secrets.ECR_APP || matrix.ecr_repo_secret == 'ECR_MIGRATIONS' && secrets.ECR_MIGRATIONS || matrix.ecr_repo_secret == 'ECR_REALTIME' && secrets.ECR_REALTIME || matrix.ecr_repo_secret == 'ECR_PII' && secrets.ECR_PII || '' }}
129154

130155
- name: Build and push
131-
uses: useblacksmith/build-push-action@fb9e3e6a9299c78462bfadd0d93352c316adc9b8 # v2
156+
uses: ./.github/actions/docker-build
132157
with:
133-
context: .
158+
provider: ${{ vars.CI_PROVIDER }}
134159
file: ${{ matrix.dockerfile }}
135160
platforms: linux/amd64
136-
push: true
137161
tags: ${{ steps.login-ecr.outputs.registry }}/${{ steps.ecr-repo.outputs.name }}:dev
138-
provenance: false
139-
sbom: false
140162

141163
# Dev: deploy Trigger.dev background tasks to the preview "dev-sim" branch.
142164
# Gated after migrate-dev for the same reason as build-dev — the new task
@@ -145,7 +167,7 @@ jobs:
145167
name: Deploy Trigger.dev (Dev)
146168
needs: [migrate-dev]
147169
if: github.event_name == 'push' && github.ref == 'refs/heads/dev'
148-
runs-on: blacksmith-4vcpu-ubuntu-2404
170+
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }}
149171
timeout-minutes: 15
150172
steps:
151173
- name: Checkout code
@@ -192,7 +214,7 @@ jobs:
192214
if: >-
193215
github.event_name == 'push' &&
194216
(github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging')
195-
runs-on: blacksmith-8vcpu-ubuntu-2404
217+
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-latest' }}
196218
timeout-minutes: 30
197219
permissions:
198220
contents: read
@@ -242,9 +264,6 @@ jobs:
242264
username: ${{ github.repository_owner }}
243265
password: ${{ secrets.GITHUB_TOKEN }}
244266

245-
- name: Set up Docker Buildx
246-
uses: useblacksmith/setup-docker-builder@ab5c1da94f53f5cd75c1038092aa276dddfccbba # v1
247-
248267
- name: Resolve ECR repo name
249268
id: ecr-repo
250269
run: echo "name=$ECR_REPO" >> $GITHUB_OUTPUT
@@ -270,15 +289,12 @@ jobs:
270289
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
271290
272291
- name: Build and push images
273-
uses: useblacksmith/build-push-action@fb9e3e6a9299c78462bfadd0d93352c316adc9b8 # v2
292+
uses: ./.github/actions/docker-build
274293
with:
275-
context: .
294+
provider: ${{ vars.CI_PROVIDER }}
276295
file: ${{ matrix.dockerfile }}
277296
platforms: linux/amd64
278-
push: true
279297
tags: ${{ steps.meta.outputs.tags }}
280-
provenance: false
281-
sbom: false
282298

283299
# Promote the sha-tagged ECR images to the deploy tags once tests and
284300
# migrations pass. Pushing the ECR latest/staging tag is what triggers
@@ -292,7 +308,7 @@ jobs:
292308
if: >-
293309
github.event_name == 'push' &&
294310
(github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging')
295-
runs-on: blacksmith-2vcpu-ubuntu-2404
311+
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-2vcpu-ubuntu-2404' || 'ubuntu-latest' }}
296312
timeout-minutes: 10
297313
permissions:
298314
contents: read
@@ -362,7 +378,7 @@ jobs:
362378
# never moves a documented tag.
363379
build-ghcr-arm64:
364380
name: Build ARM64 (GHCR Only)
365-
runs-on: blacksmith-8vcpu-ubuntu-2404-arm
381+
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-8vcpu-ubuntu-2404-arm' || 'ubuntu-24.04-arm' }}
366382
timeout-minutes: 30
367383
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
368384
permissions:
@@ -392,26 +408,20 @@ jobs:
392408
username: ${{ github.repository_owner }}
393409
password: ${{ secrets.GITHUB_TOKEN }}
394410

395-
- name: Set up Docker Buildx
396-
uses: useblacksmith/setup-docker-builder@ab5c1da94f53f5cd75c1038092aa276dddfccbba # v1
397-
398411
- name: Build and push ARM64 to GHCR
399-
uses: useblacksmith/build-push-action@fb9e3e6a9299c78462bfadd0d93352c316adc9b8 # v2
412+
uses: ./.github/actions/docker-build
400413
with:
401-
context: .
414+
provider: ${{ vars.CI_PROVIDER }}
402415
file: ${{ matrix.dockerfile }}
403416
platforms: linux/arm64
404-
push: true
405417
tags: ${{ matrix.image }}:${{ github.sha }}-arm64
406-
provenance: false
407-
sbom: false
408418

409419
# Publish all mutable GHCR tags (latest, latest-amd64/arm64, version tags)
410420
# and the multi-arch manifests from the immutable sha tags — only on main,
411421
# after the deploy gate (promote-images) and the ARM64 build both pass.
412422
create-ghcr-manifests:
413423
name: Create GHCR Manifests
414-
runs-on: blacksmith-2vcpu-ubuntu-2404
424+
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-2vcpu-ubuntu-2404' || 'ubuntu-latest' }}
415425
timeout-minutes: 10
416426
needs: [promote-images, build-ghcr-arm64, detect-version]
417427
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
@@ -477,7 +487,7 @@ jobs:
477487
# Check if docs changed
478488
check-docs-changes:
479489
name: Check Docs Changes
480-
runs-on: blacksmith-4vcpu-ubuntu-2404
490+
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }}
481491
timeout-minutes: 5
482492
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
483493
outputs:
@@ -506,7 +516,7 @@ jobs:
506516
# Create GitHub Release (only for version commits on main, after all builds complete)
507517
create-release:
508518
name: Create GitHub Release
509-
runs-on: blacksmith-4vcpu-ubuntu-2404
519+
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }}
510520
timeout-minutes: 10
511521
needs: [create-ghcr-manifests, detect-version]
512522
if: needs.detect-version.outputs.is_release == 'true'

.github/workflows/docs-embeddings.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ permissions:
1010
jobs:
1111
process-docs-embeddings:
1212
name: Process Documentation Embeddings
13-
runs-on: blacksmith-8vcpu-ubuntu-2404
13+
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-latest' }}
1414
timeout-minutes: 30
1515
if: github.ref == 'refs/heads/main'
1616

.github/workflows/migrations.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ permissions:
2424
jobs:
2525
migrate:
2626
name: Apply Database Migrations
27-
runs-on: blacksmith-4vcpu-ubuntu-2404
27+
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }}
2828
timeout-minutes: 45
2929

3030
steps:

.github/workflows/publish-cli.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ permissions:
1111

1212
jobs:
1313
publish-npm:
14-
runs-on: blacksmith-4vcpu-ubuntu-2404
14+
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }}
1515
timeout-minutes: 15
1616
steps:
1717
- name: Checkout repository

.github/workflows/publish-python-sdk.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ permissions:
1111

1212
jobs:
1313
publish-pypi:
14-
runs-on: blacksmith-4vcpu-ubuntu-2404
14+
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }}
1515
timeout-minutes: 15
1616
steps:
1717
- name: Checkout repository

.github/workflows/publish-ts-sdk.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ permissions:
1111

1212
jobs:
1313
publish-npm:
14-
runs-on: blacksmith-4vcpu-ubuntu-2404
14+
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }}
1515
timeout-minutes: 15
1616
steps:
1717
- name: Checkout repository

0 commit comments

Comments
 (0)