From 360c63e4460db334ea28721261e2b98856b8bafa Mon Sep 17 00:00:00 2001 From: Ludwig Nussel Date: Thu, 23 Feb 2023 17:05:40 +0100 Subject: [PATCH] update pusher --- pusher | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 178 insertions(+), 22 deletions(-) diff --git a/pusher b/pusher index dcdde22..c86df16 100755 --- a/pusher +++ b/pusher @@ -1,36 +1,192 @@ #!/bin/bash +set -e + +# config options +PR_SRC_USER= +BASE_BRANCH="main" +PR_PROJECT= +PR_REPO= +TOKEN= +PUSH_REMOTE="origin" + +# command line only +verbose=0 +cfg_file= +dryrun= +show_status= + +################### +push_url= +did_push= + tmpfile=$(mktemp pusher.XXXXXX) cleanup() { - rm -f "$tmpfile" + echo rm -f "$tmpfile" } trap cleanup EXIT -. .settings +helpandquit() +{ + cat <<-EOF + Usage: $0 [OPTIONS] [ ...] + OPTIONS: + -h help screen + EOF + exit 0 +} -needed=(PUSH_URL PR_SRC_USER PR_TARGET TOKEN) -for i in "${needed[@]}"; do - eval test -n "\$$i" || { echo "The following settings are mandatory: ${needed[*]}"; exit 1; } +log_info() +{ + [ "$verbose" -gt 0 ] || return 0 + echo "$@" +} + +makedict() +{ + local dict="$1" + shift + mapfile -t a < <("$@") + for k in "${a[@]}"; do + eval "$dict"["$k"]=1 + done +} + +request_pulls() +{ + curl -s -f "$pr_target?state=open" \ + -H "accept: application/json" \ + -H "Authorization: token $TOKEN" \ + -H "Content-Type: application/json" +} + +getopttmp=$(getopt -o hc:v --long help,single,branch:,config:,date:,remote:,status,verbose,dry -n "${0##*/}" -- "$@") +eval set -- "$getopttmp" + +while true ; do + case "$1" in + -h|--help) helpandquit; shift ;; + -v|--verbose) verbose=$((++verbose)); shift ;; + -c|--config) cfg_file="$2"; shift 2 ;; + --status) show_status=1; shift ;; + --dry) dryrun=1; shift ;; + --) shift ; break ;; + *) echo "Internal error!" ; exit 1 ;; + esac done -declare -A commits +declare -A modules +for m in "$@"; do + modules["$m"]=1 +done -for m in "${!commits[@]}"; do - if git send-pack --force "$PUSH_URL" "${commits[$m]}:refs/heads/update_$m"; then - #https://github.com/go-gitea/gitea/issues/18842 - if curl -s -f "$PR_TARGET" \ - -H "accept: application/json" \ - -H "Authorization: token $TOKEN" \ - -H "Content-Type: application/json" \ - -d "{ \"base\": \"main\", \"head\": \"$PR_SRC_USER:update_$m\", \"title\": \"Update $m\"}" > "$tmpfile"; then - prid=$(jq .id < "$tmpfile") - echo "filed pr #$prid for $m" - else - echo "failed to file pr for $m" - jq .message < "$tmpfile" - fi +# shellcheck disable=SC1090 +. "${cfg_file:-.settings}" + +needed=(PR_SRC_USER PR_PROJECT PR_REPO TOKEN) +for i in "${needed[@]}"; do + eval test -n "\"\$$i\"" || { echo "The following settings are mandatory: ${needed[*]}"; exit 1; } +done + +push_url="$(git config --get remote."$PUSH_REMOTE".url)" +pr_target="https://gitea.opensuse.org/api/v1/repos/$PR_PROJECT/$PR_REPO/pulls" + +# push queue +declare -A pq +while read -r cid _c ref; do + m="${ref#refs/pq/}" + pq["$m"]="$cid" +done < <(git for-each-ref 'refs/pq/*') +# request queue +declare -A rq +while read -r cid _c ref; do + m="${ref#refs/remotes/"$PUSH_REMOTE"/update_}" + [ "$m" != "$ref" ] || continue + rq["$m"]="$cid" +done < <(git for-each-ref "refs/remotes/$PUSH_REMOTE/*") + +declare -A pr +while read -r _id cid ref; do + m="${ref#update_}" + pr["$m"]="$cid" + log_info "pr $m: $cid" +done < <(request_pulls | jq ".[]|select(.head.repo.owner.login == \"$PR_SRC_USER\")|[((.number|tostring)), .head.sha, .head.ref]|join(\" \")" -r) + +log_info "to push: ${!pq[*]}" +log_info "remote: ${!rq[*]}" + +if [ -n "$show_status" ]; then + if [ -n "${!pq[*]}" ]; then + echo "Push queue:" + for m in "${!pq[@]}"; do + [ "${pq[$m]}" = "${rq[$m]}" ] && continue + echo " ${pq[$m]} $m" + done + fi + if [ -n "${!rq[*]}" ]; then + echo "Request queue:" + for m in "${!rq[@]}"; do + [ "${rq[$m]}" = "${pr[$m]}" ] && continue + echo " ${rq[$m]} $m" + done + fi + if [ -n "${!pr[*]}" ]; then + echo "Requests:" + for m in "${!pr[@]}"; do + echo " ${pr[$m]} $m" + done + fi + exit 0 +fi + +ret=0 +for m in "${!pq[@]}"; do + [ "${#modules[@]}" -eq 0 -o -n "${modules[$m]}" ] || continue + cid="${pq[$m]}" + [ -n "$cid" ] + if [ -n "${rq[$m]}" ] && [ "$cid" = "${rq[$m]}" ]; then + log_info "$m already pushed" else - echo "failed to push $m update" >&2 - jq .message < "$tmpfile" + log_info "pushing $m: $cid" + if ! git send-pack --force "$push_url" "${cid}:refs/heads/update_$m"; then + echo "failed to push $m update" >&2 + ret=1 + continue + fi + did_push=1 + fi + + if [ -n "${pr[$m]}" ]; then + if [ "$cid" = "${pr[$m]}" ]; then + log_info "pr for $m exists, no update" + else + echo "Warning: exiting pr for $m with different content" + fi + continue + fi + + title=$(git log -1 "--format=%s" "$cid") + head="update_$m" + [ "$PR_PROJECT" = "$PR_SRC_USER" ] || head="$PR_SRC_USER:$head" + log_info "Filing pr '$title': $cid at $pr_target" + [ -z "$dryrun" ] || continue + #https://github.com/go-gitea/gitea/issues/18842 + if curl -s -f "$pr_target" \ + -H "accept: application/json" \ + -H "Authorization: token $TOKEN" \ + -H "Content-Type: application/json" \ + -d "{ \"base\": \"$BASE_BRANCH\", \"head\": \"$head\", \"title\": \"$title\"}" > "$tmpfile"; then + prid=$(jq -r .number < "$tmpfile") + echo "filed pr #$prid for $m" + else + echo "failed to file pr for $m" + jq -r .message < "$tmpfile" fi done + +if [ -n "$did_push" ]; then + log_info "Updating remote $PUSH_REMOTE" + git remote update "$PUSH_REMOTE" > /dev/null +fi + +exit "$ret"