zorath-env 0.3.7

Fast CLI for .env validation against JSON/YAML schemas. 14 types, secret detection, watch mode, remote schemas, export to shell/docker/k8s/json, health diagnostics, code scanning, auto-fix. CI-friendly. Language-agnostic single binary.
Documentation
//! CI/CD template generation for zenv validation workflows

use std::fs;

/// Available template names
pub const TEMPLATES: &[&str] = &["github", "gitlab", "circleci"];

/// Generate CI/CD template for the given platform
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(())
}

/// GitHub Actions workflow template
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()
}

/// GitLab CI template
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()
}

/// CircleCI config template
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() {
        // Test that aliases work
        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());
    }
}