use std::fs;
use crate::errors::CliError;
pub const TEMPLATES: &[&str] = &["github", "gitlab", "circleci"];
#[doc(hidden)]
pub fn run(template: &str, output: Option<&str>, list: bool, use_binary: bool) -> Result<(), CliError> {
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(use_binary),
"gitlab" | "gl" | "gitlab-ci" => gitlab_ci_template(use_binary),
"circleci" | "circle" => circleci_template(use_binary),
_ => return Err(CliError::Input(format!(
"Unknown template: '{}'. Available: {}",
template,
TEMPLATES.join(", ")
))),
};
match output {
Some(path) => {
fs::write(path, &content).map_err(|e| CliError::Input(format!("Failed to write {}: {}", path, e)))?;
println!("Template written to {}", path);
}
None => {
print!("{}", content);
}
}
Ok(())
}
fn github_actions_template(use_binary: bool) -> String {
let install_step = if use_binary {
r#" - name: Install zenv
run: |
curl -fsSL https://github.com/zorl-engine/zorath-env/releases/latest/download/zenv-linux-x64.tar.gz | tar xz
sudo mv zenv /usr/local/bin/"#
} else {
r#" - name: Install zenv
run: cargo install zorath-env"#
};
format!(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: 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
"#, if use_binary { " --use-binary" } else { "" }, install_step)
}
fn gitlab_ci_template(use_binary: bool) -> String {
let install_script = if use_binary {
r#" - curl -fsSL https://github.com/zorl-engine/zorath-env/releases/latest/download/zenv-linux-x64.tar.gz | tar xz
- mv zenv /usr/local/bin/"#
} else {
" - cargo install zorath-env"
};
let image = if use_binary { "alpine:latest" } else { "rust:latest" };
let extra_deps = if use_binary { "\n - apk add --no-cache curl" } else { "" };
format!(r#"# .gitlab-ci.yml
# Generated by zenv template gitlab{}
stages:
- validate
validate-env:
stage: validate
image: {}
before_script:{}
{}
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: {}
# before_script:{}
#{}
# script:
# - zenv docs > ENVIRONMENT.md
# artifacts:
# paths:
# - ENVIRONMENT.md
"#, if use_binary { " --use-binary" } else { "" }, image, extra_deps, install_script, image, extra_deps, install_script)
}
fn circleci_template(use_binary: bool) -> String {
if use_binary {
r#"# .circleci/config.yml
# Generated by zenv template circleci --use-binary
version: 2.1
executors:
alpine:
docker:
- image: alpine:latest
jobs:
validate-env:
executor: alpine
steps:
- checkout
- run:
name: Install dependencies
command: apk add --no-cache curl
- run:
name: Install zenv
command: |
curl -fsSL https://github.com/zorl-engine/zorath-env/releases/latest/download/zenv-linux-x64.tar.gz | tar xz
mv zenv /usr/local/bin/
- run:
name: Validate .env
command: zenv check --allow-missing-env
workflows:
version: 2
validate:
jobs:
- validate-env:
filters:
branches:
only:
- main
- develop
"#.to_string()
} else {
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(false);
assert!(template.contains("name: Validate Environment"));
assert!(template.contains("zenv check"));
assert!(template.contains("cargo install zorath-env"));
}
#[test]
fn test_github_template_binary_mode() {
let template = github_actions_template(true);
assert!(template.contains("name: Validate Environment"));
assert!(template.contains("zenv check"));
assert!(template.contains("curl -fsSL"));
assert!(!template.contains("cargo install"));
}
#[test]
fn test_gitlab_template_contains_stages() {
let template = gitlab_ci_template(false);
assert!(template.contains("stages:"));
assert!(template.contains("validate-env:"));
assert!(template.contains("cargo install zorath-env"));
}
#[test]
fn test_gitlab_template_binary_mode() {
let template = gitlab_ci_template(true);
assert!(template.contains("stages:"));
assert!(template.contains("validate-env:"));
assert!(template.contains("curl -fsSL"));
assert!(template.contains("alpine:latest"));
}
#[test]
fn test_circleci_template_contains_jobs() {
let template = circleci_template(false);
assert!(template.contains("version: 2.1"));
assert!(template.contains("validate-env:"));
assert!(template.contains("cargo install zorath-env"));
}
#[test]
fn test_circleci_template_binary_mode() {
let template = circleci_template(true);
assert!(template.contains("version: 2.1"));
assert!(template.contains("validate-env:"));
assert!(template.contains("curl -fsSL"));
assert!(template.contains("alpine:latest"));
}
#[test]
fn test_run_list_templates() {
let result = run("", None, true, false);
assert!(result.is_ok());
}
#[test]
fn test_run_unknown_template() {
let result = run("unknown", None, false, false);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Unknown template"));
}
#[test]
fn test_template_aliases() {
let gh = run("gh", None, false, false);
assert!(gh.is_ok());
let gl = run("gl", None, false, false);
assert!(gl.is_ok());
let circle = run("circle", None, false, false);
assert!(circle.is_ok());
}
}