Skip to content

Commit 0e00efc

Browse files
committed
chore: migrate techlabblog to docker buildx bake
Introduces a docker buildx bake-based build system for the monorepo, migrating techlabblog as the first app. The root Dockerfile and dc.sh path remain untouched for all other apps — this is an incremental migration.
1 parent 35692d3 commit 0e00efc

File tree

12 files changed

+816
-22
lines changed

12 files changed

+816
-22
lines changed

.dockerignore

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,67 @@
1-
# Include application-specific Dockerfiles e.g. charterafrica.Dockerfile
1+
2+
# -----------------------------------------------------------------------------
3+
# Docker build context filtering for monorepo builds
4+
# Goal: keep context small while preserving files needed by turbo prune/build.
5+
# -----------------------------------------------------------------------------
6+
7+
# Exclude Dockerfiles by default, then explicitly keep the ones bake uses.
28
*Dockerfile
9+
!Dockerfile
10+
!docker/base.Dockerfile
11+
!docker/apps/*.Dockerfile
12+
13+
# Docker metadata
314
.dockerignore
15+
16+
# VCS / CI / editor metadata (not needed in image builds)
17+
.git
18+
.github
19+
.DS_Store
20+
**/.vscode
21+
**/.idea
22+
23+
# Dependency directories
424
**/node_modules
25+
**/.pnpm-store
26+
27+
# Package manager / tooling logs
528
npm-debug.log
629
.pnpm-debug.log
30+
**/*.log
31+
32+
# Local docs / notes not used for builds
733
README.md
8-
**/.env.local
34+
docker/README.md
35+
36+
# Local env overrides (sensitive / machine-specific)
37+
# Keep checked-in .env files included; only ignore .env.local
38+
**/.env*.local
39+
40+
# Framework/build caches and outputs
941
**/.next
1042
**/.turbo
11-
**/.vscode
43+
**/.cache
44+
**/.swc
45+
**/.eslintcache
46+
**/.nyc_output
1247
**/build
48+
**/coverage
49+
**/dist
50+
**/storybook-static
51+
**/*.tsbuildinfo
52+
53+
# App/static media export folders (if generated)
1354
**/media
55+
56+
# Databases / sqlite artifacts
57+
**/*.db
58+
**/*.sqlite
59+
**/*.sqlite3
60+
61+
# Temp folders
62+
**/tmp
63+
**/temp
64+
65+
# Local-only repo artifacts
66+
mongo-keyfile
67+
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
name: Bake and Push
2+
3+
# Reusable workflow for building and pushing a bake target.
4+
# Replaces build-docker-image.yml for apps migrated to docker-bake.hcl.
5+
#
6+
# Callers pass app-specific build args via the `set` input using GitHub Variables
7+
# (vars.*) for NEXT_PUBLIC_* values — these are public by design and belong in
8+
# vars, not secrets. Sentry secrets are declared explicitly below.
9+
10+
on:
11+
workflow_call:
12+
inputs:
13+
target:
14+
required: true
15+
type: string
16+
description: "Bake target name (e.g. techlabblog)"
17+
tag:
18+
required: true
19+
type: string
20+
description: "Image tag to push (e.g. git SHA or semver)"
21+
base_tag:
22+
required: false
23+
type: string
24+
default: ""
25+
description: >
26+
Pre-built base image tag (BASE_TAG). When set, pulls ui-builder-base
27+
and ui-runner-base from the registry instead of building them inline.
28+
Use this in CI to avoid rebuilding base images on every app push.
29+
Omit (or leave empty) to build base images inline — useful when
30+
testing base image changes locally via act or in build-base-images.yml.
31+
platforms:
32+
required: false
33+
type: string
34+
default: "linux/amd64,linux/arm64"
35+
description: "Target platforms (comma-separated). Override to build for a single platform."
36+
set:
37+
required: false
38+
type: string
39+
default: ""
40+
description: >
41+
Extra bake --set overrides (newline-separated target.field=value pairs).
42+
Use this to inject app-specific build args, e.g.:
43+
techlabblog.args.NEXT_PUBLIC_APP_URL=${{ vars.TECHLABBLOG_APP_URL }}
44+
Note: GitHub Variables (vars.*) are available here; secrets are not —
45+
pass truly secret build args via the declared secrets inputs below.
46+
secrets:
47+
DOCKER_HUB_USERNAME:
48+
required: true
49+
DOCKER_HUB_ACCESS_TOKEN:
50+
required: true
51+
# Sentry secrets: sourced from env by BuildKit secret mounts in Dockerfiles
52+
# (--mount=type=secret,id=sentry_auth_token,env=SENTRY_AUTH_TOKEN).
53+
# Mark required: false so apps without Sentry can use this workflow too.
54+
SENTRY_AUTH_TOKEN:
55+
required: false
56+
SENTRY_ORG:
57+
required: false
58+
SENTRY_PROJECT:
59+
required: false
60+
61+
jobs:
62+
bake:
63+
runs-on: ubuntu-latest
64+
65+
steps:
66+
- uses: actions/checkout@v4
67+
with:
68+
fetch-depth: 1
69+
70+
- name: Build metadata
71+
id: meta
72+
run: echo "date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT"
73+
74+
- uses: docker/setup-qemu-action@v3
75+
76+
- uses: docker/setup-buildx-action@v3
77+
78+
- uses: docker/login-action@v3
79+
with:
80+
username: ${{ secrets.DOCKER_HUB_USERNAME }}
81+
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
82+
83+
- name: Build and push
84+
uses: docker/bake-action@v6
85+
env:
86+
TAG: ${{ inputs.tag }}
87+
BASE_TAG: ${{ inputs.base_tag }}
88+
GIT_REVISION: ${{ github.sha }}
89+
BUILD_DATE: ${{ steps.meta.outputs.date }}
90+
# Sentry secrets: exposed to BuildKit as secret mounts (not build args).
91+
# See --mount=type=secret,id=sentry_auth_token,env=SENTRY_AUTH_TOKEN
92+
# in app Dockerfiles.
93+
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
94+
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
95+
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
96+
with:
97+
files: docker-bake.hcl
98+
targets: ${{ inputs.target }}
99+
push: true
100+
set: |
101+
*.cache-from=type=gha,scope=${{ inputs.target }}
102+
*.cache-to=type=gha,mode=max,scope=${{ inputs.target }}
103+
*.platforms=${{ inputs.platforms }}
104+
${{ inputs.set }}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
name: Build Base Images
2+
3+
# Builds and pushes ui-builder-base and ui-runner-base to DockerHub.
4+
#
5+
# Base images have an independent version lifecycle from apps — they only change
6+
# when Node.js, pnpm, Alpine, or turbo tooling changes. They are NOT rebuilt on
7+
# every app push. See docker/README.md for the full rationale.
8+
#
9+
# Workflow:
10+
# 1. Update NODE_VERSION / PNPM_VERSION / TURBO_VERSION in docker-bake.hcl.
11+
# 2. Run this workflow with the next version tag (e.g. v4).
12+
# 3. Update BASE_TAG in app CI workflows (e.g. techlabblog.yml) to the new tag.
13+
#
14+
# The tag (e.g. v3) is separate from app image tags and from the Node version
15+
# string. It tracks the iteration of the base image configuration.
16+
17+
on:
18+
workflow_dispatch:
19+
inputs:
20+
tag:
21+
description: "Base image tag to publish (e.g. v3)"
22+
required: true
23+
type: string
24+
25+
jobs:
26+
build:
27+
runs-on: ubuntu-latest
28+
29+
steps:
30+
- uses: actions/checkout@v4
31+
32+
- name: Build metadata
33+
id: meta
34+
run: echo "date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT"
35+
36+
- uses: docker/setup-qemu-action@v3
37+
38+
- uses: docker/setup-buildx-action@v3
39+
40+
- uses: docker/login-action@v3
41+
with:
42+
username: ${{ secrets.DOCKER_HUB_USERNAME }}
43+
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
44+
45+
- name: Build and push base images
46+
uses: docker/bake-action@v6
47+
env:
48+
TAG: ${{ inputs.tag }}
49+
GIT_REVISION: ${{ github.sha }}
50+
BUILD_DATE: ${{ steps.meta.outputs.date }}
51+
with:
52+
files: docker-bake.hcl
53+
targets: base
54+
push: true
55+
set: |
56+
*.cache-from=type=gha,scope=ui-base
57+
*.cache-to=type=gha,mode=max,scope=ui-base
58+
*.platforms=linux/amd64,linux/arm64

