diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-08-18 08:27:36 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-08-18 08:27:36 +0800 |
| commit | 5d0918ff5e19ebc67e4698bc308f6562779b7110 (patch) | |
| tree | a9d7f5fb54afd16056b0a4c24d118db2d95f8d78 /mingling_ci/src/reporter.rs | |
| parent | 00cf68abdd2be1cfca8b5a268d087ea2ccedf1dd (diff) | |
feat: add new Mingling CI system crate (WIP)
Add `mingling_ci` as a standalone CI system built on Mingling 0.4.0
to validate the next version, with report collection and manifest
listing commands.
Diffstat (limited to 'mingling_ci/src/reporter.rs')
| -rw-r--r-- | mingling_ci/src/reporter.rs | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/mingling_ci/src/reporter.rs b/mingling_ci/src/reporter.rs new file mode 100644 index 0000000..00ce3e5 --- /dev/null +++ b/mingling_ci/src/reporter.rs @@ -0,0 +1,108 @@ +//! Minimal log exporter for CI reports. +//! +//! Writes per-package results into `collect/{task}/{platform}/{package}.{ok|err}` +//! so that the [`crate::cmd::collect_results`] command can assemble the final +//! report. The task name is set once per CI phase via [`set_task`]. + +use std::fs; +use std::path::Path; +use std::sync::Mutex; + +/// Root of the collected CI logs (relative to the repo root). +pub const COLLECT_DIR: &str = "./.temp/reports/collect"; + +/// The platform a package check ran on. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ReportPlatform { + Windows, + Linux, + MacOS, +} + +impl ReportPlatform { + /// Directory name used under the task folder. + const fn dir_name(self) -> &'static str { + match self { + Self::Windows => "Windows", + Self::Linux => "Linux", + Self::MacOS => "MacOS", + } + } +} + +/// The outcome of a package check. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ReportResult { + /// Check passed. + Ok, + /// Check failed, with the captured output. + Error(String), +} + +/// Current task name (e.g. `Build-All`); set via [`set_task`]. +static CURRENT_TASK: Mutex<Option<String>> = Mutex::new(None); + +/// Sets the task that subsequent [`export`] calls write under. +/// +/// # Panics +/// +/// Panics if the internal mutex is poisoned. +pub fn set_task(task: &str) { + *CURRENT_TASK.lock().unwrap() = Some(task.to_string()); +} + +/// Exports one package result to `collect/{task}/{platform}/{package}.{ok|err}`. +/// +/// Writes `{package}.ok` on success and `{package}.err` (with the output) on +/// failure. Errors are reported to stderr and otherwise ignored. +/// +/// # Panics +/// +/// Panics if the internal task mutex is poisoned. +pub fn export(package: &str, platform: ReportPlatform, result: ReportResult) { + let Some(task) = CURRENT_TASK.lock().unwrap().clone() else { + eprintln!("reporter: no current task; call reporter::set_task first"); + return; + }; + + let dir = Path::new(COLLECT_DIR).join(task).join(platform.dir_name()); + if let Err(e) = fs::create_dir_all(&dir) { + eprintln!("reporter: failed to create {}: {e}", dir.display()); + return; + } + + let (file_name, content) = match result { + ReportResult::Ok => (format!("{package}.ok"), String::new()), + ReportResult::Error(output) => (format!("{package}.err"), output), + }; + let path = dir.join(file_name); + if let Err(e) = fs::write(&path, content) { + eprintln!("reporter: failed to write {}: {e}", path.display()); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn export_writes_ok_and_err_files() { + set_task("reporter-test"); + let task_root = Path::new(COLLECT_DIR).join("reporter-test"); + let dir = task_root.join("Linux"); + fs::remove_dir_all(&task_root).ok(); + + export("pkg-a", ReportPlatform::Linux, ReportResult::Ok); + export( + "pkg-b", + ReportPlatform::Linux, + ReportResult::Error("boom".to_string()), + ); + + assert!(dir.join("pkg-a.ok").is_file()); + assert!(dir.join("pkg-b.err").is_file()); + assert_eq!(fs::read_to_string(dir.join("pkg-b.err")).unwrap(), "boom"); + + fs::remove_dir_all(&task_root).ok(); + } +} |
