diff --git a/src/main/kotlin/app/hashers/CodeLongevity.kt b/src/main/kotlin/app/hashers/CodeLongevity.kt index 22356649..d5c9c397 100644 --- a/src/main/kotlin/app/hashers/CodeLongevity.kt +++ b/src/main/kotlin/app/hashers/CodeLongevity.kt @@ -143,7 +143,8 @@ class CodeLineAges : Serializable { */ class CodeLongevity(private val serverRepo: Repo, private val emails: HashSet, - git: Git) { + git: Git, + private val onError: (Throwable) -> Unit) { val repo: Repository = git.repository val revWalk = RevWalk(repo) val head: RevCommit = @@ -330,7 +331,7 @@ class CodeLongevity(private val serverRepo: Repo, } } - getDiffsObservable(tail).blockingSubscribe { (commit, diffs) -> + getDiffsObservable(tail).blockingSubscribe( { (commit, diffs) -> // A step back in commits history. Update the files map according // to the diff. Traverse the diffs backwards to handle double // renames properly. @@ -383,10 +384,17 @@ class CodeLongevity(private val serverRepo: Repo, for (idx in insStart .. insEnd - 1) { val from = RevCommitLine(commit, newId, newPath, idx, false) - val to = lines.get(idx) - val cl = CodeLine(repo, from, to) - Logger.trace { "Collected: ${cl}" } - subscriber.onNext(cl) + try { + val to = lines.get(idx) + val cl = CodeLine(repo, from, to) + Logger.trace { "Collected: ${cl}" } + subscriber.onNext(cl) + } + catch(e: IndexOutOfBoundsException) { + Logger.error(e, + "No line at ${idx}; commit: ${commit.getName()}; '${commit.getShortMessage()}'") + throw e + } } lines.subList(insStart, insEnd).clear() } @@ -416,7 +424,7 @@ class CodeLongevity(private val serverRepo: Repo, files.set(oldPath, files.remove(newPath)!!) } } - } + }, onError) // If a tail revision was given then the map has to contain unclaimed // code lines, i.e. the lines added before the tail revision. Push diff --git a/src/main/kotlin/app/hashers/RepoHasher.kt b/src/main/kotlin/app/hashers/RepoHasher.kt index f5a3c20c..f7882c31 100644 --- a/src/main/kotlin/app/hashers/RepoHasher.kt +++ b/src/main/kotlin/app/hashers/RepoHasher.kt @@ -80,7 +80,8 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api, // TODO(anatoly): CodeLongevity hash from observable. try { - CodeLongevity(serverRepo, filteredEmails, git).updateStats(api) + CodeLongevity(serverRepo, filteredEmails, git, onError) + .updateStats(api) } catch (e: Throwable) { onError(e) diff --git a/src/test/kotlin/test/tests/hashers/CodeLongevityTest.kt b/src/test/kotlin/test/tests/hashers/CodeLongevityTest.kt index 7bc110aa..50cda460 100644 --- a/src/test/kotlin/test/tests/hashers/CodeLongevityTest.kt +++ b/src/test/kotlin/test/tests/hashers/CodeLongevityTest.kt @@ -14,6 +14,7 @@ import test.utils.TestRepo import kotlin.test.assertEquals import kotlin.test.assertTrue +import kotlin.test.fail import org.eclipse.jgit.revwalk.RevCommit @@ -68,7 +69,8 @@ class CodeLongevityTest : Spek({ // t1: initial insertion testRepo.createFile(fileName, listOf("line1", "line2")) val rev1 = testRepo.commit("initial commit") - val lines1 = CodeLongevity(Repo(), emails, testRepo.git).getLinesList() + val lines1 = CodeLongevity(Repo(), emails, testRepo.git, + { _ -> fail("exception") }).getLinesList() it("'t1: initial insertion'") { assertEquals(2, lines1.size) @@ -85,7 +87,8 @@ class CodeLongevityTest : Spek({ // t2: subsequent insertion testRepo.insertLines(fileName, 1, listOf("line in the middle")) val rev2 = testRepo.commit("insert line") - val lines2 = CodeLongevity(Repo(), emails, testRepo.git).getLinesList() + val lines2 = CodeLongevity(Repo(), emails, testRepo.git, + { _ -> fail("exception") }).getLinesList() it("'t2: subsequent insertion'") { assertEquals(3, lines2.size) @@ -106,7 +109,8 @@ class CodeLongevityTest : Spek({ // t3: subsequent deletion testRepo.deleteLines(fileName, 2, 2) val rev3 = testRepo.commit("delete line") - val lines3 = CodeLongevity(Repo(), emails, testRepo.git).getLinesList() + val lines3 = CodeLongevity(Repo(), emails, testRepo.git, + { _ -> fail("exception") }).getLinesList() it("'t3: subsequent deletion'") { assertEquals(3, lines3.size) @@ -127,7 +131,8 @@ class CodeLongevityTest : Spek({ // t4: file deletion testRepo.deleteFile(fileName) val rev4 = testRepo.commit("delete file") - val lines4 = CodeLongevity(Repo(), emails, testRepo.git).getLinesList() + val lines4 = CodeLongevity(Repo(), emails, testRepo.git, + { _ -> fail("exception") }).getLinesList() it("'t4: file deletion'") { assertEquals(3, lines4.size) @@ -181,7 +186,8 @@ class CodeLongevityTest : Spek({ ) testRepo.createFile(fileName, fileContent) val rev1 = testRepo.commit("initial commit") - val lines1 = CodeLongevity(Repo(), emails, testRepo.git).getLinesList() + val lines1 = CodeLongevity(Repo(), emails, testRepo.git, + { _ -> fail("exception") }).getLinesList() it("'t2.1: initial insertion'") { assertEquals(fileContent.size, lines1.size) @@ -227,7 +233,8 @@ class CodeLongevityTest : Spek({ testRepo.insertLines(fileName, 11, listOf("Proof addition 3")) val rev2 = testRepo.commit("insert+delete") - val lines2 = CodeLongevity(Repo(), emails, testRepo.git).getLinesList() + val lines2 = CodeLongevity(Repo(), emails, testRepo.git, + { _ -> fail("exception") }).getLinesList() it("'t2.2: ins+del'") { assertEquals(22, lines2.size) @@ -299,7 +306,8 @@ class CodeLongevityTest : Spek({ testRepo.deleteLines(fileName, 2, 2) val rev3 = testRepo.commit("delete line2") - val lines1 = CodeLongevity(Repo(), emails, testRepo.git).getLinesList() + val lines1 = CodeLongevity(Repo(), emails, testRepo.git, + { _ -> fail("exception") }).getLinesList() val lines1_line15 = lines1[0] val lines1_line1 = lines1[1] val lines1_line2 = lines1[2] @@ -323,8 +331,8 @@ class CodeLongevityTest : Spek({ testRepo.deleteLines(fileName, 0, 0) val rev4 = testRepo.commit("delete line1") - val lines2 = - CodeLongevity(Repo(), emails, testRepo.git).getLinesList(rev3) + val lines2 = CodeLongevity(Repo(), emails, testRepo.git, + { _ -> fail("exception") }).getLinesList(rev3) val lines2_line1 = lines2[0] val lines2_line15 = lines2[1] @@ -367,10 +375,12 @@ class CodeLongevityTest : Spek({ val t1_rev = testRepo.commit(message = "insert line", date = Calendar.Builder().setTimeOfDay(0, 1, 0).build().time) - val t1_ages = CodeLongevity(Repo(rehash = testRehash), - emails, testRepo.git).scan()!! - val t1_lines = CodeLongevity(Repo(rehash = testRehash), - emails, testRepo.git).getLinesList() + val t1_ages = CodeLongevity( + Repo(rehash = testRehash), emails, testRepo.git, + { _ -> fail("exception") }).scan()!! + val t1_lines = CodeLongevity( + Repo(rehash = testRehash), emails, testRepo.git, + { _ -> fail("exception") }).getLinesList() it("'t1'") { assertTrue(t1_ages.aggrAges.isEmpty(), @@ -387,10 +397,12 @@ class CodeLongevityTest : Spek({ testRepo.commit(message = "delete line2", date = Calendar.Builder().setTimeOfDay(0, 3, 0).build().time) - val t2_ages = CodeLongevity(Repo(rehash = testRehash), - emails, testRepo.git).scan()!! - val t2_lines = CodeLongevity(Repo(rehash = testRehash), - emails, testRepo.git).getLinesList(t1_rev) + val t2_ages = CodeLongevity( + Repo(rehash = testRehash), emails, testRepo.git, + { _ -> fail("exception") }).scan()!! + val t2_lines = CodeLongevity( + Repo(rehash = testRehash), emails, testRepo.git, + { _ -> fail("exception") }).getLinesList(t1_rev) it("'t2'") { assertEquals(1, t2_ages.aggrAges[email]!!.count, @@ -408,8 +420,9 @@ class CodeLongevityTest : Spek({ } afterGroup { - CodeLongevity(Repo(rehash = testRehash), - emails, testRepo.git).dropSavedData() + CodeLongevity( + Repo(rehash = testRehash), emails, testRepo.git, + { _ -> fail("exception") }).dropSavedData() testRepo.destroy() } } @@ -446,7 +459,8 @@ class CodeLongevityTest : Spek({ author = author1, date = Calendar.Builder().setTimeOfDay(0, 4, 0).build().time) - CodeLongevity(serverRepo, emails, testRepo.git).updateStats(mockApi) + CodeLongevity(serverRepo, emails, testRepo.git, + { _ -> fail("exception") }).updateStats(mockApi) it("'t1'") { assertTrue(mockApi.receivedFacts.contains( @@ -464,8 +478,9 @@ class CodeLongevityTest : Spek({ } afterGroup { - CodeLongevity(Repo(rehash = testRehash), - emails, testRepo.git).dropSavedData() + CodeLongevity( + Repo(rehash = testRehash), emails, testRepo.git, + { _ -> fail("exception") }).dropSavedData() testRepo.destroy() } }