Skip to content

Commit

Permalink
Skip abandoned repos
Browse files Browse the repository at this point in the history
  • Loading branch information
fthomas committed Jan 21, 2025
1 parent 30e1311 commit 62be14c
Show file tree
Hide file tree
Showing 10 changed files with 62 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ import org.scalasteward.core.forge.ForgeType.*
import org.scalasteward.core.git.FileGitAlg.{dotdot, gitCmd}
import org.scalasteward.core.io.process.{ProcessFailedException, SlurpOptions}
import org.scalasteward.core.io.{FileAlg, ProcessAlg, WorkspaceAlg}
import org.scalasteward.core.util.Nel
import org.scalasteward.core.util.{Nel, Timestamp}
import scala.util.Try

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

override def getCommitDate(repo: File, sha1: Sha1): F[Timestamp] =
git("show", "--no-patch", "--format=%ct", sha1.value.value)(repo)
.flatMap(out => F.fromTry(Try(out.mkString.trim.toLong)))
.map(Timestamp.fromEpochSecond)

Check warning on line 109 in modules/core/src/main/scala/org/scalasteward/core/git/FileGitAlg.scala

View check run for this annotation

Codecov / codecov/patch

modules/core/src/main/scala/org/scalasteward/core/git/FileGitAlg.scala#L106-L109

Added lines #L106 - L109 were not covered by tests

