chore: move tag logic into bake file, drop all metadata-action steps
docker-bake.hcl now owns semver tag generation via HCL locals + a reusable img_tags() function: GIT_TAG="v4.1.5" → :4.1.5, :4.1, :latest on all images. The Docker job shrinks from 13 steps to 6 — no docker/metadata-action needed. CI simply passes GIT_TAG, COMMIT, BUILD_TIME as env vars to bake-action. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -148,13 +148,9 @@ jobs:
|
|||||||
# SENTRY_PROJECT: ui
|
# SENTRY_PROJECT: ui
|
||||||
|
|
||||||
# ── docker: build + push all images via docker bake ──────────────────────────
|
# ── docker: build + push all images via docker bake ──────────────────────────
|
||||||
# docker-bake.hcl defines all five targets. BuildKit builds them with maximum
|
# docker-bake.hcl owns all tag logic (semver, major.minor, latest) via HCL
|
||||||
# parallelism: backend/runner/pocketbase share the Go builder stage (compiled
|
# functions — no docker/metadata-action needed. BuildKit builds all five
|
||||||
# once), while caddy and ui build concurrently alongside the Go targets.
|
# targets in parallel, sharing the Go builder stage across backend/runner/pocketbase.
|
||||||
#
|
|
||||||
# Metadata (tags + labels) is generated per-image by docker/metadata-action
|
|
||||||
# (bake-target mode), then merged into a single bake call via the bake-action
|
|
||||||
# targets input — one Docker Hub login, one buildx invocation.
|
|
||||||
docker:
|
docker:
|
||||||
name: Docker
|
name: Docker
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -170,7 +166,6 @@ jobs:
|
|||||||
username: ${{ secrets.DOCKER_USER }}
|
username: ${{ secrets.DOCKER_USER }}
|
||||||
password: ${{ secrets.DOCKER_TOKEN }}
|
password: ${{ secrets.DOCKER_TOKEN }}
|
||||||
|
|
||||||
# ── Prepare ui build artifact ─────────────────────────────────────────────
|
|
||||||
- name: Download ui build artifacts
|
- name: Download ui build artifacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
@@ -182,80 +177,16 @@ jobs:
|
|||||||
grep -v '^build$' ui/.dockerignore > ui/.dockerignore.tmp
|
grep -v '^build$' ui/.dockerignore > ui/.dockerignore.tmp
|
||||||
mv ui/.dockerignore.tmp ui/.dockerignore
|
mv ui/.dockerignore.tmp ui/.dockerignore
|
||||||
|
|
||||||
# ── Generate per-image tags + labels (bake-target mode) ───────────────────
|
|
||||||
- name: Docker meta / backend
|
|
||||||
id: meta-backend
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: ${{ secrets.DOCKER_USER }}/libnovel-backend
|
|
||||||
bake-target: backend
|
|
||||||
tags: |
|
|
||||||
type=semver,pattern={{version}}
|
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
|
||||||
type=raw,value=latest
|
|
||||||
|
|
||||||
- name: Docker meta / runner
|
|
||||||
id: meta-runner
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: ${{ secrets.DOCKER_USER }}/libnovel-runner
|
|
||||||
bake-target: runner
|
|
||||||
tags: |
|
|
||||||
type=semver,pattern={{version}}
|
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
|
||||||
type=raw,value=latest
|
|
||||||
|
|
||||||
- name: Docker meta / pocketbase
|
|
||||||
id: meta-pocketbase
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: ${{ secrets.DOCKER_USER }}/libnovel-pocketbase
|
|
||||||
bake-target: pocketbase
|
|
||||||
tags: |
|
|
||||||
type=semver,pattern={{version}}
|
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
|
||||||
type=raw,value=latest
|
|
||||||
|
|
||||||
- name: Docker meta / ui
|
|
||||||
id: meta-ui
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: ${{ secrets.DOCKER_USER }}/libnovel-ui
|
|
||||||
bake-target: ui
|
|
||||||
tags: |
|
|
||||||
type=semver,pattern={{version}}
|
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
|
||||||
type=raw,value=latest
|
|
||||||
|
|
||||||
- name: Docker meta / caddy
|
|
||||||
id: meta-caddy
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: ${{ secrets.DOCKER_USER }}/libnovel-caddy
|
|
||||||
bake-target: caddy
|
|
||||||
tags: |
|
|
||||||
type=semver,pattern={{version}}
|
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
|
||||||
type=raw,value=latest
|
|
||||||
|
|
||||||
# ── Build + push all images in parallel ───────────────────────────────────
|
|
||||||
- name: Build and push all images
|
- name: Build and push all images
|
||||||
uses: docker/bake-action@v6
|
uses: docker/bake-action@v6
|
||||||
with:
|
with:
|
||||||
files: |
|
files: docker-bake.hcl
|
||||||
docker-bake.hcl
|
|
||||||
${{ steps.meta-backend.outputs.bake-file }}
|
|
||||||
${{ steps.meta-runner.outputs.bake-file }}
|
|
||||||
${{ steps.meta-pocketbase.outputs.bake-file }}
|
|
||||||
${{ steps.meta-ui.outputs.bake-file }}
|
|
||||||
${{ steps.meta-caddy.outputs.bake-file }}
|
|
||||||
set: |
|
set: |
|
||||||
backend.args.VERSION=${{ steps.meta-backend.outputs.version }}
|
|
||||||
backend.args.COMMIT=${{ gitea.sha }}
|
|
||||||
runner.args.VERSION=${{ steps.meta-runner.outputs.version }}
|
|
||||||
runner.args.COMMIT=${{ gitea.sha }}
|
|
||||||
ui.args.BUILD_TIME=${{ gitea.event.head_commit.timestamp }}
|
|
||||||
*.output=type=image,push=true
|
*.output=type=image,push=true
|
||||||
|
env:
|
||||||
|
GIT_TAG: ${{ gitea.ref_name }}
|
||||||
|
COMMIT: ${{ gitea.sha }}
|
||||||
|
BUILD_TIME: ${{ gitea.event.head_commit.timestamp }}
|
||||||
|
|
||||||
# ── deploy: sync docker-compose.yml + restart prod ───────────────────────────
|
# ── deploy: sync docker-compose.yml + restart prod ───────────────────────────
|
||||||
# Runs after all images are pushed to Docker Hub.
|
# Runs after all images are pushed to Docker Hub.
|
||||||
|
|||||||
@@ -5,75 +5,99 @@
|
|||||||
# - backend, runner, pocketbase share the Go builder stage (built once)
|
# - backend, runner, pocketbase share the Go builder stage (built once)
|
||||||
# - caddy and ui build independently in parallel alongside the Go targets
|
# - caddy and ui build independently in parallel alongside the Go targets
|
||||||
#
|
#
|
||||||
# Local build (no push):
|
# Local build (push=false by default):
|
||||||
# docker buildx bake
|
# docker buildx bake
|
||||||
#
|
#
|
||||||
# CI sets per-target tags and labels via --set overrides in docker/bake-action.
|
# CI passes GIT_TAG (e.g. "v4.1.3") and the bake file computes all three tag
|
||||||
|
# variants (full semver, major.minor, latest) — no docker/metadata-action needed.
|
||||||
|
|
||||||
# ── Variables injected by CI via --set ───────────────────────────────────────
|
# ── Variables injected by CI ──────────────────────────────────────────────────
|
||||||
|
|
||||||
variable "DOCKER_USER" { default = "kalekber" }
|
variable "DOCKER_USER" { default = "kalekber" }
|
||||||
|
|
||||||
variable "VERSION" { default = "dev" }
|
# Full git tag, e.g. "v4.1.3". CI passes this via --set or env.
|
||||||
|
# Locally defaults to "dev" so images get a :dev tag.
|
||||||
|
variable "GIT_TAG" { default = "dev" }
|
||||||
|
|
||||||
variable "COMMIT" { default = "unknown" }
|
variable "COMMIT" { default = "unknown" }
|
||||||
variable "BUILD_TIME" { default = "" }
|
variable "BUILD_TIME" { default = "" }
|
||||||
|
|
||||||
# ── Shared defaults ───────────────────────────────────────────────────────────
|
# ── Tag helpers ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
# All targets inherit these. CI overrides tags/labels per-target via --set.
|
locals {
|
||||||
target "_defaults" {
|
# Strip leading "v": "v4.1.3" → "4.1.3"
|
||||||
pull = true
|
version = trimprefix(GIT_TAG, "v")
|
||||||
output = ["type=image,push=false"]
|
|
||||||
|
# major.minor only: "4.1.3" → "4.1"
|
||||||
|
major_minor = join(".", slice(split(".", local.version), 0, 2))
|
||||||
|
|
||||||
|
# true when building a real release tag (not local "dev" build)
|
||||||
|
is_release = GIT_TAG != "dev"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Registry cache shared across all targets in a run.
|
# Return the three standard tags for a given image repo.
|
||||||
target "_cache" {
|
# Always includes :latest and the full version; skips major.minor for dev builds.
|
||||||
|
function "img_tags" {
|
||||||
|
params = [repo]
|
||||||
|
result = local.is_release ? [
|
||||||
|
"${repo}:${local.version}",
|
||||||
|
"${repo}:${local.major_minor}",
|
||||||
|
"${repo}:latest",
|
||||||
|
] : ["${repo}:dev"]
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Shared defaults ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
target "_defaults" {
|
||||||
|
pull = true
|
||||||
|
# CI overrides this to push=true via --set *.output=type=image,push=true
|
||||||
|
output = ["type=image,push=false"]
|
||||||
cache-to = ["type=inline"]
|
cache-to = ["type=inline"]
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Go targets (share the backend/ build context + builder stage) ─────────────
|
# ── Go targets (share the backend/ build context + builder stage) ─────────────
|
||||||
|
|
||||||
target "backend" {
|
target "backend" {
|
||||||
inherits = ["_defaults", "_cache"]
|
inherits = ["_defaults"]
|
||||||
context = "backend"
|
context = "backend"
|
||||||
target = "backend"
|
target = "backend"
|
||||||
tags = ["${DOCKER_USER}/libnovel-backend:latest"]
|
tags = img_tags("${DOCKER_USER}/libnovel-backend")
|
||||||
cache-from = ["type=registry,ref=${DOCKER_USER}/libnovel-backend:latest"]
|
cache-from = ["type=registry,ref=${DOCKER_USER}/libnovel-backend:latest"]
|
||||||
args = {
|
args = {
|
||||||
VERSION = VERSION
|
VERSION = local.version
|
||||||
COMMIT = COMMIT
|
COMMIT = COMMIT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
target "runner" {
|
target "runner" {
|
||||||
inherits = ["_defaults", "_cache"]
|
inherits = ["_defaults"]
|
||||||
context = "backend"
|
context = "backend"
|
||||||
target = "runner"
|
target = "runner"
|
||||||
tags = ["${DOCKER_USER}/libnovel-runner:latest"]
|
tags = img_tags("${DOCKER_USER}/libnovel-runner")
|
||||||
cache-from = ["type=registry,ref=${DOCKER_USER}/libnovel-runner:latest"]
|
cache-from = ["type=registry,ref=${DOCKER_USER}/libnovel-runner:latest"]
|
||||||
args = {
|
args = {
|
||||||
VERSION = VERSION
|
VERSION = local.version
|
||||||
COMMIT = COMMIT
|
COMMIT = COMMIT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
target "pocketbase" {
|
target "pocketbase" {
|
||||||
inherits = ["_defaults", "_cache"]
|
inherits = ["_defaults"]
|
||||||
context = "backend"
|
context = "backend"
|
||||||
target = "pocketbase"
|
target = "pocketbase"
|
||||||
tags = ["${DOCKER_USER}/libnovel-pocketbase:latest"]
|
tags = img_tags("${DOCKER_USER}/libnovel-pocketbase")
|
||||||
cache-from = ["type=registry,ref=${DOCKER_USER}/libnovel-pocketbase:latest"]
|
cache-from = ["type=registry,ref=${DOCKER_USER}/libnovel-pocketbase:latest"]
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── UI (SvelteKit — separate context) ────────────────────────────────────────
|
# ── UI (SvelteKit — separate context) ────────────────────────────────────────
|
||||||
|
|
||||||
target "ui" {
|
target "ui" {
|
||||||
inherits = ["_defaults", "_cache"]
|
inherits = ["_defaults"]
|
||||||
context = "ui"
|
context = "ui"
|
||||||
tags = ["${DOCKER_USER}/libnovel-ui:latest"]
|
tags = img_tags("${DOCKER_USER}/libnovel-ui")
|
||||||
cache-from = ["type=registry,ref=${DOCKER_USER}/libnovel-ui:latest"]
|
cache-from = ["type=registry,ref=${DOCKER_USER}/libnovel-ui:latest"]
|
||||||
args = {
|
args = {
|
||||||
BUILD_VERSION = VERSION
|
BUILD_VERSION = local.version
|
||||||
BUILD_COMMIT = COMMIT
|
BUILD_COMMIT = COMMIT
|
||||||
BUILD_TIME = BUILD_TIME
|
BUILD_TIME = BUILD_TIME
|
||||||
PREBUILT = "1"
|
PREBUILT = "1"
|
||||||
@@ -83,9 +107,9 @@ target "ui" {
|
|||||||
# ── Caddy (custom plugins — separate context) ─────────────────────────────────
|
# ── Caddy (custom plugins — separate context) ─────────────────────────────────
|
||||||
|
|
||||||
target "caddy" {
|
target "caddy" {
|
||||||
inherits = ["_defaults", "_cache"]
|
inherits = ["_defaults"]
|
||||||
context = "caddy"
|
context = "caddy"
|
||||||
tags = ["${DOCKER_USER}/libnovel-caddy:latest"]
|
tags = img_tags("${DOCKER_USER}/libnovel-caddy")
|
||||||
cache-from = ["type=registry,ref=${DOCKER_USER}/libnovel-caddy:latest"]
|
cache-from = ["type=registry,ref=${DOCKER_USER}/libnovel-caddy:latest"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user