Add the GitHub and Gitea steps and split the script into library files
Dry run by default: the script reads from both hosts (tokens, owners, names, license, SSH) and prints a plan; --apply creates the repositories and the Gitea -> GitHub push mirror after a final yes. Choosing GitHub applies the AGPL-3.0 license to the Gitea repository. A failed step is reported with what exists and how to continue; nothing is ever deleted. create-project.sh is now the entry point; the work lives in src/lib/, one responsibility per file. .gitignore gets !src/lib (the Python template ignores any lib/ folder). Tests grow to 599 checks, with a stub curl and ssh, and guards for the file structure. Task: MIL-002#1 Task: MIL-002#2 Task: MIL-002#3 Task: MIL-002#4 Task: MIL-002#5 Task: MIL-002#6 Refs #9 Refs #10 Refs #11 Refs #12 Refs #13 Refs #14 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
# shellcheck shell=bash
|
||||
# shellcheck disable=SC2004,SC2034,SC2154 # shared state and arrays are declared in constants.sh
|
||||
# api.sh - Calls to the GitHub and Gitea APIs and the reporting of a refused call.
|
||||
#
|
||||
# Part of create-project.sh: sourced by it, never run on its own.
|
||||
#
|
||||
# Provides: host_label, api_call, server_message, fail_request, expect_status
|
||||
|
||||
host_label() {
|
||||
case "$1" in
|
||||
gitea) printf 'Gitea' ;;
|
||||
github) printf 'GitHub' ;;
|
||||
*) die "internal error: unknown host" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# api_call HOST METHOD PATH [BODY]: HOST is gitea or github. A network
|
||||
# failure ends the run; the HTTP status is left in HTTP_STATUS.
|
||||
api_call() {
|
||||
local host="$1" method="$2" path="$3" body="${4:-}"
|
||||
case "$host" in
|
||||
gitea)
|
||||
http_request "$method" "${CONFIG[GITEA_API_URL]}$path" token \
|
||||
"${CREDENTIALS[GITEA_TOKEN]}" "$body" || die "$HTTP_ERROR"
|
||||
;;
|
||||
github)
|
||||
http_request "$method" "${CONFIG[GITHUB_API_URL]}$path" bearer \
|
||||
"${CREDENTIALS[GITHUB_PAT]}" "$body" || die "$HTTP_ERROR"
|
||||
;;
|
||||
*) die "internal error: unknown host" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# server_message: the "message" of the last response, cleaned and shortened.
|
||||
server_message() {
|
||||
local message
|
||||
# A response that is not JSON must not stop the error report.
|
||||
message="$(json_get "$HTTP_BODY_FILE" message 2>/dev/null || true)"
|
||||
message="${message//[[:cntrl:]]/ }"
|
||||
printf '%s' "${message:0:160}"
|
||||
}
|
||||
|
||||
fail_request() {
|
||||
local detail message
|
||||
detail="$(describe_http_status "$HTTP_STATUS")"
|
||||
message="$(server_message)"
|
||||
die "$1: $detail${message:+ (the server says: $message)}"
|
||||
}
|
||||
|
||||
# expect_status CONTEXT CODE...: go on if the last status is one of CODE,
|
||||
# otherwise stop with CONTEXT and the server's own words.
|
||||
expect_status() {
|
||||
local context="$1" code
|
||||
shift
|
||||
for code in "$@"; do
|
||||
if [[ $HTTP_STATUS == "$code" ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
fail_request "$context"
|
||||
}
|
||||
Reference in New Issue
Block a user