#!/bin/bash set -e # config options # shellcheck disable=SC2034 declare -A keep 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" } trap cleanup EXIT helpandquit() { cat <<-EOF Usage: $0 [OPTIONS] [ ...] OPTIONS: -h help screen EOF exit 0 } log_info() { [ "$verbose" -gt 0 ] || return 0 echo "$@" } 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 modules for m in "$@"; do modules["$m"]=1 done # 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 echo "# local remote pr package" if [ "${#modules[@]}" -eq 0 ]; then for m in "${!pq[@]}" "${!rq[@]}" "${!pr[@]}"; do modules["$m"]=1 done fi for m in "${!modules[@]}"; do a=${pq[$m]:0:7} b=${rq[$m]:0:7} c=${pr[$m]:0:7} echo "${a:- } ${b:- } ${c:- } $m" done 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 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 for m in "${!rq[@]}"; do [ "${#modules[@]}" -eq 0 -o -n "${modules[$m]}" ] || continue if [ -z "${pq[$m]}" ]; then log_info "delete remote request $m" if ! git send-pack --force "$push_url" ":refs/heads/update_$m"; then echo "failed to push $m update" >&2 ret=1 continue fi did_push=1 fi done if [ -n "$did_push" ]; then log_info "Updating remote $PUSH_REMOTE" git remote update -p "$PUSH_REMOTE" > /dev/null fi exit "$ret"