Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/monetize

xtask/src/main.rs

//! `cargo xtask <task>`: monetize's repository tasks.
//!
//! ```text
//!   cargo xtask publish [--push]   build the PUBLIC branch and prove it compiles
//!   cargo xtask drill [--live --owner-yes]   the 5.4 resilience drill (mock by default)
//!   cargo xtask clippy             the lint gate: workspace + detached crates, -D warnings
//!   cargo xtask trials [--out <dir>]   the 14 buy trials on monetize_admin::linked() (signed guests)
//!   cargo xtask browser            the buy pages' browser tests, in the browser image (Chromium)
//! ```
//!
//! Nothing here is a build dependency of anything: repository tooling is
//! invoked as a tool, never as a dependency.

use std::process::ExitCode;

/// `cargo xtask publish [--push]`; see [`xtask::publish`].
///
/// Two steps, and the second is the one that matters: it writes branch `public`
/// from HEAD's tree minus the declared exclusion list, and then compiles that
/// branch in a throwaway worktree. Excluding a file a build reads produces a
/// branch that looks right and does not build, and nothing about writing the
/// list would have said so.
fn task_publish() -> ExitCode {
    let mut push = false;
    for a in std::env::args().skip(2) {
        match a.as_str() {
            "--push" => push = true,
            other => {
                eprintln!("xtask publish: unknown argument `{other}`");
                eprintln!("usage: cargo xtask publish [--push] | build-guests | clippy | drill [--live --owner-yes] | bench lake [--out <dir>] [--cloud mock|sandbox|upcloud|scaleway] [--vendor mock|sandbox|stripe|klarna|swish] | fast --product <holger|gunnar> | trials [--out <dir>] | browser | ci [--quick|--nightly]");
                return ExitCode::FAILURE;
            }
        }
    }
    match xtask::publish::run(&xtask::workspace_root(), push) {
        Ok(r) => {
            println!("\npublic tree {}", r.tree);
            println!("commit      {}", r.commit);
            println!("branch      public");
            println!("\n  kept      {} path(s)", r.kept);
            println!("  excluded  {} path(s):", r.excluded_total());
            for (why, n) in &r.excluded_by_reason {
                println!("    {n:>4}  {why}");
            }
            println!(
                "\n  cargo metadata + check -p monetize-server -p monetize-ui-server + \
                 readme_version: {}",
                if r.checked { "PASS" } else { "not run" }
            );
            if r.pushed {
                println!("  pushed to github-public (main)");
            } else {
                println!("  NOT pushed: `cargo xtask publish --push` does that");
            }
            ExitCode::SUCCESS
        }
        Err(e) => {
            eprintln!("xtask publish: {e}");
            ExitCode::FAILURE
        }
    }
}

fn main() -> ExitCode {
    match std::env::args().nth(1).as_deref() {
        Some("publish") => task_publish(),
        Some("build-guests") => task_build_guests(),
        Some("clippy") => task_clippy(),
        Some("drill") => task_drill(),
        Some("bench") => task_bench(),
        Some("fast") => task_fast(),
        Some("trials") => task_trials(),
        Some("browser") => xtask::browser::run(&xtask::workspace_root()),
        Some("ci") => task_ci(),
        Some("score") => xtask::score::main(&xtask::workspace_root(), &std::env::args().skip(2).collect::<Vec<_>>()),
        Some(other) => {
            eprintln!("xtask: unknown task `{other}`");
            eprintln!("usage: cargo xtask publish [--push] | build-guests | clippy | drill [--live --owner-yes] | bench lake [--out <dir>] [--cloud mock|sandbox|upcloud|scaleway] [--vendor mock|sandbox|stripe|klarna|swish] | fast --product <holger|gunnar> | trials [--out <dir>] | browser | ci [--quick|--nightly]");
            ExitCode::FAILURE
        }
        None => {
            eprintln!("usage: cargo xtask publish [--push] | build-guests | clippy | drill [--live --owner-yes] | bench lake [--out <dir>] [--cloud mock|sandbox|upcloud|scaleway] [--vendor mock|sandbox|stripe|klarna|swish] | fast --product <holger|gunnar> | trials [--out <dir>] | browser | ci [--quick|--nightly]");
            ExitCode::FAILURE
        }
    }
}

/// `cargo xtask ci [--quick|--nightly] [--list] [--only <prefix>]`: monetize's CI plan
/// ([`xtask::ci::plan`]) on the shared runner.
fn task_ci() -> ExitCode {
    let mut args: Vec<String> = std::env::args().skip(2).collect();
    // the quick set's lean profile (QUICK_ENV) on every step: it fits the forge's 40 GB target
    let mut plan = xtask::ci::for_mode(xtask::ci::plan(&xtask::workspace_root()), nornir_xtask_support::ci::Mode::from_args(&args));
    // `--only <prefix>` is applied here ([`xtask::ci::only`]): it keeps the guests a step loads.
    if let Some(i) = args.iter().position(|a| a == "--only").filter(|i| i + 1 < args.len()) {
        let prefix = args.remove(i + 1);
        args.remove(i);
        plan = xtask::ci::only(plan, &prefix);
    }
    ExitCode::from(nornir_xtask_support::ci::main(&plan, &args).clamp(0, 255) as u8)
}

