derive-gitlab.sh
4.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/env bash
# derive-gitlab.sh — 从 git origin 远程派生 GitLab 凭据并回填 .env.local
# macOS / Linux 用此版本;Windows 用同目录 derive-gitlab.ps1。
# 两份脚本严格等价 — 改动任一份必须同步对方。
#
# 用法: bash derive-gitlab.sh [.env.local 路径,默认 .env.local]
#
# 派生字段:
# GITLAB_API_URL = <scheme>://<host>/api/v3
# GITLAB_PROJECT_ID = 通过 GitLab API(GET /projects?search=...)解析得到的项目数字 ID
# 要求 GITLAB_TOKEN 已填且有效;token 缺失 / 验证失败 / 未匹配时留 TBD
#
# 仅当字段值为 TBD(A5 自动补) 或空时回填;用户手填值不动。
# 仅支持 http(s) origin URL;其他协议(ssh / git@)跳过。
# GITLAB_TOKEN 不派生,留给用户手填。
#
# 退出码:
# 0 = 派生完成或主动跳过(origin 不存在 / 协议不支持)
# 2 = .env.local 路径错
set -uo pipefail
ENV_FILE=${1:-.env.local}
[ -f "$ENV_FILE" ] || { echo "derive-gitlab.sh: env file not found: $ENV_FILE" >&2; exit 2; }
URL=$(git remote get-url origin 2>/dev/null || true)
if [ -z "$URL" ]; then
echo "derive-gitlab.sh: 未配置 origin 远程,GITLAB_* 留给用户手填" >&2
exit 0
fi
case "$URL" in
https://*) SCHEME=https ;;
http://*) SCHEME=http ;;
*)
echo "derive-gitlab.sh: origin 不是 http(s) URL ($URL),跳过派生" >&2
exit 0
;;
esac
REST=${URL#${SCHEME}://}
HOST=${REST%%/*}
PATH_RAW=${REST#*/}
PATH_RAW=${PATH_RAW%.git}
REPO_NAME=$(basename "$PATH_RAW")
API_URL="${SCHEME}://${HOST}/api/v3"
update_field() {
local key=$1 newval=$2
local line
line=$(grep -E "^${key}=" "$ENV_FILE" | head -1)
if [ -z "$line" ]; then
echo " ${key} = (.env.local 中无此行,跳过)" >&2
return
fi
local current=${line#${key}=}
# 剥外层单/双引号再比较,模板里 TBD(A5 自动补) 因含空格/括号必须加引号才能被 source
local stripped=$current
case "$stripped" in
\'*\') stripped=${stripped#\'}; stripped=${stripped%\'} ;;
\"*\") stripped=${stripped#\"}; stripped=${stripped%\"} ;;
esac
if [ -z "$stripped" ] || [ "$stripped" = "TBD(A5 自动补)" ]; then
sed -i.bak -E "s|^${key}=.*$|${key}=${newval}|" "$ENV_FILE" && rm -f "${ENV_FILE}.bak"
echo " ${key} = ${newval} [已派生填入]"
elif [ "$stripped" = "$newval" ]; then
echo " ${key} = ${newval} [已是派生值,无需更新]"
else
echo " ${key} = ${stripped} [保留用户手填,未覆盖派生值 ${newval}]"
fi
}
report_token() {
local key=GITLAB_TOKEN
local line
line=$(grep -E "^${key}=" "$ENV_FILE" | head -1)
if [ -z "$line" ]; then
echo " ${key} = (.env.local 中无此行,跳过)" >&2
return
fi
local current=${line#${key}=}
local stripped=$current
case "$stripped" in
\'*\') stripped=${stripped#\'}; stripped=${stripped%\'} ;;
\"*\") stripped=${stripped#\"}; stripped=${stripped%\"} ;;
esac
case "$stripped" in
""|"【人工填写:"*|"TBD"*)
echo " ${key} = ${stripped} [待人工填写:GitLab Profile → Account → Private token]"
;;
*)
local masked
if [ ${#stripped} -le 8 ]; then
masked=$(printf '%*s' ${#stripped} '' | tr ' ' '*')
else
masked="${stripped:0:4}$(printf '%*s' $((${#stripped}-8)) '' | tr ' ' '*')${stripped: -4}"
fi
echo " ${key} = ${masked} [已填入,长度 ${#stripped}]"
;;
esac
}
echo "derive-gitlab.sh: 从 origin ($URL) 派生 GitLab 凭据:"
update_field GITLAB_API_URL "$API_URL"
# GITLAB_PROJECT_ID:通过 GitLab API 解析数字 ID(要求 token 已填且有效)
TOKEN_LINE=$(grep -E '^GITLAB_TOKEN=' "$ENV_FILE" | head -1)
TOKEN_VAL=${TOKEN_LINE#GITLAB_TOKEN=}
case "$TOKEN_VAL" in
\'*\') TOKEN_VAL=${TOKEN_VAL#\'}; TOKEN_VAL=${TOKEN_VAL%\'} ;;
\"*\") TOKEN_VAL=${TOKEN_VAL#\"}; TOKEN_VAL=${TOKEN_VAL%\"} ;;
esac
case "$TOKEN_VAL" in
""|"【人工填写:"*|"TBD"*)
echo " GITLAB_PROJECT_ID = TBD [token 未填,跳过 API 解析;填完 token 后重跑此脚本]"
;;
*)
USER_HTTP=$(curl -sS -o /dev/null -w '%{http_code}' --header "PRIVATE-TOKEN: $TOKEN_VAL" "$API_URL/user" 2>/dev/null || echo "000")
if [ "$USER_HTTP" != "200" ]; then
echo " GITLAB_PROJECT_ID = TBD [token 验证失败 HTTP $USER_HTTP,留 TBD 待人工确认]"
else
SEARCH_RESP=$(curl -sS --header "PRIVATE-TOKEN: $TOKEN_VAL" \
"$API_URL/projects?search=$REPO_NAME&simple=true&per_page=50" 2>/dev/null || echo "[]")
NUMERIC_ID=$(echo "$SEARCH_RESP" | jq -r --arg p "$PATH_RAW" \
'.[] | select(.path_with_namespace == $p) | .id' 2>/dev/null | head -1)
if [ -n "$NUMERIC_ID" ]; then
update_field GITLAB_PROJECT_ID "$NUMERIC_ID"
else
echo " GITLAB_PROJECT_ID = TBD [API 未匹配 path_with_namespace=$PATH_RAW,请到 GitLab 项目设置页查数字 ID 后填入]"
fi
fi
;;
esac
report_token