#!/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 # gitea.sh var-get # # 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 " 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 " 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 ] (default org: wp-sites) gitea.sh vars-list gitea.sh var-get 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