# 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