Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fileSummary function #131

Merged
merged 5 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export(diffFiles)
export(diffPreviousRevisions)
export(diffQced)
export(dirSummary)
export(fileSummary)
export(getQcedRevision)
export(logAccept)
export(logAssign)
Expand Down
143 changes: 143 additions & 0 deletions R/fileSummary.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#' Summarize revision and QC history for a file
#'
#' @description
#' Generates a comprehensive summary of the revision and quality control (QC) history
#' for a file. The function reports:
#' * QC status (up to date, needs QC, or not assigned)
#' * Presence in the QC log
#' * Historical information about previous authors
#' * Historical information about previous QC reviewers
#'
#' @param .file File path.
#'
#' @details
#' The function prints a formatted summary to the console and invisibly returns
#' the data for programmatic use. Non-existent files generate warnings and are
#' skipped. Files not found in the repository history are also skipped.
#'
#' QC status can be:
#' * "QC up to date" - Latest revision has been QC'd
#' * "Needs QC" - New changes need review
#' * "Not assigned" - File not in QC system
#'
#' @examples
#' \dontrun{
#' # Analyze a single script file
#' fileSummary("script/data-assembly/study-101.R")
#'
#' # Process all files in a directory
#' purrr::walk(list.files("script/data-assembly", full.names = TRUE), ~ fileSummary(.file = .x))
#' }
#'
#' @export
fileSummary <- function(.file) {
if (length(.file) != 1) {
stop("'.file' must be a single file path")
}

if (!file.exists(.file)) {
warning(paste0(.file, " does not exist"))
return(invisible(NULL))
}

# Initialize output list
out <- list()
out$qclog <- cli::col_red("No")
out$qcstatus <- cli::col_magenta("Not assigned")
out$prevQC <- "No previous QC"

# Get repo history and QC log
file_history <- repoHistory()
qc_log <- logRead()

# Get repo commit history for the file
script_history <- file_history[file_history$file == .file, ]

if (nrow(script_history) == 0) {
warning(paste0(.file, " has no svn history"))
return(invisible(NULL))
}

# Get last revision of the file
last_rev <- as.numeric(script_history$rev[1])

# Filter QC log to file of interest
qc_file <- qc_log[qc_log$file == .file, ]

# Check if file is in QC log
if (nrow(qc_file) > 0) {

out$qclog <- cli::col_green("Yes")

# Process QC history
qc_file_filtered <- qc_file %>% dplyr::filter(revf != 0)

# For cases where no QC has been previously completed
if (nrow(qc_file_filtered) == 0) {

out$qcstatus <- cli::col_red("Needs QC")

} else {

qc_rev <-
qc_file_filtered %>%
dplyr::arrange(-as.numeric(revf)) %>%
dplyr::slice(1) %>%
dplyr::pull(revf) %>%
as.numeric()

out$prevQC <-
qc_file_filtered %>%
dplyr::arrange(-as.numeric(revf)) %>%
dplyr::group_by(reviewer) %>%
dplyr::slice(1) %>%
dplyr::ungroup() %>%
dplyr::transmute(VALUE = paste0(
reviewer, ", ",
as.numeric(difftime(Sys.Date(), as.Date(time), units = "days")),
" days ago"
)) %>%
dplyr::pull()

out$qcstatus <-
ifelse(
last_rev > qc_rev,
cli::col_red("Needs QC"),
cli::col_green("QC up to date")
)

}

}

# Process author history
out$authors <-
script_history %>%
dplyr::group_by(author) %>%
dplyr::slice(1) %>%
dplyr::ungroup() %>%
dplyr::arrange(-as.numeric(rev)) %>%
dplyr::transmute(VALUE = paste0(
author, ", ",
as.numeric(difftime(Sys.Date(), date, units = "days")),
" days ago"
)) %>%
dplyr::pull()

# Print summary
cli::cli_h2(glue::glue(.file, " summary"))
cli::cli_inform(glue::glue("In QC log: ", out$qclog))
cli::cli_inform(glue::glue("QC status: ", out$qcstatus))

cli::cli_verbatim("") # line break
cli::cli_inform("Previous QCer(s): ")
names(out$prevQC) <- rep(">", length(out$prevQC))
cli::cli_bullets(out$prevQC)

cli::cli_verbatim("") # line break
cli::cli_inform("Previous author(s): ")
names(out$authors) <- rep(">", length(out$authors))
cli::cli_bullets(out$authors)

return(invisible(out))
}
3 changes: 2 additions & 1 deletion R/reviewPackage.R
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ globalVariables(
"commit",
"name",
"value",
"paths"
"paths",
"time"
)
)
1 change: 1 addition & 0 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ reference:
- renderQCSummary
- compareFigures
- compareTables
- fileSummary
- title: SVN Tools
desc: Easily access information about SVN repos
contents:
Expand Down
43 changes: 43 additions & 0 deletions man/fileSummary.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion tests/testthat/test-dirSummary.R
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,3 @@ dirSummaryResDir <- dirSummary()
test_that("dirSummary works in a directory other than log root", {
expect_identical(dirSummaryRes, dirSummaryResDir)
})

32 changes: 32 additions & 0 deletions tests/testthat/test-fileSummary.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
create_test_svn()
logAccept("script/data-assembly/da-functions.R")
logAssign("script/model-summary.Rmd")

test_that("Function requires single file input", {
da_files <- list.files("script/data-assembly", full.names = TRUE)
expect_error(fileSummary(da_files), "must be a single file path")
})

test_that("Works correctly for a single file QC filed", {
da_functions <- fileSummary("script/data-assembly/da-functions.R")

expect_true(grepl("Yes", as.character(da_functions$qclog)))
expect_true(grepl("0 days ago", as.character(da_functions$prevQC)))
expect_true(grepl("QC up to date", as.character(da_functions$qcstatus)))
})

test_that("Output structure is correct for non QCed file", {
da_study_abc <- fileSummary("script/data-assembly/da-study-abc.Rmd")

expect_true(grepl("No", as.character(da_study_abc$qclog)))
expect_true(grepl("No previous QC", as.character(da_study_abc$prevQC)))
expect_true(grepl("Not assigned", as.character(da_study_abc$qcstatus)))
})

test_that("Function handles non-existent files appropriately", {
expect_warning(
non_nonexistent <- fileSummary("nonexistent-file.R"),
"does not exist"
)
expect_null(non_nonexistent)
})
Loading