# SPDX-License-Identifier: MIT set -o pipefail declare -A options PREFIX=============== VERBOSE=false DEBUG=false : ${EXIT_ON_ERROR:=true} : ${TMPDIR:=$(mktemp -d)} # default loop delay is 3600 sec (1 hour) : ${LOOPS:=100} : ${LOOP_DELAY:=36} : ${RETRY_DELAYS:=1 1 5 5 15 30} function dependencies() { if ! which jq curl > /dev/null ; then apt-get update -qq apt-get -qq install -y jq curl fi } function retry() { rm -f $TMPDIR/retry.{out,attempt,err} local success=false for delay in $RETRY_DELAYS ; do if "$@" > $TMPDIR/retry.attempt 2>> $TMPDIR/retry.err ; then success=true break fi cat $TMPDIR/retry.{err,attempt} >> $TMPDIR/retry.out cat $TMPDIR/retry.{err,attempt} >&2 echo waiting $delay "$@" >&2 sleep $delay done if $success ; then cat $TMPDIR/retry.attempt return 0 else echo retry failed for "$@" >&2 cat $TMPDIR/retry.out >&2 return 1 fi } function debug() { DEBUG=true VERBOSE=true set -x PS4='${BASH_SOURCE[0]}:$LINENO: ${FUNCNAME[0]}: ' } function verbose() { VERBOSE=true } function log() { echo "$@" >&2 } function log_error() { log "$@" } function log_verbose() { if $VERBOSE ; then log_info "$@" fi } function log_info() { echo "$PREFIX $@" } function fatal_error() { log_error "$@" if $EXIT_ON_ERROR ; then exit 1 else return 1 fi } function stash_debug() { echo start $SELF mkdir -p $TMPDIR > $TMPDIR/run.out tail --follow $TMPDIR/run.out | sed --unbuffered -n -e "/^$PREFIX/s/^$PREFIX //p" & pid=$! if ! $SELF --debug "$@" >& $TMPDIR/run.out ; then kill $pid cat $TMPDIR/run.out echo fail $SELF return 1 fi kill $pid echo success $SELF } function host_port() { local url="$1" local host_port="${url##http*://}" echo ${host_port%%/} } function scheme() { local url="$1" echo "${url%%://*}" } function owner() { local repo="$1" echo "${repo%%/*}" } function repository() { local repo="$1" echo "${repo##*/}" } function get_status() { local api="$1" local sha="$2" forgejo-curl.sh api_json $api/commits/$sha/status } function check_status() { local api="$1" local sha="$2" local expected_status="$3" local expected_description="$4" get_status $api $sha > $TMPDIR/status.json local status="$(jq --raw-output .state < $TMPDIR/status.json)" local description="$(jq --raw-output .statuses[0].description < $TMPDIR/status.json)" if test "$status" = "$expected_status" && test -z "$expected_description" -o "$description" = "$expected_description"; then echo OK elif test "$status" = "failure" -o "$status" = "success"; then echo NOK else echo RETRY fi } function wait_success() { wait_status success "$@" } function wait_failure() { wait_status failure "$@" } function wait_running() { wait_status pending "$@" "Has started running" } function wait_log() { local sha="$1" expected_status="$2" expected_description="$3" local status="$(jq --raw-output .state < $TMPDIR/status.json)" local description="$(jq --raw-output .statuses[0].description < $TMPDIR/status.json)" if test "$expected_description"; then expected_description=" '$expected_description'" fi log_info "$sha status waiting '$expected_status'$expected_description, currently '$status' '$description'" } function wait_status() { local status="$1" local api="$2" local sha="$3" local description="$4" for i in $(seq $LOOPS); do if test $(check_status "$api" "$sha" "$status" "$description") != RETRY ; then break fi wait_log "$sha" "$status" "$description" sleep $LOOP_DELAY done if test $(check_status "$api" "$sha" "$status" "$description") = "OK" ; then log_info "$sha status OK" else get_status $api $sha | jq .statuses log_info "$sha status NOK" return 1 fi } function sanity_check_pr_or_ref() { local pr="$1" ref="$2" if test "$pr" -a "$ref" ; then log_error "--origin-pr $pr and --origin-ref $ref are mutually exclusive" return 1 fi if test -z "$pr" -a -z "$ref" ; then log_error "one of --origin-pr or --origin-ref must be set" return 2 fi } function set_origin_head() { local pr="${options[origin_pr]}" local ref="${options[origin_ref]}" sanity_check_pr_or_ref "$pr" "$ref" if test "$pr"; then options[origin_head]=refs/pull/$pr/head origin_sanity_check else options[origin_head]=$ref fi } function origin_has_pr() { test "${options[origin_pr]}" } function set_destination_head() { local pr="${options[origin_pr]}" local ref="${options[origin_ref]}" sanity_check_pr_or_ref "$pr" "$ref" if $(origin_has_pr); then options[destination_head]=${options[prefix]}-$pr else options[destination_head]=${options[prefix]}-$ref fi }