#!/bin/bash -e

[[ -z $DEBUG ]] || set -x

tmp_dir=/tmp/gh_releases
rm -rf $tmp_dir
mkdir -p $tmp_dir
touch $tmp_dir/releases

fatal() { echo -e "\n[FATAL] $*" >&2; exit 1; }
warning() { echo -e "[WARNING] $*" >&2; }

usage() {
    cat >&2 <<EOF
Usage: $(basename "$0") <user>/<repo>

Args:

    -h|--help   Show this help and exit.

Env Vars:
    # used for github api
    GITHUB_USER (optional)
    GITHUB_USER_TOKEN (recommended)

    # retain temp files and set x if set
    DEBUG

    # omit tags or releases in output respectively if set
    NO_TAGS
    NO_RELEASES

Note: GITHUB_USER_TOKEN environment variable is highly recommended as
      multipage results may be unreliable. GITHUB_USER is optional and not
      actually required for gh_releases to function.
EOF
    exit 1
}

repo_path=
while [[ $# -gt 0 ]]; do
    case $1 in
        -h|--help)
            usage;;
        *)
            if [[ -z "$repo_path" ]]; then
                repo_path=$1
            else
                fatal "Only one <user>/<repo> can be provided"
            fi;;
    esac
    shift
done

if [[ -z "$repo_path" ]]; then
    fatal "<user>/<repo> not provided"
elif [[ "$repo_path" != *"/"* ]]; then
    fatal "Remote repo must be in form <user>/<repo>"
fi

auth=()
if [[ -n $GITHUB_USER_TOKEN ]]; then
    auth=(-H "Authorization: Bearer $GITHUB_USER_TOKEN")
    if [[ -n $GITHUB_USER ]]; then
        echo "Using GitHub token for user: $GITHUB_USER" >&2
    else
        warning "$GITHUB_USER is optional for gh_releases but may be used elsewhere"
    fi
else
    warning "GITHUB_USER_TOKEN not set. Results may be unreliable."
fi

if [[ -n "$NO_TAGS" ]]; then
    warning "omitting tags (NO_TAGS is set)"
fi
if [[ -n "$NO_RELEASES" ]]; then
    warning "omitting releases (NO_RELEASES is set)"
fi

echo -n "Fetching releases from github for '$repo_path'... " >&2

get_page() {
    url=$1
    key=$2
    page=$3
    tmp_file=$(mktemp $tmp_dir/XXXX.tmp)
    http_code=$(curl -s -o "$tmp_file" -w "%{http_code}\n" "${auth[@]}" \
        "${url}?page=${page}&per_page=100")
    if [[ $http_code != 2* ]]; then
        [[ -n $DEBUG ]] || rm -f "$tmp_file"
        fatal "Downloading $repo_path returned: HTTP $http_code"
    fi
    grep -oP "\"$key\": \"\\K(.*)(?=\")" "$tmp_file"
    [[ -n $DEBUG ]] || rm -f "$tmp_file"
}

get_all_pages() {
    url=$1
    key=$2
    declare -i page=1
    last_page="$(get_page "$url" "$key" "$page")"

    while [[ -n "$last_page" ]] && [[ $page -lt 10 ]]
    do
        echo "$last_page" >> $tmp_dir/releases
        page+=1
        last_page="$(get_page "$url" "$key" "$page")"
    done

    if [[ $page -eq 10 ]]; then
        warning "some releases may of been truncated from gh_releases output"
    fi
}

if [[ -z $NO_RELEASES ]]; then
    get_all_pages "https://api.github.com/repos/${repo_path}/releases" "tag_name"
fi
if [[ -z $NO_TAGS ]]; then
    get_all_pages "https://api.github.com/repos/${repo_path}/tags" "name"
fi

echo "Done." >&2
sort --version-sort --unique $tmp_dir/releases
[[ -n $DEBUG ]] || rm -rf $tmp_dir
