| #!/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. |
| |
| set -e |
| |
| function trap_err { |
| echo |
| echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" |
| echo "!!! An error occurred while creating the release candidate !!!" |
| echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" |
| echo |
| echo "Perform the following steps:" |
| echo |
| echo "- Drop the staged files (if they exist) at https://repository.apache.org" |
| echo "- Type 'exit', fix the issues, and start over" |
| echo |
| } |
| |
| trap 'trap_err' ERR |
| |
| function usage { |
| BN=$(basename $0) |
| cat <<USAGE >&2 |
| usage: $BN [OPTION]... |
| |
| Options: |
| -n, --dry-run [alt] Run all commands but do not actually publish anything. |
| Can optionally provide an alternative github repo and |
| branch of the form "user/repo@branch" instead of the |
| default "apache/daffodil@main" |
| -h, --help Display this help and exit |
| USAGE |
| } |
| |
| DRY_RUN=false |
| |
| echo "Which project to release?" |
| select PROJECT_REPO in daffodil daffodil-vscode |
| do |
| case $PROJECT_REPO in |
| "daffodil") |
| PROJECT_DIST_DIR="" |
| PROJECT_NAME="Daffodil" |
| break |
| ;; |
| "daffodil-vscode") |
| PROJECT_DIST_DIR="$PROJECT_REPO" |
| PROJECT_NAME="Daffodil VS Code Extension" |
| break |
| ;; |
| *) |
| echo "unknown project: $REPLY" >&2 |
| exit 1 |
| ;; |
| esac |
| done |
| |
| DAFFODIL_CODE_USER="apache" |
| DAFFODIL_CODE_REPO="$PROJECT_REPO" |
| DAFFODIL_CODE_BRANCH="main" |
| |
| DAFFODIL_SITE_REPO="daffodil-site" |
| |
| DAFFODIL_DIST="daffodil-dist" |
| |
| while [[ $# -gt 0 ]] |
| do |
| option=$1 |
| case $option in |
| -n|--dry-run) |
| DRY_RUN=true |
| if [[ (! -z $2) && ($2 != -*) ]] |
| then |
| DAFFODIL_CODE_USER=`echo $2 | cut -d/ -f1` |
| DAFFODIL_CODE_REPO=`echo $2 | cut -d/ -f2 | cut -d@ -f1` |
| DAFFODIL_CODE_BRANCH=`echo $2 | cut -d@ -f2` |
| shift |
| fi |
| shift |
| ;; |
| -h|--help) |
| usage |
| exit 0 |
| ;; |
| *) |
| echo "unknown option: $option" >&2 |
| usage |
| exit 1 |
| ;; |
| esac |
| done |
| |
| gpg-agent --daemon --default-cache-ttl 3000 --max-cache-ttl 3000 |
| if [ $? -ne 0 ]; then |
| echo -e "\n!!! Unable to change timeout of the gpg-agent !!!\n" |
| echo -e "\n!!! Try updating it manually at ~/.gnupg/gpg-agent.conf for 3000 seconds each !!!\n" |
| exit |
| fi |
| |
| export GPG_TTY=$(tty) |
| export WIX=/opt/wix311/ |
| export LANG=en_US.UTF-8 |
| export CC=clang |
| export AR=llvm-ar |
| |
| AVAILABLE_KEYS=() |
| SHORT_SEC_KEY_IDS=`gpg --list-secret-keys --with-colons | grep '^sec' | cut -d: -f 5` |
| for SHORT_SEC_KEY_ID in $SHORT_SEC_KEY_IDS |
| do |
| LONG_SEC_KEY_ID=`gpg --list-secret-keys --with-colons $SHORT_SEC_KEY_ID | grep -m 1 '^fpr' | cut -d: -f10` |
| SEC_KEY_UID=`gpg --list-secret-keys --with-colons $LONG_SEC_KEY_ID | grep '^uid' | cut -d: -f10` |
| AVAILABLE_KEYS+=("$LONG_SEC_KEY_ID [$SEC_KEY_UID]") |
| done |
| |
| if [ ${#AVAILABLE_KEYS[@]} -eq 0 ] |
| then |
| echo -e "\n!!! No secret keys found !!!\n" |
| echo -e "\n!!! Ensure you have created a bind mount of your gpg directory, for example with -v ~/.gnupg/:/root/.gnupg/ !!!\n" |
| exit |
| fi |
| |
| echo |
| echo "Which code signing key:" |
| select PGP_KEY_SELECTION in "${AVAILABLE_KEYS[@]}" |
| do |
| if [ -z "$PGP_KEY_SELECTION" ] |
| then |
| echo -e "\n!!! Bad key selection !!!\n" |
| exit |
| fi |
| PGP_SIGNING_KEY_ID=$(echo $PGP_KEY_SELECTION | cut -d" " -f 1) |
| break |
| done |
| |
| echo |
| read -p "Pre Release label (e.g. rc1): " PRE_RELEASE |
| read -p "Git Commit Name: " GIT_COMMIT_NAME |
| read -p "Git Commit Email: " GIT_COMMIT_EMAIL |
| read -p "Apache Username: " APACHE_USERNAME |
| read -s -p "Apache Password: " APACHE_PASSWD |
| |
| echo |
| echo |
| |
| echo "test" | gpg --default-key $PGP_SIGNING_KEY_ID --detach-sign --armor --output /dev/null |
| if [ $? -ne 0 ]; then |
| echo -e "\n!!! Unable to sign data with given key: $PGP_SIGNING_KEY !!!\n" |
| echo -e "\n!!! Ensure you have created a bind mount of your gpg directory, for example with -v ~/.gnupg/:/root/.gnupg/ !!!\n" |
| exit |
| fi |
| |
| |
| TEST_GIT_DIR=/tmp/test-git-sign |
| mkdir -p $TEST_GIT_DIR |
| pushd $TEST_GIT_DIR &> /dev/null |
| git init -b main . |
| git commit --allow-empty --allow-empty-message -m "Test Commit" |
| git tag -as -u $PGP_SIGNING_KEY_ID -m "Test Signed Tag" test-tag |
| if [ $? -ne 0 ]; then |
| echo -e "\n!!! Unable to sign git tag with given key: $PGP_SIGNING_KEY !!!\n" |
| echo -e "\n!!! Ensure you have created a bind mount of your gitconfig file, for example with -v ~/.gitconfig:/root/.gitconfig !!!\n" |
| exit |
| fi |
| popd &> /dev/null |
| rm -rf $TEST_GIT_DIR |
| |
| if [ ! -d /root/.ssh/ ]; then |
| echo -e "\n!!! SSH keys missing, needed to pull/push github repos !!!\n" |
| echo -e "\n!!! Ensure you have created a bind mount of your ssh directory, for example with -v ~/.ssh/:/root/.ssh/ !!!\n" |
| exit |
| fi |
| |
| echo |
| echo |
| |
| REPO_ROOT=`pwd` |
| |
| echo "Cloning repos..." |
| |
| echo |
| echo git clone -b $DAFFODIL_CODE_BRANCH ssh://git@github.com/$DAFFODIL_CODE_USER/$DAFFODIL_CODE_REPO.git |
| git clone -b $DAFFODIL_CODE_BRANCH ssh://git@github.com/$DAFFODIL_CODE_USER/$DAFFODIL_CODE_REPO.git |
| echo |
| echo git clone ssh://git@github.com/apache/$DAFFODIL_SITE_REPO.git |
| git clone ssh://git@github.com/apache/$DAFFODIL_SITE_REPO.git |
| |
| echo svn checkout https://dist.apache.org/repos/dist/dev/daffodil/$PROJECT_DIST_DIR $DAFFODIL_DIST |
| svn checkout https://dist.apache.org/repos/dist/dev/daffodil/$PROJECT_DIST_DIR $DAFFODIL_DIST |
| |
| pushd $REPO_ROOT/$DAFFODIL_CODE_REPO &> /dev/null |
| |
| case $PROJECT_REPO in |
| "daffodil") |
| VERSION=$(grep 'version :=' build.sbt | cut -d\" -f2) |
| ;; |
| "daffodil-vscode") |
| VERSION=$(grep '"version"' package.json | cut -d\" -f4) |
| ;; |
| esac |
| |
| if [[ $VERSION == *SNAPSHOT* ]]; then |
| echo -e "\n!!! $PROJECT_NAME version ($VERSION) should not contain SNAPSHOT for a release !!!\n"; |
| if [ "$DRY_RUN" = true ]; then |
| echo -e "!!! Ignoring because this is a dry run !!!\n"; |
| else |
| exit |
| fi |
| fi |
| |
| DAFFODIL_CODE_DIR=$REPO_ROOT/$DAFFODIL_CODE_REPO |
| DAFFODIL_SITE_DIR=$REPO_ROOT/$DAFFODIL_SITE_REPO |
| DAFFODIL_DOCS_DIR=$DAFFODIL_SITE_DIR/site/docs/$VERSION |
| DAFFODIL_TUTORIALS_DIR=$DAFFODIL_SITE_DIR/site/tutorials |
| DAFFODIL_DIST_DIR=$REPO_ROOT/$DAFFODIL_DIST |
| DAFFODIL_RELEASE_DIR=$DAFFODIL_DIST_DIR/$VERSION-$PRE_RELEASE |
| |
| if [ -d "$DAFFODIL_RELEASE_DIR" ]; then echo -e "\n!!! $PROJECT_NAME release directory already exists: $DAFFODIL_RELEASE_DIR !!! "; exit; fi |
| |
| git -C $DAFFODIL_CODE_DIR config --local user.name "$GIT_COMMIT_NAME" |
| git -C $DAFFODIL_CODE_DIR config --local user.email "$GIT_COMMIT_EMAIL" |
| git -C $DAFFODIL_SITE_DIR config --local user.name "$GIT_COMMIT_NAME" |
| git -C $DAFFODIL_SITE_DIR config --local user.email "$GIT_COMMIT_EMAIL" |
| |
| echo |
| echo "!!! Creating $PROJECT_NAME $VERSION-$PRE_RELEASE in $DAFFODIL_RELEASE_DIR !!!" |
| echo |
| |
| echo "Removing old release candidates..." |
| find $DAFFODIL_DIST_DIR -maxdepth 1 -name $VERSION-\* -exec svn delete --force {} \; |
| |
| echo "Installing Source..." |
| mkdir -p $DAFFODIL_RELEASE_DIR/src/ |
| git archive --format=zip --prefix=apache-$PROJECT_REPO-$VERSION-src/ HEAD > $DAFFODIL_RELEASE_DIR/src/apache-$PROJECT_REPO-$VERSION-src.zip |
| |
| case $PROJECT_REPO in |
| "daffodil") |
| if [ "$DRY_RUN" = true ]; then |
| SBT_PUBLISH="publishLocalSigned" |
| else |
| SBT_PUBLISH="publishSigned" |
| fi |
| |
| echo "Building Convenience Binaries and Publishing to Apache Repository..." |
| sbt \ |
| "set ThisBuild/updateOptions := updateOptions.value.withGigahorse(false)" \ |
| "set ThisBuild/credentials += Credentials(\"Sonatype Nexus Repository Manager\", \"repository.apache.org\", \"$APACHE_USERNAME\", \"$APACHE_PASSWD\")" \ |
| "set ThisBuild/publishTo := Some(\"Apache Staging Distribution Repository\" at \"https://repository.apache.org/service/local/staging/deploy/maven2\")" \ |
| "set pgpSigningKey := Some(\"$PGP_SIGNING_KEY_ID\")" \ |
| "+compile" \ |
| "+$SBT_PUBLISH" \ |
| "daffodil-cli/Rpm/packageBin" \ |
| "daffodil-cli/Windows/packageBin" \ |
| "daffodil-cli/Universal/packageBin" \ |
| "daffodil-cli/Universal/packageZipTarball" \ |
| "unidoc" \ |
| |
| echo "Installing Convenience Binaries..." |
| mkdir -p $DAFFODIL_RELEASE_DIR/bin/ |
| cp daffodil-cli/target/universal/apache-daffodil-*.tgz $DAFFODIL_RELEASE_DIR/bin/ |
| cp daffodil-cli/target/universal/apache-daffodil-*.zip $DAFFODIL_RELEASE_DIR/bin/ |
| cp daffodil-cli/target/rpm/RPMS/noarch/apache-daffodil-*.rpm $DAFFODIL_RELEASE_DIR/bin/ |
| MSI_NAME=$(basename $DAFFODIL_RELEASE_DIR/bin/*.zip .zip).msi |
| cp daffodil-cli/target/windows/Daffodil.msi $DAFFODIL_RELEASE_DIR/bin/$MSI_NAME |
| chmod -x $DAFFODIL_RELEASE_DIR/bin/$MSI_NAME |
| |
| echo "Embedding RPM Signature..." |
| rpmsign --define "_gpg_name $PGP_SIGNING_KEY_ID" --define "_binary_filedigest_algorithm 10" --addsign $DAFFODIL_RELEASE_DIR/bin/*.rpm |
| |
| echo "Installing Site Docs..." |
| rm -rf $DAFFODIL_DOCS_DIR |
| mkdir -p $DAFFODIL_DOCS_DIR/{javadoc,scaladoc}/ |
| cp -R target/javaunidoc/* $DAFFODIL_DOCS_DIR/javadoc/ |
| cp -R target/scala-2.12/unidoc/* $DAFFODIL_DOCS_DIR/scaladoc/ |
| |
| echo "Installing Site Tutorials..." |
| rm -rf $DAFFODIL_TUTORIALS_DIR |
| mkdir -p $DAFFODIL_TUTORIALS_DIR |
| cp -R tutorials/src/main/resources/* $DAFFODIL_TUTORIALS_DIR |
| |
| ;; |
| |
| "daffodil-vscode") |
| |
| echo "Building Convenience Binaries..." |
| mkdir -p $DAFFODIL_RELEASE_DIR/bin/ |
| yarn package |
| cp *.vsix $DAFFODIL_RELEASE_DIR/bin/ |
| |
| ;; |
| |
| esac |
| |
| echo "Calculating Checksums..." |
| for i in src/ bin/ |
| do |
| pushd $DAFFODIL_RELEASE_DIR/$i > /dev/null |
| for file in * |
| do |
| sha512sum --binary $file > $file.sha512 |
| gpg --default-key $PGP_SIGNING_KEY_ID --detach-sign --armor --output $file.asc $file |
| done |
| popd &> /dev/null |
| done |
| |
| echo "Creating Git Tag..." |
| git tag -as -u $PGP_SIGNING_KEY_ID -m "Release v$VERSION-$PRE_RELEASE" v$VERSION-$PRE_RELEASE |
| |
| popd &> /dev/null |
| |
| pushd $DAFFODIL_SITE_DIR &> /dev/null |
| echo "Committing Site Changes..." |
| git add . |
| git diff-index --quiet HEAD || git commit -m "Stage release v$VERSION-$PRE_RELEASE" |
| popd &> /dev/null |
| |
| echo "Adding Release Files..." |
| svn add $DAFFODIL_RELEASE_DIR |
| |
| echo |
| echo |
| echo |
| echo |
| echo "!!! Success: $PROJECT_NAME $VERSION-$PRE_RELEASE output to $DAFFODIL_RELEASE_DIR !!!" |
| echo |
| echo "Things to verify: " |
| echo |
| echo "- Files in $DAFFODIL_DIST_DIR" |
| echo "- Git tag created in $DAFFODIL_CODE_DIR for $PROJECT_REPO v$VERSION-$PRE_RELEASE" |
| if [ "$PROJECT_REPO" = "daffodil" ] |
| then |
| echo "- Files in $DAFFODIL_DOCS_DIR" |
| echo "- Files in $DAFFODIL_TUTORIALS_DIR" |
| echo "- Staged published files at https://repository.apache.org/" |
| fi |
| echo |
| |
| if [ "$DRY_RUN" = true ]; then |
| echo "!!! This was a dry run. Do not push/publish any changes !!!" |
| echo |
| echo "Type 'exit' when done with the container" |
| else |
| |
| cat << EOF > /root/complete-release |
| #!/bin/bash |
| set -x |
| cd $DAFFODIL_DIST_DIR && svn ci --username $APACHE_USERNAME -m 'Staging Apache $PROJECT_NAME $VERSION-$PRE_RELEASE' |
| cd $DAFFODIL_CODE_DIR && git push origin v$VERSION-$PRE_RELEASE |
| cd $DAFFODIL_SITE_DIR && git push origin main |
| EOF |
| chmod +x /root/complete-release |
| |
| echo "If everything looks correct, do the following:" |
| echo |
| echo "- Run: /root/complete-release" |
| echo "- Close the staged files at https://repository.apache.org" |
| echo "- Type 'exit' and start a VOTE!" |
| echo |
| echo "If anything looks incorrect, do the following:" |
| echo |
| echo "- Drop the staged files at https://repository.apache.org" |
| echo "- Type 'exit', fix the issues, and start over" |
| echo |
| fi |
| |
| echo |
| |
| gpgconf --kill gpg-agent |
| |
| bash |