gitkit 0.3.1

Standalone CLI for configuring git repos — hooks, .gitignore, and .gitattributes
pub(crate) struct Builtin {
    pub name: &'static str,
    pub hook: &'static str,
    pub description: &'static str,
    pub script: &'static str,
}

pub(crate) const ALL: &[Builtin] = &[
    Builtin {
        name: "conventional-commits",
        hook: "commit-msg",
        description: "Validates Conventional Commits format",
        script: CONVENTIONAL_COMMITS,
    },
    Builtin {
        name: "no-secrets",
        hook: "pre-commit",
        description: "Detects common secret patterns in staged changes",
        script: NO_SECRETS,
    },
    Builtin {
        name: "branch-naming",
        hook: "pre-commit",
        description: "Validates branch name matches convention",
        script: BRANCH_NAMING,
    },
];

pub(crate) fn get(name: &str) -> Option<&'static Builtin> {
    ALL.iter().find(|b| b.name == name)
}

const CONVENTIONAL_COMMITS: &str = r#"#!/bin/sh
commit_msg=$(cat "$1")
pattern='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?: .{1,}'
if ! echo "$commit_msg" | grep -qE "$pattern"; then
  echo "ERROR: Commit message does not follow Conventional Commits format."
  echo "Expected: <type>(<scope>): <description>"
  echo "Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert"
  exit 1
fi
"#;

const NO_SECRETS: &str = r#"#!/bin/sh
# Detects common secret patterns. Not exhaustive — use dedicated tools for production.
patterns='(AKIA[0-9A-Z]{16}|AIza[0-9A-Za-z_-]{35}|ghp_[0-9A-Za-z]{36}|sk-[0-9A-Za-z]{48}|password\s*=\s*["'"'"'][^"'"'"']{8,})'
if git diff --cached --diff-filter=ACM | grep -qE "$patterns"; then
  echo "ERROR: Possible secret detected in staged changes."
  echo "Review your changes and remove any credentials before committing."
  exit 1
fi
"#;

const BRANCH_NAMING: &str = r#"#!/bin/sh
branch=$(git symbolic-ref --short HEAD)
pattern='^(main|master|develop|release/.+|hotfix/.+|feat/.+|feature/.+|fix/.+|chore/.+)$'
if ! echo "$branch" | grep -qE "$pattern"; then
  echo "ERROR: Branch name '$branch' does not match naming convention."
  echo "Expected pattern: main|master|develop|release/*|hotfix/*|feat/*|feature/*|fix/*|chore/*"
  exit 1
fi
"#;