release-image.yml108 lines · main
1name: release-image
2
3# Builds + publishes the briven self-host container images on every
4# `v*` tag pushed to main. Five separate images — one per app — under
5# ghcr.io/flndrn/briven-<app>:<version>. Multi-arch (amd64 + arm64) so
6# M-series Mac developers and ARM VPS can pull without QEMU.
7#
8# Required repo permissions: `packages: write` (granted by the
9# permissions block below — uses the workflow's GITHUB_TOKEN, no PAT
10# needed).
11#
12# Tag strategy:
13# v0.3.1 → :0.3.1, :0.3, :0 (stable) and :latest
14# v0.3.1-beta.2 → :0.3.1-beta.2 only (no :latest, no major/minor float)
15# (metadata-action handles the differentiation via flavor.latest=auto +
16# the semver/match patterns below).
17
18on:
19 push:
20 tags:
21 - 'v*'
22 # workflow_dispatch lets you re-build a release from the Actions UI
23 # without retagging — useful if a build node was flaky.
24 workflow_dispatch:
25 inputs:
26 tag:
27 description: 'Tag to build (e.g. v0.3.1)'
28 required: true
29
30concurrency:
31 group: ${{ github.workflow }}-${{ github.event.inputs.tag || github.ref }}
32 cancel-in-progress: false
33
34permissions:
35 contents: read
36 packages: write
37
38env:
39 REGISTRY: ghcr.io
40 IMAGE_OWNER: flndrn
41
42jobs:
43 publish:
44 name: publish · ${{ matrix.app }}
45 runs-on: ubuntu-latest
46 strategy:
47 fail-fast: false
48 matrix:
49 app: [api, runtime, realtime, web, docs]
50 steps:
51 - name: checkout
52 uses: actions/checkout@v6
53 with:
54 ref: ${{ github.event.inputs.tag || github.ref }}
55
56 - name: set up qemu (for arm64 cross-build)
57 uses: docker/setup-qemu-action@v3
58 with:
59 platforms: arm64
60
61 - name: set up buildx
62 uses: docker/setup-buildx-action@v3
63
64 - name: login to ghcr.io
65 uses: docker/login-action@v3
66 with:
67 registry: ${{ env.REGISTRY }}
68 username: ${{ github.actor }}
69 password: ${{ secrets.GITHUB_TOKEN }}
70
71 - name: extract metadata
72 id: meta
73 uses: docker/metadata-action@v5
74 with:
75 images: ${{ env.REGISTRY }}/${{ env.IMAGE_OWNER }}/briven-${{ matrix.app }}
76 # Tag the image with: full semver, major.minor, major (when
77 # stable), and `latest` (when stable, controlled by
78 # flavor.latest=auto). Pre-releases get only the full version.
79 tags: |
80 type=semver,pattern={{version}}
81 type=semver,pattern={{major}}.{{minor}}
82 type=semver,pattern={{major}}
83 flavor: |
84 latest=auto
85
86 - name: build + push
87 uses: docker/build-push-action@v6
88 with:
89 context: .
90 file: apps/${{ matrix.app }}/Dockerfile
91 # arm64 build is slower (qemu-emulated) but worth it — a
92 # majority of self-hosters run amd64 VPS, the ARM minority is
93 # macOS local + raspberry-pi-class boxes which still need an
94 # image. If build time becomes painful, drop arm64 from the
95 # release matrix and offer a separate "request arm build"
96 # workflow_dispatch path.
97 platforms: linux/amd64,linux/arm64
98 push: true
99 tags: ${{ steps.meta.outputs.tags }}
100 labels: ${{ steps.meta.outputs.labels }}
101 # Cache layers between matrix runs + across tags — keyed on
102 # the app so api's cache doesn't bleed into web's.
103 cache-from: type=gha,scope=${{ matrix.app }}
104 cache-to: type=gha,scope=${{ matrix.app }},mode=max
105 # Provenance + SBOM attestations land in the OCI manifest.
106 # Useful for downstream security scans + verifiable builds.
107 provenance: true
108 sbom: true