2023-10-11 15:39:52 +02:00
#!/bin/bash
# SPDX-License-Identifier: MIT
2023-10-11 19:20:52 +02:00
set -e
2023-10-22 22:26:03 +02:00
set -o posix
2023-10-11 19:20:52 +02:00
2023-10-11 15:39:52 +02:00
SELF_DIR = " $( cd " $( dirname " ${ BASH_SOURCE [0] } " ) " && pwd ) "
2023-10-12 15:12:52 +02:00
TMPDIR = /tmp/cascading-pr-test
2023-10-22 17:35:29 +02:00
export LOOP_DELAY = 5
2023-10-13 22:30:22 +02:00
mkdir -p $TMPDIR
2023-10-11 18:05:11 +02:00
source $SELF_DIR /../cascading-pr-lib.sh
2023-10-11 15:39:52 +02:00
function push_self( ) {
2023-10-12 15:12:52 +02:00
forgejo-test-helper.sh push_self_action http://user1:admin1234@${ options [host_port] } user1 cascading-pr vTest
2023-10-11 15:39:52 +02:00
}
2023-10-11 19:20:52 +02:00
function user_login( ) {
local username = $1
(
export DOT = $TMPDIR /$username
forgejo-curl.sh logout
forgejo-curl.sh --user $username --password " ${ options [password] } " login ${ options [url] }
)
}
function user_curl( ) {
local username = $1
shift
2023-10-12 15:12:52 +02:00
DOT = $TMPDIR /$username forgejo-curl.sh " $@ "
2023-10-11 19:20:52 +02:00
}
2023-10-11 22:32:24 +02:00
function user_token( ) {
local username = $1 name = $2
2023-10-22 17:25:03 +02:00
curl -sS -f -H Content-Type:application/json --user " $username : ${ options [password] } " --data '{"name":"' $name '","scopes":["write:repository","write:issue","read:user"]}' ${ options [url] } /api/v1/users/$username /tokens | jq --raw-output .sha1 | tee $TMPDIR /$username /repo-token
2023-10-11 22:32:24 +02:00
}
function user_secret( ) {
local username = $1 name = $2 token = $3
2023-10-22 18:26:56 +02:00
user_curl $username api_json -X PUT --data '{"data":"' $token '"}' ${ options [url] } /api/v1/user/actions/secrets/$name
2023-10-11 22:32:24 +02:00
}
2023-10-24 18:44:03 +02:00
function orgs_delete( ) {
forgejo-curl.sh api_json ${ options [url] } /api/v1/orgs | jq --raw-output '.[] | .name' | while read owner ; do
forgejo-curl.sh api_json ${ options [url] } /api/v1/orgs/$owner /repos | jq --raw-output '.[] | .name' | while read repo ; do
forgejo-curl.sh api_json -X DELETE ${ options [url] } /api/v1/repos/$owner /$repo
done
forgejo-curl.sh api_json -X DELETE ${ options [url] } /api/v1/orgs/$owner
done
}
2023-10-11 22:32:24 +02:00
function user_create( ) {
2023-10-11 19:20:52 +02:00
local username = " $1 " email = " $2 "
2023-10-11 20:00:00 +02:00
forgejo-curl.sh api_json -X DELETE ${ options [url] } /api/v1/admin/users/$username ?purge= true >& /dev/null || true
2023-10-22 17:25:03 +02:00
forgejo-curl.sh api_json --data '{"username":"' $username '","email":"' $email '","password":"' ${ options [password] } '","must_change_password":false}' ${ options [url] } /api/v1/admin/users
2023-10-11 19:20:52 +02:00
user_login $username
}
2023-10-13 19:10:50 +02:00
function close_pull_request( ) {
2023-10-31 23:23:30 +01:00
local repo = $1
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
2023-10-13 19:10:50 +02:00
done
}
2023-10-13 21:08:52 +02:00
function merge_pull_request( ) {
2023-10-24 22:51:30 +02:00
local repo = $1
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
2023-10-13 21:08:52 +02:00
done
}
2023-10-22 18:26:56 +02:00
function has_cascade_pull_request( ) {
2023-10-24 22:51:30 +02:00
pr_count = $( forgejo-curl.sh api_json ${ options [url] } /api/v1/repos/user2/destinationrepo/pulls | jq '[ .[] | select(.state == "open") ] | length' )
2023-10-22 18:26:56 +02:00
test $pr_count -gt 0
}
2023-10-24 18:44:03 +02:00
function create_branch1( ) {
2023-10-28 17:40:09 +02:00
local owner = $1 repo = $2 modify = $3
2023-10-22 18:26:56 +02:00
2023-10-24 18:44:03 +02:00
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
2023-10-12 00:03:58 +02:00
(
cd $TMPDIR
2023-10-24 18:44:03 +02:00
rm -fr ${ repo }
git clone -b branch1 http://user1:admin1234@${ options [host_port] } /$owner /${ repo }
cd ${ repo }
2023-10-12 00:03:58 +02:00
echo CONTENT > README
2023-10-28 17:40:09 +02:00
$modify
2023-10-12 00:03:58 +02:00
git config user.email root@example.com
git config user.name username
git add .
git commit -m 'update'
git push origin branch1
2023-10-24 18:44:03 +02:00
git rev-parse HEAD > ../${ owner } -${ repo } .sha
2023-10-12 00:03:58 +02:00
)
2023-10-24 18:44:03 +02:00
}
2023-10-28 17:40:09 +02:00
function delete_pull_requests( ) {
local owner = $1 repo = $2
2023-10-24 18:44:03 +02:00
2023-10-28 17:40:09 +02:00
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
2023-10-24 18:44:03 +02:00
done
2023-10-28 17:40:09 +02:00
}
2023-10-12 00:03:58 +02:00
2023-10-28 17:40:09 +02:00
function create_pull_request( ) {
local baseowner = $1 headowner = $2 repo = $3
2023-10-24 18:44:03 +02:00
local head
if test $baseowner = = $headowner ; then
head = branch1
else
head = $headowner :branch1
fi
cat > $TMPDIR /data <<EOF
{ "title" :"PR" ,"base" :"main" ,"head" :" $head " }
EOF
forgejo-curl.sh api_json --data @$TMPDIR /data ${ options [url] } /api/v1/repos/$baseowner /${ repo } /pulls
2023-10-12 00:03:58 +02:00
}
2023-10-28 17:40:09 +02:00
function create_pull_request_case1( ) {
local baseowner = $1 headowner = $2 repo = $3
delete_pull_requests $baseowner $repo
create_branch1 $headowner $repo
create_pull_request $baseowner $headowner $repo
}
2023-10-13 15:23:50 +02:00
function finalize_options( ) {
if test -f forgejo-ip; then
: ${ options [host_port] : = $( cat forgejo-ip) : 3000 }
fi
options[ url] = http://${ options [host_port] }
if test -f forgejo-token; then
: ${ options [token] : = $( cat forgejo-token) }
fi
options[ password] = admin1234
}
2023-10-14 16:01:37 +02:00
function unit_retry_fail( ) {
local file = $1
local value = $( cat $file )
expr $value - 1 > $file
echo RESULT
if test $value -gt 0 ; then
return 1
else
return 0
fi
}
function unit_retry( ) {
local two = $TMPDIR /unit_retry_two
rm -f $TMPDIR /retry.*
#
# Succeeds after two tries
#
echo 2 > $TMPDIR /unit_retry_two
RETRY_DELAYS = '1 1 1 1' retry unit_retry_fail $two > $TMPDIR /retry.result 2> $TMPDIR /retry.log
test " $( cat $TMPDIR /retry.result) " = "RESULT"
test " $( grep -c 'waiting 1 unit_retry_fail' $TMPDIR /retry.log) " = 2
#
# Succeeds immediately
#
RETRY_DELAYS = '1' retry unit_retry_fail $two > $TMPDIR /retry.result 2> $TMPDIR /retry.log
test " $( cat $TMPDIR /retry.result) " = "RESULT"
test " $( grep -c 'waiting 1 unit_retry_fail' $TMPDIR /retry.log) " = 0
#
# Verify the output is only the output of the last run and is not polluted by
# unrelated output
#
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 | & tee $TMPDIR /retry.log ; then
return 1
fi
grep --quiet 'retry failed' $TMPDIR /retry.log
}
2023-10-22 18:26:56 +02:00
function fixture( ) {
local origin = $1
local destination = $2
2023-10-24 18:44:03 +02:00
orgs_delete
2023-10-31 23:23:30 +01:00
user_create user3 user3@example.com
user_curl user3 api_json --data '{"username":"destination-fork"}' ${ options [url] } /api/v1/orgs
2023-10-11 22:32:24 +02:00
user_create user2 user2@example.com
2023-10-22 18:26:56 +02:00
forgejo-test-helper.sh push tests/${ destination } http://user2:admin1234@${ options [host_port] } user2 ${ destination }
2023-10-11 20:00:00 +02:00
2023-10-11 22:32:24 +02:00
user_create user1 user1@example.com
2023-10-22 18:26:56 +02:00
forgejo-test-helper.sh push tests/${ origin } http://user1:admin1234@${ options [host_port] } user1 ${ origin } cascading-pr
2023-10-31 23:23:30 +01:00
user_curl user1 api_json --data '{"username":"origin-fork"}' ${ options [url] } /api/v1/orgs
user_curl user1 api_json --data '{"organization":"origin-fork"}' ${ options [url] } /api/v1/repos/user1/${ origin } /forks
2023-10-11 22:32:24 +02:00
user_secret user1 ORIGIN_TOKEN $( user_token user1 ORIGIN_TOKEN)
2023-10-11 19:20:52 +02:00
2023-10-13 15:23:50 +02:00
push_self
2023-10-22 18:26:56 +02:00
}
2023-10-13 15:23:50 +02:00
2023-10-22 18:26:56 +02:00
function no_change_no_cascade_pr( ) {
fixture originrepo-do-nothing destinationrepo
2023-10-31 23:23:30 +01:00
user_secret user1 DESTINATION_TOKEN $( user_token user2 DESTINATION_TOKEN)
2023-10-22 18:26:56 +02:00
2023-10-28 17:40:09 +02:00
create_pull_request_case1 user1 user1 originrepo-do-nothing
2023-10-24 18:44:03 +02:00
wait_success ${ options [url] } /api/v1/repos/user1/originrepo-do-nothing $( cat $TMPDIR /user1-originrepo-do-nothing.sha)
2023-10-22 18:26:56 +02:00
! has_cascade_pull_request
}
function create_and_close( ) {
fixture originrepo destinationrepo
2023-10-31 23:23:30 +01:00
user_secret user1 DESTINATION_TOKEN $( user_token user2 DESTINATION_TOKEN)
2023-10-22 18:26:56 +02:00
2023-10-28 17:40:09 +02:00
create_pull_request_case1 user1 user1 originrepo
2023-10-24 18:44:03 +02:00
wait_success ${ options [url] } /api/v1/repos/user1/originrepo $( cat $TMPDIR /user1-originrepo.sha)
has_cascade_pull_request
2023-10-31 23:23:30 +01:00
close_pull_request originrepo
2023-10-24 18:44:03 +02:00
wait_success ${ options [url] } /api/v1/repos/user1/originrepo $( cat $TMPDIR /user1-originrepo.sha)
}
2023-10-28 17:40:09 +02:00
function taint_update( ) {
if ! test -f upgraded ; then
echo upgraded file not found
return 1
fi
echo 'TAINTED' > upgraded
}
2023-10-31 23:23:30 +01:00
function create_from_origin_fork_and_close( ) {
2023-10-24 18:44:03 +02:00
fixture originrepo destinationrepo
2023-10-31 23:23:30 +01:00
user_secret user1 DESTINATION_TOKEN $( user_token user2 DESTINATION_TOKEN)
2023-10-24 18:44:03 +02:00
2023-10-28 17:40:09 +02:00
delete_pull_requests user1 originrepo
2023-10-31 23:23:30 +01:00
create_branch1 origin-fork originrepo taint_update
create_pull_request user1 origin-fork originrepo
2023-10-28 17:40:09 +02:00
2023-10-31 23:23:30 +01:00
wait_success ${ options [url] } /api/v1/repos/user1/originrepo $( cat $TMPDIR /origin-fork-originrepo.sha)
2023-10-22 18:26:56 +02:00
has_cascade_pull_request
2023-10-31 23:23:30 +01:00
close_pull_request originrepo
wait_success ${ options [url] } /api/v1/repos/user1/originrepo $( cat $TMPDIR /origin-fork-originrepo.sha)
2023-10-22 18:26:56 +02:00
}
2023-10-13 19:10:50 +02:00
2023-10-22 18:26:56 +02:00
function create_and_merge( ) {
fixture originrepo destinationrepo
2023-10-31 23:23:30 +01:00
user_secret user1 DESTINATION_TOKEN $( user_token user2 DESTINATION_TOKEN)
2023-10-22 18:26:56 +02:00
2023-10-28 17:40:09 +02:00
create_pull_request_case1 user1 user1 originrepo
2023-10-31 23:23:30 +01:00
2023-10-24 18:44:03 +02:00
wait_success ${ options [url] } /api/v1/repos/user1/originrepo $( cat $TMPDIR /user1-originrepo.sha)
2023-10-22 18:26:56 +02:00
has_cascade_pull_request
2023-10-24 22:51:30 +02:00
merge_pull_request originrepo
2023-10-24 18:44:03 +02:00
wait_success ${ options [url] } /api/v1/repos/user1/originrepo $( cat $TMPDIR /user1-originrepo.sha)
2023-10-24 22:51:30 +02:00
has_cascade_pull_request
}
2023-10-31 23:23:30 +01:00
function create_in_destination_fork_and_close( ) {
fixture origin-fork-destination destinationrepo
user_secret user1 DESTINATION_TOKEN $( user_token user3 DESTINATION_TOKEN)
create_pull_request_case1 user1 user1 origin-fork-destination
wait_success ${ options [url] } /api/v1/repos/user1/origin-fork-destination $( cat $TMPDIR /user1-origin-fork-destination.sha)
has_cascade_pull_request
close_pull_request origin-fork-destination
wait_success ${ options [url] } /api/v1/repos/user1/origin-fork-destination $( cat $TMPDIR /user1-origin-fork-destination.sha)
}
2023-10-24 22:51:30 +02:00
function create_and_merge_close( ) {
fixture originrepo-close-merge destinationrepo
2023-10-31 23:23:30 +01:00
user_secret user1 DESTINATION_TOKEN $( user_token user2 DESTINATION_TOKEN)
2023-10-24 22:51:30 +02:00
2023-10-28 17:40:09 +02:00
create_pull_request_case1 user1 user1 originrepo-close-merge
2023-10-31 23:23:30 +01:00
2023-10-24 22:51:30 +02:00
wait_success ${ options [url] } /api/v1/repos/user1/originrepo-close-merge $( cat $TMPDIR /user1-originrepo-close-merge.sha)
has_cascade_pull_request
merge_pull_request originrepo-close-merge
wait_success ${ options [url] } /api/v1/repos/user1/originrepo-close-merge $( cat $TMPDIR /user1-originrepo-close-merge.sha)
! has_cascade_pull_request
2023-10-11 15:39:52 +02:00
}
2023-10-22 18:26:56 +02:00
function integration( ) {
2023-10-31 23:23:30 +01:00
for t in create_in_destination_fork_and_close no_change_no_cascade_pr create_from_origin_fork_and_close create_and_close create_and_merge create_and_merge_close; do
2023-10-27 15:40:09 +02:00
log_info " running $t "
$t
done
2023-10-22 18:26:56 +02:00
}
2023-10-14 16:01:37 +02:00
function unit( ) {
unit_retry
}
function run( ) {
unit
integration
}
2023-10-11 15:39:52 +02:00
function main( ) {
local command = run
while true; do
case " $1 " in
--verbose)
shift
verbose
; ;
--debug)
shift
debug
; ;
2023-10-11 15:50:12 +02:00
--host_port)
shift
2023-10-11 18:05:11 +02:00
options[ host_port] = $1
2023-10-13 15:45:50 +02:00
shift
2023-10-11 15:50:12 +02:00
; ;
--url)
shift
2023-10-11 18:05:11 +02:00
options[ url] = $1
2023-10-13 15:45:50 +02:00
shift
2023-10-11 15:50:12 +02:00
; ;
--token)
shift
2023-10-11 18:05:11 +02:00
options[ token] = $1
2023-10-13 15:45:50 +02:00
shift
2023-10-11 15:50:12 +02:00
; ;
2023-10-11 15:39:52 +02:00
*)
2023-10-13 15:23:50 +02:00
finalize_options
2023-10-11 18:05:11 +02:00
" ${ 1 :- run } "
2023-10-11 15:39:52 +02:00
return 0
; ;
esac
done
}
2023-10-13 15:47:22 +02:00
dependencies
2023-10-11 15:39:52 +02:00
${ MAIN :- main } " ${ @ } "