Last active 2 months ago

anduin's Avatar anduin revised this gist 2 months ago. Go to revision

1 file changed, 0 insertions, 0 deletions

gistfile1.txt renamed to gistfile1.py

File renamed without changes

anduin's Avatar anduin revised this gist 2 months ago. Go to revision

1 file changed, 113 insertions

gistfile1.txt(file created)

@@ -0,0 +1,113 @@
1 + #!/usr/bin/env python3
2 + """
3 + 为个人所有 GitLab 仓库批量添加 CI/CD 变量:
4 + DOCKER_USERNAME
5 + DOCKER_PASSWORD
6 + LOCAL_DOCKER_USERNAME
7 + LOCAL_DOCKER_PASSWORD
8 + """
9 +
10 + import os
11 + import sys
12 + import requests
13 +
14 + def get_user_id(base_url, headers, username):
15 + resp = requests.get(
16 + f"{base_url}/api/v4/users",
17 + params={"username": username},
18 + headers=headers
19 + )
20 + resp.raise_for_status()
21 + users = resp.json()
22 + if not users:
23 + print(f"用户 '{username}' 未找到", file=sys.stderr)
24 + sys.exit(1)
25 + return users[0]["id"]
26 +
27 + def get_projects(base_url, headers, user_id):
28 + projects = []
29 + page = 1
30 + while True:
31 + resp = requests.get(
32 + f"{base_url}/api/v4/users/{user_id}/projects",
33 + params={"per_page": 100, "page": page},
34 + headers=headers
35 + )
36 + resp.raise_for_status()
37 + data = resp.json()
38 + if not data:
39 + break
40 + projects.extend(data)
41 + page += 1
42 + return projects
43 +
44 + def delete_variable(base_url, headers, project_id, key):
45 + """无脑删除项目下的指定变量,忽略不存在的错误"""
46 + url = f"{base_url}/api/v4/projects/{project_id}/variables/{key}"
47 + r = requests.delete(url, headers=headers)
48 + # 204:删除成功;404:变量本就不存在,都视作 OK
49 + return r.status_code in (204, 404)
50 +
51 + def add_variable(base_url, headers, project_id, key, value):
52 + payload = {
53 + "key": key,
54 + "value": value,
55 + "variable_type": "env_var",
56 + "protected": "true", # 仅在受保护的分支/标签上可用
57 + "masked": "true", # 在 Job 日志中掩码
58 + "masked_and_hidden": "true", # 掩码并在 UI 中隐藏(不能再查看)
59 + "raw": "true", # 原样,不展开变量引用
60 + "environment_scope": "*" # 生效所有环境
61 + }
62 + resp = requests.post(
63 + f"{base_url}/api/v4/projects/{project_id}/variables",
64 + headers=headers,
65 + data=payload
66 + )
67 + if resp.status_code == 201:
68 + return True, None
69 + elif resp.status_code == 400:
70 + return False, resp.text
71 + else:
72 + resp.raise_for_status()
73 +
74 + def main():
75 + base_url = os.getenv("GITLAB_BASE_URL", "https://gitlab.aiursoft.cn")
76 + token = "glpat-9ztZJRPATvsuaQ59yBxZ"
77 + headers = {"Private-Token": token}
78 +
79 + username = os.getenv("GITLAB_USERNAME", "anduin")
80 +
81 + user_id = get_user_id(base_url, headers, username)
82 + projects = get_projects(base_url, headers, user_id)
83 +
84 + variables = [
85 + ("DOCKER_USERNAME", "aaaaa"),
86 + ("DOCKER_PASSWORD", "bbbbb"),
87 + ("LOCAL_DOCKER_USERNAME", "ccccc"),
88 + ("LOCAL_DOCKER_PASSWORD", "ddddd"),
89 + ("LOCAL_NUGET_API_KEY", "eeeeeeee"),
90 + ("NUGET_API_KEY", "fffff"),
91 + ]
92 +
93 + for proj in projects:
94 + pid = proj["id"]
95 + name = proj.get("path_with_namespace", proj["name"])
96 + print(f"▶ 处理项目:{name}")
97 +
98 + # —— 新增:先无脑删除所有旧变量 ——
99 + for key, _ in variables:
100 + deleted = delete_variable(base_url, headers, pid, key)
101 + status = "已删除" if deleted else "删除失败"
102 + print(f" ↳ 删除 {key}: {status}")
103 +
104 + # —— 再批量添加 ——
105 + for key, val in variables:
106 + ok, msg = add_variable(base_url, headers, pid, key, val)
107 + if ok:
108 + print(f" ✔ 添加 {key}")
109 + else:
110 + print(f" ✖ 添加 {key} 失败:{msg}")
111 +
112 + if __name__ == "__main__":
113 + main()
Newer Older