This is an automated email from the ASF dual-hosted git repository. dlmarion pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/accumulo-access.git
The following commit(s) were added to refs/heads/main by this push: new f315807 Added description to pom, added initial release candidate script (#39) f315807 is described below commit f315807509b26a1e1f46cb428d56d285853f805a Author: Dave Marion <dlmar...@apache.org> AuthorDate: Mon Feb 12 08:49:49 2024 -0500 Added description to pom, added initial release candidate script (#39) --- pom.xml | 3 + src/build/create-release-candidate.sh | 440 ++++++++++++++++++++++++++++++++++ 2 files changed, 443 insertions(+) diff --git a/pom.xml b/pom.xml index d455c3e..0836585 100644 --- a/pom.xml +++ b/pom.xml @@ -30,6 +30,9 @@ <artifactId>accumulo-access</artifactId> <version>1.0.0-SNAPSHOT</version> <name>Apache Accumulo Access Project</name> + <description>Apache Accumulo Access is a library that provides the same functionality, semantics, and syntax + as the Apache Accumulo ColumnVisibility and VisibilityEvaluator classes. This functionality is provided in a + standalong Java library that has no runtime dependencies.</description> <url>https://accumulo.apache.org</url> <organization> <name>The Apache Software Foundation</name> diff --git a/src/build/create-release-candidate.sh b/src/build/create-release-candidate.sh new file mode 100755 index 0000000..6fb94ad --- /dev/null +++ b/src/build/create-release-candidate.sh @@ -0,0 +1,440 @@ +#! /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 +# +# https://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. +# + +cd "$(dirname "$0")/.." || exit 1 +scriptname=$(basename "$0") +projectroot="$(git rev-parse --show-toplevel)" || exit 1 +cd "$projectroot" || exit 1 +export tlpName=accumulo +export projName="${tlpName}-access" +export projNameLong="Apache ${projName^}" +export stagingRepoPrefix="https://repository.apache.org/content/repositories/orgapache$tlpName" +export srcQualifier="src" +export relTestingUrl="https://$tlpName.apache.org/contributor/verifying-release" +export tagPrefix="rel/" + +# check if running in a color terminal +terminalSupportsColor() { + local c + c=$(tput colors 2>/dev/null) || c=-1 + [[ -t 1 ]] && [[ $c -ge 8 ]] +} +terminalSupportsColor && doColor=1 || doColor=0 + +color() { + local c + c=$1 + shift + [[ $doColor -eq 1 ]] && echo -e "\\e[0;${c}m${*}\\e[0m" || echo "$@" +} +red() { color 31 "$@"; } +green() { color 32 "$@"; } +yellow() { color 33 "$@"; } + +fail() { + echo -e ' ' "$@" + exit 1 +} +runLog() { + local o + o=$1 && shift && echo "$(green Running) $(yellow "$@" '>>' "$o")" && echo Running "$*" >>"$o" && "$@" >>"$o" +} +run() { echo "$(green Running) $(yellow "$@")" && "$@"; } + +currentBranch() { + local b + b=$(git symbolic-ref -q HEAD) && echo "${b##refs/heads/}" +} + +cacheGPG() { + # make sure gpg agent has key cached + # first clear cache, to reset timeouts (best attempt) + { hash gpg-connect-agent && gpg-connect-agent reloadagent /bye; } &>/dev/null + # determine fingerprint to use + until selectFingerprint; do + red 'ERROR - Invalid selection' + done + local TESTFILE + TESTFILE=$(mktemp --tmpdir "${USER}-gpgTestFile-XXXXXXXX.txt") + [[ -r $TESTFILE ]] && gpg --local-user "$SELECTED_FINGERPRINT" --sign "$TESTFILE" && rm -f "$TESTFILE" "$TESTFILE.gpg" +} + +prompter() { + # $1 description; $2 pattern to validate against + local x + read -r -p "Enter the $1: " x + until eval "[[ \$x =~ ^$2\$ ]]"; do + echo " $(red "$x") is not a proper $1" 1>&2 + read -r -p "Enter the $1: " x + done + echo "$x" +} + +pretty() { + local f + f=$1 + shift + git log "--pretty=tformat:$f" "$@" +} +gitCommits() { pretty %H "$@"; } +gitCommit() { gitCommits -n1 "$@"; } +gitSubject() { pretty %s "$@"; } + +selectFingerprint() { + local f fingerprints=() + if [[ $SELECTED_FINGERPRINT =~ ^[0-9a-fA-F]{40}$ ]]; then + # it's already set, don't set it again + return 0 + fi + mapfile -t fingerprints < <(gpg --list-secret-keys --with-colons --with-fingerprint 2>/dev/null | awk -F: '$1 == "fpr" {print $10}') + fingerprints+=('Other') + echo + echo "Select the $(green gpg) key to use:" + COLUMNS=1 + select f in "${fingerprints[@]}"; do + if [[ -z $f ]]; then + return 1 + elif [[ $f == 'Other' ]]; then + SELECTED_FINGERPRINT=$(prompter "$(green gpg) key's $(green fingerprint)" '[0-9a-fA-F]{40}') + return 0 + else + SELECTED_FINGERPRINT="$f" + return 0 + fi + done +} + +createEmail() { + echo + yellow "IMPORTANT!! IMPORTANT!! IMPORTANT!! IMPORTANT!! IMPORTANT!! IMPORTANT!!" + echo + echo " Release candidate will be staged at:" + echo " $(yellow 'https://repository.apache.org/#stagingRepositories')" + echo + echo " $(green 'DO') click $(green 'Close') to complete the staging process!" + echo " $(red 'DO *NOT*') click $(red 'Release') until after the vote has been approved!" + echo + yellow "IMPORTANT!! IMPORTANT!! IMPORTANT!! IMPORTANT!! IMPORTANT!! IMPORTANT!!" + echo + # $1 version (optional); $2 rc sequence num (optional); $3 staging repo num (optional) + local ver + [[ -n $1 ]] && ver=$1 || ver=$(prompter 'version to be released (eg. x.y.z)' '[0-9]+[.][0-9]+[.][0-9]+') + local rc + [[ -n $2 ]] && rc=$2 || rc=$(prompter 'release candidate sequence number (eg. 1, 2, etc.)' '[0-9]+') + local stagingrepo + [[ -n $3 ]] && stagingrepo=$3 || stagingrepo=$(prompter 'staging repository number from https://repository.apache.org/#stagingRepositories' '[0-9]+') + local srcSha + [[ -n $4 ]] && srcSha=$4 || srcSha=$(prompter 'SHA512 for source tarball' '[0-9a-f]{128}') + local binSha + [[ -n $5 ]] && binSha=$5 || binSha=$(prompter 'SHA512 for binary tarball' '[0-9a-f]{128}') + + local branch + branch=$ver-rc$rc + local commit + commit=$(gitCommit "$branch") || exit 1 + local tag + tag=$tagPrefix$ver + echo + yellow "IMPORTANT!! IMPORTANT!! IMPORTANT!! IMPORTANT!! IMPORTANT!! IMPORTANT!!" + echo + echo " Don't forget to make the staged branch available for review by" + echo " pushing a branch named $(yellow "$branch") with its head at" + echo " $(yellow "$commit"):" + echo + echo " # replace $(yellow 'ORIGIN') with your upstream remote name " + echo " $(green "git push") $(yellow 'ORIGIN') $(green "$commit:refs/heads/$branch")" + echo + echo " Remember, $(red DO NOT PUSH) the $(red "$tag") tag until after the vote" + echo " passes and the tag is re-made with a gpg signature using:" + echo " $(red "git tag -f -s -m '$projNameLong $ver' $tag") \\" + echo " $(red "$commit")" + echo + yellow "IMPORTANT!! IMPORTANT!! IMPORTANT!! IMPORTANT!! IMPORTANT!! IMPORTANT!!" + echo + read -r -s -p 'Press Enter to generate the [VOTE] email...' + echo 1>&2 + + # determine fingerprint to use + until selectFingerprint; do + red 'ERROR - Invalid selection' + done + + # compute the date with a buffer of 30 minutes + local votedate + votedate=$(date -d "+3 days 30 minutes" "+%s") + # round back to the previous half-hour + local halfhour + halfhour=$((votedate - (votedate % 1800))) + votedate=$(date -u -d"1970-01-01 $halfhour seconds UTC") + export TZ="America/New_York" + local edtvotedate + edtvotedate=$(date -d"1970-01-01 $halfhour seconds UTC") + export TZ="America/Los_Angeles" + local pdtvotedate + pdtvotedate=$(date -d"1970-01-01 $halfhour seconds UTC") + + cat <<EOF +$(yellow '============================================================') +Subject: $(green [VOTE] "$projNameLong $branch") +$(yellow '============================================================') +${tlpName^} Developers, + +Please consider the following candidate for $projNameLong $(green "$ver"). + +Git Commit: + $(green "$commit") +Branch: + $(green "$branch") + +If this vote passes, a gpg-signed tag will be created using: + $(green "git tag -f -s -m '$projNameLong $ver' $tag") \\ + $(green "$commit") + +Staging repo: $(green "$stagingRepoPrefix-$stagingrepo") +Source (official release artifact): $(green "$stagingRepoPrefix-$stagingrepo/org/apache/$tlpName/$projName/$ver/$projName-$ver-$srcQualifier.tar.gz") + +Append ".asc" to download the cryptographic signature for a given artifact. +(You can also append ".sha1" or ".md5" instead in order to verify the checksums +generated by Maven to verify the integrity of the Nexus repository staging area.) + +Signing keys are available at https://www.apache.org/dist/$tlpName/KEYS +(Expected fingerprint: $(green "$SELECTED_FINGERPRINT")) + +In addition to the tarballs and their signatures, the following checksum +files will be added to the dist/release SVN area after release: +$(yellow "$projName-$ver-$srcQualifier.tar.gz.sha512") will contain: +SHA512 ($(green "$projName-$ver-$srcQualifier.tar.gz")) = $(yellow "$srcSha") + +Release notes (in progress) can be found at: $(green "https://$tlpName.apache.org/release/$projName-$ver") + +Release testing instructions: $relTestingUrl + +Please vote one of: +[ ] +1 - I have verified and accept... +[ ] +0 - I have reservations, but not strong enough to vote against... +[ ] -1 - Because..., I do not accept... +... these artifacts as the $(green "$ver") release of $projNameLong. + +This vote will remain open until at least $(green "$votedate"). +($(green "$edtvotedate") / $(green "$pdtvotedate")) +Voting can continue after this deadline until the release manager +sends an email ending the vote. + +Thanks! + +P.S. Hint: download the whole staging repo with + wget -erobots=off -r -l inf -np -nH \\ + $(green "$stagingRepoPrefix-$stagingrepo/") + # note the trailing slash is needed +$(yellow '============================================================') +EOF +} + +cleanUpAndFail() { + # $1 command; $2 log; $3 original branch; $4 next branch + echo " Failure in $(red "$1")!" + echo " Check output in $(yellow "$2")" + echo " Initiating clean up steps..." + + run git checkout "$3" + + # pre-populate branches with expected next branch; de-duplicate later + local branches + branches=("$4") + local tags + tags=() + local x + local y + for x in $(gitCommits "${cBranch}..${nBranch}"); do + for y in $(git branch --contains "$x" | cut -c3-); do + branches=("${branches[@]}" "$y") + done + for y in $(git tag --contains "$x"); do + tags=("${tags[@]}" "$y") + done + done + + # de-duplicate branches + local a + local tmpArray + tmpArray=("${branches[@]}") + IFS=$'\n' read -d '' -r -a branches < <(printf '%s\n' "${tmpArray[@]}" | sort -u) + for x in "${branches[@]}"; do + echo "Do you wish to clean up (delete) the branch $(yellow "$x")?" + a=$(prompter "letter 'y' or 'n'" '[yn]') + [[ $a == 'y' ]] && git branch -D "$x" + done + for x in "${tags[@]}"; do + echo "Do you wish to clean up (delete) the tag $(yellow "$x")?" + a=$(prompter "letter 'y' or 'n'" '[yn]') + [[ $a == 'y' ]] && git tag -d "$x" + done + exit 1 +} + +selectRemote() { + local r remotes=() + for r in $(git remote); do + remotes+=("$r ($(git config "remote.$r.url"))") + done + remotes+=('Skip') + echo "Select a $(green remote) (you will be prompted again before pushing):" + COLUMNS=1 + select r in "${remotes[@]}"; do + if [[ -z $r ]]; then + return 1 + elif [[ $r == 'Skip' ]]; then + SELECTED_REMOTE=$r + return 0 + else + SELECTED_REMOTE="${r%% *}" + SELECTED_REMOTE_URL=$(git config "remote.${SELECTED_REMOTE}.url") + return 0 + fi + done +} + +createReleaseCandidate() { + echo + yellow "WARNING!! WARNING!! WARNING!! WARNING!! WARNING!! WARNING!!" + echo + echo " Don't forget to $(yellow 'Set up your development environment')!" + echo " For details, see the section by that name at:" + echo " $(green 'https://infra.apache.org/publishing-maven-artifacts.html')" + echo + echo " This will modify your local git repository by creating" + echo " branches and tags. Afterwards, you may need to perform" + echo " some manual steps to complete the release or to rollback" + echo " in the case of failure." + echo + echo " Release candidate will be staged at:" + echo " $(yellow 'https://repository.apache.org/#stagingRepositories')" + echo + yellow "WARNING!! WARNING!! WARNING!! WARNING!! WARNING!! WARNING!!" + echo + + if [[ ${#@} -ne 0 ]]; then + red "CAUTION!! Unrecognized arguments!!" + fail "You added '$*'" + fi + + local ver + ver=$(xmllint --shell pom.xml <<<'xpath /*[local-name()="project"]/*[local-name()="version"]/text()' | grep content= | cut -f2 -d=) + ver=${ver%%-SNAPSHOT} + echo "Building release candidate for version: $(green "$ver")" + local tag + tag=$tagPrefix$ver + + local cBranch + cBranch=$(currentBranch) || fail "$(red Failure)" to get current branch from git + local rc + rc=$(prompter 'release candidate sequence number (eg. 1, 2, etc.)' '[0-9]+') + local tmpNextVer + tmpNextVer="${ver%.*}.$((${ver##*.} + 1))" + local nextVer + nextVer=$(prompter "next snapshot version to be released [$tmpNextVer]" '([0-9]+[.][0-9]+[.][0-9]+)?') + [[ -n $nextVer ]] || nextVer=$tmpNextVer + local rcBranch + rcBranch=$ver-rc$rc + local nBranch + nBranch=$rcBranch-next + + cacheGPG || fail "Unable to cache GPG credentials into gpg-agent" + + # create working branch + run git checkout -b "$nBranch" "$cBranch" || + fail "Unable to create working branch $(red "$nBranch") from $(red "$cBranch")!" + + # create a release candidate from a branch + local oFile + oFile=$(mktemp --tmpdir "$projName-build-$rcBranch-XXXXXXXX.log") + { + [[ -w $oFile ]] && runLog "$oFile" mvn clean release:clean + } || cleanUpAndFail 'mvn clean release:clean' "$oFile" "$cBranch" "$nBranch" + runLog "$oFile" mvn -B release:prepare -DdevelopmentVersion="${nextVer}-SNAPSHOT" "-Dgpg.keyname=$SELECTED_FINGERPRINT" || + cleanUpAndFail "mvn -B release:prepare -DdevelopmentVersion=${nextVer}-SNAPSHOT" "$oFile" "$cBranch" "$nBranch" + runLog "$oFile" mvn release:perform "-Dgpg.keyname=$SELECTED_FINGERPRINT" || + cleanUpAndFail "mvn release:perform" "$oFile" "$cBranch" "$nBranch" + + # switch back to original branch + run git checkout "${cBranch}" + + # verify the next branch contains both expected log messages and no more + { + [[ $(gitCommits "${cBranch}..${nBranch}" | wc -l) -eq 2 ]] && + [[ $(gitCommit "${nBranch}~2") == $(gitCommit "${cBranch}") ]] && + [[ $(gitSubject "${nBranch}") =~ ^\[maven-release-plugin\]\ prepare\ for\ next ]] && + [[ $(gitSubject "${nBranch}~1") =~ ^\[maven-release-plugin\]\ prepare\ release\ rel[/] ]] + } || cleanUpAndFail "verifying that $nBranch contains only logs from release plugin" + + # verify the tag is one behind $nBranch and one ahead of $cBranch + [[ $(gitCommit "${nBranch}~1") == $(gitCommit "refs/tags/$tag") ]] || + cleanUpAndFail "verifying that ${nBranch}~1 == refs/tags/$tag" + + # remove tag which was created + run git tag -d "$tag" || + cleanUpAndFail "removing unused git tag $tag" + + # create release candidate branch to vote on + run git branch "$rcBranch" "${nBranch}~1" || + cleanUpAndFail "creating branch $rcBranch" + + # determine remote to use + until selectRemote; do + red 'ERROR - Invalid selection' + done + + # push branches (ask first) + if [[ $SELECTED_REMOTE == 'Skip' ]]; then + red "Did not push branches; you'll need to perform this step manually." + else + echo "Do you wish to push the following branches to $SELECTED_REMOTE ($(green "$SELECTED_REMOTE_URL"))?" + echo " $(yellow "$rcBranch") (for others to examine for the vote)" + echo " $(yellow "$nBranch") (for merging into $cBranch if vote passes)" + local a + a=$(prompter "letter 'y' or 'n'" '[yn]') + { + [[ $a == 'y' ]] && + run git push -u "$SELECTED_REMOTE" "refs/heads/$nBranch" "refs/heads/$rcBranch" + } || red "Did not push branches; you'll need to perform this step manually." + fi + + local numSrc + numSrc=$(find target/checkout/ -type f -name "$projName-$ver-source-release.tar.gz" | wc -l) + shopt -s globstar + local srcSha + srcSha="" + [[ $numSrc == "1" ]] && srcSha=$(sha512sum target/checkout/**/"$projName-$ver-source-release.tar.gz" | cut -f1 -d" ") + + # continue to creating email notification + echo "$(red Running)" "$(yellow "$scriptname" --email "$ver" "$rc")" + createEmail "$ver" "$rc" "" "$srcSha" "$binSha" +} + +SELECTED_FINGERPRINT="" +if [[ $1 == '--create' ]]; then + shift + createReleaseCandidate "$@" +elif [[ $1 == '--email' ]]; then + shift + createEmail "$@" +else + fail "Missing one of: $(red --create), $(red --email)" +fi