@sk8metal/michi-cli 0.0.3 → 0.0.5
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/CHANGELOG.md +38 -0
- package/README.md +25 -25
- package/dist/scripts/config/config-schema.d.ts +109 -600
- package/dist/scripts/config/config-schema.d.ts.map +1 -1
- package/dist/scripts/config/config-schema.js.map +1 -1
- package/dist/scripts/config-interactive.d.ts +1 -1
- package/dist/scripts/config-interactive.d.ts.map +1 -1
- package/dist/scripts/config-interactive.js +7 -7
- package/dist/scripts/config-interactive.js.map +1 -1
- package/dist/scripts/confluence-sync.js +5 -5
- package/dist/scripts/confluence-sync.js.map +1 -1
- package/dist/scripts/create-project.d.ts +2 -2
- package/dist/scripts/create-project.js +2 -2
- package/dist/scripts/create-project.js.map +1 -1
- package/dist/scripts/jira-sync.js +8 -8
- package/dist/scripts/jira-sync.js.map +1 -1
- package/dist/scripts/markdown-to-confluence.js +1 -1
- package/dist/scripts/markdown-to-confluence.js.map +1 -1
- package/dist/scripts/multi-project-estimate.js +1 -1
- package/dist/scripts/phase-runner.js.map +1 -1
- package/dist/scripts/pre-flight-check.js +1 -1
- package/dist/scripts/setup-existing-project.js.map +1 -1
- package/dist/scripts/utils/__tests__/config-loader.test.d.ts +5 -0
- package/dist/scripts/utils/__tests__/config-loader.test.d.ts.map +1 -0
- package/dist/scripts/utils/__tests__/config-loader.test.js +201 -0
- package/dist/scripts/utils/__tests__/config-loader.test.js.map +1 -0
- package/dist/scripts/utils/__tests__/config-validator.test.js +29 -16
- package/dist/scripts/utils/__tests__/config-validator.test.js.map +1 -1
- package/dist/scripts/utils/config-loader.d.ts +4 -0
- package/dist/scripts/utils/config-loader.d.ts.map +1 -1
- package/dist/scripts/utils/config-loader.js +24 -2
- package/dist/scripts/utils/config-loader.js.map +1 -1
- package/dist/scripts/utils/config-validator.d.ts.map +1 -1
- package/dist/scripts/utils/config-validator.js +50 -51
- package/dist/scripts/utils/config-validator.js.map +1 -1
- package/dist/scripts/utils/confluence-hierarchy.js +7 -7
- package/dist/scripts/utils/confluence-hierarchy.js.map +1 -1
- package/dist/scripts/validate-phase.js.map +1 -1
- package/dist/scripts/workflow-orchestrator.js.map +1 -1
- package/dist/src/cli.js +2 -2
- package/dist/src/cli.js.map +1 -1
- package/dist/vitest.config.d.ts.map +1 -1
- package/dist/vitest.config.js +8 -4
- package/dist/vitest.config.js.map +1 -1
- package/docs/config-reference.md +76 -197
- package/docs/customization-guide.md +61 -9
- package/docs/multi-project.md +157 -25
- package/docs/new-project-setup.md +36 -36
- package/docs/quick-reference.md +23 -20
- package/docs/release.md +365 -0
- package/docs/setup.md +5 -3
- package/env.example +3 -1
- package/package.json +15 -13
- package/scripts/config/config-schema.ts +5 -5
- package/scripts/config-interactive.ts +7 -6
- package/scripts/confluence-sync.ts +5 -5
- package/scripts/create-project.ts +21 -21
- package/scripts/jira-sync.ts +8 -8
- package/scripts/markdown-to-confluence.ts +1 -1
- package/scripts/multi-project-estimate.ts +1 -1
- package/scripts/phase-runner.ts +8 -8
- package/scripts/pre-flight-check.ts +1 -1
- package/scripts/setup-existing-project.ts +9 -9
- package/scripts/setup-existing.sh +1 -1
- package/scripts/utils/__tests__/config-loader.test.ts +254 -0
- package/scripts/utils/__tests__/config-validator.test.ts +32 -16
- package/scripts/utils/config-loader.ts +30 -2
- package/scripts/utils/config-validator.ts +51 -50
- package/scripts/utils/confluence-hierarchy.ts +51 -51
- package/scripts/validate-phase.ts +11 -11
- package/scripts/workflow-orchestrator.ts +27 -27
- package/docs/testing.md +0 -202
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
import { existsSync, readFileSync } from 'fs';
|
|
6
6
|
import { resolve } from 'path';
|
|
7
7
|
import { AppConfigSchema } from '../config/config-schema.js';
|
|
8
|
+
import type { ZodIssue } from 'zod';
|
|
8
9
|
import type { AppConfig } from '../config/config-schema.js';
|
|
9
|
-
import { getConfig } from './config-loader.js';
|
|
10
|
+
import { getConfig, getConfigPath } from './config-loader.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* バリデーション結果
|
|
@@ -26,7 +27,7 @@ export function validateProjectConfig(projectRoot: string = process.cwd()): Vali
|
|
|
26
27
|
const warnings: string[] = [];
|
|
27
28
|
const info: string[] = [];
|
|
28
29
|
|
|
29
|
-
const configPath =
|
|
30
|
+
const configPath = getConfigPath(projectRoot);
|
|
30
31
|
|
|
31
32
|
if (!existsSync(configPath)) {
|
|
32
33
|
// 設定ファイルが存在しない場合は情報メッセージ(デフォルト設定を使用)
|
|
@@ -47,8 +48,8 @@ export function validateProjectConfig(projectRoot: string = process.cwd()): Vali
|
|
|
47
48
|
const result = AppConfigSchema.safeParse(parsed);
|
|
48
49
|
|
|
49
50
|
if (!result.success) {
|
|
50
|
-
result.error.
|
|
51
|
-
const path = error.path.join('.');
|
|
51
|
+
result.error.issues.forEach((error: ZodIssue) => {
|
|
52
|
+
const path = error.path.map(String).join('.');
|
|
52
53
|
errors.push(`${path}: ${error.message}`);
|
|
53
54
|
});
|
|
54
55
|
|
|
@@ -183,7 +184,7 @@ export function validateForConfluenceSync(
|
|
|
183
184
|
const info: string[] = [];
|
|
184
185
|
|
|
185
186
|
const config = getConfig(projectRoot);
|
|
186
|
-
const configPath =
|
|
187
|
+
const configPath = getConfigPath(projectRoot);
|
|
187
188
|
|
|
188
189
|
// Confluence設定のチェック
|
|
189
190
|
if (!config.confluence) {
|
|
@@ -196,15 +197,15 @@ export function validateForConfluenceSync(
|
|
|
196
197
|
if (!process.env.CONFLUENCE_PRD_SPACE) {
|
|
197
198
|
warnings.push(
|
|
198
199
|
`confluence.spaces.${docType}が設定されていません。` +
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
200
|
+
'環境変数CONFLUENCE_PRD_SPACEも設定されていないため、デフォルト値(PRD)を使用します。' +
|
|
201
|
+
'\n 推奨: .michi/config.jsonに以下を追加してください:\n' +
|
|
202
|
+
' {\n' +
|
|
203
|
+
' "confluence": {\n' +
|
|
204
|
+
' "spaces": {\n' +
|
|
204
205
|
` "${docType}": "YOUR_SPACE_KEY"\n` +
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
206
|
+
' }\n' +
|
|
207
|
+
' }\n' +
|
|
208
|
+
' }'
|
|
208
209
|
);
|
|
209
210
|
} else {
|
|
210
211
|
info.push(`confluence.spaces.${docType}が設定されていませんが、環境変数CONFLUENCE_PRD_SPACE(${process.env.CONFLUENCE_PRD_SPACE})を使用します。`);
|
|
@@ -215,29 +216,29 @@ export function validateForConfluenceSync(
|
|
|
215
216
|
if (confluence.pageCreationGranularity === 'by-hierarchy' || confluence.pageCreationGranularity === 'manual') {
|
|
216
217
|
if (!confluence.hierarchy) {
|
|
217
218
|
errors.push(
|
|
218
|
-
|
|
219
|
+
'confluence.hierarchyが設定されていません。' +
|
|
219
220
|
`pageCreationGranularityが"${confluence.pageCreationGranularity}"の場合、hierarchy設定が必須です。` +
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
221
|
+
'\n 解決方法: .michi/config.jsonに以下を追加してください:\n' +
|
|
222
|
+
' {\n' +
|
|
223
|
+
' "confluence": {\n' +
|
|
224
|
+
' "hierarchy": {\n' +
|
|
225
|
+
' "mode": "simple",\n' +
|
|
226
|
+
' "parentPageTitle": "[{projectName}] {featureName}"\n' +
|
|
227
|
+
' }\n' +
|
|
228
|
+
' }\n' +
|
|
229
|
+
' }'
|
|
229
230
|
);
|
|
230
231
|
} else if (confluence.pageCreationGranularity === 'by-hierarchy' && confluence.hierarchy && !confluence.hierarchy.parentPageTitle) {
|
|
231
232
|
warnings.push(
|
|
232
|
-
|
|
233
|
-
|
|
233
|
+
'confluence.hierarchy.parentPageTitleが設定されていません。' +
|
|
234
|
+
'by-hierarchyモードでは推奨されます。'
|
|
234
235
|
);
|
|
235
236
|
}
|
|
236
237
|
|
|
237
238
|
if (confluence.pageCreationGranularity === 'manual' && confluence.hierarchy && !confluence.hierarchy.structure) {
|
|
238
239
|
errors.push(
|
|
239
|
-
|
|
240
|
-
|
|
240
|
+
'confluence.hierarchy.structureが設定されていません。' +
|
|
241
|
+
'pageCreationGranularityが"manual"の場合、structure設定が必須です。'
|
|
241
242
|
);
|
|
242
243
|
}
|
|
243
244
|
}
|
|
@@ -262,7 +263,7 @@ export function validateForJiraSync(projectRoot: string = process.cwd()): Valida
|
|
|
262
263
|
const info: string[] = [];
|
|
263
264
|
|
|
264
265
|
const config = getConfig(projectRoot);
|
|
265
|
-
const configPath =
|
|
266
|
+
const configPath = getConfigPath(projectRoot);
|
|
266
267
|
|
|
267
268
|
// JIRA設定のチェック
|
|
268
269
|
if (!config.jira) {
|
|
@@ -274,20 +275,20 @@ export function validateForJiraSync(projectRoot: string = process.cwd()): Valida
|
|
|
274
275
|
if (!jira.issueTypes) {
|
|
275
276
|
if (!process.env.JIRA_ISSUE_TYPE_STORY) {
|
|
276
277
|
errors.push(
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
278
|
+
'jira.issueTypes.storyが設定されていません。' +
|
|
279
|
+
'環境変数JIRA_ISSUE_TYPE_STORYも設定されていないため、JIRA同期を実行できません。' +
|
|
280
|
+
'\n 解決方法1: 環境変数を設定:\n' +
|
|
281
|
+
' export JIRA_ISSUE_TYPE_STORY=10036 # JIRAインスタンス固有のID\n' +
|
|
282
|
+
'\n 解決方法2: .michi/config.jsonに以下を追加:\n' +
|
|
283
|
+
' {\n' +
|
|
284
|
+
' "jira": {\n' +
|
|
285
|
+
' "issueTypes": {\n' +
|
|
286
|
+
' "story": "10036",\n' +
|
|
287
|
+
' "subtask": "10037"\n' +
|
|
288
|
+
' }\n' +
|
|
289
|
+
' }\n' +
|
|
290
|
+
' }' +
|
|
291
|
+
'\n 確認方法: JIRA管理画面(Settings > Issues > Issue types)またはREST API: GET /rest/api/3/issuetype'
|
|
291
292
|
);
|
|
292
293
|
} else {
|
|
293
294
|
info.push(`jira.issueTypes.storyが設定されていませんが、環境変数JIRA_ISSUE_TYPE_STORY(${process.env.JIRA_ISSUE_TYPE_STORY})を使用します。`);
|
|
@@ -296,10 +297,10 @@ export function validateForJiraSync(projectRoot: string = process.cwd()): Valida
|
|
|
296
297
|
if (!jira.issueTypes.story) {
|
|
297
298
|
if (!process.env.JIRA_ISSUE_TYPE_STORY) {
|
|
298
299
|
errors.push(
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
300
|
+
'jira.issueTypes.storyが設定されていません。' +
|
|
301
|
+
'環境変数JIRA_ISSUE_TYPE_STORYも設定されていないため、JIRA同期を実行できません。' +
|
|
302
|
+
'\n 解決方法: .michi/config.jsonのjira.issueTypes.storyに値を設定するか、' +
|
|
303
|
+
'環境変数JIRA_ISSUE_TYPE_STORYを設定してください。'
|
|
303
304
|
);
|
|
304
305
|
} else {
|
|
305
306
|
info.push(`jira.issueTypes.storyが設定されていませんが、環境変数JIRA_ISSUE_TYPE_STORY(${process.env.JIRA_ISSUE_TYPE_STORY})を使用します。`);
|
|
@@ -309,8 +310,8 @@ export function validateForJiraSync(projectRoot: string = process.cwd()): Valida
|
|
|
309
310
|
if (!jira.issueTypes.subtask) {
|
|
310
311
|
if (!process.env.JIRA_ISSUE_TYPE_SUBTASK) {
|
|
311
312
|
warnings.push(
|
|
312
|
-
|
|
313
|
-
|
|
313
|
+
'jira.issueTypes.subtaskが設定されていません。' +
|
|
314
|
+
'環境変数JIRA_ISSUE_TYPE_SUBTASKも設定されていないため、サブタスクは作成されません。'
|
|
314
315
|
);
|
|
315
316
|
} else {
|
|
316
317
|
info.push(`jira.issueTypes.subtaskが設定されていませんが、環境変数JIRA_ISSUE_TYPE_SUBTASK(${process.env.JIRA_ISSUE_TYPE_SUBTASK})を使用します。`);
|
|
@@ -321,8 +322,8 @@ export function validateForJiraSync(projectRoot: string = process.cwd()): Valida
|
|
|
321
322
|
// selectedPhases設定のチェック
|
|
322
323
|
if (jira.storyCreationGranularity === 'selected-phases' && !jira.selectedPhases) {
|
|
323
324
|
errors.push(
|
|
324
|
-
|
|
325
|
-
|
|
325
|
+
'jira.selectedPhasesが設定されていません。' +
|
|
326
|
+
'storyCreationGranularityが"selected-phases"の場合、selectedPhases設定が必須です。'
|
|
326
327
|
);
|
|
327
328
|
}
|
|
328
329
|
|
|
@@ -401,7 +401,7 @@ export async function createByHierarchySimplePages(
|
|
|
401
401
|
|
|
402
402
|
// タイトルに機能名が含まれていない場合、自動的に追加(重複を避けるため)
|
|
403
403
|
if (!childPageTitle.includes(featureName)) {
|
|
404
|
-
console.warn(
|
|
404
|
+
console.warn('⚠️ Warning: pageTitleFormat does not include {featureName}. Adding feature name to ensure uniqueness.');
|
|
405
405
|
childPageTitle = `[${featureName}] ${childPageTitle}`;
|
|
406
406
|
}
|
|
407
407
|
|
|
@@ -423,7 +423,7 @@ export async function createByHierarchySimplePages(
|
|
|
423
423
|
|
|
424
424
|
// CQLクエリで見つからない場合、親ページIDなしで検索(既存ページが別の親の下にある可能性)
|
|
425
425
|
if (!existingChild) {
|
|
426
|
-
console.log(
|
|
426
|
+
console.log(' CQL search found nothing, trying search without parent filter');
|
|
427
427
|
existingChild = await client.searchPage(spaceKey, childPageTitle);
|
|
428
428
|
if (existingChild) {
|
|
429
429
|
console.log(` ⚠️ Found page with same title: ${existingChild.id}, verifying parent page ID`);
|
|
@@ -436,14 +436,14 @@ export async function createByHierarchySimplePages(
|
|
|
436
436
|
console.log(` ✅ Parent page ID matches (${parentPageId}), proceeding with update`);
|
|
437
437
|
} else {
|
|
438
438
|
// 親ページIDが一致しない場合、エラーをスロー
|
|
439
|
-
console.error(
|
|
439
|
+
console.error(' ❌ Parent page ID mismatch!');
|
|
440
440
|
console.error(` Expected parent: ${parentPageId}`);
|
|
441
441
|
console.error(` Actual parent: ${actualParentId || 'root (no parent)'}`);
|
|
442
442
|
console.error(` Page ID: ${existingChild.id}`);
|
|
443
443
|
throw new Error(
|
|
444
444
|
`Page conflict: Found page "${childPageTitle}" (ID: ${existingChild.id}) ` +
|
|
445
445
|
`under different parent (expected: ${parentPageId}, actual: ${actualParentId || 'root'}). ` +
|
|
446
|
-
|
|
446
|
+
'Cannot update foreign page. Please rename or delete the conflicting page.'
|
|
447
447
|
);
|
|
448
448
|
}
|
|
449
449
|
}
|
|
@@ -523,7 +523,7 @@ export async function createByHierarchyNestedPages(
|
|
|
523
523
|
|
|
524
524
|
// タイトルに機能名が含まれていない場合、自動的に追加(重複を避けるため)
|
|
525
525
|
if (!docTypeParentTitle.includes(featureName)) {
|
|
526
|
-
console.warn(
|
|
526
|
+
console.warn('⚠️ Warning: pageTitleFormat does not include {featureName}. Adding feature name to ensure uniqueness.');
|
|
527
527
|
docTypeParentTitle = `[${featureName}] ${docTypeParentTitle}`;
|
|
528
528
|
}
|
|
529
529
|
|
|
@@ -569,7 +569,7 @@ export async function createByHierarchyNestedPages(
|
|
|
569
569
|
|
|
570
570
|
// タイトルに機能名が含まれていない場合、自動的に追加(重複を避けるため)
|
|
571
571
|
if (!sectionPageTitle.includes(featureName)) {
|
|
572
|
-
console.warn(
|
|
572
|
+
console.warn('⚠️ Warning: pageTitleFormat does not include {featureName}. Adding feature name to ensure uniqueness.');
|
|
573
573
|
sectionPageTitle = `[${featureName}] ${sectionPageTitle}`;
|
|
574
574
|
}
|
|
575
575
|
const confluenceContent = convertMarkdownToConfluence(section.content);
|
|
@@ -697,7 +697,7 @@ export async function createManualPages(
|
|
|
697
697
|
|
|
698
698
|
// タイトルに機能名が含まれていない場合、自動的に追加(重複を避けるため)
|
|
699
699
|
if (!pageTitle.includes(featureName)) {
|
|
700
|
-
console.warn(
|
|
700
|
+
console.warn('⚠️ Warning: Manual page title does not include {featureName}. Adding feature name to ensure uniqueness.');
|
|
701
701
|
pageTitle = `[${featureName}] ${pageTitle}`;
|
|
702
702
|
}
|
|
703
703
|
|
|
@@ -785,8 +785,34 @@ export async function createPagesByGranularity(
|
|
|
785
785
|
const granularity = config.pageCreationGranularity || 'single';
|
|
786
786
|
|
|
787
787
|
switch (granularity) {
|
|
788
|
-
|
|
789
|
-
|
|
788
|
+
case 'single':
|
|
789
|
+
return await createSinglePage(
|
|
790
|
+
client,
|
|
791
|
+
spaceKey,
|
|
792
|
+
markdown,
|
|
793
|
+
config,
|
|
794
|
+
projectMeta,
|
|
795
|
+
featureName,
|
|
796
|
+
docType,
|
|
797
|
+
githubUrl
|
|
798
|
+
);
|
|
799
|
+
|
|
800
|
+
case 'by-section':
|
|
801
|
+
return await createBySectionPages(
|
|
802
|
+
client,
|
|
803
|
+
spaceKey,
|
|
804
|
+
markdown,
|
|
805
|
+
config,
|
|
806
|
+
projectMeta,
|
|
807
|
+
featureName,
|
|
808
|
+
docType,
|
|
809
|
+
githubUrl
|
|
810
|
+
);
|
|
811
|
+
|
|
812
|
+
case 'by-hierarchy': {
|
|
813
|
+
const hierarchyMode = config.hierarchy?.mode || 'simple';
|
|
814
|
+
if (hierarchyMode === 'nested') {
|
|
815
|
+
return await createByHierarchyNestedPages(
|
|
790
816
|
client,
|
|
791
817
|
spaceKey,
|
|
792
818
|
markdown,
|
|
@@ -796,9 +822,8 @@ export async function createPagesByGranularity(
|
|
|
796
822
|
docType,
|
|
797
823
|
githubUrl
|
|
798
824
|
);
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
return await createBySectionPages(
|
|
825
|
+
} else {
|
|
826
|
+
return await createByHierarchySimplePages(
|
|
802
827
|
client,
|
|
803
828
|
spaceKey,
|
|
804
829
|
markdown,
|
|
@@ -808,48 +833,23 @@ export async function createPagesByGranularity(
|
|
|
808
833
|
docType,
|
|
809
834
|
githubUrl
|
|
810
835
|
);
|
|
811
|
-
|
|
812
|
-
case 'by-hierarchy': {
|
|
813
|
-
const hierarchyMode = config.hierarchy?.mode || 'simple';
|
|
814
|
-
if (hierarchyMode === 'nested') {
|
|
815
|
-
return await createByHierarchyNestedPages(
|
|
816
|
-
client,
|
|
817
|
-
spaceKey,
|
|
818
|
-
markdown,
|
|
819
|
-
config,
|
|
820
|
-
projectMeta,
|
|
821
|
-
featureName,
|
|
822
|
-
docType,
|
|
823
|
-
githubUrl
|
|
824
|
-
);
|
|
825
|
-
} else {
|
|
826
|
-
return await createByHierarchySimplePages(
|
|
827
|
-
client,
|
|
828
|
-
spaceKey,
|
|
829
|
-
markdown,
|
|
830
|
-
config,
|
|
831
|
-
projectMeta,
|
|
832
|
-
featureName,
|
|
833
|
-
docType,
|
|
834
|
-
githubUrl
|
|
835
|
-
);
|
|
836
|
-
}
|
|
837
836
|
}
|
|
837
|
+
}
|
|
838
838
|
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
839
|
+
case 'manual':
|
|
840
|
+
return await createManualPages(
|
|
841
|
+
client,
|
|
842
|
+
spaceKey,
|
|
843
|
+
markdown,
|
|
844
|
+
config,
|
|
845
|
+
projectMeta,
|
|
846
|
+
featureName,
|
|
847
|
+
docType,
|
|
848
|
+
githubUrl
|
|
849
|
+
);
|
|
850
850
|
|
|
851
|
-
|
|
852
|
-
|
|
851
|
+
default:
|
|
852
|
+
throw new Error(`Unknown page creation granularity: ${granularity}`);
|
|
853
853
|
}
|
|
854
854
|
}
|
|
855
855
|
|
|
@@ -215,17 +215,17 @@ export function validatePhase(feature: string, phase: Phase): ValidationResult {
|
|
|
215
215
|
let result: ValidationResult;
|
|
216
216
|
|
|
217
217
|
switch (phase) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
218
|
+
case 'requirements':
|
|
219
|
+
result = validateRequirements(feature);
|
|
220
|
+
break;
|
|
221
|
+
case 'design':
|
|
222
|
+
result = validateDesign(feature);
|
|
223
|
+
break;
|
|
224
|
+
case 'tasks':
|
|
225
|
+
result = validateTasks(feature);
|
|
226
|
+
break;
|
|
227
|
+
default:
|
|
228
|
+
throw new Error(`Unknown phase: ${phase}`);
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
// 結果表示
|
|
@@ -72,35 +72,35 @@ export class WorkflowOrchestrator {
|
|
|
72
72
|
*/
|
|
73
73
|
private async executeStage(stage: WorkflowStage): Promise<void> {
|
|
74
74
|
switch (stage) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
case 'requirements':
|
|
76
|
+
console.log(' Syncing requirements to Confluence...');
|
|
77
|
+
await syncToConfluence(this.config.feature, 'requirements');
|
|
78
|
+
break;
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
case 'design':
|
|
81
|
+
console.log(' Syncing design to Confluence...');
|
|
82
|
+
await syncToConfluence(this.config.feature, 'design');
|
|
83
|
+
break;
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
case 'tasks':
|
|
86
|
+
console.log(' Creating JIRA tasks...');
|
|
87
|
+
await syncTasksToJIRA(this.config.feature);
|
|
88
|
+
break;
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
case 'implement':
|
|
91
|
+
console.log(' Implementation phase - manual step');
|
|
92
|
+
console.log(' Use: /kiro:spec-impl <feature> <tasks>');
|
|
93
|
+
break;
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
case 'test':
|
|
96
|
+
console.log(' Test phase - execute tests');
|
|
97
|
+
// TODO: テスト実行とレポート生成
|
|
98
|
+
break;
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
case 'release':
|
|
101
|
+
console.log(' Release preparation');
|
|
102
|
+
// TODO: リリースノート生成とJIRA Release作成
|
|
103
|
+
break;
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
|
|
@@ -113,9 +113,9 @@ export class WorkflowOrchestrator {
|
|
|
113
113
|
|
|
114
114
|
const gateList =
|
|
115
115
|
stage === 'requirements' ? gates.requirements :
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
stage === 'design' ? gates.design :
|
|
117
|
+
stage === 'release' ? gates.release :
|
|
118
|
+
undefined;
|
|
119
119
|
|
|
120
120
|
return Array.isArray(gateList) && gateList.length > 0;
|
|
121
121
|
}
|
package/docs/testing.md
DELETED
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
# テスト・検証ガイド
|
|
2
|
-
|
|
3
|
-
> **凡例について**: `<feature>` などの記号の意味は [README.md#凡例の記号説明](../README.md#凡例の記号説明) を参照してください。
|
|
4
|
-
|
|
5
|
-
## E2Eテストシナリオ
|
|
6
|
-
|
|
7
|
-
### シナリオ1: 単一機能の完全フロー
|
|
8
|
-
|
|
9
|
-
新機能「ユーザー認証」を要件定義からリリースまで実行:
|
|
10
|
-
|
|
11
|
-
#### Step 1: 要件定義
|
|
12
|
-
```bash
|
|
13
|
-
# 凡例
|
|
14
|
-
/kiro:spec-init <機能説明>
|
|
15
|
-
/kiro:spec-requirements <feature>
|
|
16
|
-
jj commit -m "docs: <feature> 要件定義"
|
|
17
|
-
jj git push
|
|
18
|
-
npm run confluence:sync <feature> requirements
|
|
19
|
-
|
|
20
|
-
# 具体例
|
|
21
|
-
/kiro:spec-init OAuth 2.0を使ったユーザー認証機能
|
|
22
|
-
/kiro:spec-requirements user-auth
|
|
23
|
-
jj commit -m "docs: ユーザー認証 要件定義"
|
|
24
|
-
jj git push
|
|
25
|
-
npm run confluence:sync user-auth requirements
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
**確認ポイント**:
|
|
29
|
-
- [ ] `.kiro/specs/user-auth/requirements.md` が生成された
|
|
30
|
-
- [ ] Confluenceページが作成された
|
|
31
|
-
- [ ] ラベル `project:michi, requirements, user-auth` が付与された
|
|
32
|
-
- [ ] 企画・部長にメンション通知が届いた
|
|
33
|
-
|
|
34
|
-
#### Step 2: 設計
|
|
35
|
-
```bash
|
|
36
|
-
# 凡例
|
|
37
|
-
/kiro:spec-design <feature>
|
|
38
|
-
jj commit -m "docs: <feature> 設計"
|
|
39
|
-
jj git push
|
|
40
|
-
npm run confluence:sync <feature> design
|
|
41
|
-
npm run excel:sync <feature>
|
|
42
|
-
|
|
43
|
-
# 具体例
|
|
44
|
-
/kiro:spec-design user-auth
|
|
45
|
-
jj commit -m "docs: ユーザー認証 設計"
|
|
46
|
-
jj git push
|
|
47
|
-
npm run confluence:sync user-auth design
|
|
48
|
-
npm run excel:sync user-auth
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
**確認ポイント**:
|
|
52
|
-
- [ ] `.kiro/specs/user-auth/design.md` が生成された
|
|
53
|
-
- [ ] 見積もりセクションが含まれている
|
|
54
|
-
- [ ] Confluenceページが作成された(親: 要件定義)
|
|
55
|
-
- [ ] Excelファイルが出力された
|
|
56
|
-
|
|
57
|
-
#### Step 3: タスク分割
|
|
58
|
-
```bash
|
|
59
|
-
# 凡例
|
|
60
|
-
/kiro:spec-tasks <feature>
|
|
61
|
-
jj commit -m "docs: <feature> タスク分割"
|
|
62
|
-
jj git push
|
|
63
|
-
npm run jira:sync <feature>
|
|
64
|
-
|
|
65
|
-
# 具体例
|
|
66
|
-
/kiro:spec-tasks user-auth
|
|
67
|
-
jj commit -m "docs: ユーザー認証 タスク分割"
|
|
68
|
-
jj git push
|
|
69
|
-
npm run jira:sync user-auth
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
**確認ポイント**:
|
|
73
|
-
- [ ] `.kiro/specs/user-auth/tasks.md` が生成された
|
|
74
|
-
- [ ] JIRA Epicが作成された
|
|
75
|
-
- [ ] JIRA Storyが作成された(複数)
|
|
76
|
-
- [ ] Epic-Storyリンクが設定された
|
|
77
|
-
|
|
78
|
-
#### Step 4: 実装
|
|
79
|
-
```
|
|
80
|
-
/kiro:spec-impl user-auth FE-1,BE-1
|
|
81
|
-
jj commit -m "feat: ユーザー認証実装 [MICHI-123]"
|
|
82
|
-
jj bookmark create michi/feature/user-auth -r '@-'
|
|
83
|
-
jj git push --bookmark michi/feature/user-auth --allow-new
|
|
84
|
-
npm run github:create-pr michi/feature/user-auth
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
**確認ポイント**:
|
|
88
|
-
- [ ] テストが先に書かれた(TDD)
|
|
89
|
-
- [ ] コードが実装された
|
|
90
|
-
- [ ] PRが作成された
|
|
91
|
-
- [ ] JIRA ステータスが "In Review" に更新された
|
|
92
|
-
|
|
93
|
-
### シナリオ2: マルチプロジェクト横断テスト
|
|
94
|
-
|
|
95
|
-
3つのプロジェクトで同時に要件定義を実施:
|
|
96
|
-
|
|
97
|
-
```bash
|
|
98
|
-
# プロジェクトA
|
|
99
|
-
cd customer-a-service-1
|
|
100
|
-
/kiro:spec-requirements payment-feature
|
|
101
|
-
npm run confluence:sync payment-feature
|
|
102
|
-
|
|
103
|
-
# プロジェクトB
|
|
104
|
-
cd ../customer-b-api
|
|
105
|
-
/kiro:spec-requirements user-api
|
|
106
|
-
npm run confluence:sync user-api
|
|
107
|
-
|
|
108
|
-
# プロジェクトC(Michi)
|
|
109
|
-
cd ../michi
|
|
110
|
-
/kiro:spec-requirements integration-hub
|
|
111
|
-
npm run confluence:sync integration-hub
|
|
112
|
-
|
|
113
|
-
# 横断確認
|
|
114
|
-
npm run project:list
|
|
115
|
-
npm run project:dashboard
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
**確認ポイント**:
|
|
119
|
-
- [ ] 3つのプロジェクトすべてでページ作成成功
|
|
120
|
-
- [ ] Confluenceダッシュボードに3プロジェクト表示
|
|
121
|
-
- [ ] ラベルでフィルタリング可能
|
|
122
|
-
- [ ] JIRAダッシュボードに3プロジェクト表示
|
|
123
|
-
|
|
124
|
-
## チームフィードバック収集
|
|
125
|
-
|
|
126
|
-
### フィードバック項目
|
|
127
|
-
|
|
128
|
-
#### 使いやすさ
|
|
129
|
-
- [ ] Cursorコマンドは直感的か?
|
|
130
|
-
- [ ] ドキュメントは理解しやすいか?
|
|
131
|
-
- [ ] エラーメッセージは明確か?
|
|
132
|
-
|
|
133
|
-
#### 効率性
|
|
134
|
-
- [ ] 要件定義の時間短縮できたか?
|
|
135
|
-
- [ ] Confluence/JIRA連携は手間を減らしたか?
|
|
136
|
-
- [ ] 全体の開発スピードは向上したか?
|
|
137
|
-
|
|
138
|
-
#### 品質
|
|
139
|
-
- [ ] AIが生成する仕様書の品質は十分か?
|
|
140
|
-
- [ ] テンプレートは実務に適しているか?
|
|
141
|
-
- [ ] 見積もりの精度は妥当か?
|
|
142
|
-
|
|
143
|
-
### フィードバック方法
|
|
144
|
-
|
|
145
|
-
GitHub Issuesで収集:
|
|
146
|
-
```bash
|
|
147
|
-
gh issue create --title "フィードバック: <内容>" --body "<詳細>"
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
ラベル:
|
|
151
|
-
- `feedback:usability`: 使いやすさ
|
|
152
|
-
- `feedback:efficiency`: 効率性
|
|
153
|
-
- `feedback:quality`: 品質
|
|
154
|
-
|
|
155
|
-
## 継続的改善
|
|
156
|
-
|
|
157
|
-
### Week 1-2: パイロット運用
|
|
158
|
-
- 1プロジェクトで全フロー実行
|
|
159
|
-
- 問題点を記録
|
|
160
|
-
- フィードバック収集
|
|
161
|
-
|
|
162
|
-
### Week 3-4: 改善
|
|
163
|
-
- テンプレート調整
|
|
164
|
-
- スクリプト改善
|
|
165
|
-
- ドキュメント更新
|
|
166
|
-
|
|
167
|
-
### Week 5-6: 横展開
|
|
168
|
-
- 2-3プロジェクトに展開
|
|
169
|
-
- チーム全体でフィードバック
|
|
170
|
-
|
|
171
|
-
### Week 7-8: 最適化
|
|
172
|
-
- ベストプラクティス確立
|
|
173
|
-
- 自動化範囲の拡大
|
|
174
|
-
- ツールの安定化
|
|
175
|
-
|
|
176
|
-
## メトリクス
|
|
177
|
-
|
|
178
|
-
### 効率化指標
|
|
179
|
-
|
|
180
|
-
| 指標 | 導入前 | 導入後 | 改善率 |
|
|
181
|
-
|------|--------|--------|--------|
|
|
182
|
-
| 要件定義時間 | 3日 | 0.5日 | 83% |
|
|
183
|
-
| 設計時間 | 5日 | 1日 | 80% |
|
|
184
|
-
| タスク分割時間 | 2日 | 0.5日 | 75% |
|
|
185
|
-
| ドキュメント作成 | 2日 | 0.2日 | 90% |
|
|
186
|
-
|
|
187
|
-
### 品質指標
|
|
188
|
-
|
|
189
|
-
| 指標 | 目標値 | 測定方法 |
|
|
190
|
-
|------|--------|---------|
|
|
191
|
-
| 仕様書の完成度 | 90%以上 | レビュースコア |
|
|
192
|
-
| 見積もり精度 | ±20%以内 | 実績との比較 |
|
|
193
|
-
| テストカバレッジ | 95%以上 | 自動測定 |
|
|
194
|
-
|
|
195
|
-
## 次のステップ
|
|
196
|
-
|
|
197
|
-
1. パイロットプロジェクトでE2Eテスト実行
|
|
198
|
-
2. フィードバック収集
|
|
199
|
-
3. 改善実施
|
|
200
|
-
4. 他プロジェクトに横展開
|
|
201
|
-
5. ベストプラクティス確立
|
|
202
|
-
|