Skip to content

Commit b13ba53

Browse files
authored
feat: add alert for no known emails in repo (APP-162, APP-167) (#83)
* feat: add alert for no known emails in repo * feat: add logic for selecting default branch (APP-167)
1 parent 36c3989 commit b13ba53

File tree

5 files changed

+92
-42
lines changed

5 files changed

+92
-42
lines changed

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import app.model.Author
1010
import app.model.Repo
1111
import app.model.Fact
1212
import app.utils.FileHelper
13-
import app.utils.RepoHelper
1413
import io.reactivex.Observable
1514
import org.eclipse.jgit.diff.DiffFormatter
1615
import org.eclipse.jgit.diff.DiffEntry
@@ -23,15 +22,12 @@ import org.eclipse.jgit.revwalk.RevWalk
2322
import org.eclipse.jgit.treewalk.TreeWalk
2423
import org.eclipse.jgit.util.io.DisabledOutputStream
2524

26-
import java.io.File
2725
import java.io.FileInputStream
2826
import java.io.FileNotFoundException
2927
import java.io.FileOutputStream
3028
import java.io.ObjectOutputStream
3129
import java.io.ObjectInputStream
3230
import java.io.Serializable
33-
import java.nio.file.Files
34-
import java.nio.file.Paths
3531
import java.lang.Exception
3632
import java.text.SimpleDateFormat
3733
import java.util.Date
@@ -149,7 +145,7 @@ class CodeLongevity(private val serverRepo: Repo,
149145
val repo: Repository = git.repository
150146
val revWalk = RevWalk(repo)
151147
val head: RevCommit =
152-
try { revWalk.parseCommit(repo.resolve(RepoHelper.MASTER_BRANCH)) }
148+
try { revWalk.parseCommit(CommitCrawler.getDefaultBranchHead(git)) }
153149
catch(e: Exception) { throw Exception("No branch") }
154150

155151
val df = DiffFormatter(DisabledOutputStream.INSTANCE)

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

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,69 @@ import app.model.DiffContent
99
import app.model.DiffFile
1010
import app.model.DiffRange
1111
import app.model.Repo
12-
import app.utils.RepoHelper
1312
import io.reactivex.Observable
13+
import org.apache.commons.codec.digest.DigestUtils
1414
import org.eclipse.jgit.api.Git
1515
import org.eclipse.jgit.diff.DiffEntry
1616
import org.eclipse.jgit.diff.DiffFormatter
1717
import org.eclipse.jgit.diff.RawText
18-
import org.eclipse.jgit.errors.MissingObjectException
1918
import org.eclipse.jgit.lib.ObjectId
2019
import org.eclipse.jgit.revwalk.RevCommit
2120
import org.eclipse.jgit.revwalk.RevWalk
2221
import org.eclipse.jgit.util.io.DisabledOutputStream
22+
import java.util.LinkedList
2323

2424
object CommitCrawler {
25+
private val MASTER_BRANCH = "refs/heads/master"
26+
private val REMOTE_HEAD = "refs/remotes/origin/HEAD"
27+
28+
fun getDefaultBranchHead(git: Git): ObjectId {
29+
val remoteHead = git.branchList()?.repository?.allRefs?.filter {
30+
it.key.contains(REMOTE_HEAD)
31+
}?.entries?.firstOrNull()?.value?.target?.objectId
32+
if (remoteHead != null) {
33+
Logger.debug { "Hashing from remote default branch" }
34+
return remoteHead
35+
}
36+
val masterBranch = git.repository.resolve(MASTER_BRANCH)
37+
if (masterBranch != null) {
38+
Logger.debug { "Hashing from local master branch" }
39+
return masterBranch
40+
}
41+
throw Exception("No remote default or local master branch found")
42+
}
43+
44+
fun fetchRehashesAndEmails(git: Git):
45+
Pair<LinkedList<String>, HashSet<String>> {
46+
val head: RevCommit = RevWalk(git.repository)
47+
.parseCommit(getDefaultBranchHead(git))
48+
49+
val revWalk = RevWalk(git.repository)
50+
revWalk.markStart(head)
51+
52+
val commitsRehashes = LinkedList<String>()
53+
val emails = hashSetOf<String>()
54+
55+
var commit: RevCommit? = revWalk.next()
56+
while (commit != null) {
57+
commitsRehashes.add(DigestUtils.sha256Hex(commit.name))
58+
emails.add(commit.authorIdent.emailAddress)
59+
commit.disposeBody()
60+
commit = revWalk.next()
61+
}
62+
revWalk.dispose()
63+
64+
return Pair(commitsRehashes, emails)
65+
}
66+
2567
fun getObservable(git: Git, repo: Repo,
2668
numCommits: Int = 0): Observable<Commit> {
2769
var curNumCommits = 0
2870
return Observable
2971
.create<Commit> { subscriber ->
3072
try {
3173
val revWalk = RevWalk(git.repository)
32-
val commitId = git.repository.resolve(RepoHelper.MASTER_BRANCH)
74+
val commitId = getDefaultBranchHead(git)
3375
revWalk.markStart(revWalk.parseCommit(commitId))
3476
for (revCommit in revWalk) {
3577
subscriber.onNext(Commit(revCommit))

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

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
package app.hashers
55

6-
import app.BuildConfig
76
import app.Logger
87
import app.api.Api
98
import app.config.Configurator
@@ -12,13 +11,9 @@ import app.model.LocalRepo
1211
import app.model.Repo
1312
import app.utils.HashingException
1413
import app.utils.RepoHelper
15-
import org.apache.commons.codec.digest.DigestUtils
1614
import org.eclipse.jgit.api.Git
17-
import org.eclipse.jgit.revwalk.RevCommit
18-
import org.eclipse.jgit.revwalk.RevWalk
1915
import java.io.File
2016
import java.io.IOException
21-
import java.util.*
2217
import kotlin.collections.HashSet
2318

2419
class RepoHasher(private val localRepo: LocalRepo, private val api: Api,
@@ -35,7 +30,7 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api,
3530
Logger.info { "Hashing of repo started" }
3631
val git = loadGit(localRepo.path)
3732
try {
38-
val (rehashes, emails) = fetchRehashesAndEmails(git)
33+
val (rehashes, emails) = CommitCrawler.fetchRehashesAndEmails(git)
3934

4035
localRepo.parseGitConfig(git.repository.config)
4136
initServerRepo(rehashes.last)
@@ -127,29 +122,6 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api,
127122
initCommitRehash, localRepo))
128123
}
129124

130-
private fun fetchRehashesAndEmails(git: Git):
131-
Pair<LinkedList<String>, HashSet<String>> {
132-
val head: RevCommit = RevWalk(git.repository)
133-
.parseCommit(git.repository.resolve(RepoHelper.MASTER_BRANCH))
134-
135-
val revWalk = RevWalk(git.repository)
136-
revWalk.markStart(head)
137-
138-
val commitsRehashes = LinkedList<String>()
139-
val emails = hashSetOf<String>()
140-
141-
var commit: RevCommit? = revWalk.next()
142-
while (commit != null) {
143-
commitsRehashes.add(DigestUtils.sha256Hex(commit.name))
144-
emails.add(commit.authorIdent.emailAddress)
145-
commit.disposeBody()
146-
commit = revWalk.next()
147-
}
148-
revWalk.dispose()
149-
150-
return Pair(commitsRehashes, emails)
151-
}
152-
153125
private fun filterEmails(emails: HashSet<String>): HashSet<String> {
154126
if (localRepo.hashAllContributors) {
155127
return emails

src/main/kotlin/app/ui/EmailState.kt

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ package app.ui
66
import app.Logger
77
import app.api.Api
88
import app.config.Configurator
9+
import app.hashers.CommitCrawler
10+
import app.model.LocalRepo
911
import app.model.User
1012
import app.model.UserEmail
1113
import app.utils.UiHelper
@@ -39,16 +41,26 @@ class EmailState constructor(private val context: Context,
3941
// TODO(anatoly): Add user config parsing.
4042

4143
// Add emails from git configs.
44+
val reposEmails = hashMapOf<LocalRepo, HashSet<String>>()
4245
for (repo in configurator.getLocalRepos()) {
46+
var git: Git? = null
4347
try {
44-
val git = Git.open(File(repo.path))
48+
git = Git.open(File(repo.path))
4549
val email = git.repository
4650
.config.getString("user", null, "email") ?: ""
4751
if (!knownEmails.contains(email)) {
4852
configEmails.add(email)
4953
}
54+
// Fetch and save emails from repo for "no-email" warning.
55+
val (_, emails) = CommitCrawler.fetchRehashesAndEmails(git)
56+
reposEmails.put(repo, emails)
5057
} catch (e: Exception) {
51-
Logger.error(e, "Error while parsing git config")
58+
Logger.error(e, "Error while parsing repo")
59+
} finally {
60+
if (git != null) {
61+
git.repository?.close()
62+
git.close()
63+
}
5264
}
5365
}
5466

@@ -61,6 +73,35 @@ class EmailState constructor(private val context: Context,
6173
}
6274
}
6375

76+
// Show warning if no commits
77+
val reposUserMissing = mutableListOf<LocalRepo>()
78+
for (repo in configurator.getLocalRepos()) {
79+
val presentedEmails = reposEmails.get(repo)
80+
val updatedEmails = knownEmails + newEmails
81+
if (presentedEmails != null) {
82+
var userMissing = true
83+
for (email in presentedEmails) {
84+
if (updatedEmails.contains(email)) {
85+
userMissing = false
86+
break
87+
}
88+
}
89+
if (userMissing) {
90+
reposUserMissing.add(repo)
91+
}
92+
}
93+
}
94+
if (reposUserMissing.isNotEmpty()) {
95+
if (reposUserMissing.size == 1) {
96+
Logger.print("${reposUserMissing.first()} repo does not " +
97+
"contains commits from emails you've specified")
98+
} else {
99+
Logger.print("Following repos do not contain commits from " +
100+
"emails you've specified:")
101+
reposUserMissing.forEach { Logger.print(it) }
102+
}
103+
}
104+
64105
// Ask user to enter his emails.
65106
if (UiHelper.confirm("Do you want to specify additional emails " +
66107
"that you use in repositories?", defaultIsYes = false)) {

src/main/kotlin/app/utils/RepoHelper.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package app.utils
55

66
import app.Logger
7+
import app.hashers.CommitCrawler
78
import app.model.LocalRepo
89
import org.apache.commons.codec.digest.DigestUtils
910
import org.eclipse.jgit.api.Git
@@ -17,8 +18,6 @@ import java.nio.file.Paths
1718
* Class for utility functions on repos.
1819
*/
1920
object RepoHelper {
20-
val MASTER_BRANCH = "refs/heads/master"
21-
2221
fun isValidRepo(path: String): Boolean {
2322
if (!isDirectory(path)) {
2423
return false
@@ -30,7 +29,7 @@ object RepoHelper {
3029
try {
3130
git = Git.open(File(path))
3231
repository = git.repository
33-
commitId = repository.resolve(MASTER_BRANCH)
32+
commitId = CommitCrawler.getDefaultBranchHead(git)
3433
} catch (e: Exception) {
3534
Logger.error(e, "Cannot access repository at specified path")
3635
return false

0 commit comments

Comments
 (0)