2014-01-21 20:21:56 -05:00
|
|
|
#!/usr/bin/env bash
|
2013-10-17 04:08:14 -04:00
|
|
|
set -e
|
2013-08-07 00:16:13 -04:00
|
|
|
|
2013-08-09 20:38:48 -04:00
|
|
|
# This script looks for bundles built by make.sh, and releases them on a
|
|
|
|
# public S3 bucket.
|
2013-08-07 00:16:13 -04:00
|
|
|
#
|
|
|
|
# Bundles should be available for the VERSION string passed as argument.
|
|
|
|
#
|
2013-08-09 20:38:48 -04:00
|
|
|
# The correct way to call this script is inside a container built by the
|
|
|
|
# official Dockerfile at the root of the Docker source code. The Dockerfile,
|
|
|
|
# make.sh and release.sh should all be from the same source code revision.
|
2013-08-07 00:16:13 -04:00
|
|
|
|
2013-10-17 04:08:14 -04:00
|
|
|
set -o pipefail
|
2013-08-07 00:16:13 -04:00
|
|
|
|
|
|
|
# Print a usage message and exit.
|
|
|
|
usage() {
|
2013-10-17 04:08:14 -04:00
|
|
|
cat >&2 <<'EOF'
|
2013-08-09 21:08:06 -04:00
|
|
|
To run, I need:
|
|
|
|
- to be in a container generated by the Dockerfile at the top of the Docker
|
|
|
|
repository;
|
|
|
|
- to be provided with the name of an S3 bucket, in environment variable
|
|
|
|
AWS_S3_BUCKET;
|
|
|
|
- to be provided with AWS credentials for this S3 bucket, in environment
|
|
|
|
variables AWS_ACCESS_KEY and AWS_SECRET_KEY;
|
2013-08-14 20:02:55 -04:00
|
|
|
- the passphrase to unlock the GPG key which will sign the deb packages
|
|
|
|
(passed as environment variable GPG_PASSPHRASE);
|
2013-08-09 21:08:06 -04:00
|
|
|
- a generous amount of good will and nice manners.
|
|
|
|
The canonical way to run me is to run the image produced by the Dockerfile: e.g.:"
|
|
|
|
|
2013-10-17 04:08:14 -04:00
|
|
|
docker run -e AWS_S3_BUCKET=get-staging.docker.io \
|
|
|
|
-e AWS_ACCESS_KEY=AKI1234... \
|
|
|
|
-e AWS_SECRET_KEY=sEs4mE... \
|
|
|
|
-e GPG_PASSPHRASE=m0resEs4mE... \
|
2014-03-13 13:46:02 -04:00
|
|
|
-i -t --privileged \
|
2013-10-17 04:08:14 -04:00
|
|
|
docker ./hack/release.sh
|
2013-08-09 21:08:06 -04:00
|
|
|
EOF
|
2013-08-07 00:16:13 -04:00
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
|
2013-08-09 21:08:06 -04:00
|
|
|
[ "$AWS_S3_BUCKET" ] || usage
|
|
|
|
[ "$AWS_ACCESS_KEY" ] || usage
|
|
|
|
[ "$AWS_SECRET_KEY" ] || usage
|
2013-08-14 20:02:55 -04:00
|
|
|
[ "$GPG_PASSPHRASE" ] || usage
|
2013-10-17 04:08:14 -04:00
|
|
|
[ -d /go/src/github.com/dotcloud/docker ] || usage
|
|
|
|
cd /go/src/github.com/dotcloud/docker
|
|
|
|
[ -x hack/make.sh ] || usage
|
|
|
|
|
|
|
|
RELEASE_BUNDLES=(
|
|
|
|
binary
|
2013-12-19 01:06:14 -05:00
|
|
|
cross
|
2013-11-17 22:25:08 -05:00
|
|
|
tgz
|
2013-10-17 04:08:14 -04:00
|
|
|
ubuntu
|
|
|
|
)
|
|
|
|
|
|
|
|
if [ "$1" != '--release-regardless-of-test-failure' ]; then
|
|
|
|
RELEASE_BUNDLES=( test "${RELEASE_BUNDLES[@]}" )
|
|
|
|
fi
|
2014-03-16 17:10:59 -04:00
|
|
|
|
2013-08-09 21:08:06 -04:00
|
|
|
VERSION=$(cat VERSION)
|
2013-08-09 21:18:33 -04:00
|
|
|
BUCKET=$AWS_S3_BUCKET
|
2013-08-07 00:16:13 -04:00
|
|
|
|
2014-03-16 17:10:59 -04:00
|
|
|
# These are the 2 keys we've used to sign the deb's
|
2014-03-19 19:35:58 -04:00
|
|
|
# release (get.docker.io)
|
2014-03-16 17:10:59 -04:00
|
|
|
# GPG_KEY="36A1D7869245C8950F966E92D8576A8BA88D21E9"
|
|
|
|
# test (test.docker.io)
|
|
|
|
# GPG_KEY="740B314AE3941731B942C66ADF4FD13717AAD7D6"
|
|
|
|
|
2013-08-07 00:16:13 -04:00
|
|
|
setup_s3() {
|
|
|
|
# Try creating the bucket. Ignore errors (it might already exist).
|
2013-08-14 21:35:17 -04:00
|
|
|
s3cmd mb s3://$BUCKET 2>/dev/null || true
|
2013-08-09 21:18:33 -04:00
|
|
|
# Check access to the bucket.
|
|
|
|
# s3cmd has no useful exit status, so we cannot check that.
|
|
|
|
# Instead, we check if it outputs anything on standard output.
|
|
|
|
# (When there are problems, it uses standard error instead.)
|
|
|
|
s3cmd info s3://$BUCKET | grep -q .
|
2013-08-14 21:35:17 -04:00
|
|
|
# Make the bucket accessible through website endpoints.
|
|
|
|
s3cmd ws-create --ws-index index --ws-error error s3://$BUCKET
|
2013-08-07 00:16:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
# write_to_s3 uploads the contents of standard input to the specified S3 url.
|
|
|
|
write_to_s3() {
|
|
|
|
DEST=$1
|
|
|
|
F=`mktemp`
|
|
|
|
cat > $F
|
2013-11-09 04:28:04 -05:00
|
|
|
s3cmd --acl-public --mime-type='text/plain' put $F $DEST
|
2013-08-07 00:16:13 -04:00
|
|
|
rm -f $F
|
|
|
|
}
|
|
|
|
|
|
|
|
s3_url() {
|
2013-09-28 00:50:24 -04:00
|
|
|
case "$BUCKET" in
|
|
|
|
get.docker.io|test.docker.io)
|
|
|
|
echo "https://$BUCKET"
|
|
|
|
;;
|
|
|
|
*)
|
2013-11-08 17:44:52 -05:00
|
|
|
s3cmd ws-info s3://$BUCKET | awk -v 'FS=: +' '/http:\/\/'$BUCKET'/ { gsub(/\/+$/, "", $2); print $2 }'
|
2013-09-28 00:50:24 -04:00
|
|
|
;;
|
|
|
|
esac
|
2013-08-07 00:16:13 -04:00
|
|
|
}
|
|
|
|
|
2014-03-16 17:10:59 -04:00
|
|
|
build_all() {
|
|
|
|
if ! ./hack/make.sh "${RELEASE_BUNDLES[@]}"; then
|
|
|
|
echo >&2
|
|
|
|
echo >&2 'The build or tests appear to have failed.'
|
|
|
|
echo >&2
|
|
|
|
echo >&2 'You, as the release maintainer, now have a couple options:'
|
|
|
|
echo >&2 '- delay release and fix issues'
|
|
|
|
echo >&2 '- delay release and fix issues'
|
|
|
|
echo >&2 '- did we mention how important this is? issues need fixing :)'
|
|
|
|
echo >&2
|
|
|
|
echo >&2 'As a final LAST RESORT, you (because only you, the release maintainer,'
|
|
|
|
echo >&2 ' really knows all the hairy problems at hand with the current release'
|
|
|
|
echo >&2 ' issues) may bypass this checking by running this script again with the'
|
|
|
|
echo >&2 ' single argument of "--release-regardless-of-test-failure", which will skip'
|
|
|
|
echo >&2 ' running the test suite, and will only build the binaries and packages. Please'
|
|
|
|
echo >&2 ' avoid using this if at all possible.'
|
|
|
|
echo >&2
|
|
|
|
echo >&2 'Regardless, we cannot stress enough the scarcity with which this bypass'
|
|
|
|
echo >&2 ' should be used. If there are release issues, we should always err on the'
|
|
|
|
echo >&2 ' side of caution.'
|
|
|
|
echo >&2
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2014-03-19 21:58:39 -04:00
|
|
|
upload_release_build() {
|
|
|
|
src="$1"
|
|
|
|
dst="$2"
|
|
|
|
latest="$3"
|
|
|
|
|
|
|
|
echo
|
|
|
|
echo "Uploading $src"
|
|
|
|
echo " to $dst"
|
|
|
|
echo
|
|
|
|
s3cmd --follow-symlinks --preserve --acl-public put "$src" "$dst"
|
|
|
|
if [ "$latest" ]; then
|
|
|
|
echo
|
|
|
|
echo "Copying to $latest"
|
|
|
|
echo
|
|
|
|
s3cmd --acl-public cp "$dst" "$latest"
|
|
|
|
fi
|
|
|
|
|
|
|
|
# get hash files too (see hash_files() in hack/make.sh)
|
|
|
|
for hashAlgo in md5 sha256; do
|
|
|
|
if [ -e "$src.$hashAlgo" ]; then
|
|
|
|
echo
|
|
|
|
echo "Uploading $src.$hashAlgo"
|
|
|
|
echo " to $dst.$hashAlgo"
|
|
|
|
echo
|
|
|
|
s3cmd --follow-symlinks --preserve --acl-public --mime-type='text/plain' put "$src.$hashAlgo" "$dst.$hashAlgo"
|
|
|
|
if [ "$latest" ]; then
|
|
|
|
echo
|
|
|
|
echo "Copying to $latest.$hashAlgo"
|
|
|
|
echo
|
|
|
|
s3cmd --acl-public cp "$dst.$hashAlgo" "$latest.$hashAlgo"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
2013-12-24 01:31:53 -05:00
|
|
|
release_build() {
|
|
|
|
GOOS=$1
|
|
|
|
GOARCH=$2
|
|
|
|
|
2014-03-19 21:58:39 -04:00
|
|
|
binDir=bundles/$VERSION/cross/$GOOS/$GOARCH
|
|
|
|
tgzDir=bundles/$VERSION/tgz/$GOOS/$GOARCH
|
|
|
|
binary=docker-$VERSION
|
|
|
|
tgz=docker-$VERSION.tgz
|
|
|
|
|
|
|
|
latestBase=
|
|
|
|
if [ -z "$NOLATEST" ]; then
|
|
|
|
latestBase=docker-latest
|
|
|
|
fi
|
2013-12-24 01:31:53 -05:00
|
|
|
|
|
|
|
# we need to map our GOOS and GOARCH to uname values
|
|
|
|
# see https://en.wikipedia.org/wiki/Uname
|
|
|
|
# ie, GOOS=linux -> "uname -s"=Linux
|
|
|
|
|
2014-03-19 21:58:39 -04:00
|
|
|
s3Os=$GOOS
|
|
|
|
case "$s3Os" in
|
2013-12-24 01:31:53 -05:00
|
|
|
darwin)
|
2014-03-19 21:58:39 -04:00
|
|
|
s3Os=Darwin
|
2013-12-24 01:31:53 -05:00
|
|
|
;;
|
|
|
|
freebsd)
|
2014-03-19 21:58:39 -04:00
|
|
|
s3Os=FreeBSD
|
2013-12-24 01:31:53 -05:00
|
|
|
;;
|
|
|
|
linux)
|
2014-03-19 21:58:39 -04:00
|
|
|
s3Os=Linux
|
2013-12-24 01:31:53 -05:00
|
|
|
;;
|
|
|
|
*)
|
2014-03-19 21:58:39 -04:00
|
|
|
echo >&2 "error: can't convert $s3Os to an appropriate value for 'uname -s'"
|
2013-12-24 01:31:53 -05:00
|
|
|
exit 1
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
2014-03-19 21:58:39 -04:00
|
|
|
s3Arch=$GOARCH
|
|
|
|
case "$s3Arch" in
|
2013-12-24 01:31:53 -05:00
|
|
|
amd64)
|
2014-03-19 21:58:39 -04:00
|
|
|
s3Arch=x86_64
|
2013-12-24 01:31:53 -05:00
|
|
|
;;
|
|
|
|
386)
|
2014-03-19 21:58:39 -04:00
|
|
|
s3Arch=i386
|
2013-12-24 01:31:53 -05:00
|
|
|
;;
|
|
|
|
arm)
|
2014-03-19 21:58:39 -04:00
|
|
|
s3Arch=armel
|
2014-01-31 05:16:42 -05:00
|
|
|
# someday, we might potentially support mutliple GOARM values, in which case we might get armhf here too
|
2013-12-24 01:31:53 -05:00
|
|
|
;;
|
|
|
|
*)
|
2014-03-19 21:58:39 -04:00
|
|
|
echo >&2 "error: can't convert $s3Arch to an appropriate value for 'uname -m'"
|
2013-12-24 01:31:53 -05:00
|
|
|
exit 1
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
2014-03-19 21:58:39 -04:00
|
|
|
s3Dir=s3://$BUCKET/builds/$s3Os/$s3Arch
|
|
|
|
latest=
|
|
|
|
latestTgz=
|
|
|
|
if [ "$latestBase" ]; then
|
|
|
|
latest="$s3Dir/$latestBase"
|
|
|
|
latestTgz="$s3Dir/$latestBase.tgz"
|
|
|
|
fi
|
2013-12-24 01:31:53 -05:00
|
|
|
|
2014-03-19 21:58:39 -04:00
|
|
|
if [ ! -x "$binDir/$binary" ]; then
|
|
|
|
echo >&2 "error: can't find $binDir/$binary - was it compiled properly?"
|
2013-12-24 01:31:53 -05:00
|
|
|
exit 1
|
|
|
|
fi
|
2014-03-19 21:58:39 -04:00
|
|
|
if [ ! -f "$tgzDir/$tgz" ]; then
|
|
|
|
echo >&2 "error: can't find $tgzDir/$tgz - was it packaged properly?"
|
2013-12-24 01:31:53 -05:00
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
2014-03-19 21:58:39 -04:00
|
|
|
upload_release_build "$binDir/$binary" "$s3Dir/$binary" "$latest"
|
|
|
|
upload_release_build "$tgzDir/$tgz" "$s3Dir/$tgz" "$latestTgz"
|
2013-12-24 01:31:53 -05:00
|
|
|
}
|
|
|
|
|
2013-08-07 00:16:13 -04:00
|
|
|
# Upload the 'ubuntu' bundle to S3:
|
|
|
|
# 1. A full APT repository is published at $BUCKET/ubuntu/
|
2013-11-08 17:45:18 -05:00
|
|
|
# 2. Instructions for using the APT repository are uploaded at $BUCKET/ubuntu/index
|
2013-08-07 00:16:13 -04:00
|
|
|
release_ubuntu() {
|
2013-10-17 04:08:14 -04:00
|
|
|
[ -e bundles/$VERSION/ubuntu ] || {
|
|
|
|
echo >&2 './hack/make.sh must be run before release_ubuntu'
|
|
|
|
exit 1
|
|
|
|
}
|
2013-08-14 20:02:55 -04:00
|
|
|
|
|
|
|
# Sign our packages
|
|
|
|
dpkg-sig -g "--passphrase $GPG_PASSPHRASE" -k releasedocker \
|
2013-10-17 04:08:14 -04:00
|
|
|
--sign builder bundles/$VERSION/ubuntu/*.deb
|
2013-08-14 20:02:55 -04:00
|
|
|
|
2013-08-12 23:16:55 -04:00
|
|
|
# Setup the APT repo
|
|
|
|
APTDIR=bundles/$VERSION/ubuntu/apt
|
|
|
|
mkdir -p $APTDIR/conf $APTDIR/db
|
|
|
|
s3cmd sync s3://$BUCKET/ubuntu/db/ $APTDIR/db/ || true
|
|
|
|
cat > $APTDIR/conf/distributions <<EOF
|
|
|
|
Codename: docker
|
|
|
|
Components: main
|
2013-08-14 13:41:23 -04:00
|
|
|
Architectures: amd64 i386
|
2013-08-12 23:16:55 -04:00
|
|
|
EOF
|
|
|
|
|
|
|
|
# Add the DEB package to the APT repo
|
|
|
|
DEBFILE=bundles/$VERSION/ubuntu/lxc-docker*.deb
|
|
|
|
reprepro -b $APTDIR includedeb docker $DEBFILE
|
|
|
|
|
2013-08-14 20:02:55 -04:00
|
|
|
# Sign
|
2013-10-17 04:08:14 -04:00
|
|
|
for F in $(find $APTDIR -name Release); do
|
2013-08-14 20:02:55 -04:00
|
|
|
gpg -u releasedocker --passphrase $GPG_PASSPHRASE \
|
|
|
|
--armor --sign --detach-sign \
|
|
|
|
--output $F.gpg $F
|
|
|
|
done
|
|
|
|
|
|
|
|
# Upload keys
|
|
|
|
s3cmd sync /.gnupg/ s3://$BUCKET/ubuntu/.gnupg/
|
|
|
|
gpg --armor --export releasedocker > bundles/$VERSION/ubuntu/gpg
|
|
|
|
s3cmd --acl-public put bundles/$VERSION/ubuntu/gpg s3://$BUCKET/gpg
|
|
|
|
|
|
|
|
# Upload repo
|
|
|
|
s3cmd --acl-public sync $APTDIR/ s3://$BUCKET/ubuntu/
|
2013-11-08 17:45:18 -05:00
|
|
|
cat <<EOF | write_to_s3 s3://$BUCKET/ubuntu/index
|
2013-08-14 20:02:55 -04:00
|
|
|
# Add the repository to your APT sources
|
2013-09-28 00:50:24 -04:00
|
|
|
echo deb $(s3_url)/ubuntu docker main > /etc/apt/sources.list.d/docker.list
|
2013-08-14 20:02:55 -04:00
|
|
|
# Then import the repository key
|
2014-03-18 19:00:48 -04:00
|
|
|
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
|
2013-08-14 20:02:55 -04:00
|
|
|
# Install docker
|
2013-08-16 18:30:50 -04:00
|
|
|
apt-get update ; apt-get install -y lxc-docker
|
2013-10-17 04:08:14 -04:00
|
|
|
|
|
|
|
#
|
|
|
|
# Alternatively, just use the curl-able install.sh script provided at $(s3_url)
|
|
|
|
#
|
2013-08-07 00:16:13 -04:00
|
|
|
EOF
|
2013-11-08 17:45:18 -05:00
|
|
|
|
|
|
|
# Add redirect at /ubuntu/info for URL-backwards-compatibility
|
|
|
|
rm -rf /tmp/emptyfile && touch /tmp/emptyfile
|
|
|
|
s3cmd --acl-public --add-header='x-amz-website-redirect-location:/ubuntu/' --mime-type='text/plain' put /tmp/emptyfile s3://$BUCKET/ubuntu/info
|
|
|
|
|
|
|
|
echo "APT repository uploaded. Instructions available at $(s3_url)/ubuntu"
|
2013-08-07 00:16:13 -04:00
|
|
|
}
|
|
|
|
|
2013-12-24 01:31:53 -05:00
|
|
|
# Upload binaries and tgz files to S3
|
|
|
|
release_binaries() {
|
|
|
|
[ -e bundles/$VERSION/cross/linux/amd64/docker-$VERSION ] || {
|
|
|
|
echo >&2 './hack/make.sh must be run before release_binaries'
|
2013-11-17 22:25:08 -05:00
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
|
2013-12-24 01:31:53 -05:00
|
|
|
for d in bundles/$VERSION/cross/*/*; do
|
|
|
|
GOARCH="$(basename "$d")"
|
|
|
|
GOOS="$(basename "$(dirname "$d")")"
|
|
|
|
release_build "$GOOS" "$GOARCH"
|
|
|
|
done
|
2013-11-17 22:25:08 -05:00
|
|
|
|
2013-12-24 01:31:53 -05:00
|
|
|
# TODO create redirect from builds/*/i686 to builds/*/i386
|
2013-11-08 17:45:18 -05:00
|
|
|
|
|
|
|
cat <<EOF | write_to_s3 s3://$BUCKET/builds/index
|
2013-08-07 00:16:13 -04:00
|
|
|
# To install, run the following command as root:
|
2013-09-28 00:50:24 -04:00
|
|
|
curl -O $(s3_url)/builds/Linux/x86_64/docker-$VERSION && chmod +x docker-$VERSION && sudo mv docker-$VERSION /usr/local/bin/docker
|
2013-08-07 00:16:13 -04:00
|
|
|
# Then start docker in daemon mode:
|
|
|
|
sudo /usr/local/bin/docker -d
|
|
|
|
EOF
|
2013-11-08 17:45:18 -05:00
|
|
|
|
|
|
|
# Add redirect at /builds/info for URL-backwards-compatibility
|
|
|
|
rm -rf /tmp/emptyfile && touch /tmp/emptyfile
|
|
|
|
s3cmd --acl-public --add-header='x-amz-website-redirect-location:/builds/' --mime-type='text/plain' put /tmp/emptyfile s3://$BUCKET/builds/info
|
|
|
|
|
2013-08-07 00:16:13 -04:00
|
|
|
if [ -z "$NOLATEST" ]; then
|
|
|
|
echo "Advertising $VERSION on $BUCKET as most recent version"
|
|
|
|
echo $VERSION | write_to_s3 s3://$BUCKET/latest
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2013-08-14 21:35:17 -04:00
|
|
|
# Upload the index script
|
|
|
|
release_index() {
|
2014-01-14 21:29:02 -05:00
|
|
|
sed "s,url='https://get.docker.io/',url='$(s3_url)/'," hack/install.sh | write_to_s3 s3://$BUCKET/index
|
2013-08-14 21:35:17 -04:00
|
|
|
}
|
|
|
|
|
2013-09-09 19:30:24 -04:00
|
|
|
release_test() {
|
|
|
|
if [ -e "bundles/$VERSION/test" ]; then
|
|
|
|
s3cmd --acl-public sync bundles/$VERSION/test/ s3://$BUCKET/test/
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2014-03-16 17:10:59 -04:00
|
|
|
setup_gpg() {
|
|
|
|
# Make sure that we have our keys
|
|
|
|
mkdir -p /.gnupg/
|
2014-03-19 21:58:39 -04:00
|
|
|
s3cmd sync s3://$BUCKET/ubuntu/.gnupg/ /.gnupg/ || true
|
2014-03-16 17:10:59 -04:00
|
|
|
gpg --list-keys releasedocker >/dev/null || {
|
|
|
|
gpg --gen-key --batch <<EOF
|
|
|
|
Key-Type: RSA
|
2014-03-19 21:58:39 -04:00
|
|
|
Key-Length: 4096
|
2014-03-16 17:10:59 -04:00
|
|
|
Passphrase: $GPG_PASSPHRASE
|
|
|
|
Name-Real: Docker Release Tool
|
|
|
|
Name-Email: docker@dotcloud.com
|
|
|
|
Name-Comment: releasedocker
|
|
|
|
Expire-Date: 0
|
|
|
|
%commit
|
|
|
|
EOF
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-07 00:16:13 -04:00
|
|
|
main() {
|
2014-03-16 17:10:59 -04:00
|
|
|
build_all
|
2013-08-07 00:16:13 -04:00
|
|
|
setup_s3
|
2014-03-16 17:10:59 -04:00
|
|
|
setup_gpg
|
2013-12-24 01:31:53 -05:00
|
|
|
release_binaries
|
2013-08-07 00:16:13 -04:00
|
|
|
release_ubuntu
|
2013-08-14 21:35:17 -04:00
|
|
|
release_index
|
2013-09-09 19:30:24 -04:00
|
|
|
release_test
|
2013-08-07 00:16:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
main
|
2013-12-24 01:31:53 -05:00
|
|
|
|
|
|
|
echo
|
|
|
|
echo
|
|
|
|
echo "Release complete; see $(s3_url)"
|
|
|
|
echo
|