--- name: Docker Build and Push on: # REUSABLE WORKFLOW with INPUTS # to keep this workflow simple, assumptions are made: # - only able to push to Docker Hub and/or GHCR (GHCR by default) # - Builds on PR with tag of `prNUMBER` (same tag each PR push) # - Builds on push to main branch with tag of `latest` # - Builds on tag push with semver workflow_call: # allow reuse of this workflow in other repos inputs: dockerhub-enable: description: Log into Docker Hub required: false default: false type: boolean ghcr-enable: description: Log into GHCR required: false default: true type: boolean comment-enable: description: Create a PR comment with image tags and labels required: false default: true type: boolean context: description: Docker context (path) to start build from required: false type: string default: . file: description: Dockerfile to build, relative to context path required: false type: string target: description: Build stage to target required: false type: string platforms: description: Platforms to build for required: false type: string # common ones: linux/amd64,linux/arm64,linux/arm/v7 default: linux/amd64 image-names: description: A list of the account/repo names for docker build required: false type: string default: | ${{ github.repository }} ghcr.io/${{ github.repository }} tag-rules: # https://github.com/marketplace/actions/docker-metadata-action#tags-input description: Use docker-metadata action to create tags from a key-value pair list in CSV format required: false type: string default: | type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} type=raw,value=stable-{{date 'YYYYMMDDHHmmss'}},enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} type=ref,event=pr type=raw,value=gha-${{ github.run_id }} flavor-rules: # https://github.com/marketplace/actions/docker-metadata-action#flavor-input description: Three rules to (optionally) set for tag-rules, latest, prefix, and suffix required: false type: string default: | latest=false secrets: dockerhub-username: description: Docker Hub username required: false dockerhub-token: description: Docker Hub token required: false outputs: ghcr-tag: description: "single-use tag for ghcr.io" value: ${{ jobs.build-image.outputs.ghcr-tag }} # permissions: GITHUB_TOKEN are better set by the **calling** workflow # but we'll set defaults here for reference # https://docs.github.com/en/actions/using-workflows/reusing-workflows#supported-keywords-for-jobs-that-call-a-reusable-workflow permissions: contents: read packages: write # needed to push docker image to ghcr.io pull-requests: write # needed to create and update comments in PRs jobs: build-image: name: Build+Push runs-on: ubuntu-latest outputs: # only outputs the unique gha- image tag that's unique to each build ghcr-tag: ${{ steps.ghcr-tag.outputs.tag }} steps: - name: Checkout uses: actions/checkout@v3 - # we need qemu and buildx so we can build multiple platforms later name: Set up QEMU id: qemu uses: docker/setup-qemu-action@v2 - # BuildKit (used with `docker buildx`) is the best way to build images name: Set up Docker Buildx id: buildx uses: docker/setup-buildx-action@v2 - name: Login to DockerHub if: inputs.dockerhub-enable uses: docker/login-action@v2 with: username: ${{ secrets.dockerhub-username }} password: ${{ secrets.dockerhub-token }} - name: Login to GHCR if: inputs.ghcr-enable uses: docker/login-action@v1 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Docker meta id: docker_meta uses: docker/metadata-action@v4 with: # list of Docker images to use as base name for tags images: ${{ inputs.image-names }} flavor: ${{ inputs.flavor-rules }} tags: ${{ inputs.tag-rules }} - # this will build the images, once per platform, # then push to one or more registries (based on image list above in docker_meta) name: Docker Build and Push id: build_image uses: docker/build-push-action@v3 with: platforms: ${{ inputs.platforms }} context: ${{ inputs.context }} file: ${{ inputs.file }} target: ${{ inputs.target }} builder: ${{ steps.buildx.outputs.name }} # it uses github cache API for faster builds: # https://github.com/docker/build-push-action/blob/master/docs/advanced/cache.md#cache-backend-api cache-from: type=gha cache-to: type=gha,mode=max push: true tags: ${{ steps.docker_meta.outputs.tags }} labels: ${{ steps.docker_meta.outputs.labels }} - # If PR, put image tags in the PR comments # from https://github.com/marketplace/actions/create-or-update-comment name: Find comment for image tags uses: peter-evans/find-comment@v2 if: github.event_name == 'pull_request' && inputs.comment-enable id: fc with: issue-number: ${{ github.event.pull_request.number }} comment-author: 'github-actions[bot]' body-includes: Docker image tag(s) pushed # If PR, put image tags in the PR comments - name: Create or update comment for image tags uses: peter-evans/create-or-update-comment@v2 if: github.event_name == 'pull_request' && inputs.comment-enable with: comment-id: ${{ steps.fc.outputs.comment-id }} issue-number: ${{ github.event.pull_request.number }} body: | Docker image tag(s) pushed: ```text ${{ steps.docker_meta.outputs.tags }} ``` Labels added to images: ```text ${{ steps.docker_meta.outputs.labels }} ``` edit-mode: replace - name: Find the gha-run-based image tag we just pushed to ghcr.io id: ghcr-tag run: | echo '::echo::on' echo "::set-output name=tag::gha-${{ github.run_id }}"