# 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 }