refactor: streamline skills validation process in workflow and script

This commit is contained in:
Mohan Raj Rajamanickam 2026-03-11 14:31:16 -07:00
parent d2989fe74c
commit 6be1d8e4fc
No known key found for this signature in database
GPG Key ID: 7CE83B7611FA8B8B
2 changed files with 44 additions and 22 deletions

View File

@ -18,19 +18,4 @@ jobs:
- run: npm ci - run: npm ci
- name: Detect changed skill directories - run: npm run validate:skills -- --changed --base=origin/${{ github.base_ref }}
id: changed-skills
run: |
# Collect top-level skill dirs touched by this PR (relative to skills/).
# Passing explicit dirs means pre-existing nested skill categories
# (to be flattened in a separate PR) don't block unrelated skill PRs.
DIRS=$(git diff --name-only origin/${{ github.base_ref }}...HEAD \
| grep '^skills/' \
| cut -d'/' -f2 \
| sort -u \
| tr '\n' ' ')
echo "dirs=$DIRS" >> $GITHUB_OUTPUT
echo "Validating skill dirs: $DIRS"
- name: Validate changed skills
run: npx tsx scripts/validate-skills.ts ${{ steps.changed-skills.outputs.dirs }}

View File

@ -3,11 +3,13 @@
// Exits with code 1 if any violations are found. // Exits with code 1 if any violations are found.
// //
// Usage: // Usage:
// tsx scripts/validate-skills.ts # validate all skills // npm run validate:skills # validate all skills
// tsx scripts/validate-skills.ts apex-class # validate specific skill dirs // npm run validate:skills -- --changed --base=origin/main # validate only skills changed vs base
import { execSync } from "child_process"
import fs from "fs" import fs from "fs"
import path from "path" import path from "path"
import { parseArgs } from "util"
const SKILLS_DIR = path.join(__dirname, "..", "skills") const SKILLS_DIR = path.join(__dirname, "..", "skills")
@ -136,6 +138,23 @@ const CONTENT_CHECKS: ContentCheck[] = [
}, },
] ]
// ---------------------------------------------------------------------------
// Changed-skills detection
// ---------------------------------------------------------------------------
function getChangedSkillDirs(base: string): string[] {
const output = execSync(`git diff --name-only ${base}...HEAD`, { encoding: "utf8" })
return [
...new Set(
output
.split("\n")
.filter((f) => f.startsWith("skills/"))
.map((f) => f.split("/")[1])
.filter(Boolean)
),
]
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Helpers // Helpers
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -193,10 +212,28 @@ function validateSkill(dirName: string, dirPath: string): string[] {
} }
function main(): void { function main(): void {
// If skill dir names are passed as arguments, validate only those. const { values } = parseArgs({
// Otherwise validate all entries in skills/. args: process.argv.slice(2),
const targets = process.argv.slice(2) options: {
const entries = targets.length > 0 ? targets : fs.readdirSync(SKILLS_DIR) /** Validate only skill dirs touched in this branch vs the given base ref. */
changed: { type: "boolean", default: false },
/** Base ref for --changed (e.g. origin/main). Defaults to origin/HEAD. */
base: { type: "string", default: "origin/HEAD" },
},
})
let entries: string[]
if (values.changed) {
entries = getChangedSkillDirs(values.base!)
if (entries.length === 0) {
console.log("No skill directories changed — nothing to validate.")
return
}
console.log(`Validating ${entries.length} changed skill(s): ${entries.join(", ")}`)
} else {
entries = fs.readdirSync(SKILLS_DIR)
}
const allErrors: string[] = [] const allErrors: string[] = []
let passed = 0 let passed = 0