From 2e26ba91319df82363a793cf50abb2e8514d7d13 Mon Sep 17 00:00:00 2001 From: Dan Stefaniuk <499338+stefaniuk@users.noreply.github.com> Date: Sat, 9 Sep 2023 20:52:11 +0100 Subject: [PATCH] Implement publish workflow (#5) ## Description ## Context ## Type of changes - [ ] Refactoring (non-breaking change) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would change existing functionality) - [ ] Bug fix (non-breaking change which fixes an issue) ## Checklist - [ ] I am familiar with the [contributing guidelines](../docs/CONTRIBUTING.md) - [ ] I have followed the code style of the project - [ ] I have added tests to cover my changes - [ ] I have updated the documentation accordingly - [ ] This PR is a result of pair or mob programming --- ## Sensitive Information Declaration To ensure the utmost confidentiality and protect your and others privacy, we kindly ask you to NOT including [PII (Personal Identifiable Information) / PID (Personal Identifiable Data)](https://digital.nhs.uk/data-and-information/keeping-data-safe-and-benefitting-the-public) or any other sensitive data in this PR (Pull Request) and the codebase changes. We will remove any PR that do contain any sensitive information. We really appreciate your cooperation in this matter. - [ ] I confirm that neither PII/PID nor sensitive data are included in this PR and the codebase changes. --- Makefile | 20 +++++- README.md | 4 +- TODO.md | 8 +++ infrastructure/images/act/Dockerfile | 1 - infrastructure/images/act/VERSION | 3 - infrastructure/images/base/Dockerfile | 6 +- infrastructure/images/base/VERSION | 4 +- infrastructure/images/{act => rt}/.gitignore | 0 infrastructure/images/rt/Dockerfile | 10 +++ infrastructure/images/rt/VERSION | 3 + scripts/docker/docker.lib.sh | 66 +++++++++++++------- 11 files changed, 92 insertions(+), 33 deletions(-) delete mode 100644 infrastructure/images/act/Dockerfile delete mode 100644 infrastructure/images/act/VERSION rename infrastructure/images/{act => rt}/.gitignore (100%) create mode 100644 infrastructure/images/rt/Dockerfile create mode 100644 infrastructure/images/rt/VERSION diff --git a/Makefile b/Makefile index 73f5091..67dee8b 100644 --- a/Makefile +++ b/Makefile @@ -4,12 +4,28 @@ include ./scripts/test.mk DOCKER_IMAGE := ghcr.io/nhs-england-tools/github-runner-image DOCKER_TITLE := "GitHub Runner Image" -build: # Build Docker image - optional: name=[image name to build, default is 'base'] +# ============================================================================== + +build: # Build Docker images + make build-image name="base" + make build-image name="rt" + +publish: # Publish Docker images + make publish-image name="base" + make publish-image name="rt" + +# ============================================================================== + +build-image: # Build Docker image - optional: name=[image name to build, default is 'base'] dir=infrastructure/images/$(or ${name}, "base") make docker-build -publish: # Publish Docker image - optional: name=[image name to publish, default is 'base'] +publish-image: # Publish Docker image - optional: name=[image name to publish, default is 'base'] dir=infrastructure/images/$(or ${name}, "base") make docker-push +# ============================================================================== + .SILENT: \ build \ + build-image \ publish \ + publish-image \ diff --git a/README.md b/README.md index 7f770be..e2c36f3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# GitHub Runner Image +# GitHub Runner Image (PoC / Experimental) [![Publish](https://github.com/nhs-england-tools/github-runner-image/actions/workflows/cicd-2-publish.yaml/badge.svg)](https://github.com/nhs-england-tools/github-runner-image/actions/workflows/cicd-2-publish.yaml) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=github-runner-image&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=github-runner-image) @@ -7,7 +7,7 @@ TODO: Overview ## Table of Contents -- [GitHub Runner Image](#github-runner-image) +- [GitHub Runner Image (PoC / Experimental)](#github-runner-image-poc--experimental) - [Table of Contents](#table-of-contents) - [Setup](#setup) - [Prerequisites](#prerequisites) diff --git a/TODO.md b/TODO.md index 5813b4e..5a6b94c 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,14 @@ # TODO +- Check the [actions-runner](https://github.com/actions/runner/pkgs/container/actions-runner) image +- Check the [actions-runner-controller](https://github.com/actions/actions-runner-controller) - Finish off publishing the Docker image using an automated process - Create `docker-push` make target +- move docker shell functions to RT + - rename `_get-version` to `_get-effective-version` + - rename `_get-all-versions` to `_get-all-effective-versions` + - `version-create-effective-file` + - `_replace-image-latest-by-specific-version` - Lint the Dockerfile - Spec test the Docker image - Produce SBOM and scan for CVEs the Docker image @@ -10,4 +17,5 @@ - Sonar badge should come from main branch - NHSE Update from Template - This CI/CD pipeline has some changes to the RT skeleton, consider porting them back; e.g. a notification should be sent when an artefact is published, not built +- Align naming of jobs and steps - Write an ADR on the Linux distro choice; i.e. compare Ubuntu, Debian and Alpine diff --git a/infrastructure/images/act/Dockerfile b/infrastructure/images/act/Dockerfile deleted file mode 100644 index 5252526..0000000 --- a/infrastructure/images/act/Dockerfile +++ /dev/null @@ -1 +0,0 @@ -FROM ghcr.io/nhs-england-tools/github-runner-image:20230831-405b5c0-base diff --git a/infrastructure/images/act/VERSION b/infrastructure/images/act/VERSION deleted file mode 100644 index 018831b..0000000 --- a/infrastructure/images/act/VERSION +++ /dev/null @@ -1,3 +0,0 @@ -act -yyyymmdd-act -yyyymmdd-hash-act diff --git a/infrastructure/images/base/Dockerfile b/infrastructure/images/base/Dockerfile index 4e3f4ff..bb3e083 100644 --- a/infrastructure/images/base/Dockerfile +++ b/infrastructure/images/base/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04@sha256:56887c5194fddd8db7e36ced1c16b3569d89f74c801dc8a5adbf48236fb34564 +FROM --platform=linux/amd64 ubuntu:22.04@sha256:56887c5194fddd8db7e36ced1c16b3569d89f74c801dc8a5adbf48236fb34564 ENV \ # SEE: https://docs.docker.com/release-notes/ @@ -61,3 +61,7 @@ RUN set -eux && \ docker-compose --version && \ docker buildx version && \ node --version + +RUN set -eux && \ + \ + git config --global --add safe.directory '*' diff --git a/infrastructure/images/base/VERSION b/infrastructure/images/base/VERSION index afb9c94..9fd5df7 100644 --- a/infrastructure/images/base/VERSION +++ b/infrastructure/images/base/VERSION @@ -1,3 +1,3 @@ base -yyyymmdd-base -yyyymmdd-hash-base +${yyyy}${mm}${dd}-base +${yyyy}${mm}${dd}-${hash}-base diff --git a/infrastructure/images/act/.gitignore b/infrastructure/images/rt/.gitignore similarity index 100% rename from infrastructure/images/act/.gitignore rename to infrastructure/images/rt/.gitignore diff --git a/infrastructure/images/rt/Dockerfile b/infrastructure/images/rt/Dockerfile new file mode 100644 index 0000000..00a6a74 --- /dev/null +++ b/infrastructure/images/rt/Dockerfile @@ -0,0 +1,10 @@ +FROM --platform=linux/amd64 ghcr.io/nhs-england-tools/github-runner-image:${yyyy}${mm}${dd}-${hash}-base + +RUN set -eux && \ + \ + # Fetch the latest version of the package list + apt update --yes && \ + \ + # Install development tools + apt install --yes \ + gh diff --git a/infrastructure/images/rt/VERSION b/infrastructure/images/rt/VERSION new file mode 100644 index 0000000..46d4999 --- /dev/null +++ b/infrastructure/images/rt/VERSION @@ -0,0 +1,3 @@ +rt +${yyyy}${mm}${dd}-rt +${yyyy}${mm}${dd}-${hash}-rt diff --git a/scripts/docker/docker.lib.sh b/scripts/docker/docker.lib.sh index 2be2548..4f7435e 100644 --- a/scripts/docker/docker.lib.sh +++ b/scripts/docker/docker.lib.sh @@ -35,14 +35,14 @@ function docker-build() { --build-arg GIT_BRANCH="$(_get-git-branch-name)" \ --build-arg GIT_COMMIT_HASH="$(git rev-parse --short HEAD)" \ --build-arg BUILD_DATE="$(date -u +"%Y-%m-%dT%H:%M:%S%z")" \ - --build-arg BUILD_VERSION="$(_get-version)" \ - --tag "${DOCKER_IMAGE}:$(_get-version)" \ + --build-arg BUILD_VERSION="$(_get-effective-version)" \ + --tag "${DOCKER_IMAGE}:$(_get-effective-version)" \ --rm \ --file "${dir}/Dockerfile.effective" \ . # Tag the image with all the stated versions, see the documentation for more details - for version in $(_get-all-versions) latest; do - docker tag "${DOCKER_IMAGE}:$(_get-version)" "${DOCKER_IMAGE}:${version}" + for version in $(_get-all-effective-versions) latest; do + docker tag "${DOCKER_IMAGE}:$(_get-effective-version)" "${DOCKER_IMAGE}:${version}" done docker rmi --force "$(docker images | grep "" | awk '{print $3}')" 2> /dev/null ||: } @@ -59,7 +59,7 @@ function docker-check-test() { # shellcheck disable=SC2086,SC2154 docker run --rm --platform linux/amd64 \ ${args:-} \ - "${DOCKER_IMAGE}:$(_get-version)" 2>/dev/null \ + "${DOCKER_IMAGE}:$(_get-effective-version)" 2>/dev/null \ ${cmd:-} \ | grep -q "${check}" && echo PASS || echo FAIL } @@ -75,7 +75,7 @@ function docker-run() { # shellcheck disable=SC2086 docker run --rm --platform linux/amd64 \ ${args:-} \ - "${DOCKER_IMAGE}:$(dir="$dir" _get-version)" \ + "${DOCKER_IMAGE}:$(dir="$dir" _get-effective-version)" \ ${cmd:-} } @@ -86,7 +86,7 @@ function docker-push() { local dir=${dir:-$PWD} # Push all the image tags based on the stated versions, see the documentation for more details - for version in $(dir="$dir" _get-all-versions) latest; do + for version in $(dir="$dir" _get-all-effective-versions) latest; do docker push "${DOCKER_IMAGE}:${version}" done } @@ -97,7 +97,7 @@ function docker-push() { function docker-clean() { local dir=${dir:-$PWD} - for version in $(dir="$dir" _get-all-versions) latest; do + for version in $(dir="$dir" _get-all-effective-versions) latest; do docker rmi "${DOCKER_IMAGE}:${version}" > /dev/null 2>&1 ||: done rm -f \ @@ -112,17 +112,19 @@ function docker-clean() { function version-create-effective-file() { local dir=${dir:-$PWD} - build_datetime=${BUILD_DATETIME:-$(date -u +'%Y-%m-%dT%H:%M:%S%z')} - if [ -f "$dir/VERSION" ]; then + local version_file="$dir/VERSION" + local build_datetime=${BUILD_DATETIME:-$(date -u +'%Y-%m-%dT%H:%M:%S%z')} + + if [ -f "$version_file" ]; then # shellcheck disable=SC2002 - cat "$dir/VERSION" | \ - sed "s/yyyy/$(date --date="${build_datetime}" -u +"%Y")/g" | \ - sed "s/mm/$(date --date="${build_datetime}" -u +"%m")/g" | \ - sed "s/dd/$(date --date="${build_datetime}" -u +"%d")/g" | \ - sed "s/HH/$(date --date="${build_datetime}" -u +"%H")/g" | \ - sed "s/MM/$(date --date="${build_datetime}" -u +"%M")/g" | \ - sed "s/SS/$(date --date="${build_datetime}" -u +"%S")/g" | \ - sed "s/hash/$(git rev-parse --short HEAD)/g" \ + cat "$version_file" | \ + sed "s/\(\${yyyy}\|\$yyyy\)/$(date --date="${build_datetime}" -u +"%Y")/g" | \ + sed "s/\(\${mm}\|\$mm\)/$(date --date="${build_datetime}" -u +"%m")/g" | \ + sed "s/\(\${dd}\|\$dd\)/$(date --date="${build_datetime}" -u +"%d")/g" | \ + sed "s/\(\${HH}\|\$HH\)/$(date --date="${build_datetime}" -u +"%H")/g" | \ + sed "s/\(\${MM}\|\$MM\)/$(date --date="${build_datetime}" -u +"%M")/g" | \ + sed "s/\(\${SS}\|\$SS\)/$(date --date="${build_datetime}" -u +"%S")/g" | \ + sed "s/\(\${hash}\|\$hash\)/$(git rev-parse --short HEAD)/g" \ > "$dir/.version" fi } @@ -198,7 +200,10 @@ function _create-effective-dockerfile() { function _replace-image-latest-by-specific-version() { local dir=${dir:-$PWD} - versions_file=$(git rev-parse --show-toplevel)/.tool-versions + local versions_file=$(git rev-parse --show-toplevel)/.tool-versions + local dockerfile="${dir}/Dockerfile.effective" + local build_datetime=${BUILD_DATETIME:-$(date -u +'%Y-%m-%dT%H:%M:%S%z')} + if [ -f "$versions_file" ]; then # First, list the entries specific for Docker to take precedence, then the rest content=$(grep " docker/" "$versions_file"; grep -v " docker/" "$versions_file") @@ -207,9 +212,26 @@ function _replace-image-latest-by-specific-version() { line=$(echo "$line" | sed "s/^#\s*//; s/\s*#.*$//" | sed "s;docker/;;") name=$(echo "$line" | awk '{print $1}') version=$(echo "$line" | awk '{print $2}') - sed -i "s;FROM ${name}:latest;FROM ${name}:${version};g" "${dir}/Dockerfile.effective" + sed -i "s;\(FROM .*\) ${name}:latest;\1 ${name}:${version};g" "$dockerfile" done fi + + if [ -f "$dockerfile" ]; then + # shellcheck disable=SC2002 + cat "$dockerfile" | \ + sed "s/\(\${yyyy}\|\$yyyy\)/$(date --date="${build_datetime}" -u +"%Y")/g" | \ + sed "s/\(\${mm}\|\$mm\)/$(date --date="${build_datetime}" -u +"%m")/g" | \ + sed "s/\(\${dd}\|\$dd\)/$(date --date="${build_datetime}" -u +"%d")/g" | \ + sed "s/\(\${HH}\|\$HH\)/$(date --date="${build_datetime}" -u +"%H")/g" | \ + sed "s/\(\${MM}\|\$MM\)/$(date --date="${build_datetime}" -u +"%M")/g" | \ + sed "s/\(\${SS}\|\$SS\)/$(date --date="${build_datetime}" -u +"%S")/g" | \ + sed "s/\(\${hash}\|\$hash\)/$(git rev-parse --short HEAD)/g" \ + > "$dockerfile.tmp" + mv "$dockerfile.tmp" "$dockerfile" + fi + + # Do not ignore the issue if 'latest' is used in the effective image + sed -Ei "/# hadolint ignore=DL3007$/d" "${dir}/Dockerfile.effective" } # Append metadata to the end of Dockerfile. @@ -228,7 +250,7 @@ function _append-metadata() { # Print top Docker image version. # Arguments (provided as environment variables): # dir=[path to the image directory where the Dockerfile is located, default is '.'] -function _get-version() { +function _get-effective-version() { local dir=${dir:-$PWD} head -n 1 "${dir}/.version" @@ -237,7 +259,7 @@ function _get-version() { # Print all Docker image versions. # Arguments (provided as environment variables): # dir=[path to the image directory where the Dockerfile is located, default is '.'] -function _get-all-versions() { +function _get-all-effective-versions() { local dir=${dir:-$PWD} cat "${dir}/.version"