Files
zhuangang/topics/devops/cicd/examples/pipeline/test_ci_config.py
T

45 lines
1.5 KiB
Python

# requires: yaml
"""检查 ci.yml 的结构是否符合约定(YAML 能解析、关键任务存在、镜像只在 main 构建、没有明文密钥)。
运行:python -m pytest -q test_ci_config.py
这不能代替在真实 CI 平台上运行,只用来防止明显的配置错误。
"""
import re
from pathlib import Path
import yaml
HERE = Path(__file__).resolve().parent
TEXT = (HERE / "ci.yml").read_text(encoding="utf-8")
CI = yaml.safe_load(TEXT)
def test_jobs_exist():
assert {"changes", "api", "ai", "web", "image"} <= set(CI["jobs"])
def test_trigger():
# 注意:PyYAML 按 YAML 1.1 把键 on 解析成 True
triggers = CI.get("on", CI.get(True))
assert "pull_request" in triggers and triggers["push"]["branches"] == ["main"]
def test_image_only_on_main_and_after_tests():
image = CI["jobs"]["image"]
assert set(image["needs"]) == {"api", "ai", "web"}
assert "refs/heads/main" in image["if"]
def test_tests_run():
api_steps = " ".join(s.get("run", "") for s in CI["jobs"]["api"]["steps"])
assert "go test" in api_steps and "go vet" in api_steps
web_steps = " ".join(s.get("run", "") for s in CI["jobs"]["web"]["steps"])
assert "npm ci" in web_steps and "npm run build" in web_steps
def test_no_plaintext_secrets():
for line in TEXT.splitlines():
if re.search(r"(?i)(password|token|secret)\s*:", line) and "secrets." not in line:
# 只有 CI 服务容器里的测试数据库密码允许明文
assert "POSTGRES_PASSWORD: test" in line, line