scripts/pusher
2023-03-08 18:44:03 +01:00

190 lines
4.2 KiB
Bash
Executable File

#!/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] [<module> ...]
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"