Repository: scala-steward-org/scala-steward (scala)

Issue:
Feature request: Sign-off the Git commit
[Background](https://stackoverflow.com/questions/1962094/what-is-the-sign-off-feature-in-git-for)

This will help repositories which have a DCO check, for example in [this repo](https://github.com/librecaptcha/lc-core/pull/106)

Of course, Scala Steward isn't a legal entity and the commits are very small anyway, so it doesn't really matter from a legal POV. The sign-off will only make the process of merging the PR smoother.

Pull request description:
This should fix #2408

Patch:
diff --git a/docs/help.md b/docs/help.md
index 4930fb2646..badf427302 100644
--- a/docs/help.md
+++ b/docs/help.md
@@ -4,7 +4,7 @@ All command line arguments for the `scala-steward` application.
 
 ```
 Usage:
-    scala-steward --workspace <file> --repos-file <uri> [--repos-file <uri>]... [--git-author-name <string>] --git-author-email <string> [--git-author-signing-key <string>] --git-ask-pass <file> [--sign-commits] [--forge-type <forge-type>] [--forge-api-host <uri>] --forge-login <string> [--do-not-fork] [--add-labels] [--ignore-opts-files] [--env-var <name=value>]... [--process-timeout <duration>] [--whitelist <string>]... [--read-only <string>]... [--enable-sandbox | --disable-sandbox] [--max-buffer-size <integer>] [--repo-config <uri>]... [--disable-default-repo-config] [--scalafix-migrations <uri>]... [--disable-default-scalafix-migrations] [--artifact-migrations <uri>]... [--disable-default-artifact-migrations] [--cache-ttl <duration>] [--bitbucket-use-default-reviewers] [--bitbucket-server-use-default-reviewers] [--gitlab-merge-when-pipeline-succeeds] [--gitlab-required-reviewers <integer>] [--gitlab-remove-source-branch] [--azure-repos-organization <string>] [--github-app-id <integer> --github-app-key-file <file>] [--url-checker-test-url <uri>]... [--default-maven-repo <string>] [--refresh-backoff-period <duration>] [--exit-code-success-if-any-repo-succeeds]
+    scala-steward --workspace <file> --repos-file <uri> [--repos-file <uri>]... [--git-author-name <string>] --git-author-email <string> [--git-author-signing-key <string>] --git-ask-pass <file> [--sign-commits] [--signoff] [--forge-type <forge-type>] [--forge-api-host <uri>] --forge-login <string> [--do-not-fork] [--add-labels] [--ignore-opts-files] [--env-var <name=value>]... [--process-timeout <duration>] [--whitelist <string>]... [--read-only <string>]... [--enable-sandbox | --disable-sandbox] [--max-buffer-size <integer>] [--repo-config <uri>]... [--disable-default-repo-config] [--scalafix-migrations <uri>]... [--disable-default-scalafix-migrations] [--artifact-migrations <uri>]... [--disable-default-artifact-migrations] [--cache-ttl <duration>] [--bitbucket-use-default-reviewers] [--bitbucket-server-use-default-reviewers] [--gitlab-merge-when-pipeline-succeeds] [--gitlab-required-reviewers <integer>] [--gitlab-remove-source-branch] [--azure-repos-organization <string>] [--github-app-id <integer> --github-app-key-file <file>] [--url-checker-test-url <uri>]... [--default-maven-repo <string>] [--refresh-backoff-period <duration>] [--exit-code-success-if-any-repo-succeeds]
     scala-steward validate-repo-config
 
 
@@ -26,6 +26,8 @@ Options and flags:
         An executable file that returns the git credentials
     --sign-commits
         Whether to sign commits; default: false
+    --signoff
+        Whether to signoff commits; default: false
     --forge-type <forge-type>
         One of azure-repos, bitbucket, bitbucket-server, github, gitlab, gitea; default: github
     --vcs-type <forge-type>
diff --git a/modules/core/src/main/scala/org/scalasteward/core/application/Cli.scala b/modules/core/src/main/scala/org/scalasteward/core/application/Cli.scala
index 87a9057534..4964ed831a 100644
--- a/modules/core/src/main/scala/org/scalasteward/core/application/Cli.scala
+++ b/modules/core/src/main/scala/org/scalasteward/core/application/Cli.scala
@@ -105,8 +105,11 @@ object Cli {
   private val signCommits: Opts[Boolean] =
     flag("sign-commits", "Whether to sign commits; default: false").orFalse
 
+  private val signoff: Opts[Boolean] =
+    flag("signoff", "Whether to signoff commits; default: false").orFalse
+
   private val gitCfg: Opts[GitCfg] =
-    (gitAuthor, gitAskPass, signCommits).mapN(GitCfg.apply)
+    (gitAuthor, gitAskPass, signCommits, signoff).mapN(GitCfg.apply)
 
   private val vcsType =
     option[ForgeType](
diff --git a/modules/core/src/main/scala/org/scalasteward/core/application/Config.scala b/modules/core/src/main/scala/org/scalasteward/core/application/Config.scala
index 11d666716f..4e836627af 100644
--- a/modules/core/src/main/scala/org/scalasteward/core/application/Config.scala
+++ b/modules/core/src/main/scala/org/scalasteward/core/application/Config.scala
@@ -81,7 +81,8 @@ object Config {
   final case class GitCfg(
       gitAuthor: Author,
       gitAskPass: File,
-      signCommits: Boolean
+      signCommits: Boolean,
+      signoff: Boolean
   )
 
   final case class ForgeCfg(
diff --git a/modules/core/src/main/scala/org/scalasteward/core/git/FileGitAlg.scala b/modules/core/src/main/scala/org/scalasteward/core/git/FileGitAlg.scala
index 27c5f04c7f..0a51ed11bb 100644
--- a/modules/core/src/main/scala/org/scalasteward/core/git/FileGitAlg.scala
+++ b/modules/core/src/main/scala/org/scalasteward/core/git/FileGitAlg.scala
@@ -66,7 +66,7 @@ final class FileGitAlg[F[_]](config: GitCfg)(implicit
   override def commitAll(repo: File, message: CommitMsg): F[Commit] = {
     val messages = message.paragraphs.foldMap(m => List("-m", m))
     val trailers = message.trailers.foldMap { case (k, v) => List("--trailer", s"$k=$v") }
-    git_("commit" :: "--all" :: sign :: messages ++ trailers: _*)(repo) >>
+    git_("commit" :: "--all" :: sign :: signoff :: messages ++ trailers: _*)(repo) >>
       latestSha1(repo, Branch.head).map(Commit.apply)
   }
 
@@ -170,6 +170,9 @@ final class FileGitAlg[F[_]](config: GitCfg)(implicit
 
   private val sign: String =
     if (config.signCommits) "--gpg-sign" else "--no-gpg-sign"
+
+  private val signoff: String =
+    if (config.signoff) "--signoff" else "--no-signoff"
 }
 
 object FileGitAlg {


Test patch:
diff --git a/modules/core/src/test/scala/org/scalasteward/core/mock/MockState.scala b/modules/core/src/test/scala/org/scalasteward/core/mock/MockState.scala
index d492dc120f..a3ad28f5ee 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/mock/MockState.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/mock/MockState.scala
@@ -91,7 +91,9 @@ object MockState {
 
       def gitCommit(repoDir: File, messages: String*): Cmd = {
         val args =
-          "commit" :: "--all" :: "--no-gpg-sign" :: messages.toList.flatMap(m => List("-m", m))
+          "commit" :: "--all" :: "--no-gpg-sign" :: "--no-signoff" :: messages.toList.flatMap(m =>
+            List("-m", m)
+          )
         git(repoDir, args: _*)
       }