| #!/bin/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. |
| # |
| # |
| # Creates and sets up the actual release artifacts into dev |
| # See https://cwiki.apache.org/confluence/display/METRON/Release+Process |
| |
| |
| set -eo pipefail |
| |
| # define constants |
| # Git repos |
| # To add a new submodule, add the repo name, upstream Git repo, and update the getrepo() selection function. |
| # if versioning of the submodule isn't x.y.z format, retrieval of the git tag must also be adjusted. |
| METRON_REPO_NAME="metron" |
| BRO_PLUGIN_REPO_NAME="metron-bro-plugin-kafka" |
| METRON_UPSTREAM="https://gitbox.apache.org/repos/asf/${METRON_REPO_NAME}.git" |
| BRO_PLUGIN_UPSTREAM="https://gitbox.apache.org/repos/asf/${BRO_PLUGIN_REPO_NAME}.git" |
| |
| DEV_REPO="https://dist.apache.org/repos/dist/dev/metron" |
| RELEASE_REPO=" https://dist.apache.org/repos/dist/release/metron" |
| PLUGIN_GIT_REPO="https://gitbox.apache.org/repos/asf/${BRO_PLUGIN_REPO_NAME}.git" |
| |
| RC_PREFIX=rc |
| UPPER_RC_PREFIX="$(tr '[:lower:]' '[:upper:]' <<< ${RC_PREFIX})" |
| TAG_POSTFIX="-release" |
| |
| CONFIG_FILE=~/.metron-prepare-release-candidate |
| # does a config file already exist? |
| if [ -f $CONFIG_FILE ]; then |
| . $CONFIG_FILE |
| echo " ...using settings from $CONFIG_FILE" |
| fi |
| |
| # apache id of committer (you) |
| if [ -z "${APACHE_NAME}" ]; then |
| read -p " your apache userid [${APACHE_NAME}]: " INPUT |
| [ -n "$INPUT" ] && APACHE_NAME=$INPUT |
| |
| # write setting to config file |
| echo "APACHE_NAME=$APACHE_NAME" >> $CONFIG_FILE |
| fi |
| |
| # apache email addr of committer (you) |
| if [ -z "${APACHE_EMAIL}" ]; then |
| APACHE_EMAIL=${APACHE_NAME}@apache.org |
| read -p " your apache email [${APACHE_EMAIL}]: " INPUT |
| [ -n "$INPUT" ] && APACHE_EMAIL=$INPUT |
| |
| # write setting to config file, so it is not needed next time |
| echo "APACHE_EMAIL=$APACHE_EMAIL" >> $CONFIG_FILE |
| fi |
| |
| # which repo? metron or metron-bro-plugin-kafka |
| getrepo() { |
| echo " [1] ${METRON_REPO_NAME}" |
| echo " [2] ${BRO_PLUGIN_REPO_NAME}" |
| read -p " which repo? [1]: " INPUT |
| case "${INPUT}" in |
| [Bb][Rr][Oo]|[Mm][Ee][Tt][Rr][Oo][Nn]-[Bb][Rr][Oo]-[Pp][Ll][Uu][Gg][Ii][Nn]-[Kk][Aa][Ff][Kk][Aa]|*metron-bro-plugin-kafka\.git|2) |
| INPUT="${BRO_PLUGIN_UPSTREAM}" ;; |
| [Mm][Ee][Tt][Rr][Oo][Nn]|*metron\.git|1|'') |
| INPUT="${METRON_UPSTREAM}" ;; |
| *) |
| echo "Invalid repo, provided \"${INPUT}\". Please choose between ${METRON_REPO_NAME} or ${BRO_PLUGIN_REPO_NAME}" |
| return 1 |
| ;; |
| esac |
| [ -n "$INPUT" ] && UPSTREAM=$INPUT |
| return 0 |
| } |
| until getrepo; do :; done |
| |
| CHOSEN_REPO=$(basename ${UPSTREAM%%.git}) |
| # Need the capitalized version of the repos some naming |
| CAPITAL_REPO="$(tr '[:lower:]' '[:upper:]' <<< ${CHOSEN_REPO:0:1})${CHOSEN_REPO:1}" |
| |
| getcurrentversion() { |
| # currently released version. Used for CHANGES file |
| read -p " current version: " CURRENT_VERSION |
| if ! [[ "${CURRENT_VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then |
| printf " Please enter a valid x.y.z version\n" |
| return 1 |
| fi |
| return 0 |
| } |
| until getcurrentversion; do : ; done |
| |
| # version that we're building an RC for |
| getversion() { |
| read -p " version being built: " VERSION |
| if ! [[ "${VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then |
| printf " Please enter a valid x.y.z version\n" |
| return 1 |
| fi |
| return 0 |
| } |
| until getversion; do : ; done |
| |
| # RC number we're building |
| getrcnum() { |
| read -p " release candidate number: " RC_NUM |
| if [[ "${RC_NUM}" =~ ^[0-9]+$ ]]; then |
| RC="${RC_PREFIX}${RC_NUM}" |
| return 0 |
| else |
| printf " Please enter an integer\n" |
| return 1 |
| fi |
| } |
| until getrcnum; do : ; done |
| |
| # define default values |
| TMPDIR="$HOME/tmp" |
| WORKDIR="$TMPDIR/${CHOSEN_REPO}-${VERSION}" |
| |
| # warn the user if the working directory exists |
| if [ -d "$WORKDIR" ]; then |
| read -p " directory exists [$WORKDIR]. overwrite existing directory? [y/n] " -r |
| echo |
| if [[ ! $REPLY =~ ^[Yy]$ ]]; then |
| exit 1 |
| fi |
| fi |
| |
| # Clear out the existing work directory |
| rm -rf "$WORKDIR" |
| mkdir "$WORKDIR" |
| |
| getbaserev() { |
| read -p " base revision branch or hash for release candidate [master]: " GIT_REF |
| GIT_REF=${GIT_REF:-master} |
| |
| # check to see if we were given branch |
| git rev-parse -q --verify ${GIT_REF} >> /dev/null |
| if [[ $? -ne 0 ]]; then |
| # check to see if we were given hash |
| git cat-file -e ${GIT_REF} |
| if [[ $? -ne 0 ]]; then |
| "Unable to find git revision" |
| return 1 |
| fi |
| fi |
| return 0 |
| } |
| until getbaserev; do : ; done |
| |
| # Signing key |
| getkey() { |
| read -s -p " signing key id in 8-byte format (e.g. BADDCAFEDEADBEEF): " SIGNING_KEY |
| printf "\n" |
| if ! [[ "${SIGNING_KEY}" =~ ^[A-F0-9]{16}$ ]]; then |
| printf " Please enter a valid signing key\n" |
| return 1 |
| fi |
| return 0 |
| } |
| |
| until getkey; do : ; done |
| |
| # Determine if this is a practice run or not. |
| getpractice() { |
| read -p " do a live run (push to remote repositories?) [y/n] " INPUT |
| case "${INPUT}" in |
| y) |
| PRACTICE_RUN=false |
| return 0 ;; |
| n) |
| PRACTICE_RUN=true |
| return 0 ;; |
| *) |
| printf "Please enter 'y' or 'n'\n" |
| return 1 |
| ;; |
| esac |
| } |
| until getpractice; do : ; done |
| |
| ## Prepare everything for building the release artifacts |
| |
| # Fetch the SVN repos. Always needed regardless of what's being released. |
| fetch_svn_repo () { |
| local SVN_REPO=$1 |
| local SVN_DIR=$2 |
| mkdir "$SVN_DIR" |
| cd "$SVN_DIR" |
| printf "Checking out repo: %s\n" "$SVN_REPO" "$(basename $SVN_DIR)" |
| svn co -q $SVN_REPO |
| cd "$(dirname $WORKDIR)" |
| } |
| |
| fetch_svn_repo "$DEV_REPO" "$WORKDIR/dev" |
| fetch_svn_repo "$RELEASE_REPO" "$WORKDIR/release" |
| |
| # Fetch the appropriate Git repo. Only need what we're releasing |
| GIT_DIR="$WORKDIR/${CHOSEN_REPO}" |
| printf "Checking out git repo: %s\n" "$UPSTREAM" |
| git clone $UPSTREAM "${GIT_DIR}" |
| cd "${GIT_DIR}" |
| git fetch --tags |
| |
| # Create the release branch in the Git repo |
| printf "Creating branch: %s_%s\n" "${CAPITAL_REPO}" "$VERSION" |
| printf "Using git rev: %s\n" ${GIT_REF} |
| cd "$GIT_DIR" |
| git checkout ${GIT_REF} |
| git checkout -b "${CAPITAL_REPO}_${VERSION}" |
| |
| if [ "${PRACTICE_RUN}" = true ]; then |
| printf "This is a practice run. Not running <git push --set-upstream origin %s_%s>\n" "${CAPITAL_REPO}" "$VERSION" |
| else |
| printf "Pushing branch %s_%s\n" "${CAPITAL_REPO}" "$VERSION" |
| git push --set-upstream origin "${CAPITAL_REPO}_${VERSION}" |
| fi |
| |
| # Create directory for release artifacts |
| if [ "${CHOSEN_REPO}" = "${METRON_REPO_NAME}" ]; then |
| ART_DIR="$WORKDIR/dev/metron/${VERSION}-${UPPER_RC_PREFIX}${RC_NUM}" |
| else |
| # We're using a sub module, so put it in it's own directory. |
| ART_DIR="$WORKDIR/dev/metron/${CHOSEN_REPO}/${VERSION}-${UPPER_RC_PREFIX}${RC_NUM}" |
| fi |
| mkdir -p "$ART_DIR" |
| |
| # Setup various parameters we need for the release artifacts |
| if [ "${CHOSEN_REPO}" = "${METRON_REPO_NAME}" ]; then |
| CORE_PREFIX="apache-metron_" |
| ARTIFACT_PREFIX="${CORE_PREFIX}" |
| TAG_VERSION="${CURRENT_VERSION}" |
| TAG="${CORE_PREFIX}${TAG_VERSION}${TAG_POSTFIX}" |
| elif [ "${CHOSEN_REPO}" = "${BRO_PLUGIN_REPO_NAME}" ]; then |
| BRO_PLUGIN_PREFIX="apache-metron-bro-plugin-kafka_" |
| ARTIFACT_PREFIX="${BRO_PLUGIN_PREFIX}" |
| TAG_VERSION="${CURRENT_VERSION}" |
| TAG="${BRO_PLUGIN_PREFIX}${TAG_VERSION}${TAG_POSTFIX}" |
| else |
| # If we ever add new modules, add them as needed. |
| printf "Unrecognized module: %s\n" "${CHOSEN_REPO}" |
| exit 1 |
| fi |
| ARTIFACT="${ARTIFACT_PREFIX}${VERSION}-${RC}" |
| |
| ## Do the work of actually creating the release artifacts |
| printf "Creating tentative git tag <%s%s-%s>. Do not push this tag until RC is ready for community review.\n" "${TAG_PREFIX}" "$VERSION" "$RC" |
| cd "$GIT_DIR" |
| git checkout "${CAPITAL_REPO}_${VERSION}" |
| # The branch only exists if this is not a practice run |
| if [ "${PRACTICE_RUN}" = false ]; then |
| printf "Pulling latest state of branch\n" |
| git pull |
| fi |
| git tag "${ARTIFACT}" |
| |
| # Create the rc tarball from the tag |
| printf "Creating the RC tarball for tag %s\n" "$ARTIFACT" |
| git archive "--prefix=${ARTIFACT}/" "${ARTIFACT}" | gzip > "${ARTIFACT}.tar.gz" |
| |
| # Create signing hash files |
| printf "Creating the SHA hash files\n" |
| gpg --print-md SHA512 ${ARTIFACT}.tar.gz > ${ARTIFACT}.tar.gz.sha512 |
| gpg --print-md SHA256 ${ARTIFACT}.tar.gz > ${ARTIFACT}.tar.gz.sha256 |
| |
| # Sign the release tarball |
| printf "Signing the release tarball\n" |
| gpg -u ${SIGNING_KEY} --armor --output ${ARTIFACT}.tar.gz.asc --detach-sig ${ARTIFACT}.tar.gz |
| if [[ $? -ne 0 ]]; then |
| # gpg will print out an error on its own |
| exit 1 |
| fi |
| |
| # Setup the release artifacts |
| printf "Copying release artifacts\n" |
| mv "${GIT_DIR}/${ARTIFACT}.tar.gz" "$ART_DIR" |
| mv "${ARTIFACT}.tar.gz.sha512" "$ART_DIR" |
| mv "${ARTIFACT}.tar.gz.sha256" "$ART_DIR" |
| mv "${ARTIFACT}.tar.gz.asc" "$ART_DIR" |
| |
| # Create the CHANGES file |
| # Do this by getting all commits in current branch that aren't in current release. Filter out any merges by making sure lines start with blankspace followed by "METRON" |
| # i.e. make sure the lines starts with a ticket number to avoid merge commits into feature branches |
| printf "Creating CHANGES file\n" |
| git log "${CAPITAL_REPO}_${VERSION}" "^tags/${TAG}" --no-merges | grep -E "^[[:blank:]]+METRON" | sed 's/\[//g' | sed 's/\]//g' > "${ART_DIR}/CHANGES" |
| if [[ $? -ne 0 ]]; then |
| "Error creating CHANGES file" |
| exit 1 |
| fi |
| |
| printf "Extracting LICENSE and NOTICE from tarball\n" # Only pull from core |
| cd ${ART_DIR} |
| |
| if [ "${CHOSEN_REPO}" = "${BRO_PLUGIN_REPO_NAME}" ]; then |
| # Bro's convention for the LICENSE is different, so the file is called COPYING |
| tar --strip-components=1 -zxvf "${ARTIFACT}.tar.gz" "${ARTIFACT}/COPYING" |
| else |
| tar --strip-components=1 -zxvf "${ARTIFACT}.tar.gz" "${ARTIFACT}/LICENSE" |
| fi |
| |
| # TODO figure out what to do for bro repo here. The KEYS file only needs to live in the /dist root, rather than in each sub repo. |
| # Should we have a separate process for adding to the KEYS file without doing a Metron release? |
| tar --strip-components=1 -zxvf "${ARTIFACT}.tar.gz" "${ARTIFACT}/NOTICE" |
| |
| # Add the directory and commit to subversion |
| COMMIT_DIR=$(basename ${ART_DIR}) |
| if [ "${PRACTICE_RUN}" = true ]; then |
| printf "This is a practice run. Not running the following commands:\n" |
| printf "<svn add %s>\n" ${COMMIT_DIR} |
| printf "<svn commit -m \"Adding artifacts for %s %s\">\n" "${CHOSEN_REPO}" "${COMMIT_DIR}" |
| else |
| printf "Adding artifacts for Metron ${VERSION}-${UPPER_RC_PREFIX}${RC_NUM} to dev SVN\n" |
| # Metron goes in the root of the dir, submodules go in folder |
| if [ "${CHOSEN_REPO}" = "${METRON_REPO_NAME}" ]; then |
| cd "$WORKDIR/dev/metron/" |
| else |
| cd "$WORKDIR/dev/metron/${CHOSEN_REPO}" |
| fi |
| svn add ${COMMIT_DIR} |
| svn commit -m "Adding artifacts for ${CHOSEN_REPO} ${COMMIT_DIR}" |
| fi |
| |