build: add release helper scripts

This commit is contained in:
Zaiming (Stone) Shi 2022-11-27 22:42:52 +01:00
parent 05719daff2
commit 729cd8fda4
3 changed files with 405 additions and 0 deletions

35
scripts/rel/check-chart-vsn.sh Executable file
View File

@ -0,0 +1,35 @@
#!/usr/bin/env bash
set -euo pipefail
if [ "${DEBUG:-}" = 1 ]; then
set -x
fi
# ensure dir
cd -P -- "$(dirname -- "$0")/../.."
PROFILE="$1"
CHART_FILE="deploy/charts/${PROFILE}/Chart.yaml"
if [ ! -f "$CHART_FILE" ]; then
echo "Chart file $CHART_FILE is not found"
echo "Current working dir: $(pwd)"
exit 1
fi
CHART_VSN="$(grep -oE '^version:.*' "$CHART_FILE" | cut -d ':' -f 2 | tr -d ' ')"
APP_VSN="$(grep -oE '^appVersion:.*' "$CHART_FILE" | cut -d ':' -f 2 | tr -d ' ')"
if [ "$CHART_VSN" != "$APP_VSN" ]; then
echo "Chart version and app version mismatch in $CHART_FILE"
exit 2
fi
PKG_VSN="$(./pkg-vsn.sh "$PROFILE" | cut -d '-' -f 1)"
if [ "$CHART_VSN" != "$PKG_VSN" ]; then
echo "Chart version in $CHART_FILE is not in sync with release version."
echo "Chart version: $CHART_VSN"
echo "Release version: $PKG_VSN"
exit 3
fi

214
scripts/rel/cut.sh Executable file
View File

