Skip to content

multiplatform (#9)

multiplatform (#9) #11

name: Build and Push Docker Image
on:
push:
branches:
- main # Build and test on main push (no deployment)
tags:
- 'v*.*.*' # Semantic versioning: v1.0.0, v1.2.3, etc. (triggers deployment)
pull_request:
branches:
- main
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
# Only login for version tag pushes (actual deployments)
if: startsWith(github.ref, 'refs/tags/v')
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Lowercase image name
id: image
run: |
echo "name=$(echo ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT"
- name: Determine build type
id: build-type
run: |
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
echo "type=deployment" >> "$GITHUB_OUTPUT"
echo "::notice::🚀 DEPLOYMENT BUILD - Will push to registry"
else
echo "type=test" >> "$GITHUB_OUTPUT"
echo "::notice::🧪 TEST BUILD - Local build only, no push"
fi
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ steps.image.outputs.name }}
tags: |
# For version tags: generate semantic version tags + latest
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
# For PRs: use pr-<number> tag (local testing only)
type=ref,event=pr,prefix=pr-
# For main branch: use 'test' tag (local testing only, not pushed)
type=raw,value=test,enable=${{ github.ref == 'refs/heads/main' }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
# Only push on version tags (v1.0.0), NOT on PRs or main branch
push: ${{ startsWith(github.ref, 'refs/tags/v') }}
# Load image locally for PR and main branch testing
load: ${{ !startsWith(github.ref, 'refs/tags/v') }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: ${{ !startsWith(github.ref, 'refs/tags/v') && 'type=gha' || '' }}
cache-to: ${{ !startsWith(github.ref, 'refs/tags/v') && 'type=gha,mode=max' || '' }}
platforms: ${{ startsWith(github.ref, 'refs/tags/v') && 'linux/amd64,linux/arm64' || 'linux/amd64' }}
provenance: false
build-args: |
BUILD_DATE=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}
VCS_REF=${{ github.sha }}
VERSION=${{ github.ref_name }}
- name: Test Docker image (PR and main branch)
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
run: |
# Find the tag that was built
TAG=$(echo "${{ steps.meta.outputs.tags }}" | head -1 | cut -d':' -f2)
IMAGE_LOWER=$(echo "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" | tr '[:upper:]' '[:lower:]')
echo "Testing locally built image: ${IMAGE_LOWER}:${TAG}"
docker run --rm "${IMAGE_LOWER}:${TAG}" R --version
docker run --rm "${IMAGE_LOWER}:${TAG}" R -e "library(admiral); packageVersion('admiral')"
docker run --rm "${IMAGE_LOWER}:${TAG}" R -e "library(rtables)"
- name: Verify labels (PR and main branch)
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
run: |
TAG=$(echo "${{ steps.meta.outputs.tags }}" | head -1 | cut -d':' -f2)
IMAGE_LOWER=$(echo "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" | tr '[:upper:]' '[:lower:]')
echo "=== Image Labels ==="
docker inspect "${IMAGE_LOWER}:${TAG}" --format='{{json .Config.Labels}}' | jq -r 'to_entries[] | "\(.key)=\(.value)"'
echo ""
echo "=== Verifying OCI Labels ==="
docker inspect "${IMAGE_LOWER}:${TAG}" --format='{{index .Config.Labels "org.opencontainers.image.version"}}'
docker inspect "${IMAGE_LOWER}:${TAG}" --format='{{index .Config.Labels "org.opencontainers.image.revision"}}'
docker inspect "${IMAGE_LOWER}:${TAG}" --format='{{index .Config.Labels "org.opencontainers.image.created"}}'
# - name: Run Trivy vulnerability scanner
# if: startsWith(github.ref, 'refs/tags/v')
# uses: aquasecurity/trivy-action@master
# with:
# image-ref: ${{ steps.image.outputs.name }}:${{ steps.meta.outputs.version }}
# format: 'sarif'
# output: 'trivy-results.sarif'
# - name: Upload Trivy results to GitHub Security
# if: startsWith(github.ref, 'refs/tags/v')
# uses: github/codeql-action/upload-sarif@v2
# with:
# sarif_file: 'trivy-results.sarif'