spec-runner 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -188
- package/bin/spec-runner.js +192 -706
- package/install.sh +6 -12
- package/package.json +3 -2
- package/templates/.spec-runner/hooks/pre-commit +33 -0
- package/templates/.spec-runner/hooks/pre-push +9 -0
- package/templates/.spec-runner/project.json.example +25 -0
- package/templates/.spec-runner/scripts/branch/create-uc-branch.sh +105 -0
- package/templates/.spec-runner/scripts/branch/uc-next-id.sh +17 -0
- package/templates/.spec-runner/scripts/branch/uc-next-start.sh +81 -0
- package/templates/.spec-runner/scripts/check/drift.sh +66 -0
- package/templates/.spec-runner/scripts/check/health.sh +103 -0
- package/templates/.spec-runner/scripts/check/naming.sh +51 -0
- package/templates/.spec-runner/scripts/check/schema-drift.sh +74 -0
- package/templates/.spec-runner/scripts/check/schema-sync.sh +153 -0
- package/templates/.spec-runner/scripts/check.sh +20 -0
- package/templates/.spec-runner/scripts/lib/uc-context.sh +75 -0
- package/templates/.spec-runner/scripts/openapi/openapi-generate.sh +207 -0
- package/templates/.spec-runner/scripts/setup/init-project.sh +152 -0
- package/templates/.spec-runner/scripts/spec-runner-core.sh +282 -0
- package/templates/.spec-runner/scripts/test/require-tests-green.sh +83 -0
- package/templates/.spec-runner/spec-runner.sh +30 -0
- package/templates/.spec-runner/steps//343/201/235/343/201/256/344/273/226/344/275/234/346/245/255.md +22 -0
- package/templates/.spec-runner/steps//343/202/277/343/202/271/343/202/257/344/270/200/350/246/247.md +132 -0
- package/templates/.spec-runner/steps//343/203/201/343/202/247/343/203/203/343/202/257/343/203/252/343/202/271/343/203/210.md +106 -0
- package/templates/.spec-runner/steps//343/203/206/343/202/271/343/203/210/350/250/255/350/250/210.md +50 -0
- package/templates/.spec-runner/steps//343/203/211/343/203/241/343/202/244/343/203/263/350/250/255/350/250/210.md +32 -0
- package/templates/.spec-runner/steps//344/273/225/346/247/230/347/255/226/345/256/232.md +219 -0
- package/templates/.spec-runner/steps//345/210/206/346/236/220.md +167 -0
- package/templates/.spec-runner/steps//345/256/237/350/243/205.md +91 -0
- package/templates/.spec-runner/steps//345/256/237/350/243/205/350/250/210/347/224/273.md +96 -0
- package/templates/.spec-runner/steps//346/206/262/347/253/240.md +74 -0
- package/templates/.spec-runner/steps//346/233/226/346/230/247/343/201/225/350/247/243/346/266/210.md +159 -0
- package/templates/.spec-runner/templates/UC-NNN-/343/203/246/343/203/274/343/202/271/343/202/261/343/203/274/343/202/271/345/220/215.md +22 -0
- package/templates/spec-runner-command.md +42 -0
- package/templates/base/.github/PULL_REQUEST_TEMPLATE.md +0 -43
- package/templates/base/.github/workflows/phase-gate-check.yml +0 -216
- package/templates/base/scripts/spec-runner.sh +0 -1144
- package/templates/base/templates/01_/350/246/201/344/273/266/345/256/232/347/276/251//343/201/262/343/201/252/345/275/242.md +0 -40
- package/templates/base/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210//343/202/244/343/203/263/343/203/225/343/203/251.md +0 -14
- package/templates/base/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210//343/203/206/343/203/274/343/203/226/343/203/253.md +0 -17
- package/templates/base/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210//343/203/211/343/203/241/343/202/244/343/203/263.md +0 -18
- package/templates/base/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210//343/203/246/343/203/274/343/202/271/343/202/261/343/203/274/343/202/271.md +0 -12
- package/templates/base/templates/99_/350/250/255/350/250/210/345/210/244/346/226/255/350/250/230/351/214/262//343/201/262/343/201/252/345/275/242.md +0 -46
- package/templates/base/templates/README.md +0 -32
- package/templates/base/templates//345/210/235/346/234/237/343/203/211/343/202/255/343/203/245/343/203/241/343/203/263/343/203/210/01_/346/206/262/347/253/240.md +0 -48
- package/templates/base/templates//345/210/235/346/234/237/343/203/211/343/202/255/343/203/245/343/203/241/343/203/263/343/203/210/02_/344/273/225/346/247/230.md +0 -39
- package/templates/base/templates//345/210/235/346/234/237/343/203/211/343/202/255/343/203/245/343/203/241/343/203/263/343/203/210/03_/347/224/250/350/252/236/351/233/206.md +0 -51
- package/templates/base/templates//345/210/235/346/234/237/343/203/211/343/202/255/343/203/245/343/203/241/343/203/263/343/203/210/99_/350/250/255/350/250/210/345/210/244/346/226/255/350/250/230/351/214/262/.gitkeep +0 -0
- package/templates/base/templates//345/210/235/346/234/237/343/203/211/343/202/255/343/203/245/343/203/241/343/203/263/343/203/210//343/203/206/343/203/263/343/203/227/343/203/254/343/203/274/343/203/210/344/270/200/350/246/247.md +0 -14
- package/templates/base/templates//345/210/235/346/234/237/343/203/211/343/202/255/343/203/245/343/203/241/343/203/263/343/203/210//346/214/257/343/202/212/350/277/224/343/202/212//350/262/240/345/202/265.md +0 -8
- package/templates/claude/.claude/commands/sr-/343/202/262/343/203/274/343/203/210/350/250/255/345/256/232.md +0 -9
- package/templates/claude/.claude/commands/sr-/343/203/206/343/202/271/343/203/210/350/250/255/350/250/210.md +0 -9
- package/templates/claude/.claude/commands/sr-/343/203/254/343/203/223/343/203/245/343/203/274.md +0 -9
- package/templates/claude/.claude/commands/sr-/344/273/225/346/247/230.md +0 -9
- package/templates/claude/.claude/commands/sr-/344/277/256/346/255/243.md +0 -9
- package/templates/claude/.claude/commands/sr-/345/210/235/346/234/237/345/214/226.md +0 -10
- package/templates/claude/.claude/commands/sr-/345/256/237/350/243/205.md +0 -9
- package/templates/claude/.claude/commands/sr-/346/206/262/347/253/240.md +0 -9
- package/templates/claude/.claude/commands/sr-/346/246/202/350/246/201/350/250/255/350/250/210.md +0 -9
- package/templates/claude/.claude/commands/sr-/347/212/266/346/205/213.md +0 -9
- package/templates/claude/.claude/commands/sr-/347/267/212/346/200/245/344/277/256/346/255/243.md +0 -9
- package/templates/claude/.claude/commands/sr-/350/250/255/345/256/232.md +0 -11
- package/templates/claude/.claude/commands/sr-/350/251/263/347/264/260/350/250/255/350/250/210.md +0 -9
- package/templates/claude/.claude/hooks/pre-tool-use.sh +0 -79
- package/templates/claude/.claude/settings.json +0 -29
- package/templates/claude/CLAUDE.md +0 -141
- package/templates/copilot/.github/copilot-instructions.md +0 -25
- package/templates/copilot/.github/prompts/sr-/343/202/262/343/203/274/343/203/210/350/250/255/345/256/232.prompt.md +0 -14
- package/templates/copilot/.github/prompts/sr-/343/203/206/343/202/271/343/203/210/350/250/255/350/250/210.prompt.md +0 -13
- package/templates/copilot/.github/prompts/sr-/343/203/254/343/203/223/343/203/245/343/203/274.prompt.md +0 -14
- package/templates/copilot/.github/prompts/sr-/344/273/225/346/247/230.prompt.md +0 -13
- package/templates/copilot/.github/prompts/sr-/344/277/256/346/255/243.prompt.md +0 -14
- package/templates/copilot/.github/prompts/sr-/345/210/235/346/234/237/345/214/226.prompt.md +0 -15
- package/templates/copilot/.github/prompts/sr-/345/256/237/350/243/205.prompt.md +0 -13
- package/templates/copilot/.github/prompts/sr-/346/206/262/347/253/240.prompt.md +0 -13
- package/templates/copilot/.github/prompts/sr-/346/246/202/350/246/201/350/250/255/350/250/210.prompt.md +0 -13
- package/templates/copilot/.github/prompts/sr-/347/212/266/346/205/213.prompt.md +0 -13
- package/templates/copilot/.github/prompts/sr-/347/267/212/346/200/245/344/277/256/346/255/243.prompt.md +0 -14
- package/templates/copilot/.github/prompts/sr-/350/250/255/345/256/232.prompt.md +0 -13
- package/templates/copilot/.github/prompts/sr-/350/251/263/347/264/260/350/250/255/350/250/210.prompt.md +0 -14
- package/templates/cursor/.cursor/commands/sr-/343/202/262/343/203/274/343/203/210/350/250/255/345/256/232.md +0 -11
- package/templates/cursor/.cursor/commands/sr-/343/203/206/343/202/271/343/203/210/350/250/255/350/250/210.md +0 -9
- package/templates/cursor/.cursor/commands/sr-/343/203/254/343/203/223/343/203/245/343/203/274.md +0 -9
- package/templates/cursor/.cursor/commands/sr-/344/273/225/346/247/230.md +0 -9
- package/templates/cursor/.cursor/commands/sr-/344/277/256/346/255/243.md +0 -9
- package/templates/cursor/.cursor/commands/sr-/345/210/235/346/234/237/345/214/226.md +0 -35
- package/templates/cursor/.cursor/commands/sr-/345/256/237/350/243/205.md +0 -9
- package/templates/cursor/.cursor/commands/sr-/346/206/262/347/253/240.md +0 -9
- package/templates/cursor/.cursor/commands/sr-/346/246/202/350/246/201/350/250/255/350/250/210.md +0 -9
- package/templates/cursor/.cursor/commands/sr-/347/212/266/346/205/213.md +0 -9
- package/templates/cursor/.cursor/commands/sr-/347/267/212/346/200/245/344/277/256/346/255/243.md +0 -9
- package/templates/cursor/.cursor/commands/sr-/350/250/255/345/256/232.md +0 -20
- package/templates/cursor/.cursor/commands/sr-/350/251/263/347/264/260/350/250/255/350/250/210.md +0 -9
- package/templates/cursor/.cursorrules +0 -26
|
@@ -1,1144 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# =============================================================================
|
|
3
|
-
# spec-runner.sh — ドメイン駆動AI開発 フェーズゲートシステム
|
|
4
|
-
# =============================================================================
|
|
5
|
-
# このスクリプトが「本当の強制」を担う。
|
|
6
|
-
# Claude CodeはCLAUDE.mdを読んでルールを「知る」が、スキップできる。
|
|
7
|
-
# このスクリプトはシェルレベルで実行を拒否するため、AIも人間もスキップできない。
|
|
8
|
-
#
|
|
9
|
-
# 使い方:
|
|
10
|
-
# ./.spec-runner/scripts/spec-runner.sh init … 詳細設定の対話のみ
|
|
11
|
-
# ./.spec-runner/scripts/spec-runner.sh init <ユースケース名> [集約名] … 設定後ユースケース作成
|
|
12
|
-
# ./.spec-runner/scripts/spec-runner.sh require
|
|
13
|
-
# ./.spec-runner/scripts/spec-runner.sh design-high
|
|
14
|
-
# ./.spec-runner/scripts/spec-runner.sh design-detail <サブフェーズ: domain|usecase|table|infra>
|
|
15
|
-
# ./.spec-runner/scripts/spec-runner.sh test-design
|
|
16
|
-
# ./.spec-runner/scripts/spec-runner.sh implement
|
|
17
|
-
# ./.spec-runner/scripts/spec-runner.sh status
|
|
18
|
-
# ./.spec-runner/scripts/spec-runner.sh fix <修正内容>
|
|
19
|
-
# ./.spec-runner/scripts/spec-runner.sh hotfix <内容>
|
|
20
|
-
# ./.spec-runner/scripts/spec-runner.sh review-pass <ドキュメントパス>
|
|
21
|
-
# =============================================================================
|
|
22
|
-
|
|
23
|
-
set -euo pipefail
|
|
24
|
-
|
|
25
|
-
# ── 定数 ──────────────────────────────────────────────────────────────────────
|
|
26
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
27
|
-
# .spec-runner/scripts/ にいる場合は PROJECT_ROOT は 2 階層上、そうでなければ 1 階層上(旧レイアウト)
|
|
28
|
-
if [[ "$SCRIPT_DIR" == */.spec-runner/scripts ]]; then
|
|
29
|
-
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
30
|
-
SPEC_RUNNER_DIR="$PROJECT_ROOT/.spec-runner"
|
|
31
|
-
else
|
|
32
|
-
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
33
|
-
SPEC_RUNNER_DIR="$PROJECT_ROOT"
|
|
34
|
-
fi
|
|
35
|
-
STATE_FILE="$PROJECT_ROOT/.spec-runner/state.json"
|
|
36
|
-
DEBT_FILE="$PROJECT_ROOT/docs/振り返り/負債.md"
|
|
37
|
-
GLOSSARY="$PROJECT_ROOT/docs/03_用語集.md"
|
|
38
|
-
|
|
39
|
-
# ── フレームワーク設定を読み込む ───────────────────────────────────────────────
|
|
40
|
-
# npx spec-runner によって生成された .spec-runner/config.sh を読み込む
|
|
41
|
-
# これによりフレームワーク依存の設定(拡張子・パス等)が外部化される
|
|
42
|
-
CONFIG_FILE="$PROJECT_ROOT/.spec-runner/config.sh"
|
|
43
|
-
if [[ -f "$CONFIG_FILE" ]]; then
|
|
44
|
-
# shellcheck source=.spec-runner/config.sh
|
|
45
|
-
source "$CONFIG_FILE"
|
|
46
|
-
else
|
|
47
|
-
# .spec-runner/config.sh がない場合のデフォルト値
|
|
48
|
-
SOURCE_EXTENSIONS="${SOURCE_EXTENSIONS:-ts tsx js jsx php py rb}"
|
|
49
|
-
DOMAIN_PATH="${DOMAIN_PATH:-src/domain}"
|
|
50
|
-
USECASE_PATH="${USECASE_PATH:-src/useCase}"
|
|
51
|
-
INFRA_PATH="${INFRA_PATH:-src/infrastructure}"
|
|
52
|
-
fi
|
|
53
|
-
|
|
54
|
-
# ── カラー出力 ──────────────────────────────────────────────────────────────
|
|
55
|
-
RED='\033[0;31m'
|
|
56
|
-
GREEN='\033[0;32m'
|
|
57
|
-
YELLOW='\033[1;33m'
|
|
58
|
-
BLUE='\033[0;34m'
|
|
59
|
-
CYAN='\033[0;36m'
|
|
60
|
-
BOLD='\033[1m'
|
|
61
|
-
NC='\033[0m'
|
|
62
|
-
|
|
63
|
-
ok() { echo -e "${GREEN}✓${NC} $*"; }
|
|
64
|
-
fail() { echo -e "${RED}✗${NC} $*"; }
|
|
65
|
-
warn() { echo -e "${YELLOW}⚠${NC} $*"; }
|
|
66
|
-
info() { echo -e "${CYAN}ℹ${NC} $*"; }
|
|
67
|
-
step() { echo -e "${BOLD}${BLUE}▶${NC} $*"; }
|
|
68
|
-
die() { echo -e "${RED}${BOLD}ERROR:${NC} $*" >&2; exit 1; }
|
|
69
|
-
|
|
70
|
-
# ── 依存チェック ───────────────────────────────────────────────────────────
|
|
71
|
-
require_cmd() {
|
|
72
|
-
command -v "$1" &>/dev/null || die "$1 がインストールされていません"
|
|
73
|
-
}
|
|
74
|
-
require_cmd jq
|
|
75
|
-
require_cmd git
|
|
76
|
-
|
|
77
|
-
# ── ステート操作 ───────────────────────────────────────────────────────────
|
|
78
|
-
state_get() { jq -r ".$1 // empty" "$STATE_FILE" 2>/dev/null || echo ""; }
|
|
79
|
-
state_set() {
|
|
80
|
-
local key="$1" val="$2"
|
|
81
|
-
local tmp
|
|
82
|
-
tmp="${STATE_FILE}.tmp.$$"
|
|
83
|
-
jq ".$key = $val" "$STATE_FILE" > "$tmp" && mv "$tmp" "$STATE_FILE"
|
|
84
|
-
}
|
|
85
|
-
state_set_str() { state_set "$1" "\"$2\""; }
|
|
86
|
-
state_set_bool() { state_set "$1" "$2"; } # true / false
|
|
87
|
-
|
|
88
|
-
state_init() {
|
|
89
|
-
local usecase="$1" aggregate="${2:-}"
|
|
90
|
-
local branch="feature/uc-$(echo "$usecase" | tr ' ' '-')"
|
|
91
|
-
local agg_branch=""
|
|
92
|
-
[[ -n "$aggregate" ]] && agg_branch="aggregate/$(echo "$aggregate" | tr ' ' '-')"
|
|
93
|
-
|
|
94
|
-
mkdir -p "$(dirname "$STATE_FILE")"
|
|
95
|
-
cat > "$STATE_FILE" <<EOF
|
|
96
|
-
{
|
|
97
|
-
"usecase": "$usecase",
|
|
98
|
-
"aggregate": "$aggregate",
|
|
99
|
-
"phase": "require",
|
|
100
|
-
"branch": "$branch",
|
|
101
|
-
"aggregate_branch": "$agg_branch",
|
|
102
|
-
"started_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
|
103
|
-
"gates": {
|
|
104
|
-
"require_approved": false,
|
|
105
|
-
"glossary_checked": false,
|
|
106
|
-
"high_level_reviewed": false,
|
|
107
|
-
"domain_model_reviewed": false,
|
|
108
|
-
"usecase_design_reviewed": false,
|
|
109
|
-
"table_design_reviewed": false,
|
|
110
|
-
"infra_design_reviewed": false,
|
|
111
|
-
"test_design_reviewed": false,
|
|
112
|
-
"test_code_committed": false
|
|
113
|
-
},
|
|
114
|
-
"history": []
|
|
115
|
-
}
|
|
116
|
-
EOF
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
state_push_history() {
|
|
120
|
-
local msg="$1"
|
|
121
|
-
local tmp
|
|
122
|
-
tmp="${STATE_FILE}.tmp.$$"
|
|
123
|
-
jq ".history += [\"$(date -u +%Y-%m-%dT%H:%M:%SZ): $msg\"]" "$STATE_FILE" > "$tmp" && mv "$tmp" "$STATE_FILE"
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
# ── ステートファイル必須チェック ───────────────────────────────────────────
|
|
127
|
-
require_state() {
|
|
128
|
-
[[ -f "$STATE_FILE" ]] || die "作業中のユースケースがありません。まず: ./.spec-runner/scripts/spec-runner.sh init <ユースケース名>"
|
|
129
|
-
local phase
|
|
130
|
-
phase=$(state_get "phase")
|
|
131
|
-
[[ -n "$phase" ]] || die "ステートファイルが壊れています: $STATE_FILE"
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
# ── ゲートチェック関数群 ───────────────────────────────────────────────────
|
|
135
|
-
|
|
136
|
-
# ドキュメントのfrontmatterからstatusを取得
|
|
137
|
-
doc_status() {
|
|
138
|
-
local file="$1"
|
|
139
|
-
[[ -f "$file" ]] || { echo "missing"; return; }
|
|
140
|
-
grep -m1 '^status:' "$file" | sed 's/status: *//' | tr -d '[:space:]' || echo "draft"
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
# ファイル存在チェック(エラーメッセージ付き)
|
|
144
|
-
check_file() {
|
|
145
|
-
local file="$1" label="$2"
|
|
146
|
-
if [[ -f "$file" ]]; then
|
|
147
|
-
ok "$label: $file"
|
|
148
|
-
return 0
|
|
149
|
-
else
|
|
150
|
-
fail "$label が存在しません: $file"
|
|
151
|
-
return 1
|
|
152
|
-
fi
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
# ドキュメントステータスチェック
|
|
156
|
-
check_status() {
|
|
157
|
-
local file="$1" required_status="$2" label="$3"
|
|
158
|
-
local status
|
|
159
|
-
status=$(doc_status "$file")
|
|
160
|
-
if [[ "$status" == "$required_status" ]] || [[ "$status" == "approved" && "$required_status" == "reviewed" ]]; then
|
|
161
|
-
ok "$label (status: $status)"
|
|
162
|
-
return 0
|
|
163
|
-
else
|
|
164
|
-
fail "$label のステータスが '$status' です。'$required_status' が必要です"
|
|
165
|
-
info " レビュー後: ./.spec-runner/scripts/spec-runner.sh review-pass $file"
|
|
166
|
-
return 1
|
|
167
|
-
fi
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
# gateフラグチェック
|
|
171
|
-
check_gate() {
|
|
172
|
-
local gate="$1" label="$2"
|
|
173
|
-
local val
|
|
174
|
-
val=$(state_get "gates.$gate")
|
|
175
|
-
if [[ "$val" == "true" ]]; then
|
|
176
|
-
ok "$label"
|
|
177
|
-
return 0
|
|
178
|
-
else
|
|
179
|
-
fail "$label(未完了)"
|
|
180
|
-
return 1
|
|
181
|
-
fi
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
# ── debt.md チェック ───────────────────────────────────────────────────────
|
|
185
|
-
check_debt() {
|
|
186
|
-
if [[ -f "$DEBT_FILE" ]]; then
|
|
187
|
-
local unchecked
|
|
188
|
-
unchecked=$(grep -c '^\- \[ \]' "$DEBT_FILE" 2>/dev/null; true)
|
|
189
|
-
unchecked="${unchecked:-0}"
|
|
190
|
-
if [[ "${unchecked}" -gt 0 ]]; then
|
|
191
|
-
echo ""
|
|
192
|
-
warn "══════════════════════════════════════════════════════════"
|
|
193
|
-
warn " ドキュメント負債が $unchecked 件あります: $DEBT_FILE"
|
|
194
|
-
warn " 新規開発の前に消化することを推奨します"
|
|
195
|
-
warn "══════════════════════════════════════════════════════════"
|
|
196
|
-
echo ""
|
|
197
|
-
read -r -p "このまま続けますか? [y/N] " answer
|
|
198
|
-
[[ "$answer" =~ ^[Yy]$ ]] || die "ドキュメント負債を先に解消してください"
|
|
199
|
-
fi
|
|
200
|
-
fi
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
# ── usecase/aggregate のパス計算 ───────────────────────────────────────────
|
|
204
|
-
uc_slug() { echo "$(state_get usecase)" | tr ' ' '-'; }
|
|
205
|
-
agg_slug() { echo "$(state_get aggregate)" | tr ' ' '-'; }
|
|
206
|
-
uc_req() { echo "$PROJECT_ROOT/docs/01_要件/$(uc_slug).md"; }
|
|
207
|
-
uc_high() { echo "$PROJECT_ROOT/docs/02_概要設計/$(uc_slug).md"; }
|
|
208
|
-
uc_detail() { echo "$PROJECT_ROOT/docs/03_詳細設計/$(uc_slug)"; }
|
|
209
|
-
uc_test() { echo "$PROJECT_ROOT/docs/04_テスト設計/$(uc_slug).md"; }
|
|
210
|
-
|
|
211
|
-
# ═══════════════════════════════════════════════════════════════════════════════
|
|
212
|
-
# コマンド実装
|
|
213
|
-
# ═══════════════════════════════════════════════════════════════════════════════
|
|
214
|
-
|
|
215
|
-
# ── init ──────────────────────────────────────────────────────────────────────
|
|
216
|
-
cmd_init() {
|
|
217
|
-
local usecase="${1:-}" aggregate="${2:-}"
|
|
218
|
-
|
|
219
|
-
[[ -f "$CONFIG_FILE" ]] || die ".spec-runner/config.sh がありません。まず npx spec-runner を実行してください。"
|
|
220
|
-
|
|
221
|
-
# 詳細設定がまだの場合は対話で設定(npx では開発環境だけ聞き、ここでパス・TDD 等を聞く)
|
|
222
|
-
if [[ "${CONFIGURED:-false}" != "true" ]]; then
|
|
223
|
-
echo ""
|
|
224
|
-
info "詳細設定がまだです。パス・TDD 等を対話で設定します..."
|
|
225
|
-
echo ""
|
|
226
|
-
npx spec-runner --configure
|
|
227
|
-
# 設定を再読み込み
|
|
228
|
-
source "$CONFIG_FILE"
|
|
229
|
-
echo ""
|
|
230
|
-
fi
|
|
231
|
-
|
|
232
|
-
# 引数なしの init = 設定対話のみ。ユースケース名を渡すと作成に進む
|
|
233
|
-
if [[ -z "$usecase" ]]; then
|
|
234
|
-
info "設定が完了しました。最初のユースケースを開始するには:"
|
|
235
|
-
echo ""
|
|
236
|
-
echo " ./.spec-runner/scripts/spec-runner.sh init \"ユースケース名\" \"集約名\""
|
|
237
|
-
echo ""
|
|
238
|
-
return 0
|
|
239
|
-
fi
|
|
240
|
-
|
|
241
|
-
check_debt
|
|
242
|
-
|
|
243
|
-
echo ""
|
|
244
|
-
step "ユースケース初期化: $usecase"
|
|
245
|
-
echo ""
|
|
246
|
-
|
|
247
|
-
# 既存のstateがあれば警告(SR_YES=1 のときは AI/CI 用に確認をスキップ)
|
|
248
|
-
if [[ -f "$STATE_FILE" ]]; then
|
|
249
|
-
local current
|
|
250
|
-
current=$(state_get "usecase")
|
|
251
|
-
if [[ "${SR_YES:-0}" == "1" ]]; then
|
|
252
|
-
warn "作業中のユースケース '$current' を上書きします(SR_YES=1)"
|
|
253
|
-
else
|
|
254
|
-
warn "作業中のユースケース '$current' があります"
|
|
255
|
-
read -r -p "上書きしますか? [y/N] " answer
|
|
256
|
-
[[ "$answer" =~ ^[Yy]$ ]] || die "中止しました"
|
|
257
|
-
fi
|
|
258
|
-
fi
|
|
259
|
-
|
|
260
|
-
# ブランチ作成
|
|
261
|
-
local slug branch agg_branch
|
|
262
|
-
slug=$(echo "$usecase" | tr ' ' '-')
|
|
263
|
-
branch="feature/uc-$slug"
|
|
264
|
-
|
|
265
|
-
# デフォルトブランチを取得(main / master など)
|
|
266
|
-
local default_branch
|
|
267
|
-
default_branch=$(git symbolic-ref --short HEAD 2>/dev/null || echo "main")
|
|
268
|
-
|
|
269
|
-
if [[ -n "$aggregate" ]]; then
|
|
270
|
-
agg_branch="aggregate/$(echo "$aggregate" | tr ' ' '-')"
|
|
271
|
-
step "集約ブランチを確認/作成: $agg_branch"
|
|
272
|
-
if ! git show-ref --verify --quiet "refs/heads/$agg_branch"; then
|
|
273
|
-
git checkout -b "$agg_branch" 2>/dev/null || git checkout -b "$agg_branch" "$default_branch"
|
|
274
|
-
ok "集約ブランチ作成: $agg_branch"
|
|
275
|
-
else
|
|
276
|
-
git checkout "$agg_branch"
|
|
277
|
-
ok "集約ブランチに切替: $agg_branch"
|
|
278
|
-
fi
|
|
279
|
-
fi
|
|
280
|
-
|
|
281
|
-
step "ユースケースブランチを作成: $branch"
|
|
282
|
-
if git show-ref --verify --quiet "refs/heads/$branch"; then
|
|
283
|
-
die "ブランチ $branch は既に存在します"
|
|
284
|
-
fi
|
|
285
|
-
local base="${aggregate:+aggregate/$(echo "$aggregate" | tr ' ' '-')}"
|
|
286
|
-
git checkout -b "$branch" "${base:-$default_branch}" 2>/dev/null || git checkout -b "$branch"
|
|
287
|
-
ok "ブランチ作成: $branch"
|
|
288
|
-
|
|
289
|
-
# ステート初期化
|
|
290
|
-
state_init "$usecase" "$aggregate"
|
|
291
|
-
|
|
292
|
-
# 要件定義ファイルをテンプレートから生成(templates/requirement/template.md を必須とする)
|
|
293
|
-
local req_file tmpl
|
|
294
|
-
req_file=$(uc_req)
|
|
295
|
-
tmpl="$SPEC_RUNNER_DIR/templates/01_要件定義/ひな形.md"
|
|
296
|
-
[[ -f "$tmpl" ]] || die "要件テンプレートがありません: $tmpl (npx spec-runner でセットアップしてください)"
|
|
297
|
-
|
|
298
|
-
mkdir -p "$(dirname "$req_file")"
|
|
299
|
-
if [[ ! -f "$req_file" ]]; then
|
|
300
|
-
sed "s/{{USECASE}}/$usecase/g; s/{{DATE}}/$(date +%Y-%m-%d)/g" "$tmpl" > "$req_file"
|
|
301
|
-
ok "要件定義ファイルを作成: $req_file"
|
|
302
|
-
else
|
|
303
|
-
warn "要件定義ファイルは既に存在します: $req_file"
|
|
304
|
-
fi
|
|
305
|
-
|
|
306
|
-
echo ""
|
|
307
|
-
info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
308
|
-
info "次のステップ:"
|
|
309
|
-
info " 1. $req_file を編集する"
|
|
310
|
-
info " 2. チームに確認してもらう"
|
|
311
|
-
info " 3. ./.spec-runner/scripts/spec-runner.sh review-pass $req_file"
|
|
312
|
-
info " 4. ./.spec-runner/scripts/spec-runner.sh design-high"
|
|
313
|
-
info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
# ── require ───────────────────────────────────────────────────────────────────
|
|
317
|
-
cmd_require() {
|
|
318
|
-
require_state
|
|
319
|
-
local phase
|
|
320
|
-
phase=$(state_get "phase")
|
|
321
|
-
[[ "$phase" == "require" ]] || die "現在のフェーズは '$phase' です。要件定義フェーズではありません"
|
|
322
|
-
|
|
323
|
-
local req_file
|
|
324
|
-
req_file=$(uc_req)
|
|
325
|
-
info "要件定義ファイル: $req_file"
|
|
326
|
-
info "編集後、チームに確認してもらい:"
|
|
327
|
-
info " ./.spec-runner/scripts/spec-runner.sh review-pass $req_file"
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
# ── design-high ───────────────────────────────────────────────────────────────
|
|
331
|
-
cmd_design_high() {
|
|
332
|
-
require_state
|
|
333
|
-
|
|
334
|
-
echo ""
|
|
335
|
-
step "【ゲートチェック】概要設計フェーズに進む条件を確認します"
|
|
336
|
-
echo ""
|
|
337
|
-
|
|
338
|
-
local errors=0
|
|
339
|
-
local req_file
|
|
340
|
-
req_file=$(uc_req)
|
|
341
|
-
|
|
342
|
-
check_file "$req_file" "要件定義ファイル" || ((errors++))
|
|
343
|
-
check_status "$req_file" "approved" "要件定義のステータス" || ((errors++))
|
|
344
|
-
check_gate "glossary_checked" "用語集.md の確認済み" || ((errors++))
|
|
345
|
-
|
|
346
|
-
if [[ $errors -gt 0 ]]; then
|
|
347
|
-
echo ""
|
|
348
|
-
die "ゲートを通過できません。${errors}件の条件が未達です ↑"
|
|
349
|
-
fi
|
|
350
|
-
|
|
351
|
-
echo ""
|
|
352
|
-
ok "ゲート通過!概要設計フェーズを開始します"
|
|
353
|
-
state_set_str "phase" "design-high"
|
|
354
|
-
state_push_history "design-high フェーズ開始"
|
|
355
|
-
|
|
356
|
-
# 概要設計ファイルをテンプレートから生成
|
|
357
|
-
local high_file usecase
|
|
358
|
-
high_file=$(uc_high)
|
|
359
|
-
usecase=$(state_get "usecase")
|
|
360
|
-
mkdir -p "$(dirname "$high_file")"
|
|
361
|
-
|
|
362
|
-
if [[ ! -f "$high_file" ]]; then
|
|
363
|
-
cat > "$high_file" <<TMPL
|
|
364
|
-
---
|
|
365
|
-
title: $usecase 概要設計
|
|
366
|
-
status: draft
|
|
367
|
-
requirement: $(uc_req)
|
|
368
|
-
created: $(date +%Y-%m-%d)
|
|
369
|
-
updated: $(date +%Y-%m-%d)
|
|
370
|
-
---
|
|
371
|
-
|
|
372
|
-
# $usecase 概要設計
|
|
373
|
-
|
|
374
|
-
## ユースケース
|
|
375
|
-
|
|
376
|
-
### UC-01: $usecase
|
|
377
|
-
|
|
378
|
-
**アクター**:
|
|
379
|
-
**前提条件**:
|
|
380
|
-
**主要フロー**:
|
|
381
|
-
1.
|
|
382
|
-
**事後条件**:
|
|
383
|
-
**例外フロー**:
|
|
384
|
-
|
|
385
|
-
## ドメインモデルの洗い出し
|
|
386
|
-
|
|
387
|
-
<!-- 用語集.md の日本語名で書く -->
|
|
388
|
-
|
|
389
|
-
### エンティティ候補
|
|
390
|
-
|
|
391
|
-
| 名前(日本語) | 説明 | 属する集約 |
|
|
392
|
-
|-------------|------|----------|
|
|
393
|
-
| | | |
|
|
394
|
-
|
|
395
|
-
### 値オブジェクト候補
|
|
396
|
-
|
|
397
|
-
| 名前(日本語) | 説明 |
|
|
398
|
-
|-------------|------|
|
|
399
|
-
| | |
|
|
400
|
-
|
|
401
|
-
### ドメインイベント候補
|
|
402
|
-
|
|
403
|
-
| 名前(日本語) | いつ発生するか |
|
|
404
|
-
|-------------|-------------|
|
|
405
|
-
| | |
|
|
406
|
-
|
|
407
|
-
## 未決事項
|
|
408
|
-
|
|
409
|
-
- [ ]
|
|
410
|
-
|
|
411
|
-
## レビュー記録
|
|
412
|
-
|
|
413
|
-
| 日付 | レビュアー | 結果 |
|
|
414
|
-
|------|----------|------|
|
|
415
|
-
TMPL
|
|
416
|
-
ok "概要設計ファイルを作成: $high_file"
|
|
417
|
-
fi
|
|
418
|
-
|
|
419
|
-
echo ""
|
|
420
|
-
info "次のステップ:"
|
|
421
|
-
info " 1. $high_file を編集する"
|
|
422
|
-
info " 2. チームにレビューしてもらう"
|
|
423
|
-
info " 3. ./.spec-runner/scripts/spec-runner.sh review-pass $high_file"
|
|
424
|
-
info " 4. ./.spec-runner/scripts/spec-runner.sh design-detail domain"
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
# ── design-detail ─────────────────────────────────────────────────────────────
|
|
428
|
-
cmd_design_detail() {
|
|
429
|
-
require_state
|
|
430
|
-
local sub="${1:-}"
|
|
431
|
-
local valid_subs="domain usecase table infra"
|
|
432
|
-
|
|
433
|
-
if [[ -z "$sub" ]]; then
|
|
434
|
-
# サブフェーズなしで呼んだ場合、現在の進捗を表示
|
|
435
|
-
echo ""
|
|
436
|
-
step "詳細設計フェーズの進捗"
|
|
437
|
-
echo ""
|
|
438
|
-
local usecase detail_dir
|
|
439
|
-
usecase=$(state_get "usecase")
|
|
440
|
-
detail_dir=$(uc_detail)
|
|
441
|
-
|
|
442
|
-
local all_ok=true
|
|
443
|
-
for s in domain usecase table infra; do
|
|
444
|
-
local f="$detail_dir/$s.md"
|
|
445
|
-
if [[ -f "$f" ]]; then
|
|
446
|
-
local st
|
|
447
|
-
st=$(doc_status "$f")
|
|
448
|
-
if [[ "$st" == "reviewed" || "$st" == "approved" ]]; then
|
|
449
|
-
ok "$s.md (status: $st)"
|
|
450
|
-
else
|
|
451
|
-
warn "$s.md (status: $st) ← レビュー未完了"
|
|
452
|
-
all_ok=false
|
|
453
|
-
fi
|
|
454
|
-
else
|
|
455
|
-
fail "$s.md 未作成"
|
|
456
|
-
all_ok=false
|
|
457
|
-
fi
|
|
458
|
-
done
|
|
459
|
-
|
|
460
|
-
echo ""
|
|
461
|
-
if $all_ok; then
|
|
462
|
-
info "全サブフェーズ完了。次: ./.spec-runner/scripts/spec-runner.sh test-design"
|
|
463
|
-
else
|
|
464
|
-
info "次のサブフェーズ: ./.spec-runner/scripts/spec-runner.sh design-detail <domain|usecase|table|infra>"
|
|
465
|
-
fi
|
|
466
|
-
return
|
|
467
|
-
fi
|
|
468
|
-
|
|
469
|
-
echo "$valid_subs" | grep -qw "$sub" || die "無効なサブフェーズ: $sub(domain / usecase / table / infra)"
|
|
470
|
-
|
|
471
|
-
# ゲートチェック
|
|
472
|
-
echo ""
|
|
473
|
-
step "【ゲートチェック】詳細設計($sub)フェーズに進む条件を確認します"
|
|
474
|
-
echo ""
|
|
475
|
-
|
|
476
|
-
local errors=0
|
|
477
|
-
local high_file
|
|
478
|
-
high_file=$(uc_high)
|
|
479
|
-
|
|
480
|
-
check_file "$high_file" "概要設計ファイル" || ((errors++))
|
|
481
|
-
check_status "$high_file" "reviewed" "概要設計のステータス" || ((errors++))
|
|
482
|
-
|
|
483
|
-
# サブフェーズ固有の依存チェック
|
|
484
|
-
local detail_dir
|
|
485
|
-
detail_dir=$(uc_detail)
|
|
486
|
-
case "$sub" in
|
|
487
|
-
usecase)
|
|
488
|
-
check_file "$detail_dir/ドメイン.md" "ドメインモデル設計" || ((errors++))
|
|
489
|
-
check_status "$detail_dir/ドメイン.md" "reviewed" "ドメインモデルのレビュー" || ((errors++))
|
|
490
|
-
;;
|
|
491
|
-
table)
|
|
492
|
-
check_file "$detail_dir/ドメイン.md" "ドメインモデル設計" || ((errors++))
|
|
493
|
-
check_status "$detail_dir/ドメイン.md" "reviewed" "ドメインモデルのレビュー" || ((errors++))
|
|
494
|
-
check_file "$detail_dir/ユースケース.md" "ユースケース設計" || ((errors++))
|
|
495
|
-
check_status "$detail_dir/ユースケース.md" "reviewed" "ユースケース設計のレビュー" || ((errors++))
|
|
496
|
-
;;
|
|
497
|
-
infra)
|
|
498
|
-
check_file "$detail_dir/ドメイン.md" "ドメインモデル設計" || ((errors++))
|
|
499
|
-
check_status "$detail_dir/ドメイン.md" "reviewed" "ドメインモデルのレビュー" || ((errors++))
|
|
500
|
-
check_file "$detail_dir/ユースケース.md" "ユースケース設計" || ((errors++))
|
|
501
|
-
check_status "$detail_dir/ユースケース.md" "reviewed" "ユースケース設計のレビュー" || ((errors++))
|
|
502
|
-
check_file "$detail_dir/テーブル.md" "テーブル設計" || ((errors++))
|
|
503
|
-
check_status "$detail_dir/テーブル.md" "reviewed" "テーブル設計のレビュー" || ((errors++))
|
|
504
|
-
;;
|
|
505
|
-
esac
|
|
506
|
-
|
|
507
|
-
if [[ $errors -gt 0 ]]; then
|
|
508
|
-
echo ""
|
|
509
|
-
die "ゲートを通過できません。${errors}件の条件が未達です ↑"
|
|
510
|
-
fi
|
|
511
|
-
|
|
512
|
-
echo ""
|
|
513
|
-
ok "ゲート通過!詳細設計($sub)フェーズを開始します"
|
|
514
|
-
state_set_str "phase" "design-detail-$sub"
|
|
515
|
-
state_push_history "design-detail-$sub フェーズ開始"
|
|
516
|
-
|
|
517
|
-
# サブ種別→日本語ファイル名(ドメイン駆動の用語をそのまま)
|
|
518
|
-
local sub_ja
|
|
519
|
-
case "$sub" in
|
|
520
|
-
domain) sub_ja="ドメイン" ;;
|
|
521
|
-
usecase) sub_ja="ユースケース" ;;
|
|
522
|
-
table) sub_ja="テーブル" ;;
|
|
523
|
-
infra) sub_ja="インフラ" ;;
|
|
524
|
-
*) sub_ja="$sub" ;;
|
|
525
|
-
esac
|
|
526
|
-
|
|
527
|
-
# ファイルをテンプレートから生成
|
|
528
|
-
local dest_file usecase
|
|
529
|
-
usecase=$(state_get "usecase")
|
|
530
|
-
dest_file="$detail_dir/${sub_ja}.md"
|
|
531
|
-
mkdir -p "$detail_dir"
|
|
532
|
-
|
|
533
|
-
local tmpl="$SPEC_RUNNER_DIR/templates/03_詳細設計/${sub_ja}.md"
|
|
534
|
-
if [[ ! -f "$dest_file" ]]; then
|
|
535
|
-
if [[ -f "$tmpl" ]]; then
|
|
536
|
-
sed "s/{{USECASE}}/$usecase/g; s/{{DATE}}/$(date +%Y-%m-%d)/g" "$tmpl" > "$dest_file"
|
|
537
|
-
else
|
|
538
|
-
echo "---
|
|
539
|
-
title: $usecase $(case $sub in domain) echo "ドメインモデル設計";; usecase) echo "ユースケース設計";; table) echo "テーブル設計";; infra) echo "インフラ設計";; esac)
|
|
540
|
-
status: draft
|
|
541
|
-
created: $(date +%Y-%m-%d)
|
|
542
|
-
updated: $(date +%Y-%m-%d)
|
|
543
|
-
---
|
|
544
|
-
|
|
545
|
-
# $usecase $(case $sub in domain) echo "ドメインモデル設計";; usecase) echo "ユースケース設計";; table) echo "テーブル設計";; infra) echo "インフラ設計";; esac)
|
|
546
|
-
" > "$dest_file"
|
|
547
|
-
fi
|
|
548
|
-
ok "設計ファイルを作成: $dest_file"
|
|
549
|
-
fi
|
|
550
|
-
|
|
551
|
-
echo ""
|
|
552
|
-
info "次のステップ:"
|
|
553
|
-
info " 1. $dest_file を編集する"
|
|
554
|
-
info " 2. チームにレビューしてもらう"
|
|
555
|
-
info " 3. ./.spec-runner/scripts/spec-runner.sh review-pass $dest_file"
|
|
556
|
-
case "$sub" in
|
|
557
|
-
domain) info " 4. ./.spec-runner/scripts/spec-runner.sh design-detail usecase" ;;
|
|
558
|
-
usecase) info " 4. ./.spec-runner/scripts/spec-runner.sh design-detail table" ;;
|
|
559
|
-
table) info " 4. ./.spec-runner/scripts/spec-runner.sh design-detail infra" ;;
|
|
560
|
-
infra) info " 4. ./.spec-runner/scripts/spec-runner.sh test-design" ;;
|
|
561
|
-
esac
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
# ── test-design ───────────────────────────────────────────────────────────────
|
|
565
|
-
cmd_test_design() {
|
|
566
|
-
require_state
|
|
567
|
-
|
|
568
|
-
echo ""
|
|
569
|
-
step "【ゲートチェック】テスト設計フェーズに進む条件を確認します"
|
|
570
|
-
echo ""
|
|
571
|
-
|
|
572
|
-
local errors=0
|
|
573
|
-
local detail_dir
|
|
574
|
-
detail_dir=$(uc_detail)
|
|
575
|
-
|
|
576
|
-
for sub_ja in ドメイン ユースケース テーブル インフラ; do
|
|
577
|
-
check_file "$detail_dir/$sub_ja.md" "03_詳細設計/$sub_ja.md" || ((errors++))
|
|
578
|
-
check_status "$detail_dir/$sub_ja.md" "reviewed" "03_詳細設計/$sub_ja.md のレビュー" || ((errors++))
|
|
579
|
-
done
|
|
580
|
-
|
|
581
|
-
# 設計判断記録チェック(ADR が 1 件もない場合に促す)
|
|
582
|
-
local adr_count
|
|
583
|
-
adr_count=$(find "$PROJECT_ROOT/docs/99_設計判断記録" -name "*.md" ! -name "ひな形.md" 2>/dev/null | wc -l | tr -d ' ')
|
|
584
|
-
if [[ "$adr_count" -eq 0 ]]; then
|
|
585
|
-
warn "docs/99_設計判断記録/ にADRが1件もありません。設計判断があれば作成してください"
|
|
586
|
-
fi
|
|
587
|
-
|
|
588
|
-
if [[ $errors -gt 0 ]]; then
|
|
589
|
-
echo ""
|
|
590
|
-
die "ゲートを通過できません。${errors}件の条件が未達です ↑"
|
|
591
|
-
fi
|
|
592
|
-
|
|
593
|
-
echo ""
|
|
594
|
-
ok "ゲート通過!テスト設計フェーズを開始します"
|
|
595
|
-
state_set_str "phase" "test-design"
|
|
596
|
-
state_push_history "test-design フェーズ開始"
|
|
597
|
-
|
|
598
|
-
local test_file usecase
|
|
599
|
-
usecase=$(state_get "usecase")
|
|
600
|
-
test_file=$(uc_test)
|
|
601
|
-
mkdir -p "$(dirname "$test_file")"
|
|
602
|
-
|
|
603
|
-
if [[ ! -f "$test_file" ]]; then
|
|
604
|
-
cat > "$test_file" <<TMPL
|
|
605
|
-
---
|
|
606
|
-
title: $usecase テスト設計
|
|
607
|
-
status: draft
|
|
608
|
-
created: $(date +%Y-%m-%d)
|
|
609
|
-
updated: $(date +%Y-%m-%d)
|
|
610
|
-
---
|
|
611
|
-
|
|
612
|
-
# $usecase テスト設計
|
|
613
|
-
|
|
614
|
-
## テスト方針
|
|
615
|
-
|
|
616
|
-
| 種別 | 対象 | ツール |
|
|
617
|
-
|------|------|-------|
|
|
618
|
-
| Unit | ドメインモデルの振る舞い | PHPUnit |
|
|
619
|
-
| Unit | 値オブジェクトのバリデーション | PHPUnit |
|
|
620
|
-
| Integration | ユースケース | PHPUnit + DB |
|
|
621
|
-
| Feature | APIエンドポイント | PHPUnit + HTTP |
|
|
622
|
-
|
|
623
|
-
## ドメインモデル テストケース
|
|
624
|
-
|
|
625
|
-
| # | テストケース名(日本語) | 入力 | 期待結果 | 種別 |
|
|
626
|
-
|---|----------------------|------|---------|------|
|
|
627
|
-
| 1 | の場合、となる | | | 正常 |
|
|
628
|
-
|
|
629
|
-
## ユースケース テストケース
|
|
630
|
-
|
|
631
|
-
| # | テストケース名(日本語) | 前提条件 | 入力 | 期待結果 |
|
|
632
|
-
|---|----------------------|---------|------|---------|
|
|
633
|
-
| 1 | | | | |
|
|
634
|
-
|
|
635
|
-
## テストコードチェックリスト
|
|
636
|
-
|
|
637
|
-
- [ ] ドメインモデルのUnitテスト作成済み(Red状態確認)
|
|
638
|
-
- [ ] 値オブジェクトのUnitテスト作成済み(Red状態確認)
|
|
639
|
-
- [ ] ユースケースのIntegrationテスト作成済み(Red状態確認)
|
|
640
|
-
- [ ] APIのFeatureテスト作成済み(Red状態確認)
|
|
641
|
-
TMPL
|
|
642
|
-
ok "テスト設計ファイルを作成: $test_file"
|
|
643
|
-
fi
|
|
644
|
-
|
|
645
|
-
echo ""
|
|
646
|
-
info "次のステップ:"
|
|
647
|
-
info " 1. $test_file を編集する(テスト設計)"
|
|
648
|
-
info " 2. テストコードを書く(実装前。Red状態でOK)"
|
|
649
|
-
info " 3. git commit でテストコードをコミット"
|
|
650
|
-
info " 4. ./.spec-runner/scripts/spec-runner.sh review-pass $test_file"
|
|
651
|
-
info " 5. ./.spec-runner/scripts/spec-runner.sh implement"
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
# ── implement ─────────────────────────────────────────────────────────────────
|
|
655
|
-
cmd_implement() {
|
|
656
|
-
require_state
|
|
657
|
-
|
|
658
|
-
echo ""
|
|
659
|
-
step "【ゲートチェック】実装フェーズに進む条件を確認します"
|
|
660
|
-
echo ""
|
|
661
|
-
|
|
662
|
-
local errors=0
|
|
663
|
-
local test_file
|
|
664
|
-
test_file=$(uc_test)
|
|
665
|
-
|
|
666
|
-
# TDD 有効時のみ: テスト設計+テストコードを必須(.spec-runner/config.sh の TDD_ENABLED=false で無効化可)
|
|
667
|
-
if [[ "${TDD_ENABLED:-true}" != "false" ]]; then
|
|
668
|
-
check_file "$test_file" "テスト設計ファイル" || ((errors++))
|
|
669
|
-
check_status "$test_file" "reviewed" "テスト設計のレビュー" || ((errors++))
|
|
670
|
-
|
|
671
|
-
local test_committed
|
|
672
|
-
test_committed=$(state_get "gates.test_code_committed")
|
|
673
|
-
if [[ "$test_committed" != "true" ]]; then
|
|
674
|
-
# テストディレクトリ(.spec-runner/config.sh の TEST_DIR)配下の未コミットを検出
|
|
675
|
-
local test_dir_prefix="${TEST_DIR:-tests}"
|
|
676
|
-
local uncommitted_under_test
|
|
677
|
-
uncommitted_under_test=$(git status --porcelain 2>/dev/null | awk '{print $2}' | grep -E "^${test_dir_prefix}/" | wc -l | tr -d ' ')
|
|
678
|
-
if [[ "${uncommitted_under_test:-0}" -gt 0 ]]; then
|
|
679
|
-
fail "テストコードが未コミットです(TDD 必須。${test_dir_prefix}/ 配下をコミットするか set-gate test_code_committed)"
|
|
680
|
-
((errors++))
|
|
681
|
-
else
|
|
682
|
-
warn "テストコードがコミット済みか未確認です"
|
|
683
|
-
warn "確認後: ./.spec-runner/scripts/spec-runner.sh set-gate test_code_committed"
|
|
684
|
-
fi
|
|
685
|
-
else
|
|
686
|
-
check_gate "test_code_committed" "テストコードのコミット確認" || ((errors++))
|
|
687
|
-
fi
|
|
688
|
-
else
|
|
689
|
-
# TDD オプション時: テスト設計・テストコードは必須ではない(あれば推奨)
|
|
690
|
-
if [[ -f "$test_file" ]]; then
|
|
691
|
-
ok "テスト設計ファイル: $test_file(TDD オプションのため未レビューでも可)"
|
|
692
|
-
else
|
|
693
|
-
warn "テスト設計ファイルがありません(TDD オプションのため実装は進められます)"
|
|
694
|
-
fi
|
|
695
|
-
fi
|
|
696
|
-
|
|
697
|
-
if [[ $errors -gt 0 ]]; then
|
|
698
|
-
echo ""
|
|
699
|
-
die "ゲートを通過できません。${errors}件の条件が未達です ↑"
|
|
700
|
-
fi
|
|
701
|
-
|
|
702
|
-
echo ""
|
|
703
|
-
ok "ゲート通過!実装フェーズを開始します"
|
|
704
|
-
state_set_str "phase" "implement"
|
|
705
|
-
state_push_history "implement フェーズ開始"
|
|
706
|
-
|
|
707
|
-
echo ""
|
|
708
|
-
warn "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
709
|
-
warn " 実装フェーズのルール"
|
|
710
|
-
warn "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
711
|
-
info " 1. テストを Green にする実装を書く"
|
|
712
|
-
info " 2. 設計と乖離した場合は先にドキュメントを更新する"
|
|
713
|
-
info " 3. コードとドキュメントを同一コミットに含める"
|
|
714
|
-
info " 4. 完了したら: git push → PR 作成。次のユースケースは init <名前> で開始"
|
|
715
|
-
warn "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
# ── review-pass ───────────────────────────────────────────────────────────────
|
|
719
|
-
cmd_review_pass() {
|
|
720
|
-
local file="${1:-}"
|
|
721
|
-
[[ -n "$file" ]] || die "使い方: ./.spec-runner/scripts/spec-runner.sh review-pass <ファイルパス>"
|
|
722
|
-
[[ -f "$file" ]] || die "ファイルが存在しません: $file"
|
|
723
|
-
|
|
724
|
-
# frontmatterのstatusを更新
|
|
725
|
-
local today
|
|
726
|
-
today=$(date +%Y-%m-%d)
|
|
727
|
-
|
|
728
|
-
if grep -q '^status:' "$file"; then
|
|
729
|
-
# 既存のstatusを更新(同一デバイス上に一時ファイルを作成してmv)
|
|
730
|
-
local tmp
|
|
731
|
-
tmp="${file}.tmp.$$"
|
|
732
|
-
sed "s/^status: .*/status: reviewed/" "$file" > "$tmp" && mv "$tmp" "$file"
|
|
733
|
-
# updated日付も更新
|
|
734
|
-
tmp="${file}.tmp.$$"
|
|
735
|
-
sed "s/^updated: .*/updated: $today/" "$file" > "$tmp" && mv "$tmp" "$file"
|
|
736
|
-
else
|
|
737
|
-
die "ファイルにfrontmatter(status:)がありません: $file"
|
|
738
|
-
fi
|
|
739
|
-
|
|
740
|
-
ok "レビュー通過: $file (status: reviewed)"
|
|
741
|
-
|
|
742
|
-
# どのゲートフラグを立てるか判定
|
|
743
|
-
require_state
|
|
744
|
-
local uc_slug_val
|
|
745
|
-
uc_slug_val=$(uc_slug)
|
|
746
|
-
|
|
747
|
-
case "$file" in
|
|
748
|
-
*01_要件*)
|
|
749
|
-
state_set_bool "gates.require_approved" true
|
|
750
|
-
state_set_str "phase" "require-approved"
|
|
751
|
-
# statusもapprovedに(同一デバイス上で一時ファイル)
|
|
752
|
-
local tmp2
|
|
753
|
-
tmp2="${file}.tmp.$$"
|
|
754
|
-
sed "s/^status: .*/status: approved/" "$file" > "$tmp2" && mv "$tmp2" "$file"
|
|
755
|
-
ok "ゲート更新: require_approved = true"
|
|
756
|
-
info "次: docs/03_用語集.md を確認後 ./.spec-runner/scripts/spec-runner.sh set-gate glossary_checked"
|
|
757
|
-
info " ./.spec-runner/scripts/spec-runner.sh design-high"
|
|
758
|
-
;;
|
|
759
|
-
*02_概要設計*)
|
|
760
|
-
state_set_bool "gates.high_level_reviewed" true
|
|
761
|
-
ok "ゲート更新: high_level_reviewed = true"
|
|
762
|
-
info "次: ./.spec-runner/scripts/spec-runner.sh design-detail domain"
|
|
763
|
-
;;
|
|
764
|
-
*ドメイン*)
|
|
765
|
-
state_set_bool "gates.domain_model_reviewed" true
|
|
766
|
-
ok "ゲート更新: domain_model_reviewed = true"
|
|
767
|
-
info "次: ./.spec-runner/scripts/spec-runner.sh design-detail usecase"
|
|
768
|
-
;;
|
|
769
|
-
*ユースケース*)
|
|
770
|
-
state_set_bool "gates.usecase_design_reviewed" true
|
|
771
|
-
ok "ゲート更新: usecase_design_reviewed = true"
|
|
772
|
-
info "次: ./.spec-runner/scripts/spec-runner.sh design-detail table"
|
|
773
|
-
;;
|
|
774
|
-
*テーブル*)
|
|
775
|
-
state_set_bool "gates.table_design_reviewed" true
|
|
776
|
-
ok "ゲート更新: table_design_reviewed = true"
|
|
777
|
-
info "次: ./.spec-runner/scripts/spec-runner.sh design-detail infra"
|
|
778
|
-
;;
|
|
779
|
-
*インフラ*)
|
|
780
|
-
state_set_bool "gates.infra_design_reviewed" true
|
|
781
|
-
ok "ゲート更新: infra_design_reviewed = true"
|
|
782
|
-
info "次: ./.spec-runner/scripts/spec-runner.sh test-design"
|
|
783
|
-
;;
|
|
784
|
-
*04_テスト設計*)
|
|
785
|
-
state_set_bool "gates.test_design_reviewed" true
|
|
786
|
-
ok "ゲート更新: test_design_reviewed = true"
|
|
787
|
-
info "テストコードをコミット後: ./.spec-runner/scripts/spec-runner.sh set-gate test_code_committed"
|
|
788
|
-
info "その後: ./.spec-runner/scripts/spec-runner.sh implement"
|
|
789
|
-
;;
|
|
790
|
-
esac
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
# 日本語ゲート名 → 内部キー(set-gate で日本語指定時に使用)
|
|
794
|
-
gate_ja_to_key() {
|
|
795
|
-
case "$1" in
|
|
796
|
-
要件レビュー済み) echo "require_approved" ;;
|
|
797
|
-
用語集確認済み) echo "glossary_checked" ;;
|
|
798
|
-
概要設計レビュー済み) echo "high_level_reviewed" ;;
|
|
799
|
-
ドメインモデルレビュー済み) echo "domain_model_reviewed" ;;
|
|
800
|
-
ユースケース設計レビュー済み) echo "usecase_design_reviewed" ;;
|
|
801
|
-
テーブル設計レビュー済み) echo "table_design_reviewed" ;;
|
|
802
|
-
インフラ設計レビュー済み) echo "infra_design_reviewed" ;;
|
|
803
|
-
テスト設計レビュー済み) echo "test_design_reviewed" ;;
|
|
804
|
-
テストコードコミット済み) echo "test_code_committed" ;;
|
|
805
|
-
*) echo "$1" ;;
|
|
806
|
-
esac
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
# ── set-gate ──────────────────────────────────────────────────────────────────
|
|
810
|
-
cmd_set_gate() {
|
|
811
|
-
require_state
|
|
812
|
-
local gate="${1:-}"
|
|
813
|
-
[[ -n "$gate" ]] || die "使い方: ./.spec-runner/scripts/spec-runner.sh set-gate <ゲート名> 例: 用語集確認済み、テストコードコミット済み"
|
|
814
|
-
local key
|
|
815
|
-
key=$(gate_ja_to_key "$gate")
|
|
816
|
-
state_set_bool "gates.$key" true
|
|
817
|
-
ok "ゲートフラグ設定: $key = true"
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
# ── status 表示用:フェーズ・ゲートの日本語ラベル ─────────────────────────────
|
|
821
|
-
phase_ja() {
|
|
822
|
-
case "$1" in
|
|
823
|
-
require) echo "要件定義" ;;
|
|
824
|
-
require-approved) echo "要件承認済み" ;;
|
|
825
|
-
design-high) echo "概要設計" ;;
|
|
826
|
-
design-detail*) echo "詳細設計" ;;
|
|
827
|
-
test-design) echo "テスト設計" ;;
|
|
828
|
-
implement) echo "実装" ;;
|
|
829
|
-
complete) echo "完了" ;;
|
|
830
|
-
fix) echo "修正" ;;
|
|
831
|
-
*) echo "$1" ;;
|
|
832
|
-
esac
|
|
833
|
-
}
|
|
834
|
-
gate_ja() {
|
|
835
|
-
case "$1" in
|
|
836
|
-
require_approved) echo "要件レビュー済み" ;;
|
|
837
|
-
glossary_checked) echo "用語集確認済み" ;;
|
|
838
|
-
high_level_reviewed) echo "概要設計レビュー済み" ;;
|
|
839
|
-
domain_model_reviewed) echo "ドメインモデルレビュー済み" ;;
|
|
840
|
-
usecase_design_reviewed) echo "ユースケース設計レビュー済み" ;;
|
|
841
|
-
table_design_reviewed) echo "テーブル設計レビュー済み" ;;
|
|
842
|
-
infra_design_reviewed) echo "インフラ設計レビュー済み" ;;
|
|
843
|
-
test_design_reviewed) echo "テスト設計レビュー済み" ;;
|
|
844
|
-
test_code_committed) echo "テストコードコミット済み" ;;
|
|
845
|
-
*) echo "$1" ;;
|
|
846
|
-
esac
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
# ── status: プロジェクト土台(憲章・仕様)の未記入チェック ─────────────────────
|
|
850
|
-
# プレースホルダーが残っている=テンプレートのまま=未記入とみなす
|
|
851
|
-
CONSTITUTION_PLACEHOLDER="この節を編集"
|
|
852
|
-
SPECIFY_PLACEHOLDER="(1〜2文で。例:"
|
|
853
|
-
|
|
854
|
-
is_foundation_written() {
|
|
855
|
-
local kind="$1"
|
|
856
|
-
case "$kind" in
|
|
857
|
-
constitution)
|
|
858
|
-
[[ -f "$PROJECT_ROOT/docs/01_憲章.md" ]] && ! grep -q "$CONSTITUTION_PLACEHOLDER" "$PROJECT_ROOT/docs/01_憲章.md" 2>/dev/null
|
|
859
|
-
;;
|
|
860
|
-
specify)
|
|
861
|
-
[[ -f "$PROJECT_ROOT/docs/02_仕様.md" ]] && ! grep -q "$SPECIFY_PLACEHOLDER" "$PROJECT_ROOT/docs/02_仕様.md" 2>/dev/null
|
|
862
|
-
;;
|
|
863
|
-
*) return 1 ;;
|
|
864
|
-
esac
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
# 憲章・仕様の未記入案内を表示。mode: no_state(ユースケースなし) or has_state(開始済み)
|
|
868
|
-
status_show_foundation_reminder() {
|
|
869
|
-
local mode="${1:-no_state}"
|
|
870
|
-
local c_ok s_ok
|
|
871
|
-
is_foundation_written constitution && c_ok=1 || c_ok=0
|
|
872
|
-
is_foundation_written specify && s_ok=1 || s_ok=0
|
|
873
|
-
[[ $c_ok -eq 1 && $s_ok -eq 1 ]] && return
|
|
874
|
-
|
|
875
|
-
if [[ "$mode" == "no_state" ]]; then
|
|
876
|
-
info "プロジェクトの土台(init の前推奨):"
|
|
877
|
-
[[ $c_ok -eq 0 ]] && info " ✗ 憲章がまだ記入されていません → docs/01_憲章.md (/sr-憲章 で編集)"
|
|
878
|
-
[[ $s_ok -eq 0 ]] && info " ✗ 仕様がまだ記入されていません → docs/02_仕様.md (/sr-仕様 で編集)"
|
|
879
|
-
else
|
|
880
|
-
info "💡 プロジェクトの土台:"
|
|
881
|
-
[[ $c_ok -eq 0 ]] && info " 憲章がまだ → /sr-憲章"
|
|
882
|
-
[[ $s_ok -eq 0 ]] && info " 仕様がまだ → /sr-仕様"
|
|
883
|
-
fi
|
|
884
|
-
info ""
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
# ── status ─────────────────────────────────────────────────────────────────────
|
|
888
|
-
cmd_status() {
|
|
889
|
-
if [[ ! -f "$STATE_FILE" ]]; then
|
|
890
|
-
info "作業中のユースケースはありません"
|
|
891
|
-
info ""
|
|
892
|
-
status_show_foundation_reminder no_state
|
|
893
|
-
info "開始するには: チャットで /sr-初期化 <ユースケース名> またはターミナルで下記を実行してください。"
|
|
894
|
-
info " 例(チャット): /sr-初期化 会員登録 会員"
|
|
895
|
-
info " 例(ターミナル): ./.spec-runner/scripts/spec-runner.sh init 会員登録 会員"
|
|
896
|
-
return
|
|
897
|
-
fi
|
|
898
|
-
|
|
899
|
-
status_show_foundation_reminder has_state
|
|
900
|
-
|
|
901
|
-
local usecase phase branch agg_branch
|
|
902
|
-
usecase=$(state_get "usecase")
|
|
903
|
-
phase=$(state_get "phase")
|
|
904
|
-
branch=$(state_get "branch")
|
|
905
|
-
agg_branch=$(state_get "aggregate_branch")
|
|
906
|
-
|
|
907
|
-
local phase_ja_label
|
|
908
|
-
phase_ja_label=$(phase_ja "$phase")
|
|
909
|
-
|
|
910
|
-
echo ""
|
|
911
|
-
echo -e "${BOLD}════════════════════════════════════════${NC}"
|
|
912
|
-
echo -e "${BOLD} 現在の作業状況${NC}"
|
|
913
|
-
echo -e "${BOLD}════════════════════════════════════════${NC}"
|
|
914
|
-
echo -e " ユースケース : ${CYAN}$usecase${NC}"
|
|
915
|
-
echo -e " フェーズ : ${YELLOW}$phase_ja_label${NC}"
|
|
916
|
-
echo -e " ブランチ : ${BLUE}$branch${NC}"
|
|
917
|
-
[[ -n "$agg_branch" ]] && echo -e " 集約ブランチ: ${BLUE}$agg_branch${NC}"
|
|
918
|
-
echo ""
|
|
919
|
-
echo -e "${BOLD} ゲート状況${NC}"
|
|
920
|
-
|
|
921
|
-
local gates
|
|
922
|
-
for gate in require_approved glossary_checked high_level_reviewed \
|
|
923
|
-
domain_model_reviewed usecase_design_reviewed \
|
|
924
|
-
table_design_reviewed infra_design_reviewed \
|
|
925
|
-
test_design_reviewed test_code_committed; do
|
|
926
|
-
local val gate_label
|
|
927
|
-
val=$(state_get "gates.$gate")
|
|
928
|
-
gate_label=$(gate_ja "$gate")
|
|
929
|
-
if [[ "$val" == "true" ]]; then
|
|
930
|
-
echo -e " ${GREEN}✓${NC} $gate_label"
|
|
931
|
-
else
|
|
932
|
-
echo -e " ${RED}✗${NC} $gate_label"
|
|
933
|
-
fi
|
|
934
|
-
done
|
|
935
|
-
|
|
936
|
-
echo ""
|
|
937
|
-
echo -e "${BOLD} 次にやるべきこと${NC} ${CYAN}(チャットでは /sr-* スラッシュコマンドが使えます)${NC}"
|
|
938
|
-
local req_file high_file
|
|
939
|
-
req_file=$(uc_req)
|
|
940
|
-
high_file=$(uc_high)
|
|
941
|
-
case "$phase" in
|
|
942
|
-
require)
|
|
943
|
-
echo -e " 1. ${CYAN}$req_file${NC} を編集"
|
|
944
|
-
echo -e " 2. /sr-レビュー $req_file"
|
|
945
|
-
echo -e " 3. /sr-ゲート設定 用語集確認済み"
|
|
946
|
-
echo -e " 4. /sr-概要設計"
|
|
947
|
-
;;
|
|
948
|
-
design-high)
|
|
949
|
-
echo -e " 1. ${CYAN}$high_file${NC} を編集"
|
|
950
|
-
echo -e " 2. /sr-レビュー $high_file"
|
|
951
|
-
echo -e " 3. /sr-詳細設計 domain"
|
|
952
|
-
;;
|
|
953
|
-
design-detail*)
|
|
954
|
-
if [[ "$(state_get "gates.domain_model_reviewed")" != "true" ]]; then
|
|
955
|
-
echo -e " 1. docs/03_詳細設計/$(uc_slug)/ドメイン.md を編集"
|
|
956
|
-
echo -e " 2. /sr-レビュー のあと /sr-詳細設計 usecase"
|
|
957
|
-
elif [[ "$(state_get "gates.usecase_design_reviewed")" != "true" ]]; then
|
|
958
|
-
echo -e " 1. docs/03_詳細設計/$(uc_slug)/ユースケース.md を編集"
|
|
959
|
-
echo -e " 2. /sr-レビュー のあと /sr-詳細設計 table"
|
|
960
|
-
elif [[ "$(state_get "gates.table_design_reviewed")" != "true" ]]; then
|
|
961
|
-
echo -e " 1. docs/03_詳細設計/$(uc_slug)/テーブル.md を編集"
|
|
962
|
-
echo -e " 2. /sr-レビュー のあと /sr-詳細設計 infra"
|
|
963
|
-
elif [[ "$(state_get "gates.infra_design_reviewed")" != "true" ]]; then
|
|
964
|
-
echo -e " 1. docs/03_詳細設計/$(uc_slug)/インフラ.md を編集"
|
|
965
|
-
echo -e " 2. /sr-レビュー のあと /sr-テスト設計"
|
|
966
|
-
else
|
|
967
|
-
echo -e " /sr-テスト設計"
|
|
968
|
-
fi
|
|
969
|
-
;;
|
|
970
|
-
test-design)
|
|
971
|
-
echo -e " 1. docs/04_テスト設計/$(uc_slug).md を編集し、テストコードを書く(Red)"
|
|
972
|
-
echo -e " 2. テストコードをコミット → /sr-ゲート設定 テストコードコミット済み"
|
|
973
|
-
echo -e " 3. /sr-レビュー docs/04_テスト設計/$(uc_slug).md"
|
|
974
|
-
echo -e " 4. /sr-実装"
|
|
975
|
-
;;
|
|
976
|
-
implement)
|
|
977
|
-
echo -e " 実装完了したら: git push → PR 作成。次のユースケースは /sr-初期化 <名前> で開始"
|
|
978
|
-
;;
|
|
979
|
-
fix)
|
|
980
|
-
echo -e " 案内に従って該当ドキュメントを修正し、必要なら /sr-詳細設計 等から再実行。"
|
|
981
|
-
;;
|
|
982
|
-
*)
|
|
983
|
-
echo -e " ./.spec-runner/scripts/spec-runner.sh help でコマンド一覧を確認"
|
|
984
|
-
;;
|
|
985
|
-
esac
|
|
986
|
-
echo ""
|
|
987
|
-
echo -e "${BOLD} 履歴${NC}"
|
|
988
|
-
jq -r '.history[]' "$STATE_FILE" 2>/dev/null | tail -5 | while read -r line; do
|
|
989
|
-
echo " $line"
|
|
990
|
-
done
|
|
991
|
-
echo -e "${BOLD}════════════════════════════════════════${NC}"
|
|
992
|
-
|
|
993
|
-
# debt確認
|
|
994
|
-
if [[ -f "$DEBT_FILE" ]]; then
|
|
995
|
-
local unchecked
|
|
996
|
-
unchecked=$(grep -c '^\- \[ \]' "$DEBT_FILE" 2>/dev/null; true)
|
|
997
|
-
unchecked="${unchecked:-0}"
|
|
998
|
-
if [[ "${unchecked}" -gt 0 ]]; then
|
|
999
|
-
warn "ドキュメント負債: ${unchecked} 件"
|
|
1000
|
-
fi
|
|
1001
|
-
fi
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
# ── fix ───────────────────────────────────────────────────────────────────────
|
|
1005
|
-
cmd_fix() {
|
|
1006
|
-
local content="${1:-}"
|
|
1007
|
-
[[ -n "$content" ]] || die "使い方: ./.spec-runner/scripts/spec-runner.sh fix <修正内容>"
|
|
1008
|
-
|
|
1009
|
-
echo ""
|
|
1010
|
-
step "修正フロー: $content"
|
|
1011
|
-
echo ""
|
|
1012
|
-
echo "修正レベルを選択してください:"
|
|
1013
|
-
echo " 1) ドメインモデルの構造変更 → domain設計から再実行"
|
|
1014
|
-
echo " 2) ユースケースのフロー変更 → usecase設計から再実行"
|
|
1015
|
-
echo " 3) APIの仕様変更 → infra設計から再実行"
|
|
1016
|
-
echo " 4) テーブル構造の変更 → table設計から再実行"
|
|
1017
|
-
echo " 5) バグ修正(設計は正しい)→ テスト追加→実装修正"
|
|
1018
|
-
echo ""
|
|
1019
|
-
read -r -p "番号を選択 [1-5]: " level
|
|
1020
|
-
|
|
1021
|
-
local usecase slug branch
|
|
1022
|
-
slug=$(echo "$content" | tr ' ' '-' | tr -cd '[:alnum:]-' | cut -c1-30)
|
|
1023
|
-
usecase="${2:-$(state_get "usecase" 2>/dev/null || echo "unknown")}"
|
|
1024
|
-
branch="fix/$(echo "$usecase" | tr ' ' '-')-$slug"
|
|
1025
|
-
|
|
1026
|
-
git checkout -b "$branch" 2>/dev/null || warn "ブランチ作成に失敗しました(手動で作成してください)"
|
|
1027
|
-
|
|
1028
|
-
case "$level" in
|
|
1029
|
-
1)
|
|
1030
|
-
info "ドメインモデルから再設計します"
|
|
1031
|
-
info "修正ファイル:"
|
|
1032
|
-
info " docs/03_詳細設計/$(uc_slug)/ドメイン.md → status: draft に戻す"
|
|
1033
|
-
info " docs/03_詳細設計/$(uc_slug)/ユースケース.md → 再確認"
|
|
1034
|
-
info " docs/04_テスト設計/$(uc_slug).md → 再確認"
|
|
1035
|
-
;;
|
|
1036
|
-
2)
|
|
1037
|
-
info "ユースケース設計から修正します"
|
|
1038
|
-
info " docs/03_詳細設計/$(uc_slug)/ユースケース.md → status: draft に戻す"
|
|
1039
|
-
info " docs/04_テスト設計/$(uc_slug).md → 再確認"
|
|
1040
|
-
;;
|
|
1041
|
-
3)
|
|
1042
|
-
info "インフラ設計から修正します"
|
|
1043
|
-
info " docs/03_詳細設計/$(uc_slug)/インフラ.md → status: draft に戻す"
|
|
1044
|
-
;;
|
|
1045
|
-
4)
|
|
1046
|
-
info "テーブル設計から修正します"
|
|
1047
|
-
info " docs/03_詳細設計/$(uc_slug)/テーブル.md → status: draft に戻す"
|
|
1048
|
-
;;
|
|
1049
|
-
5)
|
|
1050
|
-
info "テストを追加して実装を修正します"
|
|
1051
|
-
info " テストコード追加 → git commit → ./.spec-runner/scripts/spec-runner.sh implement"
|
|
1052
|
-
;;
|
|
1053
|
-
*)
|
|
1054
|
-
die "無効な選択です"
|
|
1055
|
-
;;
|
|
1056
|
-
esac
|
|
1057
|
-
|
|
1058
|
-
state_set_str "phase" "fix"
|
|
1059
|
-
state_push_history "修正開始: $content (level: $level)"
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
|
-
# ── hotfix ────────────────────────────────────────────────────────────────────
|
|
1063
|
-
cmd_hotfix() {
|
|
1064
|
-
local content="${1:-}"
|
|
1065
|
-
[[ -n "$content" ]] || die "使い方: ./.spec-runner/scripts/spec-runner.sh hotfix <内容>"
|
|
1066
|
-
|
|
1067
|
-
local slug branch
|
|
1068
|
-
slug=$(echo "$content" | tr ' ' '-' | tr -cd '[:alnum:]-' | cut -c1-30)
|
|
1069
|
-
branch="hotfix/$slug"
|
|
1070
|
-
|
|
1071
|
-
step "緊急修正ブランチを作成: $branch"
|
|
1072
|
-
git checkout -b "$branch" main
|
|
1073
|
-
|
|
1074
|
-
ok "ブランチ作成: $branch"
|
|
1075
|
-
warn "緊急修正後、ドキュメント負債として記録されます"
|
|
1076
|
-
|
|
1077
|
-
# debt.mdに追記
|
|
1078
|
-
mkdir -p "$(dirname "$DEBT_FILE")"
|
|
1079
|
-
[[ -f "$DEBT_FILE" ]] || echo "# ドキュメント負債" > "$DEBT_FILE"
|
|
1080
|
-
|
|
1081
|
-
cat >> "$DEBT_FILE" <<DEBT
|
|
1082
|
-
|
|
1083
|
-
## $(date +%Y-%m-%d): hotfix/$slug
|
|
1084
|
-
|
|
1085
|
-
- [ ] 修正内容に対応するテスト設計ドキュメントの更新
|
|
1086
|
-
- hotfix内容: $content
|
|
1087
|
-
- 対象ユースケース: 要確認
|
|
1088
|
-
- 修正したコード: 要確認
|
|
1089
|
-
DEBT
|
|
1090
|
-
|
|
1091
|
-
ok "負債を記録: $DEBT_FILE"
|
|
1092
|
-
info "修正完了後: git push origin $branch → main へPR"
|
|
1093
|
-
info "次回の init 時に負債の消化を促されます"
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
# ── メインルーター ────────────────────────────────────────────────────────────
|
|
1097
|
-
main() {
|
|
1098
|
-
local cmd="${1:-help}"
|
|
1099
|
-
shift || true
|
|
1100
|
-
|
|
1101
|
-
case "$cmd" in
|
|
1102
|
-
init) cmd_init "$@" ;;
|
|
1103
|
-
require) cmd_require "$@" ;;
|
|
1104
|
-
design-high) cmd_design_high "$@" ;;
|
|
1105
|
-
design-detail) cmd_design_detail "$@" ;;
|
|
1106
|
-
test-design) cmd_test_design "$@" ;;
|
|
1107
|
-
implement) cmd_implement "$@" ;;
|
|
1108
|
-
review-pass) cmd_review_pass "$@" ;;
|
|
1109
|
-
set-gate) cmd_set_gate "$@" ;;
|
|
1110
|
-
status) cmd_status "$@" ;;
|
|
1111
|
-
fix) cmd_fix "$@" ;;
|
|
1112
|
-
hotfix) cmd_hotfix "$@" ;;
|
|
1113
|
-
help|--help|-h)
|
|
1114
|
-
echo ""
|
|
1115
|
-
echo -e "${BOLD}使い方:${NC}"
|
|
1116
|
-
echo " ./.spec-runner/scripts/spec-runner.sh <コマンド> [引数]"
|
|
1117
|
-
echo ""
|
|
1118
|
-
echo -e "${BOLD}新規開発フロー:${NC}"
|
|
1119
|
-
echo " init [ユースケース名] [集約名] 引数なしで設定対話。名前を渡すとユースケース作成"
|
|
1120
|
-
echo " require 要件定義フェーズ(ファイルパスを確認)"
|
|
1121
|
-
echo " design-high 概要設計フェーズに移行(ゲートチェック)"
|
|
1122
|
-
echo " design-detail <sub> 詳細設計フェーズ(sub: domain|usecase|table|infra)"
|
|
1123
|
-
echo " test-design テスト設計フェーズに移行(ゲートチェック)"
|
|
1124
|
-
echo " implement 実装フェーズに移行(ゲートチェック)"
|
|
1125
|
-
echo ""
|
|
1126
|
-
echo -e "${BOLD}レビュー:${NC}"
|
|
1127
|
-
echo " review-pass <ファイル> ドキュメントをレビュー通過にする"
|
|
1128
|
-
echo " set-gate <ゲート名> 手動でゲートフラグを立てる(日本語可。例: 用語集確認済み)"
|
|
1129
|
-
echo ""
|
|
1130
|
-
echo -e "${BOLD}確認:${NC}"
|
|
1131
|
-
echo " status 現在の状態を表示"
|
|
1132
|
-
echo ""
|
|
1133
|
-
echo -e "${BOLD}修正フロー:${NC}"
|
|
1134
|
-
echo " fix <修正内容> 通常修正フロー(影響範囲分析)"
|
|
1135
|
-
echo " hotfix <内容> 緊急修正(負債として記録)"
|
|
1136
|
-
echo ""
|
|
1137
|
-
;;
|
|
1138
|
-
*)
|
|
1139
|
-
die "不明なコマンド: $cmd\n使い方: ./.spec-runner/scripts/spec-runner.sh help"
|
|
1140
|
-
;;
|
|
1141
|
-
esac
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
main "$@"
|