36 Checking Local Files with repo_check and code_check
36.1 Overview
Metacheck has two modules that work together to check research code:
repo_checklists all files in a repository and checks for basic organisational quality: is there a README? Are there archives whose contents cannot be listed? Do the file names follow good practice, and are there files that do not belong in a repository? How many code, data, and other files are there?code_checkreads the actual code files and checks them for best-practice issues: comments, absolute file paths,setwd()andinstall.packages()calls, grouped library loading, missing data files, code that cannot be parsed, and whether the package versions are recorded.
Normally both modules fetch files automatically from online repositories (OSF, GitHub, GitLab, ResearchBox, Zenodo, Dataverse, Figshare, Dryad, and several others — see Repository Check for the full list) by following links found in a paper. This vignette shows how to point them at a local folder instead — useful when:
- you want to check your own code before sharing it
- you are reviewing a paper whose files were sent as a zip attachment
- you downloaded a repository’s files yourself, or the authors used a repository service Metacheck does not support automatically
If you just want a report on a folder — no manuscript involved — report_repository() wraps the pattern this chapter walks through by hand: give it a path, and it runs repo_check, code_check, data_check, and codebook_check on it and writes a report named after the folder. See Downloading OSF files to check locally below for an example, and Creating a Report for the full function reference.
Metacheck’s website checks a local folder too: under Run Metacheck on a Repository, choose the folder or a .zip file, and it runs repo_check, code_check, and data_check, and can also run the R and Python code. The folder is then uploaded to the server, which deletes it once it has been read. To keep files on your own computer, for example files sent to you for review, use the Docker installation, which offers the same website locally.
36.2 Before you start
Load the package and note the path format for your operating system:
| Operating system | Example path |
|---|---|
| Windows | "C:/Users/researcher/Documents/my_study" |
| macOS / Linux | "/Users/researcher/Documents/my_study" |
Both forward slashes / and backslashes \\ work on Windows inside R.
When you provide a local path, the folder is treated as a repository in exactly the same way as an OSF project or GitHub repo. Each folder is a repository of its own, named by its path in the repo_url column of the file table. The summary table has one row per paper, however many folders you check, and the module gives one traffic light for all of them together.
36.3 Part 1: repo_check on local files
36.3.1 What repo_check checks
For each folder you provide, repo_check will:
- List all files and classify them by type (code, data, archive, readme, …)
- Check for a README — a README file is good practice and helps others understand the contents of a folder
-
Look inside zip archives — the files inside a
.zipfile are listed in place of the archive. Other archive formats, such as.7z,.raror.tar.gz, cannot be listed this way, sorepo_checkflags them and recommends.zip - Check file names — for example names or paths that are too long, or characters that cause problems on some computers
-
Flag files that do not belong in a repository — files that software creates by itself, such as
.DS_Store,.Rhistoryor editor backups, and version-control or editor folders such as.git/. They are left out of the file list and named in the report - Report counts — how many code files, data files, and so on
The traffic light is "red" when the folder holds files that software creates by itself (such as .DS_Store or .Rhistory). It is "green" when every repository has a README, no archive is left that could not be listed, every file could be classified, no file name breaks a naming rule, there are no version-control or editor folders, every repository could be read, and (when there is a manuscript) the studies it names match how the files are grouped. Otherwise it is "yellow".
36.3.2 Checking a single folder
repo <- module_run(test_paper(), "repo_check",
local_path = "C:/projects/reaction_time_study_2024")
# Plain-text summary
repo$summary_text
# Summary counts (one row per paper)
repo$summary_table
# "green", "yellow" or "red"
repo$traffic_light
# Full file list — one row per file, with file_type and file_size columns
repo$tabletest_paper() creates a minimal paper object with no repository links. The module pipeline always requires a paper argument, but when you are only checking a local folder there is no manuscript — test_paper() gives you a valid object that causes the online repository search to find nothing, so only the local files are checked.
Note on cloud-sync folders (OneDrive, iCloud, Dropbox): If the folder is stored online and files have not been downloaded locally, the check will be slow because each code file triggers a download when it is read. Before running, right-click the folder in your file browser and choose “Always keep on this device” (OneDrive) or “Download Now” (iCloud) to make all files available locally first.
A typical $summary_text when the folder is missing a README might look like:
- We found 8 files in 1 repository.
- We found 0 README files and 1 repository without READMEs.
And $summary_table will have columns: paper_id, repo_n, repo_unchecked, files_n, files_data, files_code, files_readme, files_zip, files_unknown, naming_issues, roster_mismatch.
36.3.3 Checking multiple folders
Pass a vector of paths to check several folders at once. Each is treated as a separate repository. The summary table still has one row, for the one paper, with repo_n counting the folders; the file table names each file’s folder in repo_url:
paths <- c(
"C:/projects/study_1_power_analysis",
"C:/projects/study_2_replication",
"C:/projects/study_3_meta_analysis"
)
repo <- module_run(test_paper(), "repo_check", local_path = paths)
# One row, with repo_n = 3
repo$summary_table
# All files from all three folders, with repo_url identifying the source
repo$table
# Number of files of each type (code, data, readme, ...) per folder
table(repo$table$repo_url, repo$table$file_type)This is a quick way to compare whether several projects all have READMEs and no archives that cannot be listed before you submit or share them.
36.4 Part 2: code_check on local files
36.4.1 What code_check checks
code_check builds on repo_check: it first runs the file inventory, then reads every code file (R, Rmd, Qmd, Python and Jupyter notebooks, SAS, SPSS, Stata, Mplus, and MATLAB; JASP files are counted but not read) and checks for:
- Comments — is the code explained? A file with no comment lines at all is flagged.
-
Absolute paths — paths like
C:/myname/files/data.csvonly work on one specific computer and will break for anyone else trying to reproduce the analysis. -
setwd()andinstall.packages()calls —setwd()ties the script to one computer’s folders, andinstall.packages()installs software on the computer of whoever runs the script, without asking. -
Library loading — are all
library()/require()calls grouped together near the top of the script, or are they scattered throughout? -
Missing data files — if the script loads
read.csv("data.csv")butdata.csvis not in the folder, that is flagged. -
Parsing — can the R code (
.R,.Rmd,.qmd) be read without syntax errors? -
Recorded package versions — is there an
renv.lockfile, asessionInfo()record, or agroundhog/checkpointcall for R code, and a package list such asrequirements.txtfor Python code?
36.4.2 Checking your own code
You have finished a project and want to review the quality of your scripts before sharing:
result <- module_run(test_paper(), "code_check",
local_path = "C:/projects/reaction_time_study_2024")
# Short summary of all findings
result$summary_text
# One row per code file with detailed metrics
result$table
# "green" (no issues), "yellow" (some issues), or "na" (no code files read)
result$traffic_light
# Full formatted report
result$reportNote on cloud-sync folders: If your files are on OneDrive, iCloud, or another cloud-sync service and are not fully downloaded, the check will be slow, because every file has to be downloaded when it is read; Metacheck does not warn you about this. Right-click the folder and choose “Always keep on this device” (OneDrive) or “Download Now” (iCloud) before running the check.
36.4.3 Checking multiple projects
paths <- c(
"C:/projects/study_1_power_analysis",
"C:/projects/study_2_replication",
"C:/projects/study_3_meta_analysis"
)
result <- module_run(test_paper(), "code_check", local_path = paths)
result$summary_text
# Filter to one folder using dplyr
library(dplyr)
result$table |>
filter(grepl("study_2", repo_url)) |>
select(file_name, percentage_comment, code_abs_path, loaded_files_missing)The repo_url column contains the folder path, so you can always identify which folder a code file came from. Every code file in a folder is checked.
36.4.4 Peer review — files sent as a zip archive
When reviewing a paper, authors sometimes supply code and data as a zip file attached to the submission. Once you unzip it, you have a local folder:
# After unzipping the submission to a folder:
result <- module_run(test_paper(), "code_check",
local_path = "C:/peer_review/garcia_2024_submission")
result$report # copy this into your review36.4.5 Code hosted on an unsupported repository
Metacheck currently retrieves files automatically from OSF, GitHub, GitLab, ResearchBox, PsychArchives and other DSpace repositories, Zenodo, Dataverse, Figshare, Dryad, ReShare, 4TU.ResearchData, Mendeley Data, DataONE, and LDbase. Other services, such as Bitbucket or Google Drive, are not supported. If the paper links to one of these, download the files manually and point code_check at the downloaded folder.
The workflow is the same for all of them:
- Go to the link in the paper
- Download the files (usually a “Download all” button, or clone with git)
- Unzip if needed
- Run
code_check
# Author shared code on Bitbucket — you downloaded or cloned it locally
result <- module_run(test_paper(), "code_check",
local_path = "C:/downloads/lee_2023_bitbucket_code")
result$summary_text
result$traffic_light36.5 Part 3: Combining a paper with local files
Sometimes a paper links to an online repository that Metacheck supports, but there are also supplementary files that were shared separately — for example, the main data is on OSF but additional analysis scripts were sent as a zip by the editor. You can check both at once:
paper <- read("garcia_2024.pdf")
# repo_check fetches the OSF files AND lists the local folder
result <- module_run(paper, "code_check",
local_path = "C:/peer_review/garcia_2024_extra_scripts")
# Online files have a URL in repo_url; local files have the folder path
unique(result$table$repo_url)repo_check treats the online repository and the local folder as two repositories. The summary table counts both in one row for the paper, and the repo_url column of the file table shows which files, README files, and archives are in the online repo and which in the local folder:
repo <- module_run(paper, "repo_check",
local_path = "C:/peer_review/garcia_2024_extra_scripts")
# One row for the paper, with repo_n = 2 (the OSF project and the local folder)
repo$summary_table
repo$traffic_light
# Number of files of each type per repository
table(repo$table$repo_url, repo$table$file_type)
36.6 Part 4: Running repo_check and code_check as a two-step pipeline
By default, code_check runs repo_check internally and you do not see its output. If you want to inspect the file inventory before the code analysis, or save the repo_check results separately, run them as two steps. When you pass a repo_check result as the first argument to code_check, the file list is reused — the folder is not re-read:
path <- "C:/projects/reaction_time_study_2024"
# Step 1: inventory and organisational checks
repo <- module_run(test_paper(), "repo_check", local_path = path)
repo$summary_text # how many files, README present?
repo$traffic_light # green / yellow
repo$table # full file list with types and sizes
# Step 2: code quality analysis (reuses the file list from step 1)
code <- module_run(repo, "code_check")
code$summary_text # code-specific summary
code$table # one row per code file
code$traffic_lightThis is especially useful when the folder is on a cloud-sync drive: any slow file downloads happen once (during code_check), not twice.
36.7 Understanding the output
36.7.1 repo_check output
| Element | What it contains |
|---|---|
$traffic_light |
"green" (no issues), "yellow" (issues, such as a missing README or an archive that cannot be listed), "red" (files that software creates by itself, such as .DS_Store), or "na" (no repos) |
$summary_text |
Plain-text summary: file counts, README status, archives, file names, files that do not belong |
$summary_table |
One row per paper: paper_id, repo_n, repo_unchecked, files_n, files_data, files_code, files_readme, files_zip, files_unknown, naming_issues, roster_mismatch
|
$table |
One row per file, with columns including paper_id, repo_url, file_name, file_path, file_url, file_location, file_size, file_type, and group (the study a file belongs to) |
$report |
Formatted report explaining any README, archive, file-name, or other issues |
36.7.2 code_check output
| Element | What it contains |
|---|---|
$traffic_light |
"green" (no issues), "yellow" (issues found), or "na" (no code files read) |
$summary_text |
Plain-text summary of all checks across all files |
$summary_table |
One row per paper: paper_id, code_n, code_checked, code_abs_path, code_setwd, code_install_packages, code_missing_files, code_min_comments, code_parse_errors, code_packages_n, code_version_pinned
|
$table |
One row per code file with detailed metrics (see below) |
$report |
Full formatted report suitable for pasting into a review |
Key columns in code_check’s $table:
| Column | What it means |
|---|---|
file_name |
Script filename |
repo_url |
Which folder (or online repo) the file came from |
language |
Detected language: R, Python, SAS, SPSS, Stata, Mplus, MATLAB, or JASP |
percentage_comment |
Share of non-blank lines that are comments (0 = no comments at all) |
loaded_files_missing |
Number of data files the script tries to load that are not in the folder |
loaded_files_missing_names |
The names of those missing files |
code_abs_path |
Number of absolute file paths detected |
library_max_between |
Largest gap in lines between consecutive library() calls |
36.8 Downloading OSF files to check locally
Often the files you want to check live in an OSF project rather than on your own disk. You can download them first, then point repo_check / code_check at the downloaded folder using the local-file options above.
OSF projects let you organise information into nested components, and files within those components. To retrieve all of the files associated with a project by hand, you may need to navigate to several components, download a zip for each, then reorganise and rename the downloaded folders.
The function osf_file_download() does all of this for you, recreating a folder structure based on the component names. By default (mode = "all") it fetches every component’s files as a single compressed archive per component, with no size filtering — max_file_size and max_download_size are both NULL (no limit) by default, and neither one applies in this mode, because there is no file list to filter against. To filter by size instead, pass mode = "select", which lists every file individually through the OSF API before downloading, and only then applies max_file_size/max_download_size (in megabytes). See the Archiving OSF Files appendix for the full comparison between the two modes, and for report_repository(), which can take over from here once the files are on disk.
osf_file_download(osf_id = "pngda",
download_to = ".",
mode = "select",
max_file_size = 1,
max_download_size = 10)Starting retrieval for pngda
- omitting metacheck.png (1.5MB)
Downloading files [=====================] 24/24 00:00:35
The files are written into a folder named after the OSF id, preserving the project’s nested structure:
list.files("pngda", recursive = TRUE)#> [1] "Data/Individual/data-01.csv"
#> [2] "Data/Individual/data-02.csv"
#> [3] "Data/Individual/data-03.csv"
#> [4] "Data/Individual/data-04.csv"
#> [5] "Data/Individual/data-05.csv"
#> [6] "Data/Individual/data-06.csv"
#> [7] "Data/Individual/data-07.csv"
#> [8] "Data/Individual/data-08.csv"
#> [9] "Data/Individual/data-09.csv"
#> [10] "Data/Individual/data-10.csv"
#> [11] "Data/Individual/data-11.csv"
#> [12] "Data/Individual/data-12.csv"
#> [13] "Data/Individual/data-13.csv"
#> [14] "Data/Individual/data-14.csv"
#> [15] "Data/Processed Data/processed-data.csv"
#> [16] "Data/Raw Data/data.xlsx"
#> [17] "Data/Raw Data/nest-1/nest-2/nest-3/nest-4/test-4.txt"
#> [18] "Data/Raw Data/nest-1/nest-2/nest-3/test-3.txt"
#> [19] "Data/Raw Data/nest-1/nest-2/test-2.txt"
#> [20] "Data/Raw Data/nest-1/README"
#> [21] "Data/Raw Data/nest-1/test-1.txt"
#> [22] "Data/Raw Data/README"
#> [23] "README"
Once downloaded, you can run the checks on that folder exactly as shown earlier:
module_run(test_paper(), "code_check", local_path = "pngda", local_only = TRUE)Or, since there is no manuscript involved at this point, skip the manual test_paper()/module_run() steps and call report_repository() instead, which runs repo_check, code_check, data_check, and codebook_check on the folder in one step and writes a report named after it:
report_repository("pngda")