| #!/bin/bash |
| # |
| # Licensed 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. |
| # |
| # |
| # This script is used to create a release candidate. It will update the current |
| # .parquetcppversion as well as creates a tag for the new release candidate and |
| # publishes the source distribution and signatures to be voted on. |
| # |
| # master~1 (0.5.0-snapshot) ----- master (0.6.0-snapshot) |
| # \---- 0.5.0 (0.5.0) |
| # |
| # A email template will be generated after successfully generating a release |
| # candidate which will need to be sent to the dev@ and private@ mailing lists. |
| # |
| set -o errexit |
| set -o nounset |
| |
| rc_number=0 |
| override_version='' |
| parquetcpp_git_web_url='https://gitbox.apache.org/repos/asf?p=parquet-cpp.git' |
| parquet_svn_dist_url='https://dist.apache.org/repos/dist/dev/parquet' |
| |
| function print_help_and_exit { |
| cat <<EOF |
| Apache Parquet C++ release candidate tool. |
| |
| Usage: $0 [-h] [-l p|m|M] [-r #] [-p | publish] |
| |
| -h Print this help message and exit |
| -l Increment level, must be one of: |
| p, patch (default) |
| m, minor |
| M, major |
| -v Override the existing version in .parquetcppversion |
| -r Release candidate number (default: 0) |
| -p Publish the release candidate (default: dry-run, does not publish anything) |
| EOF |
| exit 0 |
| } |
| |
| publish=0 |
| increment_level="patch" |
| rc_number=0 |
| while getopts ":hl:v:r:p" opt; do |
| case $opt in |
| l) |
| case ${OPTARG} in |
| 'p' | 'patch') increment_level='patch' ;; |
| 'm' | 'minor') increment_level='minor' ;; |
| 'M' | 'major') increment_level='major' ;; |
| *) echo 'Unknown increment level'; exit 1 ;; |
| esac |
| ;; |
| r) |
| rc_number=${OPTARG} |
| ;; |
| p) |
| publish=1 |
| ;; |
| h) |
| print_help_and_exit |
| ;; |
| v) |
| override_version=${OPTARG} |
| ;; |
| * ) |
| echo "Unknown option: -$OPTARG" |
| print_help_and_exit |
| ;; |
| esac |
| done |
| |
| shift $(($OPTIND - 1)) |
| if [[ "${1:-dry-run}" == "publish" ]]; then |
| publish=1 |
| fi |
| |
| # Update local repository |
| git fetch --all -q |
| git fetch --tags -q |
| |
| # Verify that this is a clean repository |
| if [[ -n "`git status --porcelain`" ]]; then |
| echo "ERROR: Please run from a clean git repository." |
| exit 1 |
| elif [[ "`git rev-parse --abbrev-ref HEAD`" != "master" ]]; then |
| echo "ERROR: This script must be run from master." |
| exit 1 |
| fi |
| |
| if [[ ! -f .parquetcppversion ]]; then |
| echo "Warrning: This script must be run from the root of the repository" |
| exit 1 |
| fi |
| |
| # Calculate the new version string |
| current_version=$(cat .parquetcppversion | tr '[a-z]' '[A-Z]') |
| if ! [[ $current_version =~ .*-SNAPSHOT ]]; then |
| echo "ERROR: .parquetcppversion is required to contain 'SNAPSHOT', it is ${current_version}" |
| exit 1 |
| else |
| if [[ $override_version != "" ]]; then |
| current_version=$override_version |
| fi |
| |
| major=`echo $current_version | cut -d. -f1` |
| minor=`echo $current_version | cut -d. -f2` |
| patch=`echo $current_version | cut -d. -f3 | cut -d- -f1` |
| |
| current_version="${major}.${minor}.${patch}" |
| |
| if [[ $increment_level == "patch" ]]; then |
| new_master_version="${major}.${minor}.$((patch + 1))" |
| elif [[ $increment_level == "minor" ]]; then |
| new_master_version="${major}.$((minor + 1)).0" |
| elif [[ $increment_level == "major" ]]; then |
| new_master_version="$((major + 1)).0.0" |
| else |
| echo "Unknown release increment ${increment_level}" |
| exit 1 |
| fi |
| |
| new_snapshot_version="${new_master_version}-SNAPSHOT" |
| fi |
| |
| # Add the rc tag to the current version |
| rc_version="${current_version}-rc${rc_number}" |
| version_tag="apache-parquet-cpp-${current_version}" |
| rc_version_tag="apache-parquet-cpp-${rc_version}" |
| |
| echo |
| echo "Generating release candidate ${rc_version_tag}" |
| echo |
| |
| # Make sure the tag does not exist |
| if git rev-parse ${version_tag} >/dev/null 2>&1; then |
| echo "ERROR: tag ${version_tag} exists." |
| exit 1 |
| fi |
| |
| if git rev-parse ${rc_version_tag} >/dev/null 2>&1; then |
| echo "ERROR: tag ${rc_version_tag} exists." |
| exit 1 |
| fi |
| |
| # Reset instructions |
| current_git_rev=$(git rev-parse HEAD) |
| function print_reset_instructions { |
| cat <<EOF |
| To roll back your local repo you will need to run: |
| |
| git checkout master |
| git reset --hard ${current_git_rev} |
| git tag -d ${rc_version_tag} |
| git branch -D stage_${rc_version} |
| EOF |
| } |
| |
| # If anything goes wrong from here then print roll back instructions before exiting. |
| function print_rollback_instructions { |
| echo "ERROR: Looks like something has failed while creating the release candidate." |
| print_reset_instructions |
| } |
| trap print_rollback_instructions EXIT |
| |
| # All check are now complete, before we start alert if we are in dry-run |
| if [[ $publish == 0 ]]; then |
| echo "Performing dry-run, run with '-p' when you are ready to run and publish a release candidate" |
| fi |
| |
| # This should be a clean repo we are working against. Run clean just to ensure it is. |
| git clean -fdxq |
| |
| echo "Generating changelog" |
| ./dev/release/changelog $current_version |
| git add CHANGELOG |
| git commit -m "Updating CHANGELOG for ${current_version} release." |
| |
| echo "Committing updated .parquetcppversion on master" |
| echo $new_snapshot_version > .parquetcppversion |
| git add .parquetcppversion |
| git commit -m "Incrementing snapshot version to ${new_snapshot_version}." |
| |
| echo "Creating ${rc_version} staging branch" |
| git checkout -b "stage_${rc_version}" |
| |
| echo "Updating .parquetcppversion on staging branch" |
| # Increment the version and create a branch |
| echo ${current_version} > .parquetcppversion |
| git add .parquetcppversion |
| git commit -m "Updating .parquetcppversion to ${current_version}." |
| |
| # Build the source distribution from the new branch |
| echo "Building the source distribution" |
| dist_dir=dist |
| dist_name="${version_tag}" |
| |
| mkdir -p ${dist_dir} |
| git archive --prefix=${dist_name}/ -o ${dist_dir}/${dist_name}.tar.gz HEAD |
| pushd ${dist_dir} |
| # Sign the tarball. |
| echo "Signing the distribution" |
| gpg --armor --output ${dist_name}.tar.gz.asc --detach-sig ${dist_name}.tar.gz |
| |
| # Create the checksums |
| echo "Creating checksums" |
| gpg --print-md MD5 ${dist_name}.tar.gz > ${dist_name}.tar.gz.md5 |
| sha1sum ${dist_name}.tar.gz > ${dist_name}.tar.gz.sha1 |
| sha256sum ${dist_name}.tar.gz > ${dist_name}.tar.gz.sha256 |
| sha512sum ${dist_name}.tar.gz > ${dist_name}.tar.gz.sha512 |
| popd |
| |
| parquet_svn_rc_url="${parquet_svn_dist_url}/apache-parquet-cpp-${rc_version}" |
| |
| # Publish release candidate to svn and commit and push the new git tag |
| if [[ $publish == 1 ]]; then |
| echo "Publishing release candidate to ${parquet_svn_rc_url}" |
| svn mkdir ${parquet_svn_rc_url} -m "parquet-cpp-${current_version} release candidate ${rc_version}" |
| svn co --depth=empty ${parquet_svn_rc_url} ${dist_dir} |
| pushd ${dist_dir} |
| svn add ${dist_name}* |
| svn ci -m "parquet-cpp-${current_version} release candidate ${rc_version}" |
| popd |
| |
| echo "Creating tag ${rc_version_tag}" |
| git tag -s ${rc_version_tag} \ |
| -m "Apache Parquet C++ ${current_version} release candidate ${rc_version}" |
| git push origin "${rc_version_tag}" |
| |
| echo "Pushing updated .parquetcppversion to master" |
| git checkout master |
| git push origin "master:master-after-${rc_version_tag}" |
| fi |
| |
| echo "Done creating the release candidate. The following draft email has been created" |
| echo "to send to the dev@parquet.apache.org mailing list" |
| echo |
| |
| # Create the email template for the release candidate to be sent to the mailing lists. |
| if [[ $(uname) == Darwin ]]; then |
| vote_end=$(date -v+3d) |
| else |
| vote_end=$(date -d+3days) |
| fi |
| |
| MESSAGE=$(cat <<__EOF__ |
| To: dev@parquet.apache.org |
| Subject: [VOTE] Release Apache Parquet C++ ${current_version} RC${rc_number} |
| |
| All, |
| |
| I propose that we accept the following release candidate as the official |
| Apache Parquet C++ ${current_version} release. |
| |
| Parquet C++ ${rc_version} includes the following: |
| --- |
| The CHANGELOG for the release is available at: |
| ${parquetcpp_git_web_url}&f=CHANGELOG&hb=${rc_version_tag} |
| |
| The tag used to create the release candidate is: |
| ${parquetcpp_git_web_url};a=shortlog;h=refs/tags/${rc_version_tag} |
| |
| The release candidate is available at: |
| ${parquet_svn_rc_url}/${dist_name}.tar.gz |
| |
| The MD5 checksum of the release candidate can be found at: |
| ${parquet_svn_rc_url}/${dist_name}.tar.gz.md5 |
| |
| The signature of the release candidate can be found at: |
| ${parquet_svn_rc_url}/${dist_name}.tar.gz.asc |
| |
| The GPG key used to sign the release are available at: |
| ${parquet_svn_dist_url}/KEYS |
| |
| The release is based on the commit hash ${current_git_rev}. |
| |
| Please download, verify, and test. |
| |
| The vote will close on ${vote_end} |
| |
| [ ] +1 Release this as Apache Parquet C++ ${current_version} |
| [ ] +0 |
| [ ] -1 Do not release this as Apache Parquet C++ ${current_version} because... |
| |
| __EOF__ |
| ) |
| |
| echo "--------------------------------------------------------------------------------" |
| echo |
| echo "${MESSAGE}" |
| echo |
| echo "--------------------------------------------------------------------------------" |
| echo |
| |
| # Print reset instructions if this was a dry-run |
| if [[ $publish == 0 ]]; then |
| echo |
| echo "This was a dry run, nothing has been published." |
| echo |
| print_reset_instructions |
| fi |
| |
| # Unset error message handler and exit |
| trap '' EXIT |
| exit 0 |