โ† Browse

@easystats/report

report: Automated Results Reporting R Package

instructionscopilot

Install

agr install @easystats/report --target copilot

Writes 1 file into .github/copilot-instructions.md, pinned to git-15f06163.

  • .github/copilot-instructions.md

Document

report: Automated Results Reporting R Package

Always follow these instructions EXACTLY and only search for additional context if the information here is incomplete or found to be in error.

Overview

The report package is an R package for automated reporting of results and statistical models. It is part of the easystats ecosystem, providing functions to convert statistical models and data frames into textual reports suited for publication. The package follows standard R package development practices and focuses on ensuring standardization and quality in results reporting.

CRITICAL REMINDER: Every PR must include version number updates in DESCRIPTION and changelog entries in NEWS.md. See the Version Management section for detailed instructions.

VERSION MANAGEMENT FREQUENCY: Version numbers and NEWS.md should be updated ONCE PER PULL REQUEST, not once per commit. Multiple commits within the same PR should use the same version number.

Pre-Configured Environment

NEW: This repository now includes .github/workflows/copilot-setup-steps.yml which automatically configures the development environment before GitHub Copilot starts working. This workflow intelligently determines what setup is needed using sophisticated conditional logic:

For R package development tasks (editing .R files, functions, tests, etc.), it pre-installs:

  • R and system dependencies
  • Core development packages (rlang, dplyr, testthat, lintr, styler, roxygen2, reprex, devtools)
  • Complete reprex setup: knitr, rmarkdown, pandoc, clipr (all dependencies needed for creating reproducible examples)
  • Easystats ecosystem packages (insight, bayestestR, effectsize, performance, parameters, datawizard)
  • The report package itself (built and installed)
  • ONLY required dependencies (Imports) - suggested packages are NOT pre-installed to save time and resources
  • Verified functionality of core functions and reprex

For documentation/configuration tasks (editing .md files, .yml files, copilot instructions, etc.), it runs minimal setup:

  • Repository checkout only
  • SMART DETECTION: Uses PR file analysis (GitHub API) or git diff for accurate change detection
  • Skips time-consuming R installation and package setup
  • Saves significant time for non-code changes (2-3 minutes)

If the pre-configured environment is working, you can skip most manual installation steps below and go directly to the Build and Development Workflow section.

Verification: Check if the environment is pre-configured by running:

R --no-restore --no-save -e 'library(report); packageVersion("report")'

If this works without errors, the environment is ready. If not, follow the manual setup below.

Resource-Conscious Two-Step Development Approach

CRITICAL PHILOSOPHY: Installing R and dependencies is very expensive (time, resources, environment impact). The setup workflow is designed to minimize resource usage through a two-step approach:

Two-Step Development Scenarios

Scenario 1: Documentation/Configuration Changes Only

  • First run: No R installation (not necessary) โœ…
  • Change documentation: Still no R installation (not necessary) โœ…
  • Perfect resource optimization

Scenario 2: Code Changes Required

  • First run: No R installation (intentionally delayed to save resources)
    • Make code changes to the best ability without full testing
    • Basic syntax checking and file editing
    • Commit initial code changes
  • Second run: R installation triggered (after code changes detected)
    • Full R setup occurs because git diff now detects R file changes
    • Complete testing, building, and validation
    • Full development workflow available

Benefits of Two-Step Approach

  • ๐ŸŒฑ Environmental: Avoids unnecessary R installations (~5-10 minutes saved per run)
  • ๐Ÿ’ฐ Cost savings: Reduces compute resource usage significantly
  • โฑ๏ธ Time efficiency: First iterations are much faster (2-3 minutes vs 7-15 minutes)
  • ๐Ÿ”„ Natural workflow: Matches how developers actually work (edit first, test second)
  • ๐ŸŽฏ Smart resource allocation: Full resources only when actually needed

Implementation Note: This approach means the environment setup workflow will intentionally skip R installation on first runs, even when R code changes are planned. This is not a bug - it's a deliberate resource optimization strategy.

Environment Setup (Manual - if pre-configuration failed)

Package Installation Philosophy

CRITICAL: Install packages minimally and on-demand to avoid long installation times. Only install packages that are actually required by the specific function you are modifying in your current PR. The custom copilot environment setup now follows this philosophy by only installing required dependencies (Imports) and NOT installing suggested packages by default.

Install R and Required System Dependencies

CRITICAL: Always ensure R is properly installed and functional before proceeding with any package development tasks.

# Ubuntu/Debian systems - ALWAYS run this first in every session
sudo apt update
sudo apt install -y r-base r-base-dev

# Verify R installation is working
R --version
which R

# Install core R packages via system package manager (recommended)
sudo apt install -y r-cran-dplyr r-cran-rlang r-cran-testthat

# CRITICAL: Install development version of lintr to match CI environment
# The easystats CI uses r-lib/lintr (development version) not CRAN stable
# Check if lintr is already installed first to save resources/time/errors
R --no-restore --no-save -e '
if (!requireNamespace("lintr", quietly = TRUE)) {
  # Set GitHub token if available to avoid rate limits (use GH_PAT directly)
  if (Sys.getenv("GH_PAT") != "") {
    Sys.setenv(GITHUB_PAT = Sys.getenv("GH_PAT"))
  }
  # Priority order: r-universe FIRST, then remotes as fallback
  # Based on testing with whitelisted r-lib.r-universe.dev and cdn.r-universe.dev: both r-universe and remotes work successfully
  tryCatch({
    # FIRST PRIORITY: Try r-universe installation
    install.packages("lintr", lib = .libPaths()[1], repos=c("https://r-lib.r-universe.dev", "https://cloud.r-project.org"))
    cat("SUCCESS: r-universe installation worked\n")
  }, error = function(e1) {
    cat("r-universe installation failed, trying remotes...\n")
    tryCatch({
      # FALLBACK: Use remotes for development lintr installation
      if (!requireNamespace("remotes", quietly = TRUE)) {
        install.packages("remotes", lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))
      }
      remotes::install_github("r-lib/lintr")
      cat("SUCCESS: remotes installation worked\n")
    }, error = function(e2) {
      cat("CRITICAL ERROR: Cannot install development lintr from any source\n")
      cat("Tried: 1) r-universe (failed), 2) remotes (failed)\n")
      cat("This is required for proper linting that matches CI environment.\n")
      cat("COPILOT MUST STOP and report this issue in the PR.\n")
      cat("User must resolve lintr installation before continuing.\n")
      stop("Development lintr installation failed - cannot proceed")
    })
  })
} else {
  cat("Development lintr already installed. Version:", as.character(packageVersion("lintr")), "\n")
}'

# Install reprex (ESSENTIAL for creating reproducible examples in PRs)
sudo apt install -y r-cran-reprex || R --no-restore --no-save -e 'install.packages("reprex", lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))'

# Install other essential development packages via system packages when possible
sudo apt install -y r-cran-devtools r-cran-roxygen2 r-cran-styler || echo "Some packages not available via apt, will install via R"

# If styler, roxygen2, or devtools are not available via system packages, install via R:
R --no-restore --no-save -e '
packages_needed <- c("styler", "roxygen2", "devtools")
packages_installed <- rownames(installed.packages())
packages_to_install <- setdiff(packages_needed, packages_installed)
if (length(packages_to_install) > 0) {
  install.packages(packages_to_install, lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))
}
'

Verify R Installation and Core Packages

NEVER SKIP: Always run this verification after installing R:

# Test R basic functionality
R --no-restore --no-save -e 'print("R is working correctly")'

# Verify core packages are available
R --no-restore --no-save -e '
required_packages <- c("dplyr", "rlang", "testthat", "lintr", "reprex", "styler", "roxygen2", "knitr", "rmarkdown", "clipr")
missing_packages <- required_packages[!sapply(required_packages, requireNamespace, quietly = TRUE)]
if (length(missing_packages) > 0) {
  cat("Missing packages:", paste(missing_packages, collapse = ", "), "\n")
  cat("Run installation commands to install missing packages\n")
} else {
  cat("All core development packages are available\n")
  cat("reprex functionality fully supported\n")
}
'

Essential reprex Package Setup

CRITICAL: The reprex package is mandatory for creating reproducible examples in pull requests.

If using the pre-configured environment: reprex and all its dependencies (pandoc, knitr, rmarkdown, clipr) are already installed and tested. Skip to step 4 to verify functionality.

If setting up manually: Follow this complete setup process:

# Step 1: Install required dependencies for reprex
sudo apt install -y pandoc
R --no-restore --no-save -e 'install.packages(c("knitr", "rmarkdown"), lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))'

# Step 2: Install reprex package
R --no-restore --no-save -e '
if (!requireNamespace("reprex", quietly = TRUE)) {
  # Try multiple installation methods
  tryCatch({
    install.packages("reprex", lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))
  }, error = function(e1) {
    tryCatch({
      install.packages("reprex", lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))
    }, error = function(e2) {
      if (!requireNamespace("remotes", quietly = TRUE)) {
        install.packages("remotes", lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))
      }
      remotes::install_github("tidyverse/reprex")
    })
  })
}
'

# Step 3: CRITICAL - Set environment variable and test
export CLIPR_ALLOW=TRUE && R --no-restore --no-save -e '
library(reprex)
# Test reprex with simple code
result <- reprex({
  x <- 1:5
  mean(x)
}, venue = "gh", advertise = FALSE, html_preview = FALSE)

if (length(result) > 0) {
  cat("SUCCESS: reprex package is working correctly\n")
  cat("Sample output:\n")
  cat(paste(head(result, 5), collapse = "\n"))
} else {
  stop("FAILED: reprex package installation failed - this is required for PR creation")
}
'

ESSENTIAL: Always run export CLIPR_ALLOW=TRUE before using reprex to prevent crashes.


### Install Function-Specific Dependencies Only
**CRITICAL**: Only install packages that are actually used by the specific function you are modifying. DO NOT install all suggested packages upfront as this causes long installation times.

#### Determine Required Packages for Your Function
```bash
# Step 1: Find which packages your specific function actually requires
# Check the function's requireNamespace() calls and package dependencies in the source code
cd /home/runner/work/report/report
grep -A2 -B2 "requireNamespace\|check_installed" R/[your_function_file].R

# Or search for all function dependencies:
# grep -r "requireNamespace\|@importFrom" R/[your_function_file].R

Install Only Required Packages

# Step 2: Install ONLY the packages found in Step 1
# Example: If working on report.lm(), you might need modelbased and effectsize
R --no-restore --no-save -e 'install.packages(c("modelbased", "effectsize"), lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))'

# Example: If working on report.lavaan(), you might need lavaan  
R --no-restore --no-save -e 'install.packages("lavaan", lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))'

# Example: If working on report.brmsfit(), you need brms and related packages
R --no-restore --no-save -e 'install.packages(c("brms", "rstanarm"), lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))'

Use report's Built-in Utilities (After Building Package)

# Alternative: Check the report package's dependencies and install as needed
R --no-restore --no-save -e '
# First build and install the current report package to access its functions
if (file.exists("DESCRIPTION")) {
  system("R CMD build .")
  pkg_file <- list.files(pattern = "report_.*\\.tar\\.gz")[1]
  if (!is.na(pkg_file)) system(paste("R CMD INSTALL", pkg_file))
}

# Load report and install only specific packages for your function
library(report)
# ONLY install packages needed for your specific function:
# install.packages("your_specific_package", lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))
'

Set Up R User Library

# Create user library directory
mkdir -p ~/R/library
echo 'R_LIBS_USER=~/R/library' >> ~/.Renviron

Build and Development Workflow

Targeted Package Installation Workflow

ESSENTIAL: Follow this targeted approach to avoid "The package installation is taking a long time" issues:

  1. Identify your function: Determine which specific function you're modifying
  2. Find dependencies: Check what packages that function actually requires:
    cd /home/runner/work/report/report
    grep -A2 -B2 "requireNamespace\|@importFrom" R/[your_function].R
    
  3. Install only required packages: Install ONLY the packages found in step 2
  4. Test function: Test that your specific function works with the installed packages
  5. Proceed with development: Build, test, and develop normally

Build the Package

NEVER CANCEL: Build takes ~19 seconds. Set timeout to 60+ seconds.

cd /home/runner/work/report/report
R CMD build .
# Creates: report_0.6.1.1.tar.gz (version may vary)

Install the Package

NEVER CANCEL: Install takes ~3 seconds. Set timeout to 60+ seconds.

cd /home/runner/work/report/report
R CMD INSTALL report_0.6.1.1.tar.gz
# Or install from source:
# R CMD INSTALL .

Run Tests

NEVER CANCEL: Tests take ~11 seconds. Set timeout to 30+ seconds.

cd /home/runner/work/report/report
R --no-restore --no-save -e 'library(testthat); library(report); test_local()'

Expected results:

  • ~99 tests processed across multiple test files
  • ~94 tests should pass
  • 3-5 snapshot failures due to minor precision differences (normal and expected)
  • Some tests may be skipped if optional packages not available

Run Linting with Easystats Settings

IMPORTANT: This package uses the easystats organization's centralized lintr configuration defined in easystats/workflows. This ensures consistency across all easystats packages and stays automatically up-to-date with organization standards.

NEVER CANCEL: Linting takes ~20 seconds. Set timeout to 60+ seconds.

Recommended approach - Lint changed files only (matches CI workflow behavior):

cd /home/runner/work/report/report
# Get list of changed R files in current PR/branch
git diff --name-only HEAD~1 | grep "\\.R$" > changed_files.txt
R --no-restore --no-save -e '
library(lintr)
if (file.exists("changed_files.txt") && file.size("changed_files.txt") > 0) {
  changed_files <- readLines("changed_files.txt")
  changed_files <- changed_files[file.exists(changed_files)]
  if (length(changed_files) > 0) {
    # Use the same lintr configuration as the CI workflow
    lint(changed_files, linters = all_linters(
      coalesce_linter = NULL,
      absolute_path_linter = NULL,
      cyclocomp_linter(40L),
      if_not_else_linter(exceptions = character(0L)),
      indentation_linter = NULL,
      implicit_integer_linter = NULL,
      library_call_linter = NULL,
      line_length_linter(120L),
      namespace_linter = NULL,
      nonportable_path_linter = NULL,
      object_length_linter(50L),
      object_name_linter = NULL,
      object_usage_linter = NULL,
      one_call_pipe_linter = NULL,
      todo_comment_linter = NULL,
      commented_code_linter = NULL,
      undesirable_function_linter(c("mapply" = NA, "setwd" = NA)),
      undesirable_operator_linter = NULL,
      unnecessary_concatenation_linter(allow_single_expression = FALSE),
      unused_import_linter = NULL
    ))
  } else {
    cat("No R files changed\n")
  }
} else {
  cat("No R files changed\n")
}
'
rm -f changed_files.txt

Expected results:

  • Style warnings (normal for existing codebase)
  • Focus on new code adhering to style guidelines
  • Package is functional despite style warnings

Note: The lintr configuration above exactly matches the current settings in easystats/workflows/lint-changed-files.yaml. This ensures the local linting matches the CI workflow exactly and stays current with organization standards.

Auto-format Code with Styler

NEVER CANCEL: Styling takes ~10-30 seconds depending on package size. Set timeout to 60+ seconds.

cd /home/runner/work/report/report
# Style entire package
R --no-restore --no-save -e 'library(styler); style_pkg()'

# Style specific file
R --no-restore --no-save -e 'library(styler); style_file("R/[function_name].R")'

# Style specific directory
R --no-restore --no-save -e 'library(styler); style_dir("R")'

Expected results:

  • Automatic code formatting according to tidyverse style guide
  • Consistent indentation, spacing, and bracket placement
  • Files will be modified in-place if styling changes are needed
  • Use after making changes but before committing

Update Documentation with roxygen2

NEVER CANCEL: Documentation update takes ~5-15 seconds. Set timeout to 60+ seconds.

cd /home/runner/work/report/report
# Update documentation after making changes to roxygen2 comments
R --no-restore --no-save -e 'roxygen2::document()'

# Alternative using devtools
R --no-restore --no-save -e 'devtools::document()'

Expected results:

  • Updates .Rd files in man/ directory from roxygen2 comments
  • Updates NAMESPACE file with exports/imports
  • Essential step after modifying function documentation or adding/removing exports
  • Must be run before building the package if documentation was changed

When to use: Always run this after:

  • Adding or modifying roxygen2 comments (the #' comments above functions)
  • Adding new exported functions
  • Changing function parameters or return values in documentation
  • Adding or removing @export, @import, or @importFrom tags

Run R CMD Check

NEVER CANCEL: R CMD check takes ~30 seconds (without suggested packages) to 5 minutes (full). Set timeout to 10+ minutes.

cd /home/runner/work/report/report
# Without suggested packages (due to network limitations):
_R_CHECK_FORCE_SUGGESTS_=FALSE R CMD check report_0.6.1.1.tar.gz --no-manual --no-vignettes

# With all checks (if network access available):
# R CMD check report_0.6.1.1.tar.gz

Expected results:

  • Status: May show 1 ERROR (missing suggested packages - normal), few NOTEs
  • Core functionality passes all checks
  • Tests pass correctly
  • Examples may fail due to missing optional packages (expected)

Validation Scenarios

Always Test Core Functions After Changes

Test the main functions to ensure they work correctly:

cd /home/runner/work/report/report
R --no-restore --no-save -e '
library(report)

# Test basic report function
data(mtcars)
model <- lm(mpg ~ wt + hp, data = mtcars)
result <- report(model)
print(result)

# Test data frame reporting
report_data <- report(mtcars)
print(report_data)

# Test sample reporting
sample_report <- report_sample(mtcars)
print(sample_report)

print("Core functions working correctly")
'

MANDATORY: Test reprex Functionality Before Making Changes

CRITICAL: Always verify reprex is working before modifying any code that will require a PR:

cd /home/runner/work/report/report
export CLIPR_ALLOW=TRUE && R --no-restore --no-save -e '
# Load required packages
library(reprex)
library(report)

# Create a test reprex with actual report function (WORKING EXAMPLE)
reprex_result <- reprex({
  library(report)
  data(mtcars)

  # Example model reporting
  model <- lm(mpg ~ wt + hp, data = mtcars)
  result <- report(model)
  print(result)
  
}, venue = "gh", advertise = FALSE, html_preview = FALSE)

# Verify it worked
if (length(reprex_result) > 0 && any(grepl("library\\(report\\)", reprex_result))) {
  cat("SUCCESS: reprex is working correctly with report functions\n")
  cat("Sample reprex output:\n")
  cat(paste(reprex_result, collapse = "\n"))
  cat("\n")
} else {
  stop("FAILED: reprex is not working correctly - follow debugging guide in Troubleshooting section")
}
'

Manual Function Testing Workflow

After making changes to package functions:

  1. Always rebuild and reinstall the package:

    cd /home/runner/work/report/report
    R CMD build . && R CMD INSTALL report_*.tar.gz
    
  2. Test the specific function you modified:

    R --no-restore --no-save -e 'library(report); [your_function_test_here]'
    
  3. Run relevant tests:

    R --no-restore --no-save -e 'library(testthat); library(report); test_file("tests/testthat/test-[function_name].R")'
    

Key Locations and Files

Repository Exploration Commands

# View repository structure
ls -la /home/runner/work/report/report/

# View R source files
ls -la /home/runner/work/report/report/R/

# View test files
ls -la /home/runner/work/report/report/tests/testthat/

# Check package metadata
cat /home/runner/work/report/report/DESCRIPTION

Source Code Structure

  • /R/ - All R function source files (60+ files)
  • /tests/testthat/ - Test files using testthat framework
  • /tests/testthat.R - Test runner entry point
  • /man/ - Documentation files (auto-generated from roxygen2)
  • /vignettes/ - R Markdown tutorials and documentation

Configuration Files

  • DESCRIPTION - Package metadata, dependencies, version
  • NAMESPACE - Package exports (auto-generated from roxygen2)
  • .github/workflows/ - CI/CD workflows (R-CMD-check, lint, test-coverage)
  • .Rbuildignore - Files to exclude from package build

Important Functions by Category

Core Reporting: report(), report.lm(), report.aov(), report.htest() Data Reporting: report.data.frame(), report_sample(), report_participants() Model Components: report_parameters(), report_performance(), report_statistics() Text Formatting: report_text(), report_table(), format_value() Utilities: cite_easystats(), report_info(), report_intercept()

Dependencies and Package Management

Core Dependencies (Always Required)

# In DESCRIPTION file:
Imports: bayestestR (>= 0.16.1), effectsize (>= 1.0.1), insight (>= 1.3.1), 
         parameters (>= 0.27.0), performance (>= 0.15.0), datawizard (>= 1.2.0),
         stats, tools, utils
Depends: R (>= 3.6)

Suggested Packages (Optional)

Many functions require optional packages. The package uses requireNamespace() to check if needed packages are available when functions are called.

Key suggested packages: BayesFactor, brms, collapse, ivreg, knitr, lavaan, lme4, dplyr, rstanarm, survival, modelbased, emmeans, marginaleffects

ESSENTIAL for development: reprex (mandatory for creating PR examples)

Installing Additional Packages (Only When Needed)

PRIORITY: Always install reprex first, then install other packages ONLY as needed for the specific function you are modifying:

# ALWAYS install reprex first (essential for PR creation):
sudo apt install -y r-cran-reprex || R --no-restore --no-save -e 'install.packages("reprex", lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))'

# Via system packages (recommended for individual packages):
sudo apt install -y r-cran-[package-name]

# Via R (using r-universe for latest packages including development versions):
R --no-restore --no-save -e 'install.packages("[package-name]", lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))'

# Alternative sources when r-universe is not available:
# Via CRAN mirror (FALLBACK PRIORITY):
R --no-restore --no-save -e 'install.packages("[package-name]", lib = .libPaths()[1], repos="https://cran.r-project.org/")'

# Via remotes for GitHub packages (SECOND PRIORITY):
R --no-restore --no-save -e 'if (!requireNamespace("remotes", quietly = TRUE)) install.packages("remotes", lib = .libPaths()[1]); remotes::install_github("[author]/[package-name]")'

Common Function-Specific Package Requirements

DO NOT install all of these - only install what you need for your specific function:

  • report.lm(): modelbased, effectsize
  • report.aov(): effectsize, emmeans
  • report.brmsfit(): brms, rstanarm
  • report.lavaan(): lavaan
  • report.lme4(): lme4, modelbased
  • report.BFBayesFactor(): BayesFactor
  • report.ivreg(): ivreg
  • report.coxph(): survival
  • report_sample(): datawizard (already imported)

Check Function Dependencies Before Installing

# Find exactly which packages a function requires:
cd /home/runner/work/report/report
grep -A2 -B2 "requireNamespace\|@importFrom" R/[function_file].R

# Examples:
# For report.lm.R: requires modelbased, effectsize
# For report.lavaan.R: requires lavaan  
# For report.brmsfit.R: requires brms, rstanarm

Targeted Installation Examples

# Example 1: Working on report.lm() function
R --no-restore --no-save -e 'install.packages(c("modelbased", "effectsize"), lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))'

# Example 2: Working on report.lavaan() function  
R --no-restore --no-save -e 'install.packages("lavaan", lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))'

# Example 3: Working on report.brmsfit() function
R --no-restore --no-save -e 'install.packages(c("brms", "rstanarm"), lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))'

# Example 4: Working on report.BFBayesFactor() function
R --no-restore --no-save -e 'install.packages("BayesFactor", lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))'

Code Quality and Best Practices

R Version Compatibility Requirements

CRITICAL: Always check minimum R version requirements before using any functions to ensure compatibility across all supported environments.

Version Checking Process:

  1. Check DESCRIPTION file: Always verify the minimum R version in the package DESCRIPTION file:

    cd /home/runner/work/report/report
    grep "Depends:" DESCRIPTION
    # Shows: R (>= 3.6) - must use functions available in R 3.6+
    
  2. Function availability validation: Before using any R function, verify it was available in the minimum supported version:

    • R 3.6.0+: Functions like grep(..., value = TRUE), standard base R operations
    • R 4.0.0+: New features and syntax improvements
    • R 4.1.0+: Native pipe |>, new lambda syntax
    • R 4.4.0: Null coalescing operator %||%
    • R 4.5.0+: Functions like grepv() (if it existed)
  3. Safe function usage:

    # CORRECT: Use functions available in R 3.6+
    result <- grep(pattern, x, value = TRUE)
    
    # INCORRECT: Don't use functions from later R versions
    # result <- grepv(pattern, x)  # Not available in R 3.6
    

Documentation for Minimum R Versions:

  • R 3.6.0 reference: Check base R documentation for function availability
  • When in doubt: Use help(function_name) to check when functions were introduced
  • Alternative approach: Use more basic/older functions that are guaranteed to exist

Avoiding Global Variable Binding Issues

CRITICAL: Always use proper variable referencing to prevent "no visible binding for global variable" warnings that make CI workflows fail.

Recommended Approaches:

  1. For dplyr operations: Use .data[[variable_name]] notation

    # CORRECT: Use .data[[var]] notation
    data %>%
      group_by(.data[[group_var]]) %>%
      summarize(mean_val = mean(.data[[response_var]], na.rm = TRUE))
    
    # INCORRECT: Direct variable names (causes binding warnings)
    data %>%
      group_by(group_var) %>%
      summarize(mean_val = mean(response_var, na.rm = TRUE))
    
  2. For ggplot2 operations: Use .data[[variable_name]] or aes_string()

    # CORRECT: Use .data[[var]] in aes()
    ggplot(data, aes(x = .data[[x_var]], y = .data[[y_var]]))
    
    # ALTERNATIVE: Use aes_string() for string variables
    ggplot(data, aes_string(x = x_var, y = y_var))
    
  3. Import required functions: Always explicitly import from other packages

    #' @importFrom dplyr group_by summarize
    #' @importFrom ggplot2 ggplot aes
    

Discouraged Approaches:

  • DO NOT create global_variables.R files with utils::globalVariables()
  • DO NOT use bare variable names in dplyr or ggplot operations
  • DO NOT rely on global variable declarations to suppress warnings

Ensuring Documentation-Code Consistency

CRITICAL: Documentation must exactly match function arguments to prevent "Codoc mismatches" warnings.

Documentation Validation Steps:

  1. Match all parameter names exactly:

    #' @param response The dependent variable name
    #' @param group The grouping variable name  
    function_name <- function(response, group) { ... }
    
  2. Update documentation when changing parameters:

    • Always run roxygen2::document() after parameter changes
    • Check that .Rd files reflect actual function signatures
    • Verify examples use correct parameter names
  3. Validate before building:

    # Check for documentation mismatches
    R --no-restore --no-save -e 'roxygen2::document()'
    R CMD build .
    # Look for "Codoc mismatches" warnings
    

Common Development Tasks

Adding a New Function

  1. FIRST: Update version number and NEWS.md (see Version Management section - do this ONCE per PR)
  2. Create the function in /R/[function_name].R
  3. Identify required packages: Check which packages the function will need using rlang::check_installed()
  4. Install only required packages: Use targeted installation instead of batch installation
  5. Use proper variable referencing: Use .data[[var]] for dplyr/ggplot2 operations
  6. Add roxygen2 documentation above the function (ensure parameter names match exactly)
  7. Add @importFrom statements for all external functions used
  8. Add exports to roxygen2 comments if needed (@export)
  9. Create tests in /tests/testthat/test-[function_name].R
  10. Check for global variable issues: R CMD check should show no binding warnings
  11. Lint the code: R --no-restore --no-save -e 'library(lintr); lint("R/[function_name].R")' (lint specific file) or R --no-restore --no-save -e 'library(lintr); lint_package()' (lint entire package)
  12. Style the code: R --no-restore --no-save -e 'library(styler); style_file("R/[function_name].R")'
  13. Update documentation: R --no-restore --no-save -e 'roxygen2::document()'
  14. Validate documentation consistency: Check for "Codoc mismatches" warnings
  15. Rebuild and test: R CMD build . && R CMD INSTALL report_*.tar.gz
  16. Run tests: R --no-restore --no-save -e 'library(testthat); library(report); test_local()'
  17. Create reprex examples: Prepare reproducible examples showing the new function in action for PR description
  18. If making additional commits: DO NOT update version/NEWS.md again - use same version for all commits in this PR

Modifying Existing Functions

  1. FIRST: Update version number and NEWS.md (see Version Management section - do this ONCE per PR)
  2. Identify current function dependencies: Check which packages the function currently requires
  3. Edit the function in appropriate /R/[file].R
  4. Check if new packages are needed: If adding functionality, identify any new package requirements
  5. Install only new required packages: Install only what's newly needed, not all suggested packages
  6. Ensure proper variable referencing: Replace bare variable names with .data[[var]] notation
  7. Update documentation if parameters changed (ensure exact parameter name matches)
  8. Update @importFrom statements if new external functions are used
  9. Update tests if function behavior changes
  10. Check for global variable issues: R CMD check should show no binding warnings
  11. Lint the code: R --no-restore --no-save -e 'library(lintr); lint("R/[file].R")' (lint specific file) or R --no-restore --no-save -e 'library(lintr); lint_package()' (lint entire package)
  12. Style the code: R --no-restore --no-save -e 'library(styler); style_file("R/[file].R")'
  13. Update documentation if changed: R --no-restore --no-save -e 'roxygen2::document()'
  14. Validate documentation consistency: Check for "Codoc mismatches" warnings
  15. Always rebuild and reinstall: R CMD build . && R CMD INSTALL report_*.tar.gz
  16. Always test the specific function manually
  17. Run full test suite to check for regressions
  18. Create before/after reprexes: Prepare examples showing the old vs new behavior for PR description
  19. If making additional commits: DO NOT update version/NEWS.md again - use same version for all commits in this PR

Version Management and Changelog Updates

CRITICAL: Every PR must include version number updates and NEWS.md changelog entries. This is mandatory for all changes.

IMPORTANT CLARIFICATION: Version numbers should be bumped ONCE PER PULL REQUEST, not once per commit. If you make multiple commits within a single PR, all commits should use the same version number. Only bump the version once at the beginning of your PR work or before submitting the PR for review. Only bump if making changes to functions (e.g, not for copilot instructions, workflow, etc.).

Version Numbering System

The report package follows this versioning pattern:

  • Major releases (CRAN submissions): Standard semantic versioning (e.g., 0.6.1, 0.6.0, 0.5.9)
  • Development versions (between CRAN releases): Add a fourth decimal (e.g., 0.6.1.1, 0.6.1.2, 0.6.1.3)

When to Bump Versions

ALWAYS bump the version for ANY change that affects the package:

  1. Bug fixes: Increment the fourth decimal (0.6.1.1 โ†’ 0.6.1.2)
  2. New features: Increment the fourth decimal (0.6.1.1 โ†’ 0.6.1.2)
  3. Breaking changes: Increment the minor version (0.6.1 โ†’ 0.7.0) - rare
  4. Documentation-only changes: Still increment fourth decimal for tracking
  5. Do not bump when only making changes to copilot instructions, workflow, etc.

Multiple Commits Within a Single PR

CRITICAL RULE: If your PR involves multiple commits, use the same version number for ALL commits in that PR.

Correct approach for multi-commit PR:

  1. At the start of your PR work: Bump version from 0.6.1.1 โ†’ 0.6.1.2 and update NEWS.md
  2. First commit: Contains version bump + your first set of changes
  3. Subsequent commits: Use the same version (0.6.1.2) for any additional changes
  4. Do NOT bump version again until you start a new PR

Example of correct multi-commit PR:

  • Commit 1: "Bump version to 0.6.1.2 and add new feature X"
  • Commit 2: "Fix bug in feature X (still version 0.6.1.2)"
  • Commit 3: "Update documentation for feature X (still version 0.6.1.2)"
  • All commits use version 0.6.1.2, NEWS.md updated once in commit 1

NEVER do this (incorrect approach):

  • Commit 1: "Add feature X, bump to 0.6.1.2"
  • Commit 2: "Fix bug in feature X, bump to 0.6.1.3" โŒ WRONG
  • Commit 3: "Update docs, bump to 0.6.1.4" โŒ WRONG

How to Update Version Number

  1. Edit the DESCRIPTION file:

    cd /home/runner/work/report/report
    # Find current version
    grep "Version:" DESCRIPTION
    # Update to next version (example: 0.6.1.1 โ†’ 0.6.1.2)
    
  2. Version update pattern:

    # Current version: 0.6.1.1
    # For your PR: 0.6.1.2
    # Next PR: 0.6.1.3
    # etc.
    

How to Update NEWS.md

MANDATORY: Add your changes to the top of NEWS.md following this exact format:

  1. For first change after a major release (e.g., after 0.6.1 was released):

    # report 0.6.x
    
    Bug fixes
    
    * Your change description here
    
  2. For subsequent development changes (when 0.6.x already exists):

    # report 0.6.x
    
    Bug fixes
    
    * Your new change description here
    * Previous change description here
    
  3. Change description guidelines:

    • Use function names in backticks: report(), report_sample()
    • Be specific about what changed
    • Include issue references if applicable: (#451)
    • Examples:
      • report.lm(): fix issue with missing coefficients in summary output
      • report_sample(): add new ci_method argument for confidence interval calculation
      • Fixed CRAN check failures related to test dependencies

Automated Version Management Workflow

Follow this exact sequence ONCE PER PR (not per commit):

cd /home/runner/work/report/report

# Step 1: Check current version
grep "Version:" DESCRIPTION
grep -A5 "^# report" NEWS.md | head -10

# Step 2: Determine new version number
# Current: 0.6.1.1 โ†’ New: 0.6.1.2 (example)

# Step 3: Update DESCRIPTION file (ONCE per PR)
sed -i 's/Version: 0.6.1.1/Version: 0.6.1.2/' DESCRIPTION

# Step 4: Update NEWS.md (ONCE per PR - add entry at the top)
# Use your preferred text editor or str_replace_editor

# Step 5: Verify updates
grep "Version:" DESCRIPTION
head -10 NEWS.md

# Step 6: Proceed with normal build/test workflow
# Step 7: Make your code changes and commit everything together
# Step 8: Any additional commits in this PR should NOT change version numbers again

Version Update Examples

Example 1: Bug Fix

# In DESCRIPTION: Version: 0.6.1.1 โ†’ 0.6.1.2
# In NEWS.md (add at top):
# report 0.6.x

Bug fixes

* `report.lm()`: fix issue with confidence intervals in summary output

Example 2: New Feature

# In DESCRIPTION: Version: 0.6.1.2 โ†’ 0.6.1.3
# In NEWS.md (add at top):
# report 0.6.x

New features

* `report_sample()`: add `weights` argument for weighted sample descriptions

Example 3: Multiple Changes

# In DESCRIPTION: Version: 0.6.1.3 โ†’ 0.6.1.4  
# In NEWS.md (add at top):
# report 0.6.x

Bug fixes

* `report()`: improve error messages for unsupported model classes
* `report_participants()`: fix issue with missing gender categories
* Documentation updates for improved clarity across reporting functions

Before Submitting Your PR (Final Validation)

CRITICAL: Always run this complete validation sequence to ensure workflow checks pass on first try. This should be done once before submitting your PR for review, not before every individual commit.

cd /home/runner/work/report/report

# 0. ENSURE: Version number and NEWS.md were already updated once at the beginning of this PR
#    (Do NOT update them again if this is a subsequent commit in the same PR)

# 1. Check for global variable binding issues first (look for "no visible binding" warnings)
R --no-restore --no-save -e 'warnings(); R CMD check report_*.tar.gz --no-manual --no-vignettes 2>&1 | grep -i "binding"'

# 2. Lint code to identify style issues (20 seconds) - use easystats/workflows configuration
R --no-restore --no-save -e 'library(lintr); lint_package(linters = all_linters(
  coalesce_linter = NULL,
  absolute_path_linter = NULL,
  cyclocomp_linter(40L),
  if_not_else_linter(exceptions = character(0L)),
  indentation_linter = NULL,
  implicit_integer_linter = NULL,
  library_call_linter = NULL,
  line_length_linter(120L),
  namespace_linter = NULL,
  nonportable_path_linter = NULL,
  object_length_linter(50L),
  object_name_linter = NULL,
  object_usage_linter = NULL,
  one_call_pipe_linter = NULL,
  todo_comment_linter = NULL,
  commented_code_linter = NULL,
  undesirable_function_linter(c("mapply" = NA, "setwd" = NA)),
  undesirable_operator_linter = NULL,
  unnecessary_concatenation_linter(allow_single_expression = FALSE),
  unused_import_linter = NULL
))'

# 3. Style code to automatically fix issues (10-30 seconds) - optional but recommended
R --no-restore --no-save -e 'library(styler); style_pkg()'

# 4. Update documentation if documentation was changed (5-15 seconds)
R --no-restore --no-save -e 'roxygen2::document()'

# 5. Build (19 seconds)
R CMD build .

# 6. Install  
R CMD INSTALL report_*.tar.gz

# 7. Test (11 seconds) 
R --no-restore --no-save -e 'library(testthat); library(report); test_local()'

# 8. Final R CMD check for all issues (~30 seconds) - REQUIRED before PR submission
_R_CHECK_FORCE_SUGGESTS_=FALSE R CMD check report_*.tar.gz --no-manual --no-vignettes

# 9. Look specifically for critical warnings that fail CI:
# - "no visible binding for global variable"
# - "Codoc mismatches from Rd file"
# - Fix these issues before submitting your PR

Pull Request Requirements

CRITICAL: When creating pull requests, you MUST include ALL of the following:

  1. Version number bump in DESCRIPTION file (see Version Management section above)
  2. NEWS.md changelog entry with your changes (see Version Management section above)
  3. Reprexes (minimally reproducible examples) showing the old and new behavior for comparison

MANDATORY: Use the actual reprex package - NEVER simulate or guess at reprex output. The repository owner needs to see actual function behavior, including plots/images that cannot be simulated.

VERSION MANAGEMENT IS NOT OPTIONAL: Every PR must include version updates and changelog entries. PRs without these updates will be rejected.

Creating Reprexes for PRs:

  1. Use base R datasets when possible (e.g., mtcars, iris, airquality) for reproducible examples

  2. Show before/after behavior with your code changes

  3. ALWAYS use the actual reprex package for consistent formatting:

    # Ensure reprex is installed and working BEFORE creating PR
    R --no-restore --no-save -e '
    if (!requireNamespace("reprex", quietly = TRUE)) {
      stop("reprex package MUST be installed before creating PRs")
    }
    library(reprex)
    # Test with simple example first
    test_result <- reprex(input = "x <- 1:5\nmean(x)", venue = "gh", advertise = FALSE, show = FALSE)
    if (length(test_result) == 0) {
      stop("reprex package is not working correctly")
    }
    cat("reprex is ready for PR creation\n")
    '
    
  4. Generate ACTUAL reprex output using this workflow:

    library(reprex)
    
    # For BEFORE behavior (if modifying existing function):
    before_code <- "
    library(report)
    data(mtcars)
    # [your code showing current behavior]
    "
    before_reprex <- reprex(input = before_code, venue = "gh", advertise = FALSE)
    
    # For AFTER behavior (with your changes):
    after_code <- "
    library(report)
    data(mtcars)
    # [your code showing improved behavior]
    "
    after_reprex <- reprex(input = after_code, venue = "gh", advertise = FALSE)
    
  5. Include both ACTUAL reprex outputs in your PR description:

    • Before: Real reprex output showing the current (problematic) behavior
    • After: Real reprex output showing the improved behavior with your changes

Optimized Reprex Creation with Image Handling:

ESSENTIAL: Always generate actual reprex with automatic imgur integration for plots:

cd /home/runner/work/report/report
export CLIPR_ALLOW=TRUE && R --no-restore --no-save -e '
library(reprex)
library(report)

# Create ACTUAL reprex - plots automatically uploaded to imgur
reprex_result <- reprex({
  library(report)
  
  # Example: Create basic report output
  data(mtcars)
  model <- lm(mpg ~ wt + hp, data = mtcars)
  result <- report(model)
  print(result)
  
  # Example: Sample reporting
  sample_report <- report_sample(mtcars)  
  print(sample_report)
  
}, venue = "gh", advertise = TRUE, html_preview = FALSE)

# Display complete reprex with imgur links embedded
cat(paste(reprex_result, collapse = "\n"))
'

Key Benefits of This Approach:

  • โœ… Automatic image hosting: Plots automatically uploaded to imgur (whitelisted domain)
  • โœ… No local artifacts: No PNG files left in repository to accidentally commit
  • โœ… Complete format: Includes "Created on [date] with reprex v[version]" footer
  • โœ… Direct embedding: Images display directly in GitHub responses
  • โœ… Clean workflow: No manual upload or cleanup steps required

CRITICAL: Always set advertise = TRUE to get the complete format with date/version info that provides authority to your reprex.


**RStudio Users**: Use the reprex addin for faster creation:
- Install reprex: `install.packages("reprex")`
- Go to `Addins` โ†’ Search "reprex" โ†’ Select "Render reprex..."
- Copy code โ†’ Use addin โ†’ Check "Append session info" โ†’ Render

**Workflow Logic**: 
- Lint first to identify all style issues
- Style second to automatically fix what can be fixed
- Update documentation third if any roxygen2 comments were changed
- Build and test last to validate everything works together

## Troubleshooting

### "The package installation is taking a long time"
- **Cause**: Installing too many suggested packages instead of only the ones needed for the current function
- **Solution**: Follow the targeted installation approach - only install packages specifically required by the function you're modifying
- **Prevention**: Always use `grep -A2 -B2 "rlang::check_installed" R/[function_file].R` to identify minimal dependencies first

### "Could not find function" Errors
- **Cause**: Package not loaded or installed
- **Solution**: Run `R CMD build . && R CMD INSTALL report_*.tar.gz` then `library(report)`

### Package Installation "lib is not writable" Errors
- **Cause**: R attempting to install packages to system library (`/usr/local/lib/R/site-library`) instead of user library when custom setup doesn't run
- **Symptoms**: Warnings like `'lib = "/usr/local/lib/R/site-library"' is not writable` during package installation
- **Root Cause**: User library directory not properly configured or `.libPaths()[1]` pointing to system directory
- **Complete Solution**: 
  1. Set up user library first: `mkdir -p ~/R/library && echo 'R_LIBS_USER=~/R/library' >> ~/.Renviron`
  2. Use explicit library path: `install.packages("package", lib = "~/R/library", repos="...")`
  3. Alternatively, restart R session after step 1 and then use: `install.packages("package", lib = .libPaths()[1], repos="...")`
- **Prevention**: All install.packages calls in these instructions now include the `lib = .libPaths()[1]` parameter, but you must set up user library directory first
- **Note**: This issue occurs when the pre-configured environment setup doesn't run and R defaults to system library locations

### Missing Package Errors
- **Cause**: Suggested packages not installed
- **Solution**: Install via `sudo apt install r-cran-[package]` or ignore if testing core functionality

### Network/CRAN Access Issues  
- **Cause**: Blocked network access to CRAN mirrors
- **Solution**: Use system packages via apt or skip optional package tests

### Test Snapshot Failures
- **Cause**: Minor precision differences in numerical results (normal)
- **Solution**: Review changes, accept if precision differences are minor: `testthat::snapshot_accept()`

### Build Failures
- **Cause**: Syntax errors, missing dependencies, or file issues
- **Solution**: Check specific error messages, ensure DESCRIPTION is correct, verify all R files have valid syntax

### Styler Not Available
- **Cause**: styler package not installed
- **Solution**: Install via R: `R --no-restore --no-save -e 'install.packages("styler", lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))'` or skip styling step if not critical

### Roxygen2 Not Available
- **Cause**: roxygen2 package not installed
- **Solution**: Install via R: `R --no-restore --no-save -e 'install.packages("roxygen2", lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))'` or use devtools: `R --no-restore --no-save -e 'devtools::document()'`

### Documentation Build Failures
- **Cause**: Documentation not updated after changing roxygen2 comments
- **Solution**: Run `R --no-restore --no-save -e 'roxygen2::document()'` before building the package

### Global Variable Binding Warnings ("no visible binding")
- **Cause**: Using bare variable names in dplyr/ggplot2 operations instead of proper notation
- **Solution**: Replace with `.data[[variable_name]]` notation and add proper `@importFrom` statements
- **Example**: Change `group_by(var)` to `group_by(.data[[var]])`
- **DO NOT**: Create `global_variables.R` files with `utils::globalVariables()`

### Lintr CI vs Local Discrepancies (CRITICAL VERSION ISSUE)
- **Cause**: CI uses development lintr (`r-lib/lintr`) while local uses CRAN stable (`r-cran-lintr`)
- **Symptoms**: Local lintr passes but CI lintr fails with stricter rules
- **Root issue**: Development lintr has stricter rules and different function preferences
- **Solution**: Always install development lintr to match CI. Priority order: r-universe first, then remotes fallback:
  ```bash
  # Install development lintr to match CI - check if already installed first
  R --no-restore --no-save -e '
  if (!requireNamespace("lintr", quietly = TRUE)) {
    # Set GitHub token if available to avoid rate limits (use GH_PAT directly)
    if (Sys.getenv("GH_PAT") != "") {
      Sys.setenv(GITHUB_PAT = Sys.getenv("GH_PAT"))
    }
    # Priority order: r-universe FIRST, then remotes as fallback
    # Based on testing with whitelisted r-lib.r-universe.dev and cdn.r-universe.dev: both r-universe and remotes work successfully
    tryCatch({
      # FIRST PRIORITY: Try r-universe installation
      install.packages("lintr", lib = .libPaths()[1], repos=c("https://r-lib.r-universe.dev", "https://cloud.r-project.org"))
      cat("SUCCESS: r-universe installation worked\n")
    }, error = function(e1) {
      cat("r-universe installation failed, trying remotes...\n")
      tryCatch({
        # FALLBACK: Use remotes for development lintr installation
        if (!requireNamespace("remotes", quietly = TRUE)) {
          install.packages("remotes", lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))
        }
        remotes::install_github("r-lib/lintr")
        cat("SUCCESS: remotes installation worked\n")
      }, error = function(e2) {
        cat("CRITICAL ERROR: Cannot install development lintr from any source\n")
        cat("Tried: 1) r-universe (failed), 2) remotes (failed)\n")
        cat("This is required for proper linting that matches CI environment.\n")
        cat("COPILOT MUST STOP and report this issue in the PR.\n")
        cat("User must resolve lintr installation before continuing.\n")
        stop("Development lintr installation failed - cannot proceed")
      })
    })
  } else {
    cat("Development lintr already installed. Version:", as.character(packageVersion("lintr")), "\n")
  }
  '
  • Testing: Use exact CI configuration for local validation:
    R --no-restore --no-save -e 'library(lintr); lint_package(linters = all_linters(
      coalesce_linter = NULL, absolute_path_linter = NULL, cyclocomp_linter(40L), 
      if_not_else_linter(exceptions = character(0L)), indentation_linter = NULL, 
      implicit_integer_linter = NULL, library_call_linter = NULL, 
      line_length_linter(120L), namespace_linter = NULL, nonportable_path_linter = NULL,
      object_length_linter(50L), object_name_linter = NULL, object_usage_linter = NULL,
      one_call_pipe_linter = NULL, todo_comment_linter = NULL, commented_code_linter = NULL,
      undesirable_function_linter(c("mapply" = NA, "setwd" = NA)), undesirable_operator_linter = NULL,
      unnecessary_concatenation_linter(allow_single_expression = FALSE), unused_import_linter = NULL
    ))'
    
  • R Version Compatibility: Always check the minimum R version in DESCRIPTION file (Depends: R (>= X.X)) to ensure functions used are available in the minimum supported version. Do not use functions introduced in later R versions.