override def hasConflicts(repo: File, branch: Branch, base: Branch): F[Boolean] = {
val tryMerge = git_("merge", "--no-commit", "--no-ff", branch.name)(repo)
val abortMerge = git_("merge", "--abort")(repo).attempt.void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import cats.{FlatMap, Monad}
import org.http4s.Uri
import org.scalasteward.core.application.Config
import org.scalasteward.core.io.{FileAlg, ProcessAlg, WorkspaceAlg}
import org.scalasteward.core.util.Timestamp

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

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

def getCommitDate(repo: Repo, sha1: Sha1): F[Timestamp]

/** Returns `true` if merging `branch` into `base` results in merge conflicts. */
def hasConflicts(repo: Repo, branch: Branch, base: Branch): F[Boolean]

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

override def getCommitDate(repo: A, sha1: Sha1): F[Timestamp] =
f(repo).flatMap(self.getCommitDate(_, sha1))

Check warning on line 151 in modules/core/src/main/scala/org/scalasteward/core/git/GenGitAlg.scala

View check run for this annotation

Codecov / codecov/patch

modules/core/src/main/scala/org/scalasteward/core/git/GenGitAlg.scala#L150-L151

Added lines #L150 - L151 were not covered by tests

override def hasConflicts(repo: A, branch: Branch, base: Branch): F[Boolean] =
f(repo).flatMap(self.hasConflicts(_, branch, base))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ import io.circe.generic.semiauto.*
import org.scalasteward.core.data.{ArtifactId, DependencyInfo, GroupId, Scope}
import org.scalasteward.core.git.Sha1
import org.scalasteward.core.repoconfig.RepoConfig
import org.scalasteward.core.util.Timestamp

final case class RepoCache(
sha1: Sha1,
commitDate: Timestamp,
dependencyInfos: List[Scope[List[DependencyInfo]]],
maybeRepoConfig: Option[RepoConfig],
maybeRepoConfigParsingError: Option[String]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,13 @@ import org.scalasteward.core.forge.data.RepoOut
import org.scalasteward.core.forge.{ForgeApiAlg, ForgeRepoAlg}
import org.scalasteward.core.git.GitAlg
import org.scalasteward.core.repoconfig.RepoConfigAlg
import org.scalasteward.core.util.{dateTime, DateTimeAlg}
import org.typelevel.log4cats.Logger
import scala.util.control.NoStackTrace

final class RepoCacheAlg[F[_]](config: Config)(implicit
buildToolDispatcher: BuildToolDispatcher[F],
dateTimeAlg: DateTimeAlg[F],
forgeApiAlg: ForgeApiAlg[F],
forgeRepoAlg: ForgeRepoAlg[F],
gitAlg: GitAlg[F],
Expand All @@ -50,6 +53,7 @@ final class RepoCacheAlg[F[_]](config: Config)(implicit
maybeCache
.filter(_.sha1 === latestSha1)
.fold(cloneAndRefreshCache(repo, repoOut))(supplementCache(repo, _).pure[F])
.flatTap(skipIfAbandoned)
.map(data => (data, repoOut))
}
}
Expand All @@ -70,7 +74,8 @@ final class RepoCacheAlg[F[_]](config: Config)(implicit
private def computeCache(repo: Repo): F[RepoData] =
for {
branch <- gitAlg.currentBranch(repo)
latestSha1 <- gitAlg.latestSha1(repo, branch)
sha1 <- gitAlg.latestSha1(repo, branch)
commitDate <- gitAlg.getCommitDate(repo, sha1)

Check warning on line 78 in modules/core/src/main/scala/org/scalasteward/core/repocache/RepoCacheAlg.scala

View check run for this annotation

Codecov / codecov/patch

modules/core/src/main/scala/org/scalasteward/core/repocache/RepoCacheAlg.scala#L77-L78

Added lines #L77 - L78 were not covered by tests
configParsingResult <- repoConfigAlg.readRepoConfig(repo)
maybeConfig = configParsingResult.maybeRepoConfig
maybeConfigParsingError = configParsingResult.maybeParsingError.map(_.getMessage)
Expand All @@ -79,9 +84,21 @@ final class RepoCacheAlg[F[_]](config: Config)(implicit
dependencyInfos <-
dependencies.traverse(_.traverse(_.traverse(gatherDependencyInfo(repo, _))))
_ <- gitAlg.discardChanges(repo)
cache = RepoCache(latestSha1, dependencyInfos, maybeConfig, maybeConfigParsingError)
cache = RepoCache(sha1, commitDate, dependencyInfos, maybeConfig, maybeConfigParsingError)

Check warning on line 87 in modules/core/src/main/scala/org/scalasteward/core/repocache/RepoCacheAlg.scala

View check run for this annotation

Codecov / codecov/patch

modules/core/src/main/scala/org/scalasteward/core/repocache/RepoCacheAlg.scala#L87

Added line #L87 was not covered by tests
} yield RepoData(repo, cache, config)

private def gatherDependencyInfo(repo: Repo, dependency: Dependency): F[DependencyInfo] =
gitAlg.findFilesContaining(repo, dependency.version.value).map(DependencyInfo(dependency, _))

private def skipIfAbandoned(data: RepoData): F[Unit] =
data.config.lastCommitMaxAge.traverse_ { maxAge =>
dateTimeAlg.currentTimestamp.flatMap { now =>
val sinceLastCommit = data.cache.commitDate.until(now)
val isAbandoned = sinceLastCommit > maxAge
F.raiseWhen(isAbandoned) {
val msg = s"Skipping because last commit is older than ${dateTime.showDuration(maxAge)}"
new Throwable(msg) with NoStackTrace

Check warning on line 100 in modules/core/src/main/scala/org/scalasteward/core/repocache/RepoCacheAlg.scala

View check run for this annotation

Codecov / codecov/patch

modules/core/src/main/scala/org/scalasteward/core/repocache/RepoCacheAlg.scala#L95-L100

Added lines #L95 - L100 were not covered by tests
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ import org.scalasteward.core.buildtool.BuildRoot
import org.scalasteward.core.data.Repo
import org.scalasteward.core.edit.hooks.PostUpdateHook
import org.scalasteward.core.repoconfig.RepoConfig.defaultBuildRoots
import org.scalasteward.core.util.dateTime.*
import org.scalasteward.core.util.{combineOptions, intellijThisImportIsUsed}
import scala.concurrent.duration.FiniteDuration

final case class RepoConfig(
private val commits: Option[CommitsConfig] = None,
Expand All @@ -37,7 +40,8 @@ final case class RepoConfig(
private val assignees: Option[List[String]] = None,
private val reviewers: Option[List[String]] = None,
private val dependencyOverrides: Option[List[GroupRepoConfig]] = None,
signoffCommits: Option[Boolean] = None
signoffCommits: Option[Boolean] = None,
lastCommitMaxAge: Option[FiniteDuration] = None
) {
def commitsOrDefault: CommitsConfig =
commits.getOrElse(CommitsConfig())
Expand Down Expand Up @@ -107,8 +111,11 @@ object RepoConfig {
assignees = x.assignees |+| y.assignees,
reviewers = x.reviewers |+| y.reviewers,
dependencyOverrides = x.dependencyOverrides |+| y.dependencyOverrides,
signoffCommits = x.signoffCommits.orElse(y.signoffCommits)
signoffCommits = x.signoffCommits.orElse(y.signoffCommits),
lastCommitMaxAge = combineOptions(x.lastCommitMaxAge, y.lastCommitMaxAge)(_ max _)
)
}
)

intellijThisImportIsUsed(finiteDurationEncoder)
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ final case class Timestamp(millis: Long) {
}

object Timestamp {
def fromEpochSecond(seconds: Long): Timestamp =
Timestamp(seconds * 1000L)

Check warning on line 38 in modules/core/src/main/scala/org/scalasteward/core/util/Timestamp.scala

View check run for this annotation

Codecov / codecov/patch

modules/core/src/main/scala/org/scalasteward/core/util/Timestamp.scala#L37-L38

Added lines #L37 - L38 were not covered by tests

def fromLocalDateTime(ldt: LocalDateTime): Timestamp =
Timestamp(ldt.toInstant(ZoneOffset.UTC).toEpochMilli)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.scalasteward.core.util

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

implicit val finiteDurationDecoder: Decoder[FiniteDuration] =
Decoder[String].emap(parseFiniteDuration(_).leftMap(_.getMessage))

implicit val finiteDurationEncoder: Encoder[FiniteDuration] =
Encoder[String].contramap(renderFiniteDuration)

def showDuration(d: FiniteDuration): String = {
def symbol(unit: TimeUnit): String =
unit match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import org.scalasteward.core.git.Sha1
import org.scalasteward.core.repocache.RepoCache
import org.scalasteward.core.repoconfig.*
import org.scalasteward.core.repoconfig.PullRequestFrequency.{Asap, Timespan}
import org.scalasteward.core.util.Timestamp
import org.typelevel.log4cats.Logger
import org.typelevel.log4cats.slf4j.Slf4jLogger
import scala.concurrent.duration.FiniteDuration
Expand All @@ -19,7 +20,7 @@ object TestInstances {
Sha1.unsafeFrom("da39a3ee5e6b4b0d3255bfef95601890afd80709")

val dummyRepoCache: RepoCache =
RepoCache(dummySha1, List.empty, Option.empty, Option.empty)
RepoCache(dummySha1, Timestamp(0L), List.empty, Option.empty, Option.empty)

val dummyRepoCacheWithParsingError: RepoCache =
dummyRepoCache.copy(maybeRepoConfigParsingError = Some("Failed to parse .scala-steward.conf"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import org.scalasteward.core.forge.github.Repository
import org.scalasteward.core.git.Branch
import org.scalasteward.core.mock.MockContext.context.{repoCacheAlg, repoConfigAlg, workspaceAlg}
import org.scalasteward.core.mock.{GitHubAuth, MockEff, MockEffOps, MockState}
import org.scalasteward.core.util.intellijThisImportIsUsed
import org.scalasteward.core.util.{intellijThisImportIsUsed, Timestamp}

class RepoCacheAlgTest extends CatsEffectSuite with Http4sDsl[MockEff] {
intellijThisImportIsUsed(encodeUri)
Expand All @@ -36,7 +36,7 @@ class RepoCacheAlgTest extends CatsEffectSuite with Http4sDsl[MockEff] {
uri"https://github.com/scala-steward/cats-effect.git",
Branch("main")
)
val repoCache = RepoCache(dummySha1, Nil, None, None)
val repoCache = RepoCache(dummySha1, Timestamp(0L), Nil, None, None)
val workspace = workspaceAlg.rootDir.unsafeRunSync()
val httpApp = HttpApp[MockEff] {
case POST -> Root / "repos" / "typelevel" / "cats-effect" / "forks" =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class PruningAlgTest extends FunSuite {
val Right(repoCache) = decode[RepoCache](
s"""|{
| "sha1": "12def27a837ba6dc9e17406cbbe342fba3527c14",
| "commitDate": 0,
| "dependencyInfos": [],
| "maybeRepoConfig": {
| "pullRequests": {
Expand Down Expand Up @@ -79,6 +80,7 @@ class PruningAlgTest extends FunSuite {
val Right(repoCache) = decode[RepoCache](
s"""|{
| "sha1": "12def27a837ba6dc9e17406cbbe342fba3527c14",
| "commitDate": 0,
| "dependencyInfos" : [
| {
| "value" : [
Expand Down Expand Up @@ -218,6 +220,7 @@ class PruningAlgTest extends FunSuite {
val Right(repoCache) = decode[RepoCache](
s"""|{
| "sha1": "12def27a837ba6dc9e17406cbbe342fba3527c14",
| "commitDate": 0,
| "dependencyInfos" : [
| {
| "value" : [
Expand Down Expand Up @@ -330,6 +333,7 @@ class PruningAlgTest extends FunSuite {
val Right(repoCache) = decode[RepoCache](
s"""|{
| "sha1": "12def27a837ba6dc9e17406cbbe342fba3527c14",
| "commitDate": 0,
| "dependencyInfos" : [
| {
| "value" : [
Expand Down Expand Up @@ -441,6 +445,7 @@ class PruningAlgTest extends FunSuite {
val Right(repoCache) = decode[RepoCache](
s"""|{
| "sha1": "12def27a837ba6dc9e17406cbbe342fba3527c14",
| "commitDate": 0,
| "dependencyInfos" : [
| {
| "value" : [
Expand Down

0 comments on commit 62be14c

Please sign in to comment.