Skip to main content

smbcloud_deploy/
runner.rs

1//! Runner (runtime) detection for a working directory.
2
3use crate::{error::DeployError, report::Reporter};
4use smbcloud_model::runner::Runner;
5use smbcloud_utils::config::Config;
6use std::{env::current_dir, path::Path};
7
8/// Detect which runtime this project uses: Next.js, Rails, Rust, Swift, or a
9/// build-less static site.
10///
11/// The detection itself lives in [`Runner::from`]; this wraps it with progress
12/// reporting and the monorepo short-circuit. It owns no spinner and prints
13/// nothing directly. All progress goes through `reporter`, so the same call
14/// works under the CLI, in CI, or on the server.
15pub fn detect_runner(config: &Config, reporter: &dyn Reporter) -> Result<Runner, DeployError> {
16    reporter.step_start("Checking runner");
17
18    // A monorepo declares its runner explicitly and defers per-app detection to
19    // the selected `[[projects]]` entry.
20    if config.project.runner == Runner::Monorepo && config.projects.is_some() {
21        reporter.step_done("Monorepo universal runner");
22        return Ok(Runner::Monorepo);
23    }
24
25    let path = current_dir().map_err(|_| {
26        reporter.step_fail("Could not read the current directory.");
27        DeployError::RunnerNotDetected
28    })?;
29
30    let runner = Runner::from(&path).map_err(|_| {
31        reporter.step_fail("Could not detect a runner.");
32        DeployError::RunnerNotDetected
33    })?;
34
35    reporter.step_done(label_for(runner));
36    Ok(runner)
37}
38
39/// Human-readable confirmation line for a detected runner.
40fn label_for(runner: Runner) -> &'static str {
41    match runner {
42        Runner::Monorepo => "Monorepo universal runner",
43        Runner::NodeJs => "Node.js runner detected",
44        Runner::Static => "Static site, no build step required",
45        Runner::Ruby if Path::new("Gemfile").exists() => "Ruby runner with Rails app detected",
46        Runner::Swift if Path::new("Package.swift").exists() => {
47            "Swift runner with Vapor app detected"
48        }
49        Runner::Rust if Path::new("Cargo.toml").exists() => {
50            "Rust runner with Cargo project detected"
51        }
52        _ => "Runner detected",
53    }
54}