build-push-action icon indicating copy to clipboard operation
build-push-action copied to clipboard

Build image from specific ref

Open Starttoaster opened this issue 1 year ago • 2 comments

Description

I would like a ref variable in this Action to allow building an image from a specific ref, that may not be the same as the ref that triggered the Actions workflow.

The problem this would solve is that, in GitHub Actions, you cannot make a scheduled workflow that targets anything but your default branch. And I would like to make a scheduled workflow to rebuild a few image tags that will easily go stale on security patches from the base distro images they use.

Take, for example, the following workflow definition that currently only does not work because this Action forces the build-push step to use the branch that triggered the workflow:

name: Publish docker image

on:
  push:
    branches:
      - main
  workflow_dispatch:
  schedule:
    # Monday at 9am UTC
    - cron: '0 9 * * 1'

permissions:
  id-token: write
  contents: read
  packages: write

jobs:
  package:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    # Need this matrix because GitHub doesn't support running scheduled workflows against non-default branches
    # This checks out each branch listed here, and there are separate docker meta and build steps for each branch in the matrix.
    strategy:
      matrix:
        branch:
          - main
          - v1.0.x
    steps:
      - name: Add safe git directory
        run: git config --global --add safe.directory "$GITHUB_WORKSPACE"

      - uses: actions/checkout@v4
        with:
          ref: ${{ matrix.branch }}

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ github.token }}

      - name: Docker meta on main
        if: matrix.branch == 'main'
        id: meta-main
        uses: docker/metadata-action@v5
        with:
          images: |
            ghcr.io/${{ github.repository }}
          flavor: |
            latest=false
            prefix=
            suffix=
          tags: |
            type=raw,value=main,enable={{is_default_branch}}
            type=sha,format=long

      - name: Build Docker Container on main
        if: matrix.branch == 'main'
        uses: docker/build-push-action@v5
        with:
          platforms: "linux/amd64,linux/arm64"
          push: true
          tags: ${{ steps.meta-main.outputs.tags }}
          labels: ${{ steps.meta-main.outputs.labels }}

      - name: Docker meta on v1.0.x
        if: matrix.branch == 'v1.0.x'
        id: meta-v1dot0
        uses: docker/metadata-action@v5
        with:
          images: |
            ghcr.io/${{ github.repository }}
          flavor: |
            latest=false
            prefix=
            suffix=
          tags: |
            type=raw,value=1.0
            type=sha,format=long

      - name: Build Docker Container on v1.0.x
        if: matrix.branch == 'v1.0.x'
        uses: docker/build-push-action@v5
        with:
          platforms: "linux/amd64,linux/arm64"
          push: true
          tags: ${{ steps.meta-v1dot0.outputs.tags }}
          labels: ${{ steps.meta-v1dot0.outputs.labels }}

Starttoaster avatar Apr 22 '24 21:04 Starttoaster

Loosely related to this person's Issue: https://github.com/docker/build-push-action/issues/467 But is not a duplicate. They were apparently fine with the proposed "add the branch to your on-push workflow trigger list" suggestion. That doesn't work for scheduled workflows though. Hopefully Docker recognizes this as a valid pain point, as maintaining images that are based on upstream distro images like alpine:latest will naturally require pulling in OS updates for security patches. And it is not uncommon to have multiple supported versions of the software you distribute that live on different branches.

Starttoaster avatar Apr 22 '24 21:04 Starttoaster

As far as a proposed solution goes, I think this Action could go one of two ways (besides just ignoring the request and labeling this issue with wont-fix):

  • An input that tells the Action which ref to use
  • An input that tells the Action to just use the ref already checked out (likely by actions/checkout)

Starttoaster avatar Apr 22 '24 21:04 Starttoaster

An input that tells the Action to just use the ref already checked out (likely by actions/checkout)

This is already possible using the Git context with context: "{{defaultContext}}#${{ matrix.branch }}", so you don't need to use the actions/checkout:

jobs:
  package:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    # Need this matrix because GitHub doesn't support running scheduled workflows against non-default branches
    # This checks out each branch listed here, and there are separate docker meta and build steps for each branch in the matrix.
    strategy:
      matrix:
        branch:
          - main
          - v1.0.x
    steps:
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ github.token }}

      - name: Docker meta on main
        if: matrix.branch == 'main'
        id: meta-main
        uses: docker/metadata-action@v5
        with:
          images: |
            ghcr.io/${{ github.repository }}
          flavor: |
            latest=false
            prefix=
            suffix=
          tags: |
            type=raw,value=main,enable={{is_default_branch}}
            type=sha,format=long

      - name: Build Docker Container on main
        if: matrix.branch == 'main'
        uses: docker/build-push-action@v5
        with:
          context: "{{defaultContext}}#${{ matrix.branch }}"
          platforms: "linux/amd64,linux/arm64"
          push: true
          tags: ${{ steps.meta-main.outputs.tags }}
          labels: ${{ steps.meta-main.outputs.labels }}

      - name: Docker meta on v1.0.x
        if: matrix.branch == 'v1.0.x'
        id: meta-v1dot0
        uses: docker/metadata-action@v5
        with:
          images: |
            ghcr.io/${{ github.repository }}
          flavor: |
            latest=false
            prefix=
            suffix=
          tags: |
            type=raw,value=1.0
            type=sha,format=long

      - name: Build Docker Container on v1.0.x
        if: matrix.branch == 'v1.0.x'
        uses: docker/build-push-action@v5
        with:
          context: "{{defaultContext}}#${{ matrix.branch }}"
          platforms: "linux/amd64,linux/arm64"
          push: true
          tags: ${{ steps.meta-v1dot0.outputs.tags }}
          labels: ${{ steps.meta-v1dot0.outputs.labels }}

Also I'm not sure of the intent of this workflow but that doesn't sound right to me to have sequential builds like this when you're using a matrix. There should be one per-matrix job imo.

crazy-max avatar Jun 12 '24 14:06 crazy-max

Thanks for clueing me in on that bit of config!

Also I'm not sure of the intent of this workflow but that doesn't sound right to me to have sequential builds like this when you're using a matrix. There should be one per-matrix job imo.

The if statements I put in the steps make it so only one of those docker builds run in each of the matrix jobs. I assume you missed that bit in your advice here. I suppose I could maybe have used a matrix variable to consolidate all of those differing step definitions into one, to make it a bit more obvious what I was doing in that job, rather than using the if statements.

But anyway, thank you!

Starttoaster avatar Jul 12 '24 17:07 Starttoaster