This is an automated email from the ASF dual-hosted git repository.

francischuang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite-avatica-go.git


The following commit(s) were added to refs/heads/master by this push:
     new 3fd5360  [CALCITE-3032] Improve release script
3fd5360 is described below

commit 3fd53603b57f36a4f5208f449dec71c236722a00
Author: Francis Chuang <[email protected]>
AuthorDate: Fri Apr 26 15:43:22 2019 +1000

    [CALCITE-3032] Improve release script
---
 Dockerfile                 |  23 --
 docker-compose.yml         |  83 +++++-
 docker.sh                  | 643 +++++++++++++++++++++++++++++++++++++++++++++
 entrypoint.sh              |  24 --
 gen-protobuf.bat           |  37 ---
 gen-protobuf.sh            |  42 ---
 make-release-artifacts.sh  | 187 -------------
 site/develop/avatica-go.md |  99 +++++--
 8 files changed, 796 insertions(+), 342 deletions(-)

diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index d1645d7..0000000
--- a/Dockerfile
+++ /dev/null
@@ -1,23 +0,0 @@
-# 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.
-
-FROM golang:1.12-alpine as base
-
-ENV DEV ""
-
-RUN apk --no-cache --no-progress add build-base git
-RUN go get github.com/unchartedsoftware/witch
-WORKDIR /source
-ENTRYPOINT ["sh", "./entrypoint.sh"]
diff --git a/docker-compose.yml b/docker-compose.yml
index bb3889b..91a89f1 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -15,17 +15,84 @@
 
 version: '3'
 services:
-  calcite-avatica-go:
-    build: .
+  phoenix:
+    image: boostport/hbase-phoenix-all-in-one:2.0-5.0
+
+  hsqldb:
+    image: apache/calcite-avatica-hypersql:1.13.0
+    command: -u jdbc:hsqldb:mem:public
+
+  test:
+    image: golang:1.12-alpine
+    command: sh -c "apk --no-cache --no-progress add build-base git; export 
AVATICA_FLAVOR=HSQLDB && go test -v ./...; export AVATICA_FLAVOR=PHOENIX && go 
test -v ./..."
+    working_dir: /source
     environment:
       PHOENIX_HOST: http://phoenix:8765
       HSQLDB_HOST: http://hsqldb:8765
-      DEV: ${DEV}
     volumes:
       - .:/source
       - $GOPATH/pkg/mod/cache:/go/pkg/mod/cache
