From 07f0faf05f1a5e60a912d815f6dc5c40312d7c88 Mon Sep 17 00:00:00 2001 From: Cedric Ahlers <55838528+clowa@users.noreply.github.com> Date: Thu, 10 Oct 2024 04:46:35 +0200 Subject: [PATCH] Add support to compare platform variants (#29) Add support to optionally compare image platform variants. Eg. linux/arm64 is equal to linux/arm64/v8 and both are heavily used on docker images. --- .github/workflows/test.yml | 62 ++++++++++++++++++++++++++++++++++---- docker.sh | 12 +++++--- 2 files changed, 63 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d1c4d45..393e92a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,6 +11,9 @@ env: DEBUG: ${{ secrets.ACTIONS_STEP_DEBUG }} jobs: + ##################################### + # Singe platform tests + test1: name: Test Update Needed runs-on: ubuntu-22.04 @@ -52,6 +55,26 @@ jobs: fi test3: + name: Test single platform + runs-on: ubuntu-22.04 + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + - name: Test Action + id: test + uses: ./ + with: + base-image: alpine:3.17.1 + image: lucacome/alpine-amd64 + - name: Get Test Output + run: echo "Workflow Docker Image ${{ steps.test.outputs.needs-updating }}" + - name: Check value + run: | + if [[ "${{ steps.test.outputs.needs-updating }}" != "false" ]]; then + exit 1 + fi + + test4: name: Test Update Needed on ARM64 runs-on: ubuntu-22.04 steps: @@ -72,7 +95,10 @@ jobs: exit 1 fi - test4: + ##################################### + # Test with multiple platforms + + test5: name: Test Update Needed on multiple platforms runs-on: ubuntu-22.04 steps: @@ -93,7 +119,7 @@ jobs: exit 1 fi - test5: + test6: name: Test Update Not Needed on multiple platforms runs-on: ubuntu-22.04 steps: @@ -113,9 +139,11 @@ jobs: if [[ "${{ steps.test.outputs.needs-updating }}" != "false" ]]; then exit 1 fi + ##################################### + # Test with platform variants - test6: - name: Test single platform + test7: + name: Test Update Needed on multiple platforms with variants runs-on: ubuntu-22.04 steps: - name: Checkout Repository @@ -124,8 +152,30 @@ jobs: id: test uses: ./ with: - base-image: alpine:3.17.1 - image: lucacome/alpine-amd64 + base-image: alpine:latest + image: golang:1.14.15-alpine3.13 + platforms: linux/arm64/v8,linux/arm/v7,linux/amd64 + - name: Get Test Output + run: echo "Workflow Docker Image ${{ steps.test.outputs.needs-updating }}" + - name: Check value + run: | + if [[ "${{ steps.test.outputs.needs-updating }}" != "true" ]]; then + exit 1 + fi + + test8: + name: Test Update Not Needed on multiple platforms with variants + runs-on: ubuntu-22.04 + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + - name: Test Action + id: test + uses: ./ + with: + base-image: alpine:3.17.2 + image: alpine:3.17.2 + platforms: linux/arm64/v8,linux/arm/v7,linux/amd64 - name: Get Test Output run: echo "Workflow Docker Image ${{ steps.test.outputs.needs-updating }}" - name: Check value diff --git a/docker.sh b/docker.sh index c0f899c..c5f58d1 100755 --- a/docker.sh +++ b/docker.sh @@ -28,14 +28,16 @@ get_manifests() { fi headers=$(cat headers | awk -F ': ' '{sub(/\r/,"\n",$2); print $1","$2}' | grep 'docker-content-digest\|content-type' | jq -R 'split(",") | {(if .[0] == "content-type" then "type" else "digest" end): .[1]}' | jq -s 'reduce .[] as $item ({}; . * $item)') - manifest_v2=$(jq -r '. | select(.type == "application/vnd.docker.distribution.manifest.v2+json" or .type == "application/vnd.oci.image.manifest.v1+json") | [{digest: .digest, platform: "linux/amd64"}]' <<<"$headers") + manifest_v2=$(jq -r '. | select(.type == "application/vnd.docker.distribution.manifest.v2+json" or .type == "application/vnd.oci.image.manifest.v1+json") | [{digest: .digest, platforms: ["linux/amd64"]}]' <<<"$headers") if [ ! -z "$manifest_v2" ]; then echo "$manifest_v2" return fi - jq -r '[.manifests[] | select(.platform.architecture | contains ("unknown") | not) | {digest: .digest, platform: (.platform.os +"/"+ .platform.architecture)}]' <<<"$manifest_list" - + manifests_with_variant=$(jq -r '[.manifests[] | select(.platform.architecture | contains ("unknown") | not) | select(.platform.variant != null) | {digest: .digest, platforms: [(.platform.os +"/"+ .platform.architecture +"/"+ .platform.variant), (.platform.os +"/"+ .platform.architecture)] }]' <<<"$manifest_list") + manifests_without_variant=$(jq -r '[.manifests[] | select(.platform.architecture | contains ("unknown") | not) | select(.platform.variant == null) | {digest: .digest, platforms: [(.platform.os +"/"+ .platform.architecture)]}]' <<<"$manifest_list") + # Concat both lists + echo "${manifests_with_variant}${manifests_without_variant}" | jq -s 'flatten(1)' } get_layers() { @@ -111,7 +113,7 @@ diff=false # loop through plafforms split by comma for platform in $(echo $platforms | tr -s ',' ' '); do # get the digest for the platform - digest_base=$(jq -r ".[] | select(.platform == \"$platform\") | .digest" <<<"$manifests_base") + digest_base=$(jq -r ".[] | select(.platforms[] == \"$platform\") | .digest" <<<"$manifests_base") # if the digest is empty, then the platform is not present in the base image if [ -z "$digest_base" ]; then @@ -119,7 +121,7 @@ for platform in $(echo $platforms | tr -s ',' ' '); do fi # get the digest for the platform - digest_image=$(jq -r ".[] | select(.platform == \"$platform\") | .digest" <<<"$manifests_image") + digest_image=$(jq -r ".[] | select(.platforms[] == \"$platform\") | .digest" <<<"$manifests_image") # if the digest is empty, then the platform is not present in the image if [ -z "$digest_image" ]; then