Skip to content

Commit 89cdfad

Browse files
feat: commit share chart facts (#213)
* feat: commit share facts * fix: case when user is not a contributor
1 parent 14c33a8 commit 89cdfad

File tree

5 files changed

+111
-11
lines changed

5 files changed

+111
-11
lines changed

src/main/kotlin/app/FactCodes.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ object FactCodes {
1212
val COMMIT_NUM = 9 // Used for averaging COMMIT_LINE_NUM_AVG between repos.
1313
// A map of line numbers to commits number. Used in a commit histogram.
1414
val COMMIT_NUM_TO_LINE_NUM = 12
15+
val COMMIT_SHARE = 16 // Used for commit share chart.
16+
val COMMIT_SHARE_REPO_AVG = 17 // Used for commit share chart.
1517
val LINE_LONGEVITY = 3 // Used for longevity graph.
1618
val LINE_LONGEVITY_REPO = 4 // Used for longevity graph.
1719
val LINE_LEN_AVG = 10 // Average length of line fun fact.

src/main/kotlin/app/hashers/MetaHasher.kt

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright 2017 Sourcerer Inc. All Rights Reserved.
22
// Author: Liubov Yaronskaya ([email protected])
3+
// Author: Anatoly Kislov ([email protected])
34

45
package app.hashers
56

@@ -9,22 +10,51 @@ import app.api.Api
910
import app.model.Author
1011
import app.model.Fact
1112
import app.model.Repo
13+
import java.util.*
14+
import kotlin.collections.HashSet
1215

1316
/**
1417
* MetaHasher hashes repository and uploads stats to server.
1518
*/
1619
class MetaHasher(private val serverRepo: Repo = Repo(),
1720
private val api: Api) {
18-
fun calculateAndSendFacts(authors: HashSet<Author>) {
21+
fun calculateAndSendFacts(authors: HashSet<Author>,
22+
commitsCount: HashMap<String, Int>,
23+
userEmails: List<String>) {
24+
// Sometimes contributors use multiple emails to contribute to single
25+
// project, as we don't know exactly who is who (except current user),
26+
// let's at least filter authors by similarity.
27+
val otherAuthors = authors.filter { author ->
28+
!userEmails.contains(author.email)
29+
}
30+
// Current user may not be a contributor of repo.
31+
val isUserAuthor = otherAuthors.size < authors.size
32+
val numAuthors = getAuthorsNum(otherAuthors) +
33+
if (isUserAuthor) 1 else 0
34+
1935
val facts = mutableListOf<Fact>()
20-
facts.add(Fact(serverRepo, FactCodes.REPO_TEAM_SIZE, 0,
21-
getAuthorsNum(authors).toString()))
22-
Logger.debug { "Num authors: ${authors.size}" }
23-
Logger.debug { "Num real authors: ${facts.first().value}" }
36+
37+
// Repository facts: team size.
38+
facts.add(FactCodes.REPO_TEAM_SIZE, 0, numAuthors)
39+
40+
// Repository facts: commit share.
41+
val numAllCommits = commitsCount.values.fold(0) { acc, i -> acc + i }
42+
val avgCommits = Math.round(numAllCommits.toDouble() / numAuthors)
43+
.toInt()
44+
facts.add(FactCodes.COMMIT_SHARE_REPO_AVG, 0, avgCommits)
45+
46+
if (isUserAuthor) {
47+
val numUserCommits = userEmails
48+
.mapNotNull { email -> commitsCount[email] }
49+
.fold(0) { acc, i -> acc + i }
50+
val userEmail = userEmails.first()
51+
facts.add(FactCodes.COMMIT_SHARE, 0, numUserCommits, userEmail)
52+
}
53+
2454
postFactsToServer(facts)
2555
}
2656

27-
private fun getAuthorsNum(authors: HashSet<Author>): Int {
57+
private fun getAuthorsNum(authors: List<Author>): Int {
2858
val names = authors.map { it.name }
2959
val emails = authors.map { it.email.split("@")[0] }
3060
val namesQgrams = names.map { getThreegrams(it) }
@@ -68,4 +98,15 @@ class MetaHasher(private val serverRepo: Repo = Repo(),
6898
Logger.info { "Sent ${facts.size} facts to server" }
6999
}
70100
}
101+
102+
private fun MutableList<Fact>.add(code: Int, key: Int, value: Any,
103+
email: String? = null) {
104+
val fact = if (email != null) {
105+
Fact(serverRepo, code, key, value.toString(), Author(email = email))
106+
} else {
107+
Fact(serverRepo, code, key, value.toString())
108+
}
109+
110+
this.add(fact)
111+
}
71112
}

src/main/kotlin/app/hashers/RepoHasher.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ class RepoHasher(private val api: Api,
3636
Logger.info { "Hashing of repo started" }
3737
updateProcess(processEntryId, Api.PROCESS_STATUS_START)
3838

39-
val (rehashes, authors) = CommitCrawler.fetchRehashesAndAuthors(git)
39+
val (rehashes, authors, commitsCount) =
40+
CommitCrawler.fetchRehashesAndAuthors(git)
4041
localRepo.parseGitConfig(git.repository.config)
4142
val serverRepo = initServerRepo(localRepo, rehashes.last)
4243

@@ -86,8 +87,11 @@ class RepoHasher(private val api: Api,
8687
.updateFromObservable(jgitObservable, onError, api)
8788
}
8889
if (BuildConfig.META_HASHER_ENABLED) {
90+
val userEmail = configurator.getUser().emails.map { it.email }
8991
MetaHasher(serverRepo, api)
90-
.calculateAndSendFacts(authors)
92+
.calculateAndSendFacts(authors = authors,
93+
commitsCount = commitsCount,
94+
userEmails = userEmail)
9195
}
9296

9397
// Start and synchronously wait until all subscribers complete.

src/test/kotlin/test/tests/hashers/MetaHasherTest.kt

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import org.jetbrains.spek.api.dsl.given
1414
import org.jetbrains.spek.api.dsl.it
1515
import test.utils.TestRepo
1616
import test.utils.assertFactInt
17+
import test.utils.assertNoFact
1718

1819
class MetaHasherTest : Spek({
1920
val repoPath = "../testrepo-meta-hasher-"
@@ -35,7 +36,28 @@ class MetaHasherTest : Spek({
3536
Author("yablokov", "[email protected]"),
3637
Author("Yablokov Dmitriy Andreevich", "[email protected]"),
3738
Author("Dmitry Yablokov", "[email protected]"),
38-
Author("Dmitry Yablokov", "[email protected]"))
39+
Author("Dmitry Yablokov", "[email protected]"),
40+
Author("John Brown", "[email protected]"),
41+
Author("Johnny Brown", "[email protected]"))
42+
val commits = hashMapOf(
43+
Pair("[email protected]", 0),
44+
Pair("[email protected]", 10),
45+
Pair("[email protected]", 10),
46+
Pair("[email protected]", 10),
47+
Pair("[email protected]", 10),
48+
Pair("[email protected]", 10),
49+
Pair("[email protected]", 10),
50+
Pair("[email protected]", 10),
51+
Pair("[email protected]", 10),
52+
Pair("[email protected]", 10),
53+
Pair("[email protected]", 10),
54+
Pair("[email protected]", 20),
55+
Pair("[email protected]", 20)
56+
)
57+
val userEmails = listOf(
58+
59+
60+
)
3961
val authorsList = authors.toList()
4062
val mockApi = MockApi(mockRepo = repo)
4163
val facts = mockApi.receivedFacts
@@ -53,8 +75,31 @@ class MetaHasherTest : Spek({
5375
author = authorsList[i])
5476
}
5577

56-
MetaHasher(repo, mockApi).calculateAndSendFacts(authors)
57-
assertFactInt(FactCodes.REPO_TEAM_SIZE, 0, 6, facts = facts)
78+
MetaHasher(repo, mockApi).calculateAndSendFacts(authors, commits,
79+
userEmails)
80+
81+
assertFactInt(FactCodes.COMMIT_SHARE, 0, 20,
82+
Author(email = userEmails.first()), facts = facts)
83+
assertFactInt(FactCodes.COMMIT_SHARE_REPO_AVG, 0, 20, facts = facts)
84+
assertFactInt(FactCodes.REPO_TEAM_SIZE, 0, 7, facts = facts)
85+
}
86+
87+
it("sends facts (user not contributor)") {
88+
for (i in 0..authors.size - 1) {
89+
val line = "line number $i"
90+
val fileName = "file$i.txt"
91+
testRepo.createFile(fileName, listOf(line))
92+
testRepo.commit(message = "$line in $fileName",
93+
author = authorsList[i])
94+
}
95+
96+
MetaHasher(repo, mockApi).calculateAndSendFacts(authors, commits,
97+
listOf())
98+
99+
assertNoFact(FactCodes.COMMIT_SHARE, 0,
100+
Author(email = userEmails.first()), facts = facts)
101+
assertFactInt(FactCodes.COMMIT_SHARE_REPO_AVG, 0, 20, facts = facts)
102+
assertFactInt(FactCodes.REPO_TEAM_SIZE, 0, 7, facts = facts)
58103
}
59104

60105
afterGroup {

src/test/kotlin/test/utils/FactHelper.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import app.model.Author
77
import app.model.Fact
88
import kotlin.test.assertEquals
99
import kotlin.test.assertNotNull
10+
import kotlin.test.assertNull
1011
import kotlin.test.assertTrue
1112

1213
fun getFact(code: Int, key: Int, author: Author? = null,
@@ -23,6 +24,13 @@ fun assertFactInt(code: Int, key: Int, value: Int, author: Author? = null,
2324
assertEquals(value, fact.value.toInt())
2425
}
2526

27+
fun assertNoFact(code: Int, key: Int, author: Author? = null,
28+
facts: List<Fact>) {
29+
val fact = facts.find { fact -> fact.code == code && fact.key == key &&
30+
(author == null || fact.author == author) }
31+
assertNull(fact)
32+
}
33+
2634
fun assertFactDouble(code: Int, key: Int, value: Double, author: Author? = null,
2735
facts: List<Fact>) {
2836
val fact = getFact(code, key, author, facts)

0 commit comments

Comments
 (0)