Merge pull request 'fix: loop over the open pull requests to get an exact title match' (#37) from earl-warren/cascading-pr:wip-search into main
Some checks failed
integration / integration (push) Has been cancelled

Reviewed-on: https://code.forgejo.org/actions/cascading-pr/pulls/37
This commit is contained in:
earl-warren 2025-07-20 13:30:44 +00:00
commit 27e6cc5755
No known key found for this signature in database
GPG key ID: F128CBE6AB3A7201
5 changed files with 149 additions and 134 deletions

View file

@ -14,19 +14,22 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- id: forgejo - id: forgejo
uses: https://code.forgejo.org/actions/setup-forgejo@v1.0.1 uses: https://code.forgejo.org/actions/setup-forgejo@v3.0.1
with: with:
user: root user: root
password: admin1234 password: admin1234
image: codeberg.org/forgejo/forgejo image: codeberg.org/forgejo/forgejo
image-version: 1.21 image-version: 11
lxc-ip-prefix: 10.1.15 lxc-ip-prefix: 10.1.15
- name: tests cascading-pr - name: tests cascading-pr
run: | run: |
set -x
export PATH=$(pwd):$PATH
runner_config=/tmp/runner-config.yaml runner_config=/tmp/runner-config.yaml
sed -e 's|file: .runner|file: ${{ steps.forgejo.outputs.runner-file }}|' < tests/runner-config.yaml > $runner_config sed -e 's|file: .runner|file: ${{ steps.forgejo.outputs.runner-file }}|' < tests/runner-config.yaml > $runner_config
FORGEJO_RUNNER_CONFIG=$runner_config forgejo-runner.sh reload DIR=$(dirname ${{ steps.forgejo.outputs.runner-file }})
DIR=$DIR FORGEJO_RUNNER_CONFIG=$runner_config forgejo-runner.sh reload
tests/run.sh --verbose --host_port ${{ steps.forgejo.outputs.host-port }} --url ${{ steps.forgejo.outputs.url }} --token ${{ steps.forgejo.outputs.token }} tests/run.sh --verbose --host_port ${{ steps.forgejo.outputs.host-port }} --url ${{ steps.forgejo.outputs.url }} --token ${{ steps.forgejo.outputs.token }}
- name: full logs - name: full logs
@ -34,4 +37,4 @@ jobs:
run: | run: |
sed -e 's/^/[RUNNER LOGS] /' ${{ steps.forgejo.outputs.runner-logs }} sed -e 's/^/[RUNNER LOGS] /' ${{ steps.forgejo.outputs.runner-logs }}
docker logs forgejo | sed -e 's/^/[FORGEJO LOGS]/' docker logs forgejo | sed -e 's/^/[FORGEJO LOGS]/'
sleep 5 # hack to avoid mixing outputs in Forgejo v1.21 sleep 5 # hack to avoid mixing outputs in Forgejo v12.0

View file

@ -179,12 +179,13 @@ The test environment consists of the following (all users password is admin1234)
git clone https://code.forgejo.org/actions/setup-forgejo git clone https://code.forgejo.org/actions/setup-forgejo
export PATH=$(pwd)/setup-forgejo:$PATH export PATH=$(pwd)/setup-forgejo:$PATH
git clone https://code.forgejo.org/actions/cascading-pr git clone https://code.forgejo.org/actions/cascading-pr
export PATH=$(pwd)/cascading-pr:$PATH
cd cascading-pr cd cascading-pr
export DIR=/tmp/forgejo-for-cascading-pr export DIR=/tmp/forgejo-for-cascading-pr
forgejo-curl.sh logout forgejo-curl.sh logout
forgejo-runner.sh teardown forgejo-runner.sh teardown
forgejo-binary.sh teardown forgejo-binary.sh teardown
forgejo-binary.sh setup root admin1234 https://codeberg.org/forgejo/forgejo/releases/download/v1.21.3-0/forgejo-1.21.3-0-linux-amd64 forgejo-binary.sh setup root admin1234 https://codeberg.org/forgejo/forgejo/releases/download/v11.0.3/forgejo-11.0.3-linux-amd64
FORGEJO_RUNNER_CONFIG=$(pwd)/tests/runner-config.yaml forgejo-runner.sh setup FORGEJO_RUNNER_CONFIG=$(pwd)/tests/runner-config.yaml forgejo-runner.sh setup
url=$(cat $DIR/forgejo-url) url=$(cat $DIR/forgejo-url)
firefox $url firefox $url
@ -207,7 +208,7 @@ The test for a successful run of the cascading-pr action consists of:
Following the steps below recreate the same environment as the Following the steps below recreate the same environment as the
integration workflow locally. It is helpful for forensic analysis when integration workflow locally. It is helpful for forensic analysis when
something does not run as expected and the error displayed are unclear. something does not run as expected and the errors displayed are unclear.
To help with the development loop all steps are idempotent and To help with the development loop all steps are idempotent and
running `tests/run.sh --debug` multiple times must succeed. running `tests/run.sh --debug` multiple times must succeed.

View file

@ -14,7 +14,7 @@ function repo_login() {
local direction="$1" local direction="$1"
local repo=${options[${direction}_repo]} local repo=${options[${direction}_repo]}
( (
export DOT=$TMPDIR/$repo export DOT_FORGEJO_CURL=$TMPDIR/$repo
forgejo-curl.sh logout forgejo-curl.sh logout
forgejo-curl.sh --token "${options[${direction}_token]}" login "${options[${direction}_url]}" forgejo-curl.sh --token "${options[${direction}_token]}" login "${options[${direction}_url]}"
) )
@ -23,7 +23,7 @@ function repo_login() {
function repo_curl() { function repo_curl() {
local repo=$1 local repo=$1
shift shift
DOT=$TMPDIR/$repo forgejo-curl.sh "$@" DOT_FORGEJO_CURL=$TMPDIR/$repo forgejo-curl.sh "$@"
} }
function default_branch() { function default_branch() {
@ -132,7 +132,19 @@ function pr_get_origin() {
function pr_get_destination() { function pr_get_destination() {
local title=$(pr_destination_title) local title=$(pr_destination_title)
repo_curl ${options[destination_repo]} api --get --data state=open --data type=pulls --data-urlencode q="$title" ${options[destination_api]}/issues | jq --raw-output .[0] >$TMPDIR/destination-pr.json local page=1
touch $TMPDIR/destination-pr.json
while true; do
repo_curl ${options[destination_repo]} api --get --data page=$page --data state=open --data type=pulls ${options[destination_api]}/issues >$TMPDIR/destination-prs.json
if test "$(jq length <$TMPDIR/destination-prs.json)" = 0; then
break
fi
jq --argjson title "\"$title\"" '.[] | select(.title == $title)' <$TMPDIR/destination-prs.json >$TMPDIR/destination-pr.json
if test -s $TMPDIR/destination-pr.json; then
break
fi
page=$(expr $page + 1)
done
} }
function pr_get() { function pr_get() {

View file

@ -1,13 +1,14 @@
#!/bin/bash #!/bin/bash
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
VERSION=1.0.0 VERSION=1.0.1
SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SELF_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
VERBOSE=false VERBOSE=false
DEBUG=false DEBUG=false
: ${EXIT_ON_ERROR:=true} : ${EXIT_ON_ERROR:=true}
: ${TOKEN_NAME:=forgejo-curl} : ${TOKEN_NAME:=forgejo-curl}
: ${DOT:=$HOME/.forgejo-curl} : ${DOT_FORGEJO_CURL:=$HOME/.forgejo-curl}
: ${DOT:=$DOT_FORGEJO_CURL}
function debug() { function debug() {
DEBUG=true DEBUG=true
@ -28,7 +29,7 @@ function log_error() {
} }
function log_verbose() { function log_verbose() {
if $VERBOSE; then if $VERBOSE ; then
log "$@" log "$@"
fi fi
} }
@ -39,7 +40,7 @@ function log_info() {
function fatal_error() { function fatal_error() {
log_error "$@" log_error "$@"
if $EXIT_ON_ERROR; then if $EXIT_ON_ERROR ; then
exit 1 exit 1
else else
return 1 return 1
@ -47,12 +48,12 @@ function fatal_error() {
} }
function dot_ensure() { function dot_ensure() {
mkdir -p $DOT mkdir -p $DOT_FORGEJO_CURL
} }
HEADER_JSON='-H Content-Type:application/json' HEADER_JSON='-H Content-Type:application/json'
HEADER_TOKEN="-H @$DOT/header-token" HEADER_TOKEN="-H @$DOT_FORGEJO_CURL/header-token"
HEADER_CSRF="-H @$DOT/header-csrf" HEADER_CSRF="-H @$DOT_FORGEJO_CURL/header-csrf"
function api() { function api() {
client $HEADER_TOKEN "$@" client $HEADER_TOKEN "$@"
@ -66,43 +67,40 @@ function login_api() {
local user="$1" password="$2" token="$3" scopes="${4:-[\"all\"]}" url="$5" local user="$1" password="$2" token="$3" scopes="${4:-[\"all\"]}" url="$5"
dot_ensure dot_ensure
if test -s $DOT/token; then if test -s $DOT_FORGEJO_CURL/token ; then
log_info "already logged in, ignored" log_info "already logged in, ignored"
return return
fi fi
if test -z "$token"; then if test -z "$token" ; then
log_verbose curl -sS -X DELETE --user "${user}:${password}" "${url}/api/v1/users/$user/tokens/${TOKEN_NAME}" -o /dev/null -w "%{http_code}" log_verbose curl -sS -X DELETE --user "${user}:${password}" "${url}/api/v1/users/$user/tokens/${TOKEN_NAME}" -o /dev/null -w "%{http_code}"
local basic="${user:-unknown}:${password:-unknown}" local basic="${user:-unknown}:${password:-unknown}"
local status=$(curl -sS -X DELETE --user "${basic}" "${url}/api/v1/users/$user/tokens/${TOKEN_NAME}" -o /dev/null -w "%{http_code}") local status=$(curl -sS -X DELETE --user "${basic}" "${url}/api/v1/users/$user/tokens/${TOKEN_NAME}" -o /dev/null -w "%{http_code}")
if test "${status}" != 404 -a "${status}" != 204; then if test "${status}" != 404 -a "${status}" != 204 ; then
fatal_error permission denied, the user or password are probably incorrect, try again with --verbose fatal_error permission denied, the user or password are probably incorrect, try again with --verbose
return 1 return 1
fi fi
token=$(client $HEADER_JSON --user "${basic}" --data-raw '{"name":"'${TOKEN_NAME}'","scopes":'${scopes}'}' "${url}/api/v1/users/${user}/tokens" | jq --raw-output .sha1) token=$(client $HEADER_JSON --user "${basic}" --data-raw '{"name":"'${TOKEN_NAME}'","scopes":'${scopes}'}' "${url}/api/v1/users/${user}/tokens" | jq --raw-output .sha1)
fi fi
if [[ "$token" =~ ^@ ]]; then if [[ "$token" =~ ^@ ]] ; then
cp "${token##@}" $DOT/token cp "${token##@}" $DOT_FORGEJO_CURL/token
else else
echo "$token" >$DOT/token echo "$token" > $DOT_FORGEJO_CURL/token
fi fi
( ( echo -n "Authorization: token " ; cat $DOT_FORGEJO_CURL/token ) > $DOT_FORGEJO_CURL/header-token
echo -n "Authorization: token "
cat $DOT/token
) >$DOT/header-token
# #
# Verify it works # Verify the token works
# #
local status=$(api -w "%{http_code}" -o /dev/null "${url}/api/v1/user") local status=$(api -w "%{http_code}" -o /dev/null "${url}/api/v1/user")
if test "${status}" != 200; then if test "${status}" != 200 ; then
fatal_error "${url}/api/v1/user returns status code '${status}', the token is invalid, $0 logout and login again" fatal_error "${url}/api/v1/user returns status code '${status}', the token is invalid, $0 logout and login again"
return 1 return 1
fi fi
} }
function client() { function client() {
log_verbose curl --cookie $DOT/cookies -f -sS "$@" log_verbose curl --cookie $DOT_FORGEJO_CURL/cookies -f -sS "$@"
if ! curl --cookie $DOT/cookies -f -sS "$@"; then if ! curl --cookie $DOT_FORGEJO_CURL/cookies -f -sS "$@" ; then
fatal_error fatal_error
fi fi
} }
@ -112,9 +110,9 @@ function web() {
} }
function client_update_cookies() { function client_update_cookies() {
log_verbose curl --cookie-jar $DOT/cookies --cookie $DOT/cookies -w "%{http_code}" -f -sS "$@" log_verbose curl --cookie-jar $DOT_FORGEJO_CURL/cookies --cookie $DOT_FORGEJO_CURL/cookies -w "%{http_code}" -f -sS "$@"
local status=$(curl --cookie-jar $DOT/cookies --cookie $DOT/cookies -w "%{http_code}" -f -sS "$@") local status=$(curl --cookie-jar $DOT_FORGEJO_CURL/cookies --cookie $DOT_FORGEJO_CURL/cookies -w "%{http_code}" -f -sS "$@")
if ! test "${status}" = 200 -o "${status}" = 303; then if ! test "${status}" = 200 -o "${status}" = 303 ; then
fatal_error fatal_error
fi fi
} }
@ -122,7 +120,7 @@ function client_update_cookies() {
function login_client() { function login_client() {
local user="$1" password="$2" url="$3" local user="$1" password="$2" url="$3"
if test -z "$password"; then if test -z "$password" ; then
log_verbose "no password, web will not be authenticated" log_verbose "no password, web will not be authenticated"
return return
fi fi
@ -135,21 +133,21 @@ function login_client() {
# #
# The login stores a cookie # The login stores a cookie
# #
client_update_cookies -X POST --data "user_name=${user}" --data "password=${password}" "${url}/user/login" -o $DOT/login.html client_update_cookies -X POST --data "user_name=${user}" --data "password=${password}" "${url}/user/login" -o $DOT_FORGEJO_CURL/login.html
# #
# Get the CSRF for reuse by other requests # Get the CSRF for reuse by other requests
# #
client_update_cookies -o /dev/null "${url}/user/login" client_update_cookies -o /dev/null "${url}/user/login"
local csrf=$(sed -n -e '/csrf/s/.*csrf\t//p' $DOT/cookies) local csrf=$(sed -n -e '/csrf/s/.*csrf\t//p' $DOT_FORGEJO_CURL/cookies)
echo "X-Csrf-Token: $csrf" >$DOT/header-csrf echo "X-Csrf-Token: $csrf" > $DOT_FORGEJO_CURL/header-csrf
# #
# Verify it works # Verify it works
# #
local status=$(web -o /dev/null -w "%{http_code}" "${url}/user/settings") local status=$(web -o /dev/null -w "%{http_code}" "${url}/user/settings")
if test "${status}" != 200; then if test "${status}" != 200 ; then
grep -C 1 flash-error $DOT/login.html grep -C 1 flash-error $DOT_FORGEJO_CURL/login.html
if ${DEBUG}; then if ${DEBUG} ; then
cat $DOT/login.html cat $DOT_FORGEJO_CURL/login.html
fi fi
fatal_error login failed, the user or password are probably incorrect, try again with --verbose fatal_error login failed, the user or password are probably incorrect, try again with --verbose
fi fi
@ -162,12 +160,13 @@ function login() {
} }
function logout() { function logout() {
rm -f $DOT/* rm -f $DOT_FORGEJO_CURL/*
if test -d $DOT; then if test -d $DOT_FORGEJO_CURL ; then
rmdir $DOT rmdir $DOT_FORGEJO_CURL
fi fi
} }
function usage() { function usage() {
cat >&2 <<EOF cat >&2 <<EOF
forgejo-curl.sh - thin curl wrapper that helps with Forgejo authentication forgejo-curl.sh - thin curl wrapper that helps with Forgejo authentication
@ -187,9 +186,9 @@ LOGIN AND TOKEN
The web endpoints that require authentication will be given a cookie The web endpoints that require authentication will be given a cookie
and CSRF token created using the the --user and --password credentials and CSRF token created using the the --user and --password credentials
On a successful login the credentials are stored in the $DOT On a successful login the credentials are stored in the $DOT_FORGEJO_CURL
directory to be used by the web, api, api_json commands. The logout directory to be used by the web, api, api_json commands. The logout
command removes the $DOT directory. command removes the $DOT_FORGEJO_CURL directory.
If the argument of --token starts with @, it is used as a filename If the argument of --token starts with @, it is used as a filename
from which the token will be read. from which the token will be read.
@ -329,7 +328,7 @@ function main() {
echo "forgejo-curl.sh version $VERSION" echo "forgejo-curl.sh version $VERSION"
return 0 return 0
;; ;;
--help | *) --help|*)
usage usage
return 1 return 1
;; ;;

View file

@ -12,13 +12,13 @@ source $SELF_DIR/../cascading-pr-lib.sh
function push_self() { function push_self() {
log_verbose "push cascading-pr action to user1/cascading-pr" log_verbose "push cascading-pr action to user1/cascading-pr"
forgejo-test-helper.sh push_self_action http://user1:admin1234@${options[host_port]} user1 cascading-pr vTest forgejo-test-helper.sh push_self_action http://placeholder:${options[token]}@${options[host_port]} user1 cascading-pr vTest
} }
function user_login() { function user_login() {
local username=$1 local username=$1
( (
export DOT=$TMPDIR/$username export DOT_FORGEJO_CURL=$TMPDIR/$username
forgejo-curl.sh logout forgejo-curl.sh logout
forgejo-curl.sh --user $username --password "${options[password]}" login ${options[url]} forgejo-curl.sh --user $username --password "${options[password]}" login ${options[url]}
) )
@ -27,13 +27,13 @@ function user_login() {
function user_curl() { function user_curl() {
local username=$1 local username=$1
shift shift
DOT=$TMPDIR/$username forgejo-curl.sh "$@" DOT_FORGEJO_CURL=$TMPDIR/$username forgejo-curl.sh "$@"
} }
function user_token() { function user_token() {
local username=$1 name=$2 local username=$1 name=$2
curl -sS -f -H Content-Type:application/json --user "$username:${options[password]}" --data '{"name":"'$name'","scopes":["write:repository","write:issue","read:organization","read:user"]}' ${options[url]}/api/v1/users/$username/tokens | jq --raw-output .sha1 | tee $TMPDIR/$username/repo-token curl --fail -sS -f -H Content-Type:application/json --user "$username:${options[password]}" --data '{"name":"'$name'","scopes":["write:repository","write:issue","read:organization","read:user"]}' ${options[url]}/api/v1/users/$username/tokens | jq --raw-output .sha1 | tee $TMPDIR/$username/repo-token
} }
function user_secret() { function user_secret() {