tracel_xtask/
environment.rs1use strum::{Display, EnumIter, EnumString};
2
3use crate::group_info;
4
5#[derive(EnumString, EnumIter, Default, Display, Clone, PartialEq, clap::ValueEnum)]
6#[strum(serialize_all = "lowercase")]
7pub enum Environment {
8 #[default]
10 #[strum(serialize = "dev")]
11 #[clap(alias = "dev")]
12 Development,
13 #[strum(serialize = "stag")]
15 #[clap(alias = "stag")]
16 Staging,
17 #[strum(serialize = "test")]
19 #[clap(alias = "test")]
20 Test,
21 #[strum(serialize = "prod")]
23 #[clap(alias = "prod")]
24 Production,
25}
26
27impl Environment {
28 pub fn get_dotenv_filename(&self) -> String {
29 format!(".env.{self}")
30 }
31
32 pub fn get_dotenv_secrets_filename(&self) -> String {
33 format!("{}.secrets", self.get_dotenv_filename())
34 }
35
36 pub(crate) fn load(&self) -> anyhow::Result<()> {
37 let filename = self.get_dotenv_filename();
38 let secrets_filename = self.get_dotenv_secrets_filename();
39 if dotenvy::from_filename(".env").is_ok() {
40 group_info!("loading '.env' file...");
41 }
42 if dotenvy::from_filename(&filename).is_ok() {
43 group_info!("loading {filename} file...");
44 }
45 if dotenvy::from_filename(&secrets_filename).is_ok() {
46 group_info!("loading {secrets_filename} file...");
47 }
48 Ok(())
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use rstest::rstest;
56 use serial_test::serial;
57 use std::env;
58
59 fn expected_vars(env: &Environment) -> Vec<(String, String)> {
60 let suffix = match env {
61 Environment::Development => "DEV",
62 Environment::Staging => "STAG",
63 Environment::Test => "TEST",
64 Environment::Production => "PROD",
65 };
66
67 vec![
68 ("FROM_DOTENV".to_string(), ".env".to_string()),
69 (
70 format!("FROM_DOTENV_{suffix}").to_string(),
71 env.get_dotenv_filename(),
72 ),
73 (
74 format!("FROM_DOTENV_{suffix}_SECRETS").to_string(),
75 env.get_dotenv_secrets_filename(),
76 ),
77 ]
78 }
79
80 #[rstest]
81 #[case::dev(Environment::Development)]
82 #[case::stag(Environment::Staging)]
83 #[case::test(Environment::Test)]
84 #[case::prod(Environment::Production)]
85 #[serial]
86 fn test_environment_load(#[case] env: Environment) {
87 for (key, _) in expected_vars(&env) {
89 env::remove_var(key);
90 }
91
92 env.load().expect("Environment load should succeed");
94
95 for (key, expected_value) in expected_vars(&env) {
97 let actual_value =
98 env::var(&key).unwrap_or_else(|_| panic!("Missing expected env var: {key}"));
99 assert_eq!(
100 actual_value, expected_value,
101 "Environment variable {key} should be set to {expected_value} but was {actual_value}"
102 );
103 }
104 }
105}