Docker Publish workflow (tangyoha/telegram_media_downloader)
The Docker Publish workflow from tangyoha/telegram_media_downloader, explained and optimized by Latchkey.
CI health: C - fair
Point runs-on at Latchkey and get run de-duplication, job timeouts, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Docker Publish workflow from the tangyoha/telegram_media_downloader repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: Docker Publish
on:
push:
branches:
- master
tags:
- 'v*'
jobs:
build-and-push:
runs-on: ubuntu-latest
outputs:
compile_image_exists: ${{ steps.check-image.outputs.exists }}
requirements_modified: ${{ steps.check-requirements.outputs.modified }}
check-dockerfile: ${{ steps.check-dockerfile.outputs.dockerfile_modified }}
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 2
- name: Check if compile-image exists on Docker Hub
id: check-image
run: |
EXISTS=$(curl --silent --fail --head "https://hub.docker.com/v2/repositories/${{ secrets.DOCKER_HUB_USERNAME }}/telegram_media_downloader_compile/tags/latest" > /dev/null && echo "true" || echo "false")
echo "exists=$EXISTS" >> $GITHUB_ENV
echo "exists=$EXISTS" >> $GITHUB_OUTPUT
- name: Check if requirements.txt has been modified
id: check-requirements
run: |
MODIFIED=$(git diff --name-only HEAD~1 HEAD | grep -w 'requirements.txt' > /dev/null && echo "true" || echo "false")
echo "modified=$MODIFIED" >> $GITHUB_ENV
echo "modified=$MODIFIED" >> $GITHUB_OUTPUT
- name: Check if Dockerfile has been modified
id: check-dockerfile
run: |
DOCKERFILE_MODIFIED=$(git diff --name-only HEAD~1 HEAD | grep -w 'Dockerfile' > /dev/null && echo "true" || echo "false")
echo "dockerfile_modified=$DOCKERFILE_MODIFIED" >> $GITHUB_ENV
echo "dockerfile_modified=$DOCKERFILE_MODIFIED" >> $GITHUB_OUTPUT
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Print Env
id: env_aa
run: |
echo ${{ steps.check-image.outputs.exists }}
echo ${{ steps.check-requirements.outputs.modified }}
echo ${{ steps.check-dockerfile.outputs.dockerfile_modified }}
- name: Build and push compile-image
if: ${{ !(steps.check-image.outputs.exists == 'true' && steps.check-requirements.outputs.modified == 'false' && steps.check-dockerfile.outputs.dockerfile_modified == 'false') }}
uses: docker/build-push-action@v4
with:
context: .
push: true
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6,linux/386,linux/ppc64le
target: compile-image
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/telegram_media_downloader_compile:latest
- name: Build and push runtime-image
uses: docker/build-push-action@v4
with:
context: .
push: true
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6,linux/386,linux/ppc64le
target: runtime-image
tags: |
${{ secrets.DOCKER_HUB_USERNAME }}/telegram_media_downloader:latest
${{ secrets.DOCKER_HUB_USERNAME }}/telegram_media_downloader:${{ github.ref_name }}
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: Docker Publish on: push: branches: - master tags: - 'v*' concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build-and-push: timeout-minutes: 30 runs-on: latchkey-small outputs: compile_image_exists: ${{ steps.check-image.outputs.exists }} requirements_modified: ${{ steps.check-requirements.outputs.modified }} check-dockerfile: ${{ steps.check-dockerfile.outputs.dockerfile_modified }} steps: - name: Checkout uses: actions/checkout@v2 with: fetch-depth: 2 - name: Check if compile-image exists on Docker Hub id: check-image run: | EXISTS=$(curl --silent --fail --head "https://hub.docker.com/v2/repositories/${{ secrets.DOCKER_HUB_USERNAME }}/telegram_media_downloader_compile/tags/latest" > /dev/null && echo "true" || echo "false") echo "exists=$EXISTS" >> $GITHUB_ENV echo "exists=$EXISTS" >> $GITHUB_OUTPUT - name: Check if requirements.txt has been modified id: check-requirements run: | MODIFIED=$(git diff --name-only HEAD~1 HEAD | grep -w 'requirements.txt' > /dev/null && echo "true" || echo "false") echo "modified=$MODIFIED" >> $GITHUB_ENV echo "modified=$MODIFIED" >> $GITHUB_OUTPUT - name: Check if Dockerfile has been modified id: check-dockerfile run: | DOCKERFILE_MODIFIED=$(git diff --name-only HEAD~1 HEAD | grep -w 'Dockerfile' > /dev/null && echo "true" || echo "false") echo "dockerfile_modified=$DOCKERFILE_MODIFIED" >> $GITHUB_ENV echo "dockerfile_modified=$DOCKERFILE_MODIFIED" >> $GITHUB_OUTPUT - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Login to Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Print Env id: env_aa run: | echo ${{ steps.check-image.outputs.exists }} echo ${{ steps.check-requirements.outputs.modified }} echo ${{ steps.check-dockerfile.outputs.dockerfile_modified }} - name: Build and push compile-image if: ${{ !(steps.check-image.outputs.exists == 'true' && steps.check-requirements.outputs.modified == 'false' && steps.check-dockerfile.outputs.dockerfile_modified == 'false') }} uses: docker/build-push-action@v4 with: context: . push: true platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6,linux/386,linux/ppc64le target: compile-image tags: ${{ secrets.DOCKER_HUB_USERNAME }}/telegram_media_downloader_compile:latest - name: Build and push runtime-image uses: docker/build-push-action@v4 with: context: . push: true platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6,linux/386,linux/ppc64le target: runtime-image tags: | ${{ secrets.DOCKER_HUB_USERNAME }}/telegram_media_downloader:latest ${{ secrets.DOCKER_HUB_USERNAME }}/telegram_media_downloader:${{ github.ref_name }}
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Cancel superseded runs when a branch or PR gets a newer push.
- Add a job timeout so a hung step cannot burn hours of runner time.
3 third-party actions are referenced by a movable tag. Pin them to the commit SHA (Latchkey resolves and applies this automatically) so a repointed tag cannot change what runs.
What Latchkey heals here
This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:
- Container pulls and builds
This workflow runs 1 job per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.