@sk8metal/michi-cli 0.8.1 → 0.8.3

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.
Files changed (71) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/scripts/confluence-sync.js +2 -2
  3. package/dist/scripts/confluence-sync.js.map +1 -1
  4. package/dist/scripts/jira-sync.js +2 -2
  5. package/dist/scripts/jira-sync.js.map +1 -1
  6. package/dist/scripts/multi-project-estimate.js +2 -2
  7. package/dist/scripts/multi-project-estimate.js.map +1 -1
  8. package/dist/scripts/pr-automation.js +2 -2
  9. package/dist/scripts/pr-automation.js.map +1 -1
  10. package/dist/scripts/pre-flight-check.js +2 -2
  11. package/dist/scripts/pre-flight-check.js.map +1 -1
  12. package/dist/scripts/resource-dashboard.js +2 -2
  13. package/dist/scripts/resource-dashboard.js.map +1 -1
  14. package/dist/scripts/spec-impl-workflow.js +2 -2
  15. package/dist/scripts/spec-impl-workflow.js.map +1 -1
  16. package/dist/scripts/template/multi-repo-renderer.d.ts +1 -1
  17. package/dist/scripts/template/multi-repo-renderer.d.ts.map +1 -1
  18. package/dist/scripts/template/multi-repo-renderer.js +8 -3
  19. package/dist/scripts/template/multi-repo-renderer.js.map +1 -1
  20. package/dist/scripts/test-workflow-stages.js +2 -2
  21. package/dist/scripts/test-workflow-stages.js.map +1 -1
  22. package/dist/scripts/utils/config-loader.d.ts.map +1 -1
  23. package/dist/scripts/utils/config-loader.js +3 -2
  24. package/dist/scripts/utils/config-loader.js.map +1 -1
  25. package/dist/scripts/utils/env-loader.d.ts +11 -0
  26. package/dist/scripts/utils/env-loader.d.ts.map +1 -0
  27. package/dist/scripts/utils/env-loader.js +23 -0
  28. package/dist/scripts/utils/env-loader.js.map +1 -0
  29. package/dist/scripts/workflow-orchestrator.js +2 -2
  30. package/dist/scripts/workflow-orchestrator.js.map +1 -1
  31. package/dist/src/cli.js +3 -3
  32. package/dist/src/cli.js.map +1 -1
  33. package/docs/michi-development/design/config-unification.md +38 -4094
  34. package/docs/michi-development/design/design-config-current-state.md +330 -0
  35. package/docs/michi-development/design/design-config-implementation.md +628 -0
  36. package/docs/michi-development/design/design-config-migration.md +952 -0
  37. package/docs/michi-development/design/design-config-security.md +771 -0
  38. package/docs/michi-development/design/design-config-solution.md +583 -0
  39. package/docs/michi-development/design/design-config-testing.md +892 -0
  40. package/docs/michi-development/testing/manual-verification-flow.md +6 -1377
  41. package/docs/michi-development/testing/manual-verification-other-tools.md +1277 -0
  42. package/docs/michi-development/testing/manual-verification-troubleshooting.md +122 -0
  43. package/docs/user-guide/getting-started/setup.md +14 -32
  44. package/docs/user-guide/guides/multi-repo-guide.md +367 -44
  45. package/docs/user-guide/reference/config.md +1 -1
  46. package/docs/user-guide/reference/security-test-payloads.md +50 -0
  47. package/docs/user-guide/release/ci-setup-java.md +114 -0
  48. package/docs/user-guide/release/ci-setup-nodejs.md +94 -0
  49. package/docs/user-guide/release/ci-setup-php.md +102 -0
  50. package/docs/user-guide/release/ci-setup-troubleshooting.md +94 -0
  51. package/docs/user-guide/release/ci-setup.md +17 -370
  52. package/docs/user-guide/templates/test-specs/e2e-test-spec-template.md +9 -3
  53. package/docs/user-guide/templates/test-specs/security-test-spec-template.md +4 -43
  54. package/package.json +2 -3
  55. package/scripts/confluence-sync.ts +2 -2
  56. package/scripts/jira-sync.ts +2 -2
  57. package/scripts/multi-project-estimate.ts +2 -2
  58. package/scripts/pr-automation.ts +2 -2
  59. package/scripts/pre-flight-check.ts +2 -2
  60. package/scripts/resource-dashboard.ts +2 -2
  61. package/scripts/spec-impl-workflow.ts +2 -2
  62. package/scripts/template/__tests__/multi-repo-renderer.test.ts +15 -10
  63. package/scripts/template/multi-repo-renderer.ts +9 -3
  64. package/scripts/test-workflow-stages.ts +2 -2
  65. package/scripts/utils/__tests__/env-loader.test.ts +145 -0
  66. package/scripts/utils/config-loader.ts +3 -2
  67. package/scripts/utils/env-loader.ts +25 -0
  68. package/scripts/workflow-orchestrator.ts +2 -2
  69. package/docs/design-issue-55.md +0 -240
  70. package/docs/design-issue-56.md +0 -181
  71. package/docs/user-guide/guides/multi-repo-migration-guide.md +0 -516
