Repository: cocogitto/cocogitto
Pull request #330 (2023-10-26 12:23:32)

BREAKING CHANGE : skip-ci rework

cocogitto-bot[bot]: :heavy_check_mark: 819f669 - Conventional commits check succeeded.
oknozor: Would be nice to have a few tests for the usage discussed in #316 : 
```
cog commit --skip-ci # works if `skip_ci` pattern is set in cog.toml 
cog commit --skip-ci # fails if `skip_ci` pattern is not set in cog.toml
cog commit --skip-ci "[skip-ci]" # always work, override the current pattern if set
```
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/cocogitto/cocogitto/pull/330?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cocogitto) Report
> Merging [#330](https://app.codecov.io/gh/cocogitto/cocogitto/pull/330?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cocogitto) (819f669) into [main](https://app.codecov.io/gh/cocogitto/cocogitto/commit/3346a84b5f2a8dd7b2482a868599a6985ae2635a?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cocogitto) (3346a84) will **not change** coverage.
> The diff coverage is `100.00%`.

```diff
@@           Coverage Diff           @@
##             main     #330   +/-   ##
=======================================
  Coverage   85.60%   85.60%           
=======================================
  Files          45       45           
  Lines        6427     6427           
=======================================
  Hits         5502     5502           
  Misses        925      925           
```


| [Files](https://app.codecov.io/gh/cocogitto/cocogitto/pull/330?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cocogitto) | Coverage Δ | |
|---|---|---|
| [src/bin/cog/main.rs](https://app.codecov.io/gh/cocogitto/cocogitto/pull/330?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cocogitto#diff-c3JjL2Jpbi9jb2cvbWFpbi5ycw==) | `51.91% <ø> (ø)` | |
| [src/command/bump/monorepo.rs](https://app.codecov.io/gh/cocogitto/cocogitto/pull/330?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cocogitto#diff-c3JjL2NvbW1hbmQvYnVtcC9tb25vcmVwby5ycw==) | `92.05% <100.00%> (ø)` | |
| [src/command/bump/package.rs](https://app.codecov.io/gh/cocogitto/cocogitto/pull/330?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cocogitto#diff-c3JjL2NvbW1hbmQvYnVtcC9wYWNrYWdlLnJz) | `92.68% <100.00%> (ø)` | |
| [src/command/bump/standard.rs](https://app.codecov.io/gh/cocogitto/cocogitto/pull/330?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cocogitto#diff-c3JjL2NvbW1hbmQvYnVtcC9zdGFuZGFyZC5ycw==) | `97.26% <100.00%> (ø)` | |
| [src/settings/mod.rs](https://app.codecov.io/gh/cocogitto/cocogitto/pull/330?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cocogitto#diff-c3JjL3NldHRpbmdzL21vZC5ycw==) | `75.39% <100.00%> (ø)` | |

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cocogitto)

ABWassim: While reading the documentation I came across [default_missing_value](https://docs.rs/clap/latest/clap/struct.Arg.html#method.default_missing_value) which comes handy in our situation :)

The idea is that if no value is provided to the ```--skip-ci``` argument, it defaults to the ```default_missing_value```, which in our case will be equal to the ```skip_ci``` configuration, which defaults to ```[skip ci]``` or the value set in the ```cog.toml```.  If a value is provided to the ```--skip-ci``` argument, ```default_missing_value``` will be omitted.

In the end, we just need to ```unwrap_or_default``` the value to get the right ```skip_ci``` pattern :)

Does it look clean to you ?

Some notes :
- I need to rewrite the commit as a breaking change
- Need to implement this for the ```cog commit``` command
ABWassim: Thanks ! Will work toward this solution for the ```cog commit``` command, and will implement some tests
ABWassim: Hey @oknozor :)

Came across a little issue with the ```commit``` command. Since we're playing the ```num_args``` attribute, it doesn't work quite well when placing the option at the beginning of the command, example :

```cog commit --skip-ci chore "test commit"```

The CLI will think ```chore``` is the parameter of ```skip-ci```, therefore we would need to force place it at the end. [Clap allows this](https://docs.rs/clap/latest/clap/struct.Arg.html#method.last) but it would mean to use ```skip-ci``` like so :
```cog commit chore "test commit" -- <SKIP-CI>```

Trying to find a better way, or we could explicitly tell in the documentation to use this option last.
oknozor: > The CLI will think chore is the parameter of skip-ci, therefore we would need to force place it at the end.

I really don't like the idea, I think this would be confusing.
 
Maybe a better way would be to change the implementation (again) using two flags instead of one.
`--skip-ci` would be a boolean, `--skip-ci-value` a string, only required if the value is not in `cog.toml` or to overwrite it.  

Sorry to change this again, but I was not aware of the clap limitation at first. As the clap maintainer said using [num_args](https://docs.rs/clap/latest/clap/struct.Arg.html#method.num_args) is not recommended. 
ABWassim: Yeah I thought about going this direction too, so I'll guess I'll change the implementation as described above 😊

No worries, we're making progress little by little 😅
cocogitto-bot[bot]: :heavy_check_mark: 5ca55c4 - Conventional commits check succeeded.
ABWassim: Hey @oknozor,

Just reworked the feature as described above : ```skip-ci``` now acts as a boolean that will add the string defined in the cog.toml (or default to [skip ci]), and the ```skip-ci-override``` pattern takes a string that will takes precedence. No need to define both :
```sh
cog <bump|commit> --skip-ci # works, adds default [skip ci] or cog.toml defined string to the commit
cog <bump|commit> --skip-ci-override [ci-skip] # works, adds [ci-skip] to the commit
```

I will write some tests of course but does this implementation looks good to you ?
cocogitto-bot[bot]: :heavy_check_mark: 264d9fc...a33f445 - Conventional commits check succeeded.
cocogitto-bot[bot]: :heavy_check_mark: 0c777e0 - Conventional commits check succeeded.
cocogitto-bot[bot]: :heavy_check_mark: 0c777e0...b0a051b - Conventional commits check succeeded.
ABWassim: @oknozor Just finished everything ! Let me know what you think about :)
cocogitto-bot[bot]: :heavy_check_mark: 83ba155...a1791ac - Conventional commits check succeeded.
oknozor: Kudos @ABWassim. Thanks for the hard work :) 

Patch:
diff --git a/src/bin/cog/main.rs b/src/bin/cog/main.rs
index f0444ad..d2c616a 100644
--- a/src/bin/cog/main.rs
+++ b/src/bin/cog/main.rs
@@ -282,9 +282,13 @@ enum Command {
         #[arg(short, long)]
         dry_run: bool,
 
-        /// Specify a "Skip CI" string to append to the end of the commit
+        /// Add the skip-ci string defined in the cog.toml (or defaults to [skip ci]) to the bump commit
         #[arg(long = "skip-ci")]
-        skip_ci: Option<String>,
+        skip_ci: bool,
+
+        /// Override and add the skip-ci string with the provided value to the bump commit
+        #[arg(long = "skip-ci-override")]
+        skip_ci_override: Option<String>,
 
         /// Don't fail if there are untracked or uncommited files
         #[arg(long = "skip-untracked")]
@@ -346,6 +350,14 @@ struct CommitArgs {
     /// Sign this commit
     #[arg(short, long)]
     sign: bool,
+
+    /// Add the skip-ci string defined in the cog.toml (or defaults to [skip ci]) to the commit
+    #[arg(long = "skip-ci")]
+    skip_ci: bool,
+
+    /// Override and add the <SKIP_CI_OVERRIDE> string to the commit
+    #[arg(long = "skip-ci-override")]
+    skip_ci_override: Option<String>,
 }
 
 fn main() -> Result<()> {
@@ -370,6 +382,7 @@ fn main() -> Result<()> {
             annotated,
             dry_run,
             skip_ci,
+            skip_ci_override,
             skip_untracked,
         } => {
             let mut cocogitto = CocoGitto::get()?;
@@ -406,6 +419,7 @@ fn main() -> Result<()> {
                             annotated,
                             dry_run,
                             skip_ci,
+                            skip_ci_override,
                             skip_untracked,
                         )?
                     }
@@ -416,6 +430,7 @@ fn main() -> Result<()> {
                         annotated,
                         dry_run,
                         skip_ci,
+                        skip_ci_override,
                         skip_untracked,
                     )?,
                 }
@@ -427,6 +442,7 @@ fn main() -> Result<()> {
                     annotated,
                     dry_run,
                     skip_ci,
+                    skip_ci_override,
                     skip_untracked,
                 )?
             }
@@ -588,13 +604,24 @@ fn main() -> Result<()> {
             breaking_change,
             edit,
             sign,
+            skip_ci,
+            skip_ci_override,
         }) => {
             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 template = prepare_edit_message(
                 &typ,
-                &message,
+                &commit_message,
                 scope.as_deref(),
                 breaking_change,
                 &commit_message_path,
@@ -606,7 +633,15 @@ fn main() -> Result<()> {
             } else {
                 (None, None, breaking_change)
             };
-            cocogitto.conventional_commit(&typ, scope, message, body, footer, breaking, sign)?;
+            cocogitto.conventional_commit(
+                &typ,
+                scope,
+                commit_message,
+                body,
+                footer,
+                breaking,
+                sign,
+            )?;
             cocogitto.run_commit_hook(CommitHook::PostCommit)?;
         }
     }
diff --git a/src/command/bump/monorepo.rs b/src/command/bump/monorepo.rs
index b2c444d..0ce1e19 100644
--- a/src/command/bump/monorepo.rs
+++ b/src/command/bump/monorepo.rs
@@ -46,7 +46,8 @@ impl CocoGitto {
         hooks_config: Option<&str>,
         annotated: Option<String>,
         dry_run: bool,
-        skip_ci: Option<String>,
+        skip_ci: bool,
+        skip_ci_override: Option<String>,
         skip_untracked: bool,
     ) -> Result<()> {
         match increment {
@@ -58,6 +59,7 @@ impl CocoGitto {
                         annotated,
                         dry_run,
                         skip_ci,
+                        skip_ci_override,
                         skip_untracked,
                     )
                 } else {
@@ -69,6 +71,7 @@ impl CocoGitto {
                         hooks_config,
                         dry_run,
                         skip_ci,
+                        skip_ci_override,
                         skip_untracked,
                     )
                 }
@@ -80,6 +83,7 @@ impl CocoGitto {
                 annotated,
                 dry_run,
                 skip_ci,
+                skip_ci_override,
                 skip_untracked,
             ),
         }
@@ -90,7 +94,8 @@ impl CocoGitto {
         pre_release: Option<&str>,
         hooks_config: Option<&str>,
         dry_run: bool,
-        skip_ci: Option<String>,
+        skip_ci: bool,
+        skip_ci_override: Option<String>,
         skip_untracked: bool,
     ) -> Result<()> {
         self.pre_bump_checks(skip_untracked)?;
@@ -117,7 +122,11 @@ impl CocoGitto {
 
         let sign = self.repository.gpg_sign();
 
-        let skip_ci_pattern = skip_ci.unwrap_or(SETTINGS.skip_ci.clone().unwrap_or_default());
+        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());
+        }
 
         self.repository.commit(
             &format!("chore(version): bump packages {}", skip_ci_pattern),
@@ -151,13 +160,15 @@ impl CocoGitto {
         Ok(())
     }
 
+    #[allow(clippy::too_many_arguments)]
     fn create_monorepo_version_auto(
         &mut self,
         pre_release: Option<&str>,
         hooks_config: Option<&str>,
         annotated: Option<String>,
         dry_run: bool,
-        skip_ci: Option<String>,
+        skip_ci: bool,
+        skip_ci_override: Option<String>,
         skip_untracked: bool,
     ) -> Result<()> {
         self.pre_bump_checks(skip_untracked)?;
@@ -258,7 +269,11 @@ impl CocoGitto {
 
         let sign = self.repository.gpg_sign();
 
-        let skip_ci_pattern = skip_ci.unwrap_or(SETTINGS.skip_ci.clone().unwrap_or_default());
+        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());
+        }
 
         self.repository.commit(
             &format!(
@@ -317,7 +332,8 @@ impl CocoGitto {
         hooks_config: Option<&str>,
         annotated: Option<String>,
         dry_run: bool,
-        skip_ci: Option<String>,
+        skip_ci: bool,
+        skip_ci_override: Option<String>,
         skip_untracked: bool,
     ) -> Result<()> {
         self.pre_bump_checks(skip_untracked)?;
@@ -385,7 +401,12 @@ impl CocoGitto {
         self.unwrap_or_stash_and_exit(&tag, hook_result);
 
         let sign = self.repository.gpg_sign();
-        let skip_ci_pattern = skip_ci.unwrap_or(SETTINGS.skip_ci.clone().unwrap_or_default());
+
+        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());
+        }
 
         self.repository.commit(
             &format!(
diff --git a/src/command/bump/package.rs b/src/command/bump/package.rs
index 0024e05..37af85b 100644
--- a/src/command/bump/package.rs
+++ b/src/command/bump/package.rs
@@ -24,7 +24,8 @@ impl CocoGitto {
         hooks_config: Option<&str>,
         annotated: Option<String>,
         dry_run: bool,
-        skip_ci: Option<String>,
+        skip_ci: bool,
+        skip_ci_override: Option<String>,
         skip_untracked: bool,
     ) -> Result<()> {
         self.pre_bump_checks(skip_untracked)?;
@@ -87,7 +88,11 @@ impl CocoGitto {
 
         let sign = self.repository.gpg_sign();
 
-        let skip_ci_pattern = skip_ci.unwrap_or(SETTINGS.skip_ci.clone().unwrap_or_default());
+        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());
+        }
 
         self.repository.commit(
             &format!("chore(version): {tag} {}", skip_ci_pattern),
diff --git a/src/command/bump/standard.rs b/src/command/bump/standard.rs
index 7a0ffe7..a37202b 100644
--- a/src/command/bump/standard.rs
+++ b/src/command/bump/standard.rs
@@ -22,7 +22,8 @@ impl CocoGitto {
         hooks_config: Option<&str>,
         annotated: Option<String>,
         dry_run: bool,
-        skip_ci: Option<String>,
+        skip_ci: bool,
+        skip_ci_override: Option<String>,
         skip_untracked: bool,
     ) -> Result<()> {
         self.pre_bump_checks(skip_untracked)?;
@@ -76,7 +77,11 @@ impl CocoGitto {
 
         let sign = self.repository.gpg_sign();
 
-        let skip_ci_pattern = skip_ci.unwrap_or(SETTINGS.skip_ci.clone().unwrap_or_default());
+        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());
+        }
 
         self.repository.commit(
             &format!(
diff --git a/src/settings/mod.rs b/src/settings/mod.rs
index 354751e..86772c8 100644
--- a/src/settings/mod.rs
+++ b/src/settings/mod.rs
@@ -37,7 +37,7 @@ pub struct Settings {
     pub monorepo_version_separator: Option<String>,
     pub branch_whitelist: Vec<String>,
     pub tag_prefix: Option<String>,
-    pub skip_ci: Option<String>,
+    pub skip_ci: String,
     pub skip_untracked: bool,
     pub pre_bump_hooks: Vec<String>,
     pub post_bump_hooks: Vec<String>,
@@ -60,7 +60,7 @@ impl Default for Settings {
             monorepo_version_separator: None,
             branch_whitelist: vec![],
             tag_prefix: None,
-            skip_ci: None,
+            skip_ci: "[skip ci]".to_string(),
             skip_untracked: false,
             pre_bump_hooks: vec![],
             post_bump_hooks: vec![],


Test patch:
diff --git a/tests/cog_tests/bump.rs b/tests/cog_tests/bump.rs
index 62ef35e..1dcb8a1 100644
--- a/tests/cog_tests/bump.rs
+++ b/tests/cog_tests/bump.rs
@@ -440,3 +440,210 @@ fn uncommited_changes_should_not_throw_error_with_option() -> Result<()> {
     assert_tag_does_not_exist("1.1.0")?;
     Ok(())
 }
+
+#[sealed_test]
+fn bump_package_with_default_skip_ci_ok() -> Result<()> {
+    let mut settings = Settings {
+        ..Default::default()
+    };
+    init_monorepo(&mut settings)?;
+
+    Command::cargo_bin("cog")?
+        .arg("bump")
+        .arg("--auto")
+        .arg("--skip-ci")
+        .arg("--package")
+        .arg("one")
+        .assert()
+        .success();
+
+    let commit_message = git_log_head()?;
+
+    assert_tag_exists("one-0.1.0")?;
+    assert!(commit_message.contains("[skip ci]"));
+
+    Ok(())
+}
+
+#[sealed_test]
+fn bump_package_with_cog_toml_defined_skip_ci_ok() -> Result<()> {
+    let mut settings = Settings {
+        skip_ci: String::from("[ci-skip]"),
+        ..Default::default()
+    };
+    init_monorepo(&mut settings)?;
+
+    Command::cargo_bin("cog")?
+        .arg("bump")
+        .arg("--auto")
+        .arg("--skip-ci")
+        .arg("--package")
+        .arg("one")
+        .assert()
+        .success();
+
+    let commit_message = git_log_head()?;
+
+    assert_tag_exists("one-0.1.0")?;
+    assert!(commit_message.contains("[ci-skip]"));
+
+    Ok(())
+}
+
+#[sealed_test]
+fn bump_package_with_skip_ci_override_option_takes_predecence() -> Result<()> {
+    let mut settings = Settings {
+        skip_ci: String::from("[ci-skip]"),
+        ..Default::default()
+    };
+    init_monorepo(&mut settings)?;
+
+    Command::cargo_bin("cog")?
+        .arg("bump")
+        .arg("--auto")
+        .arg("--skip-ci-override")
+        .arg("[ci-skip-override]")
+        .arg("--package")
+        .arg("one")
+        .assert()
+        .success();
+
+    let commit_message = git_log_head()?;
+
+    assert_tag_exists("one-0.1.0")?;
+    assert!(commit_message.contains("[ci-skip-override]"));
+
+    Ok(())
+}
+
+#[sealed_test]
+fn bump_standard_repository_with_default_skip_ci_ok() -> Result<()> {
+    git_init()?;
+    git_commit("chore: init")?;
+    git_commit("feat: feature")?;
+
+    Command::cargo_bin("cog")?
+        .arg("bump")
+        .arg("--skip-ci")
+        .arg("--auto")
+        .assert()
+        .success();
+
+    let commit_message = git_log_head()?;
+    assert_tag_exists("0.1.0")?;
+    assert!(commit_message.contains("[skip ci]"));
+
+    Ok(())
+}
+
+#[sealed_test]
+fn bump_standard_repository_with_cog_toml_defined_skip_ci_ok() -> Result<()> {
+    git_init()?;
+    git_commit("chore: init")?;
+    git_add("skip_ci = \"[ci-skip]\"", "cog.toml")?;
+    git_commit("feat: feature")?;
+
+    Command::cargo_bin("cog")?
+        .arg("bump")
+        .arg("--skip-ci")
+        .arg("--auto")
+        .assert()
+        .success();
+
+    let commit_message = git_log_head()?;
+    assert_tag_exists("0.1.0")?;
+    assert!(commit_message.contains("[ci-skip]"));
+
+    Ok(())
+}
+
+#[sealed_test]
+fn bump_standard_repository_skip_ci_override_option_takes_precedence() -> Result<()> {
+    git_init()?;
+    git_commit("chore: init")?;
+    git_add("skip_ci = \"[ci-skip]\"", "cog.toml")?;
+    git_commit("feat: feature")?;
+
+    Command::cargo_bin("cog")?
+        .arg("bump")
+        .arg("--skip-ci-override")
+        .arg("[ci-skip-override]")
+        .arg("--auto")
+        .assert()
+        .success();
+
+    let commit_message = git_log_head()?;
+    assert_tag_exists("0.1.0")?;
+    assert!(commit_message.contains("[ci-skip-override]"));
+
+    Ok(())
+}
+
+#[sealed_test]
+fn bump_monorepo_with_default_skip_ci_ok() -> Result<()> {
+    let mut settings = Settings {
+        ..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()?;
+
+    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 {
+        skip_ci: String::from("[ci-skip]"),
+        ..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()?;
+
+    assert_tag_exists("0.1.0")?;
+    assert!(commit_message.contains("[ci-skip]"));
+
+    Ok(())
+}
+
+#[sealed_test]
+fn bump_monorepo_skip_ci_override_option_takes_precedence() -> Result<()> {
+    let mut settings = Settings {
+        skip_ci: String::from("[ci-skip]"),
+        ..Default::default()
+    };
+    init_monorepo(&mut settings)?;
+
+    Command::cargo_bin("cog")?
+        .arg("bump")
+        .arg("--auto")
+        .arg("--skip-ci-override")
+        .arg("[skip-ci-override]")
+        .assert()
+        .success();
+
+    let commit_message = git_log_head()?;
+
+    assert_tag_exists("0.1.0")?;
+    assert!(commit_message.contains("[skip-ci-override]"));
+
+    Ok(())
+}
diff --git a/tests/cog_tests/commit.rs b/tests/cog_tests/commit.rs
index 1c8b8cc..dde9bd5 100644
--- a/tests/cog_tests/commit.rs
+++ b/tests/cog_tests/commit.rs
@@ -130,3 +130,78 @@ fn empty_commit_err() -> Result<()> {
 
     Ok(())
 }
+
+#[sealed_test]
+fn commit_with_default_skip_ci_ok() -> Result<()> {
+    // Arrange
+    git_init()?;
+    git_add("content", "test_file")?;
+
+    // Act
+    Command::cargo_bin("cog")?
+        .arg("commit")
+        .arg("--skip-ci")
+        .arg("feat")
+        .arg("this is a commit message")
+        .arg("scope")
+        // Assert
+        .assert()
+        .success();
+
+    let commit_message = git_log_head()?;
+
+    assert!(commit_message.contains("[skip ci]"));
+
+    Ok(())
+}
+
+#[sealed_test]
+fn commit_with_cog_toml_defined_skip_ci_ok() -> Result<()> {
+    // Arrange
+    git_init()?;
+    git_add("content", "test_file")?;
+    git_add("skip_ci = \"[ci-skip]\" ", "cog.toml")?;
+
+    // Act
+    Command::cargo_bin("cog")?
+        .arg("commit")
+        .arg("--skip-ci")
+        .arg("feat")
+        .arg("this is a commit message")
+        .arg("scope")
+        // Assert
+        .assert()
+        .success();
+
+    let commit_message = git_log_head()?;
+
+    assert!(commit_message.contains("[ci-skip]"));
+
+    Ok(())
+}
+
+#[sealed_test]
+fn commit_with_skip_ci_override_option_takes_precedence() -> Result<()> {
+    // Arrange
+    git_init()?;
+    git_add("content", "test_file")?;
+    git_add("skip_ci = \"[ci-skip]\" ", "cog.toml")?;
+
+    // Act
+    Command::cargo_bin("cog")?
+        .arg("commit")
+        .arg("--skip-ci-override")
+        .arg("[skip-ci-override]")
+        .arg("feat")
+        .arg("this is a commit message")
+        .arg("scope")
+        // Assert
+        .assert()
+        .success();
+
+    let commit_message = git_log_head()?;
+
+    assert!(commit_message.contains("[skip-ci-override]"));
+
+    Ok(())
+}
diff --git a/tests/lib_tests/bump.rs b/tests/lib_tests/bump.rs
index 9c06609..9061879 100644
--- a/tests/lib_tests/bump.rs
+++ b/tests/lib_tests/bump.rs
@@ -24,8 +24,16 @@ fn bump_ok() -> Result<()> {
     let mut cocogitto = CocoGitto::get()?;
 
     // Act
-    let result =
-        cocogitto.create_version(IncrementCommand::Auto, None, None, None, false, None, false);
+    let result = cocogitto.create_version(
+        IncrementCommand::Auto,
+        None,
+        None,
+        None,
+        false,
+        false,
+        None,
+        false,
+    );
 
     // Assert
     assert_that!(result).is_ok();
@@ -51,6 +59,7 @@ fn annotated_bump_ok() -> Result<()> {
         None,
         Some(String::from("Release version {{version}}")),
         false,
+        false,
         None,
         false,
     );
@@ -80,6 +89,7 @@ fn monorepo_bump_ok() -> Result<()> {
         None,
         None,
         false,
+        false,
         None,
         false,
     );
@@ -112,6 +122,7 @@ fn monorepo_bump_manual_ok() -> Result<()> {
         None,
         None,
         false,
+        false,
         None,
         false,
     );
@@ -143,6 +154,7 @@ fn monorepo_bump_manual_disable_changelog_ok() -> Result<()> {
         None,
         None,
         false,
+        false,
         None,
         false,
     );
@@ -173,6 +185,7 @@ fn monorepo_with_tag_prefix_bump_ok() -> Result<()> {
         None,
         None,
         false,
+        false,
         None,
         false,
     );
@@ -203,6 +216,7 @@ fn package_bump_ok() -> Result<()> {
         None,
         None,
         false,
+        false,
         None,
         false,
     );
@@ -272,6 +286,7 @@ fn consecutive_package_bump_ok() -> Result<()> {
         None,
         None,
         false,
+        false,
         None,
         false,
     )?;
@@ -283,6 +298,7 @@ fn consecutive_package_bump_ok() -> Result<()> {
         None,
         None,
         false,
+        false,
         None,
         false,
     )?;
@@ -300,6 +316,7 @@ fn consecutive_package_bump_ok() -> Result<()> {
         None,
         None,
         false,
+        false,
         None,
         false,
     )?;
@@ -323,8 +340,16 @@ fn should_fallback_to_0_0_0_when_there_is_no_tag() -> Result<()> {
     let mut cocogitto = CocoGitto::get()?;
 
     // Act
-    let result =
-        cocogitto.create_version(IncrementCommand::Auto, None, None, None, false, None, false);
+    let result = cocogitto.create_version(
+        IncrementCommand::Auto,
+        None,
+        None,
+        None,
+        false,
+        false,
+        None,
+        false,
+    );
 
     // Assert
     assert_that!(result).is_ok();
@@ -383,7 +408,7 @@ fn auto_bump_package_only_ok() -> Result<()> {
     let mut cocogitto = CocoGitto::get()?;
 
     // Act
-    cocogitto.create_all_package_version_auto(None, None, false, None, false)?;
+    cocogitto.create_all_package_version_auto(None, None, false, false, None, false)?;
 
     assert_tag_exists("jenkins-0.1.0")?;
     assert_tag_exists("thumbor-0.1.0")?;
@@ -395,7 +420,7 @@ fn auto_bump_package_only_ok() -> Result<()> {
         git commit -m "fix(jenkins): bug fix on jenkins package";
     )?;
 
-    cocogitto.create_all_package_version_auto(None, None, false, None, false)?;
+    cocogitto.create_all_package_version_auto(None, None, false, false, None, false)?;
 
     // Assert
     assert_tag_exists("jenkins-0.1.1")?;
@@ -447,8 +472,16 @@ fn bump_with_whitelisted_branch_ok() -> Result<()> {
     let mut cocogitto = CocoGitto::get()?;
 
     // Act
-    let result =
-        cocogitto.create_version(IncrementCommand::Auto, None, None, None, false, None, false);
+    let result = cocogitto.create_version(
+        IncrementCommand::Auto,
+        None,
+        None,
+        None,
+        false,
+        false,
+        None,
+        false,
+    );
 
     // Assert
     assert_that!(result).is_ok();
@@ -473,8 +506,16 @@ fn bump_with_whitelisted_branch_fails() -> Result<()> {
     let mut cocogitto = CocoGitto::get()?;
 
     // Act
-    let result =
-        cocogitto.create_version(IncrementCommand::Auto, None, None, None, false, None, false);
+    let result = cocogitto.create_version(
+        IncrementCommand::Auto,
+        None,
+        None,
+        None,
+        false,
+        false,
+        None,
+        false,
+    );
 
     // Assert
     assert_that!(result.unwrap_err().to_string()).is_equal_to(
@@ -503,8 +544,16 @@ fn bump_with_whitelisted_branch_pattern_ok() -> Result<()> {
     let mut cocogitto = CocoGitto::get()?;
 
     // Act
-    let result =
-        cocogitto.create_version(IncrementCommand::Auto, None, None, None, false, None, false);
+    let result = cocogitto.create_version(
+        IncrementCommand::Auto,
+        None,
+        None,
+        None,
+        false,
+        false,
+        None,
+        false,
+    );
 
     // Assert
     assert_that!(result).is_ok();
@@ -529,8 +578,16 @@ fn bump_with_whitelisted_branch_pattern_err() -> Result<()> {
     let mut cocogitto = CocoGitto::get()?;
 
     // Act
-    let result =
-        cocogitto.create_version(IncrementCommand::Auto, None, None, None, false, None, false);
+    let result = cocogitto.create_version(
+        IncrementCommand::Auto,
+        None,
+        None,
+        None,
+        false,
+        false,
+        None,
+        false,
+    );
 
     // Assert
     assert_that!(result).is_err();
@@ -593,6 +650,7 @@ fn bump_no_error_should_be_thrown_on_only_chore_docs_commit() -> Result<()> {
         None,
         None,
         false,
+        false,
         None,
         false,
     )?;
@@ -612,6 +670,7 @@ fn bump_no_error_should_be_thrown_on_only_chore_docs_commit() -> Result<()> {
         None,
         None,
         false,
+        false,
         None,
         false,
     )?;
@@ -623,6 +682,7 @@ fn bump_no_error_should_be_thrown_on_only_chore_docs_commit() -> Result<()> {
         None,
         None,
         false,
+        false,
         None,
         false,
     )?;
@@ -639,6 +699,7 @@ fn bump_no_error_should_be_thrown_on_only_chore_docs_commit() -> Result<()> {
         None,
         None,
         false,
+        false,
         None,
         false,
     )?;
@@ -682,8 +743,16 @@ fn error_on_no_conventionnal_commits_found_for_monorepo() -> Result<()> {
     let mut cocogitto = CocoGitto::get()?;
 
     // Act
-    let first_result =
-        cocogitto.create_version(IncrementCommand::Auto, None, None, None, false, None, false);
+    let first_result = cocogitto.create_version(
+        IncrementCommand::Auto,
+        None,
+        None,
+        None,
+        false,
+        false,
+        None,
+        false,
+    );
 
     // Assert
     assert_that!(first_result).is_ok();
@@ -696,8 +765,16 @@ fn error_on_no_conventionnal_commits_found_for_monorepo() -> Result<()> {
     git_commit("second unconventional feature commit")?;
 
     // Act
-    let second_result =
-        cocogitto.create_version(IncrementCommand::Auto, None, None, None, false, None, false);
+    let second_result = cocogitto.create_version(
+        IncrementCommand::Auto,
+        None,
+        None,
+        None,
+        false,
+        false,
+        None,
+        false,
+    );
 
     // Assert
     assert_that!(second_result).is_err();
@@ -750,6 +827,7 @@ fn error_on_no_conventionnal_commits_found_for_package() -> Result<()> {
         None,
         None,
         false,
+        false,
         None,
         false,
     );
@@ -769,6 +847,7 @@ fn error_on_no_conventionnal_commits_found_for_package() -> Result<()> {
         None,
         None,
         false,
+        false,
         None,
         false,
     );
@@ -833,6 +912,7 @@ fn bump_with_unconventionnal_and_conventional_commits_found_for_packages() -> Re
         None,
         None,
         false,
+        false,
         None,
         false,
     );