Files
Tautvydas Derzinskas 200de27ff1 ci: keep :dev to develop's own builds and say which merges publish it
A manual rebuild of a release dispatched from develop no longer tags :dev or
marks the image as the dev channel. The docs now say each :dev image is only
published when a merge touches that project.
2026-10-21 10:16:31 +02:00

126 lines
4.8 KiB
YAML

name: Build image (reusable)
# Shared build+push logic used by backend-image.yml, frontend-image.yml, and
# manual-image.yml — not triggered on its own (workflow_call only).
on:
workflow_call:
inputs:
project_dir:
description: "The npm project directory to lint, e.g. backend or frontend"
required: true
type: string
image_name:
description: "Fully-qualified image name, e.g. ghcr.io/owner/thingport-backend"
required: true
type: string
context:
description: "Docker build context"
required: true
type: string
dockerfile:
description: "Path to the Dockerfile"
required: true
type: string
cache_scope:
description: "GHA cache scope, so backend/frontend caches don't collide"
required: true
type: string
push:
description: "Whether to log in and push (false for PR validation builds)"
required: false
type: boolean
default: true
ref:
description: "The commit to build; the triggering one when empty"
required: false
type: string
default: ""
version:
description: "The release's version (release-project.yml), tagged as X.Y.Z, X.Y and X; empty for none"
required: false
type: string
default: ""
jobs:
build:
runs-on: ubuntu-latest
# A build takes about 10 minutes; a step hung under QEMU otherwise runs until GitHub's 6-hour limit.
timeout-minutes: 30
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.sha }}
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: npm
cache-dependency-path: ${{ inputs.project_dir }}/package-lock.json
- name: Install dependencies
working-directory: ${{ inputs.project_dir }}
run: npm ci --no-audit --no-fund
- name: Lint (quality gate — blocks the image build on failure)
working-directory: ${{ inputs.project_dir }}
run: npm run lint
# `vite build` strips types without checking them. The backend has no typecheck script (its build
# runs tsc), so --if-present makes this a no-op there.
- name: Typecheck (quality gate — frontend only, see comment)
working-directory: ${{ inputs.project_dir }}
run: npm run --if-present typecheck
- name: Set up QEMU (for the arm64 leg of the multi-arch build below)
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
if: inputs.push
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Compute image tags
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ inputs.image_name }}
tags: |
# develop's builds go out as :dev instead, the channel for testers who want changes before a release. Not a
# manual rebuild of a release dispatched from develop, which would put the release's code under :dev.
type=ref,event=branch,enable=${{ github.ref != 'refs/heads/develop' }}
type=raw,value=dev,enable=${{ github.ref == 'refs/heads/develop' && inputs.version == '' }}
type=sha,prefix=sha-,format=short
type=semver,pattern={{version}},value=${{ inputs.version }},enable=${{ inputs.version != '' }}
type=semver,pattern={{major}}.{{minor}},value=${{ inputs.version }},enable=${{ inputs.version != '' }}
type=semver,pattern={{major}},value=${{ inputs.version }},enable=${{ inputs.version != '' }}
# main, not "the default branch": that's develop now, and :latest is what's released.
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
- name: Build (and push)
uses: docker/build-push-action@v6
with:
context: ${{ inputs.context }}
file: ${{ inputs.dockerfile }}
# arm64 covers Apple Silicon and most ARM NAS units, built via QEMU on amd64 runners (the frontend's
# Node stages run natively; see frontend/Dockerfile).
platforms: linux/amd64,linux/arm64
push: ${{ inputs.push }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
RELEASE_CHANNEL=${{ github.ref == 'refs/heads/develop' && inputs.version == '' && 'dev' || 'stable' }}
cache-from: type=gha,scope=${{ inputs.cache_scope }}
cache-to: type=gha,mode=max,scope=${{ inputs.cache_scope }}