Created
February 18, 2025 02:34
-
-
Save frozer/6dcdf9a901f32688c4e89163a65b17bd to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# GitHub Release Asset Downloader | |
# Simplest way to download the latest artifact from a public GitHub project | |
# Based on https://github.com/thenets/bash-helpers/blob/main/scripts/github-release-downloader.sh | |
# How to use: | |
# 1. Export the GITHUB_TOKEN variable | |
# 2. Export the following variables or pass them as parameters. | |
# $ ./github-release-downloader.sh \ | |
# <GITHUB_ORG> \ | |
# <GITHUB_REPO> \ | |
# <SEARCH_PATTERN> \ | |
# <OUTPUT_FILE_PATH (optional)> | |
# Example: | |
# $ ./github-release-downloader.sh \ | |
# gohugoio \ | |
# hugo \ | |
# "_linux-amd64.tar.gz" \ | |
# ./hugo.tar.gz | |
# | |
# Inspired by: | |
# https://gist.github.com/umohi/bfc7ad9a845fc10289c03d532e3d2c2f | |
# START | |
# Parameters (required) | |
declare -r GITHUB_ORG=${GITHUB_ORG:-$1} | |
declare -r GITHUB_REPO=${GITHUB_REPO:-$2} | |
declare -r SEARCH_PATTERN=${SEARCH_PATTERN:-$3} | |
# Parameters (optional) | |
declare OUTPUT_FILE_PATH=${OUTPUT_FILE_PATH:-$4} | |
# Helpers | |
if [ -z "$TERM" ] || [ "$TERM" == "dumb" ]; then | |
tput() { | |
return 0 | |
} | |
fi | |
if ! type tput >/dev/null 2>&1; then | |
tput() { | |
return 0 | |
} | |
fi | |
log_info() { | |
local CYAN=$(tput setaf 6) | |
local NC=$(tput sgr0) | |
echo "${CYAN}[INFO ]${NC} $*" 1>&2 | |
} | |
log_warning() { | |
local YELLOW=$(tput setaf 3) | |
local NC=$(tput sgr0) | |
echo "${YELLOW}[WARNING]${NC} $*" 1>&2 | |
} | |
log_error() { | |
local RED=$(tput setaf 1) | |
local NC=$(tput sgr0) | |
echo "${RED}[ERROR ]${NC} $*" 1>&2 | |
} | |
log_success() { | |
local GREEN=$(tput setaf 2) | |
local NC=$(tput sgr0) | |
echo "${GREEN}[SUCCESS]${NC} $*" 1>&2 | |
} | |
log_title() { | |
local GREEN=$(tput setaf 2) | |
local BOLD=$(tput bold) | |
local NC=$(tput sgr0) | |
echo 1>&2 | |
echo "${GREEN}${BOLD}---- $* ----${NC}" 1>&2 | |
} | |
h_run() { | |
local ORANGE=$(tput setaf 3) | |
local NC=$(tput sgr0) | |
echo "${ORANGE}\$${NC} $*" 1>&2 | |
eval "$*" | |
} | |
err() { | |
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2 | |
} | |
# Functions | |
function get_tags() { | |
# DEPRECATED, using release instead | |
log_info "Checking https://api.github.com/repos/${GITHUB_ORG}/${GITHUB_REPO}/tags" | |
# TODO add error handling | |
TAGS=$(curl -H "Authorization: Bearer ${GITHUB_TOKEN}" -sL https://api.github.com/repos/${GITHUB_ORG}/${GITHUB_REPO}/tags) | |
} | |
function get_latest_tag() { | |
# DEPRECATED, using release instead | |
get_tags | |
TAG_LATEST=$(echo ${TAGS} | jq -r '.[0]') | |
TAG_LATEST_NAME=$(echo $TAG_LATEST | jq -r .name) | |
log_info "[get_latest_tag] latest tag identified: ${TAG_LATEST_NAME}" | |
} | |
function get_releases() { | |
log_info "[get_releases] checking https://api.github.com/repos/${GITHUB_ORG}/${GITHUB_REPO}/releases" | |
# TODO add error handling | |
RELEASES=$(curl -H "Authorization: Bearer ${GITHUB_TOKEN}" -sL https://api.github.com/repos/${GITHUB_ORG}/${GITHUB_REPO}/releases) | |
} | |
function get_latest_release() { | |
get_releases | |
RELEASE_LATEST=$(echo ${RELEASES} | jq -r '.[0]') | |
RELEASE_LATEST_NAME=$(echo $RELEASE_LATEST | jq -r .name) | |
RELEASE_ID=$(echo $RELEASE_LATEST | jq -r .id) | |
log_info "[get_latest_release] latest release identified: name=${RELEASE_LATEST_NAME} id=${RELEASE_ID}" | |
} | |
function get_release_assets() { | |
local _RELEASE_ID=$1 | |
RELEASE="" | |
ASSETS="" | |
ASSETS=$(curl -L -H "Authorization: Bearer ${GITHUB_TOKEN}" https://api.github.com/repos/${GITHUB_ORG}/${GITHUB_REPO}/releases/${_RELEASE_ID}/assets) | |
# TODO error handling, release not found | |
#RELEASE=$(echo ${RELEASES} | jq -r ".[] | select(.name == \"$_RELEASE_NAME\")") | |
#ASSETS=$(echo ${RELEASES} | jq -r ".[] | select(.name == \"$_RELEASE_NAME\") | .assets") | |
local _ASSETS_COUNT=$(echo ${ASSETS} | jq length) | |
log_info "[get_release_assets] release=${_RELEASE_NAME} - total_of_assets=${_ASSETS_COUNT}" | |
} | |
function search_asset_by_name() { | |
local _CONTAINS=$1 | |
ASSET="" | |
ASSET_NAME="" | |
ASSET_URL="" | |
# TODO assert ASSETS is > 0 | |
ASSET=$(echo $ASSETS | jq -r ".[] | select(.name | contains(\"$_CONTAINS\"))") | |
echo $ASSET | |
ASSET_NAME=$(echo ${ASSET} | jq -r ".name" | head -n 1) | |
ASSET_URL=$(echo ${ASSET} | jq -r ".url" | head -n 1) | |
log_info "[search_asset_by_name] found ${ASSET_NAME}" | |
log_info "[search_asset_by_name] ${ASSET_URL}" | |
} | |
function print_help() { | |
# Prints help section from the top of the file | |
# | |
# It stops until it finds the '# START' line | |
echo "HELP:" | |
while read -r LINE; do | |
if [[ "${LINE}" == "#!/bin/bash" ]] || [[ "${LINE}" == "" ]]; then | |
continue | |
fi | |
if [[ "${LINE}" == "# START" ]]; then | |
return | |
fi | |
echo "${LINE}" | sed 's/^# / /g' | sed 's/^#//g' | |
done <${BASH_SOURCE[0]} | |
} | |
# Input validation | |
declare -i MISSING_ARG=0 | |
if [[ "${GITHUB_ORG}" == "" ]]; then | |
echo "ERROR! Missing 'GITHUB_ORG' argument!" | |
MISSING_ARG=1 | |
fi | |
if [[ "${GITHUB_REPO}" == "" ]]; then | |
echo "ERROR! Missing 'GITHUB_REPO' argument!" | |
MISSING_ARG=1 | |
fi | |
if [[ "${SEARCH_PATTERN}" == "" ]]; then | |
echo "ERROR! Missing 'SEARCH_PATTERN' argument!" | |
MISSING_ARG=1 | |
fi | |
if [[ ${MISSING_ARG} -gt 0 ]]; then | |
print_help | |
exit 1 | |
fi | |
# Variables (DEPRECATED) | |
# declare TAGS | |
# declare TAG_LATEST | |
# declare TAG_LATEST_NAME | |
# Variables | |
declare RELEASES | |
declare RELEASE_LATEST | |
declare RELEASE_LATEST_NAME | |
declare RELEASE_ID | |
declare RELEASE | |
declare ASSETS | |
declare ASSET | |
# Main | |
function main() { | |
log_info "Parameters:" | |
log_info " GITHUB_ORG : ${GITHUB_ORG}" | |
log_info " GITHUB_REPO : ${GITHUB_REPO}" | |
log_info " SEARCH_PATTERN : ${SEARCH_PATTERN}" | |
log_info " OUTPUT_FILE_PATH : ${OUTPUT_FILE_PATH}" | |
# Retrieve | |
get_latest_release | |
get_release_assets ${RELEASE_ID} | |
search_asset_by_name ${SEARCH_PATTERN} | |
if [[ "${OUTPUT_FILE_PATH}" == "" ]]; then | |
OUTPUT_FILE_PATH="$(pwd)/${ASSET_NAME}" | |
fi | |
# Download | |
if [[ -f "${OUTPUT_FILE_PATH}" ]]; then | |
log_warning "File already exist! ${OUTPUT_FILE_PATH}" | |
log_warning "Skipping..." | |
exit 0 | |
fi | |
if [[ "${ASSET_URL}" != "" ]]; then | |
log_info "Downloading..." | |
h_run "curl -H 'Authorization: Bearer ${GITHUB_TOKEN}' -H 'Accept:application/octet-stream' -SL --progress-bar -o ${OUTPUT_FILE_PATH} ${ASSET_URL}" | |
log_success "Saved on: ${OUTPUT_FILE_PATH}" | |
fi | |
} | |
main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment