sdd-tool 1.0.1 → 1.2.0
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/LICENSE +21 -21
- package/README.md +533 -471
- package/bin/sdd.js +2 -2
- package/dist/cli/index.js +11158 -5042
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +80 -81
- package/templates/agents.md +62 -62
- package/templates/constitution.md +43 -43
- package/templates/git/.gitattributes.sdd +39 -0
- package/templates/git/.gitignore.sdd +44 -0
- package/templates/git/.gitmessage +20 -0
- package/templates/git/commitlint.config.js +122 -0
- package/templates/github/branch-protection.md +194 -0
- package/templates/github/workflows/sdd-labeler.yml +125 -0
- package/templates/github/workflows/sdd-validate.yml +85 -0
- package/templates/proposal.md +71 -71
- package/templates/spec.md +27 -27
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDD 프로젝트용 commitlint 설정
|
|
3
|
+
*
|
|
4
|
+
* 사용법:
|
|
5
|
+
* 1. 이 파일을 프로젝트 루트에 복사
|
|
6
|
+
* 2. npm install --save-dev @commitlint/cli
|
|
7
|
+
* 3. Git hooks에서 commitlint 실행
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
module.exports = {
|
|
11
|
+
extends: ['@commitlint/config-conventional'],
|
|
12
|
+
|
|
13
|
+
// 스펙 커밋 타입 추가
|
|
14
|
+
rules: {
|
|
15
|
+
'type-enum': [
|
|
16
|
+
2,
|
|
17
|
+
'always',
|
|
18
|
+
[
|
|
19
|
+
// SDD 스펙 타입
|
|
20
|
+
'spec', // 스펙 신규 생성
|
|
21
|
+
'spec-update', // 스펙 내용 수정
|
|
22
|
+
'spec-status', // 스펙 상태 변경
|
|
23
|
+
'plan', // 구현 계획
|
|
24
|
+
'tasks', // 작업 분해
|
|
25
|
+
'constitution', // Constitution 변경
|
|
26
|
+
'sdd-config', // SDD 설정 변경
|
|
27
|
+
|
|
28
|
+
// Conventional Commits 타입
|
|
29
|
+
'feat', // 새 기능
|
|
30
|
+
'fix', // 버그 수정
|
|
31
|
+
'docs', // 문서 변경
|
|
32
|
+
'style', // 코드 포맷팅
|
|
33
|
+
'refactor', // 리팩토링
|
|
34
|
+
'perf', // 성능 개선
|
|
35
|
+
'test', // 테스트
|
|
36
|
+
'build', // 빌드 시스템
|
|
37
|
+
'ci', // CI 설정
|
|
38
|
+
'chore', // 기타 작업
|
|
39
|
+
'revert', // 되돌리기
|
|
40
|
+
],
|
|
41
|
+
],
|
|
42
|
+
|
|
43
|
+
// 스코프 형식: 영문 소문자, 하이픈, 슬래시, 쉼표, 별표 허용
|
|
44
|
+
'scope-case': [2, 'always', 'lower-case'],
|
|
45
|
+
'scope-empty': [0], // 스코프는 선택사항
|
|
46
|
+
|
|
47
|
+
// 제목 규칙
|
|
48
|
+
'subject-case': [0], // 케이스 제한 없음 (한글 허용)
|
|
49
|
+
'subject-empty': [2, 'never'],
|
|
50
|
+
'subject-max-length': [2, 'always', 50],
|
|
51
|
+
|
|
52
|
+
// 본문 규칙
|
|
53
|
+
'body-max-line-length': [2, 'always', 72],
|
|
54
|
+
|
|
55
|
+
// 헤더 규칙
|
|
56
|
+
'header-max-length': [2, 'always', 72],
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
// 에러 메시지 한글화
|
|
60
|
+
prompt: {
|
|
61
|
+
messages: {
|
|
62
|
+
skip: '(엔터로 건너뛰기)',
|
|
63
|
+
max: '최대 %d자',
|
|
64
|
+
min: '최소 %d자',
|
|
65
|
+
emptyWarning: '비어있으면 안 됩니다',
|
|
66
|
+
upperLimitWarning: '글자 수 초과',
|
|
67
|
+
lowerLimitWarning: '글자 수 부족',
|
|
68
|
+
},
|
|
69
|
+
questions: {
|
|
70
|
+
type: {
|
|
71
|
+
description: '커밋 유형을 선택하세요',
|
|
72
|
+
enum: {
|
|
73
|
+
spec: { description: '스펙 신규 생성', title: 'Spec' },
|
|
74
|
+
'spec-update': { description: '스펙 내용 수정', title: 'Spec Update' },
|
|
75
|
+
'spec-status': { description: '스펙 상태 변경', title: 'Spec Status' },
|
|
76
|
+
plan: { description: '구현 계획', title: 'Plan' },
|
|
77
|
+
tasks: { description: '작업 분해', title: 'Tasks' },
|
|
78
|
+
constitution: { description: 'Constitution 변경', title: 'Constitution' },
|
|
79
|
+
'sdd-config': { description: 'SDD 설정 변경', title: 'SDD Config' },
|
|
80
|
+
feat: { description: '새 기능', title: 'Feature' },
|
|
81
|
+
fix: { description: '버그 수정', title: 'Fix' },
|
|
82
|
+
docs: { description: '문서 변경', title: 'Docs' },
|
|
83
|
+
style: { description: '코드 포맷팅', title: 'Style' },
|
|
84
|
+
refactor: { description: '리팩토링', title: 'Refactor' },
|
|
85
|
+
perf: { description: '성능 개선', title: 'Perf' },
|
|
86
|
+
test: { description: '테스트', title: 'Test' },
|
|
87
|
+
build: { description: '빌드 시스템', title: 'Build' },
|
|
88
|
+
ci: { description: 'CI 설정', title: 'CI' },
|
|
89
|
+
chore: { description: '기타 작업', title: 'Chore' },
|
|
90
|
+
revert: { description: '되돌리기', title: 'Revert' },
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
scope: {
|
|
94
|
+
description: '스코프를 입력하세요 (예: auth, auth/user-login)',
|
|
95
|
+
},
|
|
96
|
+
subject: {
|
|
97
|
+
description: '간결한 변경 설명을 입력하세요',
|
|
98
|
+
},
|
|
99
|
+
body: {
|
|
100
|
+
description: '상세한 변경 설명을 입력하세요 (선택)',
|
|
101
|
+
},
|
|
102
|
+
isBreaking: {
|
|
103
|
+
description: 'Breaking Change가 있나요?',
|
|
104
|
+
},
|
|
105
|
+
breakingBody: {
|
|
106
|
+
description: 'Breaking Change 상세 내용을 입력하세요',
|
|
107
|
+
},
|
|
108
|
+
breaking: {
|
|
109
|
+
description: 'Breaking Change 요약을 입력하세요',
|
|
110
|
+
},
|
|
111
|
+
isIssueAffected: {
|
|
112
|
+
description: '관련 이슈가 있나요?',
|
|
113
|
+
},
|
|
114
|
+
issuesBody: {
|
|
115
|
+
description: '이슈 참조 (예: Refs: #123)',
|
|
116
|
+
},
|
|
117
|
+
issues: {
|
|
118
|
+
description: '이슈 번호를 입력하세요',
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
};
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# GitHub Branch Protection 설정 가이드
|
|
2
|
+
|
|
3
|
+
SDD 프로젝트에 권장하는 브랜치 보호 규칙입니다.
|
|
4
|
+
|
|
5
|
+
## 설정 위치
|
|
6
|
+
|
|
7
|
+
Repository → Settings → Branches → Add branch protection rule
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## main 브랜치 규칙
|
|
12
|
+
|
|
13
|
+
### Branch name pattern
|
|
14
|
+
```
|
|
15
|
+
main
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### 권장 설정
|
|
19
|
+
|
|
20
|
+
#### Protect matching branches
|
|
21
|
+
|
|
22
|
+
- [x] **Require a pull request before merging**
|
|
23
|
+
- [x] Require approvals: `2`
|
|
24
|
+
- [x] Dismiss stale pull request approvals when new commits are pushed
|
|
25
|
+
- [x] Require review from Code Owners
|
|
26
|
+
- [ ] Restrict who can dismiss pull request reviews
|
|
27
|
+
|
|
28
|
+
- [x] **Require status checks to pass before merging**
|
|
29
|
+
- [x] Require branches to be up to date before merging
|
|
30
|
+
- Status checks:
|
|
31
|
+
- `sdd-validate`
|
|
32
|
+
- `sdd-lint` (있는 경우)
|
|
33
|
+
|
|
34
|
+
- [x] **Require conversation resolution before merging**
|
|
35
|
+
|
|
36
|
+
- [ ] **Require signed commits** (선택)
|
|
37
|
+
|
|
38
|
+
- [x] **Require linear history** (권장)
|
|
39
|
+
|
|
40
|
+
- [ ] **Require merge queue** (대규모 팀)
|
|
41
|
+
|
|
42
|
+
- [ ] **Require deployments to succeed** (CI/CD)
|
|
43
|
+
|
|
44
|
+
#### Rules applied to everyone including administrators
|
|
45
|
+
|
|
46
|
+
- [x] **Do not allow bypassing the above settings**
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## constitution/* 브랜치 규칙
|
|
51
|
+
|
|
52
|
+
### Branch name pattern
|
|
53
|
+
```
|
|
54
|
+
constitution/*
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 권장 설정
|
|
58
|
+
|
|
59
|
+
- [x] **Require a pull request before merging**
|
|
60
|
+
- [x] Require approvals: `3` (더 많은 리뷰어)
|
|
61
|
+
- [x] Dismiss stale pull request approvals
|
|
62
|
+
|
|
63
|
+
- [x] **Require status checks to pass**
|
|
64
|
+
- `sdd-validate`
|
|
65
|
+
- `constitution-check` (있는 경우)
|
|
66
|
+
|
|
67
|
+
- [x] **Restrict who can push**
|
|
68
|
+
- 팀 리드, 아키텍트만
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## spec/* 브랜치 규칙 (선택)
|
|
73
|
+
|
|
74
|
+
작업 중인 스펙 브랜치는 보통 보호하지 않습니다.
|
|
75
|
+
필요한 경우 아래 규칙을 적용할 수 있습니다.
|
|
76
|
+
|
|
77
|
+
### Branch name pattern
|
|
78
|
+
```
|
|
79
|
+
spec/*
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 최소 설정 (선택)
|
|
83
|
+
|
|
84
|
+
- [ ] Require a pull request (불필요)
|
|
85
|
+
- [ ] Require status checks (불필요)
|
|
86
|
+
- [x] **Allow force pushes** (히스토리 정리용)
|
|
87
|
+
- [x] **Allow deletions** (병합 후 삭제)
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## CODEOWNERS 설정
|
|
92
|
+
|
|
93
|
+
`.github/CODEOWNERS` 파일을 생성하여 도메인별 리뷰어를 지정합니다.
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
# SDD 스펙 파일 오너십
|
|
97
|
+
|
|
98
|
+
# 전역 스펙 관리자
|
|
99
|
+
.sdd/ @sdd-maintainers
|
|
100
|
+
|
|
101
|
+
# Constitution은 리드만
|
|
102
|
+
.sdd/constitution.md @tech-leads @architects
|
|
103
|
+
|
|
104
|
+
# 도메인별 오너
|
|
105
|
+
.sdd/specs/auth/ @security-team
|
|
106
|
+
.sdd/specs/billing/ @billing-team
|
|
107
|
+
.sdd/specs/core/ @core-team
|
|
108
|
+
|
|
109
|
+
# 도메인 설정
|
|
110
|
+
.sdd/domains.yml @sdd-maintainers
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 상태 체크 설정
|
|
116
|
+
|
|
117
|
+
### GitHub Actions 워크플로우
|
|
118
|
+
|
|
119
|
+
`.github/workflows/sdd-validate.yml` 파일이 있어야 상태 체크가 활성화됩니다.
|
|
120
|
+
|
|
121
|
+
```yaml
|
|
122
|
+
name: SDD Validate
|
|
123
|
+
|
|
124
|
+
on:
|
|
125
|
+
pull_request:
|
|
126
|
+
paths:
|
|
127
|
+
- '.sdd/**'
|
|
128
|
+
|
|
129
|
+
jobs:
|
|
130
|
+
validate:
|
|
131
|
+
runs-on: ubuntu-latest
|
|
132
|
+
steps:
|
|
133
|
+
- uses: actions/checkout@v4
|
|
134
|
+
- name: Setup Node
|
|
135
|
+
uses: actions/setup-node@v4
|
|
136
|
+
with:
|
|
137
|
+
node-version: '20'
|
|
138
|
+
- name: Install SDD
|
|
139
|
+
run: npm install -g sdd-tool
|
|
140
|
+
- name: Validate Specs
|
|
141
|
+
run: sdd validate --ci
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 상태 체크 추가 방법
|
|
145
|
+
|
|
146
|
+
1. 워크플로우 실행 후 (최소 1번)
|
|
147
|
+
2. Settings → Branches → main 규칙 편집
|
|
148
|
+
3. "Require status checks" 섹션
|
|
149
|
+
4. 검색창에 `sdd-validate` 입력
|
|
150
|
+
5. 체크 추가
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## 빠른 설정 체크리스트
|
|
155
|
+
|
|
156
|
+
### main 브랜치
|
|
157
|
+
- [ ] Require PR with 2 approvals
|
|
158
|
+
- [ ] Dismiss stale reviews
|
|
159
|
+
- [ ] Require status checks (sdd-validate)
|
|
160
|
+
- [ ] Require up-to-date branches
|
|
161
|
+
- [ ] Require linear history
|
|
162
|
+
|
|
163
|
+
### constitution/* 브랜치
|
|
164
|
+
- [ ] Require PR with 3 approvals
|
|
165
|
+
- [ ] Restrict push to leads only
|
|
166
|
+
|
|
167
|
+
### 추가 설정
|
|
168
|
+
- [ ] CODEOWNERS 파일 생성
|
|
169
|
+
- [ ] GitHub Actions 워크플로우 추가
|
|
170
|
+
- [ ] 자동 브랜치 삭제 활성화
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 문제 해결
|
|
175
|
+
|
|
176
|
+
### "Status check not found"
|
|
177
|
+
|
|
178
|
+
상태 체크가 보이지 않으면:
|
|
179
|
+
1. 워크플로우가 최소 1번 실행되어야 함
|
|
180
|
+
2. PR을 `.sdd/` 경로 변경으로 생성
|
|
181
|
+
3. 워크플로우 이름 확인 (`sdd-validate`)
|
|
182
|
+
|
|
183
|
+
### "Required reviews not satisfied"
|
|
184
|
+
|
|
185
|
+
리뷰 수가 부족하면:
|
|
186
|
+
1. 팀원에게 리뷰 요청
|
|
187
|
+
2. CODEOWNERS에 정의된 오너 확인
|
|
188
|
+
3. 본인 승인은 카운트 안 됨
|
|
189
|
+
|
|
190
|
+
### Force push 필요
|
|
191
|
+
|
|
192
|
+
보호된 브랜치에 force push가 필요하면:
|
|
193
|
+
1. 임시로 규칙 비활성화
|
|
194
|
+
2. 또는 새 브랜치에서 작업 후 PR
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# SDD PR 라벨러 워크플로우
|
|
2
|
+
# 변경된 도메인에 따라 자동으로 라벨을 추가합니다
|
|
3
|
+
|
|
4
|
+
name: SDD Labeler
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
pull_request:
|
|
8
|
+
types: [opened, synchronize]
|
|
9
|
+
paths:
|
|
10
|
+
- '.sdd/**'
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
label:
|
|
14
|
+
name: Add Labels
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout
|
|
19
|
+
uses: actions/checkout@v4
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0
|
|
22
|
+
|
|
23
|
+
- name: Detect Changes
|
|
24
|
+
id: changes
|
|
25
|
+
run: |
|
|
26
|
+
# 변경된 도메인 감지
|
|
27
|
+
DOMAINS=$(git diff --name-only origin/${{ github.base_ref }} | \
|
|
28
|
+
grep "^\.sdd/specs/" | \
|
|
29
|
+
cut -d'/' -f3 | \
|
|
30
|
+
sort -u | \
|
|
31
|
+
tr '\n' ' ')
|
|
32
|
+
echo "domains=$DOMAINS" >> $GITHUB_OUTPUT
|
|
33
|
+
|
|
34
|
+
# Constitution 변경 감지
|
|
35
|
+
if git diff --name-only origin/${{ github.base_ref }} | grep -q "constitution.md"; then
|
|
36
|
+
echo "constitution=true" >> $GITHUB_OUTPUT
|
|
37
|
+
else
|
|
38
|
+
echo "constitution=false" >> $GITHUB_OUTPUT
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# 스펙 변경 타입 감지
|
|
42
|
+
ADDED=$(git diff --name-only --diff-filter=A origin/${{ github.base_ref }} | grep "^\.sdd/specs/" | wc -l)
|
|
43
|
+
MODIFIED=$(git diff --name-only --diff-filter=M origin/${{ github.base_ref }} | grep "^\.sdd/specs/" | wc -l)
|
|
44
|
+
DELETED=$(git diff --name-only --diff-filter=D origin/${{ github.base_ref }} | grep "^\.sdd/specs/" | wc -l)
|
|
45
|
+
|
|
46
|
+
if [ "$ADDED" -gt 0 ]; then
|
|
47
|
+
echo "has_added=true" >> $GITHUB_OUTPUT
|
|
48
|
+
fi
|
|
49
|
+
if [ "$MODIFIED" -gt 0 ]; then
|
|
50
|
+
echo "has_modified=true" >> $GITHUB_OUTPUT
|
|
51
|
+
fi
|
|
52
|
+
if [ "$DELETED" -gt 0 ]; then
|
|
53
|
+
echo "has_deleted=true" >> $GITHUB_OUTPUT
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
- name: Create Labels if Not Exist
|
|
57
|
+
uses: actions/github-script@v7
|
|
58
|
+
with:
|
|
59
|
+
script: |
|
|
60
|
+
const domains = '${{ steps.changes.outputs.domains }}'.trim().split(' ').filter(Boolean);
|
|
61
|
+
|
|
62
|
+
const labelConfigs = [
|
|
63
|
+
...domains.map(d => ({ name: `spec:${d}`, color: '0366d6', description: `${d} 도메인 스펙` })),
|
|
64
|
+
{ name: 'constitution', color: 'b60205', description: 'Constitution 변경' },
|
|
65
|
+
{ name: 'spec:new', color: '0e8a16', description: '새 스펙 추가' },
|
|
66
|
+
{ name: 'spec:update', color: 'fbca04', description: '스펙 수정' },
|
|
67
|
+
{ name: 'spec:remove', color: 'd93f0b', description: '스펙 삭제' },
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
for (const label of labelConfigs) {
|
|
71
|
+
try {
|
|
72
|
+
await github.rest.issues.getLabel({
|
|
73
|
+
owner: context.repo.owner,
|
|
74
|
+
repo: context.repo.repo,
|
|
75
|
+
name: label.name,
|
|
76
|
+
});
|
|
77
|
+
} catch (e) {
|
|
78
|
+
if (e.status === 404) {
|
|
79
|
+
await github.rest.issues.createLabel({
|
|
80
|
+
owner: context.repo.owner,
|
|
81
|
+
repo: context.repo.repo,
|
|
82
|
+
name: label.name,
|
|
83
|
+
color: label.color,
|
|
84
|
+
description: label.description,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
- name: Apply Labels
|
|
91
|
+
uses: actions/github-script@v7
|
|
92
|
+
with:
|
|
93
|
+
script: |
|
|
94
|
+
const labels = [];
|
|
95
|
+
|
|
96
|
+
// 도메인 라벨
|
|
97
|
+
const domains = '${{ steps.changes.outputs.domains }}'.trim().split(' ').filter(Boolean);
|
|
98
|
+
labels.push(...domains.map(d => `spec:${d}`));
|
|
99
|
+
|
|
100
|
+
// Constitution 라벨
|
|
101
|
+
if ('${{ steps.changes.outputs.constitution }}' === 'true') {
|
|
102
|
+
labels.push('constitution');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 변경 타입 라벨
|
|
106
|
+
if ('${{ steps.changes.outputs.has_added }}' === 'true') {
|
|
107
|
+
labels.push('spec:new');
|
|
108
|
+
}
|
|
109
|
+
if ('${{ steps.changes.outputs.has_modified }}' === 'true') {
|
|
110
|
+
labels.push('spec:update');
|
|
111
|
+
}
|
|
112
|
+
if ('${{ steps.changes.outputs.has_deleted }}' === 'true') {
|
|
113
|
+
labels.push('spec:remove');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (labels.length > 0) {
|
|
117
|
+
await github.rest.issues.addLabels({
|
|
118
|
+
issue_number: context.issue.number,
|
|
119
|
+
owner: context.repo.owner,
|
|
120
|
+
repo: context.repo.repo,
|
|
121
|
+
labels: labels,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
console.log(`Added labels: ${labels.join(', ')}`);
|
|
125
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# SDD 스펙 검증 워크플로우
|
|
2
|
+
# .sdd/ 파일 변경 시 자동으로 스펙을 검증합니다
|
|
3
|
+
|
|
4
|
+
name: SDD Validate
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
pull_request:
|
|
8
|
+
paths:
|
|
9
|
+
- '.sdd/**'
|
|
10
|
+
push:
|
|
11
|
+
branches:
|
|
12
|
+
- main
|
|
13
|
+
- master
|
|
14
|
+
paths:
|
|
15
|
+
- '.sdd/**'
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
validate:
|
|
19
|
+
name: Validate Specs
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
|
|
22
|
+
steps:
|
|
23
|
+
- name: Checkout
|
|
24
|
+
uses: actions/checkout@v4
|
|
25
|
+
|
|
26
|
+
- name: Setup Node.js
|
|
27
|
+
uses: actions/setup-node@v4
|
|
28
|
+
with:
|
|
29
|
+
node-version: '20'
|
|
30
|
+
|
|
31
|
+
- name: Install SDD Tool
|
|
32
|
+
run: npm install -g sdd-tool
|
|
33
|
+
|
|
34
|
+
- name: Validate Specs
|
|
35
|
+
run: sdd validate --ci
|
|
36
|
+
|
|
37
|
+
- name: Check Dependencies
|
|
38
|
+
run: sdd validate --ci || true
|
|
39
|
+
continue-on-error: true
|
|
40
|
+
|
|
41
|
+
- name: Constitution Check
|
|
42
|
+
run: sdd validate --constitution --ci || true
|
|
43
|
+
continue-on-error: true
|
|
44
|
+
|
|
45
|
+
- name: Comment on PR (failure)
|
|
46
|
+
if: failure() && github.event_name == 'pull_request'
|
|
47
|
+
uses: actions/github-script@v7
|
|
48
|
+
with:
|
|
49
|
+
script: |
|
|
50
|
+
github.rest.issues.createComment({
|
|
51
|
+
issue_number: context.issue.number,
|
|
52
|
+
owner: context.repo.owner,
|
|
53
|
+
repo: context.repo.repo,
|
|
54
|
+
body: `## ❌ SDD 검증 실패
|
|
55
|
+
|
|
56
|
+
스펙 검증에서 오류가 발견되었습니다.
|
|
57
|
+
|
|
58
|
+
### 확인 방법
|
|
59
|
+
\`\`\`bash
|
|
60
|
+
sdd validate
|
|
61
|
+
\`\`\`
|
|
62
|
+
|
|
63
|
+
### 상세 로그
|
|
64
|
+
[Actions 로그 확인](${context.payload.pull_request?.html_url}/checks)
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
*이 메시지는 자동으로 생성되었습니다.*`
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
- name: Comment on PR (success)
|
|
71
|
+
if: success() && github.event_name == 'pull_request'
|
|
72
|
+
uses: actions/github-script@v7
|
|
73
|
+
with:
|
|
74
|
+
script: |
|
|
75
|
+
github.rest.issues.createComment({
|
|
76
|
+
issue_number: context.issue.number,
|
|
77
|
+
owner: context.repo.owner,
|
|
78
|
+
repo: context.repo.repo,
|
|
79
|
+
body: `## ✅ SDD 검증 통과
|
|
80
|
+
|
|
81
|
+
모든 스펙 검증을 통과했습니다.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
*이 메시지는 자동으로 생성되었습니다.*`
|
|
85
|
+
})
|
package/templates/proposal.md
CHANGED
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: CHG-{{ID}}
|
|
3
|
-
status: draft
|
|
4
|
-
created: {{DATE}}
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# 변경 제안: {{TITLE}}
|
|
8
|
-
|
|
9
|
-
> 변경 목적 및 배경 설명
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## 배경
|
|
14
|
-
|
|
15
|
-
왜 이 변경이 필요한가?
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
## 영향 범위
|
|
20
|
-
|
|
21
|
-
### 영향받는 스펙
|
|
22
|
-
|
|
23
|
-
- `specs/{{SPEC_PATH}}`
|
|
24
|
-
|
|
25
|
-
### 변경 유형
|
|
26
|
-
|
|
27
|
-
- [ ] 신규 추가 (ADDED)
|
|
28
|
-
- [ ] 수정 (MODIFIED)
|
|
29
|
-
- [ ] 삭제 (REMOVED)
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## 변경 내용
|
|
34
|
-
|
|
35
|
-
### ADDED
|
|
36
|
-
|
|
37
|
-
(새로 추가되는 내용)
|
|
38
|
-
|
|
39
|
-
### MODIFIED
|
|
40
|
-
|
|
41
|
-
(수정되는 내용)
|
|
42
|
-
|
|
43
|
-
#### Before
|
|
44
|
-
|
|
45
|
-
```markdown
|
|
46
|
-
기존 내용
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
#### After
|
|
50
|
-
|
|
51
|
-
```markdown
|
|
52
|
-
변경된 내용
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### REMOVED
|
|
56
|
-
|
|
57
|
-
(삭제되는 내용)
|
|
58
|
-
|
|
59
|
-
---
|
|
60
|
-
|
|
61
|
-
## 리스크 평가
|
|
62
|
-
|
|
63
|
-
- 영향도: 낮음/중간/높음
|
|
64
|
-
- 복잡도: 낮음/중간/높음
|
|
65
|
-
|
|
66
|
-
---
|
|
67
|
-
|
|
68
|
-
## 검토자
|
|
69
|
-
|
|
70
|
-
- [ ] @reviewer1
|
|
71
|
-
- [ ] @reviewer2
|
|
1
|
+
---
|
|
2
|
+
id: CHG-{{ID}}
|
|
3
|
+
status: draft
|
|
4
|
+
created: {{DATE}}
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 변경 제안: {{TITLE}}
|
|
8
|
+
|
|
9
|
+
> 변경 목적 및 배경 설명
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 배경
|
|
14
|
+
|
|
15
|
+
왜 이 변경이 필요한가?
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 영향 범위
|
|
20
|
+
|
|
21
|
+
### 영향받는 스펙
|
|
22
|
+
|
|
23
|
+
- `specs/{{SPEC_PATH}}`
|
|
24
|
+
|
|
25
|
+
### 변경 유형
|
|
26
|
+
|
|
27
|
+
- [ ] 신규 추가 (ADDED)
|
|
28
|
+
- [ ] 수정 (MODIFIED)
|
|
29
|
+
- [ ] 삭제 (REMOVED)
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 변경 내용
|
|
34
|
+
|
|
35
|
+
### ADDED
|
|
36
|
+
|
|
37
|
+
(새로 추가되는 내용)
|
|
38
|
+
|
|
39
|
+
### MODIFIED
|
|
40
|
+
|
|
41
|
+
(수정되는 내용)
|
|
42
|
+
|
|
43
|
+
#### Before
|
|
44
|
+
|
|
45
|
+
```markdown
|
|
46
|
+
기존 내용
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
#### After
|
|
50
|
+
|
|
51
|
+
```markdown
|
|
52
|
+
변경된 내용
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### REMOVED
|
|
56
|
+
|
|
57
|
+
(삭제되는 내용)
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 리스크 평가
|
|
62
|
+
|
|
63
|
+
- 영향도: 낮음/중간/높음
|
|
64
|
+
- 복잡도: 낮음/중간/높음
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 검토자
|
|
69
|
+
|
|
70
|
+
- [ ] @reviewer1
|
|
71
|
+
- [ ] @reviewer2
|