Skip to content

Docker Build and Publish #82

Docker Build and Publish

Docker Build and Publish #82

name: Docker Build and Publish
on:
# Trigger after CI workflow completes successfully (branches and tags)
workflow_run:
workflows: ["CI"]
types:
- completed
# Allow PR builds (build but don't push)
pull_request:
branches:
- main
# Emergency manual override
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
# Only run if CI succeeded (for workflow_run) or if manually triggered or PR
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name != 'workflow_run' }}
permissions:
contents: read
packages: write
id-token: write # For signing images with cosign
attestations: write # For build provenance attestation
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
# For workflow_run, checkout the commit that triggered CI
ref: ${{ github.event.workflow_run.head_sha || github.ref }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Determine tags from workflow_run
id: tag-check
run: |
if [[ "${{ github.event_name }}" == "workflow_run" ]]; then
HEAD_BRANCH="${{ github.event.workflow_run.head_branch }}"
echo "head_branch=$HEAD_BRANCH" >> $GITHUB_OUTPUT
# Check if it's a tag (starts with v)
if [[ $HEAD_BRANCH == v* ]]; then
VERSION=${HEAD_BRANCH#v}
MAJOR=$(echo $VERSION | cut -d. -f1)
MINOR=$(echo $VERSION | cut -d. -f1-2)
echo "is_tag=true" >> $GITHUB_OUTPUT
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "major=$MAJOR" >> $GITHUB_OUTPUT
echo "minor=$MINOR" >> $GITHUB_OUTPUT
echo "is_main=false" >> $GITHUB_OUTPUT
elif [[ $HEAD_BRANCH == "main" ]]; then
echo "is_tag=false" >> $GITHUB_OUTPUT
echo "is_main=true" >> $GITHUB_OUTPUT
else
echo "is_tag=false" >> $GITHUB_OUTPUT
echo "is_main=false" >> $GITHUB_OUTPUT
fi
else
echo "is_tag=false" >> $GITHUB_OUTPUT
echo "is_main=false" >> $GITHUB_OUTPUT
fi
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
# Version tags for workflow_run from tags
type=raw,value=${{ steps.tag-check.outputs.version }},enable=${{ steps.tag-check.outputs.is_tag == 'true' }}
type=raw,value=${{ steps.tag-check.outputs.minor }},enable=${{ steps.tag-check.outputs.is_tag == 'true' }}
type=raw,value=${{ steps.tag-check.outputs.major }},enable=${{ steps.tag-check.outputs.is_tag == 'true' }}
# Version tags for direct tag pushes (v1.2.3)
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
# Branch tags
type=ref,event=branch
# PR tags
type=ref,event=pr
# Latest tag for main branch or version tags
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' || github.ref_type == 'tag' || (github.event_name == 'workflow_run' && (steps.tag-check.outputs.is_main == 'true' || steps.tag-check.outputs.is_tag == 'true')) }}
# Edge tag for develop branch
type=raw,value=edge,enable=${{ github.ref == 'refs/heads/develop' }}
# Git commit SHA (short) - only for branch builds
type=sha,prefix={{branch}}-,enable=${{ github.ref_type == 'branch' }}
labels: |
org.opencontainers.image.title=Data Archiver
org.opencontainers.image.description=Archive database data to object storage. Currently supports PostgreSQL input and S3-compatible output.
org.opencontainers.image.vendor=Airframes.io
org.opencontainers.image.authors=Airframes.io
org.opencontainers.image.documentation=https://github.com/airframesio/data-archiver
org.opencontainers.image.source=https://github.com/airframesio/data-archiver
- name: Extract version from tag
id: version
run: |
# For workflow_run events, check the head_branch
if [[ "${{ github.event_name }}" == "workflow_run" ]]; then
HEAD_BRANCH="${{ github.event.workflow_run.head_branch }}"
if [[ $HEAD_BRANCH == v* ]]; then
VERSION=${HEAD_BRANCH#v}
else
VERSION=dev
fi
elif [[ $GITHUB_REF == refs/tags/v* ]]; then
VERSION=${GITHUB_REF#refs/tags/v}
else
VERSION=dev
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
VERSION=${{ steps.version.outputs.version }}
cache-from: type=gha
cache-to: type=gha,mode=max
provenance: true
sbom: true
- name: Generate artifact attestation
if: github.event_name != 'pull_request'
uses: actions/attest-build-provenance@v1
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
subject-digest: ${{ steps.build-and-push.outputs.digest }}
push-to-registry: true
- name: Create summary
if: github.event_name != 'pull_request'
run: |
echo "## Docker Image Published 🐳" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Registry:** \`${{ env.REGISTRY }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Image:** \`${{ env.IMAGE_NAME }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Digest:** \`${{ steps.build-and-push.outputs.digest }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Tags:**" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Platforms:** linux/amd64, linux/arm64" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Pull Command" >> $GITHUB_STEP_SUMMARY
echo '```bash' >> $GITHUB_STEP_SUMMARY
echo "docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
test-image:
runs-on: ubuntu-latest
needs: build-and-push
if: github.event_name != 'pull_request'
steps:
- name: Log into registry ${{ env.REGISTRY }}
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract tag for testing
id: tag
run: |
# For workflow_run events, check the head_branch
if [[ "${{ github.event_name }}" == "workflow_run" ]]; then
HEAD_BRANCH="${{ github.event.workflow_run.head_branch }}"
if [[ $HEAD_BRANCH == v* ]]; then
TAG=${HEAD_BRANCH#v}
elif [[ $HEAD_BRANCH == "main" ]]; then
TAG=latest
elif [[ $HEAD_BRANCH == "develop" ]]; then
TAG=edge
else
TAG=$HEAD_BRANCH
fi
elif [[ $GITHUB_REF == refs/tags/v* ]]; then
TAG=${GITHUB_REF#refs/tags/v}
elif [[ $GITHUB_REF == refs/heads/main ]]; then
TAG=latest
elif [[ $GITHUB_REF == refs/heads/develop ]]; then
TAG=edge
else
TAG=${GITHUB_REF#refs/heads/}
fi
echo "tag=$TAG" >> $GITHUB_OUTPUT
- name: Pull and test image
run: |
echo "Testing image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }}"
# Pull the image
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }}
# Test basic functionality (help command)
docker run --rm ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }} --help
# Test version command
docker run --rm ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }} --version
# Inspect image
docker inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }}
echo "✅ Image tests passed successfully!"
- name: Test result summary
run: |
echo "## Image Testing Complete ✅" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Successfully tested image: \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }}\`" >> $GITHUB_STEP_SUMMARY