Skip to content

Instantly share code, notes, and snippets.

@matthewadams
Created August 13, 2018 22:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matthewadams/de8b213bb18dac8a09e12269ab2102c9 to your computer and use it in GitHub Desktop.
Save matthewadams/de8b213bb18dac8a09e12269ab2102c9 to your computer and use it in GitHub Desktop.
release-docker-image-on-codefresh.sh
#!/usr/bin/env bash
# This script implements the release branch workflow for docker images built by codefresh.io.
#
# Requirements:
# git
# docker
# TODO: port this from bash to plain ol' sh (regex matching needs to be ported)
usage() {
cat<<EOF
usage:
if on master branch: release pre|rc <chart>
if on release branch: release major|minor|patch|pre <chart>
where:
<chart> is the name of the chart
EOF
}
if [ -n "$TEST" ]; then ECHO=echo; fi
if [ -n "$DBG" ]; then set -x; fi
ORIGIN=${ORIGIN:-origin}
MASTER=${MASTER:-master}
RELEASE_LEVEL="$1"
case "$RELEASE_LEVEL" in
major|minor|patch|pre|rc)
# ok
;;
h|he|hel|help)
usage
exit 0
;;
*)
echo "ERROR: Specify release level of 'pre', 'patch', 'minor', 'major', or 'rc'" >&2
usage
exit 1
;;
esac
CODEFRESH_YML=${CODEFRESH_YML:-codefresh.yml}
DOCKER_BUILD_STEP_NAME=${DOCKER_BUILD_STEP_NAME:-BuildingDockerImage}
DOCKER_PUSH_STEP_NAME=${DOCKER_PUSH_STEP_NAME:-PushingToDockerRegistry}
git pull > /dev/null 2>&1
if ! git diff --exit-code --no-patch > /dev/null 2>&1; then
echo 'ERROR: You have modified tracked files; only release from clean directories!' >&2
exit 3
fi
if ! git diff --cached --exit-code --no-patch > /dev/null 2>&1; then
echo 'ERROR: You have cached modified tracked files; only release from clean directories!' >&2
exit 3
fi
if [ -n "$(git status -s)" ]; then
echo 'ERROR: You have unignored untracked files; only release from clean directories!' >&2
exit 3
fi
VERSION="$(cat "$CODEFRESH_YML" | docker run --rm -i matthewadams12/ymlx "this.steps['$DOCKER_PUSH_STEP_NAME'].tag")"
if [[ ! "$VERSION" =~ \-(pre|rc)\.[0-9]{1,}$ ]]; then
echo 'ERROR: repository is in an inconsistent state: version does NOT end in a prerelease suffix!' >&2
exit 3
fi
BRANCH="$(git status | head -n 1 | awk '{ print $3 }')"
if [[ ! "$BRANCH" =~ ^(master|v[0-9]{1,}\.[0-9]{1,})$ ]]; then # it is not a master or a release branch
echo 'ERROR: You can only release from the master branch or release branches (vmajor.minor)!' >&2
exit 3
fi
if ! git diff --exit-code -no-patch $BRANCH $ORIGIN/$BRANCH > /dev/null 2>&1; then
echo "ERROR: Local branch $BRANCH differs from remote branch $ORIGIN/$BRANCH" >&2
exit 3
fi
if [ "$BRANCH" == "$MASTER" ]; then
case "$RELEASE_LEVEL" in
pre|rc)
# ok
;;
*)
echo "ERROR: Only 'pre' or 'rc' releases are permitted from the $MASTER branch." >&2
exit 6
;;
esac
else # this is a release branch
case "$RELEASE_LEVEL" in
rc|patch|minor|major)
# ok
;;
*)
echo "ERROR: Only 'pre', 'patch', 'minor', or 'major' releases are permitted from a release branch." >&2
exit 7
;;
esac
fi
if [ "$BRANCH" == "$MASTER" ]; then
if [[ ! "$VERSION" =~ ^([0-9]{1,})\.([0-9]{1,})\.0\-pre\.([0-9]{1,})$ ]]; then
echo "ERROR: The version does not match the format of major.minor.0-pre.n required in the $MASTER branch." >&2
exit 8
fi
# create release branch
MAJOR=${BASH_REMATCH[1]}
MINOR=${BASH_REMATCH[2]}
PATCH=0
PRE=${BASH_REMATCH[3]}
case "$RELEASE_LEVEL" in
rc) # then it's time to create a new release branch
NEW_RELEASE_BRANCH="v$MAJOR.$MINOR"
git checkout -b $NEW_RELEASE_BRANCH > /dev/null 2>&1
NEW_RELEASE_BRANCH_VERSION="$MAJOR.$MINOR.0-rc.0"
CODEFRESH_YML_CONTENT="$(cat "$CODEFRESH_YML")"
echo -n "$CODEFRESH_YML_CONTENT" \
| docker run --rm -i matthewadams12/ymlx "it => { it.steps['$DOCKER_PUSH_STEP_NAME'].tag = '$NEW_RELEASE_BRANCH_VERSION'; return it; }" \
> "$CODEFRESH_YML"
git add . > /dev/null 2>&1
git commit -m "release $NEW_RELEASE_BRANCH_VERSION" > /dev/null 2>&1
git tag $NEW_RELEASE_BRANCH_VERSION > /dev/null 2>&1
git push -u $ORIGIN $NEW_RELEASE_BRANCH > /dev/null 2>&1
git push --tags > /dev/null 2>&1
# return to master branch
git checkout $MASTER > /dev/null 2>&1
git cherry-pick $NEW_RELEASE_BRANCH > /dev/null 2>&1 # cherry pick from release branch to get release candidate commit in master
# advance master version
NEXT_VERSION="$MAJOR.$(($MINOR+1)).0-pre.0"
CODEFRESH_YML_CONTENT="$(cat "$CODEFRESH_YML")"
echo -n "$CODEFRESH_YML_CONTENT" \
| docker run --rm -i matthewadams12/ymlx "it => { it.steps['$DOCKER_PUSH_STEP_NAME'].tag = '$NEXT_VERSION'; return it; }" \
> "$CODEFRESH_YML"
git add . > /dev/null 2>&1
git commit -m "bump to $NEXT_VERSION [skip ci]" > /dev/null 2>&1
git push > /dev/null 2>&1
# return to release branch & prepare for next prerelease
git checkout $NEW_RELEASE_BRANCH > /dev/null 2>&1
NEXT_RELEASE_BRANCH_VERSION="$MAJOR.$MINOR.0-rc.1"
CODEFRESH_YML_CONTENT="$(cat "$CODEFRESH_YML")"
echo -n "$CODEFRESH_YML_CONTENT" \
| docker run --rm -i matthewadams12/ymlx "it => { it.steps['$DOCKER_PUSH_STEP_NAME'].tag = '$NEXT_RELEASE_BRANCH_VERSION'; return it; }" \
> "$CODEFRESH_YML"
git add . > /dev/null 2>&1
git commit -m "bump to $NEXT_RELEASE_BRANCH_VERSION [skip ci]" > /dev/null 2>&1
git push > /dev/null 2>&1
echo "created release branch $NEW_RELEASE_BRANCH and tagged $NEW_RELEASE_BRANCH_VERSION for release"
exit 0
;;
pre)
git tag "v$VERSION" > /dev/null 2>&1
RELEASED_VERSION="$VERSION"
NEXT_VERSION=$MAJOR.$MINOR.$PATCH-pre.$((PRE+1))
CODEFRESH_YML_CONTENT="$(cat "$CODEFRESH_YML")"
echo -n "$CODEFRESH_YML_CONTENT" \
| docker run --rm -i matthewadams12/ymlx "it => { it.steps['$DOCKER_PUSH_STEP_NAME'].tag = '$NEXT_VERSION'; return it; }" \
> "$CODEFRESH_YML"
git add . > /dev/null 2>&1
git commit -m "bump to $NEXT_VERSION [skip ci]" > /dev/null 2>&1
git push > /dev/null 2>&1
git push --tags > /dev/null 2>&1
echo "tagged $RELEASED_VERSION for release"
exit 0
;;
esac
fi
# If we get this far, we are releasing something from a release branch.
if [[ ! "$VERSION" =~ ^([0-9]{1,})\.([0-9]{1,})\.([0-9]{1,})\-rc\.([0-9]{1,})$ ]]; then
echo "ERROR: The version does not match the format of major.minor.patch-rc.n required in the release branch." >&2
exit 8
fi
MAJOR=${BASH_REMATCH[1]}
MINOR=${BASH_REMATCH[2]}
PATCH=${BASH_REMATCH[3]}
PRE=${BASH_REMATCH[4]}
case "$RELEASE_LEVEL" in
major|minor|patch)
# NOTE: if RELEASE_LEVEL is 'minor' & we're prepped for a major release, no harm, no foul.
# A major release is the same as a minor release, only that the minor version is 0.
if [ $RELEASE_LEVEL == major ] && [ $MINOR != 0 ]; then
echo "ERROR: This branch is not prepared for a major release because the minor version is $MINOR, not 0." >&2
exit 10
else
NEXT_RELEASE_BRANCH_VERSION="$MAJOR.$MINOR.1-rc.0"
fi
if [ $RELEASE_LEVEL == minor ] && [ $PATCH != 0 ]; then
echo "ERROR: A minor release has already been performed in this release branch; only patch releases are allowed here now." >&2
exit 11
else
NEXT_RELEASE_BRANCH_VERSION="$MAJOR.$MINOR.1-rc.0"
fi
if [ $RELEASE_LEVEL == patch ] && [ $PATCH == 0 ]; then
echo "ERROR: You must release a minor release before releasing a patch in this release branch." >&2
exit 12
else
NEXT_RELEASE_BRANCH_VERSION="$MAJOR.$MINOR.$((PATCH+1))-rc.0"
fi
RELEASE_VERSION="$MAJOR.$MINOR.$PATCH"
CODEFRESH_YML_CONTENT="$(cat "$CODEFRESH_YML")"
echo -n "$CODEFRESH_YML_CONTENT" \
| docker run --rm -i matthewadams12/ymlx "it => { it.steps['$DOCKER_PUSH_STEP_NAME'].tag = '$RELEASE_VERSION'; return it; }" \
> "$CODEFRESH_YML"
git add . > /dev/null 2>&1
git commit -m "release $RELEASE_VERSION" > /dev/null 2>&1
git tag "v$RELEASE_VERSION" > /dev/null 2>&1
git push > /dev/null 2>&1
git push --tags > /dev/null 2>&1
CODEFRESH_YML_CONTENT="$(cat "$CODEFRESH_YML")"
echo -n "$CODEFRESH_YML_CONTENT" \
| docker run --rm -i matthewadams12/ymlx "it => { it.steps['$DOCKER_PUSH_STEP_NAME'].tag = '$NEXT_RELEASE_BRANCH_VERSION'; return it; }" \
> "$CODEFRESH_YML"
git add . > /dev/null 2>&1
git commit -m "bump to $NEXT_RELEASE_BRANCH_VERSION [skip ci]" > /dev/null 2>&1
git push > /dev/null 2>&1
echo "tagged $RELEASE_VERSION"
exit 0
;;
rc)
git tag "v$VERSION" > /dev/null 2>&1
NEXT_RELEASE_BRANCH_VERSION="$MAJOR.$MINOR.$PATCH-rc.$((PRE+1))"
CODEFRESH_YML_CONTENT="$(cat "$CODEFRESH_YML")"
echo -n "$CODEFRESH_YML_CONTENT" \
| docker run --rm -i matthewadams12/ymlx "it => { it.steps['$DOCKER_PUSH_STEP_NAME'].tag = '$NEXT_RELEASE_BRANCH_VERSION'; return it; }" \
> "$CODEFRESH_YML"
git add . > /dev/null 2>&1
git commit -m "bump to $NEXT_RELEASE_BRANCH_VERSION [skip ci]" > /dev/null 2>&1
git push > /dev/null 2>&1
git push --tags > /dev/null 2>&1
echo "tagged v$VERSION"
exit 0
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment