Skip to content

Commit 3d35b33

Browse files
committed
Added solutions
Upgrade version of kotlin plugins and coroutine dependencies to 1.5.0
1 parent 587a0f1 commit 3d35b33

10 files changed

+93
-16
lines changed

src/contributors/GitHubService.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@ interface GitHubService {
2525
@Path("owner") owner: String,
2626
@Path("repo") repo: String
2727
): Call<List<User>>
28+
29+
@GET("orgs/{org}/repos?per_page=100")
30+
suspend fun getOrgRepos(
31+
@Path("org") org: String
32+
): Response<List<Repo>>
33+
34+
@GET("repos/{owner}/{repo}/contributors?per_page=100")
35+
suspend fun getRepoContributors(
36+
@Path("owner") owner: String,
37+
@Path("repo") repo: String
38+
): Response<List<User>>
2839
}
2940

3041
@Serializable

src/tasks/Aggregation.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ TODO: Write aggregation code.
1515
You can use 'Navigate | Test' menu action (note the shortcut) to navigate to the test.
1616
*/
1717
fun List<User>.aggregate(): List<User> =
18-
this
18+
groupBy { it.login }
19+
.map { (login, group) -> User(login, group.sumOf { it.contributions }) }
20+
.sortedByDescending { it.contributions }

src/tasks/Request2Background.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ import kotlin.concurrent.thread
77

88
fun loadContributorsBackground(service: GitHubService, req: RequestData, updateResults: (List<User>) -> Unit) {
99
thread {
10-
loadContributorsBlocking(service, req)
10+
updateResults(loadContributorsBlocking(service, req))
1111
}
1212
}

src/tasks/Request3Callbacks.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,23 @@ import retrofit2.Call
55
import retrofit2.Callback
66
import retrofit2.Response
77
import java.util.*
8-
import java.util.concurrent.atomic.AtomicInteger
8+
import java.util.concurrent.CountDownLatch
99

1010
fun loadContributorsCallbacks(service: GitHubService, req: RequestData, updateResults: (List<User>) -> Unit) {
1111
service.getOrgReposCall(req.org).onResponse { responseRepos ->
1212
logRepos(req, responseRepos)
1313
val repos = responseRepos.bodyList()
14-
val allUsers = mutableListOf<User>()
14+
val allUsers = Collections.synchronizedList(mutableListOf<User>())
15+
val countDownLatch = CountDownLatch(repos.size)
1516
for (repo in repos) {
1617
service.getRepoContributorsCall(req.org, repo.name).onResponse { responseUsers ->
1718
logUsers(repo, responseUsers)
1819
val users = responseUsers.bodyList()
1920
allUsers += users
21+
countDownLatch.countDown()
2022
}
2123
}
22-
// TODO: Why this code doesn't work? How to fix that?
24+
countDownLatch.await()
2325
updateResults(allUsers.aggregate())
2426
}
2527
}

src/tasks/Request4Suspend.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,14 @@ package tasks
33
import contributors.*
44

55
suspend fun loadContributorsSuspend(service: GitHubService, req: RequestData): List<User> {
6-
TODO()
6+
val repos = service
7+
.getOrgRepos(req.org)
8+
.also { logRepos(req, it) }
9+
.bodyList()
10+
11+
return repos.flatMap { repo ->
12+
service.getRepoContributors(req.org, repo.name)
13+
.also { logUsers(repo, it) }
14+
.bodyList()
15+
}.aggregate()
716
}

src/tasks/Request5Concurrent.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,17 @@ import contributors.*
44
import kotlinx.coroutines.*
55

66
suspend fun loadContributorsConcurrent(service: GitHubService, req: RequestData): List<User> = coroutineScope {
7-
TODO()
7+
val repos = service
8+
.getOrgRepos(req.org)
9+
.also { logRepos(req, it) }
10+
.bodyList()
11+
12+
val deferreds: List<Deferred<List<User>>> = repos.map { repo ->
13+
async {
14+
service.getRepoContributors(req.org, repo.name)
15+
.also { logUsers(repo, it) }
16+
.bodyList()
17+
}
18+
}
19+
deferreds.awaitAll().flatten().aggregate()
820
}

src/tasks/Request5NotCancellable.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,21 @@ import contributors.*
44
import kotlinx.coroutines.*
55
import kotlin.coroutines.coroutineContext
66

7+
@OptIn(DelicateCoroutinesApi::class)
78
suspend fun loadContributorsNotCancellable(service: GitHubService, req: RequestData): List<User> {
8-
TODO()
9+
val repos = service
10+
.getOrgRepos(req.org)
11+
.also { logRepos(req, it) }
12+
.bodyList()
13+
14+
val deferreds: List<Deferred<List<User>>> = repos.map { repo ->
15+
GlobalScope.async(Dispatchers.Default) {
16+
log("starting loading for ${repo.name}")
17+
delay(3000)
18+
service.getRepoContributors(req.org, repo.name)
19+
.also { logUsers(repo, it) }
20+
.bodyList()
21+
}
22+
}
23+
return deferreds.awaitAll().flatten().aggregate()
924
}

src/tasks/Request6Progress.kt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,18 @@ suspend fun loadContributorsProgress(
77
req: RequestData,
88
updateResults: suspend (List<User>, completed: Boolean) -> Unit
99
) {
10-
TODO()
10+
val repos = service
11+
.getOrgRepos(req.org)
12+
.also { logRepos(req, it) }
13+
.bodyList()
14+
15+
var allUsers = emptyList<User>()
16+
for ((index, repo) in repos.withIndex()) {
17+
val users = service.getRepoContributors(req.org, repo.name)
18+
.also { logUsers(repo, it) }
19+
.bodyList()
20+
21+
allUsers = (allUsers + users).aggregate()
22+
updateResults(allUsers, index == repos.lastIndex)
23+
}
1124
}

src/tasks/Request7Channels.kt

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,25 @@ suspend fun loadContributorsChannels(
99
service: GitHubService,
1010
req: RequestData,
1111
updateResults: suspend (List<User>, completed: Boolean) -> Unit
12-
) {
13-
coroutineScope {
14-
TODO()
12+
) = coroutineScope {
13+
val repos = service
14+
.getOrgRepos(req.org)
15+
.also { logRepos(req, it) }
16+
.bodyList()
17+
18+
val channel = Channel<List<User>>()
19+
for (repo in repos) {
20+
launch {
21+
val users = service.getRepoContributors(req.org, repo.name)
22+
.also { logUsers(repo, it) }
23+
.bodyList()
24+
channel.send(users)
25+
}
26+
}
27+
var allUsers = emptyList<User>()
28+
repeat(repos.size) {
29+
val users = channel.receive()
30+
allUsers = (allUsers + users).aggregate()
31+
updateResults(allUsers, it == repos.lastIndex)
1532
}
1633
}

test/contributors/MockGithubService.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ object MockGithubService : GitHubService {
1414
return Calls.response(reposMap.getValue(repo).users)
1515
}
1616

17-
/*
18-
// Uncomment the following implementations after adding these methods to GitHubService:
19-
2017
override suspend fun getOrgRepos(org: String): Response<List<Repo>> {
2118
delay(reposDelay)
2219
return Response.success(repos)
@@ -27,5 +24,4 @@ object MockGithubService : GitHubService {
2724
delay(testRepo.delay)
2825
return Response.success(testRepo.users)
2926
}
30-
*/
3127
}

0 commit comments

Comments
 (0)