feat: introduce more docker tags for uv #24
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Build and publish a Docker image. | |
# | |
# Assumed to run as a subworkflow of .github/workflows/release.yml; specifically, as a local | |
# artifacts job within `cargo-dist`. | |
# | |
# TODO(charlie): Ideally, the publish step would happen as a publish job within `cargo-dist`, but | |
# sharing the built image as an artifact between jobs is challenging. | |
name: "Build Docker image" | |
on: | |
workflow_call: | |
inputs: | |
plan: | |
required: true | |
type: string | |
pull_request: | |
paths: | |
- .github/workflows/build-docker.yml | |
env: | |
UV_BASE_IMG: ghcr.io/${{ github.repository_owner }}/uv | |
jobs: | |
docker-build: | |
name: Build Docker image (ghcr.io/${{ github.repository_owner }}/uv) for ${{ matrix.platform }} | |
runs-on: ubuntu-latest | |
environment: | |
name: release | |
strategy: | |
fail-fast: false | |
matrix: | |
platform: | |
- linux/amd64 | |
- linux/arm64 | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
submodules: recursive | |
- uses: docker/setup-buildx-action@v3 | |
- uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.repository_owner }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Extract metadata (tags, labels) for Docker | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: ${{ env.UV_BASE_IMG }} | |
- name: Check tag consistency | |
if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }} | |
run: | | |
version=$(grep "version = " pyproject.toml | sed -e 's/version = "\(.*\)"/\1/g') | |
if [ "${{ fromJson(inputs.plan).announcement_tag }}" != "${version}" ]; then | |
echo "The input tag does not match the version from pyproject.toml:" >&2 | |
echo "${{ fromJson(inputs.plan).announcement_tag }}" >&2 | |
echo "${version}" >&2 | |
exit 1 | |
else | |
echo "Releasing ${version}" | |
fi | |
- name: Normalize Platform Pair (replace / with -) | |
run: | | |
platform=${{ matrix.platform }} | |
echo "PLATFORM_TUPLE=${platform//\//-}" >> $GITHUB_ENV | |
# Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/ | |
- name: Build and push by digest | |
id: build | |
uses: docker/build-push-action@v6 | |
with: | |
context: . | |
platforms: ${{ matrix.platform }} | |
cache-from: type=gha,scope=uv-${{ env.PLATFORM_TUPLE }} | |
cache-to: type=gha,mode=min,scope=uv-${{ env.PLATFORM_TUPLE }} | |
labels: ${{ steps.meta.outputs.labels }} | |
outputs: type=image,name=${{ env.UV_BASE_IMG }},push-by-digest=true,name-canonical=true,push=${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }} | |
- name: Export digests | |
run: | | |
mkdir -p /tmp/digests | |
digest="${{ steps.build.outputs.digest }}" | |
touch "/tmp/digests/${digest#sha256:}" | |
- name: Upload digests | |
uses: actions/upload-artifact@v4 | |
with: | |
name: digests-${{ env.PLATFORM_TUPLE }} | |
path: /tmp/digests/* | |
if-no-files-found: error | |
retention-days: 1 | |
docker-publish: | |
name: Publish Docker image (ghcr.io/${{ github.repository_owner }}/uv) | |
runs-on: ubuntu-latest | |
environment: | |
name: release | |
needs: | |
- docker-build | |
if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }} | |
steps: | |
- name: Download digests | |
uses: actions/download-artifact@v4 | |
with: | |
path: /tmp/digests | |
pattern: digests-* | |
merge-multiple: true | |
- uses: docker/setup-buildx-action@v3 | |
- name: Extract metadata (tags, labels) for Docker | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: ${{ env.UV_BASE_IMG }} | |
- uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.repository_owner }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
# Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/ | |
- name: Create manifest list and push | |
working-directory: /tmp/digests | |
run: | | |
docker buildx imagetools create \ | |
-t ${{ env.UV_BASE_IMG }}:latest \ | |
-t ${{ env.UV_BASE_IMG }}:${{ (inputs.plan != '' && fromJson(inputs.plan).announcement_tag) || 'dry-run' }} \ | |
$(printf '${{ env.UV_BASE_IMG }}@sha256:%s ' *) | |
docker-publish-extra: | |
name: Publish additional Docker image based on ${{ matrix.image-mapping }} | |
runs-on: ubuntu-latest | |
environment: | |
name: release | |
needs: | |
- docker-publish | |
if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }} | |
strategy: | |
fail-fast: false | |
matrix: | |
image-mapping: | |
- alpine:3.20,alpine,alpine3.20 | |
- debian:bookworm-slim,debian-slim,bookworm-slim | |
- buildpack-deps:bookworm,debian,bookworm | |
- python:3.12-alpine,python3.12-alpine | |
- python:3.11-alpine,python3.11-alpine | |
- python:3.10-alpine,python3.10-alpine | |
- python:3.9-alpine,python3.9-alpine | |
- python:3.8-alpine,python3.8-alpine | |
- python:3.12-bookworm,python3.12-bookworm | |
- python:3.11-bookworm,python3.11-bookworm | |
- python:3.10-bookworm,python3.10-bookworm | |
- python:3.9-bookworm,python3.9-bookworm | |
- python:3.8-bookworm,python3.8-bookworm | |
- python:3.12-slim-bookworm,python3.12-bookworm-slim | |
- python:3.11-slim-bookworm,python3.11-bookworm-slim | |
- python:3.10-slim-bookworm,python3.10-bookworm-slim | |
- python:3.9-slim-bookworm,python3.9-bookworm-slim | |
- python:3.8-slim-bookworm,python3.8-bookworm-slim | |
steps: | |
- uses: docker/setup-buildx-action@v3 | |
- uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.repository_owner }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Extract metadata (labels) for Docker | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: ${{ env.UV_BASE_IMG }} | |
- name: Generate Dynamic Dockerfile anTags | |
shell: bash | |
run: | | |
set -euo pipefail | |
# Extract the image and tags from the matrix variable | |
IFS=',' read -r BASE_IMAGE TAGS <<< "${{ matrix.image-mapping }}" | |
# Generate Dockerfile content | |
cat <<EOF > Dockerfile | |
FROM ${BASE_IMAGE} | |
COPY --from=${{ env.UV_BASE_IMG }}:latest /uv /usr/local/bin/uv | |
COPY --from=${{ env.UV_BASE_IMG }}:latest /uvx /usr/local/bin/uvx | |
EOF | |
# Initialize a variable to store all tags | |
TAG_LIST="" | |
# Loop through all tags and append them to the TAG_LIST | |
IFS=','; for TAG in ${TAGS}; do | |
TAG_LIST="${TAG_LIST},${{ env.UV_BASE_IMG }}:latest-${TAG},${{ env.UV_BASE_IMG }}:${{ (inputs.plan != '' && fromJson(inputs.plan).announcement_tag) || 'dry-run' }}-${TAG}" | |
done | |
# Remove the leading comma from TAG_LIST | |
TAG_LIST="${TAG_LIST:1}" | |
# Export tags | |
echo "IMAGE_REF=${BASE_IMAGE//:/-}" >> $GITHUB_ENV | |
echo "TAG_LIST=${TAG_LIST}" >> $GITHUB_ENV | |
- name: Build and push | |
uses: docker/build-push-action@v6 | |
with: | |
context: . | |
platforms: linux/amd64,linux/arm64 | |
# We do not really need to cache here as the Dockerfile is tiny | |
#cache-from: type=gha,scope=uv-${{ env.IMAGE_REF }} | |
#cache-to: type=gha,mode=min,scope=uv-${{ env.IMAGE_REF }} | |
push: true | |
tags: ${{ env.TAG_LIST }} | |
labels: ${{ steps.meta.outputs.labels }} |