Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
18e4649
fix: no_dry_run conflicts_with
masonlet Jul 2, 2026
6bae6c3
chore: add --version flag and remove -v short from verbose
masonlet Jul 2, 2026
8a43b09
fix: --help --build info
masonlet Jul 2, 2026
73cfe65
refactor: add flag help headings and shorten comomon flags
masonlet Jul 2, 2026
cec3681
chore: bump v0.4.2
masonlet Jul 2, 2026
43f4ac7
feat: show detect build system message during dry-run
masonlet Jul 2, 2026
328400f
refactor: change dry-run completion message
masonlet Jul 2, 2026
fc3eaee
fix: config init message dry-run, cargo fmt
masonlet Jul 2, 2026
fe74274
fix: clarify dry-run overwrite prompt
masonlet Jul 2, 2026
3235c11
fix: npm workspace clean removes node_modules, clarify dry-run overwr…
masonlet Jul 2, 2026
d35ce34
fix: timing and verbose logging fixes
masonlet Jul 3, 2026
66e5f32
refactor: extract dry_run_or_do helper for cleanup/creation
masonlet Jul 3, 2026
a080656
refactor: extract detect_or_dry_run helper for build system detection
masonlet Jul 3, 2026
165c837
refactor: extract io_error_msg helper for load/save config errors
masonlet Jul 3, 2026
029b2ec
refactor: gate dry-run/verbose output in dry_run_or_do, fix build_pro…
masonlet Jul 3, 2026
9aee871
fix: warn instead of silently returning on --clean for npm, remove no…
masonlet Jul 3, 2026
5306a53
docs: clarify run() error
masonlet Jul 3, 2026
e8bdaa8
fix: skip mono config/wrap/watch fs writes and process spawn on dry-run
masonlet Jul 3, 2026
1a33467
fix: single-repo dry-run with forced build system falsely reports suc…
masonlet Jul 3, 2026
6fe1930
fix: gate per-repo clone lines behind verbose in mono mode
masonlet Jul 3, 2026
51a86ce
fix: remove duplicate blank line from mono clone loop
masonlet Jul 3, 2026
ed90cf5
fix: print npm install header to avoid duplicate blank line before fi…
masonlet Jul 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "star-setup"
version = "0.4.1"
version = "0.4.2"
edition = "2021"
repository = "https://github.com/star-setup/core"
description = "Lightweight CLI to clone, configure, and wire single or multi-repo ecosystems"
Expand Down
9 changes: 5 additions & 4 deletions src/cli/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,22 @@ pub enum Command {
#[derive(Parser)]
#[command(
name = "star-setup",
version,
about = "Lightweight CLI to clone, configure, and wire single or multi-repo ecosystems",
long_about = None,
)]
pub struct Args {
/// Repository name (username/repo) or full GitHub URL
pub repo: Option<String>,

/// Skip confirmation prompts (non-interactive mode)
#[arg(short = 'y', long)]
pub yes: bool,

/// Select a named configuration to use
#[arg(long = "config")]
pub config_name: Option<String>,

/// Skip confirmation prompts (non-interactive mode)
#[arg(short = 'y', long)]
pub yes: bool,

#[command(subcommand)]
pub command: Option<Command>,

Expand Down
23 changes: 20 additions & 3 deletions src/cli/build/detect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,24 @@ fn pick_build_system(
/// # Errors
/// Returns an error on EOF during prompt, or if no supported build system is found.
pub fn detect_build_system(dir: &Path, ctx: &mut RunCtx<'_, '_>) -> Result<BuildSystem, String> {
crate::time!(ctx.flags.timing, ctx.io.output, "Detect", {
crate::time!(ctx.flags.timing, ctx.io.output, "Scanned directory", {
let mut detected = Vec::new();
if dir.join("CMakeLists.txt").exists() {
if ctx.flags.verbose {
writeln!(ctx.io.output, " Found CMakeLists.txt").ok();
}
detected.push(BuildSystem::Cmake);
}
if dir.join("meson.build").exists() {
if ctx.flags.verbose {
writeln!(ctx.io.output, " Found meson.build").ok();
}
detected.push(BuildSystem::Meson);
}
if dir.join("package.json").exists() {
if ctx.flags.verbose {
writeln!(ctx.io.output, " Found package.json").ok();
}
detected.push(BuildSystem::Npm);
}
pick_build_system(&detected, "No supported build system found", ctx)
Expand All @@ -50,16 +59,24 @@ pub fn detect_mono_build_system(
dirs: &[PathBuf],
ctx: &mut RunCtx<'_, '_>,
) -> Result<BuildSystem, String> {
writeln!(ctx.io.output, "Detecting build system\n").ok();
crate::time!(ctx.flags.timing, ctx.io.output, "Detect", {
crate::time!(ctx.flags.timing, ctx.io.output, "Scanned directories", {
let mut detected = Vec::new();
if dirs.iter().all(|d| d.join("CMakeLists.txt").exists()) {
if ctx.flags.verbose {
writeln!(ctx.io.output, " Found CMakeLists.txt").ok();
}
detected.push(BuildSystem::Cmake);
}
if dirs.iter().all(|d| d.join("meson.build").exists()) {
if ctx.flags.verbose {
writeln!(ctx.io.output, " Found meson.build").ok();
}
detected.push(BuildSystem::Meson);
}
if dirs.iter().all(|d| d.join("package.json").exists()) {
if ctx.flags.verbose {
writeln!(ctx.io.output, " Found package.json").ok();
}
detected.push(BuildSystem::Npm);
}
pick_build_system(
Expand Down
41 changes: 19 additions & 22 deletions src/cli/commands.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::path::PathBuf;

use crate::cli::{BuildFlags, ConnectionFlags, DiagnosticFlags, MonoRepoFlags};
use clap::{Parser, Subcommand};
use clap::{Args as ClapArgs, Parser, Subcommand};

/// Config subcommand.
#[derive(Parser)]
Expand Down Expand Up @@ -70,38 +70,35 @@ pub struct WorkspaceCommand {
pub action: WorkspaceAction,
}

/// Workspace subcommand actions.
#[derive(ClapArgs)]
pub struct WorkspaceTarget {
/// Workspace root directory (default: current directory).
#[arg(long)]
pub path: Option<PathBuf>,
/// Mono-repo workspace directory name (default: build-mono).
#[arg(long)]
pub mono_dir: Option<String>,
#[arg(long)]
pub build_dir: Option<String>,
}

#[derive(Subcommand)]
pub enum WorkspaceAction {
/// Pull latest changes for all repos in the workspace.
Update {
/// Workspace root directory (default: current directory).
#[arg(long)]
path: Option<PathBuf>,
/// Mono-repo workspace directory name (default: build-mono).
#[arg(long)]
mono_dir: Option<String>,
#[arg(long)]
build_dir: Option<String>,
#[command(flatten)]
target: WorkspaceTarget,
},
/// Show status of all repos in the workspace.
Status {
#[arg(long)]
path: Option<PathBuf>,
#[arg(long)]
mono_dir: Option<String>,
#[arg(long)]
build_dir: Option<String>,
#[command(flatten)]
target: WorkspaceTarget,
#[arg(long)]
fetch: bool,
},
/// Remove the build directory from the workspace.
Clean {
#[arg(long)]
path: Option<PathBuf>,
#[arg(long)]
mono_dir: Option<String>,
#[arg(long)]
build_dir: Option<String>,
#[command(flatten)]
target: WorkspaceTarget,
},
}
14 changes: 9 additions & 5 deletions src/cli/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use clap::Args as ClapArgs;

#[allow(clippy::struct_excessive_bools)]
#[derive(ClapArgs)]
#[command(next_help_heading = "Connection")]
pub struct ConnectionFlags {
/// Use SSH instead of HTTPS for cloning
#[arg(long, conflicts_with = "https")]
Expand All @@ -14,9 +15,10 @@ pub struct ConnectionFlags {

#[allow(clippy::struct_excessive_bools)]
#[derive(ClapArgs)]
#[command(next_help_heading = "Build")]
pub struct BuildFlags {
/// Build type
#[arg(short = 'b', long)]
#[arg(long)]
pub build_type: Option<String>,

/// Build directory name
Expand All @@ -27,8 +29,8 @@ pub struct BuildFlags {
#[arg(long, value_name = "BUILD_SYSTEM")]
pub build_system: Option<BuildSystem>,

// Build after configuring (overrides config)
#[arg(long, conflicts_with = "no_build")]
/// Build after configuring (overrides config)
#[arg(short = 'b', long, conflicts_with = "no_build")]
pub build: bool,
/// Skip building, only configure
#[arg(short = 'n', long, conflicts_with = "build")]
Expand Down Expand Up @@ -58,6 +60,7 @@ pub struct BuildFlags {
}

#[derive(ClapArgs)]
#[command(next_help_heading = "Mono-repo")]
pub struct MonoRepoFlags {
/// Mono-repo mode
#[arg(long)]
Expand All @@ -72,12 +75,13 @@ pub struct MonoRepoFlags {
pub repos: Option<Vec<String>>,

/// Use saved profile for library repositories
#[arg(long, conflicts_with = "repos")]
#[arg(short = 'p', long, conflicts_with = "repos")]
pub profile: Option<String>,
}

#[allow(clippy::struct_excessive_bools)]
#[derive(ClapArgs)]
#[command(next_help_heading = "Diagnostics")]
pub struct DiagnosticFlags {
/// Show detailed command output
#[arg(short = 'v', long, conflicts_with = "no_verbose")]
Expand All @@ -97,6 +101,6 @@ pub struct DiagnosticFlags {
#[arg(long)]
pub dry_run: bool,
/// Do not use dry-run mode (overrides config)
#[arg(long, conflicts_with = "no_dry_run")]
#[arg(long, conflicts_with = "dry_run")]
pub no_dry_run: bool,
}
13 changes: 8 additions & 5 deletions src/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub fn cmake_build(
});

if !args.build.no_build {
writeln!(ctx.io.output, "Building project\n").ok();
writeln!(ctx.io.output, "Building project").ok();
crate::time!(ctx.flags.timing, ctx.io.output, "CMake build", {
ctx.runner.run(
&[
Expand Down Expand Up @@ -75,7 +75,7 @@ pub fn meson_build(
ctx.runner.run(&meson_cmd, None, ctx.flags, ctx.io.output)?;
});
if !args.build.no_build {
writeln!(ctx.io.output, "Building project\n").ok();
writeln!(ctx.io.output, "Building project").ok();
crate::time!(ctx.flags.timing, ctx.io.output, "Meson compile", {
ctx.runner.run(
&["meson", "compile", "-C", to_str(build_path)?],
Expand All @@ -97,6 +97,7 @@ pub fn npm_build(
is_mono: bool,
ctx: &mut RunCtx<'_, '_>,
) -> Result<(), String> {
writeln!(ctx.io.output, "Installing dependencies").ok();
crate::time!(ctx.flags.timing, ctx.io.output, "npm install", {
ctx.runner.run(
&["npm", "install"],
Expand All @@ -106,7 +107,7 @@ pub fn npm_build(
)?;
});
if !args.build.no_build && !is_mono {
writeln!(ctx.io.output, "Building project\n").ok();
writeln!(ctx.io.output, "Building project").ok();
crate::time!(ctx.flags.timing, ctx.io.output, "npm build", {
ctx.runner.run(
&["npm", "run", "build"],
Expand All @@ -130,9 +131,11 @@ pub fn build_project(
mono: bool,
ctx: &mut RunCtx<'_, '_>,
) -> Result<(), String> {
match build_system {
let result = match build_system {
BuildSystem::Cmake => cmake_build(args, build_path, mono, ctx),
BuildSystem::Meson => meson_build(args, build_path, source_path, ctx),
BuildSystem::Npm => npm_build(args, source_path, mono, ctx),
}
};
writeln!(ctx.io.output).ok();
result
}
46 changes: 21 additions & 25 deletions src/commands/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,36 +63,32 @@ pub fn handle_profile_cmd(
/// # Errors
/// Returns an error if resolving, updating, cleaning, or fetching status for the workspace fails.
pub fn handle_workspace_cmd(
action: WorkspaceAction,
io: IoCtx,
action: &WorkspaceAction,
mut io: IoCtx,
flags: RunFlags,
) -> Result<(), Box<dyn Error>> {
let target = match &action {
WorkspaceAction::Update { target }
| WorkspaceAction::Clean { target }
| WorkspaceAction::Status { target, .. } => target,
};
let ws = resolve_workspace(
target.path.as_deref(),
target.mono_dir.as_deref(),
target.build_dir.as_deref(),
&mut io,
flags.verbose,
)?;

match action {
WorkspaceAction::Update {
path,
mono_dir,
build_dir,
} => {
let ws = resolve_workspace(path.as_deref(), mono_dir.as_deref(), build_dir.as_deref())?;
with_runner(io, flags, |ctx| ws.update(ctx).map_err(Into::into))?;
WorkspaceAction::Update { .. } => {
with_runner(io, flags, |ctx| ws.update(ctx).map_err(Into::into))
}
WorkspaceAction::Status {
path,
mono_dir,
build_dir,
fetch,
} => {
let ws = resolve_workspace(path.as_deref(), mono_dir.as_deref(), build_dir.as_deref())?;
with_runner(io, flags, |ctx| ws.status(fetch, ctx).map_err(Into::into))?;
WorkspaceAction::Status { fetch, .. } => {
with_runner(io, flags, |ctx| ws.status(*fetch, ctx).map_err(Into::into))
}
WorkspaceAction::Clean {
path,
mono_dir,
build_dir,
} => {
let ws = resolve_workspace(path.as_deref(), mono_dir.as_deref(), build_dir.as_deref())?;
with_runner(io, flags, |ctx| ws.clean(ctx).map_err(Into::into))?;
WorkspaceAction::Clean { .. } => {
with_runner(io, flags, |ctx| ws.clean(ctx).map_err(Into::into))
}
}
Ok(())
}
4 changes: 4 additions & 0 deletions src/commands/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub struct ModeHeader<'a> {
pub mono_dir: Option<&'a str>,
pub profile: Option<&'a str>,
pub lib_count: Option<usize>,
pub repo_count: Option<usize>,
}

/// Prints a formatted header summarizing the current mode and configuration.
Expand All @@ -36,5 +37,8 @@ pub fn print_mode_header(header: &ModeHeader<'_>, io: &mut IoCtx<'_>) {
if let Some(c) = header.lib_count {
writeln!(io.output, " Libraries: {c}").ok();
}
if let Some(c) = header.repo_count {
writeln!(io.output, " Total repositories: {c}").ok();
}
writeln!(io.output).ok();
}
2 changes: 1 addition & 1 deletion src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ pub use mono::{
pub mod single;
pub use single::single_repo_mode;
pub mod setup;
pub use setup::{configure_and_build, extract_repo_input, prepare_build_dir};
pub use setup::{extract_repo_input, prepare_build_dir};
pub mod handlers;
pub use handlers::{handle_config_cmd, handle_profile_cmd, handle_workspace_cmd};
25 changes: 18 additions & 7 deletions src/commands/mono/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,26 @@ pub fn clone_mono_repos(
writeln!(ctx.io.output, "Cloning repositories").ok();
crate::time!(ctx.flags.timing, ctx.io.output, "Clone", {
for repo in repos {
clone_repository(repo, repos_path, ssh, ctx)?;
if ctx.flags.verbose {
writeln!(
ctx.io.output,
" Cloning {}",
crate::repository::repo_dir_name(repo)
)
.ok();
}
clone_repository(repo, repos_path, ssh, true, false, ctx)?;
}
if ctx.flags.verbose {
writeln!(
ctx.io.output,
" Finished cloning ({} repositories)",
repos.len()
)
.ok();
}
Ok::<(), String>(())
})?;
writeln!(
ctx.io.output,
"\n Finished cloning ({} repositories)\n",
repos.len()
)
.ok();
writeln!(ctx.io.output).ok();
Ok(())
}
Loading
Loading