Skip to content

Publish serverless-init to GHCR #24

Publish serverless-init to GHCR

Publish serverless-init to GHCR #24

name: Publish serverless-init to GHCR
on:
workflow_dispatch:
inputs:
source_image:
description: 'Source image from registry.datadoghq.com (e.g., registry.datadoghq.com/serverless-init:1.7.8)'
required: true
type: string
version:
description: 'Version tag (e.g., 1.7.8 or 1.7.8-rc1)'
required: true
type: string
image_suffix:
description: 'Image suffix (empty for standard, -alpine for alpine)'
required: false
type: string
default: ''
pipeline_id:
description: 'GitLab pipeline ID'
required: true
type: string
is_latest:
description: 'Tag as latest (true for prod releases, false for RCs)'
required: true
type: boolean
default: false
permissions:
packages: write
contents: read
jobs:
publish-to-ghcr:
runs-on: ubuntu-latest
steps:
- name: Install crane
run: |
cd /tmp
wget https://github.com/google/go-containerregistry/releases/download/v0.20.2/go-containerregistry_Linux_x86_64.tar.gz
tar -xzf go-containerregistry_Linux_x86_64.tar.gz
sudo mv crane /usr/local/bin/
crane version
- name: Login to GHCR
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Wait for image availability
run: |
SOURCE_IMAGE="${{ inputs.source_image }}"
MAX_ATTEMPTS=20
RETRY_DELAY=30
# Maximum wait time: 20 attempts × 30s = 600s (10 minutes)
echo "⏳ Waiting for image to be available: ${SOURCE_IMAGE}"
echo "Will check every ${RETRY_DELAY}s for up to $((MAX_ATTEMPTS * RETRY_DELAY))s"
for i in $(seq 1 $MAX_ATTEMPTS); do
echo "Attempt $i/$MAX_ATTEMPTS: Checking if image exists..."
if crane manifest ${SOURCE_IMAGE} >/dev/null 2>&1; then
echo "✅ Image is available!"
exit 0
fi
if [ $i -lt $MAX_ATTEMPTS ]; then
echo "⏳ Image not yet available, waiting ${RETRY_DELAY}s..."
sleep $RETRY_DELAY
fi
done
echo "❌ Image did not become available after $((MAX_ATTEMPTS * RETRY_DELAY))s"
exit 1
- name: Copy image to GHCR
run: |
SOURCE_IMAGE="${{ inputs.source_image }}"
VERSION="${{ inputs.version }}"
IMAGE_SUFFIX="${{ inputs.image_suffix }}"
PIPELINE_ID="${{ inputs.pipeline_id }}"
IS_LATEST="${{ inputs.is_latest }}"
DEST_BASE="ghcr.io/datadog/datadog-lambda-extension/serverless-init"
echo "📦 Publishing serverless-init image to GHCR"
echo " Source: ${SOURCE_IMAGE}"
echo " Destinations:"
echo " - ${DEST_BASE}:${VERSION}${IMAGE_SUFFIX}"
echo " - ${DEST_BASE}:v${PIPELINE_ID}${IMAGE_SUFFIX}"
# Copy with version tag (with retry logic)
# Maximum retry duration: 3 attempts with 10s delays between retries
# This workflow is triggered in parallel with the publish attempt to registry.datadoghq.com
# Registry.datadoghq.com should normally need about ~30 seconds to recieve the new image
MAX_COPY_ATTEMPTS=3
COPY_RETRY_DELAY=10
for i in $(seq 1 $MAX_COPY_ATTEMPTS); do
echo "Copying image (attempt $i/$MAX_COPY_ATTEMPTS)..."
if crane copy ${SOURCE_IMAGE} ${DEST_BASE}:${VERSION}${IMAGE_SUFFIX}; then
echo "✅ Image copied successfully!"
break
fi
if [ $i -lt $MAX_COPY_ATTEMPTS ]; then
echo "⚠️ Copy failed, retrying in ${COPY_RETRY_DELAY}s..."
sleep $COPY_RETRY_DELAY
else
echo "❌ Failed to copy image after $MAX_COPY_ATTEMPTS attempts"
exit 1
fi
done
# Tag for pipeline ID
crane tag ${DEST_BASE}:${VERSION}${IMAGE_SUFFIX} v${PIPELINE_ID}${IMAGE_SUFFIX}
# Tag as latest if this is a production release
if [ "$IS_LATEST" = "true" ]; then
echo " - ${DEST_BASE}:latest${IMAGE_SUFFIX}"
crane tag ${DEST_BASE}:${VERSION}${IMAGE_SUFFIX} latest${IMAGE_SUFFIX}
fi
echo "✅ Successfully published image to GHCR!"
echo "📍 View at: https://github.com/DataDog/datadog-lambda-extension/pkgs/container/datadog-lambda-extension%2Fserverless-init"