@@ -13,6 +13,13 @@ import {
13
13
  type MultiRepoTemplateContext,
14
14
  } from '../multi-repo-renderer.js';
15
15
  import * as fs from 'fs';
16
+ import { fileURLToPath } from 'url';
17
+ import { dirname, resolve } from 'path';
18
+
19
+ // Calculate MICHI_PACKAGE_ROOT for tests
20
+ const __filename = fileURLToPath(import.meta.url);
21
+ const __dirname = dirname(__filename);
22
+ const MICHI_PACKAGE_ROOT = resolve(__dirname, '..', '..', '..');
16
23
 
17
24
  vi.mock('fs');
18
25
 
@@ -63,10 +70,11 @@ describe('loadMultiRepoTemplate', () => {
63
70
  const mockContent = '# {{PROJECT_NAME}} - Requirements';
64
71
  vi.spyOn(fs, 'readFileSync').mockReturnValue(mockContent);
65
72
 
66
- const content = loadMultiRepoTemplate('overview/requirements', '/test/root');
73
+ const content = loadMultiRepoTemplate('overview/requirements');
67
74
 
75
+ const expectedPath = resolve(MICHI_PACKAGE_ROOT, 'templates', 'multi-repo', 'overview', 'requirements.md');
68
76
  expect(fs.readFileSync).toHaveBeenCalledWith(
69
- '/test/root/templates/multi-repo/overview/requirements.md',
77
+ expectedPath,
70
78
  'utf-8'
71
79
  );
72
80
  expect(content).toBe(mockContent);
@@ -77,7 +85,7 @@ describe('loadMultiRepoTemplate', () => {
77
85
  throw new Error('ENOENT: no such file or directory');
78
86
  });
79
87
 
80
- expect(() => loadMultiRepoTemplate('invalid/template', '/test/root')).toThrow(
88
+ expect(() => loadMultiRepoTemplate('invalid/template')).toThrow(
81
89
  'Multi-Repo template not found: invalid/template.md'
82
90
  );
83
91
  });
@@ -151,8 +159,7 @@ describe('loadAndRenderMultiRepoTemplate', () => {
151
159
 
152
160
  const rendered = loadAndRenderMultiRepoTemplate(
153
161
  'overview/requirements',
154
- context,
155
- '/test/root'
162
+ context
156
163
  );
157
164
 
158
165
  expect(rendered).toBe('# test-project Requirements\n\n**JIRA**: TEST');
@@ -184,8 +191,7 @@ describe('renderMultiRepoTemplates', () => {
184
191
 
185
192
  const rendered = renderMultiRepoTemplates(
186
193
  ['overview/requirements', 'overview/architecture'],
187
- context,
188
- '/test/root'
194
+ context
189
195
  );
190
196
 
191
197
  expect(rendered['overview/requirements']).toBe('# test-project Requirements');
@@ -200,7 +206,7 @@ describe('renderMultiRepoTemplates', () => {
200
206
  CREATED_AT: '2025-12-14T10:00:00Z',
201
207
  };
202
208
 
203
- const rendered = renderMultiRepoTemplates([], context, '/test/root');
209
+ const rendered = renderMultiRepoTemplates([], context);
204
210
 
205
211
  expect(rendered).toEqual({});
206
212
  });
@@ -248,8 +254,7 @@ describe('統合テスト', () => {
248
254
 
249
255
  const rendered = loadAndRenderMultiRepoTemplate(
250
256
  'overview/requirements',
251
- context,
252
- '/test/root'
257
+ context
253
258
  );
254
259
 
255
260
  expect(rendered).toContain('# my-awesome-project - 要件定義書');
@@ -5,9 +5,15 @@
5
5
  */
6
6
 
7
7
  import { readFileSync } from 'fs';
8
- import { resolve, relative, isAbsolute } from 'path';
8
+ import { resolve, relative, isAbsolute, dirname } from 'path';
9
+ import { fileURLToPath } from 'url';
9
10
  import { renderTemplate, type TemplateContext } from './renderer.js';
10
11
 
12
+ // Resolve Michi package root directory
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = dirname(__filename);
15
+ const MICHI_PACKAGE_ROOT = resolve(__dirname, '..', '..');
16
+
11
17
  export interface MultiRepoTemplateContext {
12
18
  PROJECT_NAME: string;
13
19
  JIRA_KEY: string;
@@ -51,7 +57,7 @@ export const createMultiRepoTemplateContext = (
51
57
  */
52
58
  export const loadMultiRepoTemplate = (
53
59
  templateName: string,
54
- projectRoot: string = process.cwd()
60
+ _projectRoot: string = process.cwd()
55
61
  ): string => {
56
62
  // Security Layer 1: Validate template name
57
63
  // Reject path traversal characters (../, ..\, absolute paths)
@@ -63,7 +69,7 @@ export const loadMultiRepoTemplate = (
63
69
  }
64
70
 
65
71
  // Security Layer 2: Resolve absolute paths
66
- const templateDir = resolve(projectRoot, 'templates', 'multi-repo');
72
+ const templateDir = resolve(MICHI_PACKAGE_ROOT, 'templates', 'multi-repo');
67
73
  const templatePath = resolve(templateDir, `${templateName}.md`);
68
74
 
69
75
  // Security Layer 3: Verify path containment
@@ -3,10 +3,10 @@
3
3
  * testとreleaseステージのみを実行
4
4
  */
5
5
 
6
- import { config } from 'dotenv';
6
+ import { loadEnv } from './utils/env-loader.js';
7
7
  import { WorkflowOrchestrator, WorkflowConfig } from './workflow-orchestrator.js';
8
8
 
9
- config();
9
+ loadEnv();
10
10
 
11
11
  async function main() {
12
12
  const args = process.argv.slice(2);
@@ -0,0 +1,145 @@
1
+ /**
2
+ * env-loader.ts のユニットテスト
3
+ */
4
+
5
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
6
+ import { writeFileSync, existsSync, mkdirSync, rmSync } from 'fs';
7
+ import { join } from 'path';
8
+ import { config } from 'dotenv';
9
+
10
+ describe('env-loader', () => {
11
+ const testDir = join(process.cwd(), 'test-temp-env-loader');
12
+ const testGlobalDir = join(testDir, '.michi');
13
+ const testGlobalEnvPath = join(testGlobalDir, '.env');
14
+ const testLocalEnvPath = join(testDir, '.env');
15
+
16
+ // 元の環境変数を保存
17
+ const originalEnv = { ...process.env };
18
+ const originalHome = process.env.HOME;
19
+ const originalCwd = process.cwd();
20
+
21
+ beforeEach(() => {
22
+ // テスト用ディレクトリ作成
23
+ if (!existsSync(testDir)) {
24
+ mkdirSync(testDir, { recursive: true });
25
+ }
26
+ if (!existsSync(testGlobalDir)) {
27
+ mkdirSync(testGlobalDir, { recursive: true });
28
+ }
29
+
30
+ // カレントディレクトリをテストディレクトリに変更
31
+ process.chdir(testDir);
32
+
33
+ // 環境変数をクリア
34
+ for (const key in process.env) {
35
+ if (key.startsWith('TEST_')) {
36
+ delete process.env[key];
37
+ }
38
+ }
39
+ });
40
+
41
+ afterEach(() => {
42
+ // カレントディレクトリを戻す
43
+ process.chdir(originalCwd);
44
+
45
+ // クリーンアップ
46
+ if (existsSync(testDir)) {
47
+ rmSync(testDir, { recursive: true, force: true });
48
+ }
49
+
50
+ // 環境変数を復元
51
+ process.env = { ...originalEnv };
52
+ if (originalHome) {
53
+ process.env.HOME = originalHome;
54
+ }
55
+ });
56
+
57
+ it('should load global .env if exists', () => {
58
+ // グローバル .env を作成
59
+ const globalContent = `TEST_GLOBAL_VAR=global_value
60
+ TEST_SHARED_VAR=global_shared`;
61
+ writeFileSync(testGlobalEnvPath, globalContent, 'utf-8');
62
+
63
+ // HOMEを一時的に変更
64
+ process.env.HOME = testDir;
65
+
66
+ // dotenvで読み込みをシミュレート(env-loader.tsと同じロジック)
67
+ if (existsSync(testGlobalEnvPath)) {
68
+ config({ path: testGlobalEnvPath });
69
+ }
70
+
71
+ expect(process.env.TEST_GLOBAL_VAR).toBe('global_value');
72
+ expect(process.env.TEST_SHARED_VAR).toBe('global_shared');
73
+ });
74
+
75
+ it('should load local .env if exists', () => {
76
+ // ローカル .env を作成
77
+ const localContent = `TEST_LOCAL_VAR=local_value
78
+ TEST_SHARED_VAR=local_shared`;
79
+ writeFileSync(testLocalEnvPath, localContent, 'utf-8');
80
+
81
+ // dotenvでローカル.envを読み込み
82
+ config();
83
+
84
+ expect(process.env.TEST_LOCAL_VAR).toBe('local_value');
85
+ expect(process.env.TEST_SHARED_VAR).toBe('local_shared');
86
+ });
87
+
88
+ it('should override global with local', () => {
89
+ // グローバル .env を作成
90
+ const globalContent = `TEST_GLOBAL_VAR=global_value
91
+ TEST_SHARED_VAR=global_shared`;
92
+ writeFileSync(testGlobalEnvPath, globalContent, 'utf-8');
93
+
94
+ // ローカル .env を作成
95
+ const localContent = `TEST_LOCAL_VAR=local_value
96
+ TEST_SHARED_VAR=local_shared`;
97
+ writeFileSync(testLocalEnvPath, localContent, 'utf-8');
98
+
99
+ // HOMEを一時的に変更
100
+ process.env.HOME = testDir;
101
+
102
+ // env-loader.tsと同じロジックで読み込み
103
+ if (existsSync(testGlobalEnvPath)) {
104
+ config({ path: testGlobalEnvPath });
105
+ }
106
+ config({ override: true }); // ローカル .env(グローバルを上書き)
107
+
108
+ // ローカルがグローバルを上書きする
109
+ expect(process.env.TEST_GLOBAL_VAR).toBe('global_value');
110
+ expect(process.env.TEST_LOCAL_VAR).toBe('local_value');
111
+ expect(process.env.TEST_SHARED_VAR).toBe('local_shared'); // ローカルで上書き
112
+ });
113
+
114
+ it('should handle missing files gracefully', () => {
115
+ // 両方のファイルを作成しない
116
+ process.env.HOME = join(testDir, 'nonexistent');
117
+
118
+ // エラーを投げないことを確認
119
+ expect(() => {
120
+ if (existsSync(join(process.env.HOME!, '.michi', '.env'))) {
121
+ config({ path: join(process.env.HOME!, '.michi', '.env') });
122
+ }
123
+ config();
124
+ }).not.toThrow();
125
+ });
126
+
127
+ it('should not fail if global directory does not exist', () => {
128
+ // ローカル .env のみ作成
129
+ const localContent = `TEST_LOCAL_VAR=local_value`;
130
+ writeFileSync(testLocalEnvPath, localContent, 'utf-8');
131
+
132
+ // .michiディレクトリが存在しないHOMEを設定
133
+ process.env.HOME = join(testDir, 'no-michi-dir');
134
+
135
+ expect(() => {
136
+ const globalPath = join(process.env.HOME!, '.michi', '.env');
137
+ if (existsSync(globalPath)) {
138
+ config({ path: globalPath });
139
+ }
140
+ config();
141
+ }).not.toThrow();
142
+
143
+ expect(process.env.TEST_LOCAL_VAR).toBe('local_value');
144
+ });
145
+ });
@@ -7,7 +7,8 @@ import { readFileSync, writeFileSync, existsSync, statSync, renameSync, unlinkSy
7
7
  import { resolve, relative, isAbsolute, dirname } from 'path';
8
8
  import { fileURLToPath } from 'url';
9
9
  import { homedir } from 'os';
10
- import { config, parse as dotenvParse } from 'dotenv';
10
+ import { parse as dotenvParse } from 'dotenv';
11
+ import { loadEnv } from './env-loader.js';
11
12
  import {
12
13
  AppConfigSchema,
13
14
  MultiRepoProjectSchema,
@@ -18,7 +19,7 @@ import {
18
19
  } from '../config/config-schema.js';
19
20
 
20
21
  // 環境変数読み込み
21
- config();
22
+ loadEnv();
22
23
 
23
24
  /**
24
25
  * グローバル設定ファイルのパス定数
@@ -0,0 +1,25 @@
1
+ /**
2
+ * 環境変数読み込みユーティリティ
3
+ * グローバル設定(~/.michi/.env)とローカル設定(.env)を読み込む
4
+ */
5
+
6
+ import { config } from 'dotenv';
7
+ import { existsSync } from 'fs';
8
+ import { join } from 'path';
9
+ import { homedir } from 'os';
10
+
11
+ /**
12
+ * 環境変数を読み込む
13
+ * グローバル設定(~/.michi/.env)→ローカル設定(.env)の順で読み込み
14
+ * ローカル設定がグローバル設定を上書きする
15
+ */
16
+ export function loadEnv(): void {
17
+ // 1. グローバル設定 ~/.michi/.env を読み込む
18
+ const globalEnvPath = join(homedir(), '.michi', '.env');
19
+ if (existsSync(globalEnvPath)) {
20
+ config({ path: globalEnvPath });
21
+ }
22
+
23
+ // 2. ローカル設定 .env を読み込む(グローバル設定を上書き)
24
+ config({ override: true });
25
+ }
@@ -3,7 +3,7 @@
3
3
  * AI開発フロー全体を統合実行
4
4
  */
5
5
 
6
- import { config } from 'dotenv';
6
+ import { loadEnv } from './utils/env-loader.js';
7
7
  import { loadProjectMeta } from './utils/project-meta.js';
8
8
  import { syncToConfluence, getConfluenceConfig } from './confluence-sync.js';
9
9
  import { syncTasksToJIRA } from './jira-sync.js';
@@ -12,7 +12,7 @@ import { executeTests, generateTestReport } from './utils/test-runner.js';
12
12
  import { createReleaseNotes } from './utils/release-notes-generator.js';
13
13
  import { pollForApproval, waitForManualApproval } from './utils/confluence-approval.js';
14
14
 
15
- config();
15
+ loadEnv();
16
16
 
17
17
  export interface WorkflowConfig {
18
18
  feature: string;
@@ -1,240 +0,0 @@
1
- # Issue #55: バリデーションエラーハンドリング修正 - 詳細設計
2
-
3
- ## 問題の根本原因
4
-
5
- ### 現在の実装(src/commands/setup-existing.ts)
6
-
7
- ```typescript
8
- // buildConfig関数内(Line 167-172)
9
- try {
10
- projectName = validateProjectName(projectName);
11
- } catch (error) {
12
- throw new Error(`プロジェクト名が不正です: ${error instanceof Error ? error.message : error}`);
13
- }
14
-
15
- // buildConfig関数内(Line 180-185)
16
- try {
17
- jiraKey = validateJiraKey(jiraKey);
18
- } catch (error) {
19
- throw new Error(`JIRAキーが不正です: ${error instanceof Error ? error.message : error}`);
20
- }
21
- ```
22
-
23
- ### テストの期待値
24
-
25
- ```typescript
26
- // validation.test.ts(Line 214)
27
- .rejects.toThrow(/プロジェクト名が空です/);
28
-
29
- // validation.test.ts(Line 225)
30
- .rejects.toThrow(/パス区切り文字/);
31
- ```
32
-
33
- ### 問題
34
-
35
- **実際のエラーメッセージ**: `プロジェクト名が不正です: プロジェクト名が空です`
36
- **期待されるメッセージ**: `プロジェクト名が空です`
37
-
38
- → **ラッピングによってマッチしない**
39
-
40
- ---
41
-
42
- ## 修正方針
43
-
44
- ### Option 1: エラーをラッピングせずそのままスロー(推奨)
45
-
46
- **メリット**:
47
- - テストの期待値と一致する
48
- - エラーメッセージがシンプル
49
- - エラーの原因が直接的に伝わる
50
-
51
- **実装**:
52
- ```typescript
53
- // buildConfig関数内(Line 167-172)
54
- try {
55
- projectName = validateProjectName(projectName);
56
- } catch (error) {
57
- // ラッピングせず、そのままスロー
58
- throw error;
59
- }
60
-
61
- // buildConfig関数内(Line 180-185)
62
- try {
63
- jiraKey = validateJiraKey(jiraKey);
64
- } catch (error) {
65
- // ラッピングせず、そのままスロー
66
- throw error;
67
- }
68
- ```
69
-
70
- ### Option 2: テストの期待値を修正(非推奨)
71
-
72
- **デメリット**:
73
- - エラーメッセージが冗長になる
74
- - ラッピングの必要性が不明瞭
75
-
76
- **実装**:
77
- ```typescript
78
- // テストを修正
79
- .rejects.toThrow(/プロジェクト名が不正です.*プロジェクト名が空です/);
80
- ```
81
-
82
- ---
83
-
84
- ## 採用する修正方針
85
-
86
- **Option 1を採用**
87
-
88
- 理由:
89
- 1. エラーメッセージがシンプルで分かりやすい
90
- 2. `validateProjectName`や`validateJiraKey`が既に適切なエラーメッセージを返している
91
- 3. 二重ラッピングの必要性がない
92
- 4. テストの期待値が自然
93
-
94
- ---
95
-
96
- ## 修正対象ファイル
97
-
98
- ### 1. src/commands/setup-existing.ts
99
-
100
- **修正箇所**: `buildConfig`関数内のエラーハンドリング
101
-
102
- ```typescript
103
- // Line 167-172: プロジェクト名バリデーション
104
- try {
105
- projectName = validateProjectName(projectName);
106
- } catch (error) {
107
- throw error; // 修正: ラッピングを削除
108
- }
109
-
110
- // Line 180-185: JIRAキーバリデーション
111
- try {
112
- jiraKey = validateJiraKey(jiraKey);
113
- } catch (error) {
114
- throw error; // 修正: ラッピングを削除
115
- }
116
- ```
117
-
118
- ### 2. src/__tests__/integration/setup/validation.test.ts
119
-
120
- **修正箇所**: スキップされた5つのテストの`.skip`を削除
121
-
122
- ```typescript
123
- // Line 145
124
- it('should reject unsupported language', async () => { ... });
125
-
126
- // Line 207
127
- it('should reject empty project name', async () => { ... });
128
-
129
- // Line 218
130
- it('should reject project name with path traversal characters', async () => { ... });
131
-
132
- // Line 229
133
- it('should reject project name with backslash', async () => { ... });
134
-
135
- // Line 240
136
- it('should reject project name with control characters', async () => { ... });
137
- ```
138
-
139
- ---
140
-
141
- ## 影響範囲
142
-
143
- ### 変更による影響
144
-
145
- 1. **エラーメッセージの変更**:
146
- - 修正前: `プロジェクト名が不正です: <詳細メッセージ>`
147
- - 修正後: `<詳細メッセージ>`(例: `プロジェクト名が空です`)
148
-
149
- 2. **ユーザー体験**:
150
- - より直接的でシンプルなエラーメッセージ
151
- - エラーの原因が明確になる
152
-
153
- 3. **他のテストへの影響**:
154
- - 既存の成功テスト(プロジェクト名とJIRAキーの正常系)には影響なし
155
- - エラーテストのうち、以下は既に成功している(ラッピングされていないため):
156
- - Line 250: `should reject project name that is too long`
157
- - Line 328-366: JIRAキーバリデーションのエラーテスト
158
-
159
- ### 回帰テストの必要性
160
-
161
- 以下のテストが引き続き成功することを確認:
162
- - [ ] Line 250: `should reject project name that is too long`
163
- - [ ] Line 328: `should reject JIRA key with 1 character`
164
- - [ ] Line 338: `should reject JIRA key with 11 characters`
165
- - [ ] Line 348: `should reject JIRA key with numbers`
166
- - [ ] Line 358: `should reject JIRA key with special characters`
167
-
168
- ---
169
-
170
- ## テスト実行計画
171
-
172
- ### Step 1: 修正前のテスト実行(失敗確認)
173
-
174
- ```bash
175
- cd /Users/arigatatsuya/Work/git/michi
176
- npm test -- validation.test.ts
177
- ```
178
-
179
- **期待結果**: 5つのテストがスキップされていることを確認
180
-
181
- ### Step 2: 実装修正
182
-
183
- 1. `src/commands/setup-existing.ts`のエラーハンドリングを修正
184
- 2. まだ`.skip`は残す
185
-
186
- ### Step 3: テスト実行(成功確認)
187
-
188
- ```bash
189
- npm test -- validation.test.ts
190
- ```
191
-
192
- **期待結果**: 修正後も既存の成功テストが全て成功
193
-
194
- ### Step 4: `.skip`削除
195
-
196
- `src/__tests__/integration/setup/validation.test.ts`の5つのテストから`.skip`を削除
197
-
198
- ### Step 5: 最終テスト実行
199
-
200
- ```bash
201
- npm test -- validation.test.ts
202
- ```
203
-
204
- **期待結果**: 全テスト(5つの新規有効化テストを含む)が成功
205
-
206
- ### Step 6: 全テストスイート実行
207
-
208
- ```bash
209
- npm test
210
- ```
211
-
212
- **期待結果**: 全プロジェクトのテストが成功
213
-
214
- ---
215
-
216
- ## チェックリスト
217
-
218
- ### 実装
219
- - [ ] `src/commands/setup-existing.ts` Line 167-172 修正
220
- - [ ] `src/commands/setup-existing.ts` Line 180-185 修正
221
-
222
- ### テスト
223
- - [ ] `validation.test.ts` Line 145 `.skip`削除
224
- - [ ] `validation.test.ts` Line 207 `.skip`削除
225
- - [ ] `validation.test.ts` Line 218 `.skip`削除
226
- - [ ] `validation.test.ts` Line 229 `.skip`削除
227
- - [ ] `validation.test.ts` Line 240 `.skip`削除
228
-
229
- ### 検証
230
- - [ ] 修正前テスト実行(失敗/スキップ確認)
231
- - [ ] 実装修正
232
- - [ ] テスト実行(既存テスト成功確認)
233
- - [ ] `.skip`削除
234
- - [ ] テスト実行(新規テスト成功確認)
235
- - [ ] 全テストスイート実行(全テスト成功確認)
236
-
237
- ---
238
-
239
- 最終更新: 2025-11-17 (月)
240
-