blob: 82f44cadbc5ff3e06cff07a4a0d9a6b9e1f1f9ee [file] [log] [blame]
#!/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