Skip to main content

xtask/
main.rs

1//! Repo automation entry point.
2//!
3//! Run with `cargo run -p xtask -- <subcommand>`.
4
5mod drift;
6
7use std::process::ExitCode;
8
9/// The check could not be performed — distinct from having found drift.
10const EXIT_ERROR: u8 = 2;
11
12const HELP: &str = "\
13xtask — repo automation for ag-ui-rust
14
15USAGE
16    cargo run -p xtask -- <subcommand> [options]
17
18SUBCOMMANDS
19    drift-check            Compare the Rust event types against the vendored
20                           snapshot of the upstream TypeScript source of truth.
21                           Offline and deterministic; this is the CI gate.
22
23DRIFT-CHECK OPTIONS
24    --upstream             Additionally fetch upstream and report whether the
25                           vendored baseline itself has gone stale. Needs the
26                           network, so keep it out of the required CI job.
27    --refresh              Re-fetch upstream and rewrite the vendored baseline,
28                           recording the upstream commit and the fetch date.
29                           This is how a human accepts an upstream change.
30
31EXIT CODES
32    0  no drift
33    1  drift found (or, with --upstream, the baseline is stale)
34    2  the check could not run
35";
36
37fn main() -> ExitCode {
38    let args: Vec<String> = std::env::args().skip(1).collect();
39    match dispatch(&args) {
40        Ok(code) => ExitCode::from(code),
41        Err(message) => {
42            eprintln!("xtask: {message}");
43            ExitCode::from(EXIT_ERROR)
44        }
45    }
46}
47
48fn dispatch(args: &[String]) -> Result<u8, String> {
49    let Some((subcommand, options)) = args.split_first() else {
50        print!("{HELP}");
51        return Ok(EXIT_ERROR);
52    };
53
54    match subcommand.as_str() {
55        "-h" | "--help" | "help" => {
56            print!("{HELP}");
57            Ok(drift::EXIT_OK)
58        }
59        "drift-check" => drift::run(parse_drift_args(options)?),
60        other => Err(format!(
61            "unknown subcommand `{other}`.\nRun `cargo run -p xtask -- --help` for the list."
62        )),
63    }
64}
65
66fn parse_drift_args(options: &[String]) -> Result<drift::Args, String> {
67    let mut parsed = drift::Args::default();
68    for option in options {
69        match option.as_str() {
70            "--upstream" => parsed.upstream = true,
71            "--refresh" => parsed.refresh = true,
72            other => {
73                return Err(format!(
74                    "unknown option `{other}` for drift-check.\n\
75                     Valid options are --upstream and --refresh."
76                ));
77            }
78        }
79    }
80    if parsed.refresh && parsed.upstream {
81        return Err("--refresh already re-reads upstream; drop --upstream.\n\
82             Run `drift-check` on its own afterwards to compare the Rust types against the \
83             new baseline."
84            .to_string());
85    }
86    Ok(parsed)
87}