| #!/usr/bin/env bash |
| #------------------------------------------------------------- |
| # |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| # |
| #------------------------------------------------------------- |
| |
| ################################################################################ |
| ## File: release-utils.sh |
| ## Desc: Helper utilities for the release workflow |
| ################################################################################ |
| |
| ASF_REPO="https://github.com/apache/systemds" |
| ASF_REPO_CONTENT="https://raw.githubusercontent.com/apache/systemds" |
| |
| |
| # https://github.com/j143/systemds/issues/75 |
| GPG_TTY=$(tty) |
| export GPG_TTY |
| |
| # Output font formatting |
| # TODO: Does not work in git bash and mac. |
| export TERM=ansi |
| |
| bold() { |
| tput bold |
| echo -n "$@" |
| |
| # turn off bold |
| tput sgr0 |
| } |
| |
| revcolor() { |
| # standout mode |
| tput smso |
| echo -n "$@" |
| tput rmso |
| } |
| |
| |
| # color values |
| # red 1; green 2; blue 4; magenta 5; |
| greencolor() { |
| tput setaf 2 |
| echo -n "$@" |
| tput sgr0 |
| } |
| |
| # exit with error message |
| error() { |
| echo "$*" |
| exit 1 |
| } |
| |
| |
| # Read the configuration |
| read_config() { |
| local PROMPT="$1" |
| local DEFAULT="$2" |
| |
| local REPLY= |
| |
| read -p "$PROMPT [$DEFAULT]: " REPLY |
| local RETVAL="${REPLY:-$DEFAULT}" |
| if [ -z "$RETVAL" ]; then |
| error "$PROMPT must be provided" |
| fi |
| echo "$RETVAL" |
| } |
| |
| |
| # parse version number from pom.xml |
| # <version> tag. |
| parse_version() { |
| grep -e '<version>.*</version>' | \ |
| head -n 2 | tail -n 1 | cut -d '>' -f2 | cut -d '<' -f1 |
| } |
| |
| # function to log output to a .log file |
| run_silent() { |
| local DESCRIPTION="$1" |
| local LOG_FILE="$2" |
| |
| # Remove the first two arguments |
| # https://ss64.com/bash/shift.html |
| shift 2 |
| |
| printf "\n =============== " |
| printf "\n = $DESCRIPTION " |
| printf "\n Executing command: " |
| printf "\n $(bold $(greencolor $@ )) \n" |
| printf "\n Log file: $LOG_FILE " |
| printf "\n =============== \n" |
| |
| # 2>&1 https://stackoverflow.com/a/818284 |
| # 1 stdout, 2 stderr, >& redirect merger operator |
| . "$@" 1>"$LOG_FILE" 2>&1 |
| |
| # a successful command returns 0 exit code |
| local SUCCESS=$? |
| if [ $SUCCESS != 0 ]; then |
| printf "\n Command FAILED to Execute. Log files are available.\n" |
| tail "$LOG_FILE" |
| exit $SUCCESS |
| fi |
| } |
| |
| # Clean Working directory of untracked files |
| cleanup_repo() { |
| # https://git-scm.com/docs/git-clean |
| git clean -d -f -x |
| } |
| |
| # check for the tag name in git repo |
| check_for_tag() { |
| curl -s --head --fail "$ASF_REPO/releases/tag/$1" > /dev/null |
| } |
| |
| |
| # get the release info including |
| # branch details, snapshot version |
| # error validation |
| get_release_info() { |
| if [[ -z "$GIT_BRANCH" ]]; then |
| # If not branch is specified, find the latest branch from repo |
| GIT_BRANCH=$(git ls-remote --heads "$ASF_REPO" | |
| awk '{print $2}' | |
| sort -r | |
| head -n 1 | |
| cut -d/ -f3) |
| fi |
| |
| printf "\n================\n" |
| export GIT_BRANCH=$(read_config "Branch" "$GIT_BRANCH") |
| |
| # Find the current version for the branch |
| local VERSION=$(curl -s "$ASF_REPO_CONTENT/$GIT_BRANCH/pom.xml" | |
| parse_version) |
| |
| echo "Current branch version is $VERSION." |
| |
| if [[ ! $VERSION =~ .*-SNAPSHOT ]]; then |
| error "Not a SNAPSHOT version: $VERSION" |
| fi |
| |
| NEXT_VERSION="$VERSION" |
| RELEASE_VERSION="${VERSION/-SNAPSHOT/}" |
| SHORT_VERSION=$(echo "$VERSION" | cut -d . -f 1-2) |
| local REV=$(echo "$RELEASE_VERSION" | cut -d . -f 3) |
| |
| # Find out what rc is being prepared. |
| # - If the current version is "x.y.0", then this is rc1 of the "x.y.0" release. |
| # - If not, need to check whether the previous version has been already released or not. |
| # - If it has, then we're building rc1 of the current version. |
| # - If it has not, we're building the next RC of the previous version. |
| local RC_COUNT |
| if [[ $REV != 0 ]]; then |
| local PREV_REL_REV=$((REV - 1)) |
| local PREV_REL_TAG="v${SHORT_VERSION}.${PREV_REL_REV}" |
| |
| if check_for_tag "$PREV_REL_TAG"; then |
| RC_COUNT=1 |
| REV=$((REV + 1)) |
| NEXT_VERSION="${SHORT_VERSION}.${REV}-SNAPSHOT" |
| else |
| RELEASE_VERSION="${SHORT_VERSION}.${PREV_REL_REV}" |
| RC_COUNT=$(git ls-remote --tags "$ASF_REPO" "v${RELEASE_VERSION}-rc*" | wc -l) |
| RC_COUNT=$((RC_COUNT + 1)) |
| fi |
| else |
| REV=$((REV + 1)) |
| NEXT_VERSION="${SHORT_VERSION}.${REV}-SNAPSHOT" |
| RC_COUNT=1 |
| fi |
| |
| export NEXT_VERSION=$(read_config "Next development version" "$NEXT_VERSION") |
| export RELEASE_VERSION=$(read_config "Release" "$RELEASE_VERSION") |
| |
| RC_COUNT=$(read_config "RC #" "$RC_COUNT") |
| |
| # Check if the RC already exists, and if re-creating the RC, skip tag |
| # creation |
| RELEASE_TAG="${RELEASE_VERSION}-rc${RC_COUNT}" |
| SKIP_TAG=0 |
| |
| if check_for_tag "$RELEASE_TAG"; then |
| read -p "$RELEASE_TAG already exists. Continue anyway [Y/n]? " ANSWER |
| if [[ "$ANSWER" != "Y" ]]; then |
| error "Exiting." |
| fi |
| SKIP_TAG |
| fi |
| |
| export RELEASE_TAG |
| |
| GIT_REF="$RELEASE_TAG" |
| |
| export GIT_REF |
| export PACKAGE_VERSION="$RELEASE_TAG" |
| |
| # Git configuration info |
| # The ASF ID is obtained from |
| # https://people.apache.org/committers-by-project.html#systemds |
| if [[ -z "$ASF_USERNAME" ]]; then |
| export ASF_USERNAME=$(read_config "ASF ID" "$LOGNAME") |
| fi |
| |
| if [[ -z "$GIT_NAME" ]]; then |
| GIT_NAME=$(git config user.name || echo "") |
| export GIT_NAME=$(read_config "Full name" "$GIT_NAME") |
| fi |
| |
| # git configuration info |
| if [[ -z "$GIT_EMAIL" ]]; then |
| export GIT_EMAIL="$ASF_USERNAME@apache.org" |
| fi |
| |
| # GPG key configuration info |
| if [[ -z "$GPG_KEY" ]]; then |
| export GPG_KEY=$(read_config "GPG key" "$GIT_EMAIL") |
| fi |
| |
| cat <<EOF |
| ================ |
| Release details: |
| BRANCH: $GIT_BRANCH |
| VERSION: $RELEASE_VERSION |
| TAG: $RELEASE_TAG |
| NEXT: $NEXT_VERSION |
| ASF ID: $ASF_USERNAME |
| GPG KEY ID: $GPG_KEY |
| FULL NAME: $GIT_NAME |
| E-MAIL: $GIT_EMAIL |
| ================ |
| EOF |
| |
| if [[ -z "$CORRECT_RELEASE_INFO" ]]; then |
| CORRECT_RELEASE_INFO=$(read_config "Is the release info correct (1 for Yes, 0 for No) ?" "$CORRECT_RELEASE_INFO") |
| fi |
| |
| if [[ ! "$CORRECT_RELEASE_INFO" = '1' ]]; then |
| echo "Exiting." |
| exit 1 |
| fi |
| |
| if [[ -z "$ASF_PASSWORD" ]]; then |
| stty -echo && printf "ASF password: " && read ASF_PASSWORD && printf '\n' && stty echo |
| fi |
| |
| if [[ -z "$GPG_PASSPHRASE" ]]; then |
| stty -echo && printf "GPG passphrase: " && read GPG_PASSPHRASE && printf '\n' && stty echo |
| fi |
| |
| export ASF_PASSWORD |
| export GPG_PASSPHRASE |
| |
| } |
| |
| is_dry_run() { |
| # By default, evaluates to false |
| [[ "$DRY_RUN" = 1 ]] |
| } |
| |
| is_github_ci() { |
| [[ "$GITHUB_CI" = 1 ]] |
| } |