Release Docker image #4
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
| name: Release Docker image | |
| # Manual-only: builds the runtime image for every platform in `platforms` and pushes it to Docker Hub | |
| # as one multi-arch manifest per tag, so a single tag serves x86_64 Linux/Windows-WSL2/Intel Mac and | |
| # arm64 (Apple Silicon, Ampere) alike. | |
| # | |
| # It always builds the branch it was dispatched from ("Use workflow from") - there is no ref input, so | |
| # there is no second branch to keep in sync with the one you picked. | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| image: | |
| description: Docker Hub repository to push to | |
| required: true | |
| default: josefprochazka/actor-runtime-dev | |
| extra_tag: | |
| description: Optional extra tag to publish alongside the branch tags (e.g. v0.1.0) | |
| required: false | |
| default: '' | |
| latest: | |
| description: Also publish this build as :latest | |
| type: boolean | |
| required: false | |
| default: false | |
| platforms: | |
| description: Target platforms for the multi-arch manifest | |
| required: true | |
| default: linux/amd64,linux/arm64 | |
| jobs: | |
| release: | |
| name: Build and push ${{ inputs.image }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| steps: | |
| # No `ref:` - checkout defaults to the commit the workflow was dispatched from, which is | |
| # exactly the branch picked in "Use workflow from". | |
| - uses: actions/checkout@v4 | |
| # Fail here rather than three slow build steps later, with the fix named. | |
| - name: Check Docker Hub credentials are configured | |
| env: | |
| DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} | |
| DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} | |
| run: | | |
| if [ -z "$DOCKERHUB_USERNAME" ] || [ -z "$DOCKERHUB_TOKEN" ]; then | |
| echo "::error::Missing DOCKERHUB_USERNAME / DOCKERHUB_TOKEN repository secrets." \ | |
| "Create an access token at https://hub.docker.com/settings/security and add both" \ | |
| "under Settings -> Secrets and variables -> Actions." | |
| exit 1 | |
| fi | |
| # A Docker tag may only contain [A-Za-z0-9_.-] and must start with an alphanumeric, so a | |
| # branch name like `feat/foo` cannot be used as a tag verbatim. | |
| - name: Compute image tags | |
| id: tags | |
| env: | |
| IMAGE: ${{ inputs.image }} | |
| BRANCH: ${{ github.ref_name }} | |
| EXTRA_TAG: ${{ inputs.extra_tag }} | |
| LATEST: ${{ inputs.latest }} | |
| run: | | |
| set -euo pipefail | |
| slug=$(printf '%s' "$BRANCH" | tr -c 'A-Za-z0-9_.-' '-' | sed 's/^[^A-Za-z0-9]*//' | cut -c1-100) | |
| if [ -z "$slug" ]; then | |
| echo "::error::Branch '$BRANCH' contains no characters usable in a Docker tag." | |
| exit 1 | |
| fi | |
| sha=$(git rev-parse --short HEAD) | |
| # The `<branch>-<sha>` tag is the immutable one - `<branch>` and `latest` move. | |
| tags="${IMAGE}:${slug}-${sha}" | |
| tags="${tags}"$'\n'"${IMAGE}:${slug}" | |
| if [ -n "$EXTRA_TAG" ]; then | |
| tags="${tags}"$'\n'"${IMAGE}:${EXTRA_TAG}" | |
| fi | |
| if [ "$LATEST" = "true" ]; then | |
| tags="${tags}"$'\n'"${IMAGE}:latest" | |
| fi | |
| { | |
| echo 'tags<<EOF' | |
| echo "$tags" | |
| echo 'EOF' | |
| } >> "$GITHUB_OUTPUT" | |
| echo "revision=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" | |
| # Emulation for any target platform the runner isn't. Only the final stage is emulated - | |
| # the Dockerfile's builder stages are pinned to $BUILDPLATFORM and run natively. | |
| - uses: docker/setup-qemu-action@v3 | |
| - uses: docker/setup-buildx-action@v3 | |
| - uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Build and push | |
| id: build | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| platforms: ${{ inputs.platforms }} | |
| push: true | |
| tags: ${{ steps.tags.outputs.tags }} | |
| provenance: mode=max | |
| sbom: true | |
| # One shared scope: a `type=gha` value is itself a comma-separated key=value list, | |
| # so interpolating the (comma-separated) platform list into `scope` would end the | |
| # value early and buildx would reject the leftover as a key. Sharing the scope also | |
| # lets a single-platform run reuse the layers a multi-arch run already cached. | |
| cache-from: type=gha,scope=release | |
| cache-to: type=gha,mode=max,scope=release | |
| labels: | | |
| org.opencontainers.image.title=actor-runtime | |
| org.opencontainers.image.description=A minimal, self-contained local Apify platform in a single Docker image. | |
| org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} | |
| org.opencontainers.image.revision=${{ steps.tags.outputs.revision }} | |
| org.opencontainers.image.version=${{ github.ref_name }} | |
| - name: Summary | |
| env: | |
| TAGS: ${{ steps.tags.outputs.tags }} | |
| DIGEST: ${{ steps.build.outputs.digest }} | |
| run: | | |
| { | |
| echo "### Pushed \`${{ inputs.platforms }}\`" | |
| echo | |
| echo "Digest: \`${DIGEST}\`" | |
| echo | |
| echo "$TAGS" | sed 's/^/- `/; s/$/`/' | |
| } >> "$GITHUB_STEP_SUMMARY" |