-  phoenix:
-    image: boostport/hbase-phoenix-all-in-one:2.0-5.0
-  hsqldb:
-    image: apache/calcite-avatica-hypersql:1.13.0
-    command: -u jdbc:hsqldb:mem:public
\ No newline at end of file
+    depends_on:
+      - phoenix
+      - hsqldb
+
+  dev:
+    image: golang:1.12-alpine
+    command: sh -c "apk --no-cache --no-progress add build-base git; go get 
github.com/unchartedsoftware/witch; cd /source; witch --cmd=\"export 
AVATICA_FLAVOR=HSQLDB && go test -v ./...; export AVATICA_FLAVOR=PHOENIX && go 
test -v ./...\" --watch=\"*.mod,**/*.go\""
+    environment:
+      PHOENIX_HOST: http://phoenix:8765
+      HSQLDB_HOST: http://hsqldb:8765
+    volumes:
+      - .:/source
+      - $GOPATH/pkg/mod/cache:/go/pkg/mod/cache
+    depends_on:
+      - phoenix
+      - hsqldb
+
+  dry-run:
+    image: alpine
+    working_dir: /source
+    command: sh -c "apk --no-cache --no-progress add bash; ./docker.sh dry-run"
+    volumes:
+      - .:/source
+      - $GOPATH/pkg/mod/cache:/go/pkg/mod/cache
+
+  release:
+    image: alpine
+    working_dir: /source
+    command: sh -c "apk --no-cache --no-progress add bash; ./docker.sh release"
+    volumes:
+      - .:/source
+      - $GOPATH/pkg/mod/cache:/go/pkg/mod/cache
+
+  clean:
+    image: alpine
+    working_dir: /source
+    command: sh -c "apk --no-cache --no-progress add bash; ./docker.sh clean"
+    volumes:
+      - .:/source
+
+  publish-release-for-voting:
+    image: alpine
+    working_dir: /source
+    command: sh -c "apk --no-cache --no-progress add bash; ./docker.sh 
publish-release-for-voting"
+    volumes:
+      - .:/source
+
+  promote-release:
+    image: alpine
+    working_dir: /source
+    command: sh -c "apk --no-cache --no-progress add bash; ./docker.sh 
promote-release"
+    volumes:
+      - .:/source
+
+  compile-protobuf:
+    image: golang:1.12-alpine
+    working_dir: /source
+    command: sh -c "apk --no-cache --no-progress add bash; ./docker.sh 
compile-protobuf"
+    environment:
+      AVATICA_VERSION: 1.13.0
+      PROTOBUF_VERSION: 3.7.1
+    volumes:
+      - .:/source
+      - $GOPATH/pkg/mod/cache:/go/pkg/mod/cache
\ No newline at end of file
diff --git a/docker.sh b/docker.sh
new file mode 100755
index 0000000..996ba55
--- /dev/null
+++ b/docker.sh
@@ -0,0 +1,643 @@
+#!/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
+
+GITBOX_URL=https://gitbox.apache.org/repos/asf/calcite-avatica-go.git
+PRODUCT=apache-calcite-avatica-go
+
+function terminate() {
+    printf "\n\nUser terminated build. Exiting...\n"
+    exit 1
+}
+
+trap terminate SIGINT
+
+init_release(){
+    apk --no-cache add git gnupg tar
+}
+
+init_upload(){
+    apk --no-cache add git subversion
+}
+
+KEYS=()
+
+GPG_COMMAND="gpg"
+
+get_gpg_keys (){
+    GPG_KEYS=$($GPG_COMMAND --list-keys --with-colons --keyid-format LONG)
+
+    KEY_NUM=1
+
+    KEY_DETAILS=""
+
+    while read -r line; do
+
+        IFS=':' read -ra PART <<< "$line"
+
+        if [ ${PART[0]} == "pub" ]; then
+
+            if [ -n "$KEY_DETAILS" ]; then
+                KEYS[$KEY_NUM]=$KEY_DETAILS
+                KEY_DETAILS=""
+                ((KEY_NUM++))
+
+            fi
+
+            KEY_DETAILS=${PART[4]}
+        fi
+
+        if [ ${PART[0]} == "uid" ]; then
+            KEY_DETAILS="$KEY_DETAILS - ${PART[9]}"
+        fi
+
+    done <<< "$GPG_KEYS"
+
+    if [ -n "$KEY_DETAILS" ]; then
+        KEYS[$KEY_NUM]=$KEY_DETAILS
+    fi
+}
+
+mount_gpg_keys(){
+    mkdir -p /.gnupg
+
+    if [[ -z "$(ls -A /.gnupg)" ]]; then
+        echo "Please mount the contents of your .gnupg folder into /.gnupg. 
Exiting..."
+        exit 1
+    fi
+
+    mkdir -p /root/.gnupg
+
+    cp -r /.gnupg/ /root/
+
+    chmod -R 700 /root/.gnupg/
+
+    rm -rf /root/.gnupg/*.lock
+}
+
+SELECTED_GPG_KEY=""
+
+select_gpg_key(){
+
+    get_gpg_keys
+
+    export GPG_TTY=/dev/console
+
+    touch /root/.gnupg/gpg-agent.conf
+    echo 'default-cache-ttl 10000' >> /root/.gnupg/gpg-agent.conf
+    echo 'max-cache-ttl 10000' >> /root/.gnupg/gpg-agent.conf
+
+    echo "Starting GPG agent..."
+    gpg-agent --daemon
+
+    while $INVALID_KEY_SELECTED; do
+
+        if [[ "${#KEYS[@]}" -le 0 ]]; then
+            echo "You do not have any GPG keys available. Exiting..."
+            exit 1
+        fi
+
+        echo "You have the following GPG keys:"
+
+        for i in "${!KEYS[@]}"; do
+                echo "$i) ${KEYS[$i]}"
+        done
+
+        read -p "Select your GPG key for signing: " KEY_INDEX
+
+        SELECTED_GPG_KEY=$(sed 's/ -.*//' <<< ${KEYS[$KEY_INDEX]})
+
+        if [[ -z $SELECTED_GPG_KEY ]]; then
+            echo "Selected key is invalid, please try again."
+            continue
+        fi
+
+        echo "Authenticating your GPG key..."
+
+        echo "test" | $GPG_COMMAND --local-user $SELECTED_GPG_KEY --output 
/dev/null --sign -
+
+        if [[ $? != 0 ]]; then
+            echo "Invalid GPG passphrase or GPG error. Please try again."
+            continue
+        fi
+
+        echo "You have selected the following GPG key to sign the release:"
+        echo "${KEYS[$KEY_INDEX]}"
+
+        INVALID_CONFIRMATION=true
+
+        while $INVALID_CONFIRMATION; do
+            read -p "Is this correct? (y/n) " CONFIRM
+
+            if [[ ($CONFIRM == "Y") || ($CONFIRM == "y") ]]; then
+                INVALID_KEY_SELECTED=false
+                INVALID_CONFIRMATION=false
+            elif [[ ($CONFIRM == "N") || ($CONFIRM == "n") ]]; then
+                INVALID_CONFIRMATION=false
+            fi
+        done
+    done
+}
+
+check_release_guidelines(){
+
+    # Exclude files without the Apache license header
+    for i in $(git ls-files); do
+       case "$i" in
+       # The following are excluded from the license header check
+
+       # License files
+       (LICENSE|NOTICE);;
+
+       # Generated files
+       
(message/common.pb.go|message/requests.pb.go|message/responses.pb.go|Gopkg.lock|Gopkg.toml|go.mod|go.sum);;
+
+       # Binaries
+       (test-fixtures/calcite.png);;
+
+       (*) grep -q "Licensed to the Apache Software Foundation" $i || echo "$i 
has no header";;
+       esac
+    done
+
+    # Check copyright year in NOTICE
+    if ! grep -Fq "Copyright 2012-$(date +%Y)" NOTICE; then
+        echo "Ending copyright year in NOTICE is not $(date +%Y)"
+        exit 1
+    fi
+}
+
+check_if_tag_exists(){
+    # Get new tags from remote
+    git fetch --tags $GITBOX_URL
+
+    for tag in "$@"
+    do
+        # Check to see if a tag with a v in front of it has been released
+        if  git show-ref --tags | egrep -q "refs/tags/v$tag$"; then
+            echo "A release with version $1 was already released. Check that 
the version number entered is correct."
+            exit 1
+        fi
+
+        # Check to see if a tag without a v in front of it has been released 
(3.0.0 and below)
+        if  git show-ref --tags | egrep -q "refs/tags/$tag$"; then
+            echo "A release with version $1 was already released. Check that 
the version number entered is correct."
+            exit 1
+        fi
+    done
+}
+
+check_local_remote_are_even(){
+    REMOTE_COMMIT=$(git ls-remote $GITBOX_URL | head -1 | sed "s/HEAD//")
+    LOCAL_COMMIT=$(git rev-parse master)
+
+    if [[ $REMOTE_COMMIT != $LOCAL_COMMIT ]]; then
+        echo "Master in Apache repository is not even with local master"
+        exit 1
+    fi
+}
+
+
+check_import_paths(){
+    TAG_MAJOR_VERSION=$(echo $1 | sed -e 's/\..*//')
+
+    # Check that go.mod's module path contains the right version
+    if ! grep -Fq "module 
github.com/apache/calcite-avatica-go/$TAG_MAJOR_VERSION" go.mod; then
+        echo "Module declaration in go.mod does not contain the correct 
version. Expected: $TAG_MAJOR_VERSION"
+        exit 1
+    fi
+
+    # Make sure import paths contain the correct version
+    BAD_IMPORT_PATHS=false
+
+    for i in $(git ls-files); do
+
+        if [[ "$i" == "docker.sh" || "$i" =~ \.md$ ]]; then
+            continue
+        fi
+
+        lines=$(grep -F '"github.com/apache/calcite-avatica-go' $i)
+
+        if ! [[ -z "$lines" ]]; then
+            while read -r line; do
+                if ! grep -q 
"github.com/apache/calcite-avatica-go/$TAG_MAJOR_VERSION" <<< "$line" ; then
+                    BAD_IMPORT_PATHS=true
+                    echo "Import for github.com/apache/calcite-avatica-go in 
$i does not have the correct version ($TAG_MAJOR_VERSION) in its path"
+                fi
+            done <<< "$lines"
+        fi
+    done
+
+    if "$BAD_IMPORT_PATHS" == true; then
+        exit 1
+    fi
+}
+
+RELEASE_VERSION=""
+RC_NUMBER=""
+ASF_USERNAME=""
+ASF_PASSWORD=""
+
+set_git_credentials(){
+    echo https://$ASF_USERNAME:[email protected] >> 
/root/.git-credentials
+    git config --global credential.helper 'store --file=/root/.git-credentials'
+}
+
+get_asf_credentials(){
+    while $ASF_CREDS_NOT_CONFIRMED; do
+        read -p "Enter your ASF username: " ASF_USERNAME
+        read -s -p "Enter your ASF password: " ASF_PASSWORD
+        printf "\n"
+        echo "Your ASF Username is:" $ASF_USERNAME
+
+        INVALID_CONFIRMATION=true
+
+        while $INVALID_CONFIRMATION; do
+            read -p "Is this correct? (y/n) " CONFIRM
+
+            if [[ ($CONFIRM == "Y") || ($CONFIRM == "y") ]]; then
+                ASF_CREDS_NOT_CONFIRMED=false
+                INVALID_CONFIRMATION=false
+            elif [[ ($CONFIRM == "N") || ($CONFIRM == "n") ]]; then
+                INVALID_CONFIRMATION=false
+            fi
+        done
+    done
+}
+
+clean_release_directory(){
+    rm -rf dist
+}
+
+make_release_artifacts(){
+
+    CURRENT_BRANCH=$(git branch | grep \* | cut -d ' ' -f2)
+
+    if [ $CURRENT_BRANCH != "master" ]; then
+        echo "You are currently on the $CURRENT_BRANCH branch. A release must 
be made from the master branch. Exiting..."
+        exit 1
+    fi
+
+    check_local_remote_are_even
+
+    check_release_guidelines
+
+    while $NOT_CONFIRMED; do
+        read -p "Enter the version number to be released (example: 4.0.0, do 
not include the rc number): " RELEASE_VERSION
+        read -p "Enter the release candidate number (example: if you are 
releasing rc0, enter 0): " RC_NUMBER
+        echo "Build configured as follows:"
+        echo "Release: $RELEASE_VERSION-rc$RC_NUMBER"
+
+        INVALID_CONFIRMATION=true
+
+        while $INVALID_CONFIRMATION; do
+            read -p "Is this correct? (y/n) " CONFIRM
+
+            if [[ ($CONFIRM == "Y") || ($CONFIRM == "y") ]]; then
+                NOT_CONFIRMED=false
+                INVALID_CONFIRMATION=false
+            elif [[ ($CONFIRM == "N") || ($CONFIRM == "n") ]]; then
+                INVALID_CONFIRMATION=false
+            fi
+        done
+    done
+
+    select_gpg_key
+
+    check_if_tag_exists $RELEASE_VERSION $RELEASE_VERSION-rc$RC_NUMBER
+
+    TAG="v$RELEASE_VERSION-rc$RC_NUMBER"
+
+    check_import_paths $TAG
+
+    clean_release_directory
+
+    TAR_FILE=$PRODUCT-$RELEASE_VERSION-src.tar.gz
+    RELEASE_DIR=dist/$PRODUCT-$RELEASE_VERSION-rc$RC_NUMBER
+
+    #Make release dir
+    mkdir -p $RELEASE_DIR
+
+    # Make tar
+    tar -zcf $RELEASE_DIR/$TAR_FILE --transform 
"s/^/$PRODUCT-$RELEASE_VERSION-src\//g" $(git ls-files)
+
+    cd $RELEASE_DIR
+
+    # Calculate SHA512
+    gpg --print-md SHA512 $TAR_FILE > $TAR_FILE.sha512
+
+    # Sign
+    gpg -u $SELECTED_GPG_KEY --armor --output $TAR_FILE.asc --detach-sig 
$TAR_FILE
+
+    echo "Release artifacts created!"
+}
+
+make_release_artifacts_and_push_tag(){
+    make_release_artifacts
+
+    get_asf_credentials
+
+    # Create the tag
+    git tag $TAG
+
+    # Push the tag
+    set_git_credentials
+
+    git push $GITBOX_URL $TAG
+
+    echo "Release $RELEASE_VERSION-rc$RC_NUMBER has been tagged and pushed!"
+}
+
+publish_release_for_voting(){
+
+    LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`)
+
+    if [[ ! $LATEST_TAG =~ .+-rc[[:digit:]]+$ ]]; then
+        echo "The latest tag ($LATEST_TAG) is not a RC release and should not 
be published for voting."
+        exit 1
+    fi
+
+    TAG_WITHOUT_V=$(echo $LATEST_TAG | sed -e 's/v//')
+    TAG_WITHOUT_RC=$(echo $TAG_WITHOUT_V | sed -e 's/-rc[0-9][0-9]*//')
+    SOURCE_RELEASE=$PRODUCT-$TAG_WITHOUT_RC-src.tar.gz
+    GPG_SIGNATURE=$PRODUCT-$TAG_WITHOUT_RC-src.tar.gz.asc
+    SHA512=$PRODUCT-$TAG_WITHOUT_RC-src.tar.gz.sha512
+    COMMIT=$(git rev-list -n 1 $LATEST_TAG)
+
+    # Check to see a release is built
+    MISSING_FILES=false
+
+    if [ ! -f "dist/$PRODUCT-$TAG_WITHOUT_V/$SOURCE_RELEASE" ]; then
+        echo "Did not find source release ($SOURCE_RELEASE) in dist folder."
+        MISSING_FILES=true
+    fi
+
+    if [ ! -f "dist/$PRODUCT-$TAG_WITHOUT_V/$GPG_SIGNATURE" ]; then
+        echo "Did not find GPG signature ($GPG_SIGNATURE) in dist folder."
+        MISSING_FILES=true
+    fi
+
+    if [ ! -f "dist/$PRODUCT-$TAG_WITHOUT_V/$SHA512" ]; then
+        echo "Did not find SHA512($SHA512) in dist folder."
+        MISSING_FILES=true
+    fi
+
+    if $MISSING_FILES == true; then
+        exit 1
+    fi
+
+    while $NOT_CONFIRMED; do
+        echo "Publish configured as follows:"
+        echo "Release: $TAG_WITHOUT_V"
+
+        INVALID_CONFIRMATION=true
+
+        while $INVALID_CONFIRMATION; do
+            read -p "Is this correct? (y/n) " CONFIRM
+
+            if [[ ($CONFIRM == "Y") || ($CONFIRM == "y") ]]; then
+                NOT_CONFIRMED=false
+                INVALID_CONFIRMATION=false
+            elif [[ ($CONFIRM == "N") || ($CONFIRM == "n") ]]; then
+                INVALID_CONFIRMATION=false
+            fi
+        done
+    done
+
+    HASH_CONTENTS=$(cat "dist/$PRODUCT-$TAG_WITHOUT_V/$SHA512" | tr -d '\n')
+    HASH=${HASH_CONTENTS#"$SOURCE_RELEASE: "}
+
+    get_asf_credentials
+
+    svn checkout https://dist.apache.org/repos/dist/dev/calcite/ /tmp/calcite 
--depth empty
+    cp -R dist/$PRODUCT-$TAG_WITHOUT_V /tmp/calcite/
+
+    cd /tmp/calcite
+    svn add $PRODUCT-$TAG_WITHOUT_V
+    chmod -x $PRODUCT-$TAG_WITHOUT_V/*
+
+    svn commit -m "$PRODUCT-$TAG_WITHOUT_V" --force-log --username 
$ASF_USERNAME --password $ASF_PASSWORD
+
+    [[ $LATEST_TAG =~ -rc([[:digit:]]+)$ ]]
+    RC_NUMBER=${BASH_REMATCH[1]}
+
+    read -p "Please enter your first name for the voting email: " FIRST_NAME
+
+    echo "The release $PRODUCT-$TAG_WITHOUT_V has been uploaded to the 
development repository."
+    printf "\n"
+    printf "\n"
+    echo "Email the following message to [email protected]. Please check 
the message before sending."
+    printf "\n"
+    echo "To: [email protected]"
+    echo "Subject: [VOTE] Release $PRODUCT-$TAG_WITHOUT_V (release candidate 
$RC_NUMBER)"
+    echo "Message:
+Hi all,
+
+I have created a release for Apache Calcite Avatica Go $TAG_WITHOUT_V, release 
candidate $RC_NUMBER.
+
+Thanks to everyone who has contributed to this release. The release notes are 
available here:
+https://github.com/apache/calcite-avatica-go/blob/$COMMIT/site/_docs/go_history.md
+
+The commit to be voted on:
+https://gitbox.apache.org/repos/asf?p=calcite-avatica-go.git;a=commit;h=$COMMIT
+
+The hash is $COMMIT
+
+The artifacts to be voted on are located here:
+https://dist.apache.org/repos/dist/dev/calcite/$PRODUCT-$TAG_WITHOUT_V/
+
+The hashes of the artifacts are as follows:
+src.tar.gz $HASH
+
+Release artifacts are signed with the following key:
+https://people.apache.org/keys/committer/$ASF_USERNAME.asc
+
+Instructions for running the test suite is located here:
+https://github.com/apache/calcite-avatica-go/blob/$COMMIT/site/develop/avatica-go.md#testing
+
+Please vote on releasing this package as Apache Calcite Avatica Go 
$TAG_WITHOUT_RC.
+
+To run the tests without a Go environment, install docker and docker-compose. 
Then, in the root of the release's directory, run:
+docker-compose run test
+
+When the test suite completes, run \"docker-compose down\" to remove and 
shutdown all the containers.
+
+The vote is open for the next 72 hours and passes if a majority of
+at least three +1 PMC votes are cast.
+
+[ ] +1 Release this package as Apache Calcite Avatica Go $TAG_WITHOUT_RC
+[ ]  0 I don't feel strongly about it, but I'm okay with the release
+[ ] -1 Do not release this package because...
+
+
+Here is my vote:
+
++1 (binding)
+
+$FIRST_NAME
+"
+}
+
+promote_release(){
+
+    RELEASE_REPO=https://dist.apache.org/repos/dist/release/calcite/
+    DEV_REPO=https://dist.apache.org/repos/dist/dev/calcite/
+
+    LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`)
+
+    if [[ ! $LATEST_TAG =~ .+-rc[[:digit:]]+$ ]]; then
+        echo "The latest tag ($LATEST_TAG) is not a RC release and should not 
be re-released."
+        exit 1
+    fi
+
+    TAG_WITHOUT_V=$(echo $LATEST_TAG | sed -e 's/v//')
+    TAG_WITHOUT_RC=$(echo $TAG_WITHOUT_V | sed -e 's/-rc[0-9][0-9]*//')
+
+    if ! svn ls $DEV_REPO/$PRODUCT-$TAG_WITHOUT_V; then
+        echo "The release $PRODUCT-$TAG_WITHOUT_V was not found in the dev 
repository. Was it uploaded for voting?"
+        exit 1
+    fi
+
+    get_asf_credentials
+
+    set_git_credentials
+
+    git tag v$TAG_WITHOUT_RC $LATEST_TAG
+
+    git push $GITBOX_URL v$TAG_WITHOUT_RC
+
+    svn checkout $RELEASE_REPO /tmp/release
+    rm -rf /tmp/release/$PRODUCT-$TAG_WITHOUT_RC
+    mkdir -p /tmp/release/$PRODUCT-$TAG_WITHOUT_RC
+
+    svn checkout $DEV_REPO/$PRODUCT-$TAG_WITHOUT_V /tmp/
+    cp -rp /tmp/rc/* /tmp/release/$PRODUCT-$TAG_WITHOUT_RC
+
+    cd /tmp/release
+
+    svn add $PRODUCT-$TAG_WITHOUT_RC
+
+    # If there is more than 1 release, delete all of them, except for the 
newest one
+    # To do this, we do the following:
+    # 1. Get the list of releases with verbose information from svn
+    # 2. Sort by the first field (revision number) in descending order
+    # 3. Select apache-calcite-avatica-go releases
+    # 4. Exclude the release we're trying to promote, in case it was from a 
failed promotion.
+    # 5. Trim all whitespace down to 1 empty space.
+    # 6. Select field 7, which is each release's folder
+    CURRENT_RELEASES=$(svn ls -v $RELEASE_REPO | sort -k1 -r | grep 
apache-calcite-avatica-go | grep -v apache-calcite-avatica-go-$TAG_WITHOUT_RC | 
tr -s ' ' | cut -d ' ' -f 7)
+
+    RELEASE_COUNT=0
+    while read -r RELEASE; do
+        if [[ $RELEASE_COUNT -ne 0 ]]; then
+            svn rm $RELEASE
+            echo "Removing release $RELEASE"
+        fi
+
+        RELEASE_COUNT=$((RELEASE_COUNT+1))
+    done <<< "$CURRENT_RELEASES"
+
+    svn commit -m "Release $PRODUCT-$TAG_WITHOUT_V" --force-log --username 
$ASF_USERNAME --password $ASF_PASSWORD
+
+    echo "Release $PRODUCT-$LATEST_TAG successfully promoted to 
$PRODUCT-$TAG_WITHOUT_RC"
+}
+
+compile_protobuf(){
+
+    if [ -z "$AVATICA_VERSION" ]; then
+        echo "The AVATICA_VERSION environment variable must be set to a valid 
avatica version"
+    fi
+
+    if [ -z "$PROTOBUF_VERSION" ]; then
+        echo "The PROTOBUF_VERSION environment variable must be set to a valid 
protobuf version"
+    fi
+
+    apk --no-cache add ca-certificates git wget
+
+    # Install glibc
+    wget -q -O /etc/apk/keys/sgerrand.rsa.pub 
https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
+    wget -O /tmp/glibc.apk 
https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.29-r0/glibc-2.29-r0.apk
+    apk add /tmp/glibc.apk
+
+
+    # Install go protobuf compiler
+    go install github.com/golang/protobuf/protoc-gen-go
+
+    # Install protoc
+    mkdir -p /tmp/protoc
+    wget -q -O /tmp/protoc/protoc.zip 
https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip
+    cd /tmp/protoc
+    unzip protoc.zip
+    mv /tmp/protoc/include /usr/local/include
+    mv /tmp/protoc/bin/protoc /usr/local/bin/protoc
+
+    # Clone a temp copy of avatica and check out the selected version
+    mkdir /tmp/avatica
+    cd /tmp/avatica
+    git init
+    git remote add origin https://github.com/apache/calcite-avatica.git
+    git config core.sparsecheckout true
+    echo "core/src/main/protobuf/*" >> .git/info/sparse-checkout
+
+    git fetch --depth=1 origin rel/avatica-$AVATICA_VERSION
+    git checkout FETCH_HEAD
+
+    # Compile the protobuf
+    protoc --proto_path=/tmp/avatica/core/src/main/protobuf 
--go_out=import_path=message:/source/message/ 
/tmp/avatica/core/src/main/protobuf/*.proto
+
+    echo "Protobuf compiled successfully"
+}
+
+case $1 in
+    dry-run)
+        init_release
+        mount_gpg_keys
+        make_release_artifacts
+        ;;
+
+    release)
+        init_release
+        mount_gpg_keys
+        make_release_artifacts_and_push_tag
+        ;;
+
+    clean)
+        clean_release_directory
+        echo "Release directory ./dist removed"
+        ;;
+
+    publish-release-for-voting)
+        init_upload
+        publish_release_for_voting
+        ;;
+
+    promote-release)
+        init_upload
+        promote_release
+        ;;
+
+    compile-protobuf)
+        compile_protobuf
+        ;;
+
+    *)
+       echo $"Usage: $0 
{dry-run|release|clean|publish-release-for-voting|promote-release}"
+       ;;
+
+esac
+
+# End
\ No newline at end of file
diff --git a/entrypoint.sh b/entrypoint.sh
deleted file mode 100755
index 0d061fd..0000000
--- a/entrypoint.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/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.
-
-TEST_COMMAND="export AVATICA_FLAVOR=HSQLDB && go test -v ./...; export 
AVATICA_FLAVOR=PHOENIX && go test -v ./..."
-
-if [[ -z "${DEV}" ]]; then
-  sh -c "$TEST_COMMAND"
-else
-  witch --cmd="$TEST_COMMAND" --watch="*.mod,**/*.go"
-fi
\ No newline at end of file
diff --git a/gen-protobuf.bat b/gen-protobuf.bat
deleted file mode 100644
index 8a9eb8c..0000000
--- a/gen-protobuf.bat
+++ /dev/null
@@ -1,37 +0,0 @@
-@ECHO OFF
-rem Licensed to the Apache Software Foundation (ASF) under one or more
-rem contributor license agreements.  See the NOTICE file distributed with
-rem this work for additional information regarding copyright ownership.
-rem The ASF licenses this file to you under the Apache License, Version 2.0
-rem (the "License"); you may not use this file except in compliance with
-rem the License.  You may obtain a copy of the License at
-
-rem http://www.apache.org/licenses/LICENSE-2.0
-
-rem Unless required by applicable law or agreed to in writing, software
-rem distributed under the License is distributed on an "AS IS" BASIS,
-rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-rem See the License for the specific language governing permissions and
-rem limitations under the License.
-
-SET AVATICA_VER=rel/avatica-1.13.0
-
-IF EXIST message\ rmdir /Q /S message
-IF EXIST avatica-tmp\ rmdir /Q /S avatica-tmp
-
-git init avatica-tmp
-cd avatica-tmp
-git remote add origin https://github.com/apache/calcite-avatica/
-git config core.sparsecheckout true
-echo core/src/main/protobuf/* >> .git/info/sparse-checkout
-git fetch --depth=1 origin %AVATICA_VER%
-git checkout FETCH_HEAD
-
-cd ..
-mkdir message
-protoc --proto_path=avatica-tmp/core/src/main/protobuf/ 
--go_out=import_path=message:message avatica-tmp/core/src/main/protobuf/*.proto
-
-rmdir /Q /S avatica-tmp
-
-echo.
-echo Protobufs generated!
diff --git a/gen-protobuf.sh b/gen-protobuf.sh
deleted file mode 100644
index d59a333..0000000
--- a/gen-protobuf.sh
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/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
-#
-# 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
-
-rm -rf message avatica-tmp
-
-export AVATICA_VER="rel/avatica-1.13.0"
-
-mkdir -p avatica-tmp
-pushd avatica-tmp &> /dev/null
-
-git init
-git remote add origin https://github.com/apache/calcite-avatica.git
-git config core.sparsecheckout true
-echo "core/src/main/protobuf/*" >> .git/info/sparse-checkout
-
-git fetch --depth=1 origin $AVATICA_VER
-git checkout FETCH_HEAD
-
-popd &> /dev/null
-
-mkdir -p message
-
-protoc --proto_path=avatica-tmp/core/src/main/protobuf 
--go_out=import_path=message:message avatica-tmp/core/src/main/protobuf/*.proto
-
-rm -rf avatica-tmp
-
-echo -e "\nProtobufs generated!"
diff --git a/make-release-artifacts.sh b/make-release-artifacts.sh
deleted file mode 100755
index 6051880..0000000
--- a/make-release-artifacts.sh
+++ /dev/null
@@ -1,187 +0,0 @@
-#!/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.
-
-# Clean dist directory
-rm -rf dist
-mkdir -p dist
-
-# Get new tags from remote
-git fetch --tags
-
-# Prompt for tag to release (defaults to latest tag)
-echo -n "Enter tag to release (default: latest tag): "
-read tag
-
-if [[ -z $tag ]]; then
-    tag=$(git describe --tags `git rev-list --tags --max-count=1`)
-    echo "No tag provided. Using the latest tag: $tag"
-fi
-
-# Exclude files without the Apache license header
-for i in $(git ls-files); do
-   case "$i" in
-   # The following are excluded from the license header check
-
-   # License files
-   (LICENSE|NOTICE);;
-
-   # Generated files
-   
(message/common.pb.go|message/requests.pb.go|message/responses.pb.go|Gopkg.lock|Gopkg.toml|go.mod|go.sum);;
-
-   # Binaries
-   (test-fixtures/calcite.png);;
-
-   (*) grep -q "Licensed to the Apache Software Foundation" $i || echo "$i has 
no header";;
-   esac
-done
-
-# Check copyright year in NOTICE
-if ! grep -Fq "Copyright 2012-$(date +%Y)" NOTICE; then
-    echo "Ending copyright year in NOTICE is not $(date +%Y)"
-    exit 1
-fi
-
-tagMajorVersion=$(echo $tag | sed -e 's/\..*//')
-
-# Check that go.mod's module path contains the right version
-if ! grep -Fq "module github.com/apache/calcite-avatica-go/$tagMajorVersion" 
go.mod; then
-    echo "module declaration in go.mod does not contain the correct version. 
Expected: $tagMajorVersion"
-    exit 1
-fi
-
-# Make sure import paths contain the correct version
-badImportPaths=false
-
-for i in $(git ls-files); do
-
-    if [[ "$i" == "make-release-artifacts.sh" || "$i" =~ \.md$ ]]; then
-        continue
-    fi
-
-    lines=$(grep -F '"github.com/apache/calcite-avatica-go' $i)
-
-    if ! [[ -z "$lines" ]]; then
-        while read -r line; do
-            if ! grep -q 
"github.com/apache/calcite-avatica-go/$tagMajorVersion" <<< "$line" ; then
-                badImportPaths=true
-                echo "import for github.com/apache/calcite-avatica-go in $i 
does not have the correct version ($tagMajorVersion) in its path"
-            fi
-        done <<< "$lines"
-    fi
-done
-
-if "$badImportPaths" == true; then
-    exit 1
-fi
-
-# Check that Avatica versions in both gen-protobuf.bat and gen-protobuf.sh 
match
-EXPECTED_AVATICA_VERSION=$(grep -oP '^export AVATICA_VER="\K[^"]+' 
gen-protobuf.sh)
-
-if ! grep -Fq "SET AVATICA_VER=$EXPECTED_AVATICA_VERSION" gen-protobuf.bat; 
then
-    echo "AVATICA_VER in gen-protobuf.sh and gen-protobuf.bat does not match. 
Expected: $EXPECTED_AVATICA_VERSION"
-    exit 1
-fi
-
-tagWithoutV=$(echo $tag | sed -e 's/v//')
-tagWithoutRC=$(echo $tagWithoutV | sed -e 's/-rc[0-9][0-9]*//')
-product=apache-calcite-avatica-go
-tarFile=$product-$tagWithoutRC-src.tar.gz
-releaseDir=dist/$product-$tagWithoutV
-
-#Make release dir
-mkdir -p $releaseDir
-
-# Checkout tag
-if ! git checkout $tag; then
-    echo "Could not check out tag $tag. Does it exist?"
-    exit 1
-fi
-
-# Make tar
-tar -zcf $releaseDir/$tarFile --transform "s/^/$product-$tagWithoutRC-src\//g" 
$(git ls-files)
-
-cd $releaseDir
-
-# Calculate SHA512
-gpg --print-md SHA512 $tarFile > $tarFile.sha512
-
-# Select GPG key for signing
-KEYS=()
-
-GPG_COMMAND="gpg2"
-
-get_gpg_keys (){
-    GPG_KEYS=$($GPG_COMMAND --list-keys --with-colons --keyid-format LONG)
-
-    KEY_NUM=1
-
-    KEY_DETAILS=""
-
-    while read -r line; do
-
-        IFS=':' read -ra PART <<< "$line"
-
-        if [ ${PART[0]} == "pub" ]; then
-
-            if [ -n "$KEY_DETAILS" ]; then
-                KEYS[$KEY_NUM]=$KEY_DETAILS
-                KEY_DETAILS=""
-                ((KEY_NUM++))
-
-            fi
-
-            KEY_DETAILS=${PART[4]}
-        fi
-
-        if [ ${PART[0]} == "uid" ]; then
-            KEY_DETAILS="$KEY_DETAILS - ${PART[9]}"
-        fi
-
-    done <<< "$GPG_KEYS"
-
-    if [ -n "$KEY_DETAILS" ]; then
-        KEYS[$KEY_NUM]=$KEY_DETAILS
-    fi
-}
-
-get_gpg_keys
-
-if [ "${#KEYS[@]}" -le 0 ]; then
-    echo "You do not have any GPG keys available. Exiting..."
-    exit 1
-fi
-
-echo "You have the following GPG keys:"
-
-for i in "${!KEYS[@]}"; do
-        echo "$i) ${KEYS[$i]}"
-done
-
-read -p "Select your GPG key for signing: " KEY_INDEX
-
-GPG_KEY=$(sed 's/ -.*//' <<< ${KEYS[$KEY_INDEX]})
-
-if [ -z $GPG_KEY ]; then
-    echo "Selected key is invalid. Exiting..."
-    exit 1
-fi
-
-# Sign
-gpg -u $GPG_KEY --armor --output $tarFile.asc --detach-sig $tarFile
-
-echo "Release created!"
-# End
\ No newline at end of file
diff --git a/site/develop/avatica-go.md b/site/develop/avatica-go.md
index fd6faca..77a1923 100644
--- a/site/develop/avatica-go.md
+++ b/site/develop/avatica-go.md
@@ -32,12 +32,10 @@ To file issues, please use the [Calcite 
JIRA](https://issues.apache.org/jira/pro
 as the component.
 
 ## Updating protobuf definitions
-
-To update the procotol buffer definitions, update `AVATICA_VER` in 
`gen-protobuf.bat` and `gen-protobuf.sh` to match
-the version you want to generate protobufs for and then run the appropriate 
script for your platform.
+1. Install [docker](https://docs.docker.com/install/) and 
[docker-compose](https://docs.docker.com/compose/install/).
+2. From the root of the repository, run `docker-compose run compile-protobuf`
 
 ## Live reload during development
-
 It is possible to reload the code in real-time during development. This 
executes the test suite every time a `.go` or
 `.mod` file is updated. The test suite takes a while to run, so the tests will 
not complete instantly, but live-reloading
 during development allows us to not have to manually execute the test suite on 
save.
@@ -45,16 +43,19 @@ during development allows us to not have to manually 
execute the test suite on s
 ### Set up
 1. Install [docker](https://docs.docker.com/install/) and 
[docker-compose](https://docs.docker.com/compose/install/).
 
-2. From the root of the repository, run `DEV=true docker-compose up --build`.
+2. From the root of the repository, run `docker-compose run dev`.
 
-## Testing
+3. After terminating the container, stop all the containers and remove them 
using: `docker-compose down`
 
+## Testing
 The test suite takes around 4 minutes to run if you run both the Avatica 
HSQLDB and Apache Phoenix tests.
 
 ### Easy way
 1. Install [docker](https://docs.docker.com/install/) and 
[docker-compose](https://docs.docker.com/compose/install/).
 
-2. From the root of the repository, run `docker-compose up --build 
--abort-on-container-exit`.
+2. From the root of the repository, run `docker-compose run test`.
+
+3. After the tests complete, stop all the containers and remove them using: 
`docker-compose down`
 
 ### Manual set up
 1. Install [Go](https://golang.org/doc/install).
@@ -80,21 +81,50 @@ PHOENIX_HOST: http://phoenix:8765
 ## Releasing
 
 ### Preparing for release
-1. If you have not set up a GPG signing key, set one up by following these 
[instructions](https://www.apache.org/dev/openpgp.html#generate-key).
+1. You will need to have [docker](https://docs.docker.com/install/) and 
[Docker Compose](https://docs.docker.com/compose/install/) installed.
 
-2. If this release is a new major version (we are releasing 4.0.0 vs the 
current version 3.0.0), update the version in the
+2. If you have not set up a GPG signing key, set one up by following these 
[instructions](https://www.apache.org/dev/openpgp.html#generate-key).
+
+3. If this release is a new major version (we are releasing 4.0.0 vs the 
current version 3.0.0), update the version in the
 import path in `go.mod`. The import paths in the various sample code snippets 
should also be updated.
 
-3. Since we need to support Go modules, tags must be prefixed with a `v`. For 
example, tag as `v3.1.0` rather than `3.1.0`.
+4. Since we need to support Go modules, tags must be prefixed with a `v`. For 
example, tag as `v3.1.0` rather than `3.1.0`.
+
+5. Check that `NOTICE` has the current copyright year.
+
+### Perform a dry-run
+* The script expects you to mount your `~/.gnupg` directory into the `/.gnupg` 
directory in the container. Once mounted into the container,
+the script will make a copy of the contents and move it to a different 
location, so that it will not modify the contents of your original
+`~/.gnupg` directory during the build.
+
+{% highlight bash %}
+# On Linux:
+docker-compose run -v ~/.gnupg:/.gnupg dry-run
+
+# On Windows
+docker-compose run -v /c/Users/username/AppData/Roaming/gnupg:/.gnupg dry-run
+{% endhighlight %}
 
 ### Build the release
-1. Tag the release. For example, if releasing `vX.Y.Z` and this is `rc0`, 
execute: `git tag vX.Y.Z-rcN` on the master branch.
+{% highlight bash %}
+# On Linux:
+docker-compose run -v ~/.gnupg:/.gnupg release
+
+# On Windows
+docker-compose run -v /c/Users/username/AppData/Roaming/gnupg:/.gnupg release
+{% endhighlight %}
 
-2. Push the tag to git: `git push origin vX.Y.Z-rcN`
+If the build fails, perform a clean:
+1. Remove the git tag locally and remotely:
+{% highlight bash %}
+git tag -d vX.Y.Z-rcA
+git push origin :refs/tags/vX.Y.Z-rcA
+{% endhighlight %}
 
-2. From the root of the repository, run `./make-release-artifacts.sh`. You 
will be asked to select the tag to build release
-artifacts for. The latest tag is automatically selected if no tag is selected. 
The release artifacts will be placed in a
-folder named for the release within the `dist/` folder.
+2. Clean the local repository
+{% highlight bash %}
+docker-compose run clean
+{% endhighlight %}
 
 ### Check the release before uploading
 The name of the release folder must be in the following format: 
`apache-calcite-avatica-go-X.Y.Z-rcN`. The version must 
@@ -110,9 +140,10 @@ The tar.gz must be named 
`apache-calcite-avatica-go-X.Y.Z-src.tar.gz`.
 
 There must be a GPG signature for the tar.gz named: 
`apache-calcite-avatica-go-X.Y.Z-src.tar.gz.asc`
 
-There must be a SHA256 hash for the tar.gz named: 
`apache-calcite-avatica-go-X.Y.Z-src.tar.gz.sha256`
+There must be a SHA256 hash for the tar.gz named: 
`apache-calcite-avatica-go-X.Y.Z-src.tar.gz.sha512`
 
 ### Uploading release artifacts to dev for voting
+#### Manually
 `svn` must be installed in order to upload release artifacts.
 
 1. Check out the Calcite dev release subdirectory: `svn co 
"https://dist.apache.org/repos/dist/dev/calcite/"; calcite-dev`.
@@ -125,6 +156,16 @@ correct release in the command.
 4. Commit to upload the artifacts: `svn commit -m 
"apache-calcite-avatica-go-X.Y.Z-rcN" --username yourapacheusername --force-log`
 Note the use of `--force-log` to suppress the svn warning, because the commit 
message is the same as the name of the directory.
 
+#### Using docker
+This assumes that a release was built and the artifacts are in the `dist/` 
folder.
+
+{% highlight bash %}
+docker-compose run publish-release-for-voting
+{% endhighlight %}
+
+The script will also generate a vote email to send to the dev list. You can 
use this email, but make sure to check that
+all the details are correct.
+
 ### Send an email to the Dev list for voting:
 
 Send out the email for voting:
@@ -136,14 +177,13 @@ Hi all,
 
 I have created a build for Apache Calcite Avatica Go X.Y.Z, release candidate 
N.
 
-Thanks to everyone who has contributed to this release.
-<Further details about release.> You can read the release notes here:
+Thanks to everyone who has contributed to this release. The release notes are 
available here:
 https://github.com/apache/calcite-avatica-go/blob/XXXX/site/_docs/go_history.md
 
 The commit to be voted upon:
-https://gitbox.apache.org/repos/asf/calcite-avatica-go/commit/NNNNNN
+https://gitbox.apache.org/repos/asf?p=calcite-avatica-go.git;a=commit;h=NNNNNN
 
-Its hash is XXXX.
+The hash is XXXX.
 
 The artifacts to be voted on are located here:
 
https://dist.apache.org/repos/dist/dev/calcite/apache-calcite-avatica-go-X.Y.Z-rcN/
@@ -154,8 +194,16 @@ src.tar.gz.sha256 XXXX
 Release artifacts are signed with the following key:
 https://people.apache.org/keys/committer/francischuang.asc
 
+Instructions for running the test suite is located here:
+https://github.com/apache/calcite-avatica-go/blob/$COMMIT/site/develop/avatica-go.md#testing
+
 Please vote on releasing this package as Apache Calcite Avatica Go X.Y.Z.
 
+To run the tests without a Go environment, install docker and docker-compose. 
Then, in the root of the release's directory, run:
+docker-compose run test
+
+When the test suite completes, run \"docker-compose down\" to remove and 
shutdown all the containers.
+
 The vote is open for the next 72 hours and passes if a majority of
 at least three +1 PMC votes are cast.
 
@@ -198,6 +246,7 @@ Francis
 {% endhighlight %}
 
 ### Promoting a release after voting
+#### Manually
 `svn` must be installed in order to upload release artifacts.
 
 NOTE: Only official releases that has passed a vote may be uploaded to the 
release directory.
@@ -219,7 +268,15 @@ git tag vX.Y.Z X.Y.Z-rcN
 git push origin vX.Y.Z
 {% endhighlight %}
 
-6. After 24 hours, announce the release by sending an announcement to the [dev 
list](https://mail-archives.apache.org/mod_mbox/calcite-dev/)
+#### Using docker
+This assumes that a rc release was tagged and pushed to the git repository.
+
+{% highlight bash %}
+docker-compose run promote-release
+{% endhighlight %}
+
+### Announce the release
+After 24 hours, announce the release by sending an announcement to the [dev 
list](https://mail-archives.apache.org/mod_mbox/calcite-dev/)
 and 
[[email protected]](https://mail-archives.apache.org/mod_mbox/www-announce/).
 
 An example of the announcement could look like:

Reply via email to