v1.11.5 #436
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
| # Publish flant/shell-operator image on hub.docker.com. | |
| # Build tag from release name when release is published. | |
| # Build 'latest' tag when release is published and marked as 'latest'. | |
| name: Publish release image | |
| on: | |
| workflow_dispatch: | |
| release: | |
| types: [published] | |
| env: | |
| QEMU_PLATFORMS: arm64,arm | |
| BUILDX_PLATFORMS: "linux/amd64,linux/arm64,linux/arm/v7" | |
| DOCKER_HUB_REPO: flant/shell-operator | |
| GHCR_IO_REPO: ghcr.io/flant/shell-operator | |
| jobs: | |
| check: | |
| name: Check | |
| runs-on: ubuntu-latest | |
| outputs: | |
| run_publish: ${{ steps.check.outputs.run_publish }} | |
| image_tag: ${{ steps.check.outputs.image_tag }} | |
| additional_tag: ${{ steps.check.outputs.additional_tag }} | |
| steps: | |
| - uses: actions/github-script@v7 | |
| id: check | |
| with: | |
| script: | | |
| const SKIP_LATEST_LABEL_NAME = 'skip/image/latest'; | |
| const event = context.payload; | |
| const eventName = context.eventName; | |
| let runPublish = false; | |
| let imageTag = ''; | |
| let additionalTag = ''; // Also push additional tag when building a released tag. | |
| // Check ref name for manual running. | |
| if (eventName === 'workflow_dispatch') { | |
| if (event.ref !== 'refs/heads/main') { | |
| return core.setFailed(`Detect manual execution for '${event.ref}'. Use only default branch. Skip 'publish latest image'.`); | |
| } | |
| console.log(`Detect manual execution for default branch. Run 'publish latest image'.`); | |
| runPublish = true; | |
| imageTag = 'latest'; | |
| } | |
| // Check for release is published. | |
| if (eventName === 'release' && event.action === 'published') { | |
| runPublish = true; | |
| imageTag = event.release.tag_name; | |
| // Fetch the "latest" release as defined by GitHub | |
| const { data: latestRelease } = await github.rest.repos.getLatestRelease({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| }); | |
| let isLatest = latestRelease.tag_name === imageTag; | |
| console.log(`DEBUG: latestRelease.tag_name=${latestRelease.tag_name} imageTag=${imageTag} is_latest=${isLatest}`); | |
| // If the release is the "latest" release, build the "latest" tag. | |
| if (isLatest) { | |
| console.log(`Detect current release is the "latest" release. Run 'publish latest image'.`); | |
| additionalTag = 'latest'; | |
| } | |
| } | |
| console.log(`Outputs: run_publish=${runPublish} image_tag=${imageTag} additional_tag=${additionalTag}`); | |
| if (!runPublish) { | |
| console.log(`DEBUG: eventName=${eventName} action=${event.action} ref=${event.ref} merged=${event.pull_request && event.pull_request.merged} prLabels=${JSON.stringify(event.pull_request && event.pull_request.labels)}`) | |
| return console.log(`Skip 'publish latest image'.`); | |
| } | |
| core.setOutput('run_publish', runPublish.toString()); | |
| core.setOutput('image_tag', imageTag); | |
| core.setOutput('additional_tag', additionalTag); | |
| publish_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: | |
| ADDITIONAL_TAG: ${{ needs.check.outputs.additional_tag }} | |
| IMAGE_TAG: ${{ needs.check.outputs.image_tag }} | |
| run: | | |
| : Setup DOCKER_HUB_IMAGE_NAME, DOCKER_HUB_IMAGE_NAME and APP_VERSION for image build | |
| APP_VERSION=${IMAGE_TAG} | |
| if [[ $APP_VERSION == "latest" ]] ; then | |
| APP_VERSION=${GITHUB_REF#refs/heads/}-${GITHUB_SHA::8}-$(date +'%Y.%m.%d_%H:%M:%S') | |
| fi | |
| DOCKER_HUB_IMAGE_NAME="${DOCKER_HUB_REPO}:${IMAGE_TAG}" | |
| GHCR_IO_IMAGE_NAME="${GHCR_IO_REPO}:${IMAGE_TAG}" | |
| if [[ -n $ADDITIONAL_TAG ]] ; then | |
| ADDITIONAL_DOCKER_HUB_IMAGE_NAME="${DOCKER_HUB_REPO}:${ADDITIONAL_TAG}" | |
| ADDITIONAL_GHCR_IO_IMAGE_NAME="${GHCR_IO_REPO}:${ADDITIONAL_TAG}" | |
| fi | |
| echo "APP_VERSION=${APP_VERSION}" >> ${GITHUB_ENV} | |
| echo "DOCKER_HUB_IMAGE_NAME=${DOCKER_HUB_IMAGE_NAME}" >> ${GITHUB_ENV} | |
| echo "ADDITIONAL_DOCKER_HUB_IMAGE_NAME=${ADDITIONAL_DOCKER_HUB_IMAGE_NAME}" >> ${GITHUB_ENV} | |
| echo "GHCR_IO_IMAGE_NAME=${GHCR_IO_IMAGE_NAME}" >> ${GITHUB_ENV} | |
| echo "ADDITIONAL_GHCR_IO_IMAGE_NAME=${ADDITIONAL_GHCR_IO_IMAGE_NAME}" >> ${GITHUB_ENV} | |
| echo "=========================================" | |
| echo "APP_VERSION = $APP_VERSION" | |
| echo "DOCKER_HUB_IMAGE_NAME = $DOCKER_HUB_IMAGE_NAME" | |
| echo "GHCR_IO_IMAGE_NAME = $GHCR_IO_IMAGE_NAME" | |
| [ -n $ADDITIONAL_GHCR_IO_IMAGE_NAME ] && \ | |
| echo "ADDITIONAL_DOCKER_HUB_IMAGE_NAME = $ADDITIONAL_DOCKER_HUB_IMAGE_NAME" && \ | |
| echo "ADDITIONAL_GHCR_IO_IMAGE_NAME = $ADDITIONAL_GHCR_IO_IMAGE_NAME" | |
| echo "=========================================" | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@v3.6.0 | |
| 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/login-action@v3.4.0 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ secrets.GHCR_IO_USER }} | |
| password: ${{ secrets.GHCR_IO_PASS }} | |
| - name: Build and push multi-arch image | |
| run: | | |
| echo "Build and push $FINAL_IMAGE_NAME with version '$APP_VERSION'." | |
| [ -n "$ADDITIONAL_GHCR_IO_IMAGE_NAME" ] && echo "Also push $ADDITIONAL_GHCR_IO_IMAGE_NAME." | |
| echo | |
| docker buildx build \ | |
| --platform $BUILDX_PLATFORMS \ | |
| --build-arg appVersion=$APP_VERSION \ | |
| $( [ -n "$ADDITIONAL_GHCR_IO_IMAGE_NAME" ] && echo "--tag $ADDITIONAL_GHCR_IO_IMAGE_NAME" ) \ | |
| --tag $GHCR_IO_IMAGE_NAME \ | |
| --push \ | |
| . | |
| - name: Inspect binaries | |
| 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}" | |
| else | |
| echo $(echo -n "${manifests}" | openssl dgst -sha256 | sed s/^.stdin.*\ //) ' linux/amd64' | |
| fi \ | |
| | while read digest platform ; do | |
| if [[ ${BUILDX_PLATFORMS} != *"${platform}"* ]] ; then | |
| echo "=====================================" | |
| echo "Ignore image for non-runnable platform ${platform}" | |
| echo " ${image}" | |
| echo "=====================================" | |
| continue | |
| fi | |
| image=${GHCR_IO_IMAGE_NAME}@${digest} | |
| 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 | |
| - name: Copy image to Docker Hub | |
| env: | |
| DOCKER_USER: ${{ secrets.DOCKER_USER }} | |
| DOCKER_PASS: ${{ secrets.DOCKER_PASS }} | |
| run: | | |
| echo "Download crane tool ..." | |
| CRANE_VERSION=$(curl -s "https://api.github.com/repos/google/go-containerregistry/releases/latest" | jq -r '.tag_name') | |
| CRANE_OS=Linux # or Darwin, Windows | |
| CRANE_ARCH=x86_64 # or arm64, x86_64, armv6, i386, s390x, riscv64 | |
| echo "Crane version: ${CRANE_VERSION}, OS: ${CRANE_OS}, ARCH: ${CRANE_ARCH}" | |
| curl -sL "https://github.com/google/go-containerregistry/releases/download/${CRANE_VERSION}/go-containerregistry_${CRANE_OS}_${CRANE_ARCH}.tar.gz" > go-containerregistry.tar.gz | |
| echo "Extract crane tool ..." | |
| tar -zxvf go-containerregistry.tar.gz -C /usr/local/bin/ crane | |
| export PATH=$PATH:/usr/local/bin | |
| echo "Copy ${GHCR_IO_IMAGE_NAME} to ${DOCKER_HUB_IMAGE_NAME} ..." | |
| crane auth login -u ${DOCKER_USER} -p ${DOCKER_PASS} docker.io && \ | |
| crane copy ${GHCR_IO_IMAGE_NAME} ${DOCKER_HUB_IMAGE_NAME} | |
| echo "Copy completed." | |
| if [ -n "$ADDITIONAL_DOCKER_HUB_IMAGE_NAME" ] ; then | |
| echo "Copy ${ADDITIONAL_GHCR_IO_IMAGE_NAME} to ${ADDITIONAL_DOCKER_HUB_IMAGE_NAME} ..." | |
| crane auth login -u ${DOCKER_USER} -p ${DOCKER_PASS} docker.io && \ | |
| crane copy ${ADDITIONAL_GHCR_IO_IMAGE_NAME} ${ADDITIONAL_DOCKER_HUB_IMAGE_NAME} | |
| echo "Copy completed." | |
| fi |