my-ci 0.0.1

Minimalist Local CICD
mod build;
mod cli;
mod config;
mod graph;
mod init;
mod oci;
mod run;

use anyhow::{Context, Result};
use clap::Parser;

use crate::build::build_workflow;
use crate::cli::{Cli, Commands};
use crate::config::{get_workflow, load_config};
use crate::graph::{resolve_build_plan, topological_order};
use crate::init::scaffold_init;
use crate::oci::{OciProvider, connect_oci, detect_oci_provider, get_oci_socket_addr};
use crate::run::run_workflow;

#[tokio::main]
async fn main() -> Result<()> {
    let cli = Cli::parse();

    if let Commands::Init { path, force } = &cli.command {
        return scaffold_init(path, *force);
    }

    let config = load_config(&cli.config)?;

    let detected_provider = detect_oci_provider().unwrap_or(OciProvider::Docker);

    let oci_provider = connect_oci(detected_provider).context(format!(
        "failed to connect to an OCI socket at {}",
        get_oci_socket_addr(detected_provider)
    ))?;

    match cli.command {
        Commands::Build { workflow } => {
            if let Some(name) = workflow {
                for target in resolve_build_plan(&config, &name)? {
                    let wf = get_workflow(&config, &target)?;
                    build_workflow(&oci_provider, &config, wf).await?;
                }
            } else {
                for name in topological_order(&config)? {
                    let wf = get_workflow(&config, &name)?;
                    build_workflow(&oci_provider, &config, wf).await?;
                }
            }
        }
        Commands::Run { workflow } => {
            let targets = match workflow {
                Some(name) => vec![name],
                None => topological_order(&config)?,
            };
            for target in &targets {
                for dep in resolve_build_plan(&config, target)? {
                    let wf = get_workflow(&config, &dep)?;
                    build_workflow(&oci_provider, &config, wf).await?;
                }
            }
            for target in &targets {
                let wf = get_workflow(&config, target)?;
                if wf.command.is_some() {
                    run_workflow(&oci_provider, &config, wf).await?;
                }
            }
        }
        Commands::List => {
            for wf in &config.workflow {
                println!("{}", wf.name);
            }
        }
        Commands::Init { .. } => unreachable!("init handled before config load"),
    }

    Ok(())
}