feat(best_practice): add code quality scanning and commit message validation
- Implemented a code quality scanner that checks for common clean-code violations in Rust source files, including missing documentation, usage of `.unwrap()` in production code, and commented-out code. - Introduced a commit message validator that follows the Conventional Commits specification, ensuring proper formatting and providing suggestions for invalid messages. - Created a unified BestPracticeEngine to encapsulate the functionalities of skills, architecture audits, code quality checks, and commit message validation. - Added tests for both the code quality scanner and commit message validator to ensure reliability and correctness.
This commit is contained in:
1 parent
55677dd671
commit
8ecc588a3e
20 files changed
+3449
No files matched your search
@@ -0,0 +1,152 @@
|
||||
//! Embedding Kana Engineering best-practice skills as compiled-in static assets.
|
||||
//!
|
||||
//! Skill markdown files from `apps/infrastructure/skills/` are embedded at
|
||||
//! compile time via `include_dir!` and served through [`EmbeddedSkills`].
|
||||
//!
|
||||
//! # Flow
|
||||
//!
|
||||
//! `EmbeddedSkills::load()` reads the compile-time directory tree → indexes
|
||||
//! every `SKILL.md` by its parent directory name → exposes lookup / listing.
|
||||
|
||||
use include_dir::{include_dir, Dir, DirEntry};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// The compile-time-embedded skills directory tree.
|
||||
static SKILLS_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/skills");
|
||||
|
||||
/// Index of embedded best-practice skills, built once at startup.
|
||||
///
|
||||
/// Each skill is identified by its directory name (e.g. `"clean-code"`) and
|
||||
/// its content is the full text of `SKILL.md` within that directory.
|
||||
pub struct EmbeddedSkills {
|
||||
skills: HashMap<&'static str, &'static str>,
|
||||
}
|
||||
|
||||
impl EmbeddedSkills {
|
||||
/// Walk the embedded directory tree and build the skill index.
|
||||
///
|
||||
/// Flow: iterate `Dir::entries()` → find every `SKILL.md` file →
|
||||
/// store `(parent_dir_name, file_contents)` in the map.
|
||||
pub fn load() -> Self {
|
||||
let mut skills: HashMap<&str, &str> = HashMap::new();
|
||||
|
||||
fn walk<'a>(dir: &Dir<'a>, skills: &mut HashMap<&'a str, &'a str>) {
|
||||
for entry in dir.entries() {
|
||||
match entry {
|
||||
DirEntry::Dir(sub) => walk(sub, skills),
|
||||
DirEntry::File(file) => {
|
||||
if file.path().file_name().map_or(false, |n| n == "SKILL.md") {
|
||||
if let Some(parent) = file
|
||||
.path()
|
||||
.parent()
|
||||
.and_then(|p| p.file_name())
|
||||
.and_then(|n| n.to_str())
|
||||
{
|
||||
if let Some(content) = file.contents_utf8() {
|
||||
skills.entry(parent).or_insert(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
walk(&SKILLS_DIR, &mut skills);
|
||||
EmbeddedSkills { skills }
|
||||
}
|
||||
|
||||
/// Return the full `SKILL.md` content for a named skill, if present.
|
||||
pub fn get(&self, name: &str) -> Option<&'static str> {
|
||||
self.skills.get(name).copied()
|
||||
}
|
||||
|
||||
/// List all available skill names.
|
||||
pub fn list(&self) -> Vec<&'static str> {
|
||||
let mut names: Vec<&str> = self.skills.keys().copied().collect();
|
||||
names.sort();
|
||||
names
|
||||
}
|
||||
|
||||
/// Return an iterator of `(name, trimmed_description)` pairs.
|
||||
///
|
||||
/// Description is extracted from the YAML frontmatter `description:` field.
|
||||
pub fn summaries(&self) -> Vec<(&'static str, &'static str)> {
|
||||
let mut out: Vec<(&str, &str)> = Vec::new();
|
||||
for name in self.list() {
|
||||
let content = self.skills.get(name).copied().unwrap_or("");
|
||||
let desc = Self::extract_description(content).unwrap_or("");
|
||||
out.push((name, desc));
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// Extract the `description:` field from YAML frontmatter.
|
||||
fn extract_description(content: &str) -> Option<&str> {
|
||||
let lines: Vec<&str> = content.lines().collect();
|
||||
if lines.first()? != &"---" {
|
||||
return None;
|
||||
}
|
||||
for line in &lines[1..] {
|
||||
if let Some(rest) = line.strip_prefix("description: ") {
|
||||
return Some(rest.trim());
|
||||
}
|
||||
if line == &"---" {
|
||||
break;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn embedded_skills_loads_known_skills() {
|
||||
let skills = EmbeddedSkills::load();
|
||||
let names = skills.list();
|
||||
assert!(
|
||||
names.contains(&"clean-code"),
|
||||
"expected clean-code skill, got {names:?}"
|
||||
);
|
||||
assert!(
|
||||
names.contains(&"commit-convention"),
|
||||
"expected commit-convention skill, got {names:?}"
|
||||
);
|
||||
assert!(
|
||||
names.contains(&"kana-rust-backend-best-practice"),
|
||||
"expected kana-rust-backend-best-practice skill, got {names:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn each_skill_has_content() {
|
||||
let skills = EmbeddedSkills::load();
|
||||
for name in skills.list() {
|
||||
let content = skills.get(name);
|
||||
assert!(content.is_some(), "skill '{name}' has no content");
|
||||
assert!(
|
||||
content.unwrap().len() > 50,
|
||||
"skill '{name}' content suspiciously short"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_skill_returns_none() {
|
||||
let skills = EmbeddedSkills::load();
|
||||
assert!(skills.get("nonexistent-skill").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn summaries_include_all_skills() {
|
||||
let skills = EmbeddedSkills::load();
|
||||
let summaries = skills.summaries();
|
||||
assert_eq!(summaries.len(), skills.list().len());
|
||||
for (name, desc) in &summaries {
|
||||
assert!(!desc.is_empty(), "skill '{name}' has empty description");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user