ci: merge jsons and add missing find type arg #218
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: main | |
| on: | |
| schedule: | |
| # update the pointers once a week | |
| # https://crontab.guru/once-a-week | |
| - cron: "0 0 * * 0" | |
| push: | |
| branches: | |
| - 'main' | |
| env: | |
| TARGET_PLATFORMS: linux/amd64,linux/arm64 | |
| jobs: | |
| build_images: | |
| name: "Create runtime and buildroot OCI Images" | |
| 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' | |
| - '3.23' | |
| os: | |
| - 'ubuntu-latest' | |
| exclude: | |
| # No tag | |
| - python: '3.8' | |
| alpine: '3.21' | |
| - python: '3.8' | |
| alpine: '3.22' | |
| - python: '3.8' | |
| alpine: '3.23' | |
| - python: '3.9' | |
| alpine: '3.23' | |
| - python: '3.14' | |
| alpine: '3.20' | |
| - python: '3.15' | |
| alpine: '3.20' | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - | |
| name: Checkout | |
| uses: actions/checkout@v4 | |
| - | |
| id: setup | |
| name: Setup | |
| run: | | |
| DEBUG_OUTPUT=/dev/null | |
| if [ x"${DEBUG_DOCKERD:-}" = x1 ]; then | |
| DEBUG_OUTPUT="$GITHUB_STEP_SUMMARY" | |
| fi | |
| setup_registry () { | |
| registry_id=$(docker run \ | |
| -p5000:5000 \ | |
| --name registry \ | |
| --rm -d registry:3) | |
| echo 'REGISTRY_CONTAINER_ID='$registry_id | |
| } | |
| setup_containerd_snapshotter () { | |
| local _sudo=sudo | |
| if [ $(id -u) -eq 0 ]; then | |
| _sudo=sudo | |
| fi | |
| if ! [ -f /etc/docker/daemon.json ]; then | |
| eval $_sudo mkdir -p /etc/docker | |
| echo '{}' | >/dev/null $_sudo tee /etc/docker/daemon.json | |
| fi | |
| cat /etc/docker/daemon.json | jq '. | .+{"features": {"containerd-snapshotter": true}}' | >/dev/null eval $_sudo tee /etc/docker/daemon.json | |
| printf '# Docker config\n\n```\n' | |
| cat /etc/docker/daemon.json | |
| printf '\n```\n\n' | |
| eval $_sudo systemctl restart docker | |
| sleep 1 | |
| printf '# Docker Info\n\n```' | |
| docker info | |
| printf '\n```\n' | |
| } | |
| sudo apt-get -y install skopeo | |
| setup_containerd_snapshotter | tee -a "$DEBUG_OUTPUT" | |
| { | |
| printf '## Registry info:\n\n' | |
| setup_registry | tee -a "$GITHUB_OUTPUT" | |
| } | tee -a "$DEBUG_OUTPUT" | |
| - | |
| 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 | |
| - | |
| 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 EXAMPLE_IMAGE_TAG_SAFE="$(echo "${IMAGE_TAG}-example1" | base64 -w 0 )"| 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: | |
| allow: network.host,security.insecure # this is for the bind mount | |
| push: true | |
| platforms: ${{ env.TARGET_PLATFORMS }} | |
| context: "." | |
| file: buildroot/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" | |
| - | |
| 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: runtime/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 }} | |
| BUILDROOT_IMAGE=${{ steps.image_env.outputs.IMAGE_TAG }}-buildroot@${{ steps.buildroot.outputs.digest }} | |
| BUILD_ROOT=/d | |
| tags: "${{ steps.image_env.outputs.IMAGE_TAG }}" | |
| labels: ${{steps.image_env.outputs.IMAGE_LABELS}} | |
| sbom: true | |
| provenance: mode=max | |
| annotations: | | |
| index,manifest:org.opencontainers.image.authors=distroless-python image developers <[email protected]> | |
| 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" | |
| - | |
| 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 () { | |
| 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' | |
| return "$rv" | |
| } | |
| rc=0 | |
| REMOTE_DIGEST="$(skopeo inspect --tls-verify=false --raw docker://"$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 | |
| docker pull -q "$IMAGE_URI" | |
| { | |
| printf '# Test\n\n' | |
| printf '## Source 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' | |
| } | tee -a "$GITHUB_STEP_SUMMARY" | |
| for platform in $(echo $TARGET_PLATFORMS | tr , '\n') | |
| do | |
| rc=0 | |
| container_id="$(docker run \ | |
| --platform $platform \ | |
| --detach -p 8080:8080 \ | |
| --rm $IMAGE_URI)" || rc=$? | |
| trap 'docker stop $container_id' EXIT | |
| if [ $rc -ne 0 ]; then | |
| printf 'docker run failed (return code '$rc')!\n' | >&2 tee \ | |
| -a "$GITHUB_OUTPUT" | |
| exit $rc | |
| fi | |
| start_ts=$(date +%s) | |
| until [ x$(curl \ | |
| --silent --output /dev/null \ | |
| -w '%{http_code}\n' --fail 'http://localhost:8080/_health') = 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 | |
| printf '## Test (%s)\n\n' "$(curl 'http://localhost:8080/_arch')" | tee -a "$GITHUB_STEP_SUMMARY" | |
| (run_test "$test_command" | tee -a "$GITHUB_STEP_SUMMARY") || rc=$? | |
| if [ $rc -ne 0 ]; then | |
| exit $rc | |
| fi | |
| trap -- EXIT | |
| docker stop $container_id | |
| done | |
| - | |
| id: post_build | |
| name: 'download multiplatform images' | |
| run: | | |
| skopeo copy \ | |
| --src-no-creds \ | |
| --src-tls-verify=false \ | |
| --quiet \ | |
| --multi-arch all \ | |
| docker://$(echo '${{ steps.image_env.outputs.IMAGE_TAG }}' | rev | cut -d: -f2- | rev)@${{ steps.runtime.outputs.digest }} \ | |
| oci-archive://${{ steps.image_env.outputs.IMAGE_HOME }}/image-${{ steps.image_env.outputs.IMAGE_TAG_SAFE }}.tar \ | |
| & | |
| skopeo copy \ | |
| --src-no-creds \ | |
| --src-tls-verify=false \ | |
| --quiet \ | |
| --multi-arch all \ | |
| docker://$(echo '${{ steps.image_env.outputs.IMAGE_TAG }}-buildroot' | rev | cut -d: -f2- | rev)@${{steps.buildroot.outputs.digest}} \ | |
| oci-archive://${{ steps.image_env.outputs.IMAGE_HOME }}/image-${{ steps.image_env.outputs.IMAGE_BUILDROOT_TAG_SAFE }}.tar \ | |
| & | |
| skopeo copy \ | |
| --src-no-creds \ | |
| --src-tls-verify=false \ | |
| --quiet \ | |
| --multi-arch all \ | |
| docker://$(echo '${{ steps.image_env.outputs.EXAMPLE_IMAGE_TAG }}' | rev | cut -d: -f2- | rev)@${{steps.build_test.outputs.digest}} \ | |
| oci-archive://${{ steps.image_env.outputs.IMAGE_HOME }}/image-${{ steps.image_env.outputs.EXAMPLE_IMAGE_TAG_SAFE }}.tar \ | |
| & | |
| wait | |
| docker stop '${{ steps.setup.outputs.REGISTRY_CONTAINER_ID }}' | |
| 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 | |
| upload: | |
| name: "Upload and update metadata" | |
| needs: [build_images] | |
| strategy: | |
| fail-fast: true | |
| matrix: | |
| repository: | |
| - docker.io | |
| - ghcr.io | |
| python: | |
| - '3.14' | |
| - '3.13' | |
| - '3.12' | |
| - '3.11' | |
| - '3.10' | |
| - '3.9' | |
| - '3.8' | |
| alpine: | |
| - '3.20' | |
| - '3.21' | |
| - '3.22' | |
| - '3.23' | |
| os: | |
| - 'ubuntu-latest' | |
| exclude: | |
| # No tag | |
| - python: '3.8' | |
| alpine: '3.21' | |
| - python: '3.8' | |
| alpine: '3.22' | |
| - python: '3.8' | |
| alpine: '3.23' | |
| - python: '3.9' | |
| alpine: '3.23' | |
| - python: '3.14' | |
| alpine: '3.20' | |
| - python: '3.15' | |
| alpine: '3.20' | |
| permissions: | |
| packages: write | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - | |
| name: Checkout | |
| uses: actions/checkout@v4 | |
| - | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.12' | |
| cache: 'pip' | |
| - | |
| name: install dependencies | |
| run: | | |
| sudo apt-get -y install skopeo | |
| - | |
| name: fetch images | |
| uses: actions/download-artifact@v5 | |
| with: | |
| name: images-alpine${{ matrix.alpine }}-python${{ matrix.python }} | |
| merge-multiple: true | |
| path: dist-images/ | |
| - | |
| name: Rename files | |
| run: | | |
| { | |
| printf 'Images:\n\n' | |
| for filename in $(find dist-images -type f -name "*.tar" -print) | |
| do | |
| image_uri="$(basename -s .tar $filename | sed 's/image-//g' | base64 -d)" | |
| new_image_uri=$(echo $image_uri | sed 's|localhost:5000|${{ matrix.repository }}|g') | |
| new_filename="dist-images/image-$(echo $new_image_uri | base64 -w 0).tar" | |
| cp ${filename} ${new_filename} | |
| printf '* `'${new_filename}'` (`'${new_image_uri}'`)\n' | |
| rm $filename | |
| done | |
| printf '\n' | |
| } | tee -a "$GITHUB_STEP_SUMMARY" | |
| - name: login to dockerhub | |
| if: ${{ matrix.repository == 'docker.io' }} | |
| env: | |
| DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} | |
| run: | | |
| printf "${DOCKERHUB_TOKEN}\n" | skopeo \ | |
| login \ | |
| --password-stdin \ | |
| --username ${{ github.repository_owner }} \ | |
| '${{ matrix.repository }}' | |
| - name: login to ghcr | |
| if: ${{ matrix.repository == 'ghcr.io' }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| printf "${GITHUB_TOKEN}\n" | skopeo \ | |
| login \ | |
| --password-stdin \ | |
| --username ${{ github.repository_owner }} \ | |
| '${{ matrix.repository }}' | |
| - | |
| name: upload to registry | |
| run: | | |
| upload_image () { | |
| local manifest_file= | |
| local packages_file= | |
| local image_digest= | |
| local filename="$1" | |
| shift | |
| local image_uri="$1" | |
| shift | |
| if [ x$1 != x ]; then | |
| manifest_file="$1" | |
| shift | |
| fi | |
| if [ x$1 != x ]; then | |
| packages_file="$1" | |
| shift | |
| fi | |
| if ! case "$filename" in /*) true ;; *) false ;; esac ; then | |
| filename="$(realpath $filename)" | |
| fi | |
| local START_TIME=$(date +%s) | |
| local T="$(mktemp)" | |
| local rc=0 | |
| >&2 echo "uploading ${image_uri}" | |
| skopeo copy \ | |
| --quiet \ | |
| --retry-times 32 \ | |
| --multi-arch all \ | |
| --dest-precompute-digests \ | |
| --digestfile "$T" \ | |
| oci-archive://$filename "docker://$image_uri" || rc=$? | |
| if [ $rc -ne 0 ]; then | |
| echo 'failed to upload '$image_uri' (return code: '$rc')!' >>"$GITHUB_STEP_SUMMARY" | |
| rm -f $T | |
| return $rc | |
| fi | |
| image_digest="$(cat $T)" | |
| rm -f $T | |
| if [ x$manifest_file != x ]; then | |
| >>"$manifest_file" echo "${image_uri}@${image_digest}" | |
| fi | |
| printf '* '"${image_uri}@${image_digest}"'\n' >>"$GITHUB_STEP_SUMMARY" | |
| >&2 echo "uploaded ${image_uri} in $(expr $(date +%s) - $START_TIME) seconds" | |
| echo "${image_uri}@${image_digest}" | |
| if case $image_uri in 'ghcr.io'*) true ;; *) false ;; esac ; then | |
| ghcr_artifact_url "${image_uri}" "${packages_file}" | |
| fi | |
| } | |
| ghcr_artifact_url () { | |
| local output=- | |
| local image_tag="$1" | |
| shift | |
| if ! case $image_tag in 'ghcr.io'*) true ;; *) false ;; esac ; then | |
| >&2 echo 'image '"$image_tag"' is not a ghcr.io one!' | |
| return 1 | |
| fi | |
| if [ x"$1" != x ]; then | |
| output="$1" | |
| shift | |
| fi | |
| local tag=$(echo "${image_tag}" | rev | cut -d: -f1 | rev) | |
| local package_name=$(echo "${image_tag}" | rev | cut -d: -f2- | cut -d/ -f1 | rev) | |
| local repo_name='${{ github.repository }}' | |
| local owner='${{ github.repository_owner }}' | |
| local url="https://api.github.com/users/${owner}/packages/container/${package_name}/versions" | |
| local versions_json="$(curl -s \ | |
| -H "X-GitHub-Api-Version: 2022-11-28" \ | |
| -H "Accept: application/vnd.github+json" \ | |
| -H 'Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' \ | |
| $url)" | |
| local version_id=$(echo "${versions_json}" | jq -r --arg tag "$tag" '.[] | select(.metadata.container.tags[] == $tag) | .id') | |
| local package_url="https://github.com/${repo_name}/pkgs/container/${package_name}/${version_id}?tag=${tag}" | |
| if ! [ x$output = x -o x$output = x- -o x$output = x/dev/stdout ]; then | |
| >>"$output" echo "${image_tag}@${package_url}" | |
| else | |
| echo "${image_tag}@${package_url}" | |
| fi | |
| } | |
| num_outstanding=0 | |
| concurrency_limit=8 | |
| for filename in $(find dist-images -type f -name "*.tar" -print) | |
| do | |
| IMAGE_URI="$(basename -s .tar $filename | sed 's/image-//g' | base64 -d)" | |
| upload_image "$filename" "$IMAGE_URI" ./manifest.txt ./packages.txt & | |
| num_outstanding=$(expr $num_outstanding \+ 1) | |
| if [ $num_outstanding -ge $concurrency_limit ]; then | |
| wait | |
| num_outstanding=0 | |
| fi | |
| done | |
| wait | |
| echo 'Done uploading' | |
| { | |
| printf '# Uploaded\n\n```' | |
| cat manifest.txt | |
| printf '```\n\n' | |
| } >>"$GITHUB_STEP_SUMMARY" | |
| 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": .}' | |
| - | |
| name: Upload metadata | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| if-no-files-found: error | |
| retention-days: 1 | |
| name: upload-alpine${{ matrix.alpine }}-python${{ matrix.python }}-${{ matrix.repository}}-metadata | |
| path: | | |
| manifest.txt | |
| packages.txt | |
| values.json | |
| post-upload: | |
| name: "Post Upload" | |
| needs: [upload] | |
| runs-on: "ubuntu-latest" | |
| steps: | |
| - | |
| name: Checkout | |
| uses: actions/checkout@v4 | |
| - | |
| name: "Setup Python" | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.12' | |
| cache: 'pip' | |
| - | |
| name: install dependencies | |
| run: | | |
| python -m pip install jinplate | |
| - | |
| name: Fetch build metadata | |
| uses: actions/download-artifact@v5 | |
| with: | |
| pattern: upload-*-metadata | |
| path: dist-images/ | |
| merge-multiple: false | |
| - | |
| name: parse metadata for README | |
| run: | | |
| >./manifest.txt cat $(find ./dist-images -type f -name 'manifest.txt' -print) | |
| >./packages.txt cat $(find ./dist-images -type f -name 'packages.txt' -print) | |
| { | |
| printf '# manifest_file.txt\n\n```' | |
| cat ./manifest.txt | |
| printf '```\n\n' | |
| printf '# packages.txt\n\n```' | |
| cat ./packages.txt | |
| printf '```\n\n' | |
| printf '# values.json\n\n```' | |
| cat \ | |
| $(find ./dist-images -type f -name 'values.json' -print) | \ | |
| jq -r --slurp '[.[].images] | flatten' | tee ./values.json | |
| printf '```\n\n' | |
| } | tee -a "$GITHUB_STEP_SUMMARY" | |
| find ./dist-images \ | |
| -type f \( -name manifest.txt -o -name packages.txt -o -name values.json \) \ | |
| -delete | |
| >./README.rst python \ | |
| -m jinplate.cli \ | |
| docs/README.rst.tmpl file://$PWD/values.json | |
| { | |
| printf "# README.rst\n\n```" | |
| cat README.rst | |
| printf "```\n\n" | |
| } | tee -a "$GITHUB_STEP_SUMMARY" | |
| - | |
| name: "Convert README.rst to markdown" | |
| uses: docker://pandoc/core:3.8 | |
| with: | |
| args: >- | |
| --wrap=none | |
| -t gfm | |
| -o README.md | |
| README.rst | |
| - | |
| name: Print out markdown | |
| run: | | |
| cat README.md >>"$GITHUB_STEP_SUMMARY" | |
| printf '\n\n# README.rst\n\n```\n' >> "$GITHUB_STEP_SUMMARY" | |
| cat README.rst >> "$GITHUB_STEP_SUMMARY" | |
| printf '\n```\n' >> "$GITHUB_STEP_SUMMARY" | |
| - | |
| name: Update Dockerhub description | |
| uses: peter-evans/dockerhub-description@e98e4d1628a5f3be2be7c231e50981aee98723ae # v4.0.0 | |
| with: | |
| username: ${{ github.repository_owner }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| short-description: ${{ github.event.repository.description }} | |
| # - | |
| # name: Create Release | |
| # id: upload-release-asset | |
| # uses: softprops/action-gh-release@v1 | |
| # with: | |
| # body_path: RELEASE_NOTES.md | |
| # name: Release ${{ steps.version.outputs.CURRENT_VERSION }} | |
| # fail_on_unmatched_files: true | |
| # files: | |
| # dist-images/**/*.tar | |
| # dist-images/**/**/*.tar |