mirror of
https://code.forgejo.org/actions/cascading-pr
synced 2025-03-15 06:46:59 +01:00
split out the lib
This commit is contained in:
parent
95aee3f580
commit
5f8f262472
5 changed files with 508 additions and 58 deletions
51
action.yml
51
action.yml
|
@ -5,20 +5,55 @@ description: |
|
|||
Create and update a PR in another repository
|
||||
|
||||
inputs:
|
||||
forgejo:
|
||||
description: 'URL of the Forgejo instance where the PR is created (e.g. https://code.forgejo.org)'
|
||||
origin-url:
|
||||
description: 'URL of the Forgejo instance where the PR that triggers the action is located (e.g. https://code.forgejo.org)'
|
||||
required: true
|
||||
repo:
|
||||
description: 'the repository into which the PR is created'
|
||||
origin-repo:
|
||||
description: 'the repository in which the PR was created'
|
||||
required: true
|
||||
token:
|
||||
description: 'a token with write permission on repo'
|
||||
origin-token:
|
||||
description: 'a token with write permission on origin-repo'
|
||||
required: true
|
||||
destination-url:
|
||||
description: 'URL of the Forgejo instance where the cascading PR is created or updated (e.g. https://code.forgejo.org)'
|
||||
required: true
|
||||
destination-repo:
|
||||
description: 'the repository in which the cascading PR is created or updated'
|
||||
required: true
|
||||
destination-branch:
|
||||
description: 'the base branch of the destination repository for the cascading PR'
|
||||
required: true
|
||||
destination-token:
|
||||
description: 'a token with write permission on destination-repo'
|
||||
required: true
|
||||
update:
|
||||
description: 'path to the script to update the content of the cascading PR'
|
||||
required: true
|
||||
verbose:
|
||||
description: 'if true print verbose information'
|
||||
default: false
|
||||
debug:
|
||||
description: 'if true print debug information'
|
||||
default: false
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: |
|
||||
echo
|
||||
shell: bash
|
||||
if "${{ inputs.verbose }}"; then
|
||||
verbosity="$verbosity --verbose"
|
||||
fi
|
||||
if "${{ inputs.debug }}"; then
|
||||
verbosity="$verbosity --debug"
|
||||
fi
|
||||
|
||||
cascading-pr.sh $verbosity \
|
||||
--origin-url "${{ inputs.origin-url }}" \
|
||||
--origin-repo "${{ inputs.origin-repo }}" \
|
||||
--origin-token "${{ inputs.origin-token }}" \
|
||||
--destination-url "${{ inputs.destination-url }}" \
|
||||
--destination-repo "${{ inputs.destination-repo }}" \
|
||||
--destination-token "${{ inputs.destination-token }}" \
|
||||
--destination-branch "${{ inputs.destination-branch }}" \
|
||||
--update "${{ inputs.update }}"
|
||||
|
|
52
cascading-pr-lib.sh
Normal file
52
cascading-pr-lib.sh
Normal file
|
@ -0,0 +1,52 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
|
||||
declare -A options
|
||||
|
||||
VERBOSE=false
|
||||
DEBUG=false
|
||||
: ${EXIT_ON_ERROR:=true}
|
||||
|
||||
function debug() {
|
||||
DEBUG=true
|
||||
set -x
|
||||
PS4='${BASH_SOURCE[0]}:$LINENO: ${FUNCNAME[0]}: '
|
||||
}
|
||||
|
||||
function verbose() {
|
||||
VERBOSE=true
|
||||
}
|
||||
|
||||
function log() {
|
||||
echo "$@" >&2
|
||||
}
|
||||
|
||||
function log_error() {
|
||||
log "$@"
|
||||
}
|
||||
|
||||
function log_verbose() {
|
||||
if $VERBOSE ; then
|
||||
log "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
function log_info() {
|
||||
log "$@"
|
||||
}
|
||||
|
||||
function fatal_error() {
|
||||
log_error "$@"
|
||||
if $EXIT_ON_ERROR ; then
|
||||
exit 1
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function host_port() {
|
||||
local url="$1"
|
||||
|
||||
local host_port="${url##http*://}"
|
||||
echo ${host_port%%/}
|
||||
}
|
||||
|
66
cascading-pr.sh
Normal file
66
cascading-pr.sh
Normal file
|
@ -0,0 +1,66 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
SELF_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
source $SELF_DIR/cascading-pr-lib.sh
|
||||
|
||||
function run() {
|
||||
options[origin_host_port]=$(host_port ${options[origin_url]})
|
||||
options[destination_host_port]=$(host_port ${options[destination_url]})
|
||||
|
||||
# login destination
|
||||
# open a PR on destination
|
||||
# checkout the head of the PR
|
||||
# update the PR
|
||||
# force-push the head
|
||||
# wait on the status of the tip of the head
|
||||
}
|
||||
|
||||
function main() {
|
||||
while true; do
|
||||
case "$1" in
|
||||
--verbose)
|
||||
shift
|
||||
verbose
|
||||
;;
|
||||
--debug)
|
||||
shift
|
||||
debug
|
||||
;;
|
||||
--origin-url)
|
||||
shift
|
||||
options[origin_url]=$1
|
||||
;;
|
||||
--origin-repo)
|
||||
shift
|
||||
options[origin_repo]=$1
|
||||
;;
|
||||
--origin-token)
|
||||
shift
|
||||
options[origin_token]=$1
|
||||
;;
|
||||
--destination-url)
|
||||
shift
|
||||
options[destination_url]=$1
|
||||
;;
|
||||
--destination-repo)
|
||||
shift
|
||||
options[destination_repo]=$1
|
||||
;;
|
||||
--destination-token)
|
||||
shift
|
||||
options[destination_token]=$1
|
||||
;;
|
||||
--update)
|
||||
shift
|
||||
options[update]=$1
|
||||
;;
|
||||
*)
|
||||
"${1:-run}"
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
${MAIN:-main} "${@}"
|
338
forgejo-curl.sh
Normal file
338
forgejo-curl.sh
Normal file
|
@ -0,0 +1,338 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
VERSION=1.0.0
|
||||
SELF_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
VERBOSE=false
|
||||
DEBUG=false
|
||||
: ${EXIT_ON_ERROR:=true}
|
||||
: ${TOKEN_NAME:=forgejo-curl}
|
||||
: ${DOT:=$HOME/.forgejo-curl}
|
||||
|
||||
function debug() {
|
||||
DEBUG=true
|
||||
set -x
|
||||
PS4='${BASH_SOURCE[0]}:$LINENO: ${FUNCNAME[0]}: '
|
||||
}
|
||||
|
||||
function verbose() {
|
||||
VERBOSE=true
|
||||
}
|
||||
|
||||
function log() {
|
||||
echo "$@" >&2
|
||||
}
|
||||
|
||||
function log_error() {
|
||||
log "$@"
|
||||
}
|
||||
|
||||
function log_verbose() {
|
||||
if $VERBOSE ; then
|
||||
log "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
function log_info() {
|
||||
log "$@"
|
||||
}
|
||||
|
||||
function fatal_error() {
|
||||
log_error "$@"
|
||||
if $EXIT_ON_ERROR ; then
|
||||
exit 1
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function dot_ensure() {
|
||||
mkdir -p $DOT
|
||||
}
|
||||
|
||||
HEADER_JSON='-H Content-Type:application/json'
|
||||
HEADER_TOKEN="-H @$DOT/header-token"
|
||||
HEADER_CSRF="-H @$DOT/header-csrf"
|
||||
|
||||
function api() {
|
||||
client $HEADER_TOKEN "$@"
|
||||
}
|
||||
|
||||
function api_json() {
|
||||
api $HEADER_JSON "$@"
|
||||
}
|
||||
|
||||
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
|
||||
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)
|
||||
fi
|
||||
if [[ "$token" =~ ^@ ]] ; then
|
||||
cp "${token##@}" $DOT/token
|
||||
else
|
||||
echo "$token" > $DOT/token
|
||||
fi
|
||||
( echo -n "Authorization: token " ; cat $DOT/token ) > $DOT/header-token
|
||||
#
|
||||
# Verify it 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
|
||||
fi
|
||||
}
|
||||
|
||||
function client() {
|
||||
log_verbose curl --cookie $DOT/cookies -f -sS "$@"
|
||||
if ! curl --cookie $DOT/cookies -f -sS "$@" ; then
|
||||
fatal_error
|
||||
fi
|
||||
}
|
||||
|
||||
function web() {
|
||||
client $HEADER_CSRF "$@"
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
fi
|
||||
|
||||
dot_ensure
|
||||
#
|
||||
# Get the CSRF required for login
|
||||
#
|
||||
client_update_cookies -o /dev/null "${url}/user/login"
|
||||
#
|
||||
# The login stores a cookie
|
||||
#
|
||||
client_update_cookies -X POST --data "user_name=${user}" --data "password=${password}" "${url}/user/login" -o $DOT/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
|
||||
#
|
||||
# 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
|
||||
fi
|
||||
}
|
||||
|
||||
function login() {
|
||||
local user="$1" password="$2" token="$3" scope="$4" url="$5"
|
||||
login_client "${user}" "${password}" "${url}"
|
||||
login_api "${user}" "${password}" "${token}" "${scope}" "${url}"
|
||||
}
|
||||
|
||||
function logout() {
|
||||
rm -f $DOT/*
|
||||
if test -d $DOT ; then
|
||||
rmdir $DOT
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
function usage() {
|
||||
cat >&2 <<EOF
|
||||
forgejo-curl.sh - thin curl wrapper that helps with Forgejo authentication
|
||||
|
||||
COMMON OPTIONS
|
||||
|
||||
--verbose display curl commands
|
||||
--debug equivalent to set -x
|
||||
|
||||
LOGIN AND TOKEN
|
||||
|
||||
The API endpoints that require authentication will be given the
|
||||
token provided with the --token argument. If not provided, it will
|
||||
be generated (and named $TOKEN_NAME), using the --user and
|
||||
--password credentials.
|
||||
|
||||
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
|
||||
directory to be used by the web, api, api_json commands. The logout
|
||||
command removes the $DOT directory.
|
||||
|
||||
If the argument of --token starts with @, it is used as a filename
|
||||
from which the token will be read.
|
||||
|
||||
forgejo-curl.sh [--verbose] [--debug]
|
||||
[--user <user>] [--password <password>]
|
||||
[--token {<token>|<@tokenfilename>}]
|
||||
[--scopes <scopes>] login URL
|
||||
forgejo-curl.sh logout
|
||||
|
||||
OPTIONS
|
||||
|
||||
--user <user> username
|
||||
--password <password> password of <user>
|
||||
--scopes <scopes> scopes of the token to be created (default ["all"])
|
||||
--token {<token>|<@tokenfilename>} personal access token
|
||||
|
||||
EXAMPLES
|
||||
|
||||
forgejo-curl.sh --token ABCD \\
|
||||
login https://forgejo.example.com
|
||||
|
||||
web is not authenticated
|
||||
api, api_json use ABCD to authenticate
|
||||
|
||||
forgejo-curl.sh --token @/tmp/token \\
|
||||
login https://forgejo.example.com
|
||||
|
||||
web is not authenticated
|
||||
api, api_json use the content of /tmp/token to authenticate
|
||||
|
||||
forgejo-curl.sh --user joe --password passw0rd \\
|
||||
login https://forgejo.example.com
|
||||
|
||||
web is authenticated
|
||||
api, api_json use a newly generated token that belongs to user joe
|
||||
with scope ["all"] to authenticate
|
||||
|
||||
forgejo-curl.sh --user joe --password passw0rd --scopes '["write:package","write:issue"]' \\
|
||||
login https://forgejo.example.com
|
||||
|
||||
web is authenticated
|
||||
api, api_json use a newly generated token with write permission to packages and issues
|
||||
to authenticate
|
||||
|
||||
forgejo-curl.sh [--verbose] [--debug] web [curl options]"
|
||||
|
||||
call curl using the CSRF token generated by the login command
|
||||
|
||||
EXAMPLES
|
||||
|
||||
forgejo-curl.sh web --form avatar=@avatar.png https://forgejo.example.com/settings/avatar
|
||||
|
||||
upload the file avatar.png and update the avatar of the logged in user
|
||||
|
||||
forgejo-curl.sh [--verbose] [--debug] api|api_json [curl options]"
|
||||
|
||||
call curl using the token given to (or generated by) the login command. If called using
|
||||
api_json, the Content-Type header is set to application/json.
|
||||
|
||||
EXAMPLES
|
||||
|
||||
forgejo-curl.sh api_json --data-raw '{"title":"TITLE"}' \\
|
||||
https://forgejo.example.com/api/v1/repos/joe/test/issues
|
||||
|
||||
create a new issue in the repository test
|
||||
|
||||
forgejo-curl.sh api --form name=image.png --form attachment=@image.png \\
|
||||
https://forgejo.example.com/api/v1/repos/joe/test/issues/1234/assets
|
||||
|
||||
add the image.png file as an attachment to the issue 1234 in the test repository
|
||||
|
||||
forgejo-curl.sh --help - display help
|
||||
forgejo-curl.sh --version - show the version
|
||||
EOF
|
||||
}
|
||||
|
||||
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
|
||||
done
|
||||
}
|
||||
|
||||
${MAIN:-main} "${@}"
|
59
tests/run.sh
59
tests/run.sh
|
@ -2,46 +2,7 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
|
||||
SELF_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
VERBOSE=false
|
||||
DEBUG=false
|
||||
: ${EXIT_ON_ERROR:=true}
|
||||
|
||||
function debug() {
|
||||
DEBUG=true
|
||||
set -x
|
||||
PS4='${BASH_SOURCE[0]}:$LINENO: ${FUNCNAME[0]}: '
|
||||
}
|
||||
|
||||
function verbose() {
|
||||
VERBOSE=true
|
||||
}
|
||||
|
||||
function log() {
|
||||
echo "$@" >&2
|
||||
}
|
||||
|
||||
function log_error() {
|
||||
log "$@"
|
||||
}
|
||||
|
||||
function log_verbose() {
|
||||
if $VERBOSE ; then
|
||||
log "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
function log_info() {
|
||||
log "$@"
|
||||
}
|
||||
|
||||
function fatal_error() {
|
||||
log_error "$@"
|
||||
if $EXIT_ON_ERROR ; then
|
||||
exit 1
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
source $SELF_DIR/../cascading-pr-lib.sh
|
||||
|
||||
function push_self() {
|
||||
local host_port=$1
|
||||
|
@ -50,18 +11,16 @@ function push_self() {
|
|||
}
|
||||
|
||||
function run() {
|
||||
local host_port=$1 url=$2 token=$3
|
||||
|
||||
push_self $host_port
|
||||
push_self ${options[host_port]}
|
||||
|
||||
echo do something
|
||||
}
|
||||
|
||||
function main() {
|
||||
local command=run
|
||||
local host_port=$(cat forgejo-ip):3000
|
||||
local url=http://$host_port
|
||||
local token=$(cat forgejo-token)
|
||||
options[host_port]=$(cat forgejo-ip):3000
|
||||
options[url]=http://$host_port
|
||||
options[token]=$(cat forgejo-token)
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
|
@ -75,18 +34,18 @@ function main() {
|
|||
;;
|
||||
--host_port)
|
||||
shift
|
||||
host_port=$1
|
||||
options[host_port]=$1
|
||||
;;
|
||||
--url)
|
||||
shift
|
||||
url=$1
|
||||
options[url]=$1
|
||||
;;
|
||||
--token)
|
||||
shift
|
||||
token=$1
|
||||
options[token]=$1
|
||||
;;
|
||||
*)
|
||||
"${1:-run}" "$host_port" "$url" "$token"
|
||||
"${1:-run}"
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
|
Loading…
Add table
Reference in a new issue