use std::path::{Path, PathBuf};
use anyhow::{Context, Result};
pub const GITHUB_WORKFLOW: &str = r#"# Killer security gate - generated by `killer github enable`.
name: Killer
on:
push:
branches: [main, master]
pull_request:
jobs:
killer:
name: Killer security gate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install Killer
run: cargo install --git https://github.com/martin-k-m/killer --locked || cargo install killer --locked
- name: Run Killer gate
run: killer ci --base "origin/${{ github.base_ref || 'main' }}"
"#;
pub const GITHUB_WORKFLOW_PATH: &str = ".github/workflows/killer.yml";
pub fn write_github_workflow(root: &Path, force: bool) -> Result<PathBuf> {
let path = root.join(GITHUB_WORKFLOW_PATH);
if path.exists() && !force {
anyhow::bail!(
"{} already exists (use --force to overwrite)",
path.display()
);
}
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)
.with_context(|| format!("failed to create {}", parent.display()))?;
}
std::fs::write(&path, GITHUB_WORKFLOW)
.with_context(|| format!("failed to write {}", path.display()))?;
Ok(path)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn workflow_mentions_killer_ci() {
assert!(GITHUB_WORKFLOW.contains("killer ci"));
assert!(GITHUB_WORKFLOW.contains("on:"));
}
#[test]
fn writes_and_guards_overwrite() {
let dir = tempfile::tempdir().unwrap();
let p = write_github_workflow(dir.path(), false).unwrap();
assert!(p.exists());
assert!(write_github_workflow(dir.path(), false).is_err());
assert!(write_github_workflow(dir.path(), true).is_ok());
}
}