From cbaa32c746a1b98fb0db99bbbff92ad4aa733b44 Mon Sep 17 00:00:00 2001 From: Lars Gohr Date: Sat, 9 Apr 2022 22:25:56 +0200 Subject: [PATCH] :rocket: Enable building multiarch images --- Dockerfile | 2 +- action.yml | 6 +++++- entrypoint.sh | 17 ++++++++++++++--- test.bats | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 808f917..35c22ee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ RUN apt-get update \ && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \ && apt-get update \ - && apt-get install -y docker-ce docker-ce-cli containerd.io + && apt-get install -y docker-ce docker-ce-cli containerd.io jq ADD entrypoint.sh /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] diff --git a/action.yml b/action.yml index 2452c4b..6d34270 100644 --- a/action.yml +++ b/action.yml @@ -53,6 +53,9 @@ inputs: no_push: description: 'Set no_push to true if you want to prevent the action from pushing to a registry (default: false)' required: false + platforms: + description: 'Use platforms for building multi-arch images' + required: false outputs: tag: description: 'Is the tag, which was pushed' @@ -85,4 +88,5 @@ runs: INPUT_TAGS: ${{ inputs.tags }} INPUT_TAG_NAMES: ${{ inputs.tag_names }} INPUT_TAG_SEMVER: ${{ inputs.tag_semver }} - INPUT_NO_PUSH: ${{ inputs.no_push }} \ No newline at end of file + INPUT_NO_PUSH: ${{ inputs.no_push }} + INPUT_PLATFORMS: ${{ inputs.platforms }} \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh index df6f824..b77cdd3 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -62,10 +62,16 @@ main() { exit 0 fi - push + if ! uses "${INPUT_PLATFORMS}"; then + push + fi echo "::set-output name=tag::${FIRST_TAG}" - DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' ${DOCKERNAME}) + if uses "${INPUT_PLATFORMS}"; then + DIGEST=$(jq -r '."containerimage.digest"' metadata.json) + else + DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' ${DOCKERNAME}) + fi echo "::set-output name=digest::${DIGEST}" docker logout @@ -184,7 +190,12 @@ build() { for TAG in ${TAGS}; do BUILD_TAGS="${BUILD_TAGS}-t ${INPUT_NAME}:${TAG} " done - docker build ${INPUT_BUILDOPTIONS} ${BUILDPARAMS} ${BUILD_TAGS} ${CONTEXT} + if uses "${INPUT_PLATFORMS}"; then + local PLATFORMS="--platform ${INPUT_PLATFORMS}" + docker buildx build --push --metadata-file metadata.json ${PLATFORMS} ${INPUT_BUILDOPTIONS} ${BUILDPARAMS} ${BUILD_TAGS} ${CONTEXT} + else + docker build ${INPUT_BUILDOPTIONS} ${BUILDPARAMS} ${BUILD_TAGS} ${CONTEXT} + fi } push() { diff --git a/test.bats b/test.bats index 5e3749d..e6f33fc 100755 --- a/test.bats +++ b/test.bats @@ -647,6 +647,58 @@ teardown() { /usr/local/mock/docker logout" } +@test "it supports building multiple platforms" { + export GITHUB_REF='refs/heads/main' + export INPUT_PLATFORMS='linux/amd64,linux/arm64' + + cat <> metadata.json +{ + "containerimage.buildinfo/linux/amd64": { + "frontend": "dockerfile.v0", + "attrs": { + "filename": "Dockerfile" + }, + "sources": [ + { + "type": "docker-image", + "ref": "docker.io/library/alpine:latest", + "pin": "sha256:7580ece7963bfa863801466c0a488f11c86f85d9988051a9f9c68cb27f6b7872" + } + ] + }, + "containerimage.buildinfo/linux/arm64": { + "frontend": "dockerfile.v0", + "attrs": { + "filename": "Dockerfile" + }, + "sources": [ + { + "type": "docker-image", + "ref": "docker.io/library/alpine:latest", + "pin": "sha256:7580ece7963bfa863801466c0a488f11c86f85d9988051a9f9c68cb27f6b7872" + } + ] + }, + "containerimage.descriptor": { + "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", + "digest": "sha256:aa2c7631cc1bbf588192ec7e55b428ad92fe63834200303f28e93444d7fc114a", + "size": 741 + }, + "containerimage.digest": "sha256:aa2c7631cc1bbf588192ec7e55b428ad92fe63834200303f28e93444d7fc114a", + "image.name": "my/repository:latest" +} +EOT + + run /entrypoint.sh + + expectStdOutContains "::set-output name=tag::latest::set-output name=digest::sha256:aa2c7631cc1bbf588192ec7e55b428ad92fe63834200303f28e93444d7fc114a" + + expectMockCalledContains "/usr/local/mock/docker login -u USERNAME --password-stdin +/usr/local/mock/docker buildx build --push --metadata-file metadata.json --platform linux/amd64,linux/arm64 -t my/repository:latest . +/usr/local/mock/docker logout" + expectMockArgs "" +} + expectStdOutIs() { local expected=$(echo "${1}" | tr -d '\n') local got=$(echo "${output}" | tr -d '\n')