docbrown/scripts/build_containers.sh
Jamie Gaskins f0edbcef90
Add support for versioned releases (#13750)
* Add release scripts

* Use `delete` over `gsub` with an empty string

Co-authored-by: Michael Kohl <citizen428@dev.to>

* wip

* wip

* Include stable release-channel branches in builds

* Add changelog stub

* Include the union of changes to the changelog

* Add things

* Add stuff

* Remove test changelog content

* Fix String#delete call

Extraneous `.` made Ruby parse it as a range

* Fix suggested release command

* Use backticks to denote a command to run

* Add debugging output to script

* Build more appropriate containers for stable

This includes tags

* Check if branch *starts with* release channel name

* Cache tag builds from production tag

* Skip trying to build containers for untagged pushes

* Clear out stubbed changelog

* Update PR template to incorporate CHANGELOG.md

* Run Rubocop on release scripts

This excludes some linter rules that only make sense in code that is
running as part of the Rails app. For example, we can't rely on
`ActiveSupport::TimeWithZone` because these scripts don't load Rails,
and we define top-level methods because they're scripts rather than
complex applications.

Co-authored-by: Michael Kohl <citizen428@dev.to>
2021-07-28 10:10:33 -04:00

209 lines
8.5 KiB
Bash
Executable file

#!/bin/bash
set -euo pipefail
: ${CONTAINER_REPO:="quay.io/forem"}
: ${CONTAINER_APP:=forem}
function create_pr_containers {
PULL_REQUEST=$1
# Pull images if available for caching
echo "Pulling pull request #${PULL_REQUEST} containers from registry..."
docker pull "${CONTAINER_REPO}"/"${CONTAINER_APP}":builder ||:
docker pull "${CONTAINER_REPO}"/"${CONTAINER_APP}":builder-"${PULL_REQUEST}" ||:
docker pull "${CONTAINER_REPO}"/"${CONTAINER_APP}":pr-"${PULL_REQUEST}" ||:
docker pull "${CONTAINER_REPO}"/"${CONTAINER_APP}":testing-"${PULL_REQUEST}" ||:
# Build the builder image
echo "Building builder-${PULL_REQUEST} container..."
docker build --target builder \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":builder \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":builder-"${PULL_REQUEST}" \
--label quay.expires-after=8w \
--tag "${CONTAINER_REPO}"/"${CONTAINER_APP}":builder-"${PULL_REQUEST}" .
# Build the pull request image
echo "Building pr-${PULL_REQUEST} container..."
docker build --target production \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":builder-"${PULL_REQUEST}" \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":pr-"${PULL_REQUEST}" \
--label quay.expires-after=8w \
--tag "${CONTAINER_REPO}"/"${CONTAINER_APP}":pr-"${PULL_REQUEST}" .
# Build the testing image
echo "Building testing-$"${PULL_REQUEST}" container..."
docker build --target testing \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":builder-"${PULL_REQUEST}" \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":pr-"${PULL_REQUEST}" \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":testing-"${PULL_REQUEST}" \
--label quay.expires-after=8w \
--tag "${CONTAINER_REPO}"/"${CONTAINER_APP}":testing-"${PULL_REQUEST}" .
# Push images to Quay
echo "Pushing pull request #${PULL_REQUEST} containers to registry..."
docker push "${CONTAINER_REPO}"/"${CONTAINER_APP}":builder-"${PULL_REQUEST}"
docker push "${CONTAINER_REPO}"/"${CONTAINER_APP}":pr-"${PULL_REQUEST}"
docker push "${CONTAINER_REPO}"/"${CONTAINER_APP}":testing-"${PULL_REQUEST}"
}
function create_production_containers {
# Pull images if available for caching
docker pull "${CONTAINER_REPO}"/"${CONTAINER_APP}":builder ||:
docker pull "${CONTAINER_REPO}"/"${CONTAINER_APP}":production ||:
docker pull "${CONTAINER_REPO}"/"${CONTAINER_APP}":testing ||:
docker pull "${CONTAINER_REPO}"/"${CONTAINER_APP}":development ||:
# Build the builder image
docker build --target builder \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":builder \
--tag "${CONTAINER_REPO}"/"${CONTAINER_APP}":builder .
# Build the production image
docker build --target production \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":builder \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":production \
--tag "${CONTAINER_REPO}"/"${CONTAINER_APP}":$(date +%Y%m%d) \
--tag "${CONTAINER_REPO}"/"${CONTAINER_APP}":production \
--tag "${CONTAINER_REPO}"/"${CONTAINER_APP}":latest .
docker build --target production \
--label quay.expires-after=8w \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":builder \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":production \
--tag "${CONTAINER_REPO}"/"${CONTAINER_APP}":${BUILDKITE_COMMIT:0:7} .
# Build the testing image
docker build --target testing \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":builder \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":production \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":testing \
--tag "${CONTAINER_REPO}"/"${CONTAINER_APP}":testing .
# Build the development image
docker build --target development \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":builder \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":production \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":testing \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":development \
--tag "${CONTAINER_REPO}"/"${CONTAINER_APP}":development .
# Push images to Quay
docker push "${CONTAINER_REPO}"/"${CONTAINER_APP}":builder
docker push "${CONTAINER_REPO}"/"${CONTAINER_APP}":production
docker push "${CONTAINER_REPO}"/"${CONTAINER_APP}":testing
docker push "${CONTAINER_REPO}"/"${CONTAINER_APP}":development
docker push "${CONTAINER_REPO}"/"${CONTAINER_APP}":$(date +%Y%m%d)
docker push "${CONTAINER_REPO}"/"${CONTAINER_APP}":${BUILDKITE_COMMIT:0:7}
docker push "${CONTAINER_REPO}"/"${CONTAINER_APP}":latest
}
function create_release_containers {
BRANCH=$1
# Pull images if available for caching
docker pull "${CONTAINER_REPO}"/"${CONTAINER_APP}":builder ||:
docker pull "${CONTAINER_REPO}"/"${CONTAINER_APP}":production ||:
docker pull "${CONTAINER_REPO}"/"${CONTAINER_APP}":testing ||:
docker pull "${CONTAINER_REPO}"/"${CONTAINER_APP}":development ||:
# Build the builder image
docker build --target builder \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":builder \
--tag "${CONTAINER_REPO}"/"${CONTAINER_APP}":builder .
# Build the production image
docker build --target production \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":builder \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":production \
--tag "${CONTAINER_REPO}"/"${CONTAINER_APP}":${BUILDKITE_COMMIT:0:7} \
--tag "${CONTAINER_REPO}"/"${CONTAINER_APP}":${BRANCH} .
# Build the testing image
docker build --target testing \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":builder \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":production \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":testing \
--tag "${CONTAINER_REPO}"/"${CONTAINER_APP}":testing-${BRANCH} .
# Build the development image
docker build --target development \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":builder \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":production \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":testing \
--tag "${CONTAINER_REPO}"/"${CONTAINER_APP}":development-${BRANCH} .
# If the env var for the git tag doesn't exist or is an empty string, then we
# won't build a container image for a cut release.
if [ -v BUILDKITE_TAG || ! -z "${BUILDKITE_TAG}" ]; then
docker build --target production \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":builder \
--cache-from="${CONTAINER_REPO}"/"${CONTAINER_APP}":production \
--tag "${CONTAINER_REPO}"/"${CONTAINER_APP}":${BUILDKITE_TAG} .
fi
# Push images to Quay
docker push "${CONTAINER_REPO}"/"${CONTAINER_APP}":${BRANCH}
docker push "${CONTAINER_REPO}"/"${CONTAINER_APP}":development-${BRANCH}
docker push "${CONTAINER_REPO}"/"${CONTAINER_APP}":testing-${BRANCH}
}
function prune_containers {
docker image prune -f
}
trap prune_containers ERR INT EXIT
echo "Branch: $BUILDKITE_BRANCH"
echo "PR : $BUILDKITE_PULL_REQUEST"
echo "Commit: $BUILDKITE_COMMIT"
echo "Tag : $BUILDKITE_TAG"
if [ ! -v BUILDKITE_BRANCH ]; then
echo "Not running in Buildkite. Building Production Containers..."
BUILDKITE_COMMIT=$(git rev-parse --short HEAD)
create_production_containers
elif [ -z "$BUILDKITE_BRANCH" ]; then
echo "BUILDKITE_BRANCH is set to an empty string! Exiting..."
exit 1
elif [[ "${BUILDKITE_BRANCH}" = "master" || "${BUILDKITE_BRANCH}" = "main" ]]; then
echo "Building Production Containers..."
create_production_containers
elif [[ ${BUILDKITE_BRANCH} = stable* ]]; then
echo "Building Production Containers for ${BUILDKITE_BRANCH}..."
create_release_containers "${BUILDKITE_BRANCH}"
else
if [ ! -v BUILDKITE_PULL_REQUEST ]; then
echo "BUILDKITE_PULL_REQUEST is unset! Exiting..."
exit 1
elif [ -z "$BUILDKITE_PULL_REQUEST" ]; then
echo "BUILDKITE_PULL_REQUEST is set to an empty string! Exiting..."
exit 1
else
echo "Building containers for pull request #${BUILDKITE_PULL_REQUEST}..."
create_pr_containers "${BUILDKITE_PULL_REQUEST}"
fi
fi