Docker build & push #155
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: "Docker build & push" | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| sha: | |
| description: 'The commit SHA to build' | |
| type: string | |
| required: true | |
| branch_name: | |
| description: 'The branch name to build' | |
| type: string | |
| required: true | |
| workflow_call: | |
| inputs: | |
| sha: | |
| required: true | |
| type: string | |
| branch_name: | |
| required: true | |
| type: string | |
| outputs: | |
| image_version: | |
| description: "Docker branch tag" | |
| value: ${{ jobs.calculate_version.outputs.image_version }} | |
| build_version: | |
| description: "Docker version tag" | |
| value: ${{ jobs.calculate_version.outputs.build_version }} | |
| env: | |
| DOCKER_CLI_EXPERIMENTAL: enabled | |
| IMAGE_NAME: "${{ vars.DOCKERHUB_ORG }}/label-studio" | |
| DOCKER_IMAGE_TAG_CHECK_NAME: "Docker image tag" | |
| POETRY_VERSION: 2.1.4 | |
| jobs: | |
| calculate_version: | |
| name: "Calculate version" | |
| runs-on: ubuntu-latest | |
| outputs: | |
| image_version: ${{ steps.version.outputs.image_version }} | |
| build_version: ${{ steps.version.outputs.build_version }} | |
| pretty_branch_name: ${{ steps.version.outputs.pretty_branch_name }} | |
| sha: ${{ steps.version.outputs.sha }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| with: | |
| submodules: 'recursive' | |
| ref: ${{ inputs.sha }} | |
| fetch-depth: 1 | |
| - name: Calculate version | |
| id: version | |
| env: | |
| BRANCH_NAME: ${{ inputs.branch_name }} | |
| run: | | |
| set -x | |
| sha="$(git rev-parse HEAD)" | |
| echo "sha=$sha" >> $GITHUB_OUTPUT | |
| pretty_branch_name="$(echo -n "${BRANCH_NAME#refs/heads/}" | sed -E 's#[/_\.-]+#-#g' | tr '[:upper:]' '[:lower:]' | cut -c1-25 | sed -E 's#-$##g')" | |
| echo "pretty_branch_name=${pretty_branch_name}" >> "${GITHUB_OUTPUT}" | |
| regexp='^ls-release\/(.*)$'; | |
| if [[ "$BRANCH_NAME" =~ $regexp ]]; then | |
| image_version="${BASH_REMATCH[1]}rc${sha}" | |
| else | |
| image_version="${pretty_branch_name}" | |
| fi | |
| echo "image_version=${image_version}" >> $GITHUB_OUTPUT | |
| current_time="$(date +'%Y%m%d.%H%M%S')" | |
| branch="-${pretty_branch_name}" | |
| short_sha="$(git rev-parse --short HEAD)" | |
| long_sha="$(git rev-parse HEAD)" | |
| echo "sha=$long_sha" >> $GITHUB_OUTPUT | |
| short_sha_length="$(echo $short_sha | awk '{print length}')" | |
| current_time_length="$(echo $current_time | awk '{print length}')" | |
| version="${current_time}$(echo $branch | cut -c1-$((50 - short_sha_length - current_time_length)))-${short_sha}" | |
| echo "build_version=$version" >> $GITHUB_OUTPUT | |
| docker_build: | |
| name: "Docker image (${{ matrix.platform }})" | |
| timeout-minutes: 90 | |
| runs-on: ${{ matrix.runner }} | |
| needs: calculate_version | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: linux/amd64 | |
| runner: ubuntu-latest | |
| - platform: linux/arm64 | |
| runner: ubuntu-24.04-arm | |
| steps: | |
| - uses: hmarr/debug-action@v3.0.0 | |
| - name: Prepare | |
| run: | | |
| platform=${{ matrix.platform }} | |
| echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| with: | |
| submodules: 'recursive' | |
| ref: ${{ inputs.sha }} | |
| fetch-depth: 0 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3.11.1 | |
| - name: Login to DockerHub | |
| uses: docker/login-action@v3.5.0 | |
| with: | |
| username: ${{ vars.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Download LaunchDarkly Community config | |
| env: | |
| LAUNCHDARKLY_COMMUNITY_SDK_KEY: ${{ secrets.LAUNCHDARKLY_COMMUNITY_SDK_KEY }} | |
| LAUNCHDARKLY_DOWNLOAD_PATH: "label_studio/feature_flags.json" | |
| run: | | |
| set -xeuo pipefail | |
| curl \ | |
| --connect-timeout 30 \ | |
| --retry 5 \ | |
| --retry-delay 10 \ | |
| -H "Authorization: $LAUNCHDARKLY_COMMUNITY_SDK_KEY" \ | |
| "https://sdk.launchdarkly.com/sdk/latest-all" >"$LAUNCHDARKLY_DOWNLOAD_PATH" | |
| if [ "$(jq 'has("flags")' <<< cat $LAUNCHDARKLY_DOWNLOAD_PATH)" = "true" ]; then | |
| echo "feature_flags.json is valid" | |
| else | |
| echo "feature_flags.json is invalid" | |
| cat $LAUNCHDARKLY_DOWNLOAD_PATH | |
| exit 1 | |
| fi | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.IMAGE_NAME }} | |
| - name: Push Docker image (${{ matrix.platform }}) | |
| uses: docker/build-push-action@v6.18.0 | |
| id: docker_build_and_push | |
| with: | |
| context: . | |
| file: Dockerfile | |
| platforms: ${{ matrix.platform }} | |
| sbom: true | |
| provenance: true | |
| tags: ${{ env.IMAGE_NAME }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=min | |
| outputs: type=image,push-by-digest=true,name-canonical=true,push=true | |
| build-args: | | |
| BRANCH_OVERRIDE=${{ inputs.branch_name }} | |
| VERSION_OVERRIDE=${{ needs.calculate_version.outputs.build_version }} | |
| POETRY_VERSION=${{ env.POETRY_VERSION }} | |
| - name: Export digest | |
| run: | | |
| mkdir -p ${{ runner.temp }}/digests | |
| digest="${{ steps.docker_build_and_push.outputs.digest }}" | |
| touch "${{ runner.temp }}/digests/${digest#sha256:}" | |
| - name: Upload digest | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: digests-${{ env.PLATFORM_PAIR }} | |
| path: ${{ runner.temp }}/digests/* | |
| if-no-files-found: error | |
| retention-days: 1 | |
| merge_docker_manifest: | |
| runs-on: ubuntu-latest | |
| needs: | |
| - docker_build | |
| - calculate_version | |
| steps: | |
| - name: Download digests | |
| uses: actions/download-artifact@v5 | |
| with: | |
| path: ${{ runner.temp }}/digests | |
| pattern: digests-* | |
| merge-multiple: true | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ vars.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=raw,value=${{ needs.calculate_version.outputs.image_version }} | |
| type=raw,value=${{ needs.calculate_version.outputs.build_version }} | |
| - name: Create manifest list and push | |
| working-directory: ${{ runner.temp }}/digests | |
| run: | | |
| docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | |
| $(printf '${{ env.IMAGE_NAME }}@sha256:%s ' *) | |
| - name: Inspect image | |
| run: | | |
| docker buildx imagetools inspect ${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} | |
| create_check: | |
| name: "Create Docker image tag Check" | |
| runs-on: ubuntu-latest | |
| needs: [calculate_version, docker_build, merge_docker_manifest] | |
| if: success() | |
| steps: | |
| - name: Create Docker image tag Check | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const { repo, owner } = context.repo; | |
| const details = { | |
| "branch": "${{ inputs.branch_name }}", | |
| "pretty_branch_name": "${{ needs.calculate_version.outputs.pretty_branch_name }}", | |
| "image_version": "${{ needs.calculate_version.outputs.image_version }}", | |
| "sha": "${{ needs.calculate_version.outputs.sha }}" | |
| } | |
| const { data: check } = await github.rest.checks.create({ | |
| owner, | |
| repo, | |
| name: '${{ env.DOCKER_IMAGE_TAG_CHECK_NAME }}', | |
| head_sha: '${{ needs.calculate_version.outputs.sha }}', | |
| status: 'in_progress', | |
| output: { | |
| title: '${{ env.DOCKER_IMAGE_TAG_CHECK_NAME }}', | |
| summary: JSON.stringify(details) | |
| } | |
| }); | |
| await github.rest.checks.update({ | |
| owner, | |
| repo, | |
| check_run_id: check.id, | |
| status: 'completed', | |
| conclusion: 'success' | |
| }); | |
| notify_slack: | |
| name: "Notify Slack" | |
| runs-on: ubuntu-latest | |
| needs: [calculate_version, docker_build, create_check, merge_docker_manifest] | |
| if: always() && github.event_name == 'push' && inputs.branch_name == 'develop' | |
| steps: | |
| - name: Notify to Slack on failure | |
| if: failure() | |
| env: | |
| GITHUB_REPOSITORY: "${{ github.repository }}" | |
| GITHUB_RUN_ID: "${{ github.run_id }}" | |
| GITHUB_SHA: "${{ github.sha }}" | |
| SLACK_BOT_TOKEN: ${{ secrets.SLACK_LSE_BOT_TOKEN }} | |
| uses: slackapi/slack-github-action@v1.27 | |
| with: | |
| channel-id: 'C01RJV08UJK' | |
| slack-message: | | |
| ❌ Docker build failed for *develop* branch! <!subteam^${{ vars.SLACK_GR_DEVOPS }}> | |
| ><https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|[Workflow run]> |