commit faee15bc78c935e693f45b9f5db168a3948338ff Author: timmy Date: Tue Apr 21 13:04:09 2026 +0800 Initial commit Co-Authored-By: Claude Opus 4.7 (1M context) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2549b3d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +config.env diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..13dc87d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,109 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## 專案性質 + +這是一個 **Claude Code skill**(根目錄的 `SKILL.md` 就是 skill 定義檔)。本身不是一般應用程式,產物是一組 bash 腳本(`scripts/*.sh`),針對自架 Gitea 做常見操作。`publish.sh` 是最早的腳本,其他腳本是逐步擴充而來。 + +## 常用指令 + +在本 repo 裡沒有測試/build/lint;開發流程就是:改 `scripts/*.sh` → `bash -n` 語法檢查 → 在另一個 tmp 目錄實際跑一次看看。所有腳本共用 `scripts/lib/common.sh`。 + +實際使用腳本時(在任何專案目錄下): + +```bash +bash /path/to/gitea-cli/scripts/publish.sh [repo] [public|private] [-m "msg"] +bash /path/to/gitea-cli/scripts/list.sh [--private|--public] [--format table|tsv|name] +# ... 其他腳本見 SKILL.md / README.md +``` + +首次使用前要 `cp config.example.env config.env` 並填入 `GITEA_URL` / `GITEA_USER` / `GITEA_TOKEN`。 + +## 架構與關鍵不變量 + +### 安全模型:token 絕不落地 + +**修改任何腳本時都要守住**: + +1. `origin` remote 永遠是**乾淨 URL**,不含 token +2. Token 只能出現在 `config.env`、呼叫過程的環境變數、以及 `scripts/lib/common.sh` 裡的 `gitea_api` / `git_*_with_token` 函式內 +3. Token 絕不進入 `.git/config`、remote URL、任何 log(stdout/stderr) +4. `config.env` 被 `.gitignore` 排除 + +### 共用 lib `scripts/lib/common.sh` + +所有 API / push / clone 都走 lib,腳本本身不寫 curl 也不直接操作 credential helper。lib 提供: + +- `load_config`:讀 `config.env`,檢查三個變數都非空非預設 +- `gitea_api [json-body]`:單一 API 呼叫入口;回傳後讀 `$HTTP_CODE` 與 `$GITEA_API_RESP_FILE` +- `git_push_with_token ` / `git_push_tag_with_token ` / `git_clone_with_token `:一次性帶 token 的 git 操作 +- `infer_repo_from_cwd`:從 `git remote get-url origin` 推斷 `owner/repo` +- `confirm_destructive ` / `confirm_exact_match `:破壞性操作互動;`GITEA_YES=1` 或腳本處理的 `-y` 可略過 +- `log_info` / `log_ok` / `log_warn` / `log_err` / `log_done`:統一前綴、**全部寫 stderr** + +**什麼不放進 lib**(刻意留在各腳本): +- 各腳本自己的 arg 解析(每支不同) +- JSON body 組字串(放在呼叫處最直觀;複雜的用 jq 在呼叫端組) +- `publish.sh` 的三種 git 狀態分支(publish 獨有) + +### stdout / stderr 分流 + +- **stderr**:`log_*` 進度訊息、錯誤 +- **stdout**:最終結構化輸出 + - `publish.sh` / `rename.sh` / `visibility.sh` / `archive.sh` / `meta.sh` → repo web URL + - `list.sh` → repo 清單 + - `clone.sh` → clone 到的絕對路徑 + - `release.sh` → release URL + 每個 asset URL + - `tag.sh` → tag 名 + - `delete.sh` → 空 + +使用者可以 `URL=$(publish.sh)` 拿結果。 + +### 新腳本骨架(照抄) + +寫新腳本時以這個為起點: + +```bash +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=lib/common.sh +source "${SCRIPT_DIR}/lib/common.sh" + +load_config +# require_cmd jq # 若會用到 + +usage() { + cat >&2 <<'EOF' +Usage: