Skip to content

Instantly share code, notes, and snippets.

@yookoala
Last active October 13, 2020 10:25
Show Gist options
  • Save yookoala/0720914264204881c0ea564a2921e321 to your computer and use it in GitHub Desktop.
Save yookoala/0720914264204881c0ea564a2921e321 to your computer and use it in GitHub Desktop.
A script to create / append tagged release with any file as assets
#!/bin/bash
BASENAME=$(basename $0)
BASEPATH=$(dirname $(realpath $0))
# Print usage message
function usage {
cat <<EOF
usage: $BASENAME -k <GITHUB_API_TOKEN> -r <GITHUB_REPO_SLUG> -t <TAG> <DIST_PATH> <LABEL>
Argument:
DIST_PATH The folder containing all the files that needed to be included in
the release. Or the path to one single file to be released.
LABEL The label text used in the release asset. Can use these placeholders:
:filename: The full filename of the asset.
:extension: The file extension of the asset.
Options
-k OAuth2 Token for releasing. See "Personal Access Tokens" in GitHub Docs.
-r GitHub repository slug string (i.e. "username/reponame").
-t Tag for the release. Usually in "vX.X.X" format.
EOF
}
#
# readopts
#
# Read options into global variables:
# GITHUB_API_TOKEN OAuth2 Token for releasing. See "Personal Access Tokens" in GitHub Docs.
# GITHUB_REPO_SLUG GitHub repository slug string (i.e. "username/reponame").
# TAG The tag name of the release to create.
# DISTPATH The path where the asset(s) locate.
# LABEL The label for the released asset(s).
#
function readopts {
# Read all options as variables
while getopts ":k:r:t:" ARG; do
case ${ARG} in
k)
GITHUB_API_TOKEN="$OPTARG"
;;
r)
GITHUB_REPO_SLUG="$OPTARG"
;;
t)
TAG="$OPTARG"
;;
\?)
echo "Invalid Option: -$OPTARG" 1>&2
echo
usage
exit 1
;;
esac
done
# Remove all options from $@
shift $((OPTIND -1))
DISTPATH="$1"
LABEL="$2"
if [ -z "$GITHUB_API_TOKEN" ]; then
echo "flag -k is not set"
echo
usage
exit 1
fi
if [ -z "$GITHUB_REPO_SLUG" ]; then
echo "flag -r is not set"
echo
usage
exit 1
fi
if [ -z "$TAG" ]; then
echo "flag -t is not set"
echo
usage
exit 1
fi
}
#
# release_create [RELEASE_ID_VAR]
#
# Create a release from given information. Requires environment variables:
# GITHUB_API_TOKEN OAuth2 Token for releasing. See "Personal Access Tokens" in GitHub Docs.
# GITHUB_REPO_SLUG GitHub repository slug string (i.e. "username/reponame").
# TAG The tag name of the release to create.
#
# Argument:
# RELEASE_ID_VAR A variable reference to receive the retrieved release id, if any.
#
function release_create {
# Expects a variable name in first argument for returning release id
declare -n id=$1
local RESPONSE=$(curl \
-X POST \
-H "Authorization: token $GITHUB_API_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
-d "{\"tag_name\": \"$TAG\"}" \
"https://api.github.com/repos/$GITHUB_REPO_SLUG/releases")
eval $(echo "$RESPONSE" | grep -m 1 "id.:" | grep -w id | tr : = | tr -cd '[[:alnum:]]=')
if [ -z "$id" ]; then
echo "Failed to create release for tag: $TAG"
echo "Details: $RESPONSE"
return 1
fi
}
#
# release_get_id [RELEASE_ID_VAR]
#
# Find the release id from given information. Requires environment variable:
# GITHUB_API_TOKEN OAuth2 Token for releasing. See "Personal Access Tokens" in GitHub Docs.
# GITHUB_REPO_SLUG GitHub repository slug string (i.e. "username/reponame").
# TAG The tag name of the release to retrieve.
#
# Argument:
# RELEASE_ID_VAR A variable reference to receive the retrieved release id, if any.
#
function release_get_id {
declare -n id=$1
local RESPONSE=$(curl -sH "$AUTH" "https://api.github.com/repos/$GITHUB_REPO_SLUG/releases/tags/$TAG")
eval $(echo "$RESPONSE" | grep -m 1 "id.:" | grep -w id | tr : = | tr -cd '[[:alnum:]]=')
if [ -z "$RELEASE_ID" ]; then
echo "No release found for the tag $TAG"
echo "Details: $RESPONSE"
return 1
fi
}
#
# release_add_asset
#
# Find the release id from given information. Requires environment variable:
# GITHUB_API_TOKEN OAuth2 Token for releasing. See "Personal Access Tokens" in GitHub Docs.
# GITHUB_REPO_SLUG GitHub repository slug string (i.e. "username/reponame").
# TAG The tag name of the release to retrieve.
# FILE The full path to the file to add.
# LABEL The string label to the asset. Can include substitution placeholder
# for more complex labels. Placeholders supported:
# :filename: The full filename of the asset.
# :extension: The file extension of the asset.
#
# Argument:
# RELEASE_ID_VAR A variable reference to receive the retrieved release id, if any.
#
function release_add_asset {
# Upload asset
if [ -s "$FILE" ]; then
local FILENAME=$(basename $FILE)
if [ -z "$LABEL" ]; then
local __LABEL=""
else
local __FILENAME=$(sed_escape_string "$FILENAME")
local __EXTENSION=$(sed_escape_string $(parse_extension "$FILENAME"))
local __LABEL="$(echo $LABEL | sed --expression="s/:filename:/$__FILENAME/g")"
__LABEL="$(echo $__LABEL | sed --expression="s/:extension:/$__EXTENSION/g")"
echo "inside if: __LABEL=$__LABEL"
fi
echo "outside if: __LABEL=$__LABEL"
local QUERY="name=$(urlencode $FILENAME)"
if [ ! -z "$__LABEL" ]; then
QUERY="$QUERY&label=$(urlencode "$__LABEL")"
fi
echo "Uploading asset: $FILENAME"
echo "https://uploads.github.com/repos/$GITHUB_REPO_SLUG/releases/$RELEASE_ID/assets?$QUERY"
curl \
-X POST \
-H "Authorization: token $GITHUB_API_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
-H "Content-Type: application/x-gtar" \
--data-binary @"$FILE" \
"https://uploads.github.com/repos/$GITHUB_REPO_SLUG/releases/$RELEASE_ID/assets?$QUERY"
else
echo "Skipping empty asset: $FILE"
fi
}
#
# urlencode
#
# Encode string into URL-safe string.
#
function urlencode {
# urlencode <string>
old_lc_collate=$LC_COLLATE
LC_COLLATE=C
local length="${#1}"
for (( i = 0; i < length; i++ )); do
local c="${1:$i:1}"
case $c in
[a-zA-Z0-9.~_-]) printf '%s' "$c" ;;
*) printf '%%%02X' "'$c" ;;
esac
done
LC_COLLATE=$old_lc_collate
}
#
# sed_escape_string
#
# Escape string for escaping sed's regular expression
function sed_escape_string {
echo $1 | sed 's/[&/\]/\\&/g'
}
#
# parse_extension
#
# Parse extension of a given file. Correctly parse .tar.gz
# and .zip extension.
function parse_extension {
local FILENAME="$1"
local EXT=$(echo ${FILENAME##*.} | tr '[:upper:]' '[:lower:]')
if [ "$EXT" == "gz" ] || [ "$EXT" == "bz2" ]; then
local __FILENAME="${FILENAME%.*}"
EXT=$(echo ${__FILENAME##*.}.$EXT | tr '[:upper:]' '[:lower:]')
fi
echo $EXT
}
#
# main
#
# Read arguments and options into global variables
_IFS="$IFS"; IFS=$'\0'
readopts $@
IFS="$_IFS"
## FIXME: Validate token before use
# Find the release for the tag, or create one
if GITHUB_API_TOKEN="$GITHUB_API_TOKEN" GITHUB_REPO_SLUG="$GITHUB_REPO_SLUG" TAG="$TAG" release_get_id RELEASE_ID; then
echo "release found: RELEASE_ID=$RELEASE_ID"
echo
elif GITHUB_API_TOKEN="$GITHUB_API_TOKEN" GITHUB_REPO_SLUG="$GITHUB_REPO_SLUG" TAG="$TAG" release_create RELEASE_ID; then
echo "release created: RELEASE_ID=$RELEASE_ID"
echo
fi
if [ -z "$RELEASE_ID" ]; then
echo "unable to create or find release for tag: $TAG"
exit 1
fi
# Upload assets in the dist folder
for FILE in $DISTPATH/*; do
if [ -f "$FILE" ]; then
GITHUB_API_TOKEN="$GITHUB_API_TOKEN" GITHUB_REPO_SLUG="$GITHUB_REPO_SLUG" RELEASE_ID="$RELEASE_ID" FILE="$FILE" LABEL="$LABEL" release_add_asset
else
echo "not a file. skipped: $FILE"
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment