Files

220 lines
5.5 KiB
Bash

#!/usr/bin/env bash
# Websimple Gitea API wrapper — read-only operations.
#
# Replaces the OpenClaw plugin's three Gitea tools:
# - websimple_gitea_orgs_repos_list
# - websimple_gitea_repos_actions_variables_list
# - websimple_gitea_repos_actions_variables_get
#
# Requires:
# - jq
# - curl
# - WEBSIMPLE_GITEA_API_TOKEN env var (or --token flag)
#
# Usage:
# gitea.sh repos-list [--org wp-sites]
# gitea.sh vars-list <owner> <repo>
# gitea.sh var-get <owner> <repo> <variable-name>
#
# Output: JSON to stdout. Errors to stderr. Exit non-zero on failure.
set -euo pipefail
GITEA_BASE_URL="https://gitea.websimple.com"
GITEA_API_BASE="${GITEA_BASE_URL}/api/v1"
PAGE_LIMIT=100
# ----- helpers -----
die() {
printf 'gitea.sh: %s\n' "$*" >&2
exit 1
}
require_token() {
if [[ -z "${WEBSIMPLE_GITEA_API_TOKEN:-}" ]]; then
die "WEBSIMPLE_GITEA_API_TOKEN is not set. Export it before calling this script."
fi
}
require_cmd() {
command -v "$1" >/dev/null 2>&1 || die "Required command not found: $1"
}
# Issue an authenticated GET. Echos response body, exits non-zero on HTTP error.
# Args: $1 = path beginning with /
gitea_get() {
local path="$1"
local url="${GITEA_API_BASE}${path}"
local response
local http_code
response="$(curl -sS \
--header "Authorization: token ${WEBSIMPLE_GITEA_API_TOKEN}" \
--header "Accept: application/json" \
--write-out "\n__HTTP_CODE__:%{http_code}" \
"${url}")"
http_code="${response##*__HTTP_CODE__:}"
response="${response%$'\n'__HTTP_CODE__:*}"
if [[ "${http_code}" -lt 200 || "${http_code}" -ge 300 ]]; then
die "Gitea API request failed: HTTP ${http_code} for ${url}"
fi
printf '%s' "${response}"
}
# Fetch all pages for an endpoint that supports ?page=&limit=.
# Args: $1 = base path (without query string); $2 = extra query params (may be empty)
# Echoes a single JSON array combining all pages.
gitea_get_paginated() {
local base_path="$1"
local extra_query="${2:-}"
local page=1
local combined='[]'
local page_json
local page_count
while (( page <= 10000 )); do
local sep="?"
[[ -n "${extra_query}" ]] && sep="?${extra_query}&"
local path="${base_path}${sep}page=${page}&limit=${PAGE_LIMIT}"
# If gitea_get fails (HTTP error), the subshell exits non-zero and the
# caller's `|| exit 1` handles propagation.
page_json="$(gitea_get "${path}")" || return 1
# Defensive: empty/null responses become []
if [[ -z "${page_json}" || "${page_json}" == "null" ]]; then
page_json='[]'
fi
combined="$(jq -c --argjson new "${page_json}" '. + $new' <<<"${combined}")"
page_count="$(jq 'length' <<<"${page_json}")"
if (( page_count < PAGE_LIMIT )); then
printf '%s' "${combined}"
return 0
fi
page=$(( page + 1 ))
done
die "Pagination safety limit exceeded for ${base_path}"
}
# ----- subcommands -----
cmd_repos_list() {
local org="wp-sites"
while (( $# > 0 )); do
case "$1" in
--org) org="$2"; shift 2 ;;
--org=*) org="${1#--org=}"; shift ;;
*) die "Unknown argument to repos-list: $1" ;;
esac
done
require_token
local repos
repos="$(gitea_get_paginated "/orgs/${org}/repos" "")" || exit 1
# Match the OpenClaw tool's output shape: filtered fields + metadata envelope.
jq -n \
--arg baseUrl "${GITEA_BASE_URL}" \
--arg org "${org}" \
--argjson pageSize "${PAGE_LIMIT}" \
--argjson repos "${repos}" \
'{
baseUrl: $baseUrl,
org: $org,
fetchedAll: true,
pageSize: $pageSize,
count: ($repos | length),
repos: ($repos
| sort_by((.full_name // .name // ""))
| map({
id, name, full_name, html_url, clone_url, ssh_url,
default_branch, private, archived, updated_at
}))
}'
}
cmd_vars_list() {
(( $# == 2 )) || die "Usage: gitea.sh vars-list <owner> <repo>"
local owner="$1" repo="$2"
require_token
local variables
variables="$(gitea_get_paginated "/repos/${owner}/${repo}/actions/variables" "")" || exit 1
jq -n \
--arg baseUrl "${GITEA_BASE_URL}" \
--arg owner "${owner}" \
--arg repo "${repo}" \
--argjson pageSize "${PAGE_LIMIT}" \
--argjson variables "${variables}" \
'{
baseUrl: $baseUrl,
owner: $owner,
repo: $repo,
fetchedAll: true,
pageSize: $pageSize,
count: ($variables | length),
variables: ($variables | sort_by(.name // ""))
}'
}
cmd_var_get() {
(( $# == 3 )) || die "Usage: gitea.sh var-get <owner> <repo> <variable-name>"
local owner="$1" repo="$2" name="$3"
require_token
local variable
variable="$(gitea_get "/repos/${owner}/${repo}/actions/variables/${name}")" || exit 1
jq -n \
--arg baseUrl "${GITEA_BASE_URL}" \
--arg owner "${owner}" \
--arg repo "${repo}" \
--argjson variable "${variable}" \
'{
baseUrl: $baseUrl,
owner: $owner,
repo: $repo,
variable: $variable
}'
}
usage() {
cat >&2 <<'EOF'
Websimple Gitea API wrapper — read-only.
Usage:
gitea.sh repos-list [--org <org>] (default org: wp-sites)
gitea.sh vars-list <owner> <repo>
gitea.sh var-get <owner> <repo> <variable-name>
Requires WEBSIMPLE_GITEA_API_TOKEN in the environment.
EOF
exit 2
}
# ----- dispatch -----
require_cmd jq
require_cmd curl
[[ $# -ge 1 ]] || usage
cmd="$1"; shift
case "${cmd}" in
repos-list) cmd_repos_list "$@" ;;
vars-list) cmd_vars_list "$@" ;;
var-get) cmd_var_get "$@" ;;
-h|--help|help) usage ;;
*) die "Unknown subcommand: ${cmd}" ;;
esac