diff --git a/src/main/scala/com/github/sbt/git/ConsoleGitReadableOnly.scala b/src/main/scala/com/github/sbt/git/ConsoleGitReadableOnly.scala index 0ff326f..43d3791 100644 --- a/src/main/scala/com/github/sbt/git/ConsoleGitReadableOnly.scala +++ b/src/main/scala/com/github/sbt/git/ConsoleGitReadableOnly.scala @@ -24,4 +24,10 @@ class ConsoleGitReadableOnly(git: GitRunner, cwd: File, log: Logger) extends Git def remoteOrigin: String = git("ls-remote", "--get-url", "origin")(cwd, log) def headCommitMessage: Option[String] = Try(git("log", "--pretty=%s\n\n%b", "-n", "1")(cwd, log)).toOption + + def changedFiles: Seq[String] = + headCommitSha + .flatMap(headCommit => Try(git("diff-tree", "--no-commit-id", "--name-only", "-r", headCommit)(cwd, log)).toOption) + .map(_.split('\n').map(_.trim).toSeq) + .getOrElse(Seq.empty) } diff --git a/src/main/scala/com/github/sbt/git/GitPlugin.scala b/src/main/scala/com/github/sbt/git/GitPlugin.scala index f5131b4..0962a30 100644 --- a/src/main/scala/com/github/sbt/git/GitPlugin.scala +++ b/src/main/scala/com/github/sbt/git/GitPlugin.scala @@ -19,6 +19,9 @@ object SbtGit { val gitHeadCommitDate = SettingKey[Option[String]]("git-head-commit-date", "The commit date for the top commit of this project in ISO-8601 format.") val gitDescribedVersion = SettingKey[Option[String]]("git-described-version", "Version as returned by `git describe --tags`.") val gitUncommittedChanges = SettingKey[Boolean]("git-uncommitted-changes", "Whether there are uncommitted changes.") + val gitMergeMessagePatterns = settingKey[Seq[String]]("Collection of regex patterns with one sub-group to parse commit messages of merge commits") + val gitMergeFrom = SettingKey[Option[String]]("git-merge-from", "Possible name of a branch HEAD is a merge from") + val gitFilesChangedLastCommit = SettingKey[Seq[String]]("git-last-changes", "List of files changed in the last commit") // A Mechanism to run Git directly. val gitRunner = TaskKey[GitRunner]("git-runner", "The mechanism used to run git in the current build.") @@ -124,6 +127,22 @@ object SbtGit { gitCurrentTags := gitReader.value.withGit(_.currentTags), gitCurrentBranch := Option(gitReader.value.withGit(_.branch)).getOrElse(""), ThisBuild / gitUncommittedChanges := gitReader.value.withGit(_.hasUncommittedChanges), + gitMergeMessagePatterns := Seq.empty[String], + gitFilesChangedLastCommit := gitReader.value.withGit(_.changedFiles), + gitMergeFrom := { + for { + headMessage <- gitHeadMessage.value.map(_.trim) + mergedFrom <- gitMergeMessagePatterns.value + .map(_.r.unanchored) + .flatMap { regex => + headMessage match { + case regex(branch) => Option(branch) + case _ => None + } + } + .headOption + } yield mergedFrom + }, scmInfo := parseScmInfo(gitReader.value.withGit(_.remoteOrigin)) ) private[sbt] def parseScmInfo(remoteOrigin: String): Option[ScmInfo] = { @@ -260,6 +279,9 @@ object SbtGit { val baseVersion = ThisBuild / GitKeys.baseVersion val versionProperty = ThisBuild / GitKeys.versionProperty val gitUncommittedChanges = ThisBuild / GitKeys.gitUncommittedChanges + val gitFilesChangedLastCommit = ThisBuild / GitKeys.gitFilesChangedLastCommit + val gitMergeFrom = ThisBuild / GitKeys.gitMergeFrom + val gitMergeMessagePatterns = ThisBuild / GitKeys.gitMergeMessagePatterns val uncommittedSignifier = ThisBuild / GitKeys.uncommittedSignifier val formattedShaVersion = ThisBuild / GitKeys.formattedShaVersion val formattedDateVersion = ThisBuild / GitKeys.formattedDateVersion diff --git a/src/main/scala/com/github/sbt/git/JGit.scala b/src/main/scala/com/github/sbt/git/JGit.scala index c580884..f291709 100644 --- a/src/main/scala/com/github/sbt/git/JGit.scala +++ b/src/main/scala/com/github/sbt/git/JGit.scala @@ -2,16 +2,18 @@ package com.github.sbt.git import org.eclipse.jgit.lib.Repository import org.eclipse.jgit.storage.file.FileRepositoryBuilder -import org.eclipse.jgit.api.{Git => PGit} -import java.io.File +import org.eclipse.jgit.api.Git as PGit +import org.eclipse.jgit.diff.DiffFormatter + +import java.io.{ByteArrayOutputStream, File} import java.text.SimpleDateFormat import java.util.Date - import org.eclipse.jgit.lib.ObjectId import org.eclipse.jgit.lib.Ref import org.eclipse.jgit.revwalk.{RevCommit, RevWalk} import scala.util.Try +import scala.collection.JavaConverters.* // TODO - This class needs a bit more work, but at least it lets us use porcelain and wrap some higher-level @@ -29,12 +31,10 @@ final class JGit(val repo: Repository) extends GitReadonlyInterface { def branch: String = repo.getBranch private def branchesRef: Seq[Ref] = { - import collection.JavaConverters._ porcelain.branchList.call.asScala } def tags: Seq[Ref] = { - import collection.JavaConverters._ porcelain.tagList.call().asScala } @@ -96,14 +96,12 @@ final class JGit(val repo: Repository) extends GitReadonlyInterface { override def branches: Seq[String] = branchesRef.filter(_.getName.startsWith("refs/heads")).map(_.getName.drop(11)) override def remoteBranches: Seq[String] = { - import collection.JavaConverters._ import org.eclipse.jgit.api.ListBranchCommand.ListMode porcelain.branchList.setListMode(ListMode.REMOTE).call.asScala.filter(_.getName.startsWith("refs/remotes")).map(_.getName.drop(13)) } override def remoteOrigin: String = { // same functionality as Process("git ls-remote --get-url origin").lines_!.head - import collection.JavaConverters._ porcelain.remoteList().call.asScala .filter(_.getName == "origin") .flatMap(_.getURIs.asScala) @@ -125,6 +123,24 @@ final class JGit(val repo: Repository) extends GitReadonlyInterface { format.format(new Date(millis)) } } + + /** Files changed in current commit * */ + override def changedFiles: Seq[String] = { + val walk = new RevWalk(repo) + val maybeChanges = for { + head <- headCommit.map(walk.parseCommit) + parent <- Try(head.getParent(0)).toOption + } yield { + val os = new ByteArrayOutputStream() + val diffFormatter = new DiffFormatter(os) + diffFormatter.setRepository(repo) + diffFormatter.scan(parent, head) + .asScala + .flatMap(entry => Set(entry.getOldPath, entry.getNewPath)) + .filterNot(_.startsWith("/")) + } + maybeChanges.getOrElse(Seq.empty) + } } object JGit { diff --git a/src/main/scala/com/github/sbt/git/ReadableGit.scala b/src/main/scala/com/github/sbt/git/ReadableGit.scala index 6add7c4..b7b9e84 100644 --- a/src/main/scala/com/github/sbt/git/ReadableGit.scala +++ b/src/main/scala/com/github/sbt/git/ReadableGit.scala @@ -28,6 +28,8 @@ trait GitReadonlyInterface { def remoteOrigin: String /** The message of current commit **/ def headCommitMessage: Option[String] + /** Files changed in current commit **/ + def changedFiles: Seq[String] } diff --git a/src/sbt-test/git-plugin/files-changed/README.md b/src/sbt-test/git-plugin/files-changed/README.md new file mode 100644 index 0000000..e69de29 diff --git a/src/sbt-test/git-plugin/files-changed/README2.md b/src/sbt-test/git-plugin/files-changed/README2.md new file mode 100644 index 0000000..e69de29 diff --git a/src/sbt-test/git-plugin/files-changed/README3.md b/src/sbt-test/git-plugin/files-changed/README3.md new file mode 100644 index 0000000..e69de29 diff --git a/src/sbt-test/git-plugin/files-changed/changes/build.sbt b/src/sbt-test/git-plugin/files-changed/changes/build.sbt new file mode 100644 index 0000000..0c28a65 --- /dev/null +++ b/src/sbt-test/git-plugin/files-changed/changes/build.sbt @@ -0,0 +1,16 @@ +def proj(name: String) = Project(name, file(name)).enablePlugins(GitVersioning) + + +lazy val a = proj("a") +lazy val b = proj("b") + +enablePlugins(GitVersioning) + +git.baseVersion := "1.0" +git.versionProperty := "DUMMY_BUILD_VERSION" + +val checkChangedFiles = taskKey[Unit]("checks the files changed in the last commit") +checkChangedFiles := { + val value = git.gitFilesChangedLastCommit.value + assert(value sameElements Seq("README2.md", "README3.md"), s"changed files should return 2 entries, got $value") +} \ No newline at end of file diff --git a/src/sbt-test/git-plugin/files-changed/project/plugins.sbt b/src/sbt-test/git-plugin/files-changed/project/plugins.sbt new file mode 100644 index 0000000..3417043 --- /dev/null +++ b/src/sbt-test/git-plugin/files-changed/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.github.sbt" % "sbt-git" % sys.props("project.version")) \ No newline at end of file diff --git a/src/sbt-test/git-plugin/files-changed/test b/src/sbt-test/git-plugin/files-changed/test new file mode 100644 index 0000000..73e69fa --- /dev/null +++ b/src/sbt-test/git-plugin/files-changed/test @@ -0,0 +1,11 @@ +> git init +> git config user.email "test@jsuereth.com" +> git config user.name "Tester" +> git add README.md +> git commit -m "test" +> git add README2.md +> git add README3.md +> git commit -m "test2" +$ copy-file changes/build.sbt build.sbt +> reload +> checkChangedFiles \ No newline at end of file diff --git a/src/sbt-test/git-plugin/merged-from/README.md b/src/sbt-test/git-plugin/merged-from/README.md new file mode 100644 index 0000000..e69de29 diff --git a/src/sbt-test/git-plugin/merged-from/README2.md b/src/sbt-test/git-plugin/merged-from/README2.md new file mode 100644 index 0000000..e69de29 diff --git a/src/sbt-test/git-plugin/merged-from/README3.md b/src/sbt-test/git-plugin/merged-from/README3.md new file mode 100644 index 0000000..e69de29 diff --git a/src/sbt-test/git-plugin/merged-from/changes/build.sbt b/src/sbt-test/git-plugin/merged-from/changes/build.sbt new file mode 100644 index 0000000..49fae44 --- /dev/null +++ b/src/sbt-test/git-plugin/merged-from/changes/build.sbt @@ -0,0 +1,19 @@ +def proj(name: String) = Project(name, file(name)).enablePlugins(GitVersioning) + + +lazy val a = proj("a") +lazy val b = proj("b") + +enablePlugins(GitVersioning) + +git.baseVersion := "1.0" +git.versionProperty := "DUMMY_BUILD_VERSION" +git.gitMergeMessagePatterns := Seq( + raw"Merge branch '(.*?)'" +) + +val checkMergedFrom = taskKey[Unit]("checks the merged from branch is correct") +checkMergedFrom := { + val value = git.gitMergeFrom.value + assert(value == Option("branch_2"), s"Merged from should return the correct branch, got $value") +} \ No newline at end of file diff --git a/src/sbt-test/git-plugin/merged-from/project/plugins.sbt b/src/sbt-test/git-plugin/merged-from/project/plugins.sbt new file mode 100644 index 0000000..3417043 --- /dev/null +++ b/src/sbt-test/git-plugin/merged-from/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.github.sbt" % "sbt-git" % sys.props("project.version")) \ No newline at end of file diff --git a/src/sbt-test/git-plugin/merged-from/test b/src/sbt-test/git-plugin/merged-from/test new file mode 100644 index 0000000..fd8aa2d --- /dev/null +++ b/src/sbt-test/git-plugin/merged-from/test @@ -0,0 +1,15 @@ +> git init +> git config user.email "test@jsuereth.com" +> git config user.name "Tester" +> git add README.md +> git commit -m "test" +> git checkout -b branch_2 +> git add README2.md +> git commit -m "test2" +> git checkout master +> git add README3.md +> git commit -m "test3" +> git merge --no-edit branch_2 +$ copy-file changes/build.sbt build.sbt +> reload +> checkMergedFrom \ No newline at end of file