/// `cargo xtask build-guests` — every product guest to `wasm32-unknown-unknown`,
/// release, and a loud failure when a module did not appear.
fn task_build_guests() -> ExitCode {
    match xtask::guests::run(&xtask::workspace_root()) {
        Ok(built) => {
            for p in &built {
                let size = std::fs::metadata(p).map(|m| m.len()).unwrap_or(0);
                println!("  ✅ {} ({size} bytes)", p.display());
            }
            println!("\n✅ {} guest module(s) built", built.len());
            ExitCode::SUCCESS
        }
        Err(e) => {
            eprintln!("\n✗ build-guests failed: {e}");
            ExitCode::FAILURE
        }
    }
}

/// `cargo xtask bench lake [--out <dir>] [--cloud mock|sandbox|upcloud|scaleway] [--vendor mock|sandbox|stripe|klarna|swish]`; see [`xtask::bench`].
fn task_bench() -> ExitCode {
    let args: Vec<String> = std::env::args().skip(2).collect();
    let parsed = match xtask::bench::parse(&args) {
        Ok(o) => o,
        Err(e) => {
            eprintln!("xtask bench: {e}");
            return ExitCode::FAILURE;
        }
    };
    match xtask::bench::run(&xtask::workspace_root(), &parsed) {
        Ok(receipt) => {
            println!("✅ the Lake bench passed; receipt: {}", receipt.display());
            ExitCode::SUCCESS
        }
        Err(e) => {
            eprintln!("✗ xtask bench: {e}");
            ExitCode::FAILURE
        }
    }
}

/// `cargo xtask trials [--out <dir>]`; see [`xtask::trials`].
/// `cargo xtask fast --product <id> …` — the product's fast test on this checkout's
/// monetize-fast ([`xtask::fast`]).
fn task_fast() -> ExitCode {
    let args: Vec<String> = std::env::args().skip(2).collect();
    let parsed = match xtask::fast::parse(&args) {
        Ok(a) => a,
        Err(e) => {
            eprintln!("xtask fast: {e}");
            return ExitCode::FAILURE;
        }
    };
    match xtask::fast::run(&xtask::workspace_root(), &parsed) {
        Ok(secs) => {
            println!("✅ the fast test of {} is green in {secs} s (buy → terminate)", parsed.product.id);
            ExitCode::SUCCESS
        }
        Err(e) => {
            eprintln!("✗ xtask fast: {e}");
            ExitCode::FAILURE
        }
    }
}

fn task_trials() -> ExitCode {
    let args: Vec<String> = std::env::args().skip(2).collect();
    let out = match xtask::trials::parse(&args) {
        Ok(o) => o,
        Err(e) => {
            eprintln!("xtask trials: {e}");
            return ExitCode::FAILURE;
        }
    };
    match xtask::trials::run(&xtask::workspace_root(), out) {
        Ok(receipt) => {
            println!("✅ the 14 buy trials passed on the ONE box's program; receipt: {}", receipt.display());
            ExitCode::SUCCESS
        }
        Err(e) => {
            eprintln!("✗ xtask trials: {e}");
            ExitCode::FAILURE
        }
    }
}

/// `cargo xtask drill [--live --owner-yes]`; see [`xtask::drill`].
fn task_drill() -> ExitCode {
    let args: Vec<String> = std::env::args().skip(2).collect();
    match xtask::drill::parse(&args) {
        Ok(xtask::drill::Drill::Mock) => {
            let status = std::process::Command::new(std::env::var("CARGO").unwrap_or_else(|_| "cargo".into()))
                .args(xtask::drill::mock_command())
                .current_dir(xtask::workspace_root())
                .status();
            match status {
                Ok(s) if s.success() => {
                    println!("\n✅ drill (mock): the guardian functional tests pass");
                    ExitCode::SUCCESS
                }
                Ok(s) => {
                    eprintln!("\n✗ drill (mock) failed: {s}");
                    ExitCode::FAILURE
                }
                Err(e) => {
                    eprintln!("\n✗ drill (mock): cargo did not start: {e}");
                    ExitCode::FAILURE
                }
            }
        }
        Ok(xtask::drill::Drill::Live) => {
            eprintln!("✗ drill --live is not built yet: it would create only boxes tagged drill-r5-4-<date>, delete them all on exit, and write its receipt to ~/runs/repair-2026-10-10/. Nothing was created.");
            ExitCode::FAILURE
        }
        Err(e) => {
            eprintln!("xtask drill: {e}");
            ExitCode::FAILURE
        }
    }
}

/// `cargo xtask clippy` — the lint gate; see [`xtask::clippy`].
fn task_clippy() -> ExitCode {
    match xtask::clippy::run(&xtask::workspace_root()) {
        Ok(n) => {
            println!("\n✅ clippy clean: {n} run(s), --all-targets, -D warnings");
            ExitCode::SUCCESS
        }
        Err(e) => {
            eprintln!("\n✗ xtask clippy: {e}");
            ExitCode::FAILURE
        }
    }
}