Skip to content

Commit

Permalink
Updated MD report template, cleanups and refactorings
Browse files Browse the repository at this point in the history
  • Loading branch information
Rd4dev committed Jul 10, 2024
1 parent dd918ea commit b814d15
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 142 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,88 +34,17 @@ class CoverageReporter(
fun generateRichTextReport(): Pair<Float, String> {
logCoverageReport()

// Rough
/* If HTML -> HTML report -> send reportText -> Done
* If MD -> generate report() -> send reportText ("file.kt, 23%, 2/4 lines, :x:")
* oh wait no... the last one is decided also based on exemption
* so after coverageCheckThreshold -> determine coverage status ->
* set coverage status to PASS or FAIL
* reportText += " > :tick: ; < :wrong:"
*
* In execute after awaitAll -> check MD -> generateMD report
* */

return when (reportFormat) {
ReportFormat.MARKDOWN -> generateMarkdownReport()
ReportFormat.HTML -> generateHtmlReport()
}
}

private fun generateMarkdownReport(): Pair<Float, String> {
// TODO: (remove)
/*Thinking of alternating or having 2 versions
* one for just printing to the console
* two an actual md template with dropdowns as discussed in meeting
*
* Adding the meeting template for reference here
* Total coverage:
* Files covered: (# changed / # run with coverage)
* Coverage percentage: ##% covered / ##% expected
* LOC: # covered / # instrumented
*
* (indent left) Specific coverage:
* app/src/.../app
* home
* HomeActivity.kt - 87% (110/115)
* ...
* ...
*
* ### Coverage Report
* <details>
* <summary>MathModel.kt - 100%</summary>
* <ul>
* <li><b>Covered File:</b> <a href="https://github.com/oppia/oppia-android/blob/develop/utility/src/main/java/org/oppia/android/util/parser/math/MathModel.kt">
* utility/src/main/java/org/oppia/android/util/parser/math/MathModel.kt</a>
* </li>
* <li><b>Coverage Percentage</b>: 100%
* <li><b>Lines Coverage</b>: 19/19 covered
* </ul>
* </details>
*
* Sample template for reference:
* |Covered File|Percentage|Line Coverage|Status|
|-------------|:----------:|:---------------:|:------:|
|[HomeActivity.kt](https://www.github.com)|53.00%|4/7 lines|:x:|
# Coverage Report
## Failed Coverage
| File Path | Coverage Percentage | Line Coverage |
|-------------------------------|----------------------|-------------------|
| src/main/file1.kt | 45.00% | 90/200 lines |
| src/main/file2.kt | 50.50% | 101/200 lines |
| src/main/really_long_file_name.kt | 60.00% | 120/200 lines |
<details>
<summary>Success Coverage</summary>
| File Path | Coverage Percentage | Line Coverage |Status
|-------------------------------|:----------------------:|-------------------|:------:|
| src/main/file3.kt | 85.00% | 170/200 lines |:white_check_mark:|
| src/main/file4.kt | 90.50% | 181/200 lines |:white_check_mark:|
| src/main/file5.kt | 95.00% | 190/200 lines |:x:|
</details>
*/
val markdownContent = "|$filePath" +
val markdownContent = "|${getFilenameAsLink(filePath)}" +
"|$formattedCoveragePercentage%" +
"|$totalLinesHit / $totalLinesFound"

println("\n$markdownContent")

return Pair(computedCoverageRatio, markdownContent)
}

Expand Down Expand Up @@ -278,11 +207,9 @@ class CoverageReporter(
}

private fun computeCoverageRatio(): Float {
return if (coverageReport.linesFound != 0) {
coverageReport.linesHit.toFloat() / coverageReport.linesFound.toFloat()
} else {
0f
}
return coverageReport.linesFound.takeIf { it != 0 }?.let {
coverageReport.linesHit.toFloat() / it.toFloat()
} ?: 0f
}

private fun logCoverageReport() {
Expand All @@ -303,6 +230,12 @@ class CoverageReporter(
}
}

private fun getFilenameAsLink(filePath: String): String {
val filename = filePath.substringAfterLast("/").trim()
val filenameAsLink = "[$filename](https://github.com/oppia/oppia-android/tree/develop/$filePath)"
return filenameAsLink
}

/** Represents the different types of formats available to generate code coverage reports. */
enum class ReportFormat {
/** Indicates that the report should be formatted in .md format. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package org.oppia.android.scripts.coverage
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import org.oppia.android.scripts.common.BazelClient
import org.oppia.android.scripts.common.CommandExecutor
import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher
Expand All @@ -14,7 +13,6 @@ import java.io.File
import java.nio.file.Files
import java.nio.file.Paths
import java.security.MessageDigest
import java.time.LocalDateTime

/**
* Class responsible for running coverage analysis asynchronously.
Expand All @@ -40,12 +38,9 @@ class CoverageRunner(
bazelTestTarget: String
): Deferred<CoverageReport> {
return CoroutineScope(scriptBgDispatcher).async {
// println("$bazelTestTarget start: ${LocalDateTime.now()} on thread: ${Thread.currentThread().name}")
val coverageResult = retrieveCoverageResult(bazelTestTarget)
?: return@async generateFailedCoverageReport()

// println("$bazelTestTarget end: ${LocalDateTime.now()} on thread: ${Thread.currentThread().name}")

coverageDataFileLines(coverageResult, bazelTestTarget)
}
}
Expand Down
100 changes: 40 additions & 60 deletions scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import java.util.concurrent.TimeUnit
fun main(vararg args: String) {
val repoRoot = args[0]
val filePath = args[1]
println("FilePath = $filePath")
println("File Path: $filePath")

//TODO: once the file list is received (git client), it need to be filtered to just have
// .kt files and also not Test.kt files
Expand All @@ -48,16 +48,14 @@ fun main(vararg args: String) {
"utility/src/main/java/org/oppia/android/util/math/NumericExpressionEvaluator.kt",
"utility/src/main/java/org/oppia/android/util/math/MathTokenizer.kt",
"utility/src/main/java/org/oppia/android/util/math/RealExtensions.kt",
// "utility/src/main/java/org/oppia/android/util/logging/ConsoleLogger.kt",
// "domain/src/main/java/org/oppia/android/domain/auth/FirebaseAuthWrapperImpl.kt"
)

val format = args.find { it.startsWith("format=", ignoreCase = true) }
?.substringAfter("=")
?.uppercase() ?: "MARKDOWN"

val reportFormat = when (format) {
// TODO: (default to HTML) as it would be much simpler for local development
// TODO: (default to HTML) as that would be much simpler for local development
"HTML" -> ReportFormat.HTML
"MARKDOWN" -> ReportFormat.MARKDOWN
else -> throw IllegalArgumentException("Unsupported report format: $format")
Expand Down Expand Up @@ -115,7 +113,7 @@ class RunCoverage(
.associateBy { it.exemptedFilePath }
}

private val MIN_THRESHOLD = 10 // Example threshold, yet to be decided on a value
private val MIN_THRESHOLD = 10 // TODO: (to be decided) min threshold, yet to be decided on a value
private var coverageCheckState = CoverageCheck.PASS

/**
Expand All @@ -135,7 +133,6 @@ class RunCoverage(

if (reportFormat == ReportFormat.MARKDOWN) generateFinalMdReport(coverageResults)

// println("Coverage Results: $coverageResults")
println("\nCOVERAGE ANALYSIS COMPLETED.")
}

Expand All @@ -162,8 +159,8 @@ class RunCoverage(

val coverageReports = deferredCoverageReports.awaitAll()

// Check if the coverage reports are successfully generated else return failure message.
// TODO: (yet to decide) if this too needs to be set as coverage state -> FAIL.
// Check if the coverage reports are successfully generated else return failure message.
coverageReports.firstOrNull()?.let {
if (!it.isGenerated) {
return "Failed to generate coverage report for the file: $filePath.".also {
Expand All @@ -176,16 +173,15 @@ class RunCoverage(
val reporter = CoverageReporter(repoRoot, aggregatedCoverageReport, reportFormat)
var (computedCoverageRatio, reportText) = reporter.generateRichTextReport()

val coverageCheckThreshold = exemption?.overrideMinCoveragePercentRequired ?: MIN_THRESHOLD
val coverageCheckThreshold = exemption?.overrideMinCoveragePercentRequired
?: MIN_THRESHOLD

// println("**************************Coverage threshold : $coverageCheckThreshold")
if (computedCoverageRatio*100 < coverageCheckThreshold) {
coverageCheckState = CoverageCheck.FAIL
reportText += "|:x:|"
} else {
reportText += "|:white_check_mark:|"
}
// println("***************Coverage check state: $coverageCheckState")

File(reportOutputPath).apply {
parentFile?.mkdirs()
Expand All @@ -200,65 +196,49 @@ class RunCoverage(
}
}

private enum class CoverageCheck {
PASS,
FAIL
}
}

private fun generateFinalMdReport(coverageResults: List<String>) {
/*val coverageTableHeader = "| Covered File | Percentage | Line Coverage | Status |\n" +
"|--------------|------------|---------------|--------|\n"
println("Coverage table header: $coverageTableHeader")
*//*val coverageFailures = coverageResults.map { result ->
result.split("|").fil{it}
}*//*
println(coverageResults[0].split("|")[4])
println("Coverage Failures: $coverageResults")*/

val coverageTableHeader = "| Covered File | Percentage | Line Coverage | Status |\n" +
"|--------------|------------|---------------|--------|\n"
private fun generateFinalMdReport(coverageResults: List<String>) {
val coverageTableHeader = "| Covered File | Percentage | Line Coverage | Status |\n" +
"|--------------|------------|---------------|--------|\n"

val coverageFailures = coverageResults.filter { result ->
result.contains("|") && result.split("|")[4].trim() == ":x:"
}

val coverageSuccesses = coverageResults.filter { result ->
result.contains("|") && result.split("|")[4].trim() == ":white_check_mark:"
}
val coverageFailures = coverageResults.filter { result ->
result.contains("|") && result.split("|")[4].trim() == ":x:"
}

val exemptedCases = coverageResults.filterNot { it.contains("|") }
val coverageSuccesses = coverageResults.filter { result ->
result.contains("|") && result.split("|")[4].trim() == ":white_check_mark:"
}

val coverageFailuresRows = coverageFailures.joinToString(separator = "\n")
val coverageSuccessesRows = coverageSuccesses.joinToString(separator = "\n")
val anamolyCases = coverageResults.filterNot { it.contains("|") }

val failureMarkdownTable = "## Coverage Report\n\n" +
"Total covered files: ${coverageResults.size}\n" +
"Coverage Status: FAIL\n" +
"Min Coverage Required: 10%\n\n" + // make use of MIN_THRESHOLD
coverageTableHeader +
coverageFailuresRows
val coverageFailuresRows = coverageFailures.joinToString(separator = "\n")
val coverageSuccessesRows = coverageSuccesses.joinToString(separator = "\n")

val successMarkdownTable = "<details>\n" +
"<summary>Succeeded Coverages</summary>\n\n" +
coverageTableHeader +
coverageSuccessesRows +
"\n</details>"
val failureMarkdownTable = "## Coverage Report\n\n" +
"- Total covered files: ${coverageResults.size}\n" +
"- Coverage Status: **$coverageCheckState**\n" +
"- Min Coverage Required: $MIN_THRESHOLD%\n\n" +
coverageTableHeader +
coverageFailuresRows

val exemptedCasesList = exemptedCases.joinToString(separator = "\n") { "- $it" }
val successMarkdownTable = "<details>\n" +
"<summary>Succeeded Coverages</summary><br>\n\n" +
coverageTableHeader +
coverageSuccessesRows +
"\n</details>"

val finalReportText = failureMarkdownTable + "\n\n" + successMarkdownTable + "\n\n" + "### Exempted Cases\n" + exemptedCasesList
/*
val anamolyCasesList = anamolyCases.joinToString(separator = "\n") { "- $it" }
val finalReportText = failureMarkdownTable +
"\n\n" + successMarkdownTable +
"\n\n" + "### Anamoly Cases\n" +
anamolyCasesList

println("""
## Coverage Report
$coverageResults
""".trimIndent())
*/
println(finalReportText)
}

println(finalReportText)
private enum class CoverageCheck {
PASS,
FAIL
}
}

private fun calculateAggregateCoverageReport(
Expand Down

0 comments on commit b814d15

Please sign in to comment.