Skip to main content

qtcloud_devops_cli/
contract.rs

1/// 契约模块 — 适配层,委托给 `quanttide-devops` toolkit。
2pub use quanttide_devops::contract::{
3    check_version_consistency, load_or_default, normalize_version, validate_version,
4    verify_version, BuildTool, Contract, ContractError, Language, Pipeline, Platform, Registry,
5    Scope, SourceControl, Stage, StageBuild, StageRelease, StageTest, VersionState,
6};
7pub use quanttide_devops::source::config_file::{detect_language, read_config_versions};
8
9use std::path::Path;
10
11/// 加载契约。有 `contract.yaml` 则解析,无则自动推测。
12pub fn load(repo_path: &Path) -> Contract {
13    load_or_default(repo_path)
14}
15
16pub fn load_scopes(repo_path: &Path) -> Vec<Scope> {
17    load(repo_path).scopes
18}
19
20pub fn detect_by_files(dir: &Path) -> Language {
21    detect_language(dir)
22}
23
24/// 检测目录下的所有语言(不限于优先级最高的一个)。
25pub fn detect_all_languages(dir: &Path) -> Vec<String> {
26    let mut langs = Vec::new();
27    if dir.join("Cargo.toml").exists() {
28        langs.push("rust".into());
29    }
30    if dir.join("pyproject.toml").exists() || dir.join("requirements.txt").exists() {
31        langs.push("python".into());
32    }
33    if dir.join("go.mod").exists() {
34        langs.push("go".into());
35    }
36    if dir.join("pubspec.yaml").exists() {
37        langs.push("dart".into());
38    }
39    if dir.join("package.json").exists() {
40        langs.push("typescript".into());
41    }
42    langs
43}
44
45/// 检查 scope 版本一致性。失败时返回空状态。
46pub fn version_status(repo_path: &Path, scope: &Scope) -> VersionState {
47    verify_version(repo_path, scope).unwrap_or_else(|e| {
48        eprintln!("  ⚠ 版本状态检查失败: {}", e);
49        VersionState {
50            tag_version: None,
51            config_version: None,
52            consistent: false,
53            config_files: vec![],
54        }
55    })
56}
57
58/// 显示当前契约的完整状态。
59pub fn status(repo_path: &Path) {
60    let mut stdout = std::io::stdout();
61    status_to(&mut stdout, repo_path).ok();
62}
63
64/// 写入指定 writer 的版本(可测试)。
65pub fn status_to(writer: &mut impl std::io::Write, repo_path: &Path) -> std::io::Result<()> {
66    let contract_path = repo_path.join(".quanttide/devops/contract.yaml");
67    let exists = contract_path.exists();
68    let c = load(repo_path);
69
70    writeln!(writer, "契约状态")?;
71    writeln!(writer, "{}", "-".repeat(40))?;
72    if exists {
73        writeln!(writer, "  配置文件:  {}", contract_path.display())?;
74        writeln!(writer, "  状态:      ✅ 已加载")?;
75    } else {
76        writeln!(writer, "  配置文件:  未找到,使用默认契约")?;
77        writeln!(writer, "  状态:      ⚠ 默认配置")?;
78    }
79    writeln!(writer)?;
80
81    writeln!(writer, "  Stages:")?;
82    writeln!(
83        writer,
84        "    build:    {}",
85        c.stages.build.command.as_deref().unwrap_or("—")
86    )?;
87    writeln!(
88        writer,
89        "    test:     {}(阈值 {}%)",
90        c.stages.test.command.as_deref().unwrap_or("—"),
91        c.stages.test.threshold
92    )?;
93    writeln!(
94        writer,
95        "    release:  {}(pre_publish: {:?})",
96        c.stages.release.changelog, c.stages.release.pre_publish
97    )?;
98    writeln!(writer)?;
99
100    writeln!(writer, "  Platform:")?;
101    writeln!(
102        writer,
103        "    source_control:   {:?}",
104        c.platform.source_control
105    )?;
106    writeln!(writer, "    pipeline:         {:?}", c.platform.pipeline)?;
107    writeln!(
108        writer,
109        "    artifact_registry: {}",
110        c.platform.artifact_registry
111    )?;
112    writeln!(writer)?;
113
114    writeln!(writer, "  Sources:")?;
115    writeln!(
116        writer,
117        "    version:  {:?} {:?}",
118        c.sources.version.source_type, c.sources.version.path
119    )?;
120    writeln!(writer)?;
121
122    writeln!(writer, "  Scopes:  {} 个", c.scopes.len())?;
123    if c.scopes.is_empty() {
124        writeln!(writer, "    未定义 scope")?;
125    } else {
126        for s in &c.scopes {
127            writeln!(
128                writer,
129                "    {:<12} dir: {:<24} {} / {}",
130                s.name,
131                s.dir,
132                s.language.as_str(),
133                s.build_tool.as_str()
134            )?;
135        }
136    }
137
138    let langs = detect_all_languages(repo_path);
139    if !langs.is_empty() {
140        writeln!(writer)?;
141        writeln!(writer, "  语言:      {}", langs.join(", "))?;
142    }
143    Ok(())
144}