#!/usr/bin/env bash set -euo pipefail COMMAND="" REGISTRY="" IMAGE="" TAG="" PACKAGE_FILE="" REPO="" usage() { echo "Usage:" echo " publish-package docker --proj " echo " publish-package nuget --proj " echo " publish-package pypi --proj " echo " publish-package npm --proj " exit 1 } while [[ $# -gt 0 ]]; do case $1 in docker|nuget|pypi|npm) COMMAND="$1" shift ;; --proj) REPO="$2" shift 2 ;; *) if [[ -z "$COMMAND" ]]; then usage fi case $COMMAND in docker) [[ -z "$REGISTRY" ]] && REGISTRY="$1" && shift && continue [[ -z "$IMAGE" ]] && IMAGE="$1" && shift && continue [[ -z "$TAG" ]] && TAG="$1" && shift && continue ;; nuget) [[ -z "$SOURCE" ]] && SOURCE="$1" && shift && continue [[ -z "$PACKAGE_FILE" ]] && PACKAGE_FILE="$1" && shift && continue ;; pypi) [[ -z "$PACKAGE_FILE" ]] && PACKAGE_FILE="$1" && shift && continue ;; esac shift ;; esac done if [[ -z "$COMMAND" ]] || [[ -z "$REPO" ]]; then usage fi do_docker() { if [[ -z "$REGISTRY" ]] || [[ -z "$IMAGE" ]] || [[ -z "$TAG" ]]; then echo "Error: docker requires " exit 1 fi OWNER=$(ego-mgr get default-username) if [[ -z "$OWNER" ]]; then echo "Error: cannot get username from ego-mgr" exit 1 fi KEY=$(python3 -c "import uuid; print(uuid.uuid4())") LOCKFILE="$HOME/.openclaw/.docker" lock-mgr acquire "$LOCKFILE" "$KEY" # Push via SSH tunnel to bypass Cloudflare's 100MB request body limit. # Tunnel forwards 127.0.0.1:$TUNNEL_PORT on this host to Gitea's HTTP port on vps.git. TUNNEL_HOST="root@vps.git" TUNNEL_PORT="5000" TUNNEL_LOCAL="127.0.0.1:${TUNNEL_PORT}" TUNNEL_CTL="$HOME/.openclaw/.docker-tunnel.sock" rm -f "$TUNNEL_CTL" ssh -fN -o ExitOnForwardFailure=yes -o ControlMaster=yes -o ControlPath="$TUNNEL_CTL" \ -L "${TUNNEL_LOCAL}:127.0.0.1:3000" "$TUNNEL_HOST" cleanup() { ssh -O exit -o ControlPath="$TUNNEL_CTL" "$TUNNEL_HOST" 2>/dev/null || true rm -f "$TUNNEL_CTL" docker logout "$REGISTRY" 2>/dev/null || true docker logout "$TUNNEL_LOCAL" 2>/dev/null || true lock-mgr release "$LOCKFILE" "$KEY" 2>/dev/null || true } trap cleanup EXIT echo "Logging in to $REGISTRY (via tunnel $TUNNEL_LOCAL)..." docker login "$TUNNEL_LOCAL" -u "$OWNER" -p "$(secret-mgr get-secret --key git)" 2>/dev/null FULL_IMAGE="${REGISTRY}/${OWNER}/${IMAGE}:${TAG}" TUNNEL_IMAGE="${TUNNEL_LOCAL}/${OWNER}/${IMAGE}:${TAG}" echo "Building: $FULL_IMAGE" cd "$REPO" docker build -t "$FULL_IMAGE" . docker tag "$FULL_IMAGE" "$TUNNEL_IMAGE" echo "Pushing via tunnel: $TUNNEL_IMAGE" docker push "$TUNNEL_IMAGE" docker rmi "$TUNNEL_IMAGE" 2>/dev/null || true # Link package to repository TOKEN=$(secret-mgr get-secret --key git-access-token) REPO_NAME=$(basename "$REPO") # Determine the actual owner of the git repository REPO_OWNER="$OWNER" if [[ -d "$REPO/.git" ]]; then REMOTE_URL=$(git -C "$REPO" remote get-url origin 2>/dev/null || true) if [[ "$REMOTE_URL" =~ git\.hangman-lab\.top/([^/]+)/ ]]; then REPO_OWNER="${BASH_REMATCH[1]}" fi fi LINK_RESP=$(curl -s -w "%{http_code}" -X POST \ -u "${OWNER}:${TOKEN}" \ "https://git.hangman-lab.top/api/v1/packages/${OWNER}/container/${IMAGE}/-/link/${REPO_NAME}") LINK_STATUS="${LINK_RESP: -3}" LINK_BODY="${LINK_RESP:0:-3}" if [[ "$LINK_STATUS" != "200" && "$LINK_STATUS" != "201" ]]; then if echo "$LINK_BODY" | grep -q '"message".*repository does not exist'; then echo "Warning: repository '$REPO_NAME' is not owned by '$OWNER' — skipping link (requires site admin or matching owner)." else echo "Warning: package link failed (HTTP $LINK_STATUS): $LINK_BODY" fi fi lock-mgr release "$LOCKFILE" "$KEY" echo "Done: $FULL_IMAGE" } do_nuget() { echo "publish-package nuget: not yet implemented" exit 1 } do_pypi() { echo "publish-package pypi: not yet implemented" exit 1 } do_npm() { echo "publish-package npm: not yet implemented" exit 1 } # For docker, determine the actual repo owner via search API and switch to that owner's agent-id if [[ "$COMMAND" == "docker" ]]; then REPO_NAME=$(basename "$REPO") SCRIPT_DIR_CALLER=$(cd "$(dirname "$0")" && pwd) search_result=$("$SCRIPT_DIR_CALLER/repo" search "$REPO_NAME" 2>&1) || true if [[ -n "$search_result" ]] && echo "$search_result" | python3 -q -c "import sys,json; sys.exit(0 if json.load(sys.stdin) else 1)" 2>/dev/null; then repo_owner=$(echo "$search_result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('owner',''))" 2>/dev/null) if [[ -n "$repo_owner" ]]; then owner_agent_id=$(ego-mgr lookup "$repo_owner" 2>/dev/null || echo "") if [[ -n "$owner_agent_id" ]]; then export AGENT_ID="$owner_agent_id" fi fi fi fi case "$COMMAND" in docker) do_docker ;; nuget) do_nuget ;; pypi) do_pypi ;; npm) do_npm ;; esac