#!/bin/bash

set -e

ARGS=$@

# . env_setup

usage() {
    cat << EOF
USAGE: pymdeploy [--debug] [--no-test] [--no-build] [--no-push] [--no-deploy]

Run the pymacaron deployment pipeline:
 1. Run local tests with pymtest
 2. Build a docker image with pymdocker
 3. Run the tests again, against the docker image
    started in a local container
 4. Push the docker image to a docker repository
 5. Deploy the docker image to a live environment
    (Amazon Beanstalk, GKE or GCR)
 6. Run the tests again, against the live api

OPTIONS:

  --env ENV:        deploy the service described in 'pym-config.ENV.yaml'
                    (defaults to using 'pym-config.yaml')
  --debug:          be very verbose.
  --no-test:        skip all tests (steps 1, 3 and 6).
  --no-build:       skip building the docker image and use
                    the latest built image instead (step 2)
  --no-push:        skip pushing the image to docker hub (step 4).
  --no-deploy:      skip deploying to live (step 5).
  --staging-only    deploy only to staging, not live (if possible).

EXAMPLES:

# test, build, push, deploy
pymdeploy

# same against a staging environment described in pym-config.staging.yaml
pymdeploy --env staging

# only build docker image and push it
pymdeploy --no-test --no-deploy

# deploy quickly, without testing
pymdeploy --no-test

EOF
}

DO_PUSH=1
DO_DEPLOY=1
DO_TEST=1
DO_BUILD=1
DEPLOY_ARGS=
WITH_DEBUG=
TARGET_ENV=

parse_args() {
    while [ "$1" != "" ]; do
        case $1 in
            "--env")           shift; export TARGET_ENV=$1;;
            "--debug")         set -x; DEBUG='true'; WITH_DEBUG="--debug";;
            "--no-build")      export DO_BUILD=;;
            "--no-push")       export DO_PUSH=;;
            "--no-deploy")     export DO_DEPLOY=;;
            "--no-test")       export DO_TEST=; export DEPLOY_ARGS="$DEPLOY_ARGS --no-test";;
            "--staging-only")  export DEPLOY_ARGS="$DEPLOY_ARGS --staging-only";;
            "-h" | "--help")   usage; exit 0;;
            *)                 echo "Unknown argument '$1' (-h for help)"; exit 0;;
        esac
        shift
    done
}

parse_args $ARGS

WITH_ENV=""
if [ ! -z "$TARGET_ENV" ]; then
    WITH_ENV="--env $TARGET_ENV"
    export PYM_ENV=$TARGET_ENV
    echo "=> Using PYM_ENV=$PYM_ENV"
fi

# Check that pymconfig exists
pymconfig $WITH_ENV

NAME=$(pymconfig $WITH_ENV --name)
DOCKER_ROOT_REPO=$(pymconfig $WITH_ENV --docker-repo)
DOCKER_REPO=$DOCKER_ROOT_REPO/$NAME
DEPLOY_TARGET=$(pymconfig $WITH_ENV --deploy-target)


do_check_git_repo() {
    CURRENT_BRANCH=$(git branch | grep \* | cut -d ' ' -f2)
    if [ "$CURRENT_BRANCH" != "master" ]; then
        echo "ERROR: The current branch is not master - Cannot deploy!"
        exit 1
    fi

    IS_DIRTY_CLONE=$(git status --short --porcelain | wc -l)
    if [ "$IS_DIRTY_CLONE" -gt 0 ]; then
        echo "ERROR: $PWD is not clean! Commit and re-run."
        exit 1
    fi

    GIT_DIFF_REMOTE=$(git diff master origin/master | wc -l)
    if [ "$GIT_DIFF_REMOTE" -ne 0 ]; then
        echo "ERROR: $PWD differs from origin. Please push to origin before releasing!"
        exit 1
    fi
}

do_gen_version() {
    VERSION=$(pymversion)
    echo "=> Using version: ${VERSION}"
}

do_get_last_version() {
    if [ -f ".pym/last_version" ]; then
        VERSION=$(cat ".pym/last_version")
    else
        VERSION=$(docker images | grep $DOCKER_REPO | head -n 1 | awk '{ print $2 }')
        if [ -z "$VERSION" ]; then
            echo "ERROR: cannot find the latest docker image"
            exit 1
        fi
    fi
    echo "=> Using version: ${VERSION}"
}

do_unit_tests() {
    if [ -d 'test' ]; then
        echo "=> Running nosetests"
        nosetests -xv test/
    fi
}

do_check_git_repo

if [ ! -z "$DO_TEST" ]; then
    do_unit_tests $WITH_DEBUG
else
    echo "=> Skip nosetest"
fi

if [ ! -z "$DO_BUILD" ]; then
    do_gen_version $WITH_DEBUG
    pymdocker $WITH_ENV --version $VERSION $WITH_DEBUG

    if [ ! -z "$DO_TEST" ]; then
        IMAGE_ID=$(docker images --quiet ${DOCKER_REPO}:${VERSION})
        pymtest $WITH_ENV --image $IMAGE_ID
    else
        echo "=> Skip running tests against docker image"
    fi
else
    echo "=> Skip building docker image. Using last image built."
    do_get_last_version
fi

if [ ! -z "$DO_PUSH" ]; then
    REGISTRY=gcr.io
    if [ "$DEPLOY_TARGET" == "aws-beanstalk" ]; then
        REGISTRY=docker.io
    fi
    pymdocker $WITH_ENV --version $VERSION --no-build --push $WITH_DEBUG --registry $REGISTRY

else
    echo "=> Skip pushing image to docker repository"
fi

if [ ! -z "$DO_DEPLOY" ]; then

    if [ "$DEPLOY_TARGET" == "aws-beanstalk" ]; then
        pymaws $VERSION $WITH_DEBUG $DEPLOY_ARGS

        echo "=> Waiting 1 min for cname swap to propagate"
        sleep 60

    elif [ "$DEPLOY_TARGET" == "gcp-cloud-run" ]; then

        pymgcr $VERSION $WITH_DEBUG $DEPLOY_ARGS

    elif [ "$DEPLOY_TARGET" == "gke" ]; then

        pymgke $WITH_ENV $VERSION $WITH_DEBUG $DEPLOY_ARGS

    else
        echo "ERROR: don't know how to deploy to target $DEPLOY_TARGET"
        exit 1
    fi
else
    echo "=> Skip deploying to live environment"
fi

if [ ! -z "$DO_TEST" ]; then
    pymtest $WITH_ENV $WITH_DEBUG
else
    echo "=> Skip running tests against live api"
fi

echo "=> Done."
