From ec3b18edebef063f7534c4002d44a4521d8c9725 Mon Sep 17 00:00:00 2001 From: Nicholas McDonnell <50747025+mcdonnnj@users.noreply.github.com> Date: Wed, 8 Jan 2025 14:21:10 -0500 Subject: [PATCH 1/2] Use the docker/metadata-action Action to generate metadata Switch to using the docker/metadata-action GitHub Action to generate Docker image metadata. This replaces manually specifying the labels and calculating appropriate tags. This approach will both be easier as well as eliminate some of the issues we've had with manually calculating the image tags. --- .github/dependabot.yml | 2 +- .github/workflows/build.yml | 158 +++++------------------------------- 2 files changed, 23 insertions(+), 137 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d01227a..1128608 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -29,10 +29,10 @@ updates: - dependency-name: step-security/harden-runner # Managed by cisagov/skeleton-docker # - dependency-name: actions/download-artifact - # - dependency-name: actions/github-script # - dependency-name: actions/upload-artifact # - dependency-name: docker/build-push-action # - dependency-name: docker/login-action + # - dependency-name: docker/metadata-action # - dependency-name: docker/setup-buildx-action # - dependency-name: docker/setup-qemu-action # - dependency-name: github/codeql-action diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f14bae0..f15ba5e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -191,54 +191,13 @@ jobs: uses: mxschmitt/action-tmate@v3 if: env.RUN_TMATE prepare: - # Calculates and publishes outputs that are used by other jobs. - # - # Outputs: - # created: - # The current date-time in RFC3339 format. - # repometa: - # The json metadata describing this repository. - # source_version: - # The source version as reported by the `bump-version show` command. - # tags: - # A comma separated list of Docker tags to be applied to the images on - # Docker Hub. The tags will vary depending on: - # - The event that triggered the build. - # - The branch the build is based upon. - # - The git tag the build is based upon. - # - # When a build is based on a git tag of the form `v*.*.*` the image will - # be tagged on Docker Hub with multiple levels of version specificity. - # For example, a git tag of `v1.2.3+a` will generate Docker tags of - # `:1.2.3_a`, `:1.2.3`, `:1.2`, `:1`, and `:latest`. - # - # Builds targeting the default branch will be tagged with `:edge`. - # - # Builds from other branches will be tagged with the branch name. Solidi - # (`/` characters - commonly known as slashes) in branch names are - # replaced with hyphen-minuses (`-` characters) in the Docker tag. For - # more information about the solidus see these links: - # * https://www.compart.com/en/unicode/U+002F - # * https://en.wikipedia.org/wiki/Slash_(punctuation)#Encoding - # - # Builds triggered by a push event are tagged with a short hash in the - # form: sha-12345678 - # - # Builds triggered by a pull request are tagged with the pull request - # number in the form pr-123. - # - # Builds triggered using the GitHub GUI (workflow_dispatch) are tagged - # with the value specified by the user. - # - # Scheduled builds are tagged with `:nightly`. + # Generate Docker image metadata using the docker/metadata-action GitHub Action. name: Prepare build variables needs: - diagnostics outputs: - created: ${{ steps.prep.outputs.created }} - repometa: ${{ steps.repo.outputs.result }} - source_version: ${{ steps.prep.outputs.source_version }} - tags: ${{ steps.prep.outputs.tags }} + labels: ${{ steps.generate-metadata.outputs.labels }} + tags: ${{ steps.generate-metadata.outputs.tags }} permissions: # actions/checkout needs this to fetch code contents: read @@ -254,53 +213,24 @@ jobs: with: egress-policy: audit - uses: actions/checkout@v4 - - name: Gather repository metadata - id: repo - uses: actions/github-script@v7 + - id: generate-metadata + name: Generate Docker image metadata + uses: docker/metadata-action@v5 with: - script: | - const repo = await github.rest.repos.get(context.repo) - return repo.data - - name: Calculate output values - id: prep - run: | - VERSION=noop - SEMVER="^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-((0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\+([0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*))?$" - if [ "${{ github.event_name }}" = "schedule" ]; then - VERSION=nightly - elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - VERSION=${{ github.event.inputs.image-tag }} - elif [[ $GITHUB_REF == refs/tags/* ]]; then - VERSION=${GITHUB_REF#refs/tags/} - elif [[ $GITHUB_REF == refs/heads/* ]]; then - VERSION=$(echo ${GITHUB_REF#refs/heads/} | sed -r 's#/+#-#g') - if [ "${{ github.event.repository.default_branch }}" = "$VERSION" ]; - then - VERSION=edge - fi - elif [[ $GITHUB_REF == refs/pull/* ]]; then - VERSION=pr-${{ github.event.number }} - fi - if [[ $VERSION =~ $SEMVER ]]; then - VERSION_NO_V=${VERSION#v} - MAJOR="${BASH_REMATCH[1]}" - MINOR="${BASH_REMATCH[2]}" - PATCH="${BASH_REMATCH[3]}" - TAGS="${IMAGE_NAME}:${VERSION_NO_V//+/_},${IMAGE_NAME}:${MAJOR}.${MINOR}.${PATCH},${IMAGE_NAME}:${MAJOR}.${MINOR},${IMAGE_NAME}:${MAJOR},${IMAGE_NAME}:latest" - else - TAGS="${IMAGE_NAME}:${VERSION}" - fi - if [ "${{ github.event_name }}" = "push" ]; then - TAGS="${TAGS},${IMAGE_NAME}:sha-${GITHUB_SHA::8}" - fi - for i in ${TAGS//,/ } - do - TAGS="${TAGS},ghcr.io/${i}" - done - echo "created=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT - echo "source_version=$(./bump-version show)" >> $GITHUB_OUTPUT - echo "tags=${TAGS}" >> $GITHUB_OUTPUT - echo tags=${TAGS} + images: | + ${{ env.IMAGE_NAME }} + ghcr.io/${{ env.IMAGE_NAME }} + tags: | + type=edge + type=raw,event=workflow_dispatch,value=${{ github.event.inputs.image-tag }} + type=ref,event=branch + type=ref,event=pr + type=ref,event=tag + type=schedule + type=semver,pattern={{major}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{version}} + type=sha - name: Setup tmate debug session uses: mxschmitt/action-tmate@v3 if: github.event.inputs.remote-shell == 'true' || env.RUN_TMATE @@ -350,29 +280,7 @@ jobs: cache-to: type=local,dest=${{ env.BUILDX_CACHE_DIR }} context: . file: ./Dockerfile - labels: "\ - org.opencontainers.image.created=${{ - needs.prepare.outputs.created }} - - org.opencontainers.image.description=${{ - fromJson(needs.prepare.outputs.repometa).description }} - - org.opencontainers.image.licenses=${{ - fromJson(needs.prepare.outputs.repometa).license.spdx_id }} - - org.opencontainers.image.revision=${{ github.sha }} - - org.opencontainers.image.source=${{ - fromJson(needs.prepare.outputs.repometa).clone_url }} - - org.opencontainers.image.title=${{ - fromJson(needs.prepare.outputs.repometa).name }} - - org.opencontainers.image.url=${{ - fromJson(needs.prepare.outputs.repometa).html_url }} - - org.opencontainers.image.version=${{ - needs.prepare.outputs.source_version }}" + labels: ${{ needs.prepare.outputs.labels }} outputs: type=docker,dest=dist/image.tar # Uncomment the following option if you are building an image for use # on Google Cloud Run or AWS Lambda. The current default image output @@ -516,29 +424,7 @@ jobs: cache-to: type=local,dest=${{ env.BUILDX_CACHE_DIR }} context: . file: ./Dockerfile-x - labels: "\ - org.opencontainers.image.created=${{ - needs.prepare.outputs.created }} - - org.opencontainers.image.description=${{ - fromJson(needs.prepare.outputs.repometa).description }} - - org.opencontainers.image.licenses=${{ - fromJson(needs.prepare.outputs.repometa).license.spdx_id }} - - org.opencontainers.image.revision=${{ github.sha }} - - org.opencontainers.image.source=${{ - fromJson(needs.prepare.outputs.repometa).clone_url }} - - org.opencontainers.image.title=${{ - fromJson(needs.prepare.outputs.repometa).name }} - - org.opencontainers.image.url=${{ - fromJson(needs.prepare.outputs.repometa).html_url }} - - org.opencontainers.image.version=${{ - needs.prepare.outputs.source_version }}" + labels: ${{ needs.prepare.outputs.labels }} platforms: | linux/amd64 linux/arm/v6 From 5698c1713675d8a650864a65eb9a05d7bc0a6593 Mon Sep 17 00:00:00 2001 From: Nicholas McDonnell <50747025+mcdonnnj@users.noreply.github.com> Date: Fri, 10 Jan 2025 06:05:24 -0500 Subject: [PATCH 2/2] Only check the version label on releases Update the test configuration to only check the org.opencontainers.image.version label on releases. We must make this change because the docker/metadata-action will only populate the label with an appropriate value on a release. Otherwise it will be the branch that is sourced when building the image. --- tests/container_test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/container_test.py b/tests/container_test.py index bddee4b..449c117 100644 --- a/tests/container_test.py +++ b/tests/container_test.py @@ -77,6 +77,9 @@ def test_log_version(dockerc, project_version, version_container): ), f"Container version output to log does not match project version file {VERSION_FILE}" +@pytest.mark.skipif( + RELEASE_TAG in [None, ""], reason="this is not a release (RELEASE_TAG not set)" +) def test_container_version_label_matches(project_version, version_container): """Verify the container version label is the correct version.""" assert (