Alpine 3.23, Test vector, Clean up output, reduce messages #50
Workflow file for this run
This file contains hidden or 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
| name: development | |
| on: | |
| pull_request: | |
| push: | |
| branches: | |
| - '!main' # excludes main | |
| - '!master' # excludes master | |
| env: | |
| TARGET_PLATFORMS: linux/amd64,linux/arm64 | |
| COMPOSE_DOCKER_CLI_BUILD: '1' | |
| DOCKER_BUILDKIT: '1' | |
| jobs: | |
| build_images: | |
| name: "Create runtime and buildroot OCI Images" | |
| services: | |
| registry: | |
| image: registry:3 | |
| ports: | |
| - 5000:5000 | |
| strategy: | |
| fail-fast: true | |
| matrix: | |
| python: | |
| - '3.14' | |
| - '3.13' | |
| - '3.12' | |
| - '3.11' | |
| - '3.10' | |
| - '3.9' | |
| - '3.8' | |
| alpine: | |
| - '3.20' | |
| - '3.21' | |
| - '3.22' | |
| os: | |
| - 'ubuntu-latest' | |
| exclude: | |
| # No tag | |
| - python: '3.8' | |
| alpine: '3.21' | |
| - python: '3.8' | |
| alpine: '3.22' | |
| - python: '3.14' | |
| alpine: '3.20' | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - | |
| name: Checkout | |
| uses: actions/checkout@v4 | |
| - | |
| name: Setup | |
| run: | | |
| sudo apt-get -y install skopeo | |
| - | |
| name: Set up QEMU | |
| uses: docker/setup-qemu-action@v3 | |
| - | |
| name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| with: | |
| driver-opts: network=host | |
| daemon-config: | | |
| { | |
| "features": { | |
| "containerd-snapshotter": true | |
| } | |
| } | |
| - | |
| id: image_env | |
| run: | | |
| . ./env.sh \ | |
| '${{ matrix.alpine }}' \ | |
| '${{ matrix.python }}' \ | |
| '${{ github.repository_owner }}' \ | |
| 'localhost:5000' | |
| docker pull -q "${SOURCE_IMAGE}" || true | |
| echo "IMAGE_HOME=$(mktemp -d)" >> "$GITHUB_OUTPUT" | |
| echo ALPINE_VERSION="${ALPINE_VERSION}"| tee -a "$GITHUB_OUTPUT" | |
| echo PYTHON_VERSION="${PYTHON_VERSION}"| tee -a "$GITHUB_OUTPUT" | |
| echo SOURCE_IMAGE="${SOURCE_IMAGE}"| tee -a "$GITHUB_OUTPUT" | |
| echo IMAGE_TAG="${IMAGE_TAG}"| tee -a "$GITHUB_OUTPUT" | |
| echo IMAGE_BUILDROOT_TAG="${IMAGE_TAG}-buildroot"| tee -a "$GITHUB_OUTPUT" | |
| echo IMAGE_TAG_SAFE="$(echo "$IMAGE_TAG" | base64 -w 0 )"| tee -a "$GITHUB_OUTPUT" | |
| echo IMAGE_BUILDROOT_TAG_SAFE="$(echo "${IMAGE_TAG}-buildroot" | base64 -w 0 )"| tee -a "$GITHUB_OUTPUT" | |
| echo 'EXAMPLE_IMAGE_TAG='"${IMAGE_TAG}-example1" | tee -a "$GITHUB_OUTPUT" | |
| echo REPOSITORY="${REPOSITORY}"| tee -a "$GITHUB_OUTPUT" | |
| echo REPOSITORY_SAFE="$(echo "${REPOSITORY}" | base64 -w 0 )"| tee -a "$GITHUB_OUTPUT" | |
| echo BASE_IMAGE_DIGEST="$(digest_of "$SOURCE_IMAGE")"| tee -a "$GITHUB_OUTPUT" | |
| echo 'IMAGE_DESCRIPTION=${{ github.event.repository.description }}. See ${{ github.server_url }}/${{ github.repository }} for more info.' | tee -a "$GITHUB_OUTPUT" | |
| - | |
| name: Create Buildroot | |
| uses: docker/build-push-action@v6 | |
| id: buildroot | |
| env: | |
| DOCKER_BUILD_SUMMARY: false | |
| DOCKER_BUILD_RECORD_UPLOAD: false | |
| with: | |
| push: true | |
| platforms: ${{ env.TARGET_PLATFORMS }} | |
| context: "." | |
| file: Dockerfile.alpine | |
| sbom: true | |
| provenance: mode=max | |
| target: buildroot | |
| cache-to: | | |
| type=gha,mode=max | |
| cache-from: | | |
| type=gha | |
| type=registry,ref=${{ steps.image_env.outputs.IMAGE_TAG }}-buildroot | |
| type=registry,ref=${{ steps.image_env.outputs.SOURCE_IMAGE }}@${{ steps.image_env.outputs.BASE_IMAGE_DIGEST }} | |
| build-args: | | |
| ALPINE_VERSION=${{ steps.image_env.outputs.ALPINE_VERSION }} | |
| BASE_IMAGE_DIGEST=${{ steps.image_env.outputs.BASE_IMAGE_DIGEST }} | |
| PYTHON_VERSION=${{ steps.image_env.outputs.PYTHON_VERSION }} | |
| SOURCE_IMAGE=${{ steps.image_env.outputs.SOURCE_IMAGE }} | |
| BUILD_ROOT=/d | |
| tags: "${{ steps.image_env.outputs.IMAGE_TAG }}-buildroot" | |
| outputs: type=oci,dest=${{ steps.image_env.outputs.IMAGE_HOME }}/image-${{ steps.image_env.outputs.IMAGE_BUILDROOT_TAG_SAFE }}.tar | |
| - | |
| name: Create Image | |
| id: runtime | |
| uses: docker/build-push-action@v6 | |
| env: | |
| SOURCE_DATE_EPOCH: 0 | |
| DOCKER_BUILD_SUMMARY: false | |
| DOCKER_BUILD_RECORD_UPLOAD: false | |
| with: | |
| push: true | |
| context: "." | |
| platforms: ${{ env.TARGET_PLATFORMS }} | |
| file: Dockerfile.alpine | |
| cache-to: | | |
| type=gha,mode=max | |
| cache-from: | | |
| type=gha | |
| type=registry,ref=${{ steps.image_env.outputs.IMAGE_TAG }} | |
| type=registry,ref=${{ steps.image_env.outputs.IMAGE_TAG }}-buildroot | |
| type=registry,ref=${{ steps.image_env.outputs.SOURCE_IMAGE }}@${{ steps.image_env.outputs.BASE_IMAGE_DIGEST }} | |
| build-args: | | |
| ALPINE_VERSION=${{ steps.image_env.outputs.ALPINE_VERSION }} | |
| BASE_IMAGE_DIGEST=${{ steps.image_env.outputs.BASE_IMAGE_DIGEST }} | |
| PYTHON_VERSION=${{ steps.image_env.outputs.PYTHON_VERSION }} | |
| SOURCE_IMAGE=${{ steps.image_env.outputs.SOURCE_IMAGE }} | |
| BUILD_ROOT=/d | |
| tags: "${{ steps.image_env.outputs.IMAGE_TAG }}" | |
| outputs: type=oci,dest=${{ steps.image_env.outputs.IMAGE_HOME }}/image-${{ steps.image_env.outputs.IMAGE_TAG_SAFE }}.tar | |
| labels: ${{steps.image_env.outputs.IMAGE_LABELS}} | |
| sbom: true | |
| provenance: mode=max | |
| annotations: | | |
| index,manifest:org.opencontainers.image.authors=distroless-python image developers <autumn.jolitz+distroless-python@gmail.com> | |
| index,manifest:org.opencontainers.image.source=https://github.com/autumnjolitz/distroless-python | |
| index,manifest:org.opencontainers.image.title=distroless-python${{ steps.image_env.outputs.PYTHON_VERSION }}-alpine${{ steps.image_env.outputs.ALPINE_VERSION }} | |
| index,manifest:org.opencontainers.image.description=${{ steps.image_env.outputs.IMAGE_DESCRIPTION }} | |
| index,manifest:org.opencontainers.image.base.digest=${{ steps.image_env.outputs.BASE_IMAGE_DIGEST }} | |
| index,manifest:org.opencontainers.image.base.name=${{ steps.image_env.outputs.SOURCE_IMAGE }} | |
| index,manifest:distroless.python-version=${{ steps.image_env.outputs.PYTHON_VERSION }} | |
| index,manifest:distroless.alpine-version=${{ steps.image_env.outputs.ALPINE_VERSION }} | |
| index,manifest:distroless.base-image=alpine${{ steps.image_env.outputs.ALPINE_VERSION }} | |
| - | |
| name: examples/simple-flask | |
| id: build_test | |
| uses: docker/build-push-action@v6 | |
| env: | |
| DOCKER_BUILD_SUMMARY: false | |
| DOCKER_BUILD_RECORD_UPLOAD: false | |
| with: | |
| push: true | |
| context: "examples/simple-flask" | |
| platforms: ${{ env.TARGET_PLATFORMS }} | |
| cache-from: | | |
| type=gha | |
| type=registry,ref=${{ steps.image_env.outputs.IMAGE_TAG }} | |
| type=registry,ref=${{ steps.image_env.outputs.IMAGE_TAG }}-buildroot | |
| type=registry,ref=${{ steps.image_env.outputs.SOURCE_IMAGE }}@${{ steps.image_env.outputs.BASE_IMAGE_DIGEST }} | |
| build-args: | | |
| SOURCE_IMAGE=${{ steps.image_env.outputs.IMAGE_TAG }} | |
| tags: "${{ steps.image_env.outputs.IMAGE_TAG }}-example1" | |
| outputs: type=oci,dest=${{ steps.image_env.outputs.IMAGE_HOME }}/example1-${{ steps.image_env.outputs.IMAGE_TAG_SAFE }}.tar | |
| - | |
| id: test | |
| name: Test Example | |
| env: | |
| IMAGE_URI: '${{ steps.image_env.outputs.EXAMPLE_IMAGE_TAG }}' | |
| IMAGE_DIGEST: '${{ steps.build_test.outputs.digest }}' | |
| test_command: curl -sLv 'http://localhost:8080/' | |
| run: | | |
| set -o pipefail | |
| run_test () { | |
| printf '## Test\n\n' | |
| local rv=0 | |
| local T="$(mktemp)" | |
| trap 'rm -f '"$T" RETURN | |
| >"$T" 2>&1 eval "$@" || rv=$? | |
| if [ $rv -eq 0 ] && case "$(tail -1 $T)" in '<p>Hello, World!</p>') false ;; *) true ;; esac ; then | |
| >&2 echo 'failed! got "'"$(tail -1 $T)"'" !' | |
| rv=1 | |
| fi | |
| printf '`%s` (returned code: ' "$@" | |
| printf '%s)\n```\n' "$rv" | |
| cat "$T" | |
| printf '\n```\n\n### images\n\n```' | |
| docker images --tree $IMAGE_URI | sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2};?)?)?[mGK]//g" | |
| printf '\n```\n' | |
| return "$rv" | |
| } | |
| rc=0 | |
| REMOTE_DIGEST="$(skopeo inspect --raw "$IMAGE_URI" | skopeo manifest-digest /dev/stdin)" | |
| if [ "$REMOTE_DIGEST" != "${IMAGE_DIGEST}" ]; then | |
| echo 'generated a diferent manifest than '"${IMAGE_DIGEST}"': '"$REMOTE_DIGEST" | |
| exit 2 | |
| fi | |
| docker pull -q "$(echo "$IMAGE_URI" | rev | cut -d: -f2- | rev )@${IMAGE_DIGEST}" | |
| for platform in $(echo $TARGET_PLATFORMS | tr , '\n') | |
| do | |
| docker pull --platform $platform -q "$IMAGE_URI" | |
| >&2 printf 'pulled %s (%s)\n' "$IMAGE_TAG" "$platform" | |
| done | |
| container_id="$(docker run --detach -p 8080:8080 --rm $IMAGE_URI)" || rc=$? | |
| if [ $rc -ne 0 ]; then | |
| printf 'docker run failed (return code '$rc')!\n' | >&2 tee \ | |
| -a "$GITHUB_OUTPUT" | |
| exit $rc | |
| fi | |
| trap 'docker stop $container_id' EXIT | |
| start_ts=$(date +%s) | |
| until [ x$(curl \ | |
| --silent --output /dev/null \ | |
| -w '%{http_code}\n' --fail 'http://localhost:8080/') = x200 ] | |
| do | |
| sleep 1 | |
| if [ "$(expr "${start_ts}" \+ 30)" -lt "$(date +%s)" ]; then | |
| >&2 echo 'failed to get a good response in 30 seconds!' | |
| break | |
| fi | |
| done | |
| rc=0 | |
| (run_test "$test_command" | tee -a "$GITHUB_STEP_SUMMARY") || rc=$? | |
| if [ $rc -ne 0 ]; then | |
| exit $rc | |
| fi | |
| - | |
| id: post_build | |
| run: | | |
| IMAGE_DIGEST='${{steps.runtime.outputs.digest}}' | |
| IMAGE_BUILDROOT_DIGEST='${{steps.buildroot.outputs.digest}}' | |
| echo 'IMAGE_DIGEST='$IMAGE_DIGEST >> "GITHUB_OUTPUT" | |
| echo 'IMAGE_BUILDROOT_DIGEST='$IMAGE_BUILDROOT_DIGEST >> "GITHUB_OUTPUT" | |
| echo '${{ steps.image_env.outputs.IMAGE_TAG }}@'"$IMAGE_DIGEST" | tee -a ${{ steps.image_env.outputs.IMAGE_HOME }}/manifest.txt | |
| echo '${{ steps.image_env.outputs.IMAGE_BUILDROOT_TAG }}@'"$IMAGE_BUILDROOT_DIGEST" | tee -a ${{ steps.image_env.outputs.IMAGE_HOME }}/manifest.txt | |
| ls ${{ steps.image_env.outputs.IMAGE_HOME }} | |
| - | |
| name: upload build | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| if-no-files-found: error | |
| retention-days: 1 | |
| name: images-alpine${{steps.image_env.outputs.ALPINE_VERSION}}-python${{steps.image_env.outputs.PYTHON_VERSION}} | |
| path: | | |
| ${{ steps.image_env.outputs.IMAGE_HOME }}/image-${{ steps.image_env.outputs.IMAGE_TAG_SAFE }}.tar | |
| ${{ steps.image_env.outputs.IMAGE_HOME }}/image-${{ steps.image_env.outputs.IMAGE_BUILDROOT_TAG_SAFE }}.tar | |
| - | |
| name: upload build info | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| if-no-files-found: error | |
| retention-days: 1 | |
| name: metadata-alpine${{steps.image_env.outputs.ALPINE_VERSION}}-python${{steps.image_env.outputs.PYTHON_VERSION}} | |
| path: | | |
| ${{ steps.image_env.outputs.IMAGE_HOME }}/*.txt | |
| post-build: | |
| name: "Render metadata" | |
| needs: [build_images] | |
| runs-on: "ubuntu-latest" | |
| steps: | |
| - | |
| name: Checkout | |
| uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.12' | |
| - | |
| name: install dependencies | |
| run: | | |
| python -m pip install jinplate | |
| - | |
| name: fetch metadata | |
| uses: actions/download-artifact@v5 | |
| with: | |
| pattern: metadata-* | |
| path: dist-images | |
| - | |
| name: aggregate metadata | |
| run: | | |
| cat $(find dist-images -type f -name manifest.txt -print) > manifest.txt | |
| cat $(find dist-images -type f -name packages.txt -print) > packages.txt | |
| find dist-images -type f \( -name manifest.txt -o -name packages.txt \) -delete | |
| { | |
| printf '### manifest.txt\n\n' | |
| printf '```\n' | |
| cat manifest.txt | |
| printf '```\n' | |
| } >>"$GITHUB_STEP_SUMMARY" | |
| { | |
| printf '### packages.txt\n\n' | |
| printf '```\n' | |
| cat packages.txt | |
| printf '```\n' | |
| } >>"$GITHUB_STEP_SUMMARY" | |
| - | |
| name: fetch images | |
| uses: actions/download-artifact@v5 | |
| with: | |
| pattern: images-* | |
| path: dist-images | |
| merge-multiple: true | |
| - | |
| name: parse metadata for README | |
| run: | | |
| for filename in $(echo dist-images/image-*.tar) | |
| do | |
| IMAGE_URI="$(basename -s .tar $filename | sed 's/image-//g' | base64 -d)" | |
| mkdir -p "$(dirname "$IMAGE_URI")" | |
| mv $filename "${IMAGE_URI}.tar" | |
| filename="${IMAGE_URI}.tar" | |
| PACKAGE_URL="$(grep "${IMAGE_URI}@" packages.txt | cut -d@ -f2-)" | |
| echo '{ | |
| "filename": "'"$(basename $filename)"'", | |
| "url": "'"$IMAGE_URI"'", | |
| "tag": "'$(echo $IMAGE_URI | rev | cut -d: -f1 | rev)'", | |
| "path": "'$(echo $IMAGE_URI | cut -d/ -f2- | cut -d: -f1)'", | |
| "name": "'$(echo $IMAGE_URI | rev | cut -d: -f2- | cut -d/ -f1 | rev)'", | |
| "registry": "'"$(echo $IMAGE_URI | cut -d/ -f1)"'", | |
| "size": '"$(wc -c "$filename" | xargs | cut -f1 -d' ')"', | |
| "digest": "'$(grep "${IMAGE_URI}@" manifest.txt | cut -d@ -f2-)'", | |
| "package_url": "'$PACKAGE_URL'" | |
| }' | |
| done | >./values.json jq -s '. | {"images": .}' | |
| cat ./values.json | |
| >./README.rst python \ | |
| -m jinplate.cli \ | |
| docs/README.rst.tmpl file://$PWD/values.json | |
| - | |
| name: Convert README.rst to markdown | |
| uses: docker://pandoc/core:3.8 | |
| with: | |
| args: >- | |
| -s | |
| --wrap=none | |
| -t gfm | |
| -o README.md | |
| README.rst | |
| - | |
| name: Print out markdown | |
| run: | | |
| cat README.md >>"$GITHUB_STEP_SUMMARY" |