
Managing Multiple Environments
Source:vignettes/multiple_environments.Rmd
multiple_environments.Rmd
Multiple Environment Configuration
Real-world projects typically need different configurations for development, quality assurance, and production environments. This guide shows you how to set up environment-specific configurations.
The Challenge
Consider this common workflow:
Development: Developers work with data to produce outputs
QA: Quality assurance independently confirms the results of the developer
Production: Verified data and final outputs are made available to
Each environment needs different paths, but you don’t want to change your code.
Environment-Specific Configuration
Here’s how to set up different configurations for each environment:
default:
paths:
data: "/demo/DEV/username/project1/data"
output: "/demo/DEV/username/project1/output"
programs: "/demo/DEV/username/project1/programs"
qa:
paths:
data: "/demo/QA/project1/data"
output: "/demo/QA/project1/output"
programs: "/demo/QA/project1/programs"
prod:
paths:
data: "/demo/PROD/project1/data"
output: "/demo/PROD/project1/output"
programs: "/demo/PROD/project1/programs"
Working Example
Let’s create a multi-environment configuration:
library(envsetup)
# Create temporary directory
dir <- fs::file_temp()
dir.create(dir)
config_path <- file.path(dir, "_envsetup.yml")
# Write multi-environment config
file_conn <- file(config_path)
writeLines(
paste0(
"default:
paths:
data: '", dir, "/demo/DEV/username/project1/data'
output: '", dir, "/demo/DEV/username/project1/output'
programs: '", dir, "/demo/DEV/username/project1/programs'
qa:
paths:
data: '", dir, "/demo/QA/project1/data'
output: '", dir, "/demo/QA/project1/output'
programs: '", dir, "/demo/QA/project1/programs'
prod:
paths:
data: '", dir, "/demo/PROD/project1/data'
output: '", dir, "/demo/PROD/project1/output'
programs: '", dir, "/demo/PROD/project1/programs'"
), file_conn)
close(file_conn)
Loading Different Environments
Default Environment
# Load default configuration (development)
envsetup_config <- config::get(file = config_path)
rprofile(envsetup_config)
#> Assigned paths to __callr_data__Assigned paths to R_GlobalEnv
# Check the paths
cat("Default environment paths:\n")
#> Default environment paths:
cat("Data:", get_path(data), "\n")
#> Data: /tmp/RtmpXmtg5B/file1e763e3c9c3f/demo/DEV/username/project1/data
cat("Output:", get_path(output), "\n")
#> Output: /tmp/RtmpXmtg5B/file1e763e3c9c3f/demo/DEV/username/project1/output
QA Environment
# Load QA configuration
envsetup_config <- config::get(file = config_path, config = "qa")
rprofile(envsetup_config)
#> Assigned paths to __callr_data__Assigned paths to R_GlobalEnv
# Check the paths
cat("QA environment paths:\n")
#> QA environment paths:
cat("Data:", get_path(data), "\n")
#> Data: /tmp/RtmpXmtg5B/file1e763e3c9c3f/demo/QA/project1/data
cat("Output:", get_path(output), "\n")
#> Output: /tmp/RtmpXmtg5B/file1e763e3c9c3f/demo/QA/project1/output
Production Environment
# Load production configuration
envsetup_config <- config::get(file = config_path, config = "prod")
rprofile(envsetup_config)
#> Assigned paths to __callr_data__Assigned paths to R_GlobalEnv
# Check the paths
cat("Production environment paths:\n")
#> Production environment paths:
cat("Data:", get_path(data), "\n")
#> Data: /tmp/RtmpXmtg5B/file1e763e3c9c3f/demo/PROD/project1/data
cat("Output:", get_path(output), "\n")
#> Output: /tmp/RtmpXmtg5B/file1e763e3c9c3f/demo/PROD/project1/output
Configuration Inheritance
The config
package supports inheritance, meaning
environments can inherit from default
and only override
specific settings:
default:
paths:
data: "/demo/DEV/username/project1/data"
output: "/demo/DEV/username/project1/output"
programs: "/demo/DEV/username/project1/programs"
log_level: "DEBUG"
prod:
paths:
data: "/demo/PROD/project1/data"
output: "/demo/PROD/project1/output"
log_level: "ERROR"
# programs inherits from default
Environment Selection Strategies
1. Environment Variable
# Set environment variable
Sys.setenv(R_CONFIG_ACTIVE = "prod")
envsetup_config <- config::get(file = "_envsetup.yml")
2. Programmatic Selection
# Choose environment in code
environment <- "prod"
envsetup_config <- config::get(file = "_envsetup.yml", config = environment)
Best Practices
-
Use
default
for development: Most development work happens here - Minimize environment differences: Only change what’s necessary
- Document environment purposes: Clear comments in your YAML
- Test all environments: Ensure configurations work as expected
-
Version control: Keep
_envsetup.yml
in your repository