Skip to content

Commit 28ddb99

Browse files
committed
ci: add automated Docker image publishing to GHCR
1 parent 6765466 commit 28ddb99

2 files changed

Lines changed: 159 additions & 0 deletions

File tree

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
name: Build and Publish Docker Image
2+
3+
# Triggers:
4+
# 1. Push to master whose commit message starts with "chore: sync upstream v..."
5+
# (i.e. a clean auto-merge from teal-sync-upstream-release.yml)
6+
# 2. A pull_request with the "upstream-sync" label is merged to master
7+
# (i.e. a conflict resolution PR from teal-sync-upstream-release.yml)
8+
# 3. Manual dispatch — useful for rebuilding any version on demand.
9+
10+
on:
11+
push:
12+
branches:
13+
- master
14+
pull_request:
15+
types: [closed]
16+
workflow_dispatch:
17+
inputs:
18+
version:
19+
description: "Upstream version tag to label the image (e.g. v0.53.2). Defaults to the current latest upstream release."
20+
required: false
21+
22+
jobs:
23+
# ── Resolve whether this run should produce a build, and which version tag ──
24+
25+
resolve:
26+
name: Resolve version
27+
runs-on: ubuntu-latest
28+
outputs:
29+
should_build: ${{ steps.resolve.outputs.should_build }}
30+
version: ${{ steps.resolve.outputs.version }}
31+
steps:
32+
- name: Determine version and build gate
33+
id: resolve
34+
env:
35+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36+
run: |
37+
EVENT="${{ github.event_name }}"
38+
39+
if [[ "$EVENT" == "workflow_dispatch" ]]; then
40+
VERSION="${{ inputs.version }}"
41+
if [[ -z "$VERSION" ]]; then
42+
VERSION=$(gh api repos/metabase/metabase/releases/latest --jq '.tag_name')
43+
fi
44+
echo "should_build=true" >> "$GITHUB_OUTPUT"
45+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
46+
echo "Manual dispatch — building $VERSION"
47+
48+
elif [[ "$EVENT" == "push" ]]; then
49+
COMMIT_MSG="${{ github.event.head_commit.message }}"
50+
if [[ "$COMMIT_MSG" =~ ^chore:\ sync\ upstream\ (v[0-9]+\.[0-9x.]+) ]]; then
51+
VERSION="${BASH_REMATCH[1]}"
52+
echo "should_build=true" >> "$GITHUB_OUTPUT"
53+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
54+
echo "Sync commit detected — building $VERSION"
55+
else
56+
echo "should_build=false" >> "$GITHUB_OUTPUT"
57+
echo "Not a sync commit — skipping."
58+
fi
59+
60+
elif [[ "$EVENT" == "pull_request" ]]; then
61+
MERGED="${{ github.event.pull_request.merged }}"
62+
LABELS='${{ toJson(github.event.pull_request.labels.*.name) }}'
63+
BRANCH="${{ github.event.pull_request.head.ref }}"
64+
65+
if [[ "$MERGED" == "true" ]] && echo "$LABELS" | grep -q '"upstream-sync"'; then
66+
VERSION=$(echo "$BRANCH" | grep -oP 'v[0-9]+\.[0-9x.]+' || true)
67+
if [[ -z "$VERSION" ]]; then
68+
VERSION=$(gh api repos/metabase/metabase/releases/latest --jq '.tag_name')
69+
fi
70+
echo "should_build=true" >> "$GITHUB_OUTPUT"
71+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
72+
echo "Upstream-sync PR merged — building $VERSION"
73+
else
74+
echo "should_build=false" >> "$GITHUB_OUTPUT"
75+
echo "PR is not a merged upstream-sync — skipping."
76+
fi
77+
fi
78+
79+
# ── Build the Docker image and push to GHCR ──
80+
81+
build-and-push:
82+
name: Build and push to GHCR
83+
needs: resolve
84+
if: needs.resolve.outputs.should_build == 'true'
85+
runs-on: ubuntu-latest
86+
timeout-minutes: 90
87+
permissions:
88+
contents: read
89+
packages: write
90+
91+
steps:
92+
- name: Checkout
93+
uses: actions/checkout@v4
94+
95+
# Docker image names must be lowercase; github.repository preserves case.
96+
- name: Normalise image name
97+
id: image
98+
run: |
99+
echo "name=ghcr.io/$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" \
100+
>> "$GITHUB_OUTPUT"
101+
102+
- name: Set up Docker Buildx
103+
uses: docker/setup-buildx-action@v3
104+
105+
- name: Log in to GHCR
106+
uses: docker/login-action@v3
107+
with:
108+
registry: ghcr.io
109+
username: ${{ github.actor }}
110+
password: ${{ secrets.GITHUB_TOKEN }}
111+
112+
- name: Build and push
113+
uses: docker/build-push-action@v6
114+
with:
115+
context: .
116+
push: true
117+
build-args: |
118+
MB_EDITION=oss
119+
VERSION=${{ needs.resolve.outputs.version }}
120+
tags: |
121+
${{ steps.image.outputs.name }}:${{ needs.resolve.outputs.version }}
122+
${{ steps.image.outputs.name }}:latest
123+
# Layer cache stored in GitHub Actions cache — speeds up subsequent builds
124+
# significantly since the apt/JDK/Clojure install layers rarely change.
125+
cache-from: type=gha
126+
cache-to: type=gha,mode=max
127+
128+
- name: Summary
129+
run: |
130+
IMAGE="${{ steps.image.outputs.name }}"
131+
VERSION="${{ needs.resolve.outputs.version }}"
132+
{
133+
echo "### 🐳 Docker image published"
134+
echo ""
135+
echo "| Tag | Image |"
136+
echo "|-----|-------|"
137+
echo "| \`$VERSION\` | \`$IMAGE:$VERSION\` |"
138+
echo "| \`latest\` | \`$IMAGE:latest\` |"
139+
echo ""
140+
echo "\`\`\`bash"
141+
echo "docker pull $IMAGE:$VERSION"
142+
echo "\`\`\`"
143+
} >> "$GITHUB_STEP_SUMMARY"

README-TEAL.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,20 @@ Polls [metabase/metabase](https://github.com/metabase/metabase) for new releases
6464

6565
**Conflict resolution:** The three branding files above are the most likely to conflict. In each case, keep the Teal values — the upstream values for those specific keys will always be wrong for this fork.
6666

67+
### Docker Publishing — `teal-docker-publish.yml`
68+
69+
Builds the Metabase OSS image from the root `Dockerfile` and publishes it to the GitHub Container Registry (GHCR) after each successful upstream sync.
70+
71+
```bash
72+
docker pull ghcr.io/decode-development/metabase-teal:latest
73+
docker pull ghcr.io/decode-development/metabase-teal:v0.53.2 # specific version
74+
```
75+
76+
**Triggers:**
77+
- Push to `master` with a sync commit message (clean auto-merge)
78+
- Merge of a PR carrying the `upstream-sync` label (conflict resolution)
79+
- Manual dispatch — accepts an optional version tag, defaults to the current latest upstream release
80+
81+
> **Note:** The build compiles the full frontend and backend from source and takes approximately 60–90 minutes on a standard GitHub-hosted runner. Layer caching (`type=gha`) reduces this significantly on subsequent builds.
82+
6783

0 commit comments

Comments
 (0)