Publish agent-radar via gitea-publish skill

This commit is contained in:
gitea-publish
2026-09-01 15:14:54 +08:00
commit 78b87e8b2f
17 changed files with 2279 additions and 0 deletions
+148
View File
@@ -0,0 +1,148 @@
#!/usr/bin/env bash
# 把被追踪项目的源码镜像到 gitinbox 组织,供代码级追踪。
#
# 用法:
# bash scripts/mirror_sync.sh --id ipollowork
# bash scripts/mirror_sync.sh --id ipollowork --depth 200 # 超大仓只取近期历史
#
# 可见性由档案的 business.license.redistributable 决定(L1/L2 → public,L3 → private)。
# 这条规则不能手工绕过:把 source-available 项目公开镜像,等于替对方做了一次
# 未经授权的公开分发。
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
GITEA_URL="${GITEA_URL:-https://gitea.apescale.com}"
DISPLAY_URL="${GITEA_DISPLAY_URL:-https://gitea.apescale.com}"
ORG="${GITEA_ORG:-gitinbox}"
ID=""
DEPTH=""
while [[ $# -gt 0 ]]; do
case "$1" in
--id) ID="$2"; shift 2;;
--org) ORG="$2"; shift 2;;
--url) GITEA_URL="$2"; shift 2;;
--depth) DEPTH="$2"; shift 2;;
*) echo "未知参数: $1" >&2; exit 1;;
esac
done
[[ -z "$ID" ]] && { echo "缺少 --id" >&2; exit 1; }
YAML="$ROOT/data/projects/$ID.yaml"
[[ -f "$YAML" ]] || { echo "档案不存在: $YAML" >&2; exit 1; }
# ---- 从档案读取镜像配置(bash 不适合解析 YAML,借用 python 输出 shell 赋值) ----
# 用"写临时文件再 source"而不是 eval "$(...)":
# eval 会二次解析内容,YAML 里的括号/引号一旦漏转义就会变成难定位的
# syntax error,而且报错行号会偏移到完全无关的位置。
CONF_FILE="$(mktemp)"
trap 'rm -f "$CONF_FILE"' EXIT
/Users/figmarlite/.workbuddy/binaries/python/envs/default/bin/python - "$YAML" > "$CONF_FILE" <<'PY'
import sys, shlex
from pathlib import Path
sys.path.insert(0, str(Path(sys.argv[1]).resolve().parent.parent.parent / "scripts"))
from _common import load_yaml
d = load_yaml(Path(sys.argv[1]))
m = d.get("mirror") or {}
lic = (d.get("business") or {}).get("license") or {}
print(f"UPSTREAM={shlex.quote(str(m.get('upstream') or ''))}")
print(f"REPO_NAME={shlex.quote(str(m.get('gitea_repo') or '').split('/')[-1] or d.get('id',''))}")
# 可见性以许可证判定为准,不信任档案里手写的 visibility
vis = "public" if lic.get("redistributable") else "private"
print(f"VISIBILITY={shlex.quote(vis)}")
print(f"LIC_LEVEL={shlex.quote(str(lic.get('openness') or '?'))}")
print(f"LIC_NAME={shlex.quote(str(lic.get('name') or ''))}")
PY
# shellcheck disable=SC1090
source "$CONF_FILE"
[[ -z "$UPSTREAM" ]] && { echo "档案缺少 mirror.upstream" >&2; exit 1; }
echo "==> 镜像 $ID"
echo " 上游 : $UPSTREAM"
echo " 目标 : $ORG/$REPO_NAME"
echo " 许可证 : $LIC_LEVEL ($LIC_NAME)"
echo " 可见性 : $VISIBILITY"
if [[ "$VISIBILITY" == "private" ]]; then
echo " ⚠ L3 级 source-available,已强制私有。公开镜像可能构成未经授权的分发。"
fi
# ---- 凭据:优先环境变量,回退到 macOS 钥匙串 ----
if [[ -z "${GITEA_TOKEN:-}" ]]; then
CRED="$(printf "host=%s\nprotocol=https\n" "${DISPLAY_URL#*://}" | git credential-osxkeychain get 2>/dev/null || true)"
GITEA_USER="${GITEA_USER:-$(printf '%s' "$CRED" | sed -n 's/^username=//p')}"
GITEA_TOKEN="$(printf '%s' "$CRED" | sed -n 's/^password=//p')"
fi
[[ -z "${GITEA_TOKEN:-}" || -z "${GITEA_USER:-}" ]] && {
echo "未拿到 Gitea 凭据(设 GITEA_TOKEN/GITEA_USER,或存入钥匙串)" >&2; exit 1; }
# ---- 确保目标仓库存在(组织端点,不是 /user/repos) ----
API="$GITEA_URL/api/v1"
HTTP="$(curl -sS -o /dev/null -w '%{http_code}' -u "$GITEA_USER:$GITEA_TOKEN" "$API/repos/$ORG/$REPO_NAME" || echo 000)"
if [[ "$HTTP" == "200" ]]; then
echo " 仓库已存在"
elif [[ "$HTTP" == "404" ]]; then
echo " 创建仓库 $ORG/$REPO_NAME (private=$([[ $VISIBILITY == private ]] && echo true || echo false)) ..."
CREATE="$(curl -sS -o /tmp/gitea_mirror_create.json -w '%{http_code}' -u "$GITEA_USER:$GITEA_TOKEN" \
-H 'Content-Type: application/json' -X POST "$API/org/$ORG/repos" \
-d "{\"name\":\"$REPO_NAME\",\"private\":$([[ $VISIBILITY == private ]] && echo true || echo false),\"auto_init\":false,\"description\":\"Mirror of $UPSTREAM (license: $LIC_NAME)\"}")"
[[ "$CREATE" =~ ^(200|201)$ ]] || {
echo "创建失败 (HTTP $CREATE):" >&2; cat /tmp/gitea_mirror_create.json >&2; exit 1; }
echo " 已创建"
else
echo "查询仓库失败 (HTTP $HTTP)" >&2; exit 1
fi
# 已存在的仓库若应为私有,显式修正(创建时的 private 对已存在仓库不生效)
if [[ "$VISIBILITY" == "private" ]]; then
curl -sS -o /dev/null -u "$GITEA_USER:$GITEA_TOKEN" -X PATCH \
-H 'Content-Type: application/json' -d '{"private":true}' "$API/repos/$ORG/$REPO_NAME" || true
fi
# ---- 同步 ----
MIRROR_DIR="$ROOT/.mirrors/$REPO_NAME.git"
mkdir -p "$ROOT/.mirrors"
if [[ -d "$MIRROR_DIR" ]]; then
echo " 更新已有裸仓 ..."
git -C "$MIRROR_DIR" remote update --prune
else
echo " 首次全量镜像(大仓请耐心)..."
if [[ -n "$DEPTH" ]]; then
git clone --mirror --depth "$DEPTH" "$UPSTREAM" "$MIRROR_DIR"
else
git clone --mirror "$UPSTREAM" "$MIRROR_DIR"
fi
fi
PROTO="${GITEA_URL%%://*}"
HOST="${GITEA_URL#*//}"
U_ENC="$(/Users/figmarlite/.workbuddy/binaries/python/envs/default/bin/python -c \
'import sys,urllib.parse;print(urllib.parse.quote(sys.argv[1],safe=""))' "$GITEA_USER")"
P_ENC="$(/Users/figmarlite/.workbuddy/binaries/python/envs/default/bin/python -c \
'import sys,urllib.parse;print(urllib.parse.quote(sys.argv[1],safe=""))' "$GITEA_TOKEN")"
echo " 推送到 $ORG/$REPO_NAME ..."
git -C "$MIRROR_DIR" push --mirror "$PROTO://$U_ENC:$P_ENC@$HOST/$ORG/$REPO_NAME.git"
# ---- 回写档案 ----
/Users/figmarlite/.workbuddy/binaries/python/envs/default/bin/python - "$YAML" "$VISIBILITY" "$REPO_NAME" <<'PY'
import sys
from datetime import datetime
from pathlib import Path
sys.path.insert(0, str(Path(sys.argv[1]).resolve().parent.parent.parent / "scripts"))
from _common import today, update_block
p = Path(sys.argv[1])
text = p.read_text(encoding="utf-8")
text = update_block(text, "mirror", {
"visibility": sys.argv[2],
"gitea_repo": f"{'gitinbox'}/{sys.argv[3]}",
"last_sync": today(),
})
p.write_text(text, encoding="utf-8")
PY
SIZE="$(du -sh "$MIRROR_DIR" 2>/dev/null | cut -f1 || echo '?')"
echo "==> 完成。$DISPLAY_URL/$ORG/$REPO_NAME (本地裸仓 $SIZE)"