git_proc/
commit.rs

1use std::ffi::OsStr;
2use std::path::Path;
3
4use crate::CommandError;
5
6/// Create a new `git commit` command builder.
7#[must_use]
8pub fn new() -> Commit<'static> {
9    Commit::new()
10}
11
12/// Builder for `git commit` command.
13///
14/// See `git commit --help` for full documentation.
15#[derive(Debug)]
16pub struct Commit<'a> {
17    repo_path: Option<&'a Path>,
18    message: Option<&'a str>,
19    author: Option<&'a str>,
20    date: Option<&'a str>,
21    allow_empty: bool,
22    allow_empty_message: bool,
23    env_vars: Vec<(cmd_proc::EnvVariableName<'a>, &'a OsStr)>,
24}
25
26impl<'a> Commit<'a> {
27    #[must_use]
28    fn new() -> Self {
29        Self {
30            repo_path: None,
31            message: None,
32            author: None,
33            date: None,
34            allow_empty: false,
35            allow_empty_message: false,
36            env_vars: Vec::new(),
37        }
38    }
39
40    /// Set the repository path (`-C <path>`).
41    #[must_use]
42    pub fn repo_path(mut self, path: &'a Path) -> Self {
43        self.repo_path = Some(path);
44        self
45    }
46
47    /// Set the commit message.
48    ///
49    /// Corresponds to `--message` or `-m`.
50    #[must_use]
51    pub fn message(mut self, message: &'a str) -> Self {
52        self.message = Some(message);
53        self
54    }
55
56    /// Set the commit author.
57    ///
58    /// Corresponds to `--author`. Format: `Name <email>`.
59    #[must_use]
60    pub fn author(mut self, author: &'a str) -> Self {
61        self.author = Some(author);
62        self
63    }
64
65    /// Set the author date.
66    ///
67    /// Corresponds to `--date`.
68    #[must_use]
69    pub fn date(mut self, date: &'a str) -> Self {
70        self.date = Some(date);
71        self
72    }
73
74    crate::flag_methods! {
75        /// Allow creating a commit with no changes.
76        ///
77        /// Corresponds to `--allow-empty`.
78        pub fn allow_empty / allow_empty_if, allow_empty, "Conditionally allow creating a commit with no changes."
79    }
80
81    crate::flag_methods! {
82        /// Allow creating a commit with an empty message.
83        ///
84        /// Corresponds to `--allow-empty-message`.
85        pub fn allow_empty_message / allow_empty_message_if, allow_empty_message, "Conditionally allow creating a commit with an empty message."
86    }
87
88    /// Set an environment variable for the command.
89    #[must_use]
90    pub fn env(mut self, key: cmd_proc::EnvVariableName<'a>, value: &'a OsStr) -> Self {
91        self.env_vars.push((key, value));
92        self
93    }
94
95    /// Execute the command and return the exit status.
96    pub fn status(self) -> Result<(), CommandError> {
97        self.build().status()
98    }
99
100    fn build(self) -> cmd_proc::Command {
101        crate::base_command(self.repo_path)
102            .argument("commit")
103            .optional_option("--message", self.message)
104            .optional_option("--author", self.author)
105            .optional_option("--date", self.date)
106            .optional_argument(self.allow_empty.then_some("--allow-empty"))
107            .optional_argument(self.allow_empty_message.then_some("--allow-empty-message"))
108            .envs(self.env_vars)
109    }
110}
111
112impl Default for Commit<'_> {
113    fn default() -> Self {
114        Self::new()
115    }
116}
117
118#[cfg(feature = "test-utils")]
119impl Commit<'_> {
120    /// Compare the built command with another command using debug representation.
121    pub fn test_eq(&self, other: &cmd_proc::Command) {
122        let command = Self {
123            repo_path: self.repo_path,
124            message: self.message,
125            author: self.author,
126            date: self.date,
127            allow_empty: self.allow_empty,
128            allow_empty_message: self.allow_empty_message,
129            env_vars: self.env_vars.clone(),
130        }
131        .build();
132        command.test_eq(other);
133    }
134}