tools/build/publish

#!/usr/bin/env bash

set -o errexit
set -o nounset

declare -r debug='false'
declare -r tmpfile_file="/tmp/publish.$$.tmpfiles"

function make_temp_file
{
    local template="${1:-publish.$$.XXXXXX}"
    if [[ $template != *XXXXXX ]]
    then
        template="$template.XXXXXX"
    fi
    local tmp=$(mktemp -t "$template")
    echo "$tmp" >> "$tmpfile_file"
    echo "$tmp"
}

function now
{
    date '+%Y-%m-%d %H:%M:%S'
}

function pwarn
{
    echo "$(now) [warning]: $@" 1>&2
}

function perr
{
    echo "$(now) [error]: $@" 1>&2
}

function pinfo
{
    echo "$(now) [info]: $@"
}

function pdebug
{
    if [[ $debug == 'true' ]]
    then
        echo "$(now) [debug]: $@"
    fi
}

function errexit
{
    perr "$@"
    exit 1
}

function onexit
{
    if [[ -f $tmpfile_file ]]
    then
        for tmpfile in $(< $tmpfile_file)
        do
            pdebug "removing temp file $tmpfile"
            rm -f $tmpfile
        done
        rm -f $tmpfile_file
    fi
}

function gh_publish {
    if [[ -z $version_string ]]
    then
        errexit 'gh_publish: version_string required'
    fi

    # NB: we use a X.Y.Z tag
    local -r release_json="{
        \"tag_name\" : \"$version_string\",
        \"name\" : \"$client_name  $version_string\",
        \"body\" : \"$client_slug $version_string\nhttps://github.com/basho/$client_slug/blob/$client_default_branch/RELNOTES.md\",
        \"draft\" : false,
        \"prerelease\" : $is_prerelease
    }"

    pdebug "Release JSON: $release_json"

    local curl_content_file="$(make_temp_file)"
    local curl_stdout_file="$(make_temp_file)"
    local curl_stderr_file="$(make_temp_file)"

    curl -4so $curl_content_file -w '%{http_code}' -XPOST \
        -H "Authorization: token $(< $github_api_key_file)" -H 'Content-type: application/json' \
        "https://api.github.com/repos/basho/$client_slug/releases" -d "$release_json" 1> "$curl_stdout_file" 2> "$curl_stderr_file"
    if [[ $? != 0 ]]
    then
        errexit "curl error exited with code: '$?' see '$curl_stderr_file'"
    fi

    local -i curl_rslt="$(< $curl_stdout_file)"
    if (( curl_rslt == 422 ))
    then
        pwarn "Release in GitHub already exists! (http code: '$curl_rslt')"
        curl -4so $curl_content_file -w '%{http_code}' -XGET \
            -H "Authorization: token $(< $github_api_key_file)" -H 'Content-type: application/json' \
            "https://api.github.com/repos/basho/$client_slug/releases/tags/$version_string" 1> "$curl_stdout_file" 2> "$curl_stderr_file"
        if [[ $? != 0 ]]
        then
            errexit "curl error exited with code: '$?' see '$curl_stderr_file'"
        fi
    elif (( curl_rslt != 201 ))
    then
        errexit "Creating release in GitHub failed with http code '$curl_rslt'"
    fi

    if [[ -z $client_package_file ]]
    then
        pinfo 'No release assets to upload, exiting.'
        exit 0
    fi

    if [[ -s $client_package_file ]]
    then
        pinfo "Uploading release assets file: $client_package_file"
    else
        exit 0
    fi

    if [[ ! -s $curl_content_file ]]
    then
        errexit 'no release info to parse for asset uploads'
    fi

    # "upload_url": "https://uploads.github.com/repos/basho/$client_slug/releases/1115734/assets{?name,label}"
    # https://uploads.github.com/repos/basho/$client_slug/releases/1115734/assets{?name,label}
    local -r upload_url_with_name=$(perl -ne 'print qq($1\n) and exit if /"upload_url"[ :]+"(https:\/\/[^"]+)"/' "$curl_content_file")
    local -r upload_url="${upload_url_with_name/\{?name,label\}/?name=$client_package_name}"

    curl_content_file="$(make_temp_file)"
    curl_stdout_file="$(make_temp_file)"
    curl_stderr_file="$(make_temp_file)"

    curl -4so $curl_content_file -w '%{http_code}' -XPOST \
        -H "Authorization: token $(< $github_api_key_file)" -H 'Content-type: application/x-compressed, application/x-tar' \
        "$upload_url" --data-binary "@$client_package_file" 1> "$curl_stdout_file" 2> "$curl_stderr_file"
    if [[ $? != 0 ]]
    then
        errexit "curl error exited with code: '$?' see '$curl_stderr_file'"
    fi

    curl_rslt="$(< $curl_stdout_file)"
    if (( curl_rslt != 201 ))
    then
        errexit "Uploading release assets to GitHub failed with http code '$curl_rslt'"
    fi
}

trap onexit EXIT

declare -r version_string="${1:-unknown}"

declare -r client_default_branch="${2:-''}"
if [[ -z $client_default_branch ]]
then
    errexit 'second argument must be default git branch ("master")'
fi

if [[ ! $version_string =~ ^[0-9].[0-9].[0-9](-[a-z]+[0-9]+)?$ ]]
then
    errexit 'first argument must be valid version string in X.Y.Z format'
fi

is_prerelease='false'
if [[ $version_string =~ ^[0-9].[0-9].[0-9]-[a-z]+[0-9]+$ ]]
then
    pinfo "publishing pre-release version: $version_string"
    is_prerelease='true'
else
    pinfo "publishing version $version_string"
fi

declare -r github_api_key_file="$HOME/.ghapi"
if [[ ! -s $github_api_key_file ]]
then
    errexit "please save your GitHub API token in $github_api_key_file"
fi

declare -r current_branch="$(git rev-parse --abbrev-ref HEAD)"
if [[ $debug == 'false' && $is_prerelease == 'false' && $current_branch != $client_default_branch ]]
then
    errexit "publish must be run on $client_default_branch branch"
fi

# Validate commands
if ! hash curl 2>/dev/null
then
    errexit "'curl' must be in your PATH"
fi

validate=${3:-''}
if [[ $validate == 'validate' ]]
then
    exit 0
fi

declare -r client_name="${3:-''}"
if [[ -z $client_name ]]
then
    errexit 'third argument must be client name ("Riak Java Client")'
fi

declare -r client_slug="${4:-''}"
if [[ -z $client_slug ]]
then
    errexit 'fourth argument must be client slug ("riak-java-client")'
fi

declare -r client_package_file="${5:-''}"
declare -r client_package_name="${6:-''}"

gh_publish