补齐 CI 缓存维护器请求与任务契约校验
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 1/2 (push) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (push) Has been cancelled
Project CI / AI game creator shell Rust smoke (push) Has been cancelled
Project CI / AI game creator shell Rust crates (push) Has been cancelled
Project CI / Backend tests (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled
Project CI / Frontend tests (push) Has been cancelled
Project CI / Repository checks (push) Has been cancelled
Project CI / AI game creator shell web tests (push) Has been cancelled

要求 API 请求显式指定 HTTP 方法并更新全部调用点
增加 workflow 全部任务名称与缓存导出映射的契约测试
从 Rust 任务映射推导集合和数量,消除重复硬编码
同步开发流程中的维护约定
This commit was merged in pull request #467.
This commit is contained in:
2026-09-22 09:10:47 +00:00
parent 705bb1e6b3
commit ff7c5f3589
3 changed files with 53 additions and 15 deletions
+10 -10
View File
@@ -33,7 +33,6 @@ JOBS = {
"Backend tests", "Native shell tests", "Frontend tests",
"Repository checks", "AI game creator shell web tests",
}
RUST_JOBS = {name for name in JOBS if "Rust" in name or name in {"Backend tests", "Native shell tests"}}
RUST_JOB_IDS = {
"AI game creator shell Rust lane 1/2": "ai-game-creator-shell-rust-lane-1",
"AI game creator shell Rust lane 2/2": "ai-game-creator-shell-rust-lane-2",
@@ -42,6 +41,7 @@ RUST_JOB_IDS = {
"Backend tests": "backend-tests",
"Native shell tests": "native-shell-tests",
}
RUST_JOBS = set(RUST_JOB_IDS)
ARTIFACT_PREFIX = "rust-cache-v1-"
MAX_DOWNLOAD = 4 * 1024 ** 3 + 129 * 1024 ** 2
EXPORT_STEP = "Publish master Rust cache artifact"
@@ -143,14 +143,14 @@ class Api:
raise ValueError("api_url must use HTTPS")
self.token_file = Path(token_file)
def request(self, path, body=None, raw=False, method=None):
def request(self, path, *, method, body=None, raw=False):
token = self.token_file.read_text().strip()
if not token or "\n" in token:
raise ValueError("invalid token file")
request = urllib.request.Request(
self.url + "/" + path.lstrip("/"),
data=None if body is None else json.dumps(body).encode(),
method=method or ("GET" if body is None else "PATCH"),
method=method,
headers={"Authorization": "token " + token, "Content-Type": "application/json"},
)
try:
@@ -199,7 +199,7 @@ class Api:
separator = "&" if "?" in path else "?"
page = 1
while True:
response = self.request(f"{path}{separator}limit=50&page={page}")
response = self.request(f"{path}{separator}limit=50&page={page}", method="GET")
items = response[key]
yield from items
if len(items) < 50:
@@ -328,7 +328,7 @@ class Maintenance:
continue
jobs = list(self.api.pages(self.repo_api + f'/actions/runs/{run["id"]}/jobs', "jobs"))
rust_jobs = [job for job in jobs if job["name"] in RUST_JOB_IDS]
if len(rust_jobs) != 6 or {job["name"] for job in rust_jobs} != RUST_JOBS:
if len(rust_jobs) != len(RUST_JOB_IDS) or {job["name"] for job in rust_jobs} != RUST_JOBS:
continue
if any(job.get("status") != "completed" or job.get("conclusion") not in {"success", "failure"}
or job.get("head_sha") != sha
@@ -344,7 +344,7 @@ class Maintenance:
and item.get("workflow_run", {}).get("id") == run["id"]]
if len(matches) != 1:
break
content = self.api.request(self.repo_api + f'/actions/jobs/{job["id"]}/logs', raw=True)
content = self.api.request(self.repo_api + f'/actions/jobs/{job["id"]}/logs', method="GET", raw=True)
if not re.search(re.escape(f"[rust-cache] artifact={name}")
+ r" objects=\d+ bytes=\d+ complete=true", content):
break
@@ -354,7 +354,7 @@ class Maintenance:
images.update(used)
selected.append({"id": matches[0]["id"], "name": name,
"job": RUST_JOB_IDS[job["name"]], "attempt": job["run_attempt"]})
if len(selected) != 6 or len(images) != 1:
if len(selected) != len(RUST_JOB_IDS) or len(images) != 1:
continue
source_image = images.pop()
if source_image not in {row["image"] for row in self.state["versions"]}:
@@ -493,7 +493,7 @@ class Maintenance:
if not fully_passed(run, jobs):
continue
if all(verifies_image(job, self.api.request(
self.repo_api + f'/actions/jobs/{job["id"]}/logs', raw=True), current["image"],
self.repo_api + f'/actions/jobs/{job["id"]}/logs', method="GET", raw=True), current["image"],
require_cache=current.get("source") is not None,
) for job in jobs):
current["verified_run"] = run["id"]
@@ -588,7 +588,7 @@ class Maintenance:
continue
# Artifact.workflow_run 在 Gitea 1.26.4 中只有 id/repository_id/head_sha。
if run_id not in runs:
runs[run_id] = self.api.request(self.repo_api + f"/actions/runs/{run_id}")
runs[run_id] = self.api.request(self.repo_api + f"/actions/runs/{run_id}", method="GET")
run = runs[run_id]
if not self.master_run(run) or run.get("status") != "completed":
continue
@@ -831,7 +831,7 @@ def main():
config = json.loads(Path(args.config).read_text())
maintenance = Maintenance(config)
if not args.apply and not args.resume:
maintenance.api.request(maintenance.repo_api + "/actions/artifacts?limit=1")
maintenance.api.request(maintenance.repo_api + "/actions/artifacts?limit=1", method="GET")
image = configured_image(maintenance.read_config())
head = command("git", "ls-remote", config["clone_url"], "refs/heads/master").split()[0]
maintenance.check_gate_route()