mirror of
https://code.forgejo.org/actions/cascading-pr.git
synced 2025-06-28 04:43:44 +00:00
forked origin requires a forked destination
Fixes: https://code.forgejo.org/actions/cascading-pr/issues/10
This commit is contained in:
parent
277569106a
commit
dd5427bc63
3 changed files with 141 additions and 32 deletions
153
cascading-pr.sh
153
cascading-pr.sh
|
@ -64,21 +64,6 @@ EOF
|
|||
log_info "comment added to $(pr_url origin)"
|
||||
}
|
||||
|
||||
function upsert_destination_branch() {
|
||||
if $(exists_branch destination) ; then
|
||||
log_info "branch ${options[destination_head]} already exists"
|
||||
return
|
||||
fi
|
||||
cat > $TMPDIR/data <<EOF
|
||||
{
|
||||
"new_branch_name":"${options[destination_head]}",
|
||||
"old_branch_name":"${options[destination_base]}"
|
||||
}
|
||||
EOF
|
||||
repo_curl ${options[destination_repo]} api_json --data @$TMPDIR/data ${options[destination_api]}/branches
|
||||
log_info "branch ${options[destination_head]} created"
|
||||
}
|
||||
|
||||
function pr_destination_title() {
|
||||
echo "cascading-pr from ${options[origin_url]}/${options[origin_repo]}/pulls/${options[origin_pr]}"
|
||||
}
|
||||
|
@ -94,13 +79,18 @@ function upsert_destination_pr() {
|
|||
log_info "an open PR already exists $url"
|
||||
return
|
||||
fi
|
||||
if ${options[destination_is_fork]} ; then
|
||||
head="$(owner ${options[destination_fork_repo]}):${options[destination_head]}"
|
||||
else
|
||||
head=${options[destination_head]}
|
||||
fi
|
||||
local title=$(pr_destination_title)
|
||||
cat > $TMPDIR/data <<EOF
|
||||
{
|
||||
"title":"$(pr_destination_title)",
|
||||
"body":"$(pr_destination_body)",
|
||||
"base":"${options[destination_base]}",
|
||||
"head":"${options[destination_head]}"
|
||||
"head":"$head"
|
||||
}
|
||||
EOF
|
||||
retry repo_curl ${options[destination_repo]} api_json --data @$TMPDIR/data ${options[destination_api]}/pulls > $TMPDIR/destination-pr.json
|
||||
|
@ -165,26 +155,55 @@ function pr_from_fork() {
|
|||
pr $1 | jq --raw-output .head.repo.fork
|
||||
}
|
||||
|
||||
function upsert_clone() {
|
||||
local direction=$1 ref="$2" clone=$3
|
||||
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 $clone $TMPDIR/$direction
|
||||
git -c credential.helper="store --file=$TMPDIR/$direction.git-credentials" clone $url $TMPDIR/$direction
|
||||
fi
|
||||
(
|
||||
cd $TMPDIR/$direction
|
||||
if [[ "$ref" =~ ^refs/ ]] ; then
|
||||
git fetch origin +$ref:$ref
|
||||
else
|
||||
ref=origin/$ref
|
||||
fi
|
||||
git checkout -b $direction $ref
|
||||
git config credential.helper "store --file=$TMPDIR/$direction.git-credentials"
|
||||
git config user.email cascading-pr@example.com
|
||||
git config user.name cascading-pr
|
||||
)
|
||||
}
|
||||
|
||||
function git_checkout() {
|
||||
local direction=$1 ref="$3"
|
||||
local remote=origin
|
||||
|
||||
(
|
||||
cd $TMPDIR/$direction
|
||||
if [[ "$ref" =~ ^refs/ ]] ; then
|
||||
git fetch ${remote} +$ref:$ref
|
||||
else
|
||||
ref=${remote}/$ref
|
||||
fi
|
||||
git checkout -b prbranch $ref
|
||||
)
|
||||
}
|
||||
|
||||
function git_remote() {
|
||||
local direction=$1 remote=$2 url=$3
|
||||
|
||||
(
|
||||
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
|
||||
)
|
||||
}
|
||||
|
||||
function sha_pushed() {
|
||||
local direction=$1
|
||||
if test -f $TMPDIR/$direction.sha ; then
|
||||
|
@ -193,13 +212,13 @@ function sha_pushed() {
|
|||
}
|
||||
|
||||
function push() {
|
||||
local direction=$1 branch=$2 clone=$3
|
||||
local direction=$1 remote=$2 branch=$3
|
||||
|
||||
(
|
||||
cd $TMPDIR/$direction
|
||||
git add .
|
||||
if git commit -m 'cascading-pr update'; then
|
||||
git push --force origin $direction:$branch
|
||||
git push --force ${remote} prbranch:$branch
|
||||
git rev-parse HEAD > ../$direction.sha
|
||||
log_info "pushed"
|
||||
else
|
||||
|
@ -214,9 +233,53 @@ function wait_destination_ci() {
|
|||
wait_success $repo_api $sha
|
||||
}
|
||||
|
||||
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)" != 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)
|
||||
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]})
|
||||
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/${options[destination_repo]}/forks
|
||||
fi
|
||||
}
|
||||
|
||||
function checkout() {
|
||||
#
|
||||
# origin
|
||||
#
|
||||
git_clone origin ${options[origin_clone]}
|
||||
git_checkout origin "${options[origin_head]}"
|
||||
|
||||
#
|
||||
# destination
|
||||
#
|
||||
git_clone destination ${options[destination_clone]}
|
||||
git_checkout destination "${options[destination_base]}"
|
||||
|
||||
#
|
||||
# fork
|
||||
#
|
||||
local head_remote=origin
|
||||
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() {
|
||||
upsert_clone origin "${options[origin_head]}" ${options[origin_clone]}
|
||||
upsert_clone destination "${options[destination_head]}" ${options[destination_clone]}
|
||||
(
|
||||
local update=${options[update]}
|
||||
if ! [[ "$update" =~ ^/ ]] ; then
|
||||
|
@ -234,7 +297,11 @@ function update() {
|
|||
cd $TMPDIR
|
||||
$update $TMPDIR/destination $TMPDIR/destination-pr.json $TMPDIR/origin $TMPDIR/origin-pr.json
|
||||
)
|
||||
push destination ${options[destination_head]} ${options[destination_clone]}
|
||||
local remote_head=origin
|
||||
if ${options[destination_is_fork]} ; then
|
||||
remote_head=fork
|
||||
fi
|
||||
push destination $remote_head ${options[destination_head]}
|
||||
}
|
||||
|
||||
function set_clone() {
|
||||
|
@ -254,12 +321,22 @@ function set_clone() {
|
|||
options[${direction}_clone]=${options[${direction}_scheme]}://${options[${direction}_host_port]}/${options[${direction}_repo]}
|
||||
}
|
||||
|
||||
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
|
||||
fi
|
||||
}
|
||||
|
||||
function finalize_options() {
|
||||
options[origin_api]=${options[origin_url]}/api/v1/repos/${options[origin_repo]}
|
||||
options[origin_scheme]=$(scheme ${options[origin_url]})
|
||||
options[origin_host_port]=$(host_port ${options[origin_url]})
|
||||
set_clone origin
|
||||
options[origin_head]=refs/pull/${options[origin_pr]}/head
|
||||
|
||||
options[destination_api]=${options[destination_url]}/api/v1/repos/${options[destination_repo]}
|
||||
options[destination_scheme]=$(scheme ${options[destination_url]})
|
||||
options[destination_host_port]=$(host_port ${options[destination_url]})
|
||||
|
@ -267,6 +344,14 @@ function finalize_options() {
|
|||
options[destination_base]=${options[destination_branch]}
|
||||
: ${options[prefix]:=${options[origin_repo]}}
|
||||
options[destination_head]=${options[prefix]}-${options[origin_pr]}
|
||||
|
||||
if test "${options[destination_fork_repo]}"; then
|
||||
fork_sanity_check
|
||||
options[destination_is_fork]=true
|
||||
options[destination_fork_api]=${options[destination_url]}/api/v1/repos/${options[destination_fork_repo]}
|
||||
options[destination_is_fork]=false
|
||||
fi
|
||||
|
||||
: ${options[close_merge]:=false}
|
||||
}
|
||||
|
||||
|
@ -279,7 +364,7 @@ function run() {
|
|||
case "$state" in
|
||||
open)
|
||||
log_info "PR is open, update or create the cascade branch and PR"
|
||||
upsert_destination_branch
|
||||
checkout
|
||||
update
|
||||
local sha=$(sha_pushed destination)
|
||||
if test "$sha" ; then
|
||||
|
@ -297,6 +382,7 @@ function run() {
|
|||
log_info "PR was merged, update the cascade PR"
|
||||
pr_get origin
|
||||
pr_get destination
|
||||
checkout
|
||||
update
|
||||
fi
|
||||
else
|
||||
|
@ -351,6 +437,11 @@ function main() {
|
|||
options[destination_repo]=$1
|
||||
shift
|
||||
;;
|
||||
--destination-fork-repo)
|
||||
shift
|
||||
options[destination_fork_repo]=$1
|
||||
shift
|
||||
;;
|
||||
--destination-token)
|
||||
shift
|
||||
options[destination_token]=$1
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue