Repository: cocogitto/cocogitto
Pull request #373 (2024-02-29 17:19:31)

Add files option for cog commit
Resolves https://github.com/cocogitto/cocogitto/issues/354

ABWassim: @oknozor Additionally I refactored the `skip-ci` String process for the `cog commit` command (removed the potential trailing whitespace at the end of the commit) and enforced test results for that feature
oknozor: Hey @ABWassim can you rebase main ? 
ABWassim: @oknozor just rebased :)

Patch:
diff --git a/docs/website/config/README.md b/docs/website/config/README.md
index df2d75f..f871171 100755
--- a/docs/website/config/README.md
+++ b/docs/website/config/README.md
@@ -215,6 +215,19 @@ The config reference list all value that can be set in the `cog.toml` file at th
     disable_changelog = true
     ```
 
+### `disable_bump_commit`
+
+- Type: `boolean`
+- Optional: `true`
+- Default value: `false`
+- Description: Cocogitto will not create a bump commit and will instead tag the latest commit.
+- Example:
+    ```toml
+    disable_bump_commit = true
+    ```
+- Also see:
+    * [User guide -> Disable bump commit creation](../guide/#disable-bump-commit-creation)
+
 ## Changelog
 
 ### `path`
diff --git a/docs/website/guide/README.md b/docs/website/guide/README.md
index 6744922..b97c07e 100644
--- a/docs/website/guide/README.md
+++ b/docs/website/guide/README.md
@@ -1039,6 +1039,22 @@ Date: Tue Mar 7 15:06:18 2023 +0200
 
 By default, Cocogitto will abort bump if there are uncommited or untracked changes. You can change this behavior using the `skip_untracked` configuration in the `cog.toml` file or the `--skip-untracked` option of the `bump` command. If so, the warning will be printed to `stderr` and the bump will continue.
 
+## Disable bump commit creation
+
+When bumping by default, Cocogitto will create a commit that will include the Changelog(s), the tag(s) and any file updated in the `pre_bump_hooks`.
+
+**Example with a monorepo** :
+
+```bash
+❯ git log
+commit xxx (HEAD -> main, tag: 0.1.0, tag: one-0.1.0)
+Author: John Doe <jon.doe@unknown.com>
+Date: Tue Mar 7 15:06:18 2023 +0200
+    chore(version): bump packages
+```
+
+To disable its creation, you can use the `disable_bump_commit` configuration in the `cog.toml` or the `--disable-bump-commit` option of the `cog bump` command. In that case, Cocogitto will create the tag(s) on the latest commit and will not commit the files mentionned above. They will have to be manually commited, for example using the `post_bump_hooks`.
+
 ## Get the current version
 
 It's sometime needed to display the current version for scripting purpose. 
diff --git a/src/bin/cog/main.rs b/src/bin/cog/main.rs
index 9dd7eab..4853162 100644
--- a/src/bin/cog/main.rs
+++ b/src/bin/cog/main.rs
@@ -294,6 +294,10 @@ enum Command {
         /// Don't fail if there are untracked or uncommited files
         #[arg(long = "skip-untracked")]
         skip_untracked: bool,
+
+        /// Disable the creation of the bump commit
+        #[arg(long = "disable-bump-commit")]
+        disable_bump_commit: bool,
     },
 
     /// Install cog config files
@@ -359,6 +363,14 @@ struct CommitArgs {
     /// Override and add the <SKIP_CI_OVERRIDE> string to the commit
     #[arg(long = "skip-ci-override")]
     skip_ci_override: Option<String>,
+
+    /// Add files to the commit (similar to git add .)
+    #[arg(short, long = "add")]
+    add_files: bool,
+
+    /// Update but doesn't add files to the commit (similar to git add -u .)
+    #[arg(short, long = "update")]
+    update_files: bool,
 }
 
 fn main() -> Result<()> {
@@ -385,6 +397,7 @@ fn main() -> Result<()> {
             skip_ci,
             skip_ci_override,
             skip_untracked,
+            disable_bump_commit,
         } => {
             let mut cocogitto = CocoGitto::get()?;
             let is_monorepo = !SETTINGS.packages.is_empty();
@@ -424,6 +437,7 @@ fn main() -> Result<()> {
                             skip_ci,
                             skip_ci_override,
                             skip_untracked,
+                            disable_bump_commit,
                         };
 
                         cocogitto.create_package_version(opts)?
@@ -438,6 +452,7 @@ fn main() -> Result<()> {
                             skip_ci,
                             skip_ci_override,
                             skip_untracked,
+                            disable_bump_commit,
                         };
 
                         cocogitto.create_monorepo_version(opts)?
@@ -453,6 +468,7 @@ fn main() -> Result<()> {
                     skip_ci,
                     skip_ci_override,
                     skip_untracked,
+                    disable_bump_commit,
                 };
                 cocogitto.create_version(opts)?
             }
@@ -613,18 +629,22 @@ fn main() -> Result<()> {
             sign,
             skip_ci,
             skip_ci_override,
+            add_files,
+            update_files,
         }) => {
             let cocogitto = CocoGitto::get()?;
             cocogitto.run_commit_hook(CommitHook::PreCommit)?;
             let commit_message_path = cocogitto.prepare_edit_message_path();
 
-            let mut skip_ci_pattern = String::new();
-
-            if skip_ci || skip_ci_override.is_some() {
-                skip_ci_pattern = skip_ci_override.unwrap_or(SETTINGS.skip_ci.clone())
-            }
-
-            let commit_message = message + " " + &skip_ci_pattern;
+            let commit_message = if skip_ci || skip_ci_override.is_some() {
+                format!(
+                    "{} {}",
+                    message,
+                    skip_ci_override.unwrap_or(SETTINGS.skip_ci.clone())
+                )
+            } else {
+                message
+            };
 
             let template = prepare_edit_message(
                 &typ,
@@ -649,6 +669,8 @@ fn main() -> Result<()> {
                 footer,
                 breaking,
                 sign,
+                add_files,
+                update_files,
             };
 
             cocogitto.conventional_commit(opts)?;
diff --git a/src/command/bump/mod.rs b/src/command/bump/mod.rs
index a7b5c48..4aa114f 100644
--- a/src/command/bump/mod.rs
+++ b/src/command/bump/mod.rs
@@ -35,6 +35,7 @@ pub struct BumpOptions<'a> {
     pub skip_ci: bool,
     pub skip_ci_override: Option<String>,
     pub skip_untracked: bool,
+    pub disable_bump_commit: bool,
 }
 
 #[derive(Default)]
@@ -49,6 +50,7 @@ pub struct PackageBumpOptions<'a> {
     pub skip_ci: bool,
     pub skip_ci_override: Option<String>,
     pub skip_untracked: bool,
+    pub disable_bump_commit: bool,
 }
 
 struct HookRunOptions<'a> {
diff --git a/src/command/bump/monorepo.rs b/src/command/bump/monorepo.rs
index b3f4acc..33c7b42 100644
--- a/src/command/bump/monorepo.rs
+++ b/src/command/bump/monorepo.rs
@@ -76,26 +76,30 @@ impl CocoGitto {
         let hook_result =
             self.run_hooks(HookRunOptions::pre_bump().hook_profile(opts.hooks_config));
 
+        let disable_bump_commit = opts.disable_bump_commit || SETTINGS.disable_bump_commit;
+
         self.repository.add_all()?;
         self.unwrap_or_stash_and_exit(&Tag::default(), hook_result);
         self.bump_packages(opts.pre_release, opts.hooks_config, &bumps)?;
 
-        let sign = self.repository.gpg_sign();
-
-        let mut skip_ci_pattern = String::new();
-
-        if opts.skip_ci || opts.skip_ci_override.is_some() {
-            skip_ci_pattern = opts.skip_ci_override.unwrap_or(SETTINGS.skip_ci.clone());
+        if !disable_bump_commit {
+            let sign = self.repository.gpg_sign();
+            if opts.skip_ci || opts.skip_ci_override.is_some() {
+                let skip_ci_pattern = opts.skip_ci_override.unwrap_or(SETTINGS.skip_ci.clone());
+                self.repository.commit(
+                    &format!("chore(version): bump packages {}", skip_ci_pattern),
+                    sign,
+                    true,
+                )?;
+            } else {
+                self.repository
+                    .commit("chore(version): bump packages", sign, true)?;
+            }
         }
 
-        self.repository.commit(
-            &format!("chore(version): bump packages {}", skip_ci_pattern),
-            sign,
-            true,
-        )?;
-
         for bump in &bumps {
-            self.repository.create_tag(&bump.new_version.prefixed_tag)?;
+            self.repository
+                .create_tag(&bump.new_version.prefixed_tag, disable_bump_commit)?;
         }
 
         // Run per package post hooks
@@ -221,30 +225,35 @@ impl CocoGitto {
         );
 
         self.repository.add_all()?;
-
-        self.unwrap_or_stash_and_exit(&tag, hook_result);
-
+        self.unwrap_or_stash_and_exit(&Tag::default(), hook_result);
         self.bump_packages(opts.pre_release, opts.hooks_config, &bumps)?;
 
-        let sign = self.repository.gpg_sign();
-
-        let mut skip_ci_pattern = String::new();
-
-        if opts.skip_ci || opts.skip_ci_override.is_some() {
-            skip_ci_pattern = opts.skip_ci_override.unwrap_or(SETTINGS.skip_ci.clone());
+        let disable_bump_commit = opts.disable_bump_commit || SETTINGS.disable_bump_commit;
+
+        if !disable_bump_commit {
+            let sign = self.repository.gpg_sign();
+            if opts.skip_ci || opts.skip_ci_override.is_some() {
+                let skip_ci_pattern = opts.skip_ci_override.unwrap_or(SETTINGS.skip_ci.clone());
+                self.repository.commit(
+                    &format!(
+                        "chore(version): {} {}",
+                        next_version.prefixed_tag, skip_ci_pattern
+                    ),
+                    sign,
+                    true,
+                )?;
+            } else {
+                self.repository.commit(
+                    &format!("chore(version): {}", next_version.prefixed_tag),
+                    sign,
+                    true,
+                )?;
+            }
         }
 
-        self.repository.commit(
-            &format!(
-                "chore(version): {} {}",
-                next_version.prefixed_tag, skip_ci_pattern
-            ),
-            sign,
-            true,
-        )?;
-
         for bump in &bumps {
-            self.repository.create_tag(&bump.new_version.prefixed_tag)?;
+            self.repository
+                .create_tag(&bump.new_version.prefixed_tag, disable_bump_commit)?;
         }
 
         if let Some(msg_tmpl) = opts.annotated {
@@ -252,9 +261,10 @@ impl CocoGitto {
             context.insert("latest", &old.version.to_string());
             context.insert("version", &tag.version.to_string());
             let msg = Tera::one_off(&msg_tmpl, &context, false)?;
-            self.repository.create_annotated_tag(&tag, &msg)?;
+            self.repository
+                .create_annotated_tag(&tag, &msg, disable_bump_commit)?;
         } else {
-            self.repository.create_tag(&tag)?;
+            self.repository.create_tag(&tag, disable_bump_commit)?;
         }
 
         // Run per package post hooks
@@ -353,33 +363,41 @@ impl CocoGitto {
         );
 
         self.repository.add_all()?;
-        self.unwrap_or_stash_and_exit(&tag, hook_result);
-
-        let sign = self.repository.gpg_sign();
-
-        let mut skip_ci_pattern = String::new();
+        self.unwrap_or_stash_and_exit(&Tag::default(), hook_result);
 
-        if opts.skip_ci || opts.skip_ci_override.is_some() {
-            skip_ci_pattern = opts.skip_ci_override.unwrap_or(SETTINGS.skip_ci.clone());
+        let disable_bump_commit = opts.disable_bump_commit || SETTINGS.disable_bump_commit;
+
+        if !disable_bump_commit {
+            let sign = self.repository.gpg_sign();
+
+            if opts.skip_ci || opts.skip_ci_override.is_some() {
+                let skip_ci_pattern = opts.skip_ci_override.unwrap_or(SETTINGS.skip_ci.clone());
+                self.repository.commit(
+                    &format!(
+                        "chore(version): {} {}",
+                        next_version.prefixed_tag, skip_ci_pattern
+                    ),
+                    sign,
+                    true,
+                )?;
+            } else {
+                self.repository.commit(
+                    &format!("chore(version): {}", next_version.prefixed_tag),
+                    sign,
+                    true,
+                )?;
+            }
         }
 
-        self.repository.commit(
-            &format!(
-                "chore(version): {} {}",
-                next_version.prefixed_tag, skip_ci_pattern
-            ),
-            sign,
-            true,
-        )?;
-
         if let Some(msg_tmpl) = opts.annotated {
             let mut context = tera::Context::new();
             context.insert("latest", &old.version.to_string());
             context.insert("version", &tag.version.to_string());
             let msg = Tera::one_off(&msg_tmpl, &context, false)?;
-            self.repository.create_annotated_tag(&tag, &msg)?;
+            self.repository
+                .create_annotated_tag(&tag, &msg, disable_bump_commit)?;
         } else {
-            self.repository.create_tag(&tag)?;
+            self.repository.create_tag(&tag, disable_bump_commit)?;
         }
 
         // Run global post hooks
diff --git a/src/command/bump/package.rs b/src/command/bump/package.rs
index 85fd202..9591dc6 100644
--- a/src/command/bump/package.rs
+++ b/src/command/bump/package.rs
@@ -81,30 +81,35 @@ impl CocoGitto {
         );
 
         self.repository.add_all()?;
-        self.unwrap_or_stash_and_exit(&tag, hook_result);
-
-        let sign = self.repository.gpg_sign();
-
-        let mut skip_ci_pattern = String::new();
-
-        if opts.skip_ci || opts.skip_ci_override.is_some() {
-            skip_ci_pattern = opts.skip_ci_override.unwrap_or(SETTINGS.skip_ci.clone());
+        self.unwrap_or_stash_and_exit(&Tag::default(), hook_result);
+
+        let disable_bump_commit = opts.disable_bump_commit || SETTINGS.disable_bump_commit;
+
+        if !disable_bump_commit {
+            let sign = self.repository.gpg_sign();
+
+            if opts.skip_ci || opts.skip_ci_override.is_some() {
+                let skip_ci_pattern = opts.skip_ci_override.unwrap_or(SETTINGS.skip_ci.clone());
+                self.repository.commit(
+                    &format!("chore(version): {tag} {}", skip_ci_pattern),
+                    sign,
+                    true,
+                )?;
+            } else {
+                self.repository
+                    .commit(&format!("chore(version): {tag}"), sign, true)?;
+            }
         }
 
-        self.repository.commit(
-            &format!("chore(version): {tag} {}", skip_ci_pattern),
-            sign,
-            true,
-        )?;
-
         if let Some(msg_tmpl) = opts.annotated {
             let mut context = tera::Context::new();
             context.insert("latest", &current_tag.version.to_string());
             context.insert("version", &tag.version.to_string());
             let msg = Tera::one_off(&msg_tmpl, &context, false)?;
-            self.repository.create_annotated_tag(&tag, &msg)?;
+            self.repository
+                .create_annotated_tag(&tag, &msg, disable_bump_commit)?;
         } else {
-            self.repository.create_tag(&tag)?;
+            self.repository.create_tag(&tag, disable_bump_commit)?;
         }
 
         self.run_hooks(
diff --git a/src/command/bump/standard.rs b/src/command/bump/standard.rs
index f301c67..c4828df 100644
--- a/src/command/bump/standard.rs
+++ b/src/command/bump/standard.rs
@@ -66,33 +66,41 @@ impl CocoGitto {
         );
 
         self.repository.add_all()?;
-        self.unwrap_or_stash_and_exit(&tag, hook_result);
-
-        let sign = self.repository.gpg_sign();
-
-        let mut skip_ci_pattern = String::new();
-
-        if opts.skip_ci || opts.skip_ci_override.is_some() {
-            skip_ci_pattern = opts.skip_ci_override.unwrap_or(SETTINGS.skip_ci.clone());
+        self.unwrap_or_stash_and_exit(&Tag::default(), hook_result);
+
+        let disable_bump_commit = opts.disable_bump_commit || SETTINGS.disable_bump_commit;
+
+        if !disable_bump_commit {
+            let sign = self.repository.gpg_sign();
+
+            if opts.skip_ci || opts.skip_ci_override.is_some() {
+                let skip_ci_pattern = opts.skip_ci_override.unwrap_or(SETTINGS.skip_ci.clone());
+                self.repository.commit(
+                    &format!(
+                        "chore(version): {} {}",
+                        next_version.prefixed_tag, skip_ci_pattern
+                    ),
+                    sign,
+                    true,
+                )?;
+            } else {
+                self.repository.commit(
+                    &format!("chore(version): {}", next_version.prefixed_tag),
+                    sign,
+                    true,
+                )?;
+            }
         }
 
-        self.repository.commit(
-            &format!(
-                "chore(version): {} {}",
-                next_version.prefixed_tag, skip_ci_pattern
-            ),
-            sign,
-            true,
-        )?;
-
         if let Some(msg_tmpl) = opts.annotated {
             let mut context = tera::Context::new();
             context.insert("latest", &current_tag.version.to_string());
             context.insert("version", &tag.version.to_string());
             let msg = Tera::one_off(&msg_tmpl, &context, false)?;
-            self.repository.create_annotated_tag(&tag, &msg)?;
+            self.repository
+                .create_annotated_tag(&tag, &msg, disable_bump_commit)?;
         } else {
-            self.repository.create_tag(&tag)?;
+            self.repository.create_tag(&tag, disable_bump_commit)?;
         }
 
         self.run_hooks(
diff --git a/src/command/commit.rs b/src/command/commit.rs
index 61a9b1d..c00d327 100644
--- a/src/command/commit.rs
+++ b/src/command/commit.rs
@@ -16,6 +16,8 @@ pub struct CommitOptions<'a> {
     pub footer: Option<String>,
     pub breaking: bool,
     pub sign: bool,
+    pub add_files: bool,
+    pub update_files: bool,
 }
 
 impl CocoGitto {
@@ -42,6 +44,14 @@ impl CocoGitto {
         // Validate the message
         conventional_commit_parser::parse(&conventional_message)?;
 
+        if opts.add_files {
+            self.repository.add_all()?;
+        }
+
+        if opts.update_files {
+            self.repository.update_all()?;
+        }
+
         // Git commit
         let sign = opts.sign || self.repository.gpg_sign();
         fs::write(self.prepare_edit_message_path(), &conventional_message)?;
diff --git a/src/git/repository.rs b/src/git/repository.rs
index 8c8cc67..f75ac36 100644
--- a/src/git/repository.rs
+++ b/src/git/repository.rs
@@ -61,7 +61,13 @@ impl Repository {
 
     pub(crate) fn add_all(&self) -> Result<(), Git2Error> {
         let mut index = self.0.index()?;
-        index.add_all(["*"], IndexAddOption::DEFAULT, None)?;
+        index.add_all(["."], IndexAddOption::DEFAULT, None)?;
+        index.write().map_err(Git2Error::GitAddError)
+    }
+
+    pub(crate) fn update_all(&self) -> Result<(), Git2Error> {
+        let mut index = self.0.index()?;
+        index.update_all(["."], None)?;
         index.write().map_err(Git2Error::GitAddError)
     }
 
diff --git a/src/git/tag.rs b/src/git/tag.rs
index 698e656..9042bf5 100644
--- a/src/git/tag.rs
+++ b/src/git/tag.rs
@@ -50,8 +50,8 @@ impl<'a> TagLookUpOptions<'a> {
 }
 
 impl Repository {
-    pub(crate) fn create_tag(&self, tag: &Tag) -> Result<(), Git2Error> {
-        if self.get_diff(true).is_some() {
+    pub(crate) fn create_tag(&self, tag: &Tag, disable_bump_commit: bool) -> Result<(), Git2Error> {
+        if !disable_bump_commit && self.get_diff(true).is_some() {
             let statuses = self.get_statuses()?;
             return Err(Git2Error::ChangesNeedToBeCommitted(statuses));
         }
@@ -63,8 +63,13 @@ impl Repository {
             .map_err(Git2Error::from)
     }
 
-    pub(crate) fn create_annotated_tag(&self, tag: &Tag, msg: &str) -> Result<(), Git2Error> {
-        if self.get_diff(true).is_some() {
+    pub(crate) fn create_annotated_tag(
+        &self,
+        tag: &Tag,
+        msg: &str,
+        disable_bump_commit: bool,
+    ) -> Result<(), Git2Error> {
+        if !disable_bump_commit && self.get_diff(true).is_some() {
             let statuses = self.get_statuses()?;
             return Err(Git2Error::ChangesNeedToBeCommitted(statuses));
         }
diff --git a/src/settings/mod.rs b/src/settings/mod.rs
index 855a086..35b8b3c 100644
--- a/src/settings/mod.rs
+++ b/src/settings/mod.rs
@@ -32,6 +32,7 @@ pub struct Settings {
     pub from_latest_tag: bool,
     pub ignore_merge_commits: bool,
     pub disable_changelog: bool,
+    pub disable_bump_commit: bool,
     pub generate_mono_repository_global_tag: bool,
     pub monorepo_version_separator: Option<String>,
     pub branch_whitelist: Vec<String>,
@@ -55,6 +56,7 @@ impl Default for Settings {
             from_latest_tag: false,
             ignore_merge_commits: false,
             disable_changelog: false,
+            disable_bump_commit: false,
             generate_mono_repository_global_tag: true,
             monorepo_version_separator: None,
             branch_whitelist: vec![],


Test patch:
diff --git a/tests/cog_tests/bump.rs b/tests/cog_tests/bump.rs
index d5313e9..33eb758 100644
--- a/tests/cog_tests/bump.rs
+++ b/tests/cog_tests/bump.rs
@@ -601,6 +601,28 @@ fn bump_monorepo_with_default_skip_ci_ok() -> Result<()> {
     Ok(())
 }
 
+#[sealed_test]
+fn bump_monorepo_manual_increment_with_default_skip_ci_ok() -> Result<()> {
+    let mut settings = Settings {
+        ..Default::default()
+    };
+    init_monorepo(&mut settings)?;
+
+    Command::cargo_bin("cog")?
+        .arg("bump")
+        .arg("--minor")
+        .arg("--skip-ci")
+        .assert()
+        .success();
+
+    let commit_message = git_log_head_message()?;
+
+    assert_tag_exists("0.1.0")?;
+    assert!(commit_message.contains("[skip ci]"));
+
+    Ok(())
+}
+
 #[sealed_test]
 fn bump_monorepo_with_cog_toml_defined_skip_ci_ok() -> Result<()> {
     let mut settings = Settings {
@@ -648,3 +670,167 @@ fn bump_monorepo_skip_ci_override_option_takes_precedence() -> Result<()> {
 
     Ok(())
 }
+
+#[sealed_test]
+fn bump_only_package_with_default_skip_ci_ok() -> Result<()> {
+    let mut settings = Settings {
+        generate_mono_repository_global_tag: false,
+        ..Default::default()
+    };
+    init_monorepo(&mut settings)?;
+
+    Command::cargo_bin("cog")?
+        .arg("bump")
+        .arg("--auto")
+        .arg("--skip-ci")
+        .assert()
+        .success();
+
+    let commit_message = git_log_head_message()?;
+
+    assert_tag_does_not_exist("0.1.0")?;
+    assert_tag_exists("one-0.1.0")?;
+    assert!(commit_message.contains("[skip ci]"));
+
+    Ok(())
+}
+
+#[sealed_test]
+fn disable_commit_creation_with_config_standard_ok() -> Result<()> {
+    git_init()?;
+
+    git_add("disable_bump_commit = true", "cog.toml")?;
+
+    git_commit("chore: init")?;
+    git_commit("feat: feature")?;
+
+    Command::cargo_bin("cog")?
+        .arg("bump")
+        .arg("--auto")
+        .assert()
+        .success();
+
+    assert_tag_exists("0.1.0")?;
+
+    Command::new("git")
+        .arg("status")
+        .arg("-s")
+        .assert()
+        .success()
+        .stdout(indoc!("A  CHANGELOG.md\n"));
+
+    Ok(())
+}
+
+#[sealed_test]
+fn disable_commit_creation_with_flag_standard_ok() -> Result<()> {
+    git_init()?;
+
+    git_commit("chore: init")?;
+    git_commit("feat: feature")?;
+
+    Command::cargo_bin("cog")?
+        .arg("bump")
+        .arg("--auto")
+        .arg("--disable-bump-commit")
+        .assert()
+        .success();
+
+    assert_tag_exists("0.1.0")?;
+
+    Command::new("git")
+        .arg("status")
+        .arg("-s")
+        .assert()
+        .success()
+        .stdout(indoc!("A  CHANGELOG.md\n"));
+
+    Ok(())
+}
+
+#[sealed_test]
+fn disable_commit_creation_with_pre_bump_hooks_standard_ok() -> Result<()> {
+    git_init()?;
+
+    git_add(
+        "pre_bump_hooks = [\"echo pre_bump_file > pre_bump_file\"]\ndisable_bump_commit = true",
+        "cog.toml",
+    )?;
+
+    git_commit("chore: init")?;
+    git_commit("feat: feature")?;
+
+    Command::cargo_bin("cog")?
+        .arg("bump")
+        .arg("--auto")
+        .arg("--disable-bump-commit")
+        .assert()
+        .success();
+
+    assert_tag_exists("0.1.0")?;
+
+    Command::new("git")
+        .arg("status")
+        .arg("-s")
+        .assert()
+        .success()
+        .stdout(indoc!("A  CHANGELOG.md\nA  pre_bump_file\n"));
+
+    Ok(())
+}
+
+#[sealed_test]
+fn disable_commit_creation_monorepo_ok() -> Result<()> {
+    let mut settings = Settings {
+        disable_bump_commit: true,
+        ..Default::default()
+    };
+    init_monorepo(&mut settings)?;
+
+    Command::cargo_bin("cog")?
+        .arg("bump")
+        .arg("--auto")
+        .assert()
+        .success();
+
+    assert_tag_exists("0.1.0")?;
+    assert_tag_exists("one-0.1.0")?;
+
+    Command::new("git")
+        .arg("status")
+        .arg("-s")
+        .assert()
+        .success()
+        .stdout(indoc!("A  CHANGELOG.md\nA  one/CHANGELOG.md\n"));
+
+    Ok(())
+}
+
+#[sealed_test]
+fn disable_commit_creation_package_ok() -> Result<()> {
+    let mut settings = Settings {
+        disable_bump_commit: true,
+        ..Default::default()
+    };
+    init_monorepo(&mut settings)?;
+
+    Command::cargo_bin("cog")?
+        .arg("bump")
+        .arg("--auto")
+        .arg("--package")
+        .arg("one")
+        .arg("--disable-bump-commit")
+        .assert()
+        .success();
+
+    assert_tag_exists("one-0.1.0")?;
+
+    Command::new("git")
+        .arg("status")
+        .arg("-s")
+        .assert()
+        .success()
+        .stdout(indoc!("A  one/CHANGELOG.md\n"));
+
+    Ok(())
+}
diff --git a/tests/cog_tests/commit.rs b/tests/cog_tests/commit.rs
index ac0f494..5f5587f 100644
--- a/tests/cog_tests/commit.rs
+++ b/tests/cog_tests/commit.rs
@@ -5,6 +5,7 @@ use crate::helpers::*;
 
 use anyhow::Result;
 use assert_cmd::prelude::*;
+use cmd_lib::run_cmd;
 use indoc::{formatdoc, indoc};
 use pretty_assertions::assert_eq;
 use sealed_test::prelude::*;
@@ -150,7 +151,10 @@ fn commit_with_default_skip_ci_ok() -> Result<()> {
 
     let commit_message = git_log_head_message()?;
 
-    assert!(commit_message.contains("[skip ci]"));
+    assert_eq!(
+        commit_message,
+        "feat(scope): this is a commit message [skip ci]"
+    );
 
     Ok(())
 }
@@ -175,7 +179,10 @@ fn commit_with_cog_toml_defined_skip_ci_ok() -> Result<()> {
 
     let commit_message = git_log_head_message()?;
 
-    assert!(commit_message.contains("[ci-skip]"));
+    assert_eq!(
+        commit_message,
+        "feat(scope): this is a commit message [ci-skip]"
+    );
 
     Ok(())
 }
@@ -201,7 +208,76 @@ fn commit_with_skip_ci_override_option_takes_precedence() -> Result<()> {
 
     let commit_message = git_log_head_message()?;
 
-    assert!(commit_message.contains("[skip-ci-override]"));
+    assert_eq!(
+        commit_message,
+        "feat(scope): this is a commit message [skip-ci-override]"
+    );
+
+    Ok(())
+}
+
+#[sealed_test]
+fn add_option_git_commit_ok() -> Result<()> {
+    // Arrange
+    git_init()?;
+    run_cmd!(
+        echo "new file" > new_file;
+        echo "dot file" > .dotfile;
+    )?;
+
+    Command::cargo_bin("cog")?
+        .arg("commit")
+        .arg("-a")
+        .arg("feat")
+        .arg("feature")
+        .assert()
+        .success();
+
+    let commit_message = git_log_head_message()?;
+
+    assert_eq!(commit_message, "feat: feature");
+
+    Command::new("git")
+        .arg("status")
+        .arg("-s")
+        .assert()
+        .success()
+        .stdout(indoc!(""));
+
+    Ok(())
+}
+
+#[sealed_test]
+fn update_option_git_commit_ok() -> Result<()> {
+    // Arrange
+    git_init()?;
+
+    run_cmd!(
+        echo "existing file" > existing_file;
+        git add .;
+        git commit -m "feat: existing file";
+        echo "update existing file" > existing_file;
+        echo "new file" > new_file;
+    )?;
+
+    Command::cargo_bin("cog")?
+        .arg("commit")
+        .arg("-u")
+        .arg("feat")
+        .arg("update existing file")
+        .assert()
+        .success();
+
+    let commit_message = git_log_head_message()?;
+
+    assert_eq!(commit_message, "feat: update existing file");
+
+    Command::new("git")
+        .arg("status")
+        .arg("-s")
+        .assert()
+        .success()
+        .stdout(indoc!("?? new_file\n"));
 
     Ok(())
 }