Просмотр исходного кода

Merge pull request #9428 from zmstone/1127-build-add-release-help-scripts

build: add release helper scripts
Zaiming (Stone) Shi 3 лет назад
Родитель
Сommit
f91d97d3c9
3 измененных файлов с 405 добавлено и 0 удалено
  1. 35 0
      scripts/rel/check-chart-vsn.sh
  2. 214 0
      scripts/rel/cut.sh
  3. 156 0
      scripts/rel/sync-remotes.sh

+ 35 - 0
scripts/rel/check-chart-vsn.sh

@@ -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 - 0
scripts/rel/cut.sh

@@ -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 - 0
scripts/rel/sync-remotes.sh

@@ -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