Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit fb06636

Browse files
committed
Skip abandoned repos
1 parent f5a5a09 commit fb06636

File tree

13 files changed

+119
-12
lines changed

13 files changed

+119
-12
lines changed

‎modules/core/src/main/resources/default.scala-steward.conf‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
// Changes to this file are therefore immediately visible to all
55
// Scala Steward instances.
66

7+
lastCommitMaxAge = "540 days"
8+
79
postUpdateHooks = [
810
{
911
groupId = "com.github.liancheng",

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ import org.scalasteward.core.forge.ForgeType.*
2525
import org.scalasteward.core.git.FileGitAlg.{dotdot, gitCmd}
2626
import org.scalasteward.core.io.process.{ProcessFailedException, SlurpOptions}
2727
import org.scalasteward.core.io.{FileAlg, ProcessAlg, WorkspaceAlg}
28-
import org.scalasteward.core.util.Nel
28+
import org.scalasteward.core.util.{Nel, Timestamp}
29+
import scala.util.Try
2930

3031
final class FileGitAlg[F[_]](config: Config)(implicit
3132
fileAlg: FileAlg[F],
@@ -102,6 +103,11 @@ final class FileGitAlg[F[_]](config: Config)(implicit
102103
.handleError(_ => List.empty[String])
103104
.map(_.filter(_.nonEmpty))
104105

106+
override def getCommitDate(repo: File, sha1: Sha1): F[Timestamp] =
107+
git("show", "--no-patch", "--format=%ct", sha1.value.value)(repo)
108+
.flatMap(out => F.fromTry(Try(out.mkString.trim.toLong)))
109+
.map(Timestamp.fromEpochSecond)
110+
105111
override def hasConflicts(repo: File, branch: Branch, base: Branch): F[Boolean] = {
106112
val tryMerge = git_("merge", "--no-commit", "--no-ff", branch.name)(repo)
107113
val abortMerge = git_("merge", "--abort")(repo).attempt.void

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import cats.{FlatMap, Monad}
2222
import org.http4s.Uri
2323
import org.scalasteward.core.application.Config
2424
import org.scalasteward.core.io.{FileAlg, ProcessAlg, WorkspaceAlg}
25+
import org.scalasteward.core.util.Timestamp
2526

2627
trait GenGitAlg[F[_], Repo] {
2728
def add(repo: Repo, file: String): F[Unit]
@@ -57,6 +58,8 @@ trait GenGitAlg[F[_], Repo] {
5758

5859
def findFilesContaining(repo: Repo, string: String): F[List[String]]
5960

61+
def getCommitDate(repo: Repo, sha1: Sha1): F[Timestamp]
62+
6063
/** Returns `true` if merging `branch` into `base` results in merge conflicts. */
6164
def hasConflicts(repo: Repo, branch: Branch, base: Branch): F[Boolean]
6265

@@ -144,6 +147,9 @@ trait GenGitAlg[F[_], Repo] {
144147
override def findFilesContaining(repo: A, string: String): F[List[String]] =
145148
f(repo).flatMap(self.findFilesContaining(_, string))
146149

150+
override def getCommitDate(repo: A, sha1: Sha1): F[Timestamp] =
151+
f(repo).flatMap(self.getCommitDate(_, sha1))
152+
147153
override def hasConflicts(repo: A, branch: Branch, base: Branch): F[Boolean] =
148154
f(repo).flatMap(self.hasConflicts(_, branch, base))
149155

‎modules/core/src/main/scala/org/scalasteward/core/repocache/RepoCache.scala‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ import io.circe.generic.semiauto.*
2222
import org.scalasteward.core.data.{ArtifactId, DependencyInfo, GroupId, Scope}
2323
import org.scalasteward.core.git.Sha1
2424
import org.scalasteward.core.repoconfig.RepoConfig
25+
import org.scalasteward.core.util.Timestamp
2526

2627
final case class RepoCache(
2728
sha1: Sha1,
29+
commitDate: Timestamp,
2830
dependencyInfos: List[Scope[List[DependencyInfo]]],
2931
maybeRepoConfig: Option[RepoConfig],
3032
maybeRepoConfigParsingError: Option[String]

‎modules/core/src/main/scala/org/scalasteward/core/repocache/RepoCacheAlg.scala‎

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,13 @@ import org.scalasteward.core.forge.data.RepoOut
2525
import org.scalasteward.core.forge.{ForgeApiAlg, ForgeRepoAlg}
2626
import org.scalasteward.core.git.GitAlg
2727
import org.scalasteward.core.repoconfig.RepoConfigAlg
28+
import org.scalasteward.core.util.{dateTime, DateTimeAlg}
2829
import org.typelevel.log4cats.Logger
30+
import scala.util.control.NoStackTrace
2931

3032
final class RepoCacheAlg[F[_]](config: Config)(implicit
3133
buildToolDispatcher: BuildToolDispatcher[F],
34+
dateTimeAlg: DateTimeAlg[F],
3235
forgeApiAlg: ForgeApiAlg[F],
3336
forgeRepoAlg: ForgeRepoAlg[F],
3437
gitAlg: GitAlg[F],
@@ -50,6 +53,7 @@ final class RepoCacheAlg[F[_]](config: Config)(implicit
5053
data <- maybeCache
5154
.filter(_.sha1 === latestSha1)
5255
.fold(cloneAndRefreshCache(repo, repoOut))(supplementCache(repo, _).pure[F])
56+
_ <- throwIfAbandoned(data)
5357
} yield (data, repoOut)
5458

5559
private def supplementCache(repo: Repo, cache: RepoCache): RepoData =
@@ -68,7 +72,8 @@ final class RepoCacheAlg[F[_]](config: Config)(implicit
6872
private def computeCache(repo: Repo): F[RepoData] =
6973
for {
7074
branch <- gitAlg.currentBranch(repo)
71-
latestSha1 <- gitAlg.latestSha1(repo, branch)
75+
sha1 <- gitAlg.latestSha1(repo, branch)
76+
commitDate <- gitAlg.getCommitDate(repo, sha1)
7277
configParsingResult <- repoConfigAlg.readRepoConfig(repo)
7378
maybeConfig = configParsingResult.maybeRepoConfig
7479
maybeConfigParsingError = configParsingResult.maybeParsingError.map(_.getMessage)
@@ -77,9 +82,21 @@ final class RepoCacheAlg[F[_]](config: Config)(implicit
7782
dependencyInfos <-
7883
dependencies.traverse(_.traverse(_.traverse(gatherDependencyInfo(repo, _))))
7984
_ <- gitAlg.discardChanges(repo)
80-
cache = RepoCache(latestSha1, dependencyInfos, maybeConfig, maybeConfigParsingError)
85+
cache = RepoCache(sha1, commitDate, dependencyInfos, maybeConfig, maybeConfigParsingError)
8186
} yield RepoData(repo, cache, config)
8287

8388
private def gatherDependencyInfo(repo: Repo, dependency: Dependency): F[DependencyInfo] =
8489
gitAlg.findFilesContaining(repo, dependency.version.value).map(DependencyInfo(dependency, _))
90+
91+
private[repocache] def throwIfAbandoned(data: RepoData): F[Unit] =
92+
data.config.lastCommitMaxAge.traverse_ { maxAge =>
93+
dateTimeAlg.currentTimestamp.flatMap { now =>
94+
val sinceLastCommit = data.cache.commitDate.until(now)
95+
val isAbandoned = sinceLastCommit > maxAge
96+
F.raiseWhen(isAbandoned) {
97+
val msg = s"Skipping because last commit is older than ${dateTime.showDuration(maxAge)}"
98+
new Throwable(msg) with NoStackTrace
99+
}
100+
}
101+
}
85102
}

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ import org.scalasteward.core.buildtool.BuildRoot
2525
import org.scalasteward.core.data.Repo
2626
import org.scalasteward.core.edit.hooks.PostUpdateHook
2727
import org.scalasteward.core.repoconfig.RepoConfig.defaultBuildRoots
28+
import org.scalasteward.core.util.dateTime.*
29+
import org.scalasteward.core.util.{combineOptions, intellijThisImportIsUsed}
30+
import scala.concurrent.duration.FiniteDuration
2831

2932
final case class RepoConfig(
3033
private val commits: Option[CommitsConfig] = None,
@@ -37,7 +40,8 @@ final case class RepoConfig(
3740
private val assignees: Option[List[String]] = None,
3841
private val reviewers: Option[List[String]] = None,
3942
private val dependencyOverrides: Option[List[GroupRepoConfig]] = None,
40-
signoffCommits: Option[Boolean] = None
43+
signoffCommits: Option[Boolean] = None,
44+
lastCommitMaxAge: Option[FiniteDuration] = None
4145
) {
4246
def commitsOrDefault: CommitsConfig =
4347
commits.getOrElse(CommitsConfig())
@@ -107,8 +111,11 @@ object RepoConfig {
107111
assignees = x.assignees |+| y.assignees,
108112
reviewers = x.reviewers |+| y.reviewers,
109113
dependencyOverrides = x.dependencyOverrides |+| y.dependencyOverrides,
110-
signoffCommits = x.signoffCommits.orElse(y.signoffCommits)
114+
signoffCommits = x.signoffCommits.orElse(y.signoffCommits),
115+
lastCommitMaxAge = combineOptions(x.lastCommitMaxAge, y.lastCommitMaxAge)(_ max _)
111116
)
112117
}
113118
)
119+
120+
intellijThisImportIsUsed(finiteDurationEncoder)
114121
}

‎modules/core/src/main/scala/org/scalasteward/core/util/Timestamp.scala‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ final case class Timestamp(millis: Long) {
3434
}
3535

3636
object Timestamp {
37+
def fromEpochSecond(seconds: Long): Timestamp =
38+
Timestamp(seconds * 1000L)
39+
3740
def fromLocalDateTime(ldt: LocalDateTime): Timestamp =
3841
Timestamp(ldt.toInstant(ZoneOffset.UTC).toEpochMilli)
3942

‎modules/core/src/main/scala/org/scalasteward/core/util/dateTime.scala‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.scalasteward.core.util
1818

1919
import cats.syntax.all.*
20+
import io.circe.{Decoder, Encoder}
2021
import java.util.concurrent.TimeUnit
2122
import scala.annotation.tailrec
2223
import scala.concurrent.duration.*
@@ -31,6 +32,12 @@ object dateTime {
3132
def renderFiniteDuration(fd: FiniteDuration): String =
3233
fd.toString.filterNot(_.isSpaceChar)
3334

35+
implicit val finiteDurationDecoder: Decoder[FiniteDuration] =
36+
Decoder[String].emap(parseFiniteDuration(_).leftMap(_.getMessage))
37+
38+
implicit val finiteDurationEncoder: Encoder[FiniteDuration] =
39+
Encoder[String].contramap(renderFiniteDuration)
40+
3441
def showDuration(d: FiniteDuration): String = {
3542
def symbol(unit: TimeUnit): String =
3643
unit match {

‎modules/core/src/test/scala/org/scalasteward/core/TestInstances.scala‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import org.scalasteward.core.git.Sha1
1010
import org.scalasteward.core.repocache.RepoCache
1111
import org.scalasteward.core.repoconfig.*
1212
import org.scalasteward.core.repoconfig.PullRequestFrequency.{Asap, Timespan}
13+
import org.scalasteward.core.util.{DateTimeAlg, Timestamp}
1314
import org.typelevel.log4cats.Logger
1415
import org.typelevel.log4cats.slf4j.Slf4jLogger
1516
import scala.concurrent.duration.FiniteDuration
@@ -19,11 +20,14 @@ object TestInstances {
1920
Sha1.unsafeFrom("da39a3ee5e6b4b0d3255bfef95601890afd80709")
2021

2122
val dummyRepoCache: RepoCache =
22-
RepoCache(dummySha1, List.empty, Option.empty, Option.empty)
23+
RepoCache(dummySha1, Timestamp(0L), List.empty, Option.empty, Option.empty)
2324

2425
val dummyRepoCacheWithParsingError: RepoCache =
2526
dummyRepoCache.copy(maybeRepoConfigParsingError = Some("Failed to parse .scala-steward.conf"))
2627

28+
val ioDateTimeAlg: DateTimeAlg[IO] =
29+
DateTimeAlg.create[IO]
30+
2731
implicit val ioLogger: Logger[IO] =
2832
Slf4jLogger.getLogger[IO]
2933

‎modules/core/src/test/scala/org/scalasteward/core/git/FileGitAlgTest.scala‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import cats.Monad
55
import cats.effect.IO
66
import cats.syntax.all.*
77
import munit.CatsEffectSuite
8-
import org.scalasteward.core.TestInstances.ioLogger
8+
import org.scalasteward.core.TestInstances.{ioDateTimeAlg, ioLogger}
99
import org.scalasteward.core.git.FileGitAlgTest.{
1010
conflictsNo,
1111
conflictsYes,
@@ -18,6 +18,7 @@ import org.scalasteward.core.io.ProcessAlgTest.ioProcessAlg
1818
import org.scalasteward.core.io.{FileAlg, ProcessAlg, WorkspaceAlg}
1919
import org.scalasteward.core.mock.MockConfig.{config, mockRoot}
2020
import org.scalasteward.core.util.Nel
21+
import scala.concurrent.duration.DurationInt
2122

2223
class FileGitAlgTest extends CatsEffectSuite {
2324
private val rootDir = mockRoot / "git-tests"
@@ -158,6 +159,19 @@ class FileGitAlgTest extends CatsEffectSuite {
158159
} yield ()
159160
}
160161

162+
test("getCommitDate") {
163+
val repo = rootDir / "getCommitDate"
164+
for {
165+
_ <- ioAuxGitAlg.createRepo(repo)
166+
sha1 <- ioGitAlg.latestSha1(repo, master)
167+
commitDate <- ioGitAlg.getCommitDate(repo, sha1)
168+
now <- ioDateTimeAlg.currentTimestamp
169+
diff = commitDate.until(now)
170+
maxDrift = 2.hours
171+
_ = assert(diff > -maxDrift && diff < maxDrift, clue((commitDate, now)))
172+
} yield ()
173+
}
174+
161175
test("hasConflicts") {
162176
val repo = rootDir / "hasConflicts"
163177
for {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /