From 0b4fb2da64841cbc5e9dca7f03a2e6250292f1f4 Mon Sep 17 00:00:00 2001 From: Victor Lin <13424970+victorlin@users.noreply.github.com> Date: Tue, 31 May 2022 18:45:35 -0700 Subject: [PATCH] Use GitHub Actions for build/pull/tag/push This replaces the existing scripts with GitHub Actions provided by Docker. Also has the benefit of using buildx which supports building multi-arch images (to be done later): https://docs.docker.com/desktop/multi-arch/ Sequence of steps inspired by https://github.com/docker/build-push-action/blob/master/docs/advanced/isolated-builders.md. --- .github/workflows/ci.yml | 108 +++++++++++++++++++++++++++++++++------ devel/build | 37 -------------- devel/pull | 18 ------- devel/push | 18 ------- devel/tag | 16 ------ 5 files changed, 91 insertions(+), 106 deletions(-) delete mode 100755 devel/build delete mode 100755 devel/pull delete mode 100755 devel/push delete mode 100755 devel/tag diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index da686be3..df96a16e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,24 +5,98 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Set CACHE_DATE - run: echo "CACHE_DATE=$(date --utc +%Y%m%dT%H%M%SZ)" >> $GITHUB_ENV - - run: ./devel/pull - - run: ./devel/build - - if: ${{ github.event_name != 'pull_request' }} + + - uses: docker/setup-buildx-action@v1 + id: builder-image-builder + + - uses: docker/setup-buildx-action@v1 + id: base-image-builder + + - name: Show builder-image-builder name + run: echo ${{ steps.builder-image-builder.outputs.name }} + + - name: Show base-image-builder name + run: echo ${{ steps.base-image-builder.outputs.name }} + + # Set CACHE_DATE in your environment to force layers after our custom cache + # point to be re-built. See the ARG CACHE_DATE line in the Dockerfile for more + # information. + - name: Set CACHE_DATE and GIT_REVISION env vars + run: | + echo "CACHE_DATE=$(date --utc +%Y%m%dT%H%M%SZ)" >> $GITHUB_ENV + echo "GIT_REVISION=$(git describe --tags --abbrev=40 --always --dirty || true)" >> $GITHUB_ENV + + # Use toJSON to store boolean values in a string + # and fromJSON to retrieve as boolean later on. + - name: Set common variables + run: | + echo "BASE_IMAGE_NAME=nextstrain/base" >> $GITHUB_ENV + echo "BUILDER_IMAGE_NAME=nextstrain/base-builder" >> $GITHUB_ENV + echo "TAG_AND_PUSH=${{ toJSON(github.event_name != 'pull_request') }}" >> $GITHUB_ENV + echo "ON_DEFAULT_BRANCH=${{ toJSON(github.ref_type == 'branch' && github.ref_name == github.event.repository.default_branch) }}" >> $GITHUB_ENV + + - if: ${{ fromJSON(env.TAG_AND_PUSH) && fromJSON(env.ON_DEFAULT_BRANCH) }} + name: Set tag name (default branch) + run: echo "TAG_NAME=build-$CACHE_DATE" >> $GITHUB_ENV + + # From `man docker-image-tag`: The tag name must be valid ASCII and may + # contain lowercase and uppercase letters, digits, underscores, periods + # and hyphens. + # TODO: parameterize this as workflow input + - if: ${{ fromJSON(env.TAG_AND_PUSH) && !fromJSON(env.ON_DEFAULT_BRANCH) }} + name: Set tag name (non-default branch) + run: echo "TAG_NAME=branch-${GITHUB_REF_NAME//[^A-Za-z0-9._-]/-}" >> $GITHUB_ENV + + - if: ${{ fromJSON(env.TAG_AND_PUSH) }} + name: Set tags to push + run: | + maybe_base_image_latest_tag=${{ fromJSON(env.ON_DEFAULT_BRANCH) && ',$BASE_IMAGE_NAME:latest' || '' }} + echo "BASE_IMAGE_TAGS=$BASE_IMAGE_NAME:$TAG_NAME$maybe_base_image_latest_tag" >> $GITHUB_ENV + maybe_builder_image_latest_tag=${{ fromJSON(env.ON_DEFAULT_BRANCH) && ',$BUILDER_IMAGE_NAME:latest' || '' }} + echo "BUILDER_IMAGE_TAGS=$BUILDER_IMAGE_NAME:$TAG_NAME$maybe_builder_image_latest_tag" >> $GITHUB_ENV + + - if: ${{ fromJSON(env.TAG_AND_PUSH) }} uses: docker/login-action@v1 with: username: ${{ secrets.DOCKER_LOGIN }} password: ${{ secrets.DOCKER_PASSWORD }} - - if: ${{ github.event_name != 'pull_request' && github.ref_type == 'branch' && github.ref_name == github.event.repository.default_branch }} - run: | - ./devel/tag build-$CACHE_DATE - ./devel/push latest build-$CACHE_DATE - - if: ${{ github.event_name != 'pull_request' && github.ref_type == 'branch' && github.ref_name != github.event.repository.default_branch }} - # From `man docker-image-tag`: The tag name must be valid ASCII and may - # contain lowercase and uppercase letters, digits, underscores, periods - # and hyphens. - run: | - tag=branch-${GITHUB_REF_NAME//[^A-Za-z0-9._-]/-} - ./devel/tag $tag - ./devel/push $tag + + # The nextstrain/base Dockerfile is a multi-stage with both a "builder" target + # and a main target. To enable proper caching via --cache-from we need both + # these images available to pull layers from. This means pulling both in at + # the start and pushing both up at the end. + + # Calling `docker run nextstrain/base` will still only pull down the small base + # image rather than pulling down the larger nextstrain/base-builder image. + - name: Build${{ fromJSON(env.TAG_AND_PUSH) && '/tag/push' || '' }} ${{ env.BUILDER_IMAGE_NAME }} + uses: docker/build-push-action@v2 + with: + target: builder + builder: ${{ steps.builder-image-builder.outputs.name }} + platforms: linux/amd64 + context: . + pull: true + push: ${{ fromJSON(env.TAG_AND_PUSH) }} + tags: ${{ fromJSON(env.TAG_AND_PUSH) && env.BUILDER_IMAGE_TAGS || null }} + cache-from: | + type=registry,ref=${{ env.BUILDER_IMAGE_NAME }} + type=registry,ref=${{ env.BASE_IMAGE_NAME }} + build-args: | + CACHE_DATE + GIT_REVISION + + - name: Build${{ fromJSON(env.TAG_AND_PUSH) && '/tag/push' || '' }} ${{ env.BASE_IMAGE_NAME }} + uses: docker/build-push-action@v2 + with: + builder: ${{ steps.base-image-builder.outputs.name }} + platforms: linux/amd64 + context: . + pull: true + push: ${{ fromJSON(env.TAG_AND_PUSH) }} + tags: ${{ fromJSON(env.TAG_AND_PUSH) && env.BASE_IMAGE_TAGS || null }} + cache-from: | + type=registry,ref=${{ env.BUILDER_IMAGE_NAME }} + type=registry,ref=${{ env.BASE_IMAGE_NAME }} + build-args: | + CACHE_DATE + GIT_REVISION diff --git a/devel/build b/devel/build deleted file mode 100755 index a564786d..00000000 --- a/devel/build +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -# -# Builds the nextstrain/base and nextstrain/base-builder images with useful -# caching. -# -# Set CACHE_DATE in your environment to force layers after our custom cache -# point to be re-built. See the ARG CACHE_DATE line in the Dockerfile for more -# information. -# -set -euo pipefail - -export GIT_REVISION=$(git describe --tags --abbrev=40 --always --dirty || true) - -# The nextstrain/base Dockerfile is a multi-stage with both a "builder" target -# and a main target. To enable proper caching via --cache-from we need both -# these images available to pull layers from. This means pulling both in at -# the start and pushing both up at the end. -# -# Calling `docker run nextstrain/base` will still only pull down the small base -# image rather than pulling down the larger nextstrain/base-builder image. - -docker build \ - --build-arg CACHE_DATE \ - --build-arg GIT_REVISION \ - --cache-from nextstrain/base-builder \ - --cache-from nextstrain/base \ - --tag nextstrain/base-builder \ - --target builder \ - . - -docker build \ - --build-arg CACHE_DATE \ - --build-arg GIT_REVISION \ - --cache-from nextstrain/base-builder \ - --cache-from nextstrain/base \ - --tag nextstrain/base \ - . diff --git a/devel/pull b/devel/pull deleted file mode 100755 index 3a9585b9..00000000 --- a/devel/pull +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# -# Pull the nextstrain/base and nextstrain/base-builder images from Docker Hub. -# -# By default this fetches the "latest" tag, but you can provide other tags in -# addition to or instead of "latest". -# -set -euo pipefail - -# If no tags are given, default to "latest". -if [[ $# -eq 0 ]]; then - set -- latest -fi - -for tag in "$@"; do - docker pull nextstrain/base-builder:$tag - docker pull nextstrain/base:$tag -done diff --git a/devel/push b/devel/push deleted file mode 100755 index c2f6650f..00000000 --- a/devel/push +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# -# Push the nextstrain/base and nextstrain/base-builder images to Docker Hub. -# -# By default this publishes the "latest" tag, but you can provide other tags in -# addition to or instead of "latest". -# -set -euo pipefail - -# If no tags are given, default to "latest". -if [[ $# -eq 0 ]]; then - set -- latest -fi - -for tag in "$@"; do - docker push nextstrain/base-builder:$tag - docker push nextstrain/base:$tag -done diff --git a/devel/tag b/devel/tag deleted file mode 100755 index 23ba5f32..00000000 --- a/devel/tag +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -# -# Assign the given additional tags to the nextstrain/base:latest and -# nextstrain/base-builder:latest images. -# -set -euo pipefail - -if [[ $# -eq 0 ]]; then - echo "Please provide at least one new tag." >&2 - exit 1 -fi - -for tag in "$@"; do - docker tag nextstrain/base-builder:{latest,$tag} - docker tag nextstrain/base:{latest,$tag} -done