Skip to content

Commit

Permalink
Updated the md text report template for uploading as a comment with s…
Browse files Browse the repository at this point in the history
…uccess and failure cases
  • Loading branch information
Rd4dev committed Jul 9, 2024
1 parent 3ed5595 commit dd918ea
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 25 deletions.
4 changes: 0 additions & 4 deletions scripts/assets/test_file_exemptions.textproto
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ test_file_exemption {
exempted_file_path: "utility/src/main/java/org/oppia/android/util/parser/math/MathModel.kt"
override_min_coverage_percent_required: 388
}
test_file_exemption {
exempted_file_path: "utility/src/main/java/org/oppia/android/util/parser/math/MathModel2.kt"
override_min_coverage_percent_required: 24
}
test_file_exemption {
exempted_file_path: "app/src/main/java/org/oppia/android/app/activity/ActivityComponent.kt"
test_file_not_required: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,11 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor:
fun runCoverageForTestTarget(bazelTestTarget: String): List<String>? {
val instrumentation = bazelTestTarget.split(":")[0]
val computeInstrumentation = instrumentation.split("/").let { "//${it[2]}/..." }
println("In computing coverage for test in bazel client for $bazelTestTarget")
val coverageCommandOutputLines = executeBazelCommand(
"coverage",
bazelTestTarget,
"--instrumentation_filter=$computeInstrumentation"
)
println("After computing coverage for test in bazel client for $bazelTestTarget")
return parseCoverageDataFilePath(coverageCommandOutputLines)?.let { path ->
File(path).readLines()
}
Expand All @@ -162,7 +160,7 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor:
val match = regex.find(line)
val extractedPath = match?.value?.substringAfterLast(",")?.trim()
if (extractedPath != null) {
println("Raw Coverage Data: $extractedPath")
// println("Raw Coverage Data: $extractedPath")
return extractedPath
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,19 @@ class CoverageReporter(
* and the second value is the generated report text
*/
fun generateRichTextReport(): Pair<Float, String> {
println("Report format: $reportFormat")
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()
Expand Down Expand Up @@ -69,15 +81,38 @@ class CoverageReporter(
* <li><b>Lines Coverage</b>: 19/19 covered
* </ul>
* </details>
*/
val markdownContent =
"""
## Coverage Report
*
* Sample template for reference:
* |Covered File|Percentage|Line Coverage|Status|
|-------------|:----------:|:---------------:|:------:|
|[HomeActivity.kt](https://www.github.com)|53.00%|4/7 lines|:x:|
- **Covered File:** $filePath
- **Coverage percentage:** $formattedCoveragePercentage% covered
- **Line coverage:** $totalLinesHit / $totalLinesFound lines covered
""".trimIndent()
# 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" +
"|$formattedCoveragePercentage%" +
"|$totalLinesHit / $totalLinesFound"

println("\n$markdownContent")

Expand Down Expand Up @@ -249,6 +284,23 @@ class CoverageReporter(
0f
}
}

private fun logCoverageReport() {
// TODO: (remove) as this looks un even in the output log
val logReportText = listOf(
"Covered File: $filePath",
"Coverage percentage: $formattedCoveragePercentage% covered",
"Line coverage: $totalLinesHit / $totalLinesFound lines covered"
)

val maxLength = logReportText.maxOf {it.length}
val horizontalBorder = "+-${"-".repeat(maxLength)}-+"
val reportText = logReportText.joinToString(separator = "\n") { line ->
"| ${line.padEnd(maxLength)} |"
}

println("$horizontalBorder\n$reportText\n$horizontalBorder")
}
}

/** Represents the different types of formats available to generate code coverage reports. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ class CoverageRunner(
bazelTestTarget: String
): Deferred<CoverageReport> {
return CoroutineScope(scriptBgDispatcher).async {
println("$bazelTestTarget start: ${LocalDateTime.now()} on thread: ${Thread.currentThread().name}")
// 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}")
// println("$bazelTestTarget end: ${LocalDateTime.now()} on thread: ${Thread.currentThread().name}")

coverageDataFileLines(coverageResult, bazelTestTarget)
}
Expand Down
77 changes: 70 additions & 7 deletions scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ fun main(vararg args: String) {
?.uppercase() ?: "MARKDOWN"

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

println("Coverage Results: $coverageResults")
println("COVERAGE ANALYSIS COMPLETED.")
if (reportFormat == ReportFormat.MARKDOWN) generateFinalMdReport(coverageResults)

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

private suspend fun runCoverageForFile(filePath: String): String {
Expand All @@ -160,6 +163,7 @@ 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.
coverageReports.firstOrNull()?.let {
if (!it.isGenerated) {
return "Failed to generate coverage report for the file: $filePath.".also {
Expand All @@ -170,21 +174,25 @@ class RunCoverage(

val aggregatedCoverageReport = calculateAggregateCoverageReport(coverageReports)
val reporter = CoverageReporter(repoRoot, aggregatedCoverageReport, reportFormat)
val (computedCoverageRatio, reportText) = reporter.generateRichTextReport()
var (computedCoverageRatio, reportText) = reporter.generateRichTextReport()

val coverageCheckThreshold = exemption?.overrideMinCoveragePercentRequired ?: MIN_THRESHOLD

println("**************************Coverage threshold : $coverageCheckThreshold")
if (computedCoverageRatio*100 < coverageCheckThreshold) coverageCheckState = CoverageCheck.FAIL
println("***************Coverage check state: $coverageCheckState")
// 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()
writeText(reportText)
}

if (File(reportOutputPath).exists()) {
println("\nComputed Coverage Ratio is: $computedCoverageRatio")
println("\nGenerated report at: $reportOutputPath\n")
}

Expand All @@ -198,6 +206,61 @@ class RunCoverage(
}
}

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"

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 exemptedCases = coverageResults.filterNot { it.contains("|") }

val coverageFailuresRows = coverageFailures.joinToString(separator = "\n")
val coverageSuccessesRows = coverageSuccesses.joinToString(separator = "\n")

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 successMarkdownTable = "<details>\n" +
"<summary>Succeeded Coverages</summary>\n\n" +
coverageTableHeader +
coverageSuccessesRows +
"\n</details>"

val exemptedCasesList = exemptedCases.joinToString(separator = "\n") { "- $it" }

val finalReportText = failureMarkdownTable + "\n\n" + successMarkdownTable + "\n\n" + "### Exempted Cases\n" + exemptedCasesList
/*
println("""
## Coverage Report
$coverageResults
""".trimIndent())
*/

println(finalReportText)
}

private fun calculateAggregateCoverageReport(
coverageReports: List<CoverageReport>
): CoverageReport {
Expand Down

0 comments on commit dd918ea

Please sign in to comment.