Skip to content

Commit a3c0851

Browse files
Merge pull request #3102 from guardian/fix-issue-3096-dependency-frequency-was-ignored-for-grouped-prs
Fix #3096: Don't ignore dependency-frequency-limits for *grouped* PRs
2 parents b1de3ab + 743ae2b commit a3c0851

File tree

3 files changed

+91
-136
lines changed

3 files changed

+91
-136
lines changed

modules/core/src/main/scala/org/scalasteward/core/data/Update.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ sealed trait Update {
3535

3636
def show: String
3737

38+
val asSingleUpdates: List[Update.Single]
3839
}
3940

4041
object Update {
@@ -46,16 +47,18 @@ object Update {
4647
) extends Update {
4748

4849
override def show: String = name
49-
50+
override val asSingleUpdates: List[Update.Single] = updates
5051
}
5152

5253
sealed trait Single extends Product with Serializable with Update {
54+
override val asSingleUpdates: List[Update.Single] = List(this)
5355
def forArtifactIds: Nel[ForArtifactId]
5456
def crossDependencies: Nel[CrossDependency]
5557
def dependencies: Nel[Dependency]
5658
def groupId: GroupId
5759
def artifactIds: Nel[ArtifactId]
5860
def mainArtifactId: String
61+
def groupAndMainArtifactId: (GroupId, String) = (groupId, mainArtifactId)
5962
def currentVersion: Version
6063
def newerVersions: Nel[Version]
6164

modules/core/src/main/scala/org/scalasteward/core/nurture/PullRequestRepository.scala

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,10 @@ final class PullRequestRepository[F[_]](kvStore: KeyValueStore[F, Repo, Map[Uri,
112112
case None => Map.empty
113113
case Some(pullRequests) =>
114114
pullRequests.values
115-
.collect { case Entry(_, u: Update.Single, _, entryCreatedAt, _, _) =>
116-
(u.groupId, u.mainArtifactId, entryCreatedAt)
115+
.flatMap { entry =>
116+
entry.update.asSingleUpdates.map(_.groupAndMainArtifactId -> entry.entryCreatedAt)
117117
}
118-
.groupBy { case (groupId, mainArtifactId, _) => (groupId, mainArtifactId) }
119-
.view
120-
.mapValues(_.map { case (_, _, createdAt) => createdAt }.max)
121-
.toMap
118+
.groupMapReduce(_._1)(_._2)(_ max _)
122119
}
123120
}
124121

modules/core/src/test/scala/org/scalasteward/core/nurture/PullRequestRepositoryTest.scala

Lines changed: 84 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ import org.scalasteward.core.forge.data.{PullRequestNumber, PullRequestState}
1111
import org.scalasteward.core.git.{Branch, Sha1}
1212
import org.scalasteward.core.mock.MockConfig.config
1313
import org.scalasteward.core.mock.MockContext.context.pullRequestRepository
14-
import org.scalasteward.core.mock.MockState
1514
import org.scalasteward.core.mock.MockState.TraceEntry
1615
import org.scalasteward.core.mock.MockState.TraceEntry.Cmd
16+
import org.scalasteward.core.mock.{MockEff, MockState}
1717
import org.scalasteward.core.util.Nel
1818

19+
import java.util.concurrent.atomic.AtomicInteger
20+
1921
class PullRequestRepositoryTest extends FunSuite {
2022
private def checkTrace(state: MockState, trace: Vector[TraceEntry]): Unit =
2123
assertEquals(state.copy(files = Map.empty), MockState.empty.copy(trace = trace))
@@ -29,166 +31,119 @@ class PullRequestRepositoryTest extends FunSuite {
2931
private val url = uri"https://github.com/typelevel/cats/pull/3291"
3032
private val sha1 = Sha1.unsafeFrom("a2ced5793c2832ada8c14ba5c77e51c4bc9656a8")
3133
private val number = PullRequestNumber(3291)
32-
private val branch = Branch("update")
34+
private def groupedUpdate(updates: Update.ForArtifactId*) =
35+
Update.Grouped("group", None, updates.toList)
36+
private def openPRFor(update: Update): PullRequestData[Id] =
37+
PullRequestData[Id](url, sha1, update, Open, number, Branch("update"))
3338

34-
test("createOrUpdate >> findPullRequest >> lastPullRequestCreatedAt") {
35-
val repo = Repo("pr-repo-test", "repo1")
36-
val update = portableScala
37-
val data = PullRequestData[Id](url, sha1, update, Open, number, branch)
39+
private val repoCounter = new AtomicInteger()
3840

39-
val p = for {
40-
_ <- pullRequestRepository.createOrUpdate(repo, data)
41-
result <- pullRequestRepository.findLatestPullRequest(repo, update.crossDependency, "1.0.0".v)
42-
createdAt <- pullRequestRepository.lastPullRequestCreatedAt(repo)
43-
} yield (result, createdAt)
44-
val (state, (result, createdAt)) = p.runSA(MockState.empty).unsafeRunSync()
41+
private def executeOnTestRepo[T](expectedStoreOps: Seq[String])(p: Repo => MockEff[T]): T = {
42+
val repo = Repo("pr-repo-test", s"repo${repoCounter.getAndIncrement()}")
43+
val (state, output) = p(repo).runSA(MockState.empty).unsafeRunSync()
4544

4645
val store =
4746
config.workspace / s"store/pull_requests/v2/github/${repo.toPath}/pull_requests.json"
48-
assertEquals(result.map(d => (d.url, d.baseSha1, d.state)), Some((url, sha1, Open)))
49-
assert(createdAt.isDefined)
50-
5147
checkTrace(
5248
state,
53-
Vector(
54-
Cmd("read", store.toString),
55-
Cmd("write", store.toString)
56-
)
49+
expectedStoreOps.map(op => Cmd(op, store.toString)).toVector
5750
)
51+
52+
output
5853
}
5954

60-
test("getObsoleteOpenPullRequests for single update") {
61-
val repo = Repo("pr-repo-test", "repo2")
55+
private def beforeAndAfterPRCreation[T](update: Update)(func: Repo => MockEff[T]): (T, T) =
56+
executeOnTestRepo(expectedStoreOps = Seq("read", "write")) { repo =>
57+
for {
58+
before <- func(repo)
59+
_ <- pullRequestRepository.createOrUpdate(repo, openPRFor(update))
60+
after <- func(repo)
61+
} yield (before, after)
62+
}
63+
64+
test("createOrUpdate >> findPullRequest >> lastPullRequestCreatedAt") {
6265
val update = portableScala
66+
val data = openPRFor(update)
67+
68+
val (result, createdAt) = executeOnTestRepo(expectedStoreOps = Seq("read", "write")) { repo =>
69+
for {
70+
_ <- pullRequestRepository.createOrUpdate(repo, data)
71+
result <-
72+
pullRequestRepository.findLatestPullRequest(repo, update.crossDependency, "1.0.0".v)
73+
createdAt <- pullRequestRepository.lastPullRequestCreatedAt(repo)
74+
} yield (result, createdAt)
75+
}
76+
77+
assertEquals(result.map(d => (d.url, d.baseSha1, d.state)), Some((url, sha1, Open)))
78+
assert(createdAt.isDefined)
79+
}
80+
81+
test("getObsoleteOpenPullRequests for single update") {
82+
val data = openPRFor(portableScala)
6383
val nextUpdate = portableScala.copy(newerVersions = Nel.of("1.0.1".v))
64-
val data = PullRequestData[Id](url, sha1, update, Open, number, branch)
65-
66-
val p = for {
67-
emptyResult <- pullRequestRepository.getObsoleteOpenPullRequests(repo, nextUpdate)
68-
_ <- pullRequestRepository.createOrUpdate(repo, data)
69-
result <- pullRequestRepository.getObsoleteOpenPullRequests(repo, nextUpdate)
70-
_ <- pullRequestRepository.changeState(repo, url, PullRequestState.Closed)
71-
closedResult <- pullRequestRepository.getObsoleteOpenPullRequests(repo, nextUpdate)
72-
} yield (emptyResult, result, closedResult)
73-
val (state, (emptyResult, result, closedResult)) = p.runSA(MockState.empty).unsafeRunSync()
74-
val store =
75-
config.workspace / s"store/pull_requests/v2/github/${repo.toPath}/pull_requests.json"
84+
85+
val (emptyResult, result, closedResult) =
86+
executeOnTestRepo(expectedStoreOps = Seq("read", "write", "write")) { repo =>
87+
val getObsoleteOpenPRs = pullRequestRepository.getObsoleteOpenPullRequests(repo, nextUpdate)
88+
for {
89+
emptyResult <- getObsoleteOpenPRs
90+
_ <- pullRequestRepository.createOrUpdate(repo, data)
91+
result <- getObsoleteOpenPRs
92+
_ <- pullRequestRepository.changeState(repo, data.url, PullRequestState.Closed)
93+
closedResult <- getObsoleteOpenPRs
94+
} yield (emptyResult, result, closedResult)
95+
}
96+
7697
assertEquals(emptyResult, List.empty)
7798
assertEquals(closedResult, List.empty)
7899
assertEquals(result, List(data))
79-
80-
checkTrace(
81-
state,
82-
Vector(
83-
Cmd("read", store.toString),
84-
Cmd("write", store.toString),
85-
Cmd("write", store.toString)
86-
)
87-
)
88100
}
89101

90102
test("getObsoleteOpenPullRequests for the same single update") {
91-
val repo = Repo("pr-repo-test", "repo3")
92-
val update = portableScala
93-
val data = PullRequestData[Id](url, sha1, update, Open, number, branch)
94-
95-
val p = for {
96-
emptyResult <- pullRequestRepository.getObsoleteOpenPullRequests(repo, update)
97-
_ <- pullRequestRepository.createOrUpdate(repo, data)
98-
result <- pullRequestRepository.getObsoleteOpenPullRequests(repo, update)
99-
} yield (emptyResult, result)
100-
val (state, (emptyResult, result)) = p.runSA(MockState.empty).unsafeRunSync()
101-
val store =
102-
config.workspace / s"store/pull_requests/v2/github/${repo.toPath}/pull_requests.json"
103-
assertEquals(emptyResult, List.empty)
104-
assertEquals(result, List.empty)
103+
val (before, after) = beforeAndAfterPRCreation(portableScala) { repo =>
104+
pullRequestRepository.getObsoleteOpenPullRequests(repo, portableScala)
105+
}
105106

106-
checkTrace(
107-
state,
108-
Vector(
109-
Cmd("read", store.toString),
110-
Cmd("write", store.toString)
111-
)
112-
)
107+
assertEquals(before, List.empty)
108+
assertEquals(after, List.empty)
113109
}
114110

115111
test("getObsoleteOpenPullRequests for the another single update and ignore closed") {
116-
val repo = Repo("pr-repo-test", "repo4")
117-
val updateInStore = portableScala
118-
val newUpdate = catsCore
119-
val data = PullRequestData[Id](url, sha1, updateInStore, Open, number, branch)
120-
121-
val p = for {
122-
emptyResult <- pullRequestRepository.getObsoleteOpenPullRequests(repo, updateInStore)
123-
_ <- pullRequestRepository.createOrUpdate(repo, data)
124-
result <- pullRequestRepository.getObsoleteOpenPullRequests(repo, newUpdate)
125-
} yield (emptyResult, result)
126-
val (state, (emptyResult, result)) = p.runSA(MockState.empty).unsafeRunSync()
127-
val store =
128-
config.workspace / s"store/pull_requests/v2/github/${repo.toPath}/pull_requests.json"
112+
val (emptyResult, result) =
113+
executeOnTestRepo(expectedStoreOps = Seq("read", "write")) { repo =>
114+
for {
115+
emptyResult <- pullRequestRepository.getObsoleteOpenPullRequests(repo, portableScala)
116+
_ <- pullRequestRepository.createOrUpdate(repo, openPRFor(portableScala))
117+
result <- pullRequestRepository.getObsoleteOpenPullRequests(repo, catsCore)
118+
} yield (emptyResult, result)
119+
}
120+
129121
assertEquals(emptyResult, List.empty)
130122
assertEquals(result, List.empty)
131-
132-
checkTrace(
133-
state,
134-
Vector(
135-
Cmd("read", store.toString),
136-
Cmd("write", store.toString)
137-
)
138-
)
139123
}
140124

141125
test("findLatestPullRequest ignores grouped updates") {
142-
val repo = Repo("pr-repo-test", "repo5")
143-
val update = portableScala
144-
val grouped = Update.Grouped("group", None, List(update))
145-
val data = PullRequestData[Id](url, sha1, grouped, Open, number, branch)
146-
147-
val p = for {
148-
_ <- pullRequestRepository.createOrUpdate(repo, data)
149-
result <- pullRequestRepository.findLatestPullRequest(repo, update.crossDependency, "1.0.0".v)
150-
} yield result
151-
152-
val (state, result) = p.runSA(MockState.empty).unsafeRunSync()
153-
154-
val store =
155-
config.workspace / s"store/pull_requests/v2/github/${repo.toPath}/pull_requests.json"
126+
val (_, result) = beforeAndAfterPRCreation(groupedUpdate(portableScala)) { repo =>
127+
pullRequestRepository.findLatestPullRequest(repo, portableScala.crossDependency, "1.0.0".v)
128+
}
156129
assert(result.isEmpty)
157-
158-
checkTrace(
159-
state,
160-
Vector(
161-
Cmd("read", store.toString),
162-
Cmd("write", store.toString)
163-
)
164-
)
165130
}
166131

167132
test("lastPullRequestCreatedAt returns timestamp for grouped updates") {
168-
val repo = Repo("pr-repo-test", "repo7")
169-
val update = catsCore
170-
val grouped = Update.Grouped("group", None, List(update))
171-
val data = PullRequestData[Id](url, sha1, grouped, Open, number, branch)
172-
173-
val p = for {
174-
emptyCreatedAt <- pullRequestRepository.lastPullRequestCreatedAt(repo)
175-
_ <- pullRequestRepository.createOrUpdate(repo, data)
176-
createdAt <- pullRequestRepository.lastPullRequestCreatedAt(repo)
177-
} yield (emptyCreatedAt, createdAt)
178-
val (state, (emptyCreatedAt, createdAt)) = p.runSA(MockState.empty).unsafeRunSync()
179-
180-
val store =
181-
config.workspace / s"store/pull_requests/v2/github/${repo.toPath}/pull_requests.json"
182-
assert(emptyCreatedAt.isEmpty)
183-
assert(createdAt.isDefined)
184-
185-
checkTrace(
186-
state,
187-
Vector(
188-
Cmd("read", store.toString),
189-
Cmd("write", store.toString)
133+
val (before, after) =
134+
beforeAndAfterPRCreation(groupedUpdate(catsCore))(
135+
pullRequestRepository.lastPullRequestCreatedAt
190136
)
191-
)
137+
assert(before.isEmpty)
138+
assert(after.isDefined)
192139
}
193140

141+
test("lastPullRequestCreatedAtByArtifact for grouped updates") {
142+
val (before, after) =
143+
beforeAndAfterPRCreation(groupedUpdate(catsCore))(
144+
pullRequestRepository.lastPullRequestCreatedAtByArtifact
145+
)
146+
assert(before.isEmpty)
147+
assert(after.contains(catsCore.groupAndMainArtifactId))
148+
}
194149
}

0 commit comments

Comments
 (0)