feat(req-test-gate): 集成 Harness Engineering 工程约束方法论
将项目级的 Ratchet/约定检测方法论融入 req-test-gate 技能, 通过 /req 流程三个节点自动触发(dev 环境检测、cr 约定建议、test Gate 0B), 无需手动记忆执行。 新增文档:harness-engineering.md、ratchet-pattern.md、convention-flow.md、 project-bootstrap.md 及 4 个模板(ratchet/convention 脚本、GATES.md、pre-commit)。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
# Convention Detection Script Template
|
||||
|
||||
泛化的约定检测脚本模板,基于 new-ai-proj `check-modal-safety.sh` 提取。用于检测代码中违反编码约定的模式。
|
||||
|
||||
## 使用方法
|
||||
|
||||
1. 复制下方脚本到 `scripts/check-{NAME}.sh`
|
||||
2. 替换所有 `{PLACEHOLDER}` 为项目特定值
|
||||
3. 运行 `chmod +x scripts/check-{NAME}.sh`
|
||||
4. 验证:`./scripts/check-{NAME}.sh` 输出 PASSED
|
||||
|
||||
## 脚本模板
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# {CONVENTION_NAME} Check — detects {WHAT_IT_DETECTS} in {TARGET_SCOPE}.
|
||||
#
|
||||
# {PROBLEM_DESCRIPTION}
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/check-{NAME}.sh # Check and report
|
||||
# ./scripts/check-{NAME}.sh --ci # Exit code 1 on violations
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
TARGET_DIR="$(cd "$(dirname "$0")/../{TARGET_DIRECTORY}" && pwd)"
|
||||
CI_MODE=false
|
||||
[[ "${1:-}" == "--ci" ]] && CI_MODE=true
|
||||
|
||||
violations=0
|
||||
|
||||
# ── detection logic ─────────────────────────────────────────────────
|
||||
|
||||
# Strategy A: Simple grep pattern (file-level)
|
||||
# Find files matching a bad pattern, optionally excluding false positives.
|
||||
#
|
||||
# while IFS= read -r file; do
|
||||
# rel_path="${file#"$TARGET_DIR"/}"
|
||||
# echo "WARNING: $rel_path — {VIOLATION_MESSAGE}"
|
||||
# violations=$((violations + 1))
|
||||
# done < <(grep -rl '{BAD_PATTERN}' "$TARGET_DIR" --include='{FILE_GLOB}' 2>/dev/null \
|
||||
# | while read f; do grep -L '{FALSE_POSITIVE_PATTERN}' "$f" 2>/dev/null; done)
|
||||
|
||||
# Strategy B: Line-level with context (multi-condition)
|
||||
# Find a primary pattern, check nearby lines for secondary pattern.
|
||||
#
|
||||
# while IFS= read -r file; do
|
||||
# while IFS= read -r line_num; do
|
||||
# # Check context around the match
|
||||
# has_mitigation=$(sed -n "${line_num},$((line_num + {CONTEXT_LINES}))p" "$file" \
|
||||
# | grep -c '{MITIGATION_PATTERN}' || true)
|
||||
# if [[ "$has_mitigation" -eq 0 ]]; then
|
||||
# # Additional condition: check if problematic follow-up exists
|
||||
# after_end=$((line_num + {LOOKAHEAD_LINES}))
|
||||
# has_problem=$(sed -n "$((line_num + 1)),${after_end}p" "$file" \
|
||||
# | grep -cE '{FOLLOW_UP_BAD_PATTERN}' || true)
|
||||
# if [[ "$has_problem" -gt 0 ]]; then
|
||||
# rel_path="${file#"$TARGET_DIR"/}"
|
||||
# echo "WARNING: $rel_path:$line_num — {VIOLATION_MESSAGE}"
|
||||
# violations=$((violations + 1))
|
||||
# fi
|
||||
# fi
|
||||
# done < <(grep -n '{PRIMARY_PATTERN}' "$file" | cut -d: -f1)
|
||||
# done < <(grep -rl '{PRIMARY_PATTERN}' "$TARGET_DIR" --include='{FILE_GLOB}' 2>/dev/null)
|
||||
|
||||
# ── results ─────────────────────────────────────────────────────────
|
||||
|
||||
if [[ "$violations" -gt 0 ]]; then
|
||||
echo ""
|
||||
echo "Found $violations {CONVENTION_NAME} violation(s)."
|
||||
echo "Fix: {FIX_GUIDANCE}"
|
||||
echo "Docs: see CLAUDE.md '{CLAUDE_MD_SECTION}'"
|
||||
$CI_MODE && exit 1
|
||||
else
|
||||
echo "{CONVENTION_NAME} check PASSED."
|
||||
fi
|
||||
```
|
||||
|
||||
## Placeholder 说明
|
||||
|
||||
| Placeholder | 含义 | 示例 |
|
||||
|-------------|------|------|
|
||||
| `{NAME}` | 脚本短名 | `modal-safety`, `sql-injection` |
|
||||
| `{CONVENTION_NAME}` | 约定显示名 | `Modal safety`, `SQL injection prevention` |
|
||||
| `{WHAT_IT_DETECTS}` | 检测内容 | `potential modal overlap patterns` |
|
||||
| `{TARGET_SCOPE}` | 目标范围描述 | `frontend code`, `Go handlers` |
|
||||
| `{TARGET_DIRECTORY}` | 扫描目录 | `frontend/src`, `backend` |
|
||||
| `{PROBLEM_DESCRIPTION}` | 问题描述 | `Ant Design Modal.success is non-blocking...` |
|
||||
| `{FILE_GLOB}` | 文件匹配 | `*.tsx`, `*.go` |
|
||||
| `{PRIMARY_PATTERN}` | 主匹配模式 | `Modal\.\(success\|info\)` |
|
||||
| `{MITIGATION_PATTERN}` | 缓解模式(有则排除) | `onOk` |
|
||||
| `{FOLLOW_UP_BAD_PATTERN}` | 后续违规模式 | `set\w*Open\(true\)` |
|
||||
| `{CONTEXT_LINES}` | 上下文行数 | `25` |
|
||||
| `{LOOKAHEAD_LINES}` | 前瞻行数 | `20` |
|
||||
| `{BAD_PATTERN}` | Strategy A 主匹配模式 | `console\.log` |
|
||||
| `{FALSE_POSITIVE_PATTERN}` | Strategy A 排除模式(匹配到则非违规) | `// eslint-disable` |
|
||||
| `{VIOLATION_MESSAGE}` | 违规消息 | `Modal without onOk followed by setState` |
|
||||
| `{FIX_GUIDANCE}` | 修复指导 | `add onOk callback to Modal` |
|
||||
| `{CLAUDE_MD_SECTION}` | CLAUDE.md 章节名 | `Frontend: Modal 安全规则` |
|
||||
|
||||
## 两种检测策略
|
||||
|
||||
### Strategy A: 文件级检测
|
||||
|
||||
适用于:整个文件不应出现某模式(或出现即违规)。
|
||||
|
||||
例子:
|
||||
- `console.log` 在生产代码中
|
||||
- `TODO` / `FIXME` 计数
|
||||
- 缺少 license header
|
||||
|
||||
### Strategy B: 行级 + 上下文检测
|
||||
|
||||
适用于:模式本身不违规,需要检查周围上下文。
|
||||
|
||||
例子:
|
||||
- `Modal.success()` 不违规,但后面紧跟 `setState` 才违规
|
||||
- `db.Exec()` 不违规,但参数用字符串拼接才违规
|
||||
- `fmt.Println()` 不违规,但在 handler 中输出敏感数据才违规
|
||||
102
skills-req/req-test-gate-plugin/skills/templates/gates-doc.md
Normal file
102
skills-req/req-test-gate-plugin/skills/templates/gates-doc.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# GATES.md Template
|
||||
|
||||
项目质量门禁文档模板。放置于 `docs/quality/GATES.md`。
|
||||
|
||||
## 使用方法
|
||||
|
||||
1. 复制下方模板到项目的 `docs/quality/GATES.md`
|
||||
2. 替换 `{PLACEHOLDER}` 为项目特定值
|
||||
3. 根据项目实际情况增删 Gate
|
||||
|
||||
## 模板
|
||||
|
||||
```markdown
|
||||
# Quality Gates
|
||||
|
||||
Quality gates are automated checks that code must pass before it can be merged or deployed.
|
||||
|
||||
## Gate Overview
|
||||
|
||||
| Gate | Name | Where | What it catches |
|
||||
|------|------|-------|-----------------|
|
||||
| 0 | Pre-commit | Local (husky) | Formatting, lint errors |
|
||||
| 1 | CI Lint | {CI_SYSTEM} | {LINT_TOOLS} |
|
||||
| 2 | Convention & Architecture | {CI_SYSTEM} | New violations of established rules |
|
||||
| 3 | Unit Tests | CI / local | Logic bugs, regressions |
|
||||
| 4 | Security Scan | CI | Dependency vulnerabilities |
|
||||
| 5 | Build | CI | Compilation errors |
|
||||
|
||||
## Gate 0: Pre-commit (Local)
|
||||
|
||||
Runs automatically on every `git commit` via husky + lint-staged.
|
||||
|
||||
{FRONTEND_SECTION — include if applicable}
|
||||
**Frontend** (`{FRONTEND_GLOBS}`):
|
||||
- {LINT_TOOL} with {LINT_FLAGS}
|
||||
- {FORMATTER}
|
||||
|
||||
{BACKEND_SECTION — include if applicable}
|
||||
**Backend** (`{BACKEND_GLOBS}`):
|
||||
- {FORMAT_TOOL} (auto-format)
|
||||
- {ANALYSIS_TOOL} (static analysis)
|
||||
|
||||
**Bypass** (emergency only): `git commit --no-verify`
|
||||
|
||||
## Gate 1: CI Lint
|
||||
|
||||
Runs on pull requests via {CI_SYSTEM}.
|
||||
|
||||
- **Backend**: {BACKEND_LINT_COMMANDS}
|
||||
- **Frontend**: {FRONTEND_LINT_COMMANDS}
|
||||
|
||||
## Gate 2: Convention & Architecture Checks
|
||||
|
||||
Runs on pull requests via {CI_SYSTEM}.
|
||||
|
||||
{LIST_EACH_CHECK_SCRIPT}
|
||||
- `./scripts/check-{name}.sh check` — {description}
|
||||
|
||||
See project CLAUDE.md and docs/architecture/ for rule details.
|
||||
|
||||
## Gates 3-5: Testing, Security, Build
|
||||
|
||||
These gates are enforced via the `/req test` workflow:
|
||||
|
||||
1. **Gate 3**: Unit test generation and execution
|
||||
2. **Gate 4**: Security regression scan
|
||||
3. **Gate 5**: E2E smoke test + final report
|
||||
|
||||
See the dev-test skill documentation for details.
|
||||
|
||||
## Local Commands
|
||||
|
||||
\`\`\`bash
|
||||
# Gate 0: Format & Lint
|
||||
{LOCAL_LINT_COMMANDS}
|
||||
|
||||
# Gate 2: Convention checks
|
||||
{LOCAL_CHECK_COMMANDS}
|
||||
|
||||
# Gate 3: Unit tests
|
||||
{LOCAL_TEST_COMMANDS}
|
||||
\`\`\`
|
||||
```
|
||||
|
||||
## Placeholder 说明
|
||||
|
||||
| Placeholder | 含义 | 示例 |
|
||||
|-------------|------|------|
|
||||
| `{CI_SYSTEM}` | CI 系统名称 | `Gitea Actions`, `GitHub Actions` |
|
||||
| `{LINT_TOOLS}` | lint 工具列表 | `golangci-lint, ESLint, TypeScript errors` |
|
||||
| `{FRONTEND_GLOBS}` | 前端文件 glob | `*.ts, *.tsx`, `*.vue` |
|
||||
| `{BACKEND_GLOBS}` | 后端文件 glob | `*.go` |
|
||||
| `{LINT_TOOL}` | lint 工具 | `ESLint` |
|
||||
| `{LINT_FLAGS}` | lint 参数 | `--fix --max-warnings 0` |
|
||||
| `{FORMATTER}` | 格式化工具 | `Prettier`, `gofmt` |
|
||||
|
||||
## 注意事项
|
||||
|
||||
- **此文档的 Gate 编号是项目级的**(描述项目基础设施层级),与 req-test-gate 技能的 Gate 0-5(需求级测试门禁)是两套独立体系
|
||||
- Gate 0-2 由 harness engineering 方法论管理(pre-commit → CI lint → ratchet/约定检测)
|
||||
- Gate 3-5 由 `/req test` 流程管理(单元测试 → 安全扫描 → 构建验证)
|
||||
- 两者互补,不要混淆编号
|
||||
@@ -0,0 +1,135 @@
|
||||
# Pre-commit Configuration Template
|
||||
|
||||
husky + lint-staged 配置模板,三种变体:Node.js 项目、Go 项目、Monorepo。
|
||||
|
||||
---
|
||||
|
||||
## 变体 1: Node.js 项目(React / Vue / 纯 TS)
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
npm install -D husky lint-staged prettier eslint
|
||||
npx husky init
|
||||
echo "npx lint-staged" > .husky/pre-commit
|
||||
```
|
||||
|
||||
### package.json
|
||||
|
||||
```json
|
||||
{
|
||||
"lint-staged": {
|
||||
"*.{ts,tsx}": [
|
||||
"eslint --fix --max-warnings 0",
|
||||
"prettier --write"
|
||||
],
|
||||
"*.{css,less,scss}": [
|
||||
"prettier --write"
|
||||
],
|
||||
"*.{json,md}": [
|
||||
"prettier --write"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 变体 2: Go 项目
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
# Go 项目需要 package.json 来驱动 husky
|
||||
npm init -y
|
||||
npm install -D husky lint-staged
|
||||
npx husky init
|
||||
echo "npx lint-staged" > .husky/pre-commit
|
||||
```
|
||||
|
||||
### package.json
|
||||
|
||||
```json
|
||||
{
|
||||
"lint-staged": {
|
||||
"*.go": [
|
||||
"gofmt -s -w",
|
||||
"bash -c 'go vet ./...'"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 可选:golangci-lint(更严格)
|
||||
|
||||
```json
|
||||
{
|
||||
"lint-staged": {
|
||||
"*.go": [
|
||||
"gofmt -s -w",
|
||||
"bash -c 'go vet ./...'",
|
||||
"bash -c 'golangci-lint run --fix'"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 变体 3: Monorepo(Go + Node.js)
|
||||
|
||||
### 安装(根目录)
|
||||
|
||||
```bash
|
||||
npm install -D husky lint-staged
|
||||
npx husky init
|
||||
echo "npx lint-staged" > .husky/pre-commit
|
||||
```
|
||||
|
||||
### package.json(根目录)
|
||||
|
||||
```json
|
||||
{
|
||||
"lint-staged": {
|
||||
"frontend/**/*.{ts,tsx}": [
|
||||
"bash -c 'cd frontend && npx eslint --fix --max-warnings 0'",
|
||||
"bash -c 'cd frontend && npx prettier --write'"
|
||||
],
|
||||
"frontend/**/*.{css,less,json}": [
|
||||
"bash -c 'cd frontend && npx prettier --write'"
|
||||
],
|
||||
"backend/**/*.go": [
|
||||
"gofmt -s -w",
|
||||
"bash -c 'cd backend && go vet ./...'"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 注意事项
|
||||
|
||||
- `bash -c 'cd xxx && ...'` 确保命令在正确的子目录中执行
|
||||
- lint-staged 传递的文件路径是相对于根目录的,部分工具(如 `go vet`)需要在子目录执行
|
||||
- 如果前端和后端各自有 `package.json`,lint-staged 仍然在根目录配置
|
||||
|
||||
---
|
||||
|
||||
## 验证配置
|
||||
|
||||
```bash
|
||||
# 修改一个文件后测试 pre-commit hook
|
||||
echo "// test" >> some-file.ts
|
||||
git add some-file.ts
|
||||
git commit -m "test: verify pre-commit hook"
|
||||
# 应该看到 lint-staged 执行 ESLint + Prettier
|
||||
# 如果有 lint 错误,commit 会被阻止
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
| 问题 | 原因 | 解决 |
|
||||
|------|------|------|
|
||||
| lint-staged 不执行 | `.husky/pre-commit` 内容不对 | 确认内容为 `npx lint-staged` |
|
||||
| ESLint 报错太多 | 旧项目首次启用 | 先 `npx eslint --fix` 全量修复,再启用 hook |
|
||||
| gofmt 修改后 commit 内容不一致 | lint-staged 自动 format 后需要 re-stage | lint-staged 自动处理,无需手动 |
|
||||
| Monorepo 路径错误 | lint-staged 传递根目录相对路径 | 使用 `bash -c 'cd sub && ...'` 包装 |
|
||||
@@ -0,0 +1,189 @@
|
||||
# Ratchet Script Template
|
||||
|
||||
泛化的 ratchet 脚本模板,基于 new-ai-proj `check-architecture.sh` 提取。
|
||||
|
||||
## 使用方法
|
||||
|
||||
1. 复制下方脚本到 `scripts/check-{NAME}.sh`
|
||||
2. 替换所有 `{PLACEHOLDER}` 为项目特定值
|
||||
3. 运行 `chmod +x scripts/check-{NAME}.sh`
|
||||
4. 运行 `./scripts/check-{NAME}.sh baseline` 记录首次基线
|
||||
5. 提交脚本和基线文件
|
||||
|
||||
## 脚本模板
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# {DESCRIPTION} Ratchet — ensures new code doesn't increase {WHAT} violations.
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/check-{NAME}.sh check # CI / pre-push: fail if violations increased
|
||||
# ./scripts/check-{NAME}.sh baseline # Record current counts (commit the result)
|
||||
# ./scripts/check-{NAME}.sh report # Pretty-print current vs baseline
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
BASELINE_FILE="$SCRIPT_DIR/.{NAME}-baseline.json"
|
||||
TARGET_DIR="$SCRIPT_DIR/../{TARGET_DIRECTORY}"
|
||||
|
||||
# ── rule definitions ────────────────────────────────────────────────
|
||||
# Add/remove rules as needed. Each rule has:
|
||||
# - A name (used as JSON key)
|
||||
# - A type: "ratchet" (baseline can decrease) or "wall" (must be 0)
|
||||
# - A count function
|
||||
|
||||
RULES=({RULE_NAMES}) # e.g. ("rule_one" "rule_two" "rule_three")
|
||||
TYPES=({RULE_TYPES}) # e.g. ("ratchet" "ratchet" "wall")
|
||||
|
||||
# ── counting functions ──────────────────────────────────────────────
|
||||
|
||||
count_rule() {
|
||||
local rule="$1"
|
||||
case "$rule" in
|
||||
{RULE_NAME_1})
|
||||
# Example: count files in {DIR} that import {PACKAGE}
|
||||
grep -rl '{PATTERN_1}' "$TARGET_DIR/{SUBDIR_1}/" 2>/dev/null | wc -l | tr -d ' '
|
||||
;;
|
||||
{RULE_NAME_2})
|
||||
grep -rl '{PATTERN_2}' "$TARGET_DIR/{SUBDIR_2}/" 2>/dev/null | wc -l | tr -d ' '
|
||||
;;
|
||||
# Add more rules...
|
||||
*)
|
||||
echo "0"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ── helpers ─────────────────────────────────────────────────────────
|
||||
|
||||
current_counts() {
|
||||
echo "{"
|
||||
local first=true
|
||||
for rule in "${RULES[@]}"; do
|
||||
local count
|
||||
count=$(count_rule "$rule")
|
||||
$first || echo ","
|
||||
printf ' "%s": %s' "$rule" "${count:-0}"
|
||||
first=false
|
||||
done
|
||||
echo ""
|
||||
echo "}"
|
||||
}
|
||||
|
||||
json_val() {
|
||||
local key="$1" file="$2"
|
||||
grep "\"${key}\"" "$file" | head -1 | sed 's/[^0-9]//g'
|
||||
}
|
||||
|
||||
json_val_str() {
|
||||
local key="$1" json="$2"
|
||||
echo "$json" | grep "\"${key}\"" | head -1 | sed 's/[^0-9]//g'
|
||||
}
|
||||
|
||||
# ── commands ────────────────────────────────────────────────────────
|
||||
|
||||
cmd_baseline() {
|
||||
echo "Recording {NAME} baseline..."
|
||||
current_counts > "$BASELINE_FILE"
|
||||
echo "Baseline written to $BASELINE_FILE"
|
||||
cat "$BASELINE_FILE"
|
||||
}
|
||||
|
||||
cmd_report() {
|
||||
if [[ ! -f "$BASELINE_FILE" ]]; then
|
||||
echo "No baseline found. Run: $0 baseline"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local current
|
||||
current=$(current_counts)
|
||||
|
||||
printf "\n%-35s %10s %10s %8s\n" "Rule" "Baseline" "Current" "Status"
|
||||
printf "%-35s %10s %10s %8s\n" "---" "---" "---" "---"
|
||||
|
||||
for i in "${!RULES[@]}"; do
|
||||
local rule="${RULES[$i]}"
|
||||
local type="${TYPES[$i]}"
|
||||
local base cur status
|
||||
|
||||
base=$(json_val "$rule" "$BASELINE_FILE")
|
||||
cur=$(json_val_str "$rule" "$current")
|
||||
|
||||
if [[ "$type" == "wall" ]]; then
|
||||
[[ "$cur" -eq 0 ]] && status="PASS" || status="FAIL"
|
||||
else
|
||||
[[ "$cur" -le "$base" ]] && status="PASS" || status="FAIL"
|
||||
fi
|
||||
|
||||
printf "%-35s %10d %10d %8s\n" "$rule" "$base" "$cur" "$status"
|
||||
done
|
||||
echo ""
|
||||
}
|
||||
|
||||
cmd_check() {
|
||||
if [[ ! -f "$BASELINE_FILE" ]]; then
|
||||
echo "ERROR: No baseline found. Run: $0 baseline"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local current
|
||||
current=$(current_counts)
|
||||
local failed=0
|
||||
|
||||
for i in "${!RULES[@]}"; do
|
||||
local rule="${RULES[$i]}"
|
||||
local type="${TYPES[$i]}"
|
||||
local base cur
|
||||
|
||||
base=$(json_val "$rule" "$BASELINE_FILE")
|
||||
cur=$(json_val_str "$rule" "$current")
|
||||
|
||||
if [[ "$type" == "wall" ]]; then
|
||||
if [[ "$cur" -ne 0 ]]; then
|
||||
echo "FAIL [hard wall] $rule: expected 0, got $cur"
|
||||
failed=1
|
||||
fi
|
||||
else
|
||||
if [[ "$cur" -gt "$base" ]]; then
|
||||
echo "FAIL [ratchet] $rule: baseline=$base, current=$cur (+$((cur - base)))"
|
||||
failed=1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$failed" -eq 1 ]]; then
|
||||
echo ""
|
||||
echo "{NAME} check FAILED. New violations detected."
|
||||
echo "If this is intentional, update the baseline: $0 baseline"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "{NAME} check PASSED."
|
||||
}
|
||||
|
||||
# ── main ────────────────────────────────────────────────────────────
|
||||
|
||||
case "${1:-check}" in
|
||||
baseline) cmd_baseline ;;
|
||||
report) cmd_report ;;
|
||||
check) cmd_check ;;
|
||||
*)
|
||||
echo "Usage: $0 {check|baseline|report}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
```
|
||||
|
||||
## Placeholder 说明
|
||||
|
||||
| Placeholder | 含义 | 示例 |
|
||||
|-------------|------|------|
|
||||
| `{NAME}` | 脚本短名 | `architecture`, `import-rules` |
|
||||
| `{DESCRIPTION}` | 一句话描述 | `Architecture`, `Import Boundary` |
|
||||
| `{TARGET_DIRECTORY}` | 扫描目标目录(相对于 scripts/) | `backend`, `frontend/src` |
|
||||
| `{RULE_NAMES}` | Bash 数组,规则名列表 | `"handler_db" "route_db"` |
|
||||
| `{RULE_TYPES}` | Bash 数组,规则类型列表 | `"ratchet" "wall"` |
|
||||
| `{PATTERN_N}` | grep 匹配模式 | `"my-pkg/database"` |
|
||||
| `{SUBDIR_N}` | 目标子目录 | `handlers/`, `routes/` |
|
||||
Reference in New Issue
Block a user