@ -0,0 +1,214 @@
#!/usr/bin/env bash
## cut a new 5.x release for EMQX (opensource or enterprise).
set -euo pipefail
if [ "${DEBUG:-}" = 1 ]; then
set -x
fi
# ensure dir
cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")/../.."
usage() {
cat <<EOF
$0 RELEASE_GIT_TAG [option]
RELEASE_GIT_TAG is a 'v*' or 'e*' tag for example:
v5.0.12
e5.0.0-beta.6
options:
-h|--help: Print this usage.
-b|--base: Specify the current release base branch, can be one of
release-50
NOTE: this option should be used when --dryrun.
--dryrun: Do not actually create the git tag.
--skip-appup: Skip checking appup
Useful when you are sure that appup is already updated'
NOTE: For 5.0 series the current working branch must be 'release-50' for opensource edition
and 'release-e50' for enterprise edition.
--.--[ master ]---------------------------.-----------.---
\\ /
\`---[release-50]----(v5.0.12 | e5.0.0)
EOF
}
logerr() {
echo "$(tput setaf 1)ERROR: $1$(tput sgr0)"
}
logmsg() {
echo "INFO: $1"
}
TAG="${1:-}"
case "$TAG" in
v*)
TAG_PREFIX='v'
PROFILE='emqx'
SKIP_APPUP='yes'
;;
e*)
TAG_PREFIX='e'
PROFILE='emqx-enterprise'
SKIP_APPUP='no'
;;
-h|--help)
usage
exit 0
;;
*)
logerr "Unknown version tag $TAG"
usage
exit 1
;;
esac
shift 1
DRYRUN='no'
while [ "$#" -gt 0 ]; do
case $1 in
-h|--help)
usage
exit 0
;;
--skip-appup)
shift
SKIP_APPUP='yes'
;;
--dryrun)
shift
DRYRUN='yes'
;;
-b|--base)
BASE_BR="${2:-}"
if [ -z "${BASE_BR}" ]; then
logerr "Must specify which base branch"
exit 1
fi
shift 2
;;
*)
logerr "Unknown option $1"
exit 1
;;
esac
done
rel_branch() {
local tag="$1"
case "$tag" in
v5.0.*)
echo 'release-50'
;;
e5.0.*)
echo 'release-50'
;;
*)
logerr "Unsupported version tag $TAG"
exit 1
;;
esac
}
## Ensure the current work branch
assert_work_branch() {
local tag="$1"
local release_branch
release_branch="$(rel_branch "$tag")"
local base_branch
base_branch="${BASE_BR:-$(git branch --show-current)}"
if [ "$base_branch" != "$release_branch" ]; then
logerr "Base branch: $base_branch"
logerr "Relase tag must be on the release branch: $release_branch"
logerr "or must use -b|--base option to specify which release branch is current branch based on"
exit 1
fi
}
assert_work_branch "$TAG"
## Ensure no dirty changes
assert_not_dirty() {
local diff
diff="$(git diff --name-only)"
if [ -n "$diff" ]; then
logerr "Git status is not clean? Changed files:"
logerr "$diff"
exit 1
fi
}
assert_not_dirty
## Assert that the tag is not already created
assert_tag_absent() {
local tag="$1"
## Fail if the tag already exists
EXISTING="$(git tag --list "$tag")"
if [ -n "$EXISTING" ]; then
logerr "$tag already released?"
logerr 'This script refuse to force re-tag.'
logerr 'If re-tag is intended, you must first delete the tag from both local and remote'
exit 1
fi
}
assert_tag_absent "$TAG"
PKG_VSN=$(./pkg-vsn.sh "$PROFILE")
## Assert package version is updated to the tag which is being created
assert_release_version() {
local tag="$1"
# shellcheck disable=SC2001
pkg_vsn="$(echo "$PKG_VSN" | sed 's/-g[0-9a-f]\{8\}$//g')"
if [ "${TAG_PREFIX}${pkg_vsn}" != "${tag}" ]; then
logerr "The release version ($pkg_vsn) is different from the desired git tag."
logerr "Update the release version in emqx_release.hrl"
exit 1
fi
}
assert_release_version "$TAG"
## Check if all upstream branches are merged
if [ -z "${BASE_BR:-}" ]; then
./scripts/rel/sync-remotes.sh
else
./scripts/rel/sync-remotes.sh --base "$BASE_BR"
fi
## Check if the Chart versions are in sync
./scripts/rel/check-chart-vsn.sh "$PROFILE"
## Check if app versions are bumped
./scripts/apps-version-check.sh
## Ensure appup files are updated
if [ "$SKIP_APPUP" = 'no' ]; then
logmsg "Checking appups"
./scripts/update-appup.sh "$PROFILE" --check
else
logmsg "Skipped checking appup updates"
fi
## Ensure relup paths are updated
## TODO: add relup path db
#./scripts/relup-base-vsns.escript check-vsn-db "$PKG_VSN" "$RELUP_PATHS"
## Run some additional checks (e.g. some for enterprise edition only)
CHECKS_DIR="./scripts/rel/checks"
if [ -d "${CHECKS_DIR}" ]; then
CHECKS="$(find "${CHECKS_DIR}" -name "*.sh" -print0 2>/dev/null | xargs -0)"
for c in $CHECKS; do
logmsg "Executing $c"
$c
done
fi
if [ "$DRYRUN" = 'yes' ]; then
logmsg "Release tag is ready to be created with command: git tag $TAG"
else
git tag "$TAG"
logmsg "$TAG is created OK."
fi

156
scripts/rel/sync-remotes.sh Executable file
View File

@ -0,0 +1,156 @@
#!/usr/bin/env bash
set -euo pipefail
# ensure dir
cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")/../.."
BASE_BRANCHES=( 'release-50' 'master' )
usage() {
cat <<EOF
$0 [option]
options:
-h|--help:
This script works on one of the branches listed in the -b|--base option below.
It tries to merge (by default with --ff-only option)
upstreams branches for the current working branch.
The uppstream branch of the current branch are as below:
* release-50: [] # no upstream for 5.0 opensource edition
* master: [release-50] # sync release-50 to master
-b|--base:
The base branch of current working branch if currently is not
on one of the following branches.
${BASE_BRANCHES[@]}
-i|--interactive:
With this option, the script will try to merge upstream
branches to local working branch interactively.
That is, there will be git prompts to edit commit messages etc.
Without this option, the script executes 'git merge' command
with '--ff-only' option which conveniently pulls remote
updates if there is any, and fails when fast-forward is not possible
EOF
}
logerr() {
echo "$(tput setaf 1)ERROR: $1$(tput sgr0)"
}
logwarn() {
echo "$(tput setaf 3)WARNING: $1$(tput sgr0)"
}
logmsg() {
echo "INFO: $1"
}
INTERACTIVE='no'
while [ "$#" -gt 0 ]; do
case $1 in
-h|--help)
usage
exit 0
;;
-i|--interactive)
shift
INTERACTIVE='yes'
;;
-b|--base)
shift
BASE_BRANCH="$1"
shift
;;
*)
logerr "Unknown option $1"
exit 1
;;
esac
done
CURRENT_BRANCH="$(git branch --show-current)"
BASE_BRANCH="${BASE_BRANCH:-${CURRENT_BRANCH}}"
## check if arg1 is one of the elements in arg2-N
is_element() {
local e match="$1"
shift
for e in "${@}"; do
if [ "$e" = "$match" ]; then
return 0
fi
done
return 1
}
if ! is_element "$BASE_BRANCH" "${BASE_BRANCHES[@]}"; then
logerr "Cannot work with branch $BASE_BRANCH"
logerr "The base branch must be one of: ${BASE_BRANCHES[*]}"
logerr "Change work branch to one of the above."
logerr "OR: use -b|--base to specify from which base branch is current working branch created"
exit 1
fi
## Find git remotes to fetch from.
##
## NOTE: For enterprise, the opensource repo must be added as a remote.
## Because not all changes in opensource repo are synced to enterprise repo immediately.
##
## NOTE: grep -v enterprise here, but why not to match on full repo name 'emqx/emqx.git'?
## It's because the git remote does not always end with .git
GIT_REMOTE_CE="$(git remote -v | grep 'emqx/emqx' | grep -v enterprise | grep fetch | head -1 | awk '{print $1}' || true)"
if [ -z "$GIT_REMOTE_CE" ]; then
logerr "Cannot find git remote for emqx/emqx"
exit 1
fi
REMOTES=( "${GIT_REMOTE_CE}" )
## Fetch the remotes
for remote in "${REMOTES[@]}"; do
logwarn "Fetching from remote=${remote} (force tag sync)."
git fetch "$remote" --tags --force
done
logmsg 'Fetched all remotes'
if [ "$INTERACTIVE" = 'yes' ]; then
MERGE_OPTS=''
else
## Using --ff-only to *check* if the remote is already merged
## Also conveniently merged it in case it's *not* merged but can be fast-forwarded
## Alternative is to check with 'git merge-base'
MERGE_OPTS='--ff-only'
fi
## Get the git remote reference of the given 'release-' or 'main-' branch
remote_ref() {
local branch="$1"
echo -n "${GIT_REMOTE_CE}/${branch} "
}
remote_refs() {
local br
for br in "${@}"; do
remote_ref "$br"
done
}
## Get upstream branches of the given branch
upstream_branches() {
local base="$1"
case "$base" in
release-50)
remote_ref "$base"
;;
master)
remote_refs "$base" 'release-50'
;;
esac
}
for remote_ref in $(upstream_branches "$BASE_BRANCH"); do
logmsg "Merging $remote_ref"
git merge $MERGE_OPTS "$remote_ref"
done