Publish gitea-publish via gitea-publish skill
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
---
|
||||
name: gitea-publish
|
||||
description: 将本地文件夹(如一个 WorkBuddy 技能)自动在自托管的 Gitea 实例上建仓并推送。当用户说"发布到 gitea"、"推到我的 gitea"、"把技能提交到 gitea"、"在 gitea 上建仓库"时使用。支持自定义 Gitea 地址、自动建仓、私有/公开仓库。
|
||||
---
|
||||
|
||||
# Gitea 发布技能
|
||||
|
||||
把任意本地目录发布为 Gitea 仓库:自动建仓(若不存在)+ git 提交并推送。
|
||||
典型用途:开发一个 WorkBuddy 技能后,直接把它发布到你自己的 Gitea。
|
||||
|
||||
## 何时使用
|
||||
|
||||
- "把这个技能发布到我的 Gitea"
|
||||
- "推送到 gitea.apescale.com"
|
||||
- "在 gitea 上建一个仓库并把内容传上去"
|
||||
- "把生成内容提交到个人 gitea"
|
||||
|
||||
## 配置(凭据,务必通过变量/参数传入,切勿硬编码)
|
||||
|
||||
通过环境变量或命令行参数传入,避免把令牌写进任何文件或在聊天里回显:
|
||||
|
||||
- `GITEA_URL` : Gitea 基地址,例如 `https://gitea.apescale.com`
|
||||
- `GITEA_USER` : 用户名
|
||||
- `GITEA_TOKEN` : 个人访问令牌(PAT,推荐)或密码
|
||||
|
||||
生成 PAT:Gitea 网页 → 右上角头像 → 设置 → 应用 → 生成令牌。
|
||||
|
||||
## 用法
|
||||
|
||||
运行本技能附带的脚本(路径相对于本 SKILL.md 所在目录):
|
||||
|
||||
```bash
|
||||
bash <skill_dir>/publish.sh \
|
||||
--repo <仓库名> \
|
||||
--path <本地目录> \
|
||||
--url "$GITEA_URL" \
|
||||
--user "$GITEA_USER" \
|
||||
--token "$GITEA_TOKEN" \
|
||||
[--private] # 可选:创建私有仓库
|
||||
[--branch <分支>] # 可选:指定默认分支,默认 main
|
||||
```
|
||||
|
||||
也可以用同名环境变量替代 `--url/--user/--token`。
|
||||
|
||||
## 脚本流程
|
||||
|
||||
1. 调用 Gitea API `GET /api/v1/repos/{user}/{repo}` 检查仓库是否存在;
|
||||
不存在则用 `POST /api/v1/user/repos` 创建(支持 `--private`)。
|
||||
2. 在 `--path` 内执行 `git init`(若尚未初始化),提交全部文件。
|
||||
3. 设置 remote 为 `https://<user>:<token>@<host>/<user>/<repo>.git` 并推送默认分支。
|
||||
4. 若远程已有内容,先 `pull --rebase` 再推送,降低冲突风险。
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 凭据仅用于本次建仓/推送,不要写入仓库或回显到聊天记录。
|
||||
- 默认分支优先使用 `main`,回退到 `master`。
|
||||
- 该技能可"自举":开发完成后,用它把自身(即本目录)发布到 Gitea。
|
||||
Executable
+109
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env bash
|
||||
# gitea-publish helper: 在自托管 Gitea 上建仓(若不存在)并推送一个本地目录。
|
||||
# 凭据通过参数或环境变量传入,不写入任何文件;推送时用一次性鉴权 URL,
|
||||
# 本地 .git/config 只保存不含口令的干净 remote,避免口令落盘。
|
||||
set -euo pipefail
|
||||
|
||||
REPO=""
|
||||
PATH_=""
|
||||
URL="${GITEA_URL:-}"
|
||||
USER="${GITEA_USER:-}"
|
||||
TOKEN="${GITEA_TOKEN:-}"
|
||||
PRIVATE="false"
|
||||
BRANCH=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--repo) REPO="$2"; shift 2;;
|
||||
--path) PATH_="$2"; shift 2;;
|
||||
--url) URL="$2"; shift 2;;
|
||||
--user) USER="$2"; shift 2;;
|
||||
--token) TOKEN="$2"; shift 2;;
|
||||
--private) PRIVATE="true"; shift;;
|
||||
--branch) BRANCH="$2"; shift 2;;
|
||||
*) echo "未知参数: $1" >&2; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
# ---- 校验必填项 ----
|
||||
[[ -z "$REPO" ]] && { echo "缺少 --repo" >&2; exit 1; }
|
||||
[[ -z "$PATH_" ]] && { echo "缺少 --path" >&2; exit 1; }
|
||||
[[ -d "$PATH_" ]] || { echo "目录不存在: $PATH_" >&2; exit 1; }
|
||||
[[ -z "$URL" ]] && { echo "缺少 --url 或环境变量 GITEA_URL" >&2; exit 1; }
|
||||
[[ -z "$USER" ]] && { echo "缺少 --user 或环境变量 GITEA_USER" >&2; exit 1; }
|
||||
[[ -z "$TOKEN" ]] && { echo "缺少 --token 或环境变量 GITEA_TOKEN" >&2; exit 1; }
|
||||
|
||||
# 规范化:去掉结尾斜杠
|
||||
URL="${URL%/}"
|
||||
|
||||
# 对凭据做 URL 百分号编码(口令可能含 # $ @ 等特殊字符)
|
||||
urlencode() { python3 -c 'import sys,urllib.parse;print(urllib.parse.quote(sys.argv[1],safe=""))' "$1"; }
|
||||
U_ENC="$(urlencode "$USER")"
|
||||
P_ENC="$(urlencode "$TOKEN")"
|
||||
AUTH_ENC="$U_ENC:$P_ENC" # 仅用于嵌入 git remote URL
|
||||
AUTH_RAW="$USER:$TOKEN" # 仅用于 curl -u(走 Basic Auth 头,base64 安全)
|
||||
|
||||
# 推断默认分支
|
||||
if [[ -z "$BRANCH" ]]; then
|
||||
if [[ -d "$PATH_/.git" ]]; then
|
||||
BRANCH="$(git -C "$PATH_" symbolic-ref --short HEAD 2>/dev/null || true)"
|
||||
fi
|
||||
fi
|
||||
[[ -z "$BRANCH" ]] && BRANCH="main"
|
||||
|
||||
API="$URL/api/v1"
|
||||
HOST="${URL#*//}"
|
||||
REMOTE_CLEAN="https://$HOST/$USER/$REPO.git"
|
||||
REMOTE_AUTH="https://$AUTH_ENC@$HOST/$USER/$REPO.git"
|
||||
|
||||
echo "==> 检查仓库 $USER/$REPO 是否存在 ..."
|
||||
HTTP="$(curl -sS -o /dev/null -w '%{http_code}' -u "$AUTH_RAW" "$API/repos/$USER/$REPO")"
|
||||
if [[ "$HTTP" == "200" ]]; then
|
||||
echo " 仓库已存在,跳过创建。"
|
||||
elif [[ "$HTTP" == "404" ]]; then
|
||||
echo " 仓库不存在,创建中 ..."
|
||||
CREATE_JSON="$(printf '{"name":"%s","private":%s,"auto_init":false,"default_branch":"%s"}' "$REPO" "$PRIVATE" "$BRANCH")"
|
||||
CREATE_HTTP="$(curl -sS -o /tmp/gitea_create.json -w '%{http_code}' -u "$AUTH_RAW" \
|
||||
-H 'Content-Type: application/json' -X POST "$API/user/repos" -d "$CREATE_JSON")"
|
||||
if [[ "$CREATE_HTTP" != "201" && "$CREATE_HTTP" != "200" ]]; then
|
||||
echo "创建仓库失败 (HTTP $CREATE_HTTP):" >&2
|
||||
cat /tmp/gitea_create.json >&2
|
||||
exit 1
|
||||
fi
|
||||
echo " 仓库已创建。"
|
||||
else
|
||||
echo "检查仓库时返回意外状态: $HTTP" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ---- git 操作 ----
|
||||
cd "$PATH_"
|
||||
[[ ! -d .git ]] && git init -q -b "$BRANCH"
|
||||
|
||||
git config user.email "${GITEA_USER:-gitea-publish}@local" 2>/dev/null || true
|
||||
git config user.name "${GITEA_USER:-gitea-publish}" 2>/dev/null || true
|
||||
|
||||
# remote 只保存不含口令的干净地址,方便后续查看/手动更新
|
||||
if git remote get-url origin >/dev/null 2>&1; then
|
||||
git remote set-url origin "$REMOTE_CLEAN"
|
||||
else
|
||||
git remote add origin "$REMOTE_CLEAN"
|
||||
fi
|
||||
|
||||
git add -A
|
||||
if git diff --cached --quiet; then
|
||||
echo " 没有需要提交的变更。"
|
||||
else
|
||||
git commit -q -m "Publish $REPO via gitea-publish skill"
|
||||
echo " 已提交。"
|
||||
fi
|
||||
|
||||
# 若远程已有该分支,先用带口令的 URL rebase,避免冲突(不落盘口令)
|
||||
if git ls-remote --exit-code "$REMOTE_AUTH" "$BRANCH" >/dev/null 2>&1; then
|
||||
git pull -q --rebase "$REMOTE_AUTH" "$BRANCH" || true
|
||||
fi
|
||||
|
||||
# 用一次性带口令 URL 推送,不设置含口令的 upstream
|
||||
git push "$REMOTE_AUTH" "$BRANCH"
|
||||
git branch --set-upstream-to="origin/$BRANCH" 2>/dev/null || true
|
||||
echo "==> 完成。仓库地址: $URL/$USER/$REPO"
|
||||
Reference in New Issue
Block a user