.github/workflows/techlabblog.yml

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
name: TechLab Blog
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- "apps/techlabblog/**"
9+
- "docker/apps/techlabblog.Dockerfile"
10+
- "docker/base.Dockerfile"
11+
- "docker-bake.hcl"
12+
- ".github/workflows/techlabblog.yml"
13+
- ".github/workflows/bake-and-push.yml"
14+
15+
# Cancel in-progress runs for the same branch so a fast-follow push doesn't
16+
# queue behind a slow build.
17+
concurrency:
18+
group: "${{ github.workflow }} @ ${{ github.ref }}"
19+
cancel-in-progress: true
20+
21+
jobs:
22+
# Checks whether apps/techlabblog/package.json has a version bump.
23+
# The prod deploy is gated on this: every push triggers a build, but only
24+
# a version bump triggers a prod deploy.
25+
version-check:
26+
runs-on: ubuntu-latest
27+
outputs:
28+
changed: ${{ steps.check.outputs.changed }}
29+
version: ${{ steps.check.outputs.version }}
30+
steps:
31+
- uses: actions/checkout@v4
32+
with:
33+
fetch-depth: 0
34+
35+
# EndBug/version-check requires Node.js — it ships as a JS action.
36+
# https://github.com/EndBug/version-check#github-workflow
37+
- uses: actions/setup-node@v4
38+
with:
39+
node-version: lts/*
40+
41+
- name: Check if version is bumped
42+
id: check
43+
uses: EndBug/version-check@v2
44+
with:
45+
# Search every commit's diff, not just the commit message. This catches
46+
# version bumps that aren't mentioned in the commit message.
47+
diff-search: true
48+
file-name: apps/techlabblog/package.json
49+
50+
# Builds the techlabblog image and pushes it to DockerHub. Always tagged with
51+
# the git SHA. When the version is bumped, also tagged with the semver and
52+
# `latest` — all three pushed in a single bake invocation.
53+
#
54+
# Tag strategy:
55+
# codeforafrica/techlabblog:<sha> — every push (immutable, for tracing)
56+
# codeforafrica/techlabblog:<version> — version bump only (immutable, for releases)
57+
# codeforafrica/techlabblog:latest — version bump only (mutable, for convenience)
58+
#
59+
# NEXT_PUBLIC_* vars are baked into the JS bundle at build time and cannot
60+
# be changed by restarting the container. Configure them as GitHub Variables
61+
# (Settings > Variables > Actions) rather than secrets since they are public
62+
# by definition (they ship to the browser).
63+
#
64+
# Required GitHub Variables:
65+
# TECHLABBLOG_SENTRY_DSN — public Sentry DSN (safe to use vars, not secrets)
66+
#
67+
# Required GitHub Secrets (for Sentry source map upload during build):
68+
# SENTRY_AUTH_TOKEN, SENTRY_ORG, TECHLABBLOG_SENTRY_PROJECT
69+
#
70+
# TODO: Set BASE_TAG below to a published base image version (e.g. v3) once
71+
# base images are built and pushed via build-base-images.yml. Until then,
72+
# base images are built inline (slower but correct).
73+
build:
74+
needs: version-check
75+
uses: ./.github/workflows/bake-and-push.yml
76+
with:
77+
target: techlabblog
78+
tag: ${{ github.sha }}
79+
# base_tag: v3
80+
set: |
81+
techlabblog.args.NEXT_PUBLIC_SENTRY_DSN=${{ vars.TECHLABBLOG_SENTRY_DSN }}
82+
${{ needs.version-check.outputs.changed == 'true' && format('techlabblog.tags[]=codeforafrica/techlabblog:{0}', needs.version-check.outputs.version) || '' }}
83+
${{ needs.version-check.outputs.changed == 'true' && 'techlabblog.tags[]=codeforafrica/techlabblog:latest' || '' }}
84+
secrets:
85+
DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }}
86+
DOCKER_HUB_ACCESS_TOKEN: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
87+
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
88+
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
89+
SENTRY_PROJECT: ${{ secrets.TECHLABBLOG_SENTRY_PROJECT }}
90+
91+
# TODO: No DEV Dokku app exists for techlabblog yet.
92+
# Enable this job (remove `if: false`) when the app is created on ui-1.dev
93+
# and update the git_remote_url below.
94+
deploy-dev:
95+
if: false
96+
needs: build
97+
uses: ./.github/workflows/push-to-dokku.yml
98+
with:
99+
git_remote_url: "ssh://azureuser@ui-1.dev.codeforafrica.org/techlabblog-ui"
100+
deploy_docker_image: "codeforafrica/techlabblog:${{ github.sha }}"
101+
secrets: inherit
102+
103+
# Deploys to production when the package.json version is bumped.
104+
# Both version-check and build must pass before this job runs.
105+
deploy-prod:
106+
needs: [version-check, build]
107+
if: needs.version-check.outputs.changed == 'true'
108+
uses: ./.github/workflows/push-to-dokku.yml
109+
with:
110+
git_remote_url: "ssh://dokku@ui-2.prod.codeforafrica.org/techlabblog-ui"
111+
deploy_docker_image: "codeforafrica/techlabblog:${{ needs.version-check.outputs.version }}"
112+
secrets: inherit

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ roboshield:
3737
./scripts/dc.sh roboshield
3838

3939
techlabblog:
40-
./scripts/dc.sh techlabblog
40+
./scripts/bake-up.sh techlabblog
4141

4242
trustlab:
4343
./scripts/dc.sh trustlab

0 commit comments

Comments
 (0)