From 6a15f5d14d97736505b2896cd8caf8dcd705a926 Mon Sep 17 00:00:00 2001 From: RoB Murdock Date: Mon, 12 Aug 2024 10:03:43 -0400 Subject: [PATCH] [patch] radically reducing the need for custom digger code by smarter use of git cli --- .../digger/core/AllContributionCommits.kt | 98 ++++--------------- .../digger/core/CurrentContributionCommits.kt | 2 +- .../tools/digger/core/DiggerGitWrapper.kt | 6 +- .../tools/digger/core/FindTrunkPath.kt | 27 +++++ .../tools/digger/AllContributionTestSpec.kt | 8 ++ 5 files changed, 60 insertions(+), 81 deletions(-) create mode 100644 tools/digger-core/src/commonMain/kotlin/com/zegreatrob/tools/digger/core/FindTrunkPath.kt diff --git a/tools/digger-core/src/commonMain/kotlin/com/zegreatrob/tools/digger/core/AllContributionCommits.kt b/tools/digger-core/src/commonMain/kotlin/com/zegreatrob/tools/digger/core/AllContributionCommits.kt index fffd6ba..74c5b49 100644 --- a/tools/digger-core/src/commonMain/kotlin/com/zegreatrob/tools/digger/core/AllContributionCommits.kt +++ b/tools/digger-core/src/commonMain/kotlin/com/zegreatrob/tools/digger/core/AllContributionCommits.kt @@ -2,86 +2,30 @@ package com.zegreatrob.tools.digger.core fun DiggerGitWrapper.allContributionCommits(): List>> { val log = log() - val tags = listTags().filter { log.map(CommitRef::id).contains(it.commitId) } - val trunkPath = tags.findTrunkPath(log) - return tags - .relateToCommits(trunkPath) - .foldInBranches(log - trunkPath.toSet()) - .map { (tag, commitSet) -> tag to commitSet.map { it.id }.toSet() } - .withCommitsInOriginalOrder(log) -} - -private fun List.findTrunkPath(log: List) = allPaths(log, log.first(), map { it.commitId }.toSet()) - .shortestPathWithMostTags(taggedCommitIds = map { it.commitId }.toSet()) - ?: log.alwaysLeftParent() + val tags = listTags() + .distinctBy { it.commitId } + .filter { log.map(CommitRef::id).contains(it.commitId) } -private fun MutableList>.shortestPathWithMostTags(taggedCommitIds: Set): List? { - val pathTagCountGroups = groupBy { path -> - path.count { taggedCommitIds.contains(it.id) } - } - return pathTagCountGroups[pathTagCountGroups.keys.max()] - ?.minBy { it.size } -} - -private fun List>>.foldInBranches(offMainCommits: List) = reversed() - .fold(emptyList>>()) { acc, (tag, commitSet) -> - acc + (tag to foldInBranches(commitSet, offMainCommits - acc.flatMap { it.second }.toSet())) - }.reversed() - -private fun foldInBranches( - commitSet: Set, - remainingOffMainCommits: List, -): Set = commitSet.fold(emptySet()) { acc, commit -> - acc + commit + if (commit.parents.size <= 1) { - emptyList() - } else { - branchCommits( - commit.parents[0], - remainingOffMainCommits - acc, - ) + branchCommits( - commit.parents[1], - remainingOffMainCommits - acc, - ) - } + return sortIntoTagSets(tags, log) } -private fun List.relateToCommits(trunkPath: List): List>> { - val tagSets: List>> = - trunkPath.fold(emptyList()) { acc, commit -> - val tag = find { it.commitId == commit.id } - if (tag != null) { - acc.plus(element = tag to setOf(commit)) - } else { - val lastPair = acc.lastOrNull() - val lastList = lastPair?.second - if (lastList != null) { - acc.slice(0..acc.size - 2).plus(element = lastPair.copy(second = lastList.plusElement(commit))) - } else { - acc.plus(element = null to setOf(commit)) - } - } +fun DiggerGitWrapper.sortIntoTagSets( + tagRefs: List, + log: List, +): List>> = tagRefs.tagPairs() + .map { (earlierTag, nextTag) -> + earlierTag to if (earlierTag == null && nextTag != null) { + logWithRange("^${nextTag.commitId}", "HEAD") + } else if (earlierTag != null && nextTag != null) { + logWithRange("^${nextTag.commitId}", earlierTag.commitId) + } else if (earlierTag != null) { + logWithRange(earlierTag.commitId) + } else { + log.alwaysLeftParent() } - return tagSets -} + }.filter { it.second.isNotEmpty() } -private fun List.alwaysLeftParent() = fold(emptyList()) { acc, commit -> - if (acc.isEmpty()) { - acc + commit - } else if (commit.id == acc.last().parents.firstOrNull()) { - acc + commit - } else { - acc +private fun List.tagPairs(): List> = + listOf(Pair(null, firstOrNull())) + mapIndexed { index, commitRef -> + commitRef to getOrNull(index + 1) } -} - -private fun List>>.withCommitsInOriginalOrder( - log: List, -) = map { (tag, commitIds) -> - tag to log.filter { commit -> commitIds.contains(commit.id) } -} - -fun branchCommits(id: String, offMainCommits: List): List = (0..offMainCommits.size) - .fold(listOf(id) to emptyList()) { (ids, foundCommits), _ -> - val newCommits = offMainCommits.filter { ids.contains(it.id) } - newCommits.flatMap { it.parents } to (foundCommits + newCommits) - }.second diff --git a/tools/digger-core/src/commonMain/kotlin/com/zegreatrob/tools/digger/core/CurrentContributionCommits.kt b/tools/digger-core/src/commonMain/kotlin/com/zegreatrob/tools/digger/core/CurrentContributionCommits.kt index 0827d2a..04d3521 100644 --- a/tools/digger-core/src/commonMain/kotlin/com/zegreatrob/tools/digger/core/CurrentContributionCommits.kt +++ b/tools/digger-core/src/commonMain/kotlin/com/zegreatrob/tools/digger/core/CurrentContributionCommits.kt @@ -3,5 +3,5 @@ package com.zegreatrob.tools.digger.core fun DiggerGitWrapper.currentContributionCommits(previousTag: TagRef?): List = if (previousTag == null) { log() } else { - logWithRange(previousTag.name, "HEAD") + logWithRange("^${previousTag.name}", "HEAD") } diff --git a/tools/digger-core/src/commonMain/kotlin/com/zegreatrob/tools/digger/core/DiggerGitWrapper.kt b/tools/digger-core/src/commonMain/kotlin/com/zegreatrob/tools/digger/core/DiggerGitWrapper.kt index af9ad45..e994070 100644 --- a/tools/digger-core/src/commonMain/kotlin/com/zegreatrob/tools/digger/core/DiggerGitWrapper.kt +++ b/tools/digger-core/src/commonMain/kotlin/com/zegreatrob/tools/digger/core/DiggerGitWrapper.kt @@ -53,15 +53,15 @@ class DiggerGitWrapper(private val workingDirectory: String) { ), ) - fun logWithRange(begin: String, end: String): List = parseLog( + fun logWithRange(begin: String, end: String? = null): List = parseLog( runProcess( listOf( "git", "--no-pager", "log", "--format=$gitLogFormat", - "$begin..$end", - ), + begin, + ) + if (end != null) listOf(end) else emptyList(), workingDirectory, ), ) diff --git a/tools/digger-core/src/commonMain/kotlin/com/zegreatrob/tools/digger/core/FindTrunkPath.kt b/tools/digger-core/src/commonMain/kotlin/com/zegreatrob/tools/digger/core/FindTrunkPath.kt new file mode 100644 index 0000000..06077cf --- /dev/null +++ b/tools/digger-core/src/commonMain/kotlin/com/zegreatrob/tools/digger/core/FindTrunkPath.kt @@ -0,0 +1,27 @@ +package com.zegreatrob.tools.digger.core + +fun DiggerGitWrapper.findTrunkPath(tagRefs: List, log: List): List = allPaths( + log = log, + firstTagCommit = log.first(), + preferredCommitIds = tagRefs.map { it.commitId }.toSet(), +) + .shortestPathWithMostTags(taggedCommitIds = tagRefs.map { it.commitId }.toSet()) + ?: log.alwaysLeftParent() + +private fun MutableList>.shortestPathWithMostTags(taggedCommitIds: Set): List? { + val pathTagCountGroups = groupBy { path -> + path.count { taggedCommitIds.contains(it.id) } + } + return pathTagCountGroups[pathTagCountGroups.keys.max()] + ?.minBy { it.size } +} + +fun List.alwaysLeftParent() = fold(emptyList()) { acc, commit -> + if (acc.isEmpty()) { + acc + commit + } else if (commit.id == acc.last().parents.firstOrNull()) { + acc + commit + } else { + acc + } +} diff --git a/tools/digger-test/src/jvmMain/kotlin/com/zegreatrob/tools/digger/AllContributionTestSpec.kt b/tools/digger-test/src/jvmMain/kotlin/com/zegreatrob/tools/digger/AllContributionTestSpec.kt index b2b6323..cdfe011 100644 --- a/tools/digger-test/src/jvmMain/kotlin/com/zegreatrob/tools/digger/AllContributionTestSpec.kt +++ b/tools/digger-test/src/jvmMain/kotlin/com/zegreatrob/tools/digger/AllContributionTestSpec.kt @@ -138,6 +138,7 @@ interface AllContributionTestSpec : SetupWithOverrides { grgit.checkout { it.branch = "main" } val mergeToMainCommit = grgit.mergeInBranch("branch", "merge-to-main") + delayLongEnoughToAffectGitDate() val release2 = grgit.addTag("release-2") val allOutput = runAllContributionData() @@ -172,6 +173,7 @@ interface AllContributionTestSpec : SetupWithOverrides { grgit.checkout { it.branch = "main" } val thirdCommit = grgit.addCommitWithMessage("third") + delayLongEnoughToAffectGitDate() val secondRelease = grgit.addTag("release-2") grgit.checkout { it.branch = "branch" } @@ -181,6 +183,7 @@ interface AllContributionTestSpec : SetupWithOverrides { grgit.checkout { it.branch = "main" } grgit.ffOnlyInBranch("branch") + delayLongEnoughToAffectGitDate() val thirdRelease = grgit.addTag("release-3") val allOutput = runAllContributionData() @@ -223,11 +226,13 @@ interface AllContributionTestSpec : SetupWithOverrides { grgit.checkout { it.branch = "main" } val thirdCommit = grgit.addCommitWithMessage("third") + delayLongEnoughToAffectGitDate() val secondRelease = grgit.addTag("release2") grgit.checkout { it.branch = "branch1" } grgit.addCommitWithMessage("fourth") grgit.checkout { it.branch = "main" } val mergeCommit = grgit.mergeInBranch("branch1", "merge") + delayLongEnoughToAffectGitDate() val thirdRelease = grgit.addTag("release3") val allOutput = runAllContributionData() @@ -279,6 +284,7 @@ interface AllContributionTestSpec : SetupWithOverrides { grgit.addCommitWithMessage("sixth") val merge2Commit = grgit.mergeInBranch("branch1", "merge2") + delayLongEnoughToAffectGitDate() val thirdRelease = grgit.addTag("release3") val allOutput = runAllContributionData() @@ -314,12 +320,14 @@ interface AllContributionTestSpec : SetupWithOverrides { grgit.checkout { it.branch = "main" } grgit.addCommitWithMessage("third") val merge1Commit = grgit.mergeInBranch("branch1", "merge1") + delayLongEnoughToAffectGitDate() val secondRelease = grgit.addTag("release2") grgit.checkout { it.branch = "branch1" } val fourthCommit = grgit.addCommitWithMessage("fourth") grgit.checkout { it.branch = "main" } val merge2Commit = grgit.mergeInBranch("branch1", "merge2") + delayLongEnoughToAffectGitDate() val thirdRelease = grgit.addTag("release3") val allOutput = runAllContributionData()