Documentation Mismatch Warnings ("Codoc mismatches")

  • Cause: Function parameter names don't match the documentation
  • Solution: Ensure @param parameter_name exactly matches function arguments
  • Prevention: Always run roxygen2::document() after changing function signatures

CRAN/Network Access Blocked

  • Cause: Cannot install packages from CRAN mirrors
  • Solutions:
    • Use system packages: sudo apt install r-cran-[package]
    • Try R-universe (FIRST PRIORITY): repos=c("https://r-universe.dev", "https://cloud.r-project.org")
    • Use remotes for GitHub packages (SECOND PRIORITY): remotes::install_github("[author]/[package]")

reprex Package Issues and Complete Debugging Guide

CRITICAL SOLUTION: The main issues with reprex are missing dependencies and environment variables.

NEW: In the pre-configured environment (copilot-setup-steps.yml), all reprex dependencies are now pre-installed: pandoc, knitr, rmarkdown, clipr. If you're using the pre-configured environment, skip to Step 3 (Set Environment Variables).

For manual setup or debugging: Follow this complete debugging guide:

Step 1: Install Required Dependencies

# Install core dependencies first
sudo apt install -y pandoc
R --no-restore --no-save -e 'install.packages(c("knitr", "rmarkdown"), lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))'

Step 2: Install reprex Package

