| #!/bin/bash | |
| # Copyright 2021 The Go Authors. All rights reserved. | |
| # Use of this source code is governed by a BSD-style | |
| # license that can be found in the LICENSE file. | |
| # This script is meant to be run from Cloud Build as a substitute | |
| # for "gcloud app deploy", as in: | |
| # | |
| # go-app-deploy.sh [--project=name] app.yaml | |
| # | |
| # It should not be run by hand and is therefore not marked executable. | |
| # | |
| # It customizes the usual "gcloud app deploy" in two ways. | |
| # | |
| # First, it deploys with --no-promote and only promotes after | |
| # the deployed app has passed an in-prod readiness test. | |
| # | |
| # Second, it chooses an app version like 2021-06-02-204309-2c120970 | |
| # giving the date, time, and commit hash of the commit being deployed. | |
| # This handles the case where multiple commits are being run through | |
| # Cloud Build at once and would otherwise end up with timestamps in | |
| # arbitrary order depending on the order in which Cloud Build happened | |
| # to reach each's gcloud app deploy command. With our choice, the | |
| # versions are ordered in git time order. | |
| set -e | |
| project=golang-org | |
| case "$1" in | |
| --project=*) | |
| project=$(echo $1 | sed 's/--project=//') | |
| shift | |
| esac | |
| yaml=app.yaml | |
| case "$1" in | |
| *.yaml) | |
| yaml=$1 | |
| shift | |
| esac | |
| if [ $# != 0 ]; then | |
| echo 'usage: go-app-deploy.sh [--project=name] path/to/app.yaml' >&2 | |
| exit 2 | |
| fi | |
| version=$(git log -n1 --date='format:%Y-%m-%d-%H%M%S' --pretty='format:%cd-%h') | |
| service=$(awk '$1=="service:" {print $2}' $yaml) | |
| servicedot="-$service-dot" | |
| if [ "$service" = default ]; then | |
| servicedot="" | |
| fi | |
| host="$version-dot$servicedot-$project.appspot.com" | |
| echo "### deploying to https://$host" | |
| gcloud -q --project=$project app deploy -v $version --no-promote $yaml | |
| curl --version | |
| for i in 1 2 3 4 5; do | |
| if curl -s --fail --show-error "https://$host/_readycheck"; then | |
| echo '### site is up!' | |
| # We used to have to worry about go-app-deploy.sh running for | |
| # other commits simultaneously, so we checked that we weren't | |
| # going to stomp a newer version of the web site. | |
| # The use of locktrigger in cloudbuild.yaml should make this impossible, | |
| # but keep checking anyway. | |
| serving=$(gcloud app services describe --project=$project $service | grep ': 1.0') | |
| if [ "$serving" '>' "$version" ]; then | |
| echo "### serving version $serving is newer than our $version; not promoting" | |
| exit 1 | |
| fi | |
| echo '### promoting' | |
| gcloud -q --project=$project app services set-traffic $service --splits=$version=1 | |
| exit 0 | |
| fi | |
| echo '### not healthy' | |
| curl "https://$host/_readycheck" # show response body | |
| done | |
| echo "### failed to become healthy; giving up" | |
| exit 1 |