GitHub 仓库选择菜单:安装仓库列表 + PATCH 补仓库 + 控制台下拉
This commit is contained in:
1 parent
5ba4d35839
commit
6ba671e051
4 files changed
+343
No files matched your search
@@ -930,6 +930,11 @@ class CloudControlPlaneHandler(BaseHTTPRequestHandler):
|
||||
def do_DELETE(self):
|
||||
self._dispatch("DELETE")
|
||||
|
||||
def do_PATCH(self):
|
||||
# PATCH 之前没有入口(BaseHTTPRequestHandler 默认回 501),
|
||||
# 项目补仓库是第一个 PATCH 路由;与其它方法一样走 _dispatch。
|
||||
self._dispatch("PATCH")
|
||||
|
||||
def _dispatch(self, method):
|
||||
parsed = urlparse(self.path)
|
||||
path = parsed.path
|
||||
@@ -1099,6 +1104,8 @@ class CloudControlPlaneHandler(BaseHTTPRequestHandler):
|
||||
self._models_overview(user_id)
|
||||
elif path == "/relay/models" and method == "GET":
|
||||
self._relay_models(user_id)
|
||||
elif path == "/github/repos" and method == "GET":
|
||||
self._github_repos_list(user_id)
|
||||
elif path.startswith("/projects/"):
|
||||
self._dispatch_project(user_id, method, path, query)
|
||||
elif path == "/environments" and method == "POST":
|
||||
@@ -1420,6 +1427,81 @@ class CloudControlPlaneHandler(BaseHTTPRequestHandler):
|
||||
store.audit(user_id, project_id, "create_project", name)
|
||||
self._send_json(201, project)
|
||||
|
||||
def _update_project(self, user_id, project_id):
|
||||
"""PATCH /projects/{id}:项目 owner 可改 repo_url(建后补仓
|
||||
库,解“建项目时没填仓库、之后建环境一直 400”的死结)。
|
||||
repo_url 缺 key 时 400;null 或空串表示清空;字符串走与
|
||||
创建时同一套 validate_repo_url 校验(带凭证的 URL 拒绝)。
|
||||
只改 projects 行,不动已建环境的快照 repo_url——已建环境
|
||||
仍用建环境时的仓库,新环境才用新值。改完记 update_project
|
||||
审计。"""
|
||||
err = self._check_project(user_id, project_id, "manage_project")
|
||||
if err:
|
||||
self._send_json(err[0], {"error": err[1]})
|
||||
return
|
||||
body, jerr = self._read_json()
|
||||
if jerr:
|
||||
self._send_json(400, {"error": jerr})
|
||||
return
|
||||
if "repo_url" not in body:
|
||||
self._send_json(400, {"error": "repo_url required"})
|
||||
return
|
||||
repo_url = body.get("repo_url")
|
||||
if repo_url is not None and repo_url != "":
|
||||
if not isinstance(repo_url, str):
|
||||
self._send_json(400, {"error": "repo_url must be a string"})
|
||||
return
|
||||
try:
|
||||
repo_url = validate_repo_url(repo_url)
|
||||
except ValueError as exc:
|
||||
self._send_json(400, {"error": str(exc)})
|
||||
return
|
||||
else:
|
||||
repo_url = None
|
||||
conn = self._db()
|
||||
try:
|
||||
row = conn.execute(
|
||||
"SELECT id, name, owner_id, created_at, repo_url, auto_pr"
|
||||
" FROM projects WHERE id = ?",
|
||||
(project_id,)).fetchone()
|
||||
if row is None:
|
||||
self._send_json(404, {"error": "project not found"})
|
||||
return
|
||||
conn.execute(
|
||||
"UPDATE projects SET repo_url = ? WHERE id = ?",
|
||||
(repo_url, project_id))
|
||||
conn.commit()
|
||||
row = conn.execute(
|
||||
"SELECT id, name, owner_id, created_at, repo_url, auto_pr"
|
||||
" FROM projects WHERE id = ?",
|
||||
(project_id,)).fetchone()
|
||||
finally:
|
||||
conn.close()
|
||||
with _auth_store(self.server.db_path) as store:
|
||||
store.audit(user_id, project_id, "update_project",
|
||||
repo_url or "(cleared)")
|
||||
self._send_json(200, {"project": _project_to_dict(row)})
|
||||
|
||||
def _github_repos_list(self, user_id):
|
||||
"""GET /github/repos:列出本服务 GitHub App 安装记录里的仓
|
||||
库(installation_repositories 事件同步进 github_app_
|
||||
installations 表),给控制台建项目/补仓库时的下拉菜单用。
|
||||
任何已认证用户可列(只含仓库名,不含密钥);选了哪个仓库
|
||||
只影响调用者自己有管理权的项目(PATCH 仍按 owner 校验)。
|
||||
手填 URL 的能力不变——没进 App 安装的公开仓库仍可手动填。"""
|
||||
conn = self._db()
|
||||
try:
|
||||
rows = list_installations(conn)
|
||||
finally:
|
||||
conn.close()
|
||||
repos = [{
|
||||
"installation_id": r["installation_id"],
|
||||
"account_login": r["account_login"],
|
||||
"repo_full_name": r["repo_full_name"],
|
||||
"clone_url": "https://github.com/%s.git" % r["repo_full_name"],
|
||||
} for r in rows]
|
||||
self._send_json(200, {"repos": repos})
|
||||
|
||||
def _list_projects(self, user_id):
|
||||
conn = self._db()
|
||||
try:
|
||||
@@ -1467,6 +1549,9 @@ class CloudControlPlaneHandler(BaseHTTPRequestHandler):
|
||||
if not project_id:
|
||||
self._send_json(404, {"error": "not found"})
|
||||
return
|
||||
if len(parts) == 1 and method == "PATCH":
|
||||
self._update_project(user_id, project_id)
|
||||
return
|
||||
# /projects/{id}/memory
|
||||
if len(parts) == 2 and parts[1] == "memory":
|
||||
if method == "POST":
|
||||
|
||||
Reference in new issue
Block a user