Title: | Tools for assisting with package validation within the SCTO package validation projedct of the Statistics and Methodology platform |
---|---|
Description: | The validation platform consists of three GitHub repositories, one of which hosts this package. The others host tests for specific packages, and a location to reports the results of tests and validations. This package provides tools to work with that data. |
Authors: | Alan G. Haynes [cre] |
Maintainer: | Alan G Haynes <[email protected]> |
License: | MIT |
Version: | 0.4.1 |
Built: | 2024-12-13 13:47:10 UTC |
Source: | https://github.com/SwissClinicalTrialOrganisation/SCTORvalidation_Rpackage |
These functions provide various ways to interact with github issues.
Open/update an issue:
post_issue
opens a new issue in a repository, with a defined body and title.
update_issue
updates an existing issue in a repository (could also be used
instead of add_labels
or close_issue
).
Getting issues:
get_issue
downloads a single issue from a repository.
get_issues
downloads all issues from a repository.
get_test_reports
downloads all issues from a repository, filtering those with
test labels, and converts the issue to a dataframe.
Labels:
add_label
adds a particular label to an issue.
remove_label
removes a particular label from an issue.
Comments:
get_comments
downloads all comments from an issue.
post_comment
posts a comment to an issue.
Closing an issue:
close_issue
closes an issue.
These functions are primarily for the use in github actions rather than for the standard user.
See https://docs.github.com/en/rest/issues/issues for full information.
add_label(issue, label, repo = sctoreports()) close_issue(issue, repo = sctoreports()) get_comments(issue, repo = sctoreports()) get_issue(issue, repo = sctoreports()) get_issues(repo = sctoreports()) get_test_reports(repo = sctoreports(), approved_only = FALSE) post_comment(issue, comment, repo = sctoreports()) post_issue(body, title, repo = sctoreports()) remove_label(issue, label, repo = sctoreports()) update_issue(issue, ..., repo = sctoreports())
add_label(issue, label, repo = sctoreports()) close_issue(issue, repo = sctoreports()) get_comments(issue, repo = sctoreports()) get_issue(issue, repo = sctoreports()) get_issues(repo = sctoreports()) get_test_reports(repo = sctoreports(), approved_only = FALSE) post_comment(issue, comment, repo = sctoreports()) post_issue(body, title, repo = sctoreports()) remove_label(issue, label, repo = sctoreports()) update_issue(issue, ..., repo = sctoreports())
issue |
issue number to update |
label |
label to remove |
repo |
repository name ... could be e.g. body, title, labels (should be a list), state (open or closed) see https://docs.github.com/en/rest/issues/issues?apiVersion=2022-11-28#update-an-issue |
approved_only |
only return approved packages (logical) |
comment |
the comment to be made |
body |
issue body |
title |
issue title |
... |
arguments passed to gh |
a list of comments
dataframe
# remove_label(issue = 1, label = "test") # post_comment(issue = 1, comment = "This is a test comment") # get_issue(21) # post_comment(issue = 1, comment = "This is a test comment") # post_issue("Some body text", title = "Issue title") # remove_label(issue = 1, label = "test") # post_issue("Some body text", title = "Issue title")
# remove_label(issue = 1, label = "test") # post_comment(issue = 1, comment = "This is a test comment") # get_issue(21) # post_comment(issue = 1, comment = "This is a test comment") # post_issue("Some body text", title = "Issue title") # remove_label(issue = 1, label = "test") # post_issue("Some body text", title = "Issue title")
The score is the mean of the individual scores for each question.
calculate_pkg_score(pkgs = NULL)
calculate_pkg_score(pkgs = NULL)
pkgs |
a list of package objects |
This function downloads the lists of risk assessed and tested packages from GitHub and compares them to the packages loaded in the current R session.
check_session( product_risk = c("low", "medium", "high"), attached_only = TRUE, approved_only = TRUE ) ## S3 method for class 'sctovalidity' print(x, ...)
check_session( product_risk = c("low", "medium", "high"), attached_only = TRUE, approved_only = TRUE ) ## S3 method for class 'sctovalidity' print(x, ...)
product_risk |
character vector, which product risk levels should be included in the report (default: c("low", "medium", "high")) |
attached_only |
logical, should all loaded packages be shown (FALSE; default), or only those that are attached (TRUE) |
approved_only |
logical, should only validated (approved) packages be shown (TRUE; default), or also those awaiting approval (FALSE) |
x |
output from |
... |
options passed to methods |
## Not run: check_session() ## End(Not run)
## Not run: check_session() ## End(Not run)
As any functions from high risk packages require testing for use in high risk products, it is important to know which functions are used in the code.
extract_functions_from_dir(dir, pattern = ".(r|rnw|rmd|qmd)$", ...) extract_functions_from_file(file)
extract_functions_from_dir(dir, pattern = ".(r|rnw|rmd|qmd)$", ...) extract_functions_from_file(file)
dir |
one or more directory to search for R scripts |
pattern |
pattern to match files (defaults to variations of R, Rmd, Rnw, and qmd files, ignoring case) |
... |
additional arguments to 'list.files' |
file |
file to extract functions from |
'extract_functions_from_file' extracts functions from a single file. Where the file is a markdown (Rmd or qmd) or Sweave file (Rnw), the R code is first extracted via the 'knitr::purl' function.
'extract_functions_from_dir' extracts all functions from R scripts within a directory that match a specified pattern. Specific files can be chosen via the 'pattern' argument, which accepts regular expressions. Files that match 'pattern' will be parsed for functions.
a dataframe with the function (fun) and it's parent package (package), and accessed_via indicating whether the function was accessed directly from the namespace with '::' or ':::', otherwise it is empty.
extract_functions_from_file()
: Extract functions from a file
It is important to note that functions used inside e.g. 'lapply' or 'sapply' are not considered functions by the code parser and may not be extracted unless they are also used directly elsewhere in the code (e.g. length will not be found if used within 'lapply(..., length)', but would be found if there was an additional use of the length function elsewhere - 'length(x)').
[getParseData()], [find_pkgs()]
# extract_functions_from_dir("dirname") # extract_functions_from_file("file.R")
# extract_functions_from_dir("dirname") # extract_functions_from_file("file.R")
This function takes a character vector of function names and returns a dataframe containing the package containing those functions.
find_pkgs(funs)
find_pkgs(funs)
funs |
a character vector of function names |
Objects that appear to be in the global environment will be indicated as '.GlobalEnv'. Functions that are referenced via a namespace (i.e. '::' or ':::') may not indicate a package, particularly when the package is not loaded.
Where the same function is found in multiple packages, all packages are returned. This is particularly the case where functions are re-exported by multiple packages (e.g. 'dplyr::mutate' is also exported by 'gtsummary').
Where the 'conflicted' package is used, the package that takes priority is returned.
dataframe with the function (fun) and it's parent package (package), each as strings
find_pkgs("mutate")
find_pkgs("mutate")
These functions are intended for use by a github action to generate a table for the website
This is intended for use by a github action to generate a table for the website
gen_pkg_table(pkgs = NULL, ...) gen_tests_table(tests = NULL, ...)
gen_pkg_table(pkgs = NULL, ...) gen_tests_table(tests = NULL, ...)
pkgs |
NULL or a list of issues from |
... |
options passed to |
tests |
NULL or a list of issues from |
gen_tests_table()
: Generate a table of function tests
Note: this is only available for CRAN or bioconductor packages
get_12month_downloads(package, from = Sys.Date() - 365, to = Sys.Date())
get_12month_downloads(package, from = Sys.Date() - 365, to = Sys.Date())
package |
package name |
from |
start date |
to |
end date |
integer number of downloads
get_12month_downloads("ggplot2") get_12month_downloads("secuTrialR")
get_12month_downloads("ggplot2") get_12month_downloads("secuTrialR")
Get the number of dependencies for a package
get_n_deps(package, fields = c("Depends", "Imports"), ...)
get_n_deps(package, fields = c("Depends", "Imports"), ...)
package |
package name |
fields |
list of fields to check for dependencies.
Defaults to |
... |
additional arguments passed to |
The recursive
and reverse
arguments are perhaps of most interest.
recursive
details the number of dependencies of the package, including
those that are dependencies of dependencies. reverse
details the number
of packages that depend on the package, which may be an indicator of a high
quality package. This function uses the
function from the tools package.
integer: the number of dependencies
For CRAN packages, package_dependencies
may be of interest.
## Not run: get_n_deps("nlme") get_n_deps("validation") get_n_deps("dplyr", reverse = TRUE) ## End(Not run)
## Not run: get_n_deps("nlme") get_n_deps("validation") get_n_deps("dplyr", reverse = TRUE) ## End(Not run)
This function tries to determine where a package was installed from, e.g. CRAN, GitHub, r-universe, etc. If the package comes from a git repository, it also attempts to extract the repository URL and commit hash.
get_pkg_source(pkg, ...)
get_pkg_source(pkg, ...)
pkg |
package to check the source of |
... |
parameters passed to other methods |
If the package was installed from a r-universe, the function will return the
git repository URL and commit hash of the package, rather than the r-universe
URL. E.g. this package is installed from the CTU-Bern r-universe, but the function
returns the URL of the GitHub repository
(https://github.com/SwissClinicalTrialOrganisation/validation
) and the
commit hash.
CRAN packages have a release date associated with them. This function downloads that date and returns it as a date object.
get_release_date(pkg)
get_release_date(pkg)
pkg |
a package name |
If the package does not exist on CRAN, the function asks the user to search elsewhere for the information.
character string containing either the date or a message to check elsewhere
get_release_date("dplyr")
get_release_date("dplyr")
Tests sometimes require specific datasets. Where a built-in dataset is insufficient, a dataset that exists within the SCTO validation tests repository can be downloaded.
get_test_data(dataset, repo = sctotests(), dir = getwd())
get_test_data(dataset, repo = sctotests(), dir = getwd())
dataset |
The filename of the dataset to download |
repo |
the repository to download from |
dir |
the directory to save the dataset to (purely for testing purposes - this option should not be used in everyday use) |
This function can be used in the setup-pkg.R file so that the datasets are available to the tests.
The function will download the dataset from the SCTO validation tests repository to the working directory, which testthat sets to the directory containing the test files. Therefore, the dataset can be downloaded and saved and used without referring to any other directory. The setup-pkg.R file might then contain:
... library(testthat) get_test_data("mtcars.csv") dat <- read.csv("mtcars.csv") withr::defer({})
TRUE if the dataset is downloaded successfully
# download the file to a temporary directory tempdir <- tempdir() get_test_data("mtcars.csv", dir = tempdir) dat <- read.csv(file.path(tempdir, "mtcars.csv")) unlink(tempdir) ## Not run: # within the setup-pkg.R file get_test_data("mtcars.csv") # then load the data using an appropriate function dat <- read.csv("mtcars.csv") ## End(Not run)
# download the file to a temporary directory tempdir <- tempdir() get_test_data("mtcars.csv", dir = tempdir) dat <- read.csv(file.path(tempdir, "mtcars.csv")) unlink(tempdir) ## Not run: # within the setup-pkg.R file get_test_data("mtcars.csv") # then load the data using an appropriate function dat <- read.csv("mtcars.csv") ## End(Not run)
Tests are assumed to be in a 'tests' directory in the repository.
get_tested_pkgs(repo = sctotests())
get_tested_pkgs(repo = sctotests())
repo |
repository to check for tests |
character vector of package (directory) names
get_tested_pkgs()
get_tested_pkgs()
This function downloads issues from github and extracts relevant information from them
get_valid_pkgs(approved_only = TRUE)
get_valid_pkgs(approved_only = TRUE)
approved_only |
only return approved packages (logical) |
dataframe including package, version, etc.
# only approved packages get_valid_pkgs() # all packages, regardless of status get_valid_pkgs(FALSE)
# only approved packages get_valid_pkgs() # all packages, regardless of status get_valid_pkgs(FALSE)
These functions provide a way to check whether an issue has a particular label.
is_
is the main function. The others are wrappers around this one.
is_package
checks for a package label.
is_test
checks for a test label.
is_approved
checks for an approved label.
is_triage
checks for a triage label.
get_labels
gets all labels associated with an issue.
is_(issues, what) is_package(issues) is_test(issues) is_approved(issues) is_triage(issues) get_labels(issue)
is_(issues, what) is_package(issues) is_test(issues) is_approved(issues) is_triage(issues) get_labels(issue)
issues |
a list of issues |
what |
the label to check for |
issue |
a specific issue |
# issues <- get_issues() # is_package(issues) # issue <- get_issue(21) # is_package(list(issue))
# issues <- get_issues() # is_package(issues) # issue <- get_issue(21) # is_package(list(issue))
Github contains a flat file of the package validation results. This function retrieves that file.
Github contains a flat file of the package validation results. This function retrieves that file.
load_pkg_table() load_tests_table()
load_pkg_table() load_tests_table()
load_tests_table()
: Load a dataset of test results
In order to print nicely in GitHub, tables are formatted using markdown syntax.
parse_evidence_tab(tab)
parse_evidence_tab(tab)
tab |
a string containing the markdown table |
This function can read that syntax and convert it back to a normal data frame.
a data frame
tab <- c("|file |context |test | nb| passed|skipped |error | warning|", "|:---------|:-------|:---------|--:|------:|:-------|:-----|-------:|", "|test-lm.R |lm |message 1 | 8| 4|FALSE |FALSE | 4|", "|test-lm.R |lm |message 2 | 3| 3|FALSE |FALSE | 0|") parse_evidence_tab(tab)
tab <- c("|file |context |test | nb| passed|skipped |error | warning|", "|:---------|:-------|:---------|--:|------:|:-------|:-----|-------:|", "|test-lm.R |lm |message 1 | 8| 4|FALSE |FALSE | 4|", "|test-lm.R |lm |message 2 | 3| 3|FALSE |FALSE | 0|") parse_evidence_tab(tab)
This is a function that can be used with Rmarkdown or quarto to collect the risk associated with a particular chunk. The risk level can then be tabulated towards the end of the document to give an overview of the risk associated with the product.
risk_hook(options, before)
risk_hook(options, before)
options |
chunk options |
before |
whether the hook is called before or after the chunk (only before does anything) |
# in e.g. setup chunk knitr::knit_hooks$set(risk = SCTORvalidation::risk_hook) RISKENV <- new.env() # as a chunk option #```{r highriskchunk, echo=FALSE, risk = "high"} #```{r mediumriskchunk, echo=FALSE, risk = "medium"} #```{r lowriskchunk, echo=FALSE, risk = "low"} # towards the end of the script, tabulate RISKENV$chunk_risk for an overview
# in e.g. setup chunk knitr::knit_hooks$set(risk = SCTORvalidation::risk_hook) RISKENV <- new.env() # as a chunk option #```{r highriskchunk, echo=FALSE, risk = "high"} #```{r mediumriskchunk, echo=FALSE, risk = "medium"} #```{r lowriskchunk, echo=FALSE, risk = "low"} # towards the end of the script, tabulate RISKENV$chunk_risk for an overview
shortcuts for the SCTO package validation repositories. The validation platform consists of 3 repositories: a repository for reporting the validations (pkg_validation), one which contains tests for specific packages (validation_tests), and one for this package itself (validation). These three functions provide the names of the three repositories.
sctoreports() sctotests() sctopkg()
sctoreports() sctotests() sctopkg()
the repository name (validation)
This function runs all predefined tests for a given package.
test( pkg, download = TRUE, cleanup = FALSE, dir = getwd(), repo = sctotests(), testthat_colours = TRUE ) ## S3 method for class 'validate_result' print(x, ...)
test( pkg, download = TRUE, cleanup = FALSE, dir = getwd(), repo = sctotests(), testthat_colours = TRUE ) ## S3 method for class 'validate_result' print(x, ...)
pkg |
package name as a string |
download |
whether to download a fresh set of tests |
cleanup |
whether to delete testing folder |
dir |
directory to download tests to. This should have |
repo |
storing the tests |
testthat_colours |
include coloured testthat output (the colours are implemented as particular characters in the output, which make it harder to read in some circumstances) |
x |
a validate_result object (the output from 'test') |
... |
additional arguments (not used) |
The print method supports the creation of a new issue in the package's repository by presenting the information in a format that can be copied and pasted in the issue template.
Object of class validate_result
if(FALSE) test("stats")
if(FALSE) test("stats")
This function will create the directory if it does not exist, and add a 'info.txt' file with the package name, and a 'setup-pkg.R' file with the necessary setup code.
test_skeleton(pkg, funs, dir = getwd())
test_skeleton(pkg, funs, dir = getwd())
pkg |
package to be tested |
funs |
functions to be tested |
dir |
where to save the tests/skeleton |
a set of files in your working directory, which can be edited and uploaded to github
# test_skeleton(pkg = "dplyr", funs = c("select", "filter"))
# test_skeleton(pkg = "dplyr", funs = c("select", "filter"))
Convert a test result object to a text string for posting to GitHub
test_to_text(x)
test_to_text(x)
x |
test result object |
a list of character strings
# texts <- test_to_text(x) # issue <- post_issue(texts$issue_body, texts$issue_title) # map(texts$issue_tags, ~ add_label(issue$number, .x))
# texts <- test_to_text(x) # issue <- post_issue(texts$issue_body, texts$issue_title) # map(texts$issue_tags, ~ add_label(issue$number, .x))
Where an issue is already in the table, the new data will replace the old data.
Where a package version is already in the table, the new data will replace the old data.
update_pkg_table(...) update_tests_table(...)
update_pkg_table(...) update_tests_table(...)
... |
options passed to gen_pkg_table e.g. a list of issues from get_pkgs |
update_tests_table()
: Append new test data to existing tests table
# update_pkg_table()
# update_pkg_table()
These functions validate the inputs from package or function tests.
Both functions return a list with two elements - an indicator of whether the validation passed without any errors and a character indicating what the error(s) was/were. The character string is formated as if it were a comment to a GitHub issue.
The functions are not intended to be used directly by the user, but are called by a github action with the results posted as a comment to github.
'validate_pkg_issue' checks the values from a package issue.
'validate_test_issue' checks the values from a function test issue.
validate_pkg_issue(score) validate_test_issue(issue)
validate_pkg_issue(score) validate_test_issue(issue)
score |
the output from calculate_pkg_score for a single package |
issue |
a single function test issue |
list wit two elements: score_ok (logical) and message (character)
list wit two elements: ok (logical) and message (character)