diff --git a/.editorconfig b/.editorconfig index c17e595..669640d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,3 +1,10 @@ root = true + [*] -tab_width: 8 +indent_style = space +indent_size = 4 +tab_width = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/cascading-pr-lib.sh b/cascading-pr-lib.sh index 0991a0a..06f3dad 100644 --- a/cascading-pr-lib.sh +++ b/cascading-pr-lib.sh @@ -21,30 +21,30 @@ DEBUG=false : ${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 + 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 + 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} >>$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 + if $success; then + cat $TMPDIR/retry.attempt + return 0 else - echo retry failed for "$@" >&2 + echo retry failed for "$@" >&2 cat $TMPDIR/retry.out >&2 return 1 fi @@ -70,8 +70,8 @@ function log_error() { } function log_verbose() { - if $VERBOSE ; then - log_info "$@" + if $VERBOSE; then + log_info "$@" fi } @@ -81,20 +81,20 @@ function log_info() { function fatal_error() { log_error "$@" - if $EXIT_ON_ERROR ; then - exit 1 + if $EXIT_ON_ERROR; then + exit 1 else - return 1 + return 1 fi } function stash_debug() { echo start $SELF mkdir -p $TMPDIR - > $TMPDIR/run.out + >$TMPDIR/run.out tail --follow $TMPDIR/run.out | sed --unbuffered -n -e "/^$PREFIX/s/^$PREFIX //p" & pid=$! - if ! $SELF --debug "$@" >& $TMPDIR/run.out ; then + if ! $SELF --debug "$@" >&$TMPDIR/run.out; then kill $pid cat $TMPDIR/run.out echo fail $SELF @@ -142,15 +142,15 @@ function check_status() { 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)" + 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 + echo OK elif test "$status" = "failure" -o "$status" = "success"; then - echo NOK + echo NOK else - echo RETRY + echo RETRY fi } @@ -168,10 +168,10 @@ function wait_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)" + 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'" + expected_description=" '$expected_description'" fi log_info "$sha status waiting '$expected_status'$expected_description, currently '$status' '$description'" } @@ -183,31 +183,31 @@ function wait_status() { 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 + 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" + 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 + 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 + 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 + if test -z "$pr" -a -z "$ref"; then + log_error "one of --origin-pr or --origin-ref must be set" + return 2 fi } @@ -218,10 +218,10 @@ function set_origin_head() { sanity_check_pr_or_ref "$pr" "$ref" if test "$pr"; then - options[origin_head]=refs/pull/$pr/head - origin_sanity_check + options[origin_head]=refs/pull/$pr/head + origin_sanity_check else - options[origin_head]=$ref + options[origin_head]=$ref fi } @@ -236,8 +236,8 @@ function set_destination_head() { sanity_check_pr_or_ref "$pr" "$ref" if $(origin_has_pr); then - options[destination_head]=${options[prefix]}-$pr + options[destination_head]=${options[prefix]}-$pr else - options[destination_head]=${options[prefix]}-$ref + options[destination_head]=${options[prefix]}-$ref fi } diff --git a/cascading-pr.sh b/cascading-pr.sh index fba348e..8d3e227 100755 --- a/cascading-pr.sh +++ b/cascading-pr.sh @@ -5,7 +5,7 @@ set -e set -o posix SELF=${BASH_SOURCE[0]} -SELF_DIR="$( cd "$( dirname "$SELF" )" && pwd )" +SELF_DIR="$(cd "$(dirname "$SELF")" && pwd)" source $SELF_DIR/cascading-pr-lib.sh trap "rm -fr $TMPDIR" EXIT @@ -14,9 +14,9 @@ function repo_login() { local direction="$1" local repo=${options[${direction}_repo]} ( - export DOT=$TMPDIR/$repo - forgejo-curl.sh logout - forgejo-curl.sh --token "${options[${direction}_token]}" login "${options[${direction}_url]}" + export DOT=$TMPDIR/$repo + forgejo-curl.sh logout + forgejo-curl.sh --token "${options[${direction}_token]}" login "${options[${direction}_url]}" ) } @@ -29,19 +29,19 @@ function repo_curl() { function default_branch() { local direction=$1 - repo_curl ${options[${direction}_repo]} api_json ${options[${direction}_api]} > $TMPDIR/$direction.json - jq --raw-output .default_branch < $TMPDIR/$direction.json + repo_curl ${options[${direction}_repo]} api_json ${options[${direction}_api]} >$TMPDIR/$direction.json + jq --raw-output .default_branch <$TMPDIR/$direction.json } function destination_updated_at() { local api - if ${options[destination_is_fork]} ; then - repo_curl ${options[destination_repo]} api_json ${options[destination_fork_api]} > $TMPDIR/updated_at.json + if ${options[destination_is_fork]}; then + repo_curl ${options[destination_repo]} api_json ${options[destination_fork_api]} >$TMPDIR/updated_at.json else - repo_curl ${options[destination_repo]} api_json ${options[destination_api]} > $TMPDIR/updated_at.json + repo_curl ${options[destination_repo]} api_json ${options[destination_api]} >$TMPDIR/updated_at.json fi - jq --raw-output .updated_at < $TMPDIR/updated_at.json + jq --raw-output .updated_at <$TMPDIR/updated_at.json } function delete_branch_destination() { @@ -49,14 +49,14 @@ function delete_branch_destination() { local repo=${options[destination_repo]} local api=${options[destination_api]} - if ${options[destination_is_fork]} ; then - repo=${options[destination_fork_repo]} - api=${options[destination_fork_api]} + if ${options[destination_is_fork]}; then + repo=${options[destination_fork_repo]} + api=${options[destination_fork_api]} fi - if ! repo_curl ${options[destination_repo]} api_json $api/branches/$branch >& /dev/null ; then - log_info "branch $branch does not exists in $repo" - return + if ! repo_curl ${options[destination_repo]} api_json $api/branches/$branch >&/dev/null; then + log_info "branch $branch does not exists in $repo" + return fi repo_curl ${options[destination_repo]} api_json -X DELETE $api/branches/$branch log_info "branch $branch deleted in $repo" @@ -67,7 +67,7 @@ function pr_origin_comment_body() { } function comment_origin_pr() { - cat > $TMPDIR/data <$TMPDIR/data < $TMPDIR/data <$TMPDIR/data < $TMPDIR/destination-pr.json + retry repo_curl ${options[destination_repo]} api_json --data @$TMPDIR/data ${options[destination_api]}/pulls >$TMPDIR/destination-pr.json log_info "PR created $(pr_url destination)" } @@ -117,32 +117,32 @@ function close_pr() { local direction=destination if test "$(pr_state ${direction})" = "open"; then - log_info "closing $(pr_url ${direction})" - local number=$(pr_number $direction) - repo_curl ${options[${direction}_repo]} api_json -X PATCH --data '{"state":"closed"}' ${options[${direction}_api]}/issues/$number - delete_branch_destination + log_info "closing $(pr_url ${direction})" + local number=$(pr_number $direction) + repo_curl ${options[${direction}_repo]} api_json -X PATCH --data '{"state":"closed"}' ${options[${direction}_api]}/issues/$number + delete_branch_destination else - log_info "no open PR found" + log_info "no open PR found" fi } function pr_get_origin() { - repo_curl ${options[origin_repo]} api_json ${options[origin_api]}/pulls/${options[origin_pr]} > $TMPDIR/origin-pr.json + repo_curl ${options[origin_repo]} api_json ${options[origin_api]}/pulls/${options[origin_pr]} >$TMPDIR/origin-pr.json } function pr_get_destination() { local title=$(pr_destination_title) - repo_curl ${options[destination_repo]} api --get --data state=open --data type=pulls --data-urlencode q="$title" ${options[destination_api]}/issues | jq --raw-output .[0] > $TMPDIR/destination-pr.json + repo_curl ${options[destination_repo]} api --get --data state=open --data type=pulls --data-urlencode q="$title" ${options[destination_api]}/issues | jq --raw-output .[0] >$TMPDIR/destination-pr.json } function pr_get() { local direction=$1 if ! test -f $TMPDIR/${direction}-pr.json; then - pr_get_$direction + pr_get_$direction fi } -function pr() { +function pr() { cat $TMPDIR/$1-pr.json } @@ -175,13 +175,13 @@ function git_clone() { local direction=$1 url=$2 if ! test -d $TMPDIR/$direction; then - git -c credential.helper="store --file=$TMPDIR/$direction.git-credentials" clone $url $TMPDIR/$direction + git -c credential.helper="store --file=$TMPDIR/$direction.git-credentials" clone $url $TMPDIR/$direction fi ( - cd $TMPDIR/$direction - git config credential.helper "store --file=$TMPDIR/$direction.git-credentials" - git config user.email cascading-pr@example.com - git config user.name cascading-pr + cd $TMPDIR/$direction + git config credential.helper "store --file=$TMPDIR/$direction.git-credentials" + git config user.email cascading-pr@example.com + git config user.name cascading-pr ) } @@ -190,13 +190,13 @@ function git_checkout() { local remote=origin ( - cd $TMPDIR/$direction - if [[ "$ref" =~ ^refs/ ]] ; then - git fetch --update-head-ok ${remote} +$ref:$ref - else - ref=${remote}/$ref - fi - git checkout -b prbranch $ref + cd $TMPDIR/$direction + if [[ "$ref" =~ ^refs/ ]]; then + git fetch --update-head-ok ${remote} +$ref:$ref + else + ref=${remote}/$ref + fi + git checkout -b prbranch $ref ) } @@ -204,26 +204,26 @@ function git_remote() { local direction=$1 remote=$2 url=$3 ( - cd $TMPDIR/$direction - git remote add $remote $url + cd $TMPDIR/$direction + git remote add $remote $url ) } function git_reset_branch() { local direction=$1 remote=$2 branch=$3 ( - cd $TMPDIR/$direction - if git ls-remote --exit-code --heads ${remote} $branch ; then - git fetch --quiet ${remote} $branch - git reset --hard ${remote}/$branch - fi + cd $TMPDIR/$direction + if git ls-remote --exit-code --heads ${remote} $branch; then + git fetch --quiet ${remote} $branch + git reset --hard ${remote}/$branch + fi ) } function sha_pushed() { local direction=$1 - if test -f $TMPDIR/$direction.sha ; then - cat $TMPDIR/$direction.sha + if test -f $TMPDIR/$direction.sha; then + cat $TMPDIR/$direction.sha fi } @@ -237,19 +237,19 @@ function push() { local remote=$1 branch=$2 ( - cd $TMPDIR/destination - git add . - if git commit -m 'cascading-pr update'; then - local before=$(destination_updated_at) - sleep 1 # the resolution of the update time is one second - git push --force ${remote} prbranch:$branch - git rev-parse HEAD > ../destination.sha - retry destination_updated_at_changed "$before" - local after=$(destination_updated_at) - log_info "pushed" - else - log_info "nothing to push" - fi + cd $TMPDIR/destination + git add . + if git commit -m 'cascading-pr update'; then + local before=$(destination_updated_at) + sleep 1 # the resolution of the update time is one second + git push --force ${remote} prbranch:$branch + git rev-parse HEAD >../destination.sha + retry destination_updated_at_changed "$before" + local after=$(destination_updated_at) + log_info "pushed" + else + log_info "nothing to push" + fi ) } @@ -260,23 +260,23 @@ function wait_destination_ci() { } function upsert_fork() { - if repo_curl ${options[destination_repo]} api_json ${options[destination_fork_api]} > $TMPDIR/fork.json 2> /dev/null ; then - if test "$(jq --raw-output .fork < $TMPDIR/fork.json)" != true ; then - log_error "the destination fork already exists but is not a fork ${options[destination_fork]}" - return 1 - fi - local forked_from_repo=$(jq --raw-output .parent.full_name < $TMPDIR/fork.json) - if test "$forked_from_repo" != "${options[destination_repo]}" ; then - log_error "${options[destination_fork]} must be a fork of ${options[destination_repo]} but is a fork of $forked_from_repo instead" - return 1 - fi + if repo_curl ${options[destination_repo]} api_json ${options[destination_fork_api]} >$TMPDIR/fork.json 2>/dev/null; then + if test "$(jq --raw-output .fork <$TMPDIR/fork.json)" != true; then + log_error "the destination fork already exists but is not a fork ${options[destination_fork]}" + return 1 + fi + local forked_from_repo=$(jq --raw-output .parent.full_name <$TMPDIR/fork.json) + if test "$forked_from_repo" != "${options[destination_repo]}"; then + log_error "${options[destination_fork]} must be a fork of ${options[destination_repo]} but is a fork of $forked_from_repo instead" + return 1 + fi else - local fork_owner=$(owner ${options[destination_fork_repo]}) - local data="{}" - if repo_curl ${options[destination_repo]} api_json ${options[destination_url]}/api/v1/orgs/${fork_owner} >& /dev/null ; then - data='{"organization":"'$fork_owner'"}' - fi - repo_curl ${options[destination_repo]} api_json --data "$data" ${options[destination_url]}/api/v1/repos/${options[destination_repo]}/forks + local fork_owner=$(owner ${options[destination_fork_repo]}) + local data="{}" + if repo_curl ${options[destination_repo]} api_json ${options[destination_url]}/api/v1/orgs/${fork_owner} >&/dev/null; then + data='{"organization":"'$fork_owner'"}' + fi + repo_curl ${options[destination_repo]} api_json --data "$data" ${options[destination_url]}/api/v1/repos/${options[destination_repo]}/forks fi } @@ -297,41 +297,41 @@ function checkout() { # fork # local head_remote=origin - if ${options[destination_is_fork]} ; then - upsert_fork - git_remote destination fork ${options[destination_fetch_fork]} - head_remote=fork + if ${options[destination_is_fork]}; then + upsert_fork + git_remote destination fork ${options[destination_fetch_fork]} + head_remote=fork fi git_reset_branch destination $head_remote "${options[destination_head]}" } function update() { ( - local update=${options[update]} - if ! [[ "$update" =~ ^/ ]] ; then - local d - if $(origin_has_pr) && $(pr_from_fork origin); then - local default_branch=$(default_branch origin) - log_info "PR is from a forked repository, using the default branch $default_branch to obtain the update script" - d=$TMPDIR/update - git -C $TMPDIR/origin worktree add $d $default_branch - else - d=$TMPDIR/origin - fi - update=$d/$update - fi - cd $TMPDIR - local origin_info - if $(origin_has_pr); then - origin_info=$TMPDIR/origin-pr.json - else - origin_info="${options[origin_ref]}" - fi - $update $TMPDIR/destination $TMPDIR/destination-pr.json $TMPDIR/origin $origin_info + local update=${options[update]} + if ! [[ "$update" =~ ^/ ]]; then + local d + if $(origin_has_pr) && $(pr_from_fork origin); then + local default_branch=$(default_branch origin) + log_info "PR is from a forked repository, using the default branch $default_branch to obtain the update script" + d=$TMPDIR/update + git -C $TMPDIR/origin worktree add $d $default_branch + else + d=$TMPDIR/origin + fi + update=$d/$update + fi + cd $TMPDIR + local origin_info + if $(origin_has_pr); then + origin_info=$TMPDIR/origin-pr.json + else + origin_info="${options[origin_ref]}" + fi + $update $TMPDIR/destination $TMPDIR/destination-pr.json $TMPDIR/origin $origin_info ) local remote_head=origin - if ${options[destination_is_fork]} ; then - remote_head=fork + if ${options[destination_is_fork]}; then + remote_head=fork fi push $remote_head ${options[destination_head]} } @@ -340,15 +340,15 @@ function set_git_url() { local direction=$1 name=$2 repo=$3 local token=${options[${direction}_token]} - if [[ "$token" =~ ^@ ]] ; then - local file=${token##@} - ( - echo -n ${options[${direction}_scheme]}://any: - cat $file - echo @${options[${direction}_host_port]}/$repo - ) > $TMPDIR/$direction.git-credentials + if [[ "$token" =~ ^@ ]]; then + local file=${token##@} + ( + echo -n ${options[${direction}_scheme]}://any: + cat $file + echo @${options[${direction}_host_port]}/$repo + ) >$TMPDIR/$direction.git-credentials else - echo ${options[${direction}_scheme]}://any:${options[${direction}_token]}@${options[${direction}_host_port]}/$repo > $TMPDIR/$direction.git-credentials + echo ${options[${direction}_scheme]}://any:${options[${direction}_token]}@${options[${direction}_host_port]}/$repo >$TMPDIR/$direction.git-credentials fi options[$name]=${options[${direction}_scheme]}://${options[${direction}_host_port]}/$repo } @@ -357,8 +357,8 @@ function fork_sanity_check() { local fork_repo=${options[destination_fork_repo]} local repo=${options[destination_repo]} if test "$(repository $fork_repo)" != "$(repository $repo)"; then - echo "$repo and its fork $fork_repo must have the same repository name (see https://codeberg.org/forgejo/forgejo/issues/1707)" - return 1 + echo "$repo and its fork $fork_repo must have the same repository name (see https://codeberg.org/forgejo/forgejo/issues/1707)" + return 1 fi } @@ -382,12 +382,12 @@ function finalize_options() { set_destination_head if test "${options[destination_fork_repo]}"; then - fork_sanity_check - options[destination_is_fork]=true - set_git_url destination destination_fetch_fork ${options[destination_fork_repo]} - options[destination_fork_api]=${options[destination_url]}/api/v1/repos/${options[destination_fork_repo]} + fork_sanity_check + options[destination_is_fork]=true + set_git_url destination destination_fetch_fork ${options[destination_fork_repo]} + options[destination_fork_api]=${options[destination_url]}/api/v1/repos/${options[destination_fork_repo]} else - options[destination_is_fork]=false + options[destination_is_fork]=false fi : ${options[close]:=false} @@ -398,9 +398,9 @@ function run() { repo_login destination if $(origin_has_pr); then - run_origin_pr + run_origin_pr else - run_origin_ref + run_origin_ref fi } @@ -409,21 +409,21 @@ function run_origin_ref() { checkout update local sha=$(sha_pushed destination) - if test "$sha" ; then - upsert_destination_pr - local status - if wait_destination_ci "$sha" ; then - log_info "cascade PR status successful" - status=0 - else - log_info "cascade PR status failed" - status=1 - fi - if "${options[close]}" ; then - log_info "close the cascade PR and remove the branch" - close_pr - fi - return $status + if test "$sha"; then + upsert_destination_pr + local status + if wait_destination_ci "$sha"; then + log_info "cascade PR status successful" + status=0 + else + log_info "cascade PR status failed" + status=1 + fi + if "${options[close]}"; then + log_info "close the cascade PR and remove the branch" + close_pr + fi + return $status fi } @@ -431,128 +431,128 @@ function run_origin_pr() { local state=$(pr_state origin) case "$state" in - open) - log_info "PR is open, update or create the cascade branch and PR" - checkout - update - local sha=$(sha_pushed destination) - if test "$sha" ; then - upsert_destination_pr - comment_origin_pr - wait_destination_ci "$sha" - fi - ;; - closed) - if "$(pr_merged origin)"; then - if "${options[close]}" ; then - log_info "PR is merged, close the cascade PR and remove the branch" - close_pr - else - log_info "PR was merged, update the cascade PR" - pr_get origin - pr_get destination - checkout - update - fi - else - log_info "PR is closed, close the cascade PR and remove the branch" - close_pr - fi - ;; - *) - log_info "state '$state', do nothing" - ;; + open) + log_info "PR is open, update or create the cascade branch and PR" + checkout + update + local sha=$(sha_pushed destination) + if test "$sha"; then + upsert_destination_pr + comment_origin_pr + wait_destination_ci "$sha" + fi + ;; + closed) + if "$(pr_merged origin)"; then + if "${options[close]}"; then + log_info "PR is merged, close the cascade PR and remove the branch" + close_pr + else + log_info "PR was merged, update the cascade PR" + pr_get origin + pr_get destination + checkout + update + fi + else + log_info "PR is closed, close the cascade PR and remove the branch" + close_pr + fi + ;; + *) + log_info "state '$state', do nothing" + ;; esac } function main() { while true; do - case "$1" in - --verbose) - shift - verbose - ;; - --debug) - shift - debug - ;; - --origin-url) - shift - options[origin_url]=$1 - shift - ;; - --origin-repo) - shift - options[origin_repo]=$1 - shift - ;; - --origin-token) - shift - options[origin_token]=$1 - shift - ;; - --origin-pr) - shift - options[origin_pr]=$1 - shift - ;; - --origin-ref) - shift - options[origin_ref]=$1 - shift - ;; - --destination-url) - shift - options[destination_url]=$1 - shift - ;; - --destination-repo) - shift - options[destination_repo]=$1 - shift - ;; - --destination-fork-repo) - shift - options[destination_fork_repo]=$1 - shift - ;; - --destination-token) - shift - options[destination_token]=$1 - shift - ;; - --destination-branch) - shift - options[destination_branch]=$1 - shift - ;; - --update) - shift - options[update]=$1 - shift - ;; - --prefix) - shift - options[prefix]=$1 - shift - ;; - --close) - shift - options[close]=$1 - shift - ;; - *) - finalize_options - "${1:-run}" - return 0 - ;; - esac + case "$1" in + --verbose) + shift + verbose + ;; + --debug) + shift + debug + ;; + --origin-url) + shift + options[origin_url]=$1 + shift + ;; + --origin-repo) + shift + options[origin_repo]=$1 + shift + ;; + --origin-token) + shift + options[origin_token]=$1 + shift + ;; + --origin-pr) + shift + options[origin_pr]=$1 + shift + ;; + --origin-ref) + shift + options[origin_ref]=$1 + shift + ;; + --destination-url) + shift + options[destination_url]=$1 + shift + ;; + --destination-repo) + shift + options[destination_repo]=$1 + shift + ;; + --destination-fork-repo) + shift + options[destination_fork_repo]=$1 + shift + ;; + --destination-token) + shift + options[destination_token]=$1 + shift + ;; + --destination-branch) + shift + options[destination_branch]=$1 + shift + ;; + --update) + shift + options[update]=$1 + shift + ;; + --prefix) + shift + options[prefix]=$1 + shift + ;; + --close) + shift + options[close]=$1 + shift + ;; + *) + finalize_options + "${1:-run}" + return 0 + ;; + esac done } dependencies -if echo "${@}" | grep --quiet -e '--debug' ; then +if echo "${@}" | grep --quiet -e '--debug'; then main "${@}" else stash_debug "${@}" diff --git a/forgejo-curl.sh b/forgejo-curl.sh index 3397683..ef3d996 100755 --- a/forgejo-curl.sh +++ b/forgejo-curl.sh @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT VERSION=1.0.0 -SELF_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" VERBOSE=false DEBUG=false : ${EXIT_ON_ERROR:=true} @@ -28,8 +28,8 @@ function log_error() { } function log_verbose() { - if $VERBOSE ; then - log "$@" + if $VERBOSE; then + log "$@" fi } @@ -39,10 +39,10 @@ function log_info() { function fatal_error() { log_error "$@" - if $EXIT_ON_ERROR ; then - exit 1 + if $EXIT_ON_ERROR; then + exit 1 else - return 1 + return 1 fi } @@ -66,41 +66,44 @@ function login_api() { local user="$1" password="$2" token="$3" scopes="${4:-[\"all\"]}" url="$5" dot_ensure - if test -s $DOT/token ; then - log_info "already logged in, ignored" - return + if test -s $DOT/token; then + log_info "already logged in, ignored" + return fi - if test -z "$token" ; then - log_verbose curl -sS -X DELETE --user "${user}:${password}" "${url}/api/v1/users/$user/tokens/${TOKEN_NAME}" -o /dev/null -w "%{http_code}" - local basic="${user:-unknown}:${password:-unknown}" - local status=$(curl -sS -X DELETE --user "${basic}" "${url}/api/v1/users/$user/tokens/${TOKEN_NAME}" -o /dev/null -w "%{http_code}") - if test "${status}" != 404 -a "${status}" != 204 ; then - fatal_error permission denied, the user or password are probably incorrect, try again with --verbose - return 1 - fi - token=$(client $HEADER_JSON --user "${basic}" --data-raw '{"name":"'${TOKEN_NAME}'","scopes":'${scopes}'}' "${url}/api/v1/users/${user}/tokens" | jq --raw-output .sha1) + if test -z "$token"; then + log_verbose curl -sS -X DELETE --user "${user}:${password}" "${url}/api/v1/users/$user/tokens/${TOKEN_NAME}" -o /dev/null -w "%{http_code}" + local basic="${user:-unknown}:${password:-unknown}" + local status=$(curl -sS -X DELETE --user "${basic}" "${url}/api/v1/users/$user/tokens/${TOKEN_NAME}" -o /dev/null -w "%{http_code}") + if test "${status}" != 404 -a "${status}" != 204; then + fatal_error permission denied, the user or password are probably incorrect, try again with --verbose + return 1 + fi + token=$(client $HEADER_JSON --user "${basic}" --data-raw '{"name":"'${TOKEN_NAME}'","scopes":'${scopes}'}' "${url}/api/v1/users/${user}/tokens" | jq --raw-output .sha1) fi - if [[ "$token" =~ ^@ ]] ; then - cp "${token##@}" $DOT/token + if [[ "$token" =~ ^@ ]]; then + cp "${token##@}" $DOT/token else - echo "$token" > $DOT/token + echo "$token" >$DOT/token fi - ( echo -n "Authorization: token " ; cat $DOT/token ) > $DOT/header-token + ( + echo -n "Authorization: token " + cat $DOT/token + ) >$DOT/header-token # # Verify it works # local status=$(api -w "%{http_code}" -o /dev/null "${url}/api/v1/user") - if test "${status}" != 200 ; then - fatal_error "${url}/api/v1/user returns status code '${status}', the token is invalid, $0 logout and login again" - return 1 + if test "${status}" != 200; then + fatal_error "${url}/api/v1/user returns status code '${status}', the token is invalid, $0 logout and login again" + return 1 fi } function client() { log_verbose curl --cookie $DOT/cookies -f -sS "$@" - if ! curl --cookie $DOT/cookies -f -sS "$@" ; then - fatal_error + if ! curl --cookie $DOT/cookies -f -sS "$@"; then + fatal_error fi } @@ -111,17 +114,17 @@ function web() { function client_update_cookies() { log_verbose curl --cookie-jar $DOT/cookies --cookie $DOT/cookies -w "%{http_code}" -f -sS "$@" local status=$(curl --cookie-jar $DOT/cookies --cookie $DOT/cookies -w "%{http_code}" -f -sS "$@") - if ! test "${status}" = 200 -o "${status}" = 303 ; then - fatal_error + if ! test "${status}" = 200 -o "${status}" = 303; then + fatal_error fi } function login_client() { local user="$1" password="$2" url="$3" - if test -z "$password" ; then - log_verbose "no password, web will not be authenticated" - return + if test -z "$password"; then + log_verbose "no password, web will not be authenticated" + return fi dot_ensure @@ -138,17 +141,17 @@ function login_client() { # client_update_cookies -o /dev/null "${url}/user/login" local csrf=$(sed -n -e '/csrf/s/.*csrf\t//p' $DOT/cookies) - echo "X-Csrf-Token: $csrf" > $DOT/header-csrf + echo "X-Csrf-Token: $csrf" >$DOT/header-csrf # # Verify it works # local status=$(web -o /dev/null -w "%{http_code}" "${url}/user/settings") - if test "${status}" != 200 ; then - grep -C 1 flash-error $DOT/login.html - if ${DEBUG} ; then - cat $DOT/login.html - fi - fatal_error login failed, the user or password are probably incorrect, try again with --verbose + if test "${status}" != 200; then + grep -C 1 flash-error $DOT/login.html + if ${DEBUG}; then + cat $DOT/login.html + fi + fatal_error login failed, the user or password are probably incorrect, try again with --verbose fi } @@ -160,12 +163,11 @@ function login() { function logout() { rm -f $DOT/* - if test -d $DOT ; then - rmdir $DOT + if test -d $DOT; then + rmdir $DOT fi } - function usage() { cat >&2 <& /dev/null || true + forgejo-curl.sh api_json -X DELETE ${options[url]}/api/v1/admin/users/$username?purge=true >&/dev/null || true forgejo-curl.sh api_json --data '{"username":"'$username'","email":"'$email'","password":"'${options[password]}'","must_change_password":false}' ${options[url]}/api/v1/admin/users user_login $username } @@ -64,8 +64,8 @@ function close_pull_request() { local repo=$1 log_verbose "close all pull requests in user1/$repo" - forgejo-curl.sh api_json ${options[url]}/api/v1/repos/user1/${repo}/pulls | jq --raw-output '.[] | .number' | while read pr ; do - forgejo-curl.sh api_json -X PATCH --data '{"state":"closed"}' ${options[url]}/api/v1/repos/user1/${repo}/issues/$pr + forgejo-curl.sh api_json ${options[url]}/api/v1/repos/user1/${repo}/pulls | jq --raw-output '.[] | .number' | while read pr; do + forgejo-curl.sh api_json -X PATCH --data '{"state":"closed"}' ${options[url]}/api/v1/repos/user1/${repo}/issues/$pr done } @@ -73,8 +73,8 @@ function merge_pull_request() { local repo=$1 log_verbose "merge all pull requests in user1/$repo" - forgejo-curl.sh api_json ${options[url]}/api/v1/repos/user1/${repo}/pulls | jq --raw-output '.[] | .number' | while read pr ; do - forgejo-curl.sh api_json --data '{"Do":"merge"}' ${options[url]}/api/v1/repos/user1/${repo}/pulls/$pr/merge + forgejo-curl.sh api_json ${options[url]}/api/v1/repos/user1/${repo}/pulls | jq --raw-output '.[] | .number' | while read pr; do + forgejo-curl.sh api_json --data '{"Do":"merge"}' ${options[url]}/api/v1/repos/user1/${repo}/pulls/$pr/merge done } @@ -120,46 +120,45 @@ function create_branch1() { local owner=$1 repo=$2 modify=$3 log_verbose "(re)create branch1 in $owner/$repo" - forgejo-curl.sh api_json -X DELETE ${options[url]}/api/v1/repos/$owner/${repo}/branches/branch1 >& /dev/null || true + forgejo-curl.sh api_json -X DELETE ${options[url]}/api/v1/repos/$owner/${repo}/branches/branch1 >&/dev/null || true forgejo-curl.sh api_json --data '{"new_branch_name":"branch1"}' ${options[url]}/api/v1/repos/$owner/${repo}/branches ( - cd $TMPDIR - rm -fr ${repo} - git clone -b branch1 http://user1:admin1234@${options[host_port]}/$owner/${repo} - cd ${repo} - echo CONTENT > README - if test "$modify" ; then - log_verbose "modify branch1 in $owner/$repo with $modify" - $modify - fi - git config user.email root@example.com - git config user.name username - git add . - git commit -m 'update' - git push origin branch1 - git rev-parse HEAD > ../${owner}-${repo}.sha + cd $TMPDIR + rm -fr ${repo} + git clone -b branch1 http://user1:admin1234@${options[host_port]}/$owner/${repo} + cd ${repo} + echo CONTENT >README + if test "$modify"; then + log_verbose "modify branch1 in $owner/$repo with $modify" + $modify + fi + git config user.email root@example.com + git config user.name username + git add . + git commit -m 'update' + git push origin branch1 + git rev-parse HEAD >../${owner}-${repo}.sha ) } function delete_pull_requests() { local owner=$1 repo=$2 - forgejo-curl.sh api_json ${options[url]}/api/v1/repos/$owner/${repo}/pulls | jq --raw-output '.[] | .number' | while read pr ; do - forgejo-curl.sh api_json -X DELETE ${options[url]}/api/v1/repos/$owner/${repo}/issues/$pr + forgejo-curl.sh api_json ${options[url]}/api/v1/repos/$owner/${repo}/pulls | jq --raw-output '.[] | .number' | while read pr; do + forgejo-curl.sh api_json -X DELETE ${options[url]}/api/v1/repos/$owner/${repo}/issues/$pr done } - function create_pull_request() { local baseowner=$1 headowner=$2 repo=$3 local head if test $baseowner == $headowner; then - head=branch1 + head=branch1 else - head=$headowner:branch1 + head=$headowner:branch1 fi - cat > $TMPDIR/data <$TMPDIR/data < $file + expr $value - 1 >$file echo RESULT - if test $value -gt 0 ; then - return 1 + if test $value -gt 0; then + return 1 else - return 0 + return 0 fi } @@ -201,43 +200,43 @@ function unit_retry() { # # Succeeds after two tries # - echo 2 > $TMPDIR/unit_retry_two - if ! RETRY_DELAYS='1 1 1 1' retry unit_retry_fail $two > $TMPDIR/retry.test-result 2> $TMPDIR/retry.test-log ; then - cat $TMPDIR/retry.test-result $TMPDIR/retry.test-log - return 1 + echo 2 >$TMPDIR/unit_retry_two + if ! RETRY_DELAYS='1 1 1 1' retry unit_retry_fail $two >$TMPDIR/retry.test-result 2>$TMPDIR/retry.test-log; then + cat $TMPDIR/retry.test-result $TMPDIR/retry.test-log + return 1 fi test "$(cat $TMPDIR/retry.test-result)" = "RESULT" - if test "$(grep -c '^waiting 1 unit_retry_fail' $TMPDIR/retry.test-log)" != 2 ; then - cat $TMPDIR/retry.test-log - return 1 + if test "$(grep -c '^waiting 1 unit_retry_fail' $TMPDIR/retry.test-log)" != 2; then + cat $TMPDIR/retry.test-log + return 1 fi # # Succeeds immediately # - if ! RETRY_DELAYS='1' retry unit_retry_fail $two > $TMPDIR/retry.test-result 2> $TMPDIR/retry.test-log ; then - cat $TMPDIR/retry.test-result $TMPDIR/retry.test-log - return 1 + if ! RETRY_DELAYS='1' retry unit_retry_fail $two >$TMPDIR/retry.test-result 2>$TMPDIR/retry.test-log; then + cat $TMPDIR/retry.test-result $TMPDIR/retry.test-log + return 1 fi test "$(cat $TMPDIR/retry.test-result)" = "RESULT" - if test "$(grep -c 'waiting 1 unit_retry_fail' $TMPDIR/retry.test-log)" != 0 ; then - cat $TMPDIR/retry.test-log - return 1 + if test "$(grep -c 'waiting 1 unit_retry_fail' $TMPDIR/retry.test-log)" != 0; then + cat $TMPDIR/retry.test-log + return 1 fi # # Verify the output is only the output of the last run and is not polluted by # unrelated output # - echo 2 > $TMPDIR/unit_retry_two + echo 2 >$TMPDIR/unit_retry_two test "$(RETRY_DELAYS='1 1 1' retry unit_retry_fail $two)" = "RESULT" # # Fails after one try # - echo 2 > $TMPDIR/unit_retry_two - if RETRY_DELAYS='1' retry unit_retry_fail $two > $TMPDIR/retry.test-result 2> $TMPDIR/retry.test-log ; then - cat $TMPDIR/retry.test-result $TMPDIR/retry.test-log - return 1 + echo 2 >$TMPDIR/unit_retry_two + if RETRY_DELAYS='1' retry unit_retry_fail $two >$TMPDIR/retry.test-result 2>$TMPDIR/retry.test-log; then + cat $TMPDIR/retry.test-result $TMPDIR/retry.test-log + return 1 fi grep --quiet 'retry failed' $TMPDIR/retry.test-log } @@ -323,11 +322,11 @@ function create_and_close() { } function taint_update() { - if ! test -f upgraded ; then - echo upgraded file not found - return 1 + if ! test -f upgraded; then + echo upgraded file not found + return 1 fi - echo 'TAINTED' > upgraded + echo 'TAINTED' >upgraded } function create_from_origin_fork_and_close() { @@ -423,20 +422,20 @@ function run() { shift echo "Start running $fun ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - if $DEBUG ; then - $fun "$@" + if $DEBUG; then + $fun "$@" else - mkdir -p $TMPDIR - > $TMPDIR/$fun.out - tail --follow $TMPDIR/$fun.out | sed --unbuffered -n -e "/^$PREFIX/s/^$PREFIX //p" & - pid=$! - if ! ${BASH_SOURCE[0]} --debug ${options[args]} $fun "$@" >& $TMPDIR/$fun.out ; then - kill $pid - cat $TMPDIR/$fun.out - echo Failure running $fun - return 1 - fi - kill $pid + mkdir -p $TMPDIR + >$TMPDIR/$fun.out + tail --follow $TMPDIR/$fun.out | sed --unbuffered -n -e "/^$PREFIX/s/^$PREFIX //p" & + pid=$! + if ! ${BASH_SOURCE[0]} --debug ${options[args]} $fun "$@" >&$TMPDIR/$fun.out; then + kill $pid + cat $TMPDIR/$fun.out + echo Failure running $fun + return 1 + fi + kill $pid fi echo "Success running $fun ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" } @@ -467,11 +466,11 @@ function run_tests() { function finalize_options() { if test -f $DIR/forgejo-ip; then - : ${options[host_port]:=$(cat $DIR/forgejo-ip):3000} + : ${options[host_port]:=$(cat $DIR/forgejo-ip):3000} fi options[url]=http://${options[host_port]} if test -f $DIR/forgejo-token; then - : ${options[token]:=$(cat $DIR/forgejo-token)} + : ${options[token]:=$(cat $DIR/forgejo-token)} fi options[password]=admin1234 } @@ -480,39 +479,39 @@ function main() { local command=run while true; do - case "$1" in - --verbose) - shift - verbose - ;; - --debug) - shift - debug - ;; - --host_port) - shift - options[args]="${options[args]} --host_port $1" - options[host_port]=$1 - shift - ;; - --url) - shift - options[args]="${options[args]} --url $1" - options[url]=$1 - shift - ;; - --token) - shift - options[args]="${options[args]} --token $1" - options[token]=$1 - shift - ;; - *) - finalize_options - "${1:-run_tests}" "${@:2}" - return 0 - ;; - esac + case "$1" in + --verbose) + shift + verbose + ;; + --debug) + shift + debug + ;; + --host_port) + shift + options[args]="${options[args]} --host_port $1" + options[host_port]=$1 + shift + ;; + --url) + shift + options[args]="${options[args]} --url $1" + options[url]=$1 + shift + ;; + --token) + shift + options[args]="${options[args]} --token $1" + options[token]=$1 + shift + ;; + *) + finalize_options + "${1:-run_tests}" "${@:2}" + return 0 + ;; + esac done }