Skip to content

Docker build & push #155

Docker build & push

Docker build & push #155

Workflow file for this run

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]>