Skip to content

Build and Push Images #1802

Build and Push Images

Build and Push Images #1802

name: Build and Push Images
on:
workflow_run:
workflows:
- CI
types:
- completed
branches:
- main
- epic/**
- release/**
push:
tags:
- v*.*.*
create:
tags:
- v*.*.*
branches:
- release/**
jobs:
prepare:
if: >
(
(github.ref_type == 'tag' && startsWith(github.ref_name, 'v')) &&
(github.event_name == 'push' || github.event_name == 'create')
) ||
(
github.event_name == 'create' &&
(
startsWith(github.ref_name, 'release/') ||
startsWith(github.ref_name, 'epic/')
)
) ||
(
github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success' &&
(
github.event.workflow_run.head_branch == 'main' ||
startsWith(github.event.workflow_run.head_branch, 'release/') ||
startsWith(github.event.workflow_run.head_branch, 'epic/')
)
) ||
(
github.event_name == 'pull_request' &&
(
github.base_ref == 'main' ||
startsWith(github.base_ref, 'release/') ||
startsWith(github.base_ref, 'epic/')
)
)
runs-on: ubuntu-latest
env:
# Prefer workflow_run context if present, otherwise fall back defaults
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch || (github.ref_type == 'branch' && github.ref_name) }}
HEAD_TAG: ${{ github.event.workflow_run.head_branch == null && github.ref_type == 'tag' && github.ref_name || '' }}
HEAD_SHA: ${{ github.event.workflow_run.head_sha || github.sha }}
outputs:
matrix: ${{ steps.read-matrix.outputs.matrix }}
build_type: ${{ steps.build-type.outputs.build_type }}
build_tag_base: ${{ steps.build-type.outputs.build_tag_base }}
build_tag_inc: ${{ steps.build-type.outputs.build_tag_inc }}
release_version: ${{ steps.build-type.outputs.release_version }}
version: ${{ steps.pkg-details.outputs.version }}
description: ${{ steps.pkg-details.outputs.description }}
build_tag: ${{ steps.incremental-tag.outputs.build_tag }}
version_bump_type: ${{ steps.build-type.outputs.version_bump_type }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ env.HEAD_SHA }}
fetch-depth: 0
- name: Read build matrix
id: read-matrix
shell: bash
run: |
MATRIX=$(cat ./.github/build.matrix.json | jq -c .)
echo "matrix=${MATRIX}" >> $GITHUB_OUTPUT
- name: Read package.json/repository version
id: pkg-details
run: |
echo "version=$(cat package.json | jq .version -r)" >> $GITHUB_OUTPUT
echo "description=$(cat package.json | jq .description -r)" >> $GITHUB_OUTPUT
- name: Determine build type
id: build-type
shell: bash
env:
PKGVER: ${{ steps.pkg-details.outputs.version }}
run: |
if [[ -n "$HEAD_TAG" ]]; then
# Build release for production
echo "release tag ${HEAD_TAG#v}"
echo "build_type=release" >> $GITHUB_OUTPUT
echo "build_tag_base=${HEAD_TAG#v}" >> $GITHUB_OUTPUT
echo "release_version=${HEAD_TAG#v}" >> $GITHUB_OUTPUT
echo "version_bump_type=patch" >> $GITHUB_OUTPUT
elif [[ "$HEAD_BRANCH" == "main" ]]; then
# Build CI snapshot
echo "CI snapshot (main)"
echo "build_type=snapshot" >> $GITHUB_OUTPUT
echo "build_tag_base=${PKGVER}-ci" >> $GITHUB_OUTPUT
echo "version_bump_type=patch" >> $GITHUB_OUTPUT
elif [[ "$HEAD_BRANCH" == epic/* ]]; then
# Build incremental epic
echo "build_type=epic" >> $GITHUB_OUTPUT
echo "build_tag_inc=true" >> $GITHUB_OUTPUT
BASE=$(echo "$HEAD_BRANCH" | awk -F"/|-" '{print $1 "-" $2 "-" $3}')
echo "build_tag_base=${BASE}" >> $GITHUB_OUTPUT
echo "Epic Branch ${BASE}"
elif [[ "$HEAD_BRANCH" == release/* ]]; then
# Build incremental release candidate
echo "build_type=rc" >> $GITHUB_OUTPUT
echo "build_tag_inc=true" >> $GITHUB_OUTPUT
echo "build_tag_base=${HEAD_BRANCH#release/}-rc" >> $GITHUB_OUTPUT
echo "release_version=${HEAD_BRANCH#release/}" >> $GITHUB_OUTPUT
echo "Release Branch ${HEAD_BRANCH}"
fi
- name: Login to GHCR
if: steps.build-type.outputs.build_tag_inc == 'true'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Install crane
uses: imjasonh/setup-crane@v0.4
- name: Determine incremental build tag
id: incremental-tag
if: steps.build-type.outputs.build_tag_inc == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
BRANCH_TAG="${{ steps.build-type.outputs.build_tag_base }}"
LATEST=$(crane ls "ghcr.io/bostads-ab-mimer/onecore/onecore-core" \
| grep "^${BRANCH_TAG}\." \
| sed "s/^${BRANCH_TAG}\.//" \
| sort -n \
| tail -1)
if [ -z "$LATEST" ]; then
NEXT=1
else
NEXT=$((LATEST + 1))
fi
echo "build_tag=${BRANCH_TAG}.${NEXT}" >> $GITHUB_OUTPUT
echo "Using tag: ${BRANCH_TAG}.${NEXT}"
- name: Enforce package.json matches release version
if: steps.build-type.outputs.build_tag_version != ''
run: |
WANT="${{ steps.build-type.outputs.release_version }}"
HAVE="${{ steps.pkg-details.outputs.version }}"
if [[ "$WANT" != "$HAVE" ]]; then
echo "::error::package.json version ($HAVE) does not match release target version ($WANT)";
exit 1;
fi
build-and-push:
needs: prepare
runs-on: ubuntu-latest
env:
HEAD_SHA: ${{ github.event.workflow_run.head_sha || github.sha }}
strategy:
matrix:
include: ${{ fromJson(needs.prepare.outputs.matrix) }}
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ env.HEAD_SHA }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GHCR
if: github.event.repository.fork == false
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}/${{ matrix.imageName || matrix.name }}
tags: |
type=raw,value=${{ needs.prepare.outputs.build_tag || needs.prepare.outputs.build_tag_base }}
type=raw,value=latest,enable=${{ github.event.workflow_run.head_branch == null && github.ref_type == 'tag' && github.ref_name && 'true' || 'false' }}
labels: |
org.opencontainers.image.title=${{ matrix.label }}
org.opencontainers.image.description=${{ needs.prepare.outputs.description }}
- name: Render build_args
id: render-build-args
env:
BUILD_TYPE: ${{ needs.prepare.outputs.build_type }}
RELEASE_BUILD_ARGS: ${{ (matrix.build_args.release && toJSON(matrix.build_args.release)) }}
TEST_BUILD_ARGS: ${{ (matrix.build_args.test && toJSON(matrix.build_args.test)) }}
run: |
if [ "${BUILD_TYPE}" == "release" ]; then
BUILD_ARGS_JSON="${RELEASE_BUILD_ARGS}"
else
BUILD_ARGS_JSON="${TEST_BUILD_ARGS}"
fi
if [ -n "${BUILD_ARGS_JSON}" ]; then
{
printf "build_args<<EOF\n"
echo "$BUILD_ARGS_JSON" | jq -r 'to_entries | .[]? | "\(.key)=\(.value)"'
printf "EOF\n"
} >> $GITHUB_OUTPUT
fi
- name: Build and push ${{ steps.meta.outputs.tags }}
uses: docker/build-push-action@v5
if: matrix.docker
with:
context: .
file: ./${{ matrix.path }}/Dockerfile
push: ${{ env.ACT != 'true' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.name }}
cache-to: type=gha,mode=max,scope=${{ matrix.name }}
build-args: ${{ steps.render-build-args.outputs.build_args }}
bump-version:
needs: [build-and-push, prepare]
if: ${{ needs.prepare.outputs.version_bump_type != '' }}
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ env.HEAD_SHA }}
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10.28.0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
cache: pnpm
- name: Configure Git
run: |
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
- name: Update version
run: |
# Enforce global version, in case of version drift by first bumping the root version...
pnpm version ${{ needs.prepare.outputs.version_bump_type }} -r --no-commit-hooks --no-git-tag-version
# And then explicitly setting that version for the entire workspace
new_version=$(jq -r .version package.json)
pnpm version "${new_version}" -r --no-commit-hooks --no-git-tag-version --include-workspace-root --allow-same-version
git add $(git ls-files -m '*package*.json')
git commit -m "chore: bump version to ${new_version} [skip ci]"
git push --follow-tags