Skip to content

Commit b8fad53

Browse files
luiseimanclaude
andcommitted
feat: v2.2.0 — CI/CD pipeline + rules linter
GitHub Actions workflow validates: hook syntax (bash -n), hook permissions (chmod +x), YAML files (registry, sources, metrics), rules frontmatter (globs: required), stack completeness (rules/ + settings.json.partial), skill completeness (SKILL.md), benchmark tasks (id, stack, prompt), and version consistency (VERSION vs plugin.json). New: tests/lint-rules.sh for local rule validation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6fe4825 commit b8fad53

5 files changed

Lines changed: 170 additions & 2 deletions

File tree

.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "claude-kit",
3-
"version": "2.0.0",
3+
"version": "2.2.0",
44
"description": "Configuration factory for Claude Code — templates, stacks, hooks, rules, and audit tools",
55
"author": "luiseiman",
66
"license": "MIT",

.github/workflows/ci.yml

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
validate:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Validate hook syntax (bash -n)
16+
run: |
17+
echo "── Hook Syntax ──"
18+
ERRORS=0
19+
for f in template/hooks/*.sh stacks/*/hooks/*.sh hooks/*.sh; do
20+
[ -f "$f" ] || continue
21+
if bash -n "$f" 2>&1; then
22+
echo "✓ $f"
23+
else
24+
echo "✗ $f"
25+
ERRORS=$((ERRORS + 1))
26+
fi
27+
done
28+
echo ""
29+
echo "Checked: $(find template/hooks stacks/*/hooks hooks -name '*.sh' 2>/dev/null | wc -l) files"
30+
[ $ERRORS -eq 0 ] || exit 1
31+
32+
- name: Validate hook permissions
33+
run: |
34+
echo "── Hook Permissions ──"
35+
ERRORS=0
36+
for f in template/hooks/*.sh stacks/*/hooks/*.sh hooks/*.sh; do
37+
[ -f "$f" ] || continue
38+
if [ -x "$f" ]; then
39+
echo "✓ $f"
40+
else
41+
echo "✗ $f (not executable)"
42+
ERRORS=$((ERRORS + 1))
43+
fi
44+
done
45+
[ $ERRORS -eq 0 ] || exit 1
46+
47+
- name: Validate YAML files
48+
run: |
49+
echo "── YAML Validation ──"
50+
python3 -c "import yaml; yaml.safe_load(open('registry/projects.yml')); print('✓ registry/projects.yml')"
51+
python3 -c "import yaml; yaml.safe_load(open('practices/sources.yml')); print('✓ practices/sources.yml')"
52+
python3 -c "import yaml; yaml.safe_load(open('practices/metrics.yml')); print('✓ practices/metrics.yml')"
53+
54+
- name: Validate rules frontmatter
55+
run: |
56+
echo "── Rules Frontmatter ──"
57+
bash tests/lint-rules.sh
58+
59+
- name: Validate stack completeness
60+
run: |
61+
echo "── Stack Completeness ──"
62+
ERRORS=0
63+
for d in stacks/*/; do
64+
[ -f "${d}detect.md" ] && continue # skip detect.md metadata file
65+
STACK=$(basename "$d")
66+
MISSING=""
67+
[ -d "${d}rules" ] || MISSING="rules/"
68+
[ -f "${d}settings.json.partial" ] || MISSING="$MISSING settings.json.partial"
69+
if [ -n "$MISSING" ]; then
70+
echo "✗ $STACK — missing: $MISSING"
71+
ERRORS=$((ERRORS + 1))
72+
else
73+
echo "✓ $STACK"
74+
fi
75+
done
76+
[ $ERRORS -eq 0 ] || exit 1
77+
78+
- name: Validate skill completeness
79+
run: |
80+
echo "── Skill Completeness ──"
81+
ERRORS=0
82+
for d in skills/*/; do
83+
SKILL=$(basename "$d")
84+
if [ ! -f "${d}SKILL.md" ]; then
85+
echo "✗ $SKILL — missing SKILL.md"
86+
ERRORS=$((ERRORS + 1))
87+
else
88+
echo "✓ $SKILL"
89+
fi
90+
done
91+
[ $ERRORS -eq 0 ] || exit 1
92+
93+
- name: Validate benchmark tasks
94+
run: |
95+
echo "── Benchmark Tasks ──"
96+
python3 -c "
97+
import yaml, glob, sys
98+
errors = 0
99+
for f in sorted(glob.glob('tests/benchmark-tasks/*.yml')):
100+
try:
101+
data = yaml.safe_load(open(f))
102+
assert 'id' in data, 'missing id'
103+
assert 'stack' in data, 'missing stack'
104+
assert 'prompt' in data, 'missing prompt'
105+
print(f'✓ {f}')
106+
except Exception as e:
107+
print(f'✗ {f}: {e}')
108+
errors += 1
109+
sys.exit(errors)
110+
"
111+
112+
- name: Version consistency check
113+
run: |
114+
echo "── Version Consistency ──"
115+
VERSION=$(cat VERSION | tr -d '[:space:]')
116+
echo "VERSION file: $VERSION"
117+
118+
PLUGIN_VERSION=$(python3 -c "import json; print(json.load(open('.claude-plugin/plugin.json'))['version'])")
119+
echo "plugin.json: $PLUGIN_VERSION"
120+
121+
if [ "$VERSION" != "$PLUGIN_VERSION" ]; then
122+
echo "✗ Version mismatch: VERSION=$VERSION, plugin.json=$PLUGIN_VERSION"
123+
exit 1
124+
fi
125+
echo "✓ Versions match"

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.1.0
1+
2.2.0

docs/changelog.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@
44
>
55
> Historial de versiones. Las entradas usan español/inglés mixto según la evolución del proyecto. Los términos técnicos son universales.
66
7+
## v2.2.0 (2026-03-20)
8+
9+
### CI/CD + Quality
10+
- Nuevo: GitHub Actions CI workflow — validates hooks (bash -n + permissions), YAML files, rules frontmatter, stack completeness, skill completeness, benchmark tasks, version consistency
11+
- Nuevo: `tests/lint-rules.sh` — validates all rule .md files have `globs:` frontmatter
12+
- Fix: plugin.json version synced to VERSION file (CI catches mismatches)
13+
14+
---
15+
716
## v2.1.0 (2026-03-20)
817

918
### Making it real

tests/lint-rules.sh

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/bin/bash
2+
# Validate that all rule .md files have proper frontmatter
3+
# Exit 0 = all pass, exit 1 = failures found
4+
5+
ERRORS=0
6+
CHECKED=0
7+
8+
for rule_file in template/rules/*.md stacks/*/rules/*.md; do
9+
[ -f "$rule_file" ] || continue
10+
CHECKED=$((CHECKED + 1))
11+
BASENAME=$(basename "$rule_file")
12+
13+
# _common.md uses globs: "**/*" which is valid
14+
# All rules must have frontmatter with globs:
15+
HAS_FRONTMATTER=$(head -1 "$rule_file" | grep -c "^---$")
16+
if [ "$HAS_FRONTMATTER" -eq 0 ]; then
17+
echo "$rule_file — missing frontmatter (no opening ---)"
18+
ERRORS=$((ERRORS + 1))
19+
continue
20+
fi
21+
22+
HAS_GLOBS=$(sed -n '/^---$/,/^---$/p' "$rule_file" | grep -c "^globs:")
23+
if [ "$HAS_GLOBS" -eq 0 ]; then
24+
echo "$rule_file — missing globs: in frontmatter"
25+
ERRORS=$((ERRORS + 1))
26+
continue
27+
fi
28+
29+
echo "$rule_file"
30+
done
31+
32+
echo ""
33+
echo "Checked: $CHECKED rules, Errors: $ERRORS"
34+
[ $ERRORS -eq 0 ] || exit 1

0 commit comments

Comments
 (0)