# shellcheck shell=bash #
# vim: ft=sh:ai:ts=8:sw=8:noet
set -eufCo pipefail
export SHELLOPTS
IFS=$'\t\n'
function _urlencode() {
# echoes url encoded input back
local _tmp="${1}"
_tmp="${_tmp// /%20}" # space
_tmp="${_tmp//-/%2d}" # -
_tmp="${_tmp//./%2e}" # .
_tmp="${_tmp//\//%2f}" # /
echo "${_tmp}"
}
export -f _urlencode
function _gitlab_paginate() {
# handles gitlab pagination, returns joined result back
# TODO: function name
# TODO: move this into generator
if [[ "unset" == "${GITLAB_TOKEN:-unset}" ]]; then
# TODO: make sure its _env_ var
>&2 echo "Error: need GITLAB_TOKEN env var"
return 42
fi
# TODO: move this into generator
if [[ 1 -ne $# ]]; then
>&2 echo "Error: need URL"
fi
local url="${1}"
if [[ "${1}" != *"per_page="* ]]; then
if [[ "${1}" = *"?"* ]]; then
url="${1}&per_page=${GITLAB_PER_PAGE:-100}"
else
url="${1}?per_page=${GITLAB_PER_PAGE:-100}"
fi
fi
# TODO: move this into generator
while read -r cmd; do
command -v "${cmd}" >/dev/null 2>/dev/null || { >&2 echo "Error: command '${cmd}' required!" ; }
done <<-CMD
awk
curl
jq
CMD
local pages
pages="$(2>/dev/null curl -qsSLI -H "PRIVATE-TOKEN: ${GITLAB_TOKEN}" "${url}" \
| awk -F ',' '/^[Ll]ink: / { gsub(/.*&page=/,"");gsub(/[&>].*/,"");print}')"
if [[ "zz" == "z${pages}z" ]]; then
>&2 echo "Got empty responce for pages, assuming no pagination and setting pages=1"
pages=1
elif [[ ! "${pages}" =~ ^[0-9]+$ ]]; then
>&2 echo "Got non-number '${pages}' as pages, exiting"
return 42
fi
for p in $(seq 1 "${pages}"); do
curl -qsSL -H "PRIVATE-TOKEN: ${GITLAB_TOKEN}" "${url}&page=${p}"
done | jq -n 'inputs' | jq -ns 'inputs | add'
}
export -f _gitlab_paginate
function _curl_with_json_expectation() {
local __f="${FUNCNAME:-no-FUNCNAME-is-this-even-bash}"
# first, ensure the explicit format of the expectation:
local json_expectation="${1:-unset}"; shift ;
if [[ ! "${json_expectation}" =~ ^json_expectation=\'.*\'$ ]]; then
>&2 cat <<-PARAM_ERROR
${__f}: invocation error: first argument must follow exact format.
- want: json_expectation=\\'.*\\' (note: single quotes are mandatory as of now)
- have: ${json_expectation}
Exiting!
PARAM_ERROR
return 42
else
# normalize, simply by substring
json_expectation="${json_expectation:18:-1}"
fi
# instruct curl to dump both response code and body into one stream and check it
# this is the place that makes this function unsuitable for anything that is big
# or high load, as it has to buffer the result
local response_with_code
response_with_code="$(set +x; curl "${@}" -w "%{response_code}")"
if [[ "${response_with_code: -3}" != 200 ]]; then
>&2 cat <<-CURL_ERROR
${__f} Error! Curl returned non HTTP/200 code!
- code: ${response_with_code: -3}
- body:
---------
${response_with_code::-3}
---------
Exiting!
CURL_ERROR
return 42
fi
# now that it's guaranteed http/OK, we only need to check json validity and expectation match
# if jq is okay (i.e. -e was not triggered), then result will be just sent to the output
if ! jq -e -r "${json_expectation}" <<< "${response_with_code::-3}"; then
>&2 cat <<-JSON_ERROR
${__f} Error! JQ says result does not match the expected pattern!
- expectation: ${json_expectation}
- body:
---------
${response_with_code::-3}
---------
Exiting!
JSON_ERROR
return 42
fi
}
#
source <(curl -qsSL https://gitlab.sh)
in scripts. handy af. strict. WIP. Commit: d58e2c2c