# Multi-method installation
R --no-restore --no-save -e '
if (!requireNamespace("reprex", quietly = TRUE)) {
  tryCatch({
    install.packages("reprex", lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))
  }, error = function(e1) {
    tryCatch({
      install.packages("reprex", lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))
    }, error = function(e2) {
      if (!requireNamespace("remotes", quietly = TRUE)) {
        install.packages("remotes", lib = .libPaths()[1], repos=c("https://r-universe.dev", "https://cloud.r-project.org"))
      }
      remotes::install_github("tidyverse/reprex")
    })
  })
}
'

Step 3: Set Environment Variables (CRITICAL)

# ESSENTIAL: Set clipboard environment variable to prevent crashes
export CLIPR_ALLOW=TRUE

Step 4: Test reprex with Simple Example

export CLIPR_ALLOW=TRUE && R --no-restore --no-save -e '
library(reprex)

# Test basic functionality
result <- reprex({
  x <- 1:5
  mean(x)
}, venue = "gh", advertise = FALSE, html_preview = FALSE)

cat("SUCCESS: Basic reprex working\n")
cat(result, sep = "\n")
'

Step 5: Test reprex with report Functions

export CLIPR_ALLOW=TRUE && R --no-restore --no-save -e '
library(reprex)

# Working reprex example with report
result <- reprex({
  library(report)
  data(mtcars)
  
  # Example model reporting
  model <- lm(mpg ~ wt + hp, data = mtcars)
  result <- report(model)
  print(result)
  
}, venue = "gh", advertise = FALSE, html_preview = FALSE)

