Skip to content

Publish Docker image

Publish Docker image #12

name: Publish Docker image
# Runs after Release succeeds (PyPI already uploaded), or manually to
# rebuild an image for an existing version. Avoids racing the tag push
# that also starts Release.
on:
workflow_run:
workflows: ["Release"]
types: [completed]
workflow_dispatch:
inputs:
version:
description: "Package version (e.g. 0.1.0)"
required: true
permissions:
contents: read
jobs:
docker:
name: Build and push Docker image
if: >-
github.event_name == 'workflow_dispatch' ||
(github.event.workflow_run.conclusion == 'success' &&
startsWith(github.event.workflow_run.head_branch, 'create-awesome-python-app@'))
runs-on: ubuntu-latest
environment: pypi
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Resolve version
id: version
env:
INPUT_VERSION: ${{ github.event.inputs.version }}
RUN_BRANCH: ${{ github.event.workflow_run.head_branch }}
run: |
set -euo pipefail
if [ -n "${INPUT_VERSION:-}" ]; then
VERSION="$INPUT_VERSION"
else
VERSION="${RUN_BRANCH#create-awesome-python-app@}"
fi
if ! echo "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+([a-zA-Z0-9.-]+)?$'; then
echo "::error::Invalid Docker image version: $VERSION"
exit 1
fi
MAJOR=$(echo "$VERSION" | cut -d. -f1)
MINOR=$(echo "$VERSION" | cut -d. -f2)
{
echo "version=$VERSION"
echo "major=$MAJOR"
echo "minor=$MINOR"
} >> "$GITHUB_OUTPUT"
- name: Wait for PyPI package
env:
VERSION: ${{ steps.version.outputs.version }}
PACKAGE: create-awesome-python-app
run: |
set -euo pipefail
attempts=24
delay=15
for attempt in $(seq 1 "$attempts"); do
if curl -sfL "https://pypi.org/pypi/${PACKAGE}/${VERSION}/json" \
| jq -e '.urls[] | select(.packagetype=="sdist") | .digests.sha256' >/dev/null; then
echo "PyPI has ${PACKAGE}==${VERSION}"
exit 0
fi
echo "::warning::PyPI not ready for ${PACKAGE}==${VERSION} (attempt ${attempt}/${attempts}); retrying in ${delay}s"
sleep "$delay"
done
echo "::error::Timed out waiting for ${PACKAGE}==${VERSION} on PyPI"
exit 1
- name: Set up QEMU
# Required so buildx can cross-build linux/arm64 on the x86_64
# ubuntu-latest runner.
uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0
with:
platforms: linux/arm64
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Log in to Docker Hub
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
images: ulisesjeremias/create-awesome-python-app
tags: |
type=raw,value=latest
type=raw,value=${{ steps.version.outputs.version }}
type=raw,value=${{ steps.version.outputs.major }}.${{ steps.version.outputs.minor }}
type=raw,value=v${{ steps.version.outputs.major }}
labels: |
org.opencontainers.image.title=create-awesome-python-app
org.opencontainers.image.description=Composable scaffolding CLI for production-ready Python apps
org.opencontainers.image.url=https://github.com/Create-Python-App/create-python-app
org.opencontainers.image.source=https://github.com/Create-Python-App/create-python-app
org.opencontainers.image.licenses=MIT
org.opencontainers.image.version=${{ steps.version.outputs.version }}
- name: Build and push
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
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