covr icon indicating copy to clipboard operation
covr copied to clipboard

add a markdown output function

Open cjyetman opened this issue 2 years ago • 3 comments

an exported function like cover::markdown_output() to print a coverage report in markdown, which could then easily be used to add either a Job Summary for a GH Action, or potentially to add a comment to a PR thread with a coverage report.

I played around making a more sophisticated markdown() function than what @jimhester suggested here. In my GH Action, I ran a coverage test on both HEAD and on MAIN and generated a markdown coverage report comparing the diff. (This is quick and dirty, but maybe of interest for ideas.)

      - name: test-coverage
         id: coverage
         run: |
           markdown_cov_diff <- function(head, main) {
             group <- "filename"
             by = "line"
             sig_num <- 2

             tally_head <- covr::tally_coverage(head, by = by)
             tally_main <- covr::tally_coverage(main, by = by)

             percs_head <- tapply(tally_head$value, tally_head[[group]], FUN = function(x) sum(x > 0) / length(x) * 100)
             percs_main <- tapply(tally_main$value, tally_main[[group]], FUN = function(x) sum(x > 0) / length(x) * 100)
             percs_diff <- unname(percs_head - percs_main)

             ttl_perc_head <- covr::percent_coverage(tally_head, by = by)
             ttl_perc_main <- covr::percent_coverage(tally_main, by = by)
             ttl_perc_diff <- ttl_perc_head - ttl_perc_main

             percs_head <- format(percs_head, digits = sig_num)
             percs_main <- format(percs_main, digits = sig_num)
             percs_diff <- paste0(ifelse(percs_diff < 0, ":small_red_triangle_down: ", ""), ifelse(percs_diff > 0, ":arrow_up: ", ""), format(percs_diff, digits = sig_num))

             ttl_perc_head <- format(ttl_perc_head, digits = sig_num)
             ttl_perc_main <- format(ttl_perc_main, digits = sig_num)
             ttl_perc_diff <- paste0(ifelse(ttl_perc_diff < 0, ":small_red_triangle_down: ", ""), ifelse(ttl_perc_diff > 0, ":arrow_up: ", ""), format(ttl_perc_diff, digits = sig_num))

             paste0(
               "<details>\n",
               "<summary>Coverage Report</summary>\n\n", 
               "|file|head|main|diff|\n|", 
               " :-- | --: | --: | --: |\n",
               paste0("|Overall|", ttl_perc_head, "%|", ttl_perc_main, "%|", ttl_perc_diff, "%|", "\n"),
               paste0("|", names(percs_head), "|", percs_head, "%|", percs_main, "%|", percs_diff, "%|", collapse = "\n"),
               "\n",
               "</details>"
             )
           }
           head <- covr::package_coverage()
           system2("git", c("checkout", "main"))
           main <- covr::package_coverage()
           writeLines(markdown_cov_diff(head, main), "coverage-report.md")
         shell: Rscript {0}

I've experimented with this a bit, and I have been successful with both.

job summary looked like this:

PR thread comment looks like: Screenshot 2022-11-30 at 17 03 30

example markdown table for a PR thread comment:

<details>
<summary>Coverage Report</summary>

|file|head|diff|
| :-- | --: | --: |
|Overall|57%|:small_red_triangle_down: -0.074%|
|R/function_one.R|91%|0.0%|
|R/function_two.R|71%|:arrow_up: 0.0%|
|R/function_three.R|94%|:small_red_triangle_down: -1.1%|
</details>

renders as:

Coverage Report
file head diff
Overall 57% :small_red_triangle_down: -0.074%
R/function_one.R 91% 0.0%
R/function_two.R 71% :arrow_up: 0.0%
R/function_three.R 94% :small_red_triangle_down: -1.1%

    @cjyetman I think that is a good idea, could you open a new issue so it doesn't get lost.

Originally posted by @jimhester in https://github.com/r-lib/covr/issues/207#issuecomment-1332325205

cjyetman avatar Nov 30 '22 15:11 cjyetman

I doubt you want to add {knitr} as a dependency for just this, but knitr::kable() can convert objects to a markdown table easily...

x <- covr::package_coverage()
coverages <- covr:::per_line(x)
overall <- covr::percent_coverage(x)
full <- lapply(coverages, function(coverage) {
  lines <- coverage$file$file_lines
  values <- coverage$coverage
  values[is.na(values)] <- ""
  data.frame(line = seq_along(lines), source = lines, coverage = values, 
             stringsAsFactors = FALSE)
})
file_stats <- covr:::compute_file_stats(full)
file_stats$File <- row.names(file_stats)
row.names(file_stats) <- NULL
cov_table <- rbind(data.frame(File = "total", Coverage = sprintf("%.2f%%", overall)), file_stats[, c("File", "Coverage")])
knitr::kable(cov_table, align = "lr")

cjyetman avatar Dec 05 '22 10:12 cjyetman

this exists in covrpage already

yonicd avatar Dec 23 '22 18:12 yonicd

Let's get this added; it seems really valuable for github actions! If a PR is requested, let me know!

shapiromatron avatar Feb 28 '24 04:02 shapiromatron