* 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>
209 lines
8.5 KiB
Bash
Executable file
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
|