Files
shared/scripts/role/examples/check-gitea-prs.sh
T
JefferyandClaude Opus 5 70efcd55f2 fix(role): 檢查腳本自行載入設定,修正 cron 環境取不到變數
晨間狀態檢查在 cron 下實際不會運作:cron 沒有互動 shell 的環境變數,
而 ~/.bashrc 多數在非互動時提早 return,導致範例腳本永遠拿不到 GITEA_TOKEN
而安靜結束,功能等於無效。

- examples/check-gitea-prs.sh 新增 load_env_var():依序從 ~/.roles/.env、
  ~/.bashrc、~/.profile 只抽取所需變數的那一行並 eval 該行賦值,
  不要求使用者把權杖複製到新檔案,也不必寫進 crontab
- role skill 補設定來源說明:非機密放 ~/.roles/.env(權限 600),
  權杖留在原本位置不要複製副本
- 版號 0.0.4 → 0.0.5

驗證:以 env -i 模擬 cron 環境(完全無環境變數)執行,成功取得設定並列出
待合併 PR;確認輸出無疑似權杖字串、.env 不含權杖。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 09:12:15 +08:00

96 lines
3.7 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# ==============================================================================
# 用途:晨間狀態檢查範例 —— 列出 Gitea 上仍開啟中的 PR,讓角色早上能主動提醒。
# 更新時間:2026/07/29 09:05:00
# 相依:bash、curl、node(不使用 jq)。
#
# 安裝:複製到 ~/.roles/<角色 ID>.checks/ 並加上執行權限,然後重跑 --install-cron
# cp check-gitea-prs.sh ~/.roles/YUI01.checks/
# chmod +x ~/.roles/YUI01.checks/check-gitea-prs.sh
#
# 設定(環境變數):
# GITEA_HOST Gitea 站台,例如 https://gitea.example.com
# GITEA_TOKEN 存取權杖(本腳本不會輸出它;晨間檢查寫入記憶前仍會再遮蔽一次)
# GITEA_REPOS 逗號分隔的 owner/repo 清單,例如 plugins/generic,plugins/code
#
# cron 沒有互動 shell 的環境變數,且 ~/.bashrc 多數在非互動時會提早 return,
# 因此本腳本會依序從 ~/.roles/.env、~/.bashrc、~/.profile **只抽取所需變數的那一行**,
# 不要求使用者把權杖複製到新檔案,也不必寫進 crontab。
# 建議把非機密設定(HOSTREPOS)放 ~/.roles/.env,權杖留在原本的位置。
#
# 慣例:**沒有需要回報的事情就不要輸出任何內容**。晨間檢查只在有輸出時才寫記憶,
# 靜默即代表「一切正常,不必打擾使用者」。
# ==============================================================================
set -u
# 從使用者既有的設定檔補齊未設定的變數。只取用「NAME=」開頭的那一行並 eval 該行賦值,
# 風險等同使用者自己 source 這些檔案;不會讀取或輸出其他內容。
load_env_var() {
local name="$1" file line current
eval "current=\${$name:-}"
[ -n "$current" ] && return 0
for file in "$HOME/.roles/.env" "$HOME/.bashrc" "$HOME/.profile"; do
[ -f "$file" ] || continue
line="$(grep -m1 -E "^[[:space:]]*(export[[:space:]]+)?${name}=" "$file" 2>/dev/null)" || true
[ -n "$line" ] || continue
eval "$(printf '%s' "$line" | sed -E 's/^[[:space:]]*export[[:space:]]+//')" 2>/dev/null || continue
export "$name"
eval "current=\${$name:-}"
[ -n "$current" ] && return 0
done
return 0
}
load_env_var GITEA_HOST
load_env_var GITEA_TOKEN
load_env_var GITEA_REPOS
HOST="${GITEA_HOST:-}"
TOKEN="${GITEA_TOKEN:-}"
REPOS="${GITEA_REPOS:-}"
# 設定不全就安靜結束:晨間檢查不該因為沒設定而每天產生雜訊
[ -n "$HOST" ] && [ -n "$TOKEN" ] && [ -n "$REPOS" ] || exit 0
command -v curl >/dev/null 2>&1 || exit 0
command -v node >/dev/null 2>&1 || exit 0
lines=""
IFS=','
for repo in $REPOS; do
repo="$(printf '%s' "$repo" | tr -d '[:space:]')"
[ -n "$repo" ] || continue
body="$(curl -sS --max-time 15 \
-H "Authorization: token ${TOKEN}" \
"${HOST}/api/v1/repos/${repo}/pulls?state=open&limit=20" 2>/dev/null)" || continue
[ -n "$body" ] || continue
summary="$(printf '%s' "$body" | node -e '
let raw = "";
process.stdin.setEncoding("utf8");
process.stdin.on("data", (chunk) => { raw += chunk; });
process.stdin.on("end", () => {
let data;
try { data = JSON.parse(raw); } catch { return; }
if (!Array.isArray(data) || !data.length) return;
const repo = process.argv[1];
for (const pr of data) {
// mergeable 為 false 通常代表有衝突或未過檢查,值得在早上提醒
const blocked = pr.mergeable === false ? ",有衝突或未過檢查" : "";
console.log(`${repo} PR #${pr.number}${pr.title}${pr.head?.ref ?? "?"} → ${pr.base?.ref ?? "?"}${blocked}`);
}
});
' "$repo" 2>/dev/null)"
[ -n "$summary" ] && lines="${lines}${summary}
"
done
unset IFS
# 有開啟中的 PR 才輸出;全部合併完畢就靜默
if [ -n "$lines" ]; then
printf '尚未合併的 PR\n%s' "$lines"
fi