Skip to content

Commit 06b24a7

Browse files
committed
Added solutions
1 parent 3f40c75 commit 06b24a7

10 files changed

+92
-16
lines changed

src/contributors/GitHubService.kt

+11
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

+3-1
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.sumBy { it.contributions }) }
20+
.sortedByDescending { it.contributions }

src/tasks/Request2Background.kt

+1-1
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

+5-3
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,18 @@ fun loadContributorsCallbacks(service: GitHubService, req: RequestData, updateRe
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 numberOfProcessed = AtomicInteger(0)
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+
if (numberOfProcessed.incrementAndGet() == repos.size) {
22+
updateResults(allUsers.aggregate())
23+
}
2024
}
2125
}
22-
// TODO: Why this code doesn't work? How to fix that?
23-
updateResults(allUsers.aggregate())
2426
}
2527
}
2628

src/tasks/Request4Suspend.kt

+10-1
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

+13-1
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

+15-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,19 @@ import kotlinx.coroutines.*
55
import kotlin.coroutines.coroutineContext
66

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

src/tasks/Request6Progress.kt

+14-1
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

+20-3
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

-4
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)