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 are pending
integration / integration (push) Waiting to run

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
- 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:
user: root
password: admin1234
image: codeberg.org/forgejo/forgejo
image-version: 1.21
image-version: 11
lxc-ip-prefix: 10.1.15
- name: tests cascading-pr
run: |
set -x
export PATH=$(pwd):$PATH
runner_config=/tmp/runner-config.yaml
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 }}
- name: full logs
@ -34,4 +37,4 @@ jobs:
run: |
sed -e 's/^/[RUNNER LOGS] /' ${{ steps.forgejo.outputs.runner-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
export PATH=$(pwd)/setup-forgejo:$PATH
git clone https://code.forgejo.org/actions/cascading-pr
export PATH=$(pwd)/cascading-pr:$PATH
cd cascading-pr
export DIR=/tmp/forgejo-for-cascading-pr
forgejo-curl.sh logout
forgejo-runner.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
url=$(cat $DIR/forgejo-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
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
running `tests/run.sh --debug` multiple times must succeed.

View file

@ -14,7 +14,7 @@ function repo_login() {
local direction="$1"
local repo=${options[${direction}_repo]}
(
export DOT=$TMPDIR/$repo
export DOT_FORGEJO_CURL=$TMPDIR/$repo
forgejo-curl.sh logout
forgejo-curl.sh --token "${options[${direction}_token]}" login "${options[${direction}_url]}"
)
@ -23,7 +23,7 @@ function repo_login() {
function repo_curl() {
local repo=$1
shift
DOT=$TMPDIR/$repo forgejo-curl.sh "$@"
DOT_FORGEJO_CURL=$TMPDIR/$repo forgejo-curl.sh "$@"
}
function default_branch() {
@ -132,7 +132,19 @@ function pr_get_origin() {
function pr_get_destination() {
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() {

View file

@ -1,13 +1,14 @@
#!/bin/bash
# SPDX-License-Identifier: MIT
VERSION=1.0.0
SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
VERSION=1.0.1
SELF_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
VERBOSE=false
DEBUG=false
: ${EXIT_ON_ERROR:=true}
: ${TOKEN_NAME:=forgejo-curl}
: ${DOT:=$HOME/.forgejo-curl}
: ${DOT_FORGEJO_CURL:=$HOME/.forgejo-curl}
: ${DOT:=$DOT_FORGEJO_CURL}
function debug() {
DEBUG=true
@ -28,8 +29,8 @@ function log_error() {
}
function log_verbose() {
if $VERBOSE; then
log "$@"
if $VERBOSE ; then
log "$@"
fi
}
@ -39,20 +40,20 @@ function log_info() {
function fatal_error() {
log_error "$@"
if $EXIT_ON_ERROR; then
exit 1
if $EXIT_ON_ERROR ; then
exit 1
else
return 1
return 1
fi
}
function dot_ensure() {
mkdir -p $DOT
mkdir -p $DOT_FORGEJO_CURL
}
HEADER_JSON='-H Content-Type:application/json'
HEADER_TOKEN="-H @$DOT/header-token"
HEADER_CSRF="-H @$DOT/header-csrf"
HEADER_TOKEN="-H @$DOT_FORGEJO_CURL/header-token"
HEADER_CSRF="-H @$DOT_FORGEJO_CURL/header-csrf"
function api() {
client $HEADER_TOKEN "$@"
@ -66,44 +67,41 @@ function login_api() {
local user="$1" password="$2" token="$3" scopes="${4:-[\"all\"]}" url="$5"
dot_ensure
if test -s $DOT/token; then
log_info "already logged in, ignored"
return
if test -s $DOT_FORGEJO_CURL/token ; then
log_info "already logged in, ignored"
return
fi
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}"
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}")
if test "${status}" != 404 -a "${status}" != 204; then
fatal_error permission denied, the user or password are probably incorrect, try again with --verbose
return 1
fi
token=$(client $HEADER_JSON --user "${basic}" --data-raw '{"name":"'${TOKEN_NAME}'","scopes":'${scopes}'}' "${url}/api/v1/users/${user}/tokens" | jq --raw-output .sha1)
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}"
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}")
if test "${status}" != 404 -a "${status}" != 204 ; then
fatal_error permission denied, the user or password are probably incorrect, try again with --verbose
return 1
fi
token=$(client $HEADER_JSON --user "${basic}" --data-raw '{"name":"'${TOKEN_NAME}'","scopes":'${scopes}'}' "${url}/api/v1/users/${user}/tokens" | jq --raw-output .sha1)
fi
if [[ "$token" =~ ^@ ]]; then
cp "${token##@}" $DOT/token
if [[ "$token" =~ ^@ ]] ; then
cp "${token##@}" $DOT_FORGEJO_CURL/token
else
echo "$token" >$DOT/token
echo "$token" > $DOT_FORGEJO_CURL/token
fi
(
echo -n "Authorization: token "
cat $DOT/token
) >$DOT/header-token
( echo -n "Authorization: token " ; cat $DOT_FORGEJO_CURL/token ) > $DOT_FORGEJO_CURL/header-token
#
# Verify it works
# Verify the token works
#
local status=$(api -w "%{http_code}" -o /dev/null "${url}/api/v1/user")
if test "${status}" != 200; then
fatal_error "${url}/api/v1/user returns status code '${status}', the token is invalid, $0 logout and login again"
return 1
if test "${status}" != 200 ; then
fatal_error "${url}/api/v1/user returns status code '${status}', the token is invalid, $0 logout and login again"
return 1
fi
}
function client() {
log_verbose curl --cookie $DOT/cookies -f -sS "$@"
if ! curl --cookie $DOT/cookies -f -sS "$@"; then
fatal_error
log_verbose curl --cookie $DOT_FORGEJO_CURL/cookies -f -sS "$@"
if ! curl --cookie $DOT_FORGEJO_CURL/cookies -f -sS "$@" ; then
fatal_error
fi
}
@ -112,19 +110,19 @@ function web() {
}
function client_update_cookies() {
log_verbose curl --cookie-jar $DOT/cookies --cookie $DOT/cookies -w "%{http_code}" -f -sS "$@"
local status=$(curl --cookie-jar $DOT/cookies --cookie $DOT/cookies -w "%{http_code}" -f -sS "$@")
if ! test "${status}" = 200 -o "${status}" = 303; then
fatal_error
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_FORGEJO_CURL/cookies --cookie $DOT_FORGEJO_CURL/cookies -w "%{http_code}" -f -sS "$@")
if ! test "${status}" = 200 -o "${status}" = 303 ; then
fatal_error
fi
}
function login_client() {
local user="$1" password="$2" url="$3"
if test -z "$password"; then
log_verbose "no password, web will not be authenticated"
return
if test -z "$password" ; then
log_verbose "no password, web will not be authenticated"
return
fi
dot_ensure
@ -135,23 +133,23 @@ function login_client() {
#
# 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
#
client_update_cookies -o /dev/null "${url}/user/login"
local csrf=$(sed -n -e '/csrf/s/.*csrf\t//p' $DOT/cookies)
echo "X-Csrf-Token: $csrf" >$DOT/header-csrf
local csrf=$(sed -n -e '/csrf/s/.*csrf\t//p' $DOT_FORGEJO_CURL/cookies)
echo "X-Csrf-Token: $csrf" > $DOT_FORGEJO_CURL/header-csrf
#
# Verify it works
#
local status=$(web -o /dev/null -w "%{http_code}" "${url}/user/settings")
if test "${status}" != 200; then
grep -C 1 flash-error $DOT/login.html
if ${DEBUG}; then
cat $DOT/login.html
fi
fatal_error login failed, the user or password are probably incorrect, try again with --verbose
if test "${status}" != 200 ; then
grep -C 1 flash-error $DOT_FORGEJO_CURL/login.html
if ${DEBUG} ; then
cat $DOT_FORGEJO_CURL/login.html
fi
fatal_error login failed, the user or password are probably incorrect, try again with --verbose
fi
}
@ -162,12 +160,13 @@ function login() {
}
function logout() {
rm -f $DOT/*
if test -d $DOT; then
rmdir $DOT
rm -f $DOT_FORGEJO_CURL/*
if test -d $DOT_FORGEJO_CURL ; then
rmdir $DOT_FORGEJO_CURL
fi
}
function usage() {
cat >&2 <<EOF
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
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
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
from which the token will be read.
@ -271,69 +270,69 @@ function main() {
local command=login user password token scopes
while true; do
case "$1" in
--verbose)
shift
verbose
;;
--debug)
shift
debug
;;
--user)
shift
user="$1"
shift
;;
--password)
shift
password="$1"
shift
;;
--token)
shift
token="$1"
shift
;;
--scopes)
shift
scopes="$1"
shift
;;
login)
shift
login "$user" "$password" "$token" "$scopes" "$1"
return 0
;;
logout)
shift
logout
return 0
;;
web)
shift
web "$@"
return 0
;;
api)
shift
api "$@"
return 0
;;
api_json)
shift
api_json "$@"
return 0
;;
--version)
echo "forgejo-curl.sh version $VERSION"
return 0
;;
--help | *)
usage
return 1
;;
esac
case "$1" in
--verbose)
shift
verbose
;;
--debug)
shift
debug
;;
--user)
shift
user="$1"
shift
;;
--password)
shift
password="$1"
shift
;;
--token)
shift
token="$1"
shift
;;
--scopes)
shift
scopes="$1"
shift
;;
login)
shift
login "$user" "$password" "$token" "$scopes" "$1"
return 0
;;
logout)
shift
logout
return 0
;;
web)
shift
web "$@"
return 0
;;
api)
shift
api "$@"
return 0
;;
api_json)
shift
api_json "$@"
return 0
;;
--version)
echo "forgejo-curl.sh version $VERSION"
return 0
;;
--help|*)
usage
return 1
;;
esac
done
}

View file

@ -12,13 +12,13 @@ source $SELF_DIR/../cascading-pr-lib.sh
function push_self() {
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() {
local username=$1
(
export DOT=$TMPDIR/$username
export DOT_FORGEJO_CURL=$TMPDIR/$username
forgejo-curl.sh logout
forgejo-curl.sh --user $username --password "${options[password]}" login ${options[url]}
)
@ -27,13 +27,13 @@ function user_login() {
function user_curl() {
local username=$1
shift
DOT=$TMPDIR/$username forgejo-curl.sh "$@"
DOT_FORGEJO_CURL=$TMPDIR/$username forgejo-curl.sh "$@"
}
function user_token() {
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() {