use std::fs;
pub const TEMPLATES: &[&str] = &["github", "gitlab", "circleci"];
pub fn run(template: &str, output: Option<&str>, list: bool) -> Result<(), String> {
if list {
println!("Available templates:");
for name in TEMPLATES {
println!(" {}", name);
}
return Ok(());
}
let content = match template.to_lowercase().as_str() {
"github" | "gh" | "github-actions" => github_actions_template(),
"gitlab" | "gl" | "gitlab-ci" => gitlab_ci_template(),
"circleci" | "circle" => circleci_template(),
_ => return Err(format!(
"Unknown template: '{}'. Available: {}",
template,
TEMPLATES.join(", ")
)),
};
match output {
Some(path) => {
fs::write(path, &content).map_err(|e| format!("Failed to write {}: {}", path, e))?;
println!("Template written to {}", path);
}
None => {
print!("{}", content);
}
}
Ok(())
}
fn github_actions_template() -> String {
r#"# .github/workflows/env-validation.yml
# Generated by zenv template github
name: Validate Environment
on:
push:
paths:
- '.env*'
- 'env.schema.json'
- 'env.schema.yaml'
pull_request:
paths:
- '.env*'
- 'env.schema.json'
- 'env.schema.yaml'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install zenv
run: cargo install zorath-env
- name: Validate .env
run: zenv check --allow-missing-env
# Optional: Generate documentation
# - name: Generate docs
# run: zenv docs > ENVIRONMENT.md
# Optional: Check for secrets
# - name: Detect secrets
# run: zenv check --detect-secrets
"#.to_string()
}
fn gitlab_ci_template() -> String {
r#"# .gitlab-ci.yml
# Generated by zenv template gitlab
stages:
- validate
validate-env:
stage: validate
image: rust:latest
before_script:
- cargo install zorath-env
script:
- zenv check --allow-missing-env
rules:
- changes:
- .env*
- env.schema.json
- env.schema.yaml
# Optional: Generate documentation as artifact
# generate-docs:
# stage: validate
# image: rust:latest
# before_script:
# - cargo install zorath-env
# script:
# - zenv docs > ENVIRONMENT.md
# artifacts:
# paths:
# - ENVIRONMENT.md
"#.to_string()
}
fn circleci_template() -> String {
r#"# .circleci/config.yml
# Generated by zenv template circleci
version: 2.1
executors:
rust:
docker:
- image: cimg/rust:1.75
jobs:
validate-env:
executor: rust
steps:
- checkout
- run:
name: Install zenv
command: cargo install zorath-env
- run:
name: Validate .env
command: zenv check --allow-missing-env
workflows:
version: 2
validate:
jobs:
- validate-env:
filters:
branches:
only:
- main
- develop
"#.to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_github_template_contains_workflow() {
let template = github_actions_template();
assert!(template.contains("name: Validate Environment"));
assert!(template.contains("zenv check"));
}
#[test]
fn test_gitlab_template_contains_stages() {
let template = gitlab_ci_template();
assert!(template.contains("stages:"));
assert!(template.contains("validate-env:"));
}
#[test]
fn test_circleci_template_contains_jobs() {
let template = circleci_template();
assert!(template.contains("version: 2.1"));
assert!(template.contains("validate-env:"));
}
#[test]
fn test_run_list_templates() {
let result = run("", None, true);
assert!(result.is_ok());
}
#[test]
fn test_run_unknown_template() {
let result = run("unknown", None, false);
assert!(result.is_err());
assert!(result.unwrap_err().contains("Unknown template"));
}
#[test]
fn test_template_aliases() {
let gh = run("gh", None, false);
assert!(gh.is_ok());
let gl = run("gl", None, false);
assert!(gl.is_ok());
let circle = run("circle", None, false);
assert!(circle.is_ok());
}
}