cat("SUCCESS: report reprex working\n")
cat(result, sep = "\n")
'

Common Error Solutions:

Error: "This reprex appears to crash R"

  • Cause: CLIPR_ALLOW not set or missing dependencies
  • Solution: Set export CLIPR_ALLOW=TRUE and install pandoc, knitr, rmarkdown

Error: "CLIPR_ALLOW has not been set"

  • Cause: Missing environment variable
  • Solution: Always run export CLIPR_ALLOW=TRUE before using reprex

Plot Rendering Issues

  • Cause: Complex ggplot objects cause crashes in reprex rendering
  • Solution: For plots, keep examples simple or use ggsave() to save plots separately
  • Workaround: Document plot creation without displaying the plot object in reprex

Verified Working Example Template

# ALWAYS use this pattern for report reprex:
export CLIPR_ALLOW=TRUE
library(reprex)

result <- reprex({
  library(report)
  
  # Your report example here
  # Keep it simple, avoid complex plots in reprex
  
}, venue = "gh", advertise = FALSE, html_preview = FALSE)

Common Reference Information

The following are outputs from frequently used commands. Reference them instead of running bash commands to save time.

Repository Root Structure

ls -la /home/runner/work/report/report/

.Rbuildignore       - Files to exclude from package build
.github/            - GitHub workflows and actions
.gitignore          - Git ignore patterns
DESCRIPTION         - Package metadata and dependencies
LICENSE             - Package license (MIT)
LICENSE.md          - License details
NAMESPACE           - Package exports (auto-generated)
NEWS.md             - Change log
R/                  - R source code (60+ files)
README.Rmd          - Source for README (edit this, not README.md)
README.md           - Main repository documentation
cran-comments.md    - CRAN submission notes
inst/               - Package installation files
man/                - Help documentation (auto-generated)
paper/              - Academic paper materials
pkgdown/            - Documentation site configuration
tests/              - Test files (testthat framework)
vignettes/          - R Markdown tutorials

Core R Functions by File

R/report.R           - Main report() generic function
R/report.lm.R        - Linear model reporting
R/report.aov.R       - ANOVA reporting
R/report.htest.R     - Statistical test reporting
R/report_sample.R    - Sample description reporting
R/report_parameters.R - Parameter reporting
R/report_performance.R - Model performance reporting
R/format_*.R         - Text formatting utilities
R/cite_easystats.R   - Citation utilities

Code Quality Examples

CORRECT: Proper Variable Referencing and Imports

# In report functions - USE proper imports and namespacing:
#' @importFrom insight get_parameters
#' @importFrom bayestestR describe_posterior
#' @importFrom effectsize effectsize

# Always include proper imports for external functions:
#' @importFrom stats lm
#' @importFrom utils head

INCORRECT: Missing Imports (Causes CI Failures)

# DO NOT: Use functions without proper imports
get_parameters(model)  # Should be insight::get_parameters or use @importFrom

# DO NOT: Missing namespace declarations
describe_posterior(model)  # Should have @importFrom bayestestR describe_posterior

CI/CD Integration

The package uses GitHub Actions with these workflows:

  • R-CMD-check: Multi-platform testing (Ubuntu, macOS, Windows)
  • lint-changed-files: Code style checking with lintr (only on changed files - efficient!)
  • test-coverage: Code coverage reporting with covr
  • pkgdown: Documentation website generation

Centralized Workflow System: The easystats organization uses a centralized workflow system at easystats/workflows that all repositories reference. This ensures consistency and automatically keeps all packages up-to-date with the latest organization standards without manual maintenance.

These workflows run automatically on pushes and pull requests to main/master branches.

Ensuring CI Workflows Pass on First Try

CRITICAL: Follow these guidelines to prevent CI failures:

1. Global Variable Binding Prevention

  • Always use .data[[variable_name]] in dplyr operations
  • Always add @importFrom package function for external functions
  • Never create global_variables.R files with utils::globalVariables()
  • Test locally: R CMD check should show no "no visible binding" warnings

2. Documentation Consistency Validation

  • Always ensure parameter names in @param match function arguments exactly
  • Always run roxygen2::document() after changing function signatures
  • Test locally: Look for "Codoc mismatches" warnings during build

3. Package Installation Strategy

When packages can't be installed from CRAN:

  • Primary: Use system packages via sudo apt install r-cran-[package]
  • Alternative (FIRST PRIORITY): Use R-universe repository: repos=c("https://r-universe.dev", "https://cloud.r-project.org")
  • Fallback (SECOND PRIORITY): Use remotes for GitHub packages: remotes::install_github("[author]/[package]")

4. Pre-Commit Validation Checklist

Before making any PR, verify locally:

# Must show ZERO "no visible binding" warnings:
R CMD check report_*.tar.gz 2>&1 | grep -i "binding"

# Must show ZERO "Codoc mismatches" warnings:  
R CMD check report_*.tar.gz 2>&1 | grep -i "codoc"

# All tests must pass (expected number varies):
R --no-restore --no-save -e 'library(testthat); library(report); test_local()'

5. PR Description Requirements

CRITICAL: Always include reprexes in PR descriptions to demonstrate code changes:

# Create examples showing before/after behavior:
library(report)
data(mtcars)

# BEFORE (if modifying existing function):
# [show current behavior]

# AFTER (with your changes):
# [show improved behavior]

Performance Notes

  • Package build: ~19 seconds
  • Package install: ~3 seconds
  • Test suite: ~15 seconds (varies based on enabled tests)
  • Linting: ~20 seconds (normal for existing codebase)
  • Code styling: ~10-30 seconds depending on package size
  • Documentation update: ~5-15 seconds (roxygen2)
  • R CMD check: ~30 seconds (without suggested packages), 2-5 minutes (full check)
  • Function loading after install: Near instant
  • Package installation: 1-5 seconds per package (targeted) vs 2-10 minutes (batch installation of all suggested packages)

CRITICAL: Never cancel builds or tests prematurely. Always wait for completion and set appropriate timeouts (60+ seconds for builds, 30+ seconds for tests, 10+ minutes for R CMD check).

PACKAGE INSTALLATION: Use targeted installation (install only what the specific function needs) to avoid "The package installation is taking a long time" messages. Installing all 15+ suggested packages takes 2-10 minutes; installing 1-3 specific packages takes 1-5 seconds each.

Trust

Not scanned yet. Artifacts are graded after they are crawled, so a recently discovered one may have no result for a while.

Versions

  • git-15f06163599d2026-08-04