Skip to content

Build and Push Docker Images #1

Build and Push Docker Images

Build and Push Docker Images #1

name: Build and Push Docker Images
# This workflow ONLY builds and pushes Docker images to GitHub Container Registry.
# Deployment is handled by external systems that watch for image updates.
#
# Workflow Summary:
# - develop branch → :develop image tag → external system deploys to dev (automatic)
# - main branch → :main image tag → external system deploys to testing (automatic)
# - v* tags → version image tags → external system handles production deployment (automatic)
# - Any other branch → manually triggered via Actions tab (workflow_dispatch)
# - v*-rc/beta/etc tags → pre-release version image tags (no :latest)
#
# Image Tags Created:
# - Push to develop: ghcr.io/org/repo:develop, ghcr.io/org/repo:develop-abc1234
# - Push to main: ghcr.io/org/repo:main, ghcr.io/org/repo:main-def5678
# - Manual trigger on any branch: ghcr.io/org/repo:branch-name, ghcr.io/org/repo:branch-name-abc1234
# - Tag v1.0.0: ghcr.io/org/repo:v1.0.0, ghcr.io/org/repo:latest
# - Tag v1.0.0-rc: ghcr.io/org/repo:v1.0.0-rc (no :latest)
on:
push:
branches:
- main
- develop
tags:
- 'v*' # Triggered when version tags are pushed
workflow_dispatch: # Manually trigger builds for feature/fix branches from the Actions tab
env:
REGISTRY: ghcr.io
BACKEND_IMAGE_NAME: helsingborg-stad/eneo-backend
FRONTEND_IMAGE_NAME: helsingborg-stad/eneo-frontend
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
attestations: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch full history for tags
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Install jq
run: sudo apt-get update && sudo apt-get install -y jq curl
- name: Install bun
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.0
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Determine build context
id: build-context
run: |
if [[ "${{ github.ref }}" == "refs/tags/v"* ]]; then
VERSION="${GITHUB_REF#refs/tags/}"
# Check if this is a pre-release (contains hyphen after version, e.g., v1.7.0-rc)
if [[ "$VERSION" == *-* ]]; then
echo "Building pre-release version: $VERSION"
echo "is-release=true" >> $GITHUB_OUTPUT
echo "is-prerelease=true" >> $GITHUB_OUTPUT
else
echo "Building production version: $VERSION"
echo "is-release=true" >> $GITHUB_OUTPUT
echo "is-prerelease=false" >> $GITHUB_OUTPUT
fi
elif [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
echo "Building main branch for testing environment"
echo "is-release=false" >> $GITHUB_OUTPUT
elif [[ "${{ github.ref }}" == "refs/heads/develop" ]]; then
echo "Building develop branch for dev environment"
echo "is-release=false" >> $GITHUB_OUTPUT
else
BRANCH_NAME="${GITHUB_REF#refs/heads/}"
echo "Building branch: $BRANCH_NAME"
echo "is-release=false" >> $GITHUB_OUTPUT
fi
# Backend build and push
- name: Extract backend metadata
id: meta-backend
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }}
tags: |
# Branch-based tags
type=raw,value=develop,enable=${{ github.ref == 'refs/heads/develop' }}
type=raw,value=main,enable=${{ github.ref == 'refs/heads/main' }}
type=ref,event=branch,enable=${{ github.ref != 'refs/heads/develop' && github.ref != 'refs/heads/main' }}
# Version tags (only for releases)
type=semver,pattern={{version}},enable=${{ steps.build-context.outputs.is-release == 'true' }}
type=raw,value=latest,enable=${{ steps.build-context.outputs.is-release == 'true' && steps.build-context.outputs.is-prerelease == 'false' }}
# Git SHA for traceability (always included)
type=sha,prefix={{branch}}-,format=short,enable=${{ github.ref_type == 'branch' }}
type=sha,format=short,enable=${{ github.ref_type == 'tag' }}
- name: Inject backend version
run: |
# For branches, use the SHA-suffixed tag (second tag), for tags use first tag
if [[ "${{ github.ref_type }}" == "branch" ]]; then
VERSION=$(echo "${{ steps.meta-backend.outputs.tags }}" | sed -n '2p' | cut -d':' -f2)
else
VERSION=$(echo "${{ steps.meta-backend.outputs.tags }}" | head -n1 | cut -d':' -f2)
fi
./scripts/inject-backend-version.sh "$VERSION"
- name: Build and push backend Docker image
uses: docker/build-push-action@v5
with:
context: ./backend
file: ./backend/Dockerfile
push: true
tags: ${{ steps.meta-backend.outputs.tags }}
labels: ${{ steps.meta-backend.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Frontend build and push
- name: Extract frontend metadata
id: meta-frontend
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.FRONTEND_IMAGE_NAME }}
tags: |
# Branch-based tags
type=raw,value=develop,enable=${{ github.ref == 'refs/heads/develop' }}
type=raw,value=main,enable=${{ github.ref == 'refs/heads/main' }}
type=ref,event=branch,enable=${{ github.ref != 'refs/heads/develop' && github.ref != 'refs/heads/main' }}
# Version tags (only for releases)
type=semver,pattern={{version}},enable=${{ steps.build-context.outputs.is-release == 'true' }}
type=raw,value=latest,enable=${{ steps.build-context.outputs.is-release == 'true' && steps.build-context.outputs.is-prerelease == 'false' }}
# Git SHA for traceability (always included)
type=sha,prefix={{branch}}-,format=short,enable=${{ github.ref_type == 'branch' }}
type=sha,format=short,enable=${{ github.ref_type == 'tag' }}
- name: Synchronize frontend with backend
run: |
# For branches, use the SHA-suffixed tag (second tag), for tags use first tag
if [[ "${{ github.ref_type }}" == "branch" ]]; then
BACKEND_TAG=$(echo "${{ steps.meta-backend.outputs.tags }}" | sed -n '2p' | cut -d':' -f2)
else
BACKEND_TAG=$(echo "${{ steps.meta-backend.outputs.tags }}" | head -n1 | cut -d':' -f2)
fi
./scripts/sync-frontend-with-backend.sh "${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }}:$BACKEND_TAG"
- name: Build and push frontend Docker image
uses: docker/build-push-action@v5
with:
context: ./frontend
file: ./frontend/Dockerfile
push: true
tags: ${{ steps.meta-frontend.outputs.tags }}
labels: ${{ steps.meta-frontend.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Summary of what was built
- name: Build Summary
run: |
echo "## 🐳 Docker Images Built and Pushed" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [[ "${{ github.ref }}" == "refs/tags/v"* ]]; then
VERSION="${GITHUB_REF#refs/tags/}"
if [[ "$VERSION" == *-* ]]; then
echo "### Pre-release: $VERSION" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Backend:**" >> $GITHUB_STEP_SUMMARY
echo "- \`${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }}:$VERSION\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Frontend:**" >> $GITHUB_STEP_SUMMARY
echo "- \`${{ env.REGISTRY }}/${{ env.FRONTEND_IMAGE_NAME }}:$VERSION\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "🧪 Pre-release images built for testing" >> $GITHUB_STEP_SUMMARY
else
echo "### Production Release: $VERSION" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Backend:**" >> $GITHUB_STEP_SUMMARY
echo "- \`${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }}:$VERSION\`" >> $GITHUB_STEP_SUMMARY
echo "- \`${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }}:latest\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Frontend:**" >> $GITHUB_STEP_SUMMARY
echo "- \`${{ env.REGISTRY }}/${{ env.FRONTEND_IMAGE_NAME }}:$VERSION\`" >> $GITHUB_STEP_SUMMARY
echo "- \`${{ env.REGISTRY }}/${{ env.FRONTEND_IMAGE_NAME }}:latest\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ Ready for production deployment" >> $GITHUB_STEP_SUMMARY
fi
elif [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
echo "### Testing Environment Build" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Backend:** \`${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }}:main\`" >> $GITHUB_STEP_SUMMARY
echo "**Frontend:** \`${{ env.REGISTRY }}/${{ env.FRONTEND_IMAGE_NAME }}:main\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "🧪 Images will be deployed to testing environment by ArgoCD/deployment system" >> $GITHUB_STEP_SUMMARY
elif [[ "${{ github.ref }}" == "refs/heads/develop" ]]; then
echo "### Development Environment Build" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Backend:** \`${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }}:develop\`" >> $GITHUB_STEP_SUMMARY
echo "**Frontend:** \`${{ env.REGISTRY }}/${{ env.FRONTEND_IMAGE_NAME }}:develop\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "🔧 Images will be deployed to dev environment by ArgoCD/deployment system" >> $GITHUB_STEP_SUMMARY
else
BRANCH_NAME="${GITHUB_REF#refs/heads/}"
BRANCH_TAG="${BRANCH_NAME//\//-}"
echo "### Branch Build: $BRANCH_NAME" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Backend:** \`${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }}:$BRANCH_TAG\`" >> $GITHUB_STEP_SUMMARY
echo "**Frontend:** \`${{ env.REGISTRY }}/${{ env.FRONTEND_IMAGE_NAME }}:$BRANCH_TAG\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "🚀 Branch images built for testing and development" >> $GITHUB_STEP_SUMMARY
fi