Skip to main content

git_atomic/cli/commands/
commit.rs

1use crate::cli::CommitArgs;
2use crate::cli::output::Printer;
3use crate::core::effect::{self, Effect};
4use crate::core::refspec::RefSpec;
5use crate::core::{ComponentMatcher, Error, GitError};
6use std::path::Path;
7
8pub fn run(
9    args: &CommitArgs,
10    config_path: &Path,
11    dry_run: bool,
12    printer: &Printer,
13) -> Result<(), Error> {
14    let repo = crate::git::open_repo(
15        &std::env::current_dir().map_err(|e| Error::General(e.to_string()))?,
16    )?;
17
18    let resolved = crate::config::load_layered_config(Some(&repo), config_path)?;
19
20    if resolved.components.is_empty() {
21        return Err(Error::General(
22            "No components defined. Create .atomic.toml with [[components]] or run git-atomic init."
23                .into(),
24        ));
25    }
26
27    let cfg = resolved.to_config();
28    let matcher = ComponentMatcher::from_config(&cfg)?;
29
30    let refspec = RefSpec::parse(&args.source_ref).map_err(Error::General)?;
31
32    let (results, mut effects) = match refspec {
33        RefSpec::Single(ref_str) => {
34            let source_id = crate::git::resolve_commit(&repo, &ref_str)?;
35            crate::git::atomize::plan_atomize(&repo, &cfg, &matcher, source_id, args.force)?
36        }
37        RefSpec::Range { start, end } => {
38            let start_id = crate::git::resolve_commit(&repo, &start).map_err(|e| {
39                GitError::Operation(format!(
40                    "could not resolve '{}' (left side of range '{}..{}'): {}",
41                    start, start, end, e
42                ))
43            })?;
44            let end_id = crate::git::resolve_commit(&repo, &end).map_err(|e| {
45                GitError::Operation(format!(
46                    "could not resolve '{}' (right side of range '{}..{}'): {}",
47                    end, start, end, e
48                ))
49            })?;
50            let commits = crate::git::walk::walk_range(&repo, start_id, end_id)?;
51            let effective = crate::git::walk::effective_files(&repo, start_id, end_id)?;
52            crate::git::atomize::plan_atomize_range(
53                &repo, &cfg, &matcher, &commits, &effective, args.force,
54            )?
55        }
56    };
57
58    if (args.push || args.ci_mode) && !results.is_empty() {
59        let branches: Vec<String> = results.iter().map(|r| r.branch.clone()).collect();
60        effects.push(Effect::Push {
61            remote: args.remote.clone(),
62            branches,
63        });
64    }
65
66    effect::execute(Some(&repo), &effects, dry_run, printer)?;
67    printer.print_commit_results(&results, dry_run);
68
69    Ok(())
70}