Skip to content

Instantly share code, notes, and snippets.

@dacr
Last active April 2, 2023 10:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dacr/bf8e037e1fda8dad0c08bf4428c777fd to your computer and use it in GitHub Desktop.
Save dacr/bf8e037e1fda8dad0c08bf4428c777fd to your computer and use it in GitHub Desktop.
JGIT operations - get number of changes for a given file / published by https://github.com/dacr/code-examples-manager #7046d4fd-21ea-49d5-83b3-16220e5ce666/6e641e15988ad2d306310dc3c6a8a9355c3ee394
// summary : JGIT operations - get number of changes for a given file
// keywords : scala, git, @testable
// publish : gist
// authors : David Crosson
// license : Apache NON-AI License Version 2.0 (https://raw.githubusercontent.com/non-ai-licenses/non-ai-licenses/main/NON-AI-APACHE2)
// id : 7046d4fd-21ea-49d5-83b3-16220e5ce666
// created-on : 2021-12-29T09:25:28.859219997Z
// managed-by : https://github.com/dacr/code-examples-manager
// run-with : scala-cli $file
// ---------------------
//> using scala "3.1.1"
//> using dep "org.eclipse.jgit:org.eclipse.jgit:6.0.0.202111291000-r"
//> using dep "commons-io:commons-io:2.11.0"
//> using dep "org.slf4j:slf4j-nop:1.7.32"
// ---------------------
import java.io.File
import java.nio.file.{Files, Path}
import java.time.{Duration, Instant}
import scala.jdk.CollectionConverters.*
import scala.util.Properties
import org.eclipse.jgit.storage.file.FileRepositoryBuilder
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.lib.Repository
import org.eclipse.jgit.lib.Constants
import org.eclipse.jgit.revwalk.RevCommit
val targetFilePath = Path.of("git-api-dealing-with-local-repo.sc").toAbsolutePath
def getLocalRepositoryFromFile(fromFile: File, ceilingDirectoryOption: Option[File] = None): Option[Repository] =
val builder = new FileRepositoryBuilder()
builder.setMustExist(true)
ceilingDirectoryOption.foreach(ceilingDirectory => builder.addCeilingDirectory(ceilingDirectory))
builder.findGitDir(fromFile)
Option(builder.getGitDir()).map(_ => builder.build())
def getFileLog(git: Git, file: File, revision: String = Constants.HEAD): List[RevCommit] =
val repository = git.getRepository
val repoHomeDir = repository.getDirectory.toPath.getParent
val revisionId = repository.resolve(Constants.HEAD)
val targetFile = repoHomeDir.relativize(file.toPath)
val targetFileLogs = git.log().add(revisionId).addPath(targetFile.toString).call()
targetFileLogs.asScala.toList
def commitTimeInstant(revCommit: RevCommit): Instant =
Instant.ofEpochSecond(revCommit.getCommitTime)
case class GitMetaData(changesCount: Int, createdOn: Instant, lastUpdated: Instant)
def getGitFileMetaData(git: Git, filePath: Path): Option[GitMetaData] =
val targetFileLogs = getFileLog(git, filePath.toFile)
val changesCount = targetFileLogs.size
for {
createdOn <- targetFileLogs.lastOption.map(commitTimeInstant)
lastUpdated <- targetFileLogs.headOption.map(commitTimeInstant)
} yield {
GitMetaData(changesCount = changesCount, createdOn = createdOn, lastUpdated = lastUpdated)
}
def getGitFileMetaData(filePath: Path): Option[GitMetaData] =
for {
homeFile <- Properties.envOrNone("HOME").map(new File(_)).filter(_.exists())
fromFile <- Option(filePath).map(_.toFile).filter(_.exists())
repo <- getLocalRepositoryFromFile(fromFile, Some(homeFile))
git = Git(repo) // TODO add close() call
metadata <- getGitFileMetaData(git, filePath)
} yield metadata
for {
gitMetaData <- getGitFileMetaData(targetFilePath)
} {
import gitMetaData.*
println(
s"""$targetFilePath
| $changesCount changes
| added on $createdOn
| last updated on $lastUpdated
| """.stripMargin
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment