xtask_toolkit/precommit/
mod.rs1use minijinja::{Environment, context};
2
3pub const PRECOMMIT_TEMPLATE: &str = include_str!("precommit.py.j2");
4
5#[derive(Copy, Clone, Debug, serde::Deserialize, serde::Serialize)]
6pub struct Features {
7 pub cargo: bool,
8 pub taplo: bool,
9 pub gitleaks: bool,
10}
11
12impl Default for Features {
13 fn default() -> Self {
14 Self {
15 cargo: true,
16 taplo: true,
17 gitleaks: true,
18 }
19 }
20}
21
22#[derive(Debug, thiserror::Error)]
23pub enum PrecommitError {
24 #[error(transparent)]
25 JinjaError(#[from] minijinja::Error),
26
27 #[error(transparent)]
28 WriteError(#[from] std::io::Error),
29
30 #[error("Project root cannot be found")]
31 ProjectRootError,
32}
33
34impl From<xshell::Error> for PrecommitError {
35 fn from(_: xshell::Error) -> Self {
36 PrecommitError::ProjectRootError
37 }
38}
39
40pub fn install_precommit(features: Features) -> Result<(), PrecommitError> {
41 let mut env = Environment::new();
42 env.add_template("precommit", PRECOMMIT_TEMPLATE)?;
43 let tmpl = env.get_template("precommit")?;
44 let context = context!(
45 features => features,
46 );
47 let rendered = tmpl.render(context)?;
48
49 let root = crate::git::get_root_path()?;
50 let dest = root.join(".git").join("hooks").join("pre-commit");
51
52 std::fs::write(dest, rendered.as_bytes())?;
53
54 Ok(())
55}