Fix race condition #384
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
# Publish flant/shell-operator-dev image to hub.docker.com and ghcr.io. | |
# Start when PR is labeled with 'publish/image/dev' or 'publish/image/dev/amd64'. | |
# Label 'publish/image/dev/amd64' publishes image only for amd64 arhitecture. | |
# Label 'publish/image/dev' publishes a multi-arch image, it is a long-lasting operation (~1h). | |
name: Publish dev image | |
on: | |
pull_request: | |
types: [labeled] | |
env: | |
QEMU_PLATFORMS: arm64,arm | |
BUILDX_PLATFORMS: "linux/amd64,linux/arm64,linux/arm/v7" | |
BUILDX_PLATFORMS_AMD64: "linux/amd64" | |
GHCR_IO_REPO: ghcr.io/flant/shell-operator-dev | |
jobs: | |
check: | |
name: Check and remove label | |
runs-on: ubuntu-latest | |
outputs: | |
run_publish: ${{ steps.check.outputs.run_publish }} | |
build_multi_arch: ${{ steps.check.outputs.build_multi_arch }} | |
steps: | |
- uses: actions/github-script@v6 | |
id: check | |
with: | |
script: | | |
const PUBLISH_DEV_LABEL = 'publish/image/dev'; | |
const PUBLISH_AMD64_LABEL = 'publish/image/dev/amd64'; | |
const labelName = context.payload.label.name; | |
let runPublish = false; | |
let buildMultiArch = false; | |
if (labelName === PUBLISH_DEV_LABEL) { | |
runPublish = true; | |
buildMultiArch = true; | |
} | |
if (labelName === PUBLISH_AMD64_LABEL) { | |
runPublish = true; | |
} | |
if (!runPublish) { | |
return console.log(`Not a 'publish' label: '${labelName}'. Skip 'publish dev image'.`); | |
} | |
if (buildMultiArch) { | |
console.log(`Detect 'publish' label '${labelName}'. Remove label and run 'publish dev image' for all architectures.`); | |
} else { | |
console.log(`Detect 'publish' label '${labelName}'. Remove label and run 'publish dev image' for amd64 arch only.`); | |
} | |
core.setOutput('run_publish', 'true'); | |
core.setOutput('build_multi_arch', buildMultiArch.toString()); | |
try { | |
await github.rest.issues.removeLabel({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
issue_number: context.issue.number, | |
name: labelName, | |
}); | |
} catch (e) { | |
console.log(`Error occurred while remove label. Possibly label is already removed. Ignore '${typeof e}' error.`); | |
} | |
publish_dev_image: | |
name: Build and publish | |
runs-on: ubuntu-latest | |
needs: | |
- check | |
if: needs.check.outputs.run_publish == 'true' | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Prepare environment | |
env: | |
BUILD_MULTI_ARCH: ${{ needs.check.outputs.build_multi_arch }} | |
run: | | |
: Image name and version for dev image | |
# Example: dev-feat_branch-371e2d3b-2020.02.06_18:37:42 | |
APP_VERSION=dev-${GITHUB_REF#refs/heads/}-${GITHUB_SHA::8}-$(date +'%Y.%m.%d_%H:%M:%S') | |
GHCR_IO_IMAGE_NAME="${GHCR_IO_REPO}:pr${{ github.event.pull_request.number }}" | |
echo "APP_VERSION=${APP_VERSION}" >> ${GITHUB_ENV} | |
echo "GHCR_IO_IMAGE_NAME=${GHCR_IO_IMAGE_NAME}" >> ${GITHUB_ENV} | |
echo "=========================================" | |
echo "APP_VERSION = $APP_VERSION" | |
echo "GHCR_IO_IMAGE_NAME = $GHCR_IO_IMAGE_NAME" | |
echo "=========================================" | |
if [[ ${BUILD_MULTI_ARCH} == "false" ]] ; then | |
echo "BUILDX_PLATFORMS=${BUILDX_PLATFORMS_AMD64}" >> ${GITHUB_ENV} | |
fi | |
echo "BUILD_MULTI_ARCH = ${BUILD_MULTI_ARCH}" | |
echo "BUILDX_PLATFORMS = ${BUILDX_PLATFORMS}" | |
echo "=========================================" | |
- name: Set up QEMU | |
if: needs.check.outputs.build_multi_arch == 'true' | |
uses: docker/[email protected] | |
with: | |
platforms: "${{ env.QEMU_PLATFORMS }}" | |
- name: Set up Docker Buildx | |
id: buildx | |
uses: docker/setup-buildx-action@v3 | |
with: | |
version: latest | |
- name: Login to Github Container Registry | |
uses: docker/[email protected] | |
with: | |
registry: ghcr.io | |
username: ${{ secrets.GHCR_IO_USER }} | |
password: ${{ secrets.GHCR_IO_PASS }} | |
- name: Build and push using buildx | |
run: | | |
echo "Build ${GHCR_IO_IMAGE_NAME} with version '${APP_VERSION}'" | |
docker buildx build \ | |
--platform $BUILDX_PLATFORMS \ | |
--build-arg appVersion=$APP_VERSION \ | |
--tag $GHCR_IO_IMAGE_NAME \ | |
--push . | |
- name: Inspect binaries | |
if: needs.check.outputs.build_multi_arch == 'true' | |
run: | | |
# Image for one arhitecture has digest in config field. | |
# Image with multiple manifests has digest in each manifest. | |
manifests=$(docker buildx imagetools inspect "${GHCR_IO_IMAGE_NAME}" --raw) | |
if grep manifests <<<"${manifests}" 2>&1 >/dev/null ; then | |
jq -r '.manifests[]? | .digest + " " + .platform.os + "/" + .platform.architecture' <<<"${manifests}" \ | |
| while read digest platform ; do | |
image=${GHCR_IO_IMAGE_NAME}@${digest} | |
if [[ ${BUILDX_PLATFORMS} != *"${platform}"* ]] ; then | |
echo "=====================================" | |
echo "Ignore image for non-runnable platform ${platform}" | |
echo " ${image}" | |
echo "=====================================" | |
continue | |
fi | |
echo "=====================================" | |
echo "Inspect image for platform ${platform}" | |
echo " ${image}" | |
echo "=====================================" | |
docker run --rm --platform ${platform} --entrypoint sh ${image} -c \ | |
'apk add file > /dev/null; file /bin/kubectl; file /bin/busybox; file /shell-operator' | |
done | |
else | |
echo Not a multi-arhitecture image. | |
#echo $(echo -n "${manifests}" | openssl dgst -sha256) ' linux/amd64' | |
fi |