Skip to content

Commit 432b78e

Browse files
michaelmiormzuehlke
authored andcommitted
Add repo-specific signoff option
1 parent 0a505fa commit 432b78e

File tree

18 files changed

+122
-59
lines changed

18 files changed

+122
-59
lines changed

docs/repo-specific-configuration.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ dependencyOverrides = [
184184
# to add assignees or request reviews. Consequently, it won't work for public @scala-steward instance on GitHub.
185185
assignees = [ "username1", "username2" ]
186186
reviewers = [ "username1", "username2" ]
187+
188+
# If true, Scala Steward will sign off all commits (e.g. `git --signoff`).
189+
# Default: false
190+
signoffCommits = true
187191
```
188192

189193
The version information given in the patterns above can be in two formats:

modules/core/src/main/scala/org/scalasteward/core/edit/EditAlg.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,11 @@ final class EditAlg[F[_]](implicit
9494
result <- logger.attemptWarn.log("Scalafix migration failed") {
9595
buildToolDispatcher.runMigration(repo, config, migration)
9696
}
97-
maybeCommit <- gitAlg.commitAllIfDirty(repo, migration.commitMessage(result))
97+
maybeCommit <- gitAlg.commitAllIfDirty(
98+
repo,
99+
migration.commitMessage(result),
100+
migration.signoffCommits
101+
)
98102
} yield ScalafixEdit(migration, result, maybeCommit)
99103

100104
private def applyUpdateReplacements(
@@ -111,7 +115,7 @@ final class EditAlg[F[_]](implicit
111115
_ <- reformatChangedFiles(data)
112116
msgTemplate = data.config.commits.messageOrDefault
113117
commitMsg = CommitMsg.replaceVariables(msgTemplate)(update, data.repo.branch)
114-
maybeCommit <- gitAlg.commitAllIfDirty(data.repo, commitMsg)
118+
maybeCommit <- gitAlg.commitAllIfDirty(data.repo, commitMsg, data.config.signoffCommits)
115119
} yield maybeCommit.map(UpdateEdit(update, _))
116120

117121
private def reformatChangedFiles(data: RepoData): F[Unit] = {

modules/core/src/main/scala/org/scalasteward/core/edit/hooks/HookExecutor.scala

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ final class HookExecutor[F[_]](implicit
4646
F: MonadThrow[F]
4747
) {
4848
def execPostUpdateHooks(data: RepoData, update: Update.Single): F[List[EditAttempt]] =
49-
(HookExecutor.postUpdateHooks ++ data.config.postUpdateHooksOrDefault)
49+
(HookExecutor.postUpdateHooks(
50+
data.config.signoffCommits
51+
) ++ data.config.postUpdateHooksOrDefault)
5052
.filter { hook =>
5153
hook.groupId.forall(update.groupId === _) &&
5254
hook.artifactId.forall(aid => update.artifactIds.exists(_.name === aid.name)) &&
@@ -75,17 +77,20 @@ final class HookExecutor[F[_]](implicit
7577
commitMessage = hook
7678
.commitMessage(update)
7779
.appendParagraph(s"Executed command: ${hook.command.mkString_(" ")}")
78-
maybeHookCommit <- gitAlg.commitAllIfDirty(repo, commitMessage)
80+
maybeHookCommit <- gitAlg.commitAllIfDirty(repo, commitMessage, hook.signoffCommits)
7981
maybeBlameIgnoreCommit <-
80-
maybeHookCommit.flatTraverse(addToGitBlameIgnoreRevs(repo, repoDir, hook, _, commitMessage))
82+
maybeHookCommit.flatTraverse(
83+
addToGitBlameIgnoreRevs(repo, repoDir, hook, _, commitMessage, hook.signoffCommits)
84+
)
8185
} yield HookEdit(hook, result, maybeHookCommit.toList ++ maybeBlameIgnoreCommit.toList)
8286

8387
private def addToGitBlameIgnoreRevs(
8488
repo: Repo,
8589
repoDir: File,
8690
hook: PostUpdateHook,
8791
commit: Commit,
88-
commitMsg: CommitMsg
92+
commitMsg: CommitMsg,
93+
signoffCommits: Option[Boolean]
8994
): F[Option[Commit]] =
9095
if (hook.addToGitBlameIgnoreRevs) {
9196
for {
@@ -100,7 +105,7 @@ final class HookExecutor[F[_]](implicit
100105
addAndCommit = gitAlg.add(repo, pathAsString).flatMap { _ =>
101106
val blameIgnoreCommitMsg =
102107
CommitMsg(s"Add '${commitMsg.title}' to $gitBlameIgnoreRevsName")
103-
gitAlg.commitAllIfDirty(repo, blameIgnoreCommitMsg)
108+
gitAlg.commitAllIfDirty(repo, blameIgnoreCommitMsg, signoffCommits)
104109
}
105110
maybeBlameIgnoreCommit <- gitAlg
106111
.checkIgnore(repo, pathAsString)
@@ -145,7 +150,8 @@ object HookExecutor {
145150
private def sbtGithubWorkflowGenerateHook(
146151
groupId: GroupId,
147152
artifactId: ArtifactId,
148-
enabledByCache: RepoCache => Boolean
153+
enabledByCache: RepoCache => Boolean,
154+
signoffCommits: Option[Boolean]
149155
): PostUpdateHook =
150156
PostUpdateHook(
151157
groupId = Some(groupId),
@@ -155,10 +161,11 @@ object HookExecutor {
155161
commitMessage = _ => CommitMsg("Regenerate GitHub Actions workflow"),
156162
enabledByCache = enabledByCache,
157163
enabledByConfig = _ => true,
158-
addToGitBlameIgnoreRevs = false
164+
addToGitBlameIgnoreRevs = false,
165+
signoffCommits = signoffCommits
159166
)
160167

161-
private val scalafmtHook =
168+
private def scalafmtHook(signoffCommits: Option[Boolean]) =
162169
PostUpdateHook(
163170
groupId = Some(scalafmtGroupId),
164171
artifactId = Some(scalafmtArtifactId),
@@ -167,12 +174,14 @@ object HookExecutor {
167174
commitMessage = update => CommitMsg(s"Reformat with scalafmt ${update.nextVersion}"),
168175
enabledByCache = _ => true,
169176
enabledByConfig = _.scalafmt.runAfterUpgradingOrDefault,
170-
addToGitBlameIgnoreRevs = true
177+
addToGitBlameIgnoreRevs = true,
178+
signoffCommits = signoffCommits
171179
)
172180

173181
private def sbtTypelevelHook(
174182
groupId: GroupId,
175-
artifactId: ArtifactId
183+
artifactId: ArtifactId,
184+
signoffCommits: Option[Boolean]
176185
): PostUpdateHook =
177186
PostUpdateHook(
178187
groupId = Some(groupId),
@@ -182,21 +191,22 @@ object HookExecutor {
182191
commitMessage = _ => CommitMsg("Run prePR with sbt-typelevel"),
183192
enabledByCache = _ => true,
184193
enabledByConfig = _ => true,
185-
addToGitBlameIgnoreRevs = false
194+
addToGitBlameIgnoreRevs = false,
195+
signoffCommits = signoffCommits
186196
)
187197

188198
private def githubWorkflowGenerateExists(cache: RepoCache): Boolean =
189199
cache.dependsOn(sbtGitHubWorkflowGenerateModules ++ sbtTypelevelModules)
190200

191-
private val postUpdateHooks: List[PostUpdateHook] =
192-
scalafmtHook ::
201+
private def postUpdateHooks(signoffCommits: Option[Boolean]): List[PostUpdateHook] =
202+
scalafmtHook(signoffCommits) ::
193203
sbtGitHubWorkflowGenerateModules.map { case (gid, aid) =>
194-
sbtGithubWorkflowGenerateHook(gid, aid, _ => true)
204+
sbtGithubWorkflowGenerateHook(gid, aid, _ => true, signoffCommits)
195205
} ++
196206
conditionalSbtGitHubWorkflowGenerateModules.map { case (gid, aid) =>
197-
sbtGithubWorkflowGenerateHook(gid, aid, githubWorkflowGenerateExists)
207+
sbtGithubWorkflowGenerateHook(gid, aid, githubWorkflowGenerateExists, signoffCommits)
198208
} ++
199209
sbtTypelevelModules.map { case (gid, aid) =>
200-
sbtTypelevelHook(gid, aid)
210+
sbtTypelevelHook(gid, aid, signoffCommits)
201211
}
202212
}

modules/core/src/main/scala/org/scalasteward/core/edit/hooks/PostUpdateHook.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ final case class PostUpdateHook(
3131
commitMessage: Update.Single => CommitMsg,
3232
enabledByCache: RepoCache => Boolean,
3333
enabledByConfig: RepoConfig => Boolean,
34-
addToGitBlameIgnoreRevs: Boolean
34+
addToGitBlameIgnoreRevs: Boolean,
35+
signoffCommits: Option[Boolean]
3536
) {
3637
def showCommand: String = command.mkString_("'", " ", "'")
3738
}

modules/core/src/main/scala/org/scalasteward/core/edit/scalafix/ScalafixMigration.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ final case class ScalafixMigration(
3434
scalacOptions: Option[Nel[String]] = None,
3535
authors: Option[Nel[Author]] = None,
3636
target: Option[Target] = None,
37-
executionOrder: Option[ExecutionOrder] = None
37+
executionOrder: Option[ExecutionOrder] = None,
38+
signoffCommits: Option[Boolean]
3839
) {
3940
def commitMessage(result: Either[Throwable, Unit]): CommitMsg = {
4041
val verb = if (result.isRight) "Applied" else "Failed"

modules/core/src/main/scala/org/scalasteward/core/git/FileGitAlg.scala

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,16 @@ final class FileGitAlg[F[_]](config: GitCfg)(implicit
6363
override def cloneExists(repo: File): F[Boolean] =
6464
fileAlg.isDirectory(repo / ".git")
6565

66-
override def commitAll(repo: File, message: CommitMsg): F[Commit] = {
66+
override def commitAll(
67+
repo: File,
68+
message: CommitMsg,
69+
signoffCommits: Option[Boolean]
70+
): F[Commit] = {
6771
val messages = message.paragraphs.foldMap(m => List("-m", m))
6872
val trailers = message.trailers.foldMap { case (k, v) => List("--trailer", s"$k=$v") }
69-
git_("commit" :: "--all" :: sign :: signoff :: messages ++ trailers: _*)(repo) >>
73+
git_("commit" :: "--all" :: sign :: signoff(signoffCommits) :: messages ++ trailers: _*)(
74+
repo
75+
) >>
7076
latestSha1(repo, Branch.head).map(Commit.apply)
7177
}
7278

@@ -171,8 +177,8 @@ final class FileGitAlg[F[_]](config: GitCfg)(implicit
171177
private val sign: String =
172178
if (config.signCommits) "--gpg-sign" else "--no-gpg-sign"
173179

174-
private val signoff: String =
175-
if (config.signoff) "--signoff" else "--no-signoff"
180+
private def signoff(signoffCommits: Option[Boolean]): String =
181+
if (signoffCommits.getOrElse(config.signoff)) "--signoff" else "--no-signoff"
176182
}
177183

178184
object FileGitAlg {

modules/core/src/main/scala/org/scalasteward/core/git/GenGitAlg.scala

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ trait GenGitAlg[F[_], Repo] {
4040

4141
def cloneExists(repo: Repo): F[Boolean]
4242

43-
def commitAll(repo: Repo, message: CommitMsg): F[Commit]
43+
def commitAll(repo: Repo, message: CommitMsg, signoffCommits: Option[Boolean]): F[Commit]
4444

4545
def containsChanges(repo: Repo): F[Boolean]
4646

@@ -78,10 +78,13 @@ trait GenGitAlg[F[_], Repo] {
7878

7979
def version: F[String]
8080

81-
final def commitAllIfDirty(repo: Repo, message: CommitMsg)(implicit
82-
F: Monad[F]
81+
final def commitAllIfDirty(repo: Repo, message: CommitMsg, signoffCommits: Option[Boolean])(
82+
implicit F: Monad[F]
8383
): F[Option[Commit]] =
84-
containsChanges(repo).ifM(commitAll(repo, message).map(Some.apply), F.pure(None))
84+
containsChanges(repo).ifM(
85+
commitAll(repo, message, signoffCommits).map(Some.apply),
86+
F.pure(None)
87+
)
8588

8689
final def returnToCurrentBranch[A, E](repo: Repo)(fa: F[A])(implicit F: MonadCancel[F, E]): F[A] =
8790
F.bracket(currentBranch(repo))(_ => fa)(checkoutBranch(repo, _))
@@ -113,8 +116,12 @@ trait GenGitAlg[F[_], Repo] {
113116
override def cloneExists(repo: A): F[Boolean] =
114117
f(repo).flatMap(self.cloneExists)
115118

116-
override def commitAll(repo: A, message: CommitMsg): F[Commit] =
117-
f(repo).flatMap(self.commitAll(_, message))
119+
override def commitAll(
120+
repo: A,
121+
message: CommitMsg,
122+
signoffCommits: Option[Boolean]
123+
): F[Commit] =
124+
f(repo).flatMap(self.commitAll(_, message, signoffCommits))
118125

119126
override def containsChanges(repo: A): F[Boolean] =
120127
f(repo).flatMap(self.containsChanges)

modules/core/src/main/scala/org/scalasteward/core/repoconfig/PostUpdateHookConfig.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ final case class PostUpdateHookConfig(
2929
artifactId: Option[String],
3030
command: Nel[String],
3131
commitMessage: String,
32-
addToGitBlameIgnoreRevs: Option[Boolean] = None
32+
addToGitBlameIgnoreRevs: Option[Boolean] = None,
33+
signoffCommits: Option[Boolean]
3334
) {
3435
def toHook: PostUpdateHook =
3536
PostUpdateHook(
@@ -40,7 +41,8 @@ final case class PostUpdateHookConfig(
4041
commitMessage = CommitMsg.replaceVariables(commitMessage)(_, None),
4142
enabledByCache = _ => true,
4243
enabledByConfig = _ => true,
43-
addToGitBlameIgnoreRevs = addToGitBlameIgnoreRevs.getOrElse(false)
44+
addToGitBlameIgnoreRevs = addToGitBlameIgnoreRevs.getOrElse(false),
45+
signoffCommits = signoffCommits
4446
)
4547
}
4648

modules/core/src/main/scala/org/scalasteward/core/repoconfig/RepoConfig.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ final case class RepoConfig(
3737
buildRoots: Option[List[BuildRootConfig]] = None,
3838
assignees: List[String] = List.empty,
3939
reviewers: List[String] = List.empty,
40-
dependencyOverrides: List[GroupRepoConfig] = List.empty
40+
dependencyOverrides: List[GroupRepoConfig] = List.empty,
41+
signoffCommits: Option[Boolean] = None
4142
) {
4243
def buildRootsOrDefault(repo: Repo): List[BuildRoot] =
4344
buildRoots
@@ -88,7 +89,8 @@ object RepoConfig {
8889
buildRoots = x.buildRoots |+| y.buildRoots,
8990
assignees = x.assignees |+| y.assignees,
9091
reviewers = x.reviewers |+| y.reviewers,
91-
dependencyOverrides = x.dependencyOverrides |+| y.dependencyOverrides
92+
dependencyOverrides = x.dependencyOverrides |+| y.dependencyOverrides,
93+
signoffCommits = x.signoffCommits.orElse(y.signoffCommits)
9294
)
9395
}
9496
)

modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/SbtAlgTest.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ class SbtAlgTest extends FunSuite {
5454
GroupId("co.fs2"),
5555
Nel.of("fs2-core"),
5656
Version("1.0.0"),
57-
Nel.of("github:functional-streams-for-scala/fs2/v1?sha=v1.0.5")
57+
Nel.of("github:functional-streams-for-scala/fs2/v1?sha=v1.0.5"),
58+
signoffCommits = None
5859
)
5960
val initialState = MockState.empty
6061
.addFiles(
@@ -93,7 +94,8 @@ class SbtAlgTest extends FunSuite {
9394
Nel.of("cats-core"),
9495
Version("2.2.0"),
9596
Nel.of("github:cb372/cats/Cats_v2_2_0?sha=235bd7c92e431ab1902db174cf4665b05e08f2f1"),
96-
scalacOptions = Some(Nel.of("-P:semanticdb:synthetics:on"))
97+
scalacOptions = Some(Nel.of("-P:semanticdb:synthetics:on")),
98+
signoffCommits = None
9799
)
98100
val initialState = MockState.empty
99101
.addFiles(

0 commit comments

Comments
 (0)