@sk8metal/michi-cli 0.14.1 → 0.20.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/CHANGELOG.md +268 -2
- package/README.md +27 -2
- package/dist/scripts/config/config-schema.d.ts +5 -333
- package/dist/scripts/config/config-schema.d.ts.map +1 -1
- package/dist/scripts/config/config-schema.js +6 -233
- package/dist/scripts/config/config-schema.js.map +1 -1
- package/dist/scripts/config-global.d.ts.map +1 -1
- package/dist/scripts/config-global.js +3 -2
- package/dist/scripts/config-global.js.map +1 -1
- package/dist/scripts/confluence-sync.d.ts +5 -73
- package/dist/scripts/confluence-sync.d.ts.map +1 -1
- package/dist/scripts/confluence-sync.js +14 -392
- package/dist/scripts/confluence-sync.js.map +1 -1
- package/dist/scripts/constants/environments.d.ts +3 -30
- package/dist/scripts/constants/environments.d.ts.map +1 -1
- package/dist/scripts/constants/environments.js +3 -41
- package/dist/scripts/constants/environments.js.map +1 -1
- package/dist/scripts/constants/languages.d.ts +3 -20
- package/dist/scripts/constants/languages.d.ts.map +1 -1
- package/dist/scripts/constants/languages.js +3 -50
- package/dist/scripts/constants/languages.js.map +1 -1
- package/dist/scripts/constants/test-commands.d.ts +3 -33
- package/dist/scripts/constants/test-commands.d.ts.map +1 -1
- package/dist/scripts/constants/test-commands.js +3 -67
- package/dist/scripts/constants/test-commands.js.map +1 -1
- package/dist/scripts/dev-tools/mermaid-converter.d.ts.map +1 -0
- package/dist/scripts/dev-tools/mermaid-converter.js.map +1 -0
- package/dist/scripts/dev-tools/test-interactive.d.ts.map +1 -0
- package/dist/scripts/{test-interactive.js → dev-tools/test-interactive.js} +4 -3
- package/dist/scripts/dev-tools/test-interactive.js.map +1 -0
- package/dist/scripts/github-actions-client.d.ts +5 -75
- package/dist/scripts/github-actions-client.d.ts.map +1 -1
- package/dist/scripts/github-actions-client.js +4 -178
- package/dist/scripts/github-actions-client.js.map +1 -1
- package/dist/scripts/jira-sync.d.ts +3 -121
- package/dist/scripts/jira-sync.d.ts.map +1 -1
- package/dist/scripts/jira-sync.js +5 -879
- package/dist/scripts/jira-sync.js.map +1 -1
- package/dist/scripts/markdown-to-confluence.d.ts.map +1 -1
- package/dist/scripts/markdown-to-confluence.js +2 -2
- package/dist/scripts/markdown-to-confluence.js.map +1 -1
- package/dist/scripts/multi-project-estimate.d.ts.map +1 -1
- package/dist/scripts/multi-project-estimate.js +3 -2
- package/dist/scripts/multi-project-estimate.js.map +1 -1
- package/dist/scripts/phase-runner.d.ts.map +1 -1
- package/dist/scripts/phase-runner.js +34 -18
- package/dist/scripts/phase-runner.js.map +1 -1
- package/dist/scripts/pre-flight-check.d.ts.map +1 -1
- package/dist/scripts/pre-flight-check.js +27 -11
- package/dist/scripts/pre-flight-check.js.map +1 -1
- package/dist/scripts/template/multi-repo-renderer.js +2 -2
- package/dist/scripts/template/multi-repo-renderer.js.map +1 -1
- package/dist/scripts/test-execution-generator.d.ts.map +1 -1
- package/dist/scripts/test-execution-generator.js +5 -4
- package/dist/scripts/test-execution-generator.js.map +1 -1
- package/dist/scripts/utils/aidlc-parser.d.ts +5 -82
- package/dist/scripts/utils/aidlc-parser.d.ts.map +1 -1
- package/dist/scripts/utils/aidlc-parser.js +4 -204
- package/dist/scripts/utils/aidlc-parser.js.map +1 -1
- package/dist/scripts/utils/ci-generator.d.ts.map +1 -1
- package/dist/scripts/utils/ci-generator.js +4 -3
- package/dist/scripts/utils/ci-generator.js.map +1 -1
- package/dist/scripts/utils/config-loader.d.ts.map +1 -1
- package/dist/scripts/utils/config-loader.js +46 -49
- package/dist/scripts/utils/config-loader.js.map +1 -1
- package/dist/scripts/utils/config-validator.d.ts +9 -10
- package/dist/scripts/utils/config-validator.d.ts.map +1 -1
- package/dist/scripts/utils/config-validator.js +68 -70
- package/dist/scripts/utils/config-validator.js.map +1 -1
- package/dist/scripts/utils/docker-requirement-detector.d.ts.map +1 -1
- package/dist/scripts/utils/docker-requirement-detector.js +5 -4
- package/dist/scripts/utils/docker-requirement-detector.js.map +1 -1
- package/dist/scripts/utils/env-config.d.ts.map +1 -1
- package/dist/scripts/utils/env-config.js +55 -38
- package/dist/scripts/utils/env-config.js.map +1 -1
- package/dist/scripts/utils/feature-name-validator.d.ts +4 -9
- package/dist/scripts/utils/feature-name-validator.d.ts.map +1 -1
- package/dist/scripts/utils/feature-name-validator.js +12 -21
- package/dist/scripts/utils/feature-name-validator.js.map +1 -1
- package/dist/scripts/utils/interactive-helpers.d.ts +5 -29
- package/dist/scripts/utils/interactive-helpers.d.ts.map +1 -1
- package/dist/scripts/utils/interactive-helpers.js +5 -89
- package/dist/scripts/utils/interactive-helpers.js.map +1 -1
- package/dist/scripts/utils/language-detector.d.ts.map +1 -1
- package/dist/scripts/utils/language-detector.js +4 -3
- package/dist/scripts/utils/language-detector.js.map +1 -1
- package/dist/scripts/utils/markdown-parser.d.ts +6 -52
- package/dist/scripts/utils/markdown-parser.d.ts.map +1 -1
- package/dist/scripts/utils/markdown-parser.js +5 -286
- package/dist/scripts/utils/markdown-parser.js.map +1 -1
- package/dist/scripts/utils/multi-repo-validator.d.ts +9 -10
- package/dist/scripts/utils/multi-repo-validator.d.ts.map +1 -1
- package/dist/scripts/utils/multi-repo-validator.js +15 -17
- package/dist/scripts/utils/multi-repo-validator.js.map +1 -1
- package/dist/scripts/utils/project-analyzer.d.ts +120 -0
- package/dist/scripts/utils/project-analyzer.d.ts.map +1 -0
- package/dist/scripts/utils/project-analyzer.js +358 -0
- package/dist/scripts/utils/project-analyzer.js.map +1 -0
- package/dist/scripts/utils/project-detector.d.ts.map +1 -1
- package/dist/scripts/utils/project-detector.js +6 -5
- package/dist/scripts/utils/project-detector.js.map +1 -1
- package/dist/scripts/utils/project-finder.d.ts +1 -21
- package/dist/scripts/utils/project-finder.d.ts.map +1 -1
- package/dist/scripts/utils/project-finder.js +2 -121
- package/dist/scripts/utils/project-finder.js.map +1 -1
- package/dist/scripts/utils/project-meta.d.ts +4 -27
- package/dist/scripts/utils/project-meta.d.ts.map +1 -1
- package/dist/scripts/utils/project-meta.js +3 -67
- package/dist/scripts/utils/project-meta.js.map +1 -1
- package/dist/scripts/utils/safe-file-reader.d.ts +84 -0
- package/dist/scripts/utils/safe-file-reader.d.ts.map +1 -0
- package/dist/scripts/utils/safe-file-reader.js +122 -0
- package/dist/scripts/utils/safe-file-reader.js.map +1 -0
- package/dist/scripts/utils/security-validator.d.ts +8 -19
- package/dist/scripts/utils/security-validator.d.ts.map +1 -1
- package/dist/scripts/utils/security-validator.js +28 -58
- package/dist/scripts/utils/security-validator.js.map +1 -1
- package/dist/scripts/utils/spec-archiver.d.ts.map +1 -1
- package/dist/scripts/utils/spec-archiver.js +7 -6
- package/dist/scripts/utils/spec-archiver.js.map +1 -1
- package/dist/scripts/utils/spec-updater.d.ts.map +1 -1
- package/dist/scripts/utils/spec-updater.js +10 -7
- package/dist/scripts/utils/spec-updater.js.map +1 -1
- package/dist/scripts/utils/tasks-converter.js +2 -2
- package/dist/scripts/utils/tasks-converter.js.map +1 -1
- package/dist/scripts/utils/tasks-format-validator.js +4 -4
- package/dist/scripts/utils/tasks-format-validator.js.map +1 -1
- package/dist/scripts/utils/template-applier.d.ts.map +1 -1
- package/dist/scripts/utils/template-applier.js +4 -3
- package/dist/scripts/utils/template-applier.js.map +1 -1
- package/dist/scripts/utils/types/validation.d.ts +57 -0
- package/dist/scripts/utils/types/validation.d.ts.map +1 -0
- package/dist/scripts/utils/types/validation.js +50 -0
- package/dist/scripts/utils/types/validation.js.map +1 -0
- package/dist/scripts/validate-phase.d.ts +6 -1
- package/dist/scripts/validate-phase.d.ts.map +1 -1
- package/dist/scripts/validate-phase.js +42 -20
- package/dist/scripts/validate-phase.js.map +1 -1
- package/dist/scripts/workflow-orchestrator.d.ts +4 -40
- package/dist/scripts/workflow-orchestrator.d.ts.map +1 -1
- package/dist/scripts/workflow-orchestrator.js +7 -194
- package/dist/scripts/workflow-orchestrator.js.map +1 -1
- package/dist/src/application/interfaces/config-provider.d.ts +89 -0
- package/dist/src/application/interfaces/config-provider.d.ts.map +1 -0
- package/dist/src/application/interfaces/config-provider.js +8 -0
- package/dist/src/application/interfaces/config-provider.js.map +1 -0
- package/dist/src/application/interfaces/external-api.d.ts +80 -0
- package/dist/src/application/interfaces/external-api.d.ts.map +1 -0
- package/dist/src/application/interfaces/external-api.js +8 -0
- package/dist/src/application/interfaces/external-api.js.map +1 -0
- package/dist/src/application/interfaces/spec-repository.d.ts +52 -0
- package/dist/src/application/interfaces/spec-repository.d.ts.map +1 -0
- package/dist/src/application/interfaces/spec-repository.js +8 -0
- package/dist/src/application/interfaces/spec-repository.js.map +1 -0
- package/dist/src/application/services/spec-service.d.ts +49 -0
- package/dist/src/application/services/spec-service.d.ts.map +1 -0
- package/dist/src/application/services/spec-service.js +94 -0
- package/dist/src/application/services/spec-service.js.map +1 -0
- package/dist/src/application/services/workflow-service.d.ts +58 -0
- package/dist/src/application/services/workflow-service.d.ts.map +1 -0
- package/dist/src/application/services/workflow-service.js +125 -0
- package/dist/src/application/services/workflow-service.js.map +1 -0
- package/dist/src/application/templates/processor.d.ts +31 -0
- package/dist/src/application/templates/processor.d.ts.map +1 -0
- package/dist/src/application/templates/processor.js +58 -0
- package/dist/src/application/templates/processor.js.map +1 -0
- package/dist/src/application/use-cases/spec/archive-spec.d.ts +34 -0
- package/dist/src/application/use-cases/spec/archive-spec.d.ts.map +1 -0
- package/dist/src/application/use-cases/spec/archive-spec.js +56 -0
- package/dist/src/application/use-cases/spec/archive-spec.js.map +1 -0
- package/dist/src/application/use-cases/spec/generate-design.d.ts +34 -0
- package/dist/src/application/use-cases/spec/generate-design.d.ts.map +1 -0
- package/dist/src/application/use-cases/spec/generate-design.js +58 -0
- package/dist/src/application/use-cases/spec/generate-design.js.map +1 -0
- package/dist/src/application/use-cases/spec/generate-requirements.d.ts +34 -0
- package/dist/src/application/use-cases/spec/generate-requirements.d.ts.map +1 -0
- package/dist/src/application/use-cases/spec/generate-requirements.js +58 -0
- package/dist/src/application/use-cases/spec/generate-requirements.js.map +1 -0
- package/dist/src/application/use-cases/spec/generate-tasks.d.ts +34 -0
- package/dist/src/application/use-cases/spec/generate-tasks.d.ts.map +1 -0
- package/dist/src/application/use-cases/spec/generate-tasks.js +58 -0
- package/dist/src/application/use-cases/spec/generate-tasks.js.map +1 -0
- package/dist/src/application/use-cases/spec/init-spec.d.ts +48 -0
- package/dist/src/application/use-cases/spec/init-spec.d.ts.map +1 -0
- package/dist/src/application/use-cases/spec/init-spec.js +121 -0
- package/dist/src/application/use-cases/spec/init-spec.js.map +1 -0
- package/dist/src/cli.d.ts +6 -7
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +6 -745
- package/dist/src/cli.js.map +1 -1
- package/dist/src/commands/config-validate.js +2 -2
- package/dist/src/commands/init.d.ts +6 -21
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +5 -508
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/migrate.js +4 -3
- package/dist/src/commands/migrate.js.map +1 -1
- package/dist/src/commands/spec-archive.d.ts +6 -13
- package/dist/src/commands/spec-archive.d.ts.map +1 -1
- package/dist/src/commands/spec-archive.js +5 -36
- package/dist/src/commands/spec-archive.js.map +1 -1
- package/dist/src/commands/spec-list.d.ts +6 -11
- package/dist/src/commands/spec-list.d.ts.map +1 -1
- package/dist/src/commands/spec-list.js +5 -51
- package/dist/src/commands/spec-list.js.map +1 -1
- package/dist/src/domain/constants/approval.d.ts +18 -0
- package/dist/src/domain/constants/approval.d.ts.map +1 -0
- package/dist/src/domain/constants/approval.js +23 -0
- package/dist/src/domain/constants/approval.js.map +1 -0
- package/dist/src/domain/constants/environments.d.ts +33 -0
- package/dist/src/domain/constants/environments.d.ts.map +1 -0
- package/dist/src/domain/constants/environments.js +44 -0
- package/dist/src/domain/constants/environments.js.map +1 -0
- package/dist/src/domain/constants/index.d.ts +12 -0
- package/dist/src/domain/constants/index.d.ts.map +1 -0
- package/dist/src/domain/constants/index.js +18 -0
- package/dist/src/domain/constants/index.js.map +1 -0
- package/dist/src/domain/constants/languages.d.ts +23 -0
- package/dist/src/domain/constants/languages.d.ts.map +1 -0
- package/dist/src/domain/constants/languages.js +53 -0
- package/dist/src/domain/constants/languages.js.map +1 -0
- package/dist/src/domain/constants/phases.d.ts +32 -0
- package/dist/src/domain/constants/phases.d.ts.map +1 -0
- package/dist/src/domain/constants/phases.js +52 -0
- package/dist/src/domain/constants/phases.js.map +1 -0
- package/dist/src/domain/constants/test-commands.d.ts +36 -0
- package/dist/src/domain/constants/test-commands.d.ts.map +1 -0
- package/dist/src/domain/constants/test-commands.js +70 -0
- package/dist/src/domain/constants/test-commands.js.map +1 -0
- package/dist/src/domain/constants/validation-rules.d.ts +32 -0
- package/dist/src/domain/constants/validation-rules.d.ts.map +1 -0
- package/dist/src/domain/constants/validation-rules.js +51 -0
- package/dist/src/domain/constants/validation-rules.js.map +1 -0
- package/dist/src/domain/entities/spec.d.ts +66 -0
- package/dist/src/domain/entities/spec.d.ts.map +1 -0
- package/dist/src/domain/entities/spec.js +112 -0
- package/dist/src/domain/entities/spec.js.map +1 -0
- package/dist/src/domain/entities/task.d.ts +43 -0
- package/dist/src/domain/entities/task.d.ts.map +1 -0
- package/dist/src/domain/entities/task.js +65 -0
- package/dist/src/domain/entities/task.js.map +1 -0
- package/dist/src/domain/services/spec-validator.d.ts +46 -0
- package/dist/src/domain/services/spec-validator.d.ts.map +1 -0
- package/dist/src/domain/services/spec-validator.js +99 -0
- package/dist/src/domain/services/spec-validator.js.map +1 -0
- package/dist/src/domain/value-objects/feature-name.d.ts +24 -0
- package/dist/src/domain/value-objects/feature-name.d.ts.map +1 -0
- package/dist/src/domain/value-objects/feature-name.js +36 -0
- package/dist/src/domain/value-objects/feature-name.js.map +1 -0
- package/dist/src/domain/value-objects/index.d.ts +7 -0
- package/dist/src/domain/value-objects/index.d.ts.map +1 -0
- package/dist/src/domain/value-objects/index.js +7 -0
- package/dist/src/domain/value-objects/index.js.map +1 -0
- package/dist/src/infrastructure/config/index.d.ts +5 -0
- package/dist/src/infrastructure/config/index.d.ts.map +1 -0
- package/dist/src/infrastructure/config/index.js +6 -0
- package/dist/src/infrastructure/config/index.js.map +1 -0
- package/dist/src/infrastructure/config/schema.d.ts +337 -0
- package/dist/src/infrastructure/config/schema.d.ts.map +1 -0
- package/dist/src/infrastructure/config/schema.js +237 -0
- package/dist/src/infrastructure/config/schema.js.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/approval.d.ts +14 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/approval.d.ts.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/approval.js +102 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/approval.js.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/client.d.ts +23 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/client.d.ts.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/client.js +192 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/client.js.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/hierarchy.d.ts +48 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/hierarchy.d.ts.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/hierarchy.js +531 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/hierarchy.js.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/index.d.ts +10 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/index.d.ts.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/index.js +12 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/index.js.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/sync-service.d.ts +13 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/sync-service.d.ts.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/sync-service.js +129 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/sync-service.js.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/types.d.ts +113 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/types.d.ts.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/types.js +5 -0
- package/dist/src/infrastructure/external-apis/atlassian/confluence/types.js.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/adf-converter.d.ts +15 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/adf-converter.d.ts.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/adf-converter.js +141 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/adf-converter.js.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/client.d.ts +50 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/client.d.ts.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/client.js +226 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/client.js.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/index.d.ts +12 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/index.d.ts.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/index.js +16 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/index.js.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/issue-builder.d.ts +49 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/issue-builder.d.ts.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/issue-builder.js +165 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/issue-builder.js.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/status-mapper.d.ts +14 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/status-mapper.d.ts.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/status-mapper.js +110 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/status-mapper.js.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/sync-service.d.ts +32 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/sync-service.d.ts.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/sync-service.js +284 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/sync-service.js.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/types.d.ts +114 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/types.d.ts.map +1 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/types.js +7 -0
- package/dist/src/infrastructure/external-apis/atlassian/jira/types.js.map +1 -0
- package/dist/src/infrastructure/external-apis/github/client.d.ts +25 -0
- package/dist/src/infrastructure/external-apis/github/client.d.ts.map +1 -0
- package/dist/src/infrastructure/external-apis/github/client.js +109 -0
- package/dist/src/infrastructure/external-apis/github/client.js.map +1 -0
- package/dist/src/infrastructure/external-apis/github/index.d.ts +7 -0
- package/dist/src/infrastructure/external-apis/github/index.d.ts.map +1 -0
- package/dist/src/infrastructure/external-apis/github/index.js +8 -0
- package/dist/src/infrastructure/external-apis/github/index.js.map +1 -0
- package/dist/src/infrastructure/external-apis/github/types.d.ts +69 -0
- package/dist/src/infrastructure/external-apis/github/types.d.ts.map +1 -0
- package/dist/src/infrastructure/external-apis/github/types.js +5 -0
- package/dist/src/infrastructure/external-apis/github/types.js.map +1 -0
- package/dist/src/infrastructure/external-apis/github/utils.d.ts +18 -0
- package/dist/src/infrastructure/external-apis/github/utils.d.ts.map +1 -0
- package/dist/src/infrastructure/external-apis/github/utils.js +84 -0
- package/dist/src/infrastructure/external-apis/github/utils.js.map +1 -0
- package/dist/src/infrastructure/filesystem/index.d.ts +6 -0
- package/dist/src/infrastructure/filesystem/index.d.ts.map +1 -0
- package/dist/src/infrastructure/filesystem/index.js +5 -0
- package/dist/src/infrastructure/filesystem/index.js.map +1 -0
- package/dist/src/infrastructure/filesystem/project-meta.d.ts +32 -0
- package/dist/src/infrastructure/filesystem/project-meta.d.ts.map +1 -0
- package/dist/src/infrastructure/filesystem/project-meta.js +75 -0
- package/dist/src/infrastructure/filesystem/project-meta.js.map +1 -0
- package/dist/src/infrastructure/parsers/aidlc-parser.d.ts +86 -0
- package/dist/src/infrastructure/parsers/aidlc-parser.d.ts.map +1 -0
- package/dist/src/infrastructure/parsers/aidlc-parser.js +208 -0
- package/dist/src/infrastructure/parsers/aidlc-parser.js.map +1 -0
- package/dist/src/infrastructure/parsers/index.d.ts +8 -0
- package/dist/src/infrastructure/parsers/index.d.ts.map +1 -0
- package/dist/src/infrastructure/parsers/index.js +6 -0
- package/dist/src/infrastructure/parsers/index.js.map +1 -0
- package/dist/src/infrastructure/parsers/markdown-parser.d.ts +51 -0
- package/dist/src/infrastructure/parsers/markdown-parser.d.ts.map +1 -0
- package/dist/src/infrastructure/parsers/markdown-parser.js +253 -0
- package/dist/src/infrastructure/parsers/markdown-parser.js.map +1 -0
- package/dist/src/presentation/cli/config.d.ts +12 -0
- package/dist/src/presentation/cli/config.d.ts.map +1 -0
- package/dist/src/presentation/cli/config.js +22 -0
- package/dist/src/presentation/cli/config.js.map +1 -0
- package/dist/src/presentation/cli/version.d.ts +10 -0
- package/dist/src/presentation/cli/version.d.ts.map +1 -0
- package/dist/src/presentation/cli/version.js +41 -0
- package/dist/src/presentation/cli/version.js.map +1 -0
- package/dist/src/presentation/cli.d.ts +22 -0
- package/dist/src/presentation/cli.d.ts.map +1 -0
- package/dist/src/presentation/cli.js +85 -0
- package/dist/src/presentation/cli.js.map +1 -0
- package/dist/src/presentation/commands/config/register.d.ts +11 -0
- package/dist/src/presentation/commands/config/register.d.ts.map +1 -0
- package/dist/src/presentation/commands/config/register.js +98 -0
- package/dist/src/presentation/commands/config/register.js.map +1 -0
- package/dist/src/presentation/commands/confluence/register.d.ts +11 -0
- package/dist/src/presentation/commands/confluence/register.d.ts.map +1 -0
- package/dist/src/presentation/commands/confluence/register.js +32 -0
- package/dist/src/presentation/commands/confluence/register.js.map +1 -0
- package/dist/src/presentation/commands/confluence/sync.d.ts +17 -0
- package/dist/src/presentation/commands/confluence/sync.d.ts.map +1 -0
- package/dist/src/presentation/commands/confluence/sync.js +25 -0
- package/dist/src/presentation/commands/confluence/sync.js.map +1 -0
- package/dist/src/presentation/commands/init/handler.d.ts +10 -0
- package/dist/src/presentation/commands/init/handler.d.ts.map +1 -0
- package/dist/src/presentation/commands/init/handler.js +64 -0
- package/dist/src/presentation/commands/init/handler.js.map +1 -0
- package/dist/src/presentation/commands/init/prompts.d.ts +41 -0
- package/dist/src/presentation/commands/init/prompts.d.ts.map +1 -0
- package/dist/src/presentation/commands/init/prompts.js +119 -0
- package/dist/src/presentation/commands/init/prompts.js.map +1 -0
- package/dist/src/presentation/commands/init/register.d.ts +11 -0
- package/dist/src/presentation/commands/init/register.d.ts.map +1 -0
- package/dist/src/presentation/commands/init/register.js +141 -0
- package/dist/src/presentation/commands/init/register.js.map +1 -0
- package/dist/src/presentation/commands/init/setup.d.ts +26 -0
- package/dist/src/presentation/commands/init/setup.d.ts.map +1 -0
- package/dist/src/presentation/commands/init/setup.js +196 -0
- package/dist/src/presentation/commands/init/setup.js.map +1 -0
- package/dist/src/presentation/commands/init/templates.d.ts +19 -0
- package/dist/src/presentation/commands/init/templates.d.ts.map +1 -0
- package/dist/src/presentation/commands/init/templates.js +140 -0
- package/dist/src/presentation/commands/init/templates.js.map +1 -0
- package/dist/src/presentation/commands/init/validation.d.ts +21 -0
- package/dist/src/presentation/commands/init/validation.d.ts.map +1 -0
- package/dist/src/presentation/commands/init/validation.js +65 -0
- package/dist/src/presentation/commands/init/validation.js.map +1 -0
- package/dist/src/presentation/commands/jira/register.d.ts +11 -0
- package/dist/src/presentation/commands/jira/register.d.ts.map +1 -0
- package/dist/src/presentation/commands/jira/register.js +75 -0
- package/dist/src/presentation/commands/jira/register.js.map +1 -0
- package/dist/src/presentation/commands/jira/sync.d.ts +29 -0
- package/dist/src/presentation/commands/jira/sync.d.ts.map +1 -0
- package/dist/src/presentation/commands/jira/sync.js +37 -0
- package/dist/src/presentation/commands/jira/sync.js.map +1 -0
- package/dist/src/{commands/multi-repo-add-repo.d.ts → presentation/commands/multi-repo/add-repo.d.ts} +1 -1
- package/dist/src/presentation/commands/multi-repo/add-repo.d.ts.map +1 -0
- package/dist/src/{commands/multi-repo-add-repo.js → presentation/commands/multi-repo/add-repo.js} +4 -4
- package/dist/src/presentation/commands/multi-repo/add-repo.js.map +1 -0
- package/dist/src/{commands/multi-repo-ci-status.d.ts → presentation/commands/multi-repo/ci-status.d.ts} +2 -2
- package/dist/src/presentation/commands/multi-repo/ci-status.d.ts.map +1 -0
- package/dist/src/{commands/multi-repo-ci-status.js → presentation/commands/multi-repo/ci-status.js} +95 -81
- package/dist/src/presentation/commands/multi-repo/ci-status.js.map +1 -0
- package/dist/src/{commands/multi-repo-confluence-sync.d.ts → presentation/commands/multi-repo/confluence-sync.d.ts} +1 -1
- package/dist/src/presentation/commands/multi-repo/confluence-sync.d.ts.map +1 -0
- package/dist/src/{commands/multi-repo-confluence-sync.js → presentation/commands/multi-repo/confluence-sync.js} +7 -6
- package/dist/src/presentation/commands/multi-repo/confluence-sync.js.map +1 -0
- package/dist/src/{commands/multi-repo-init.d.ts → presentation/commands/multi-repo/init.d.ts} +1 -1
- package/dist/src/presentation/commands/multi-repo/init.d.ts.map +1 -0
- package/dist/src/{commands/multi-repo-init.js → presentation/commands/multi-repo/init.js} +6 -6
- package/dist/src/presentation/commands/multi-repo/init.js.map +1 -0
- package/dist/src/{commands/multi-repo-list.d.ts → presentation/commands/multi-repo/list.d.ts} +1 -1
- package/dist/src/presentation/commands/multi-repo/list.d.ts.map +1 -0
- package/dist/src/{commands/multi-repo-list.js → presentation/commands/multi-repo/list.js} +2 -2
- package/dist/src/presentation/commands/multi-repo/list.js.map +1 -0
- package/dist/src/presentation/commands/multi-repo/register.d.ts +12 -0
- package/dist/src/presentation/commands/multi-repo/register.d.ts.map +1 -0
- package/dist/src/presentation/commands/multi-repo/register.js +249 -0
- package/dist/src/presentation/commands/multi-repo/register.js.map +1 -0
- package/dist/src/{commands/multi-repo-test.d.ts → presentation/commands/multi-repo/test.d.ts} +1 -1
- package/dist/src/presentation/commands/multi-repo/test.d.ts.map +1 -0
- package/dist/src/{commands/multi-repo-test.js → presentation/commands/multi-repo/test.js} +4 -4
- package/dist/src/presentation/commands/multi-repo/test.js.map +1 -0
- package/dist/src/presentation/commands/phase/register.d.ts +11 -0
- package/dist/src/presentation/commands/phase/register.d.ts.map +1 -0
- package/dist/src/presentation/commands/phase/register.js +97 -0
- package/dist/src/presentation/commands/phase/register.js.map +1 -0
- package/dist/src/presentation/commands/spec/archive.d.ts +17 -0
- package/dist/src/presentation/commands/spec/archive.d.ts.map +1 -0
- package/dist/src/presentation/commands/spec/archive.js +40 -0
- package/dist/src/presentation/commands/spec/archive.js.map +1 -0
- package/dist/src/presentation/commands/spec/list.d.ts +15 -0
- package/dist/src/presentation/commands/spec/list.d.ts.map +1 -0
- package/dist/src/presentation/commands/spec/list.js +55 -0
- package/dist/src/presentation/commands/spec/list.js.map +1 -0
- package/dist/src/presentation/commands/spec/register.d.ts +11 -0
- package/dist/src/presentation/commands/spec/register.d.ts.map +1 -0
- package/dist/src/presentation/commands/spec/register.js +45 -0
- package/dist/src/presentation/commands/spec/register.js.map +1 -0
- package/dist/src/presentation/commands/workflow/orchestrator.d.ts +50 -0
- package/dist/src/presentation/commands/workflow/orchestrator.d.ts.map +1 -0
- package/dist/src/presentation/commands/workflow/orchestrator.js +174 -0
- package/dist/src/presentation/commands/workflow/orchestrator.js.map +1 -0
- package/dist/src/presentation/commands/workflow/register.d.ts +11 -0
- package/dist/src/presentation/commands/workflow/register.d.ts.map +1 -0
- package/dist/src/presentation/commands/workflow/register.js +58 -0
- package/dist/src/presentation/commands/workflow/register.js.map +1 -0
- package/dist/src/presentation/formatters/error-formatter.d.ts +79 -0
- package/dist/src/presentation/formatters/error-formatter.d.ts.map +1 -0
- package/dist/src/presentation/formatters/error-formatter.js +150 -0
- package/dist/src/presentation/formatters/error-formatter.js.map +1 -0
- package/dist/src/presentation/formatters/index.d.ts +8 -0
- package/dist/src/presentation/formatters/index.d.ts.map +1 -0
- package/dist/src/presentation/formatters/index.js +11 -0
- package/dist/src/presentation/formatters/index.js.map +1 -0
- package/dist/src/presentation/formatters/output-formatter.d.ts +98 -0
- package/dist/src/presentation/formatters/output-formatter.d.ts.map +1 -0
- package/dist/src/presentation/formatters/output-formatter.js +165 -0
- package/dist/src/presentation/formatters/output-formatter.js.map +1 -0
- package/dist/src/presentation/formatters/progress-formatter.d.ts +121 -0
- package/dist/src/presentation/formatters/progress-formatter.d.ts.map +1 -0
- package/dist/src/presentation/formatters/progress-formatter.js +235 -0
- package/dist/src/presentation/formatters/progress-formatter.js.map +1 -0
- package/dist/src/presentation/interactive/config/env-wizard.d.ts +9 -0
- package/dist/src/presentation/interactive/config/env-wizard.d.ts.map +1 -0
- package/dist/src/presentation/interactive/config/env-wizard.js +193 -0
- package/dist/src/presentation/interactive/config/env-wizard.js.map +1 -0
- package/dist/src/presentation/interactive/config/index.d.ts +5 -0
- package/dist/src/presentation/interactive/config/index.d.ts.map +1 -0
- package/dist/src/presentation/interactive/config/index.js +5 -0
- package/dist/src/presentation/interactive/config/index.js.map +1 -0
- package/dist/src/presentation/interactive/confirmation.d.ts +24 -0
- package/dist/src/presentation/interactive/confirmation.d.ts.map +1 -0
- package/dist/src/presentation/interactive/confirmation.js +54 -0
- package/dist/src/presentation/interactive/confirmation.js.map +1 -0
- package/dist/src/presentation/interactive/index.d.ts +8 -0
- package/dist/src/presentation/interactive/index.d.ts.map +1 -0
- package/dist/src/presentation/interactive/index.js +11 -0
- package/dist/src/presentation/interactive/index.js.map +1 -0
- package/dist/src/presentation/interactive/prompts.d.ts +30 -0
- package/dist/src/presentation/interactive/prompts.d.ts.map +1 -0
- package/dist/src/presentation/interactive/prompts.js +69 -0
- package/dist/src/presentation/interactive/prompts.js.map +1 -0
- package/dist/src/presentation/interactive/selection.d.ts +31 -0
- package/dist/src/presentation/interactive/selection.d.ts.map +1 -0
- package/dist/src/presentation/interactive/selection.js +138 -0
- package/dist/src/presentation/interactive/selection.js.map +1 -0
- package/dist/src/shared/types/errors.d.ts +132 -0
- package/dist/src/shared/types/errors.d.ts.map +1 -0
- package/dist/src/shared/types/errors.js +61 -0
- package/dist/src/shared/types/errors.js.map +1 -0
- package/dist/src/shared/types/result.d.ts +53 -0
- package/dist/src/shared/types/result.d.ts.map +1 -0
- package/dist/src/shared/types/result.js +42 -0
- package/dist/src/shared/types/result.js.map +1 -0
- package/dist/test-confluence-auth.d.ts +6 -0
- package/dist/test-confluence-auth.d.ts.map +1 -0
- package/dist/test-confluence-auth.js +128 -0
- package/dist/test-confluence-auth.js.map +1 -0
- package/docs/MIGRATION.md +513 -0
- package/docs/architecture.md +774 -0
- package/docs/guides/comprehensive-verification-guide.md +1926 -0
- package/docs/guides/interactive-config.md +285 -0
- package/docs/onion-architecture-phase0-complete.md +91 -0
- package/package.json +6 -6
- package/scripts/README.md +148 -0
- package/scripts/__tests__/jira-transitions.test.ts +44 -30
- package/scripts/__tests__/mermaid-converter.test.ts +2 -2
- package/scripts/__tests__/multi-repo-validator.test.ts +62 -62
- package/scripts/__tests__/spec-archiver.test.ts +12 -0
- package/scripts/__tests__/validate-phase.test.ts +6 -6
- package/scripts/build/README.md +24 -0
- package/scripts/{copy-static-assets.js → build/copy-static-assets.js} +1 -1
- package/scripts/{set-permissions.js → build/set-permissions.js} +1 -1
- package/scripts/config/config-schema.ts +43 -302
- package/scripts/config-global.ts +3 -2
- package/scripts/confluence-sync.ts +17 -538
- package/scripts/constants/environments.ts +3 -53
- package/scripts/constants/languages.ts +3 -68
- package/scripts/constants/test-commands.ts +3 -94
- package/scripts/dev-tools/README.md +22 -0
- package/scripts/{test-interactive.ts → dev-tools/test-interactive.ts} +4 -3
- package/scripts/github-actions-client.ts +18 -256
- package/scripts/jira-sync.ts +5 -1270
- package/scripts/markdown-to-confluence.ts +5 -5
- package/scripts/multi-project-estimate.ts +3 -2
- package/scripts/phase-runner.ts +41 -19
- package/scripts/pre-flight-check.ts +27 -11
- package/scripts/template/__tests__/multi-repo-renderer.test.ts +12 -0
- package/scripts/template/multi-repo-renderer.ts +2 -2
- package/scripts/test-execution-generator.ts +5 -4
- package/scripts/utils/__tests__/config-validator.test.ts +19 -19
- package/scripts/utils/__tests__/feature-name-validator.test.ts +13 -13
- package/scripts/utils/__tests__/multi-repo-validator.test.ts +34 -34
- package/scripts/utils/__tests__/project-analyzer.test.ts +542 -0
- package/scripts/utils/__tests__/safe-file-reader.test.ts +208 -0
- package/scripts/utils/__tests__/security-validator.test.ts +33 -33
- package/scripts/utils/__tests__/validation-result.test.ts +112 -0
- package/scripts/utils/aidlc-parser.ts +18 -287
- package/scripts/utils/ci-generator.ts +4 -3
- package/scripts/utils/config-loader.ts +54 -50
- package/scripts/utils/config-validator.ts +89 -80
- package/scripts/utils/docker-requirement-detector.ts +5 -4
- package/scripts/utils/env-config.ts +59 -40
- package/scripts/utils/feature-name-validator.ts +25 -40
- package/scripts/utils/interactive-helpers.ts +24 -132
- package/scripts/utils/language-detector.ts +4 -3
- package/scripts/utils/markdown-parser.ts +18 -373
- package/scripts/utils/multi-repo-validator.ts +27 -28
- package/scripts/utils/project-analyzer.ts +429 -0
- package/scripts/utils/project-detector.ts +6 -5
- package/scripts/utils/project-finder.ts +2 -154
- package/scripts/utils/project-meta.ts +8 -91
- package/scripts/utils/safe-file-reader.ts +158 -0
- package/scripts/utils/security-validator.ts +42 -78
- package/scripts/utils/spec-archiver.ts +7 -6
- package/scripts/utils/spec-updater.ts +12 -6
- package/scripts/utils/tasks-converter.ts +2 -2
- package/scripts/utils/tasks-format-validator.ts +4 -4
- package/scripts/utils/template-applier.ts +4 -3
- package/scripts/utils/types/validation.ts +92 -0
- package/scripts/validate-phase.ts +51 -23
- package/scripts/workflow-orchestrator.ts +16 -251
- package/dist/scripts/mermaid-converter.d.ts.map +0 -1
- package/dist/scripts/mermaid-converter.js.map +0 -1
- package/dist/scripts/resource-dashboard.d.ts +0 -7
- package/dist/scripts/resource-dashboard.d.ts.map +0 -1
- package/dist/scripts/resource-dashboard.js +0 -157
- package/dist/scripts/resource-dashboard.js.map +0 -1
- package/dist/scripts/test-interactive.d.ts.map +0 -1
- package/dist/scripts/test-interactive.js.map +0 -1
- package/dist/scripts/test-new-features.d.ts +0 -5
- package/dist/scripts/test-new-features.d.ts.map +0 -1
- package/dist/scripts/test-new-features.js +0 -148
- package/dist/scripts/test-new-features.js.map +0 -1
- package/dist/scripts/test-spec-generator.d.ts +0 -29
- package/dist/scripts/test-spec-generator.d.ts.map +0 -1
- package/dist/scripts/test-spec-generator.js +0 -493
- package/dist/scripts/test-spec-generator.js.map +0 -1
- package/dist/scripts/utils/confluence-approval.d.ts +0 -46
- package/dist/scripts/utils/confluence-approval.d.ts.map +0 -1
- package/dist/scripts/utils/confluence-approval.js +0 -120
- package/dist/scripts/utils/confluence-approval.js.map +0 -1
- package/dist/scripts/utils/template-finder.d.ts +0 -37
- package/dist/scripts/utils/template-finder.d.ts.map +0 -1
- package/dist/scripts/utils/template-finder.js +0 -58
- package/dist/scripts/utils/template-finder.js.map +0 -1
- package/dist/src/commands/multi-repo-add-repo.d.ts.map +0 -1
- package/dist/src/commands/multi-repo-add-repo.js.map +0 -1
- package/dist/src/commands/multi-repo-ci-status.d.ts.map +0 -1
- package/dist/src/commands/multi-repo-ci-status.js.map +0 -1
- package/dist/src/commands/multi-repo-confluence-sync.d.ts.map +0 -1
- package/dist/src/commands/multi-repo-confluence-sync.js.map +0 -1
- package/dist/src/commands/multi-repo-init.d.ts.map +0 -1
- package/dist/src/commands/multi-repo-init.js.map +0 -1
- package/dist/src/commands/multi-repo-list.d.ts.map +0 -1
- package/dist/src/commands/multi-repo-list.js.map +0 -1
- package/dist/src/commands/multi-repo-test.d.ts.map +0 -1
- package/dist/src/commands/multi-repo-test.js.map +0 -1
- package/dist/src/commands/setup-existing.d.ts +0 -22
- package/dist/src/commands/setup-existing.d.ts.map +0 -1
- package/dist/src/commands/setup-existing.js +0 -606
- package/dist/src/commands/setup-existing.js.map +0 -1
- package/scripts/__tests__/setup-existing-project.test.ts +0 -244
- package/scripts/resource-dashboard.ts +0 -189
- package/scripts/test-new-features.ts +0 -171
- package/scripts/test-spec-generator.ts +0 -570
- package/scripts/utils/confluence-approval.ts +0 -169
- package/scripts/utils/template-finder.ts +0 -69
- /package/dist/scripts/{mermaid-converter.d.ts → dev-tools/mermaid-converter.d.ts} +0 -0
- /package/dist/scripts/{mermaid-converter.js → dev-tools/mermaid-converter.js} +0 -0
- /package/dist/scripts/{test-interactive.d.ts → dev-tools/test-interactive.d.ts} +0 -0
- /package/scripts/{mermaid-converter.ts → dev-tools/mermaid-converter.ts} +0 -0
|
@@ -1,885 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* JIRA連携スクリプト
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* 【重要】Epic Link について:
|
|
6
|
-
* JIRA Cloud では Story を Epic に紐付けるには、Epic Link カスタムフィールド
|
|
7
|
-
* (通常 customfield_10014)を使用する必要があります。
|
|
8
|
-
*
|
|
9
|
-
* 現在の実装では parent フィールドを使用していますが、これは Subtask 専用です。
|
|
10
|
-
* Story 作成時に 400 エラーが発生する可能性があります。
|
|
11
|
-
*
|
|
12
|
-
* 対処方法:
|
|
13
|
-
* 1. JIRA 管理画面で Epic Link のカスタムフィールドIDを確認
|
|
14
|
-
* 2. 環境変数 JIRA_EPIC_LINK_FIELD に設定(例: customfield_10014)
|
|
15
|
-
* 3. または、Story 作成後に手動で Epic Link を設定
|
|
16
|
-
*
|
|
17
|
-
* 参考: https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-post
|
|
2
|
+
* JIRA連携スクリプト - Entry Point
|
|
3
|
+
* The actual logic has been moved to src/presentation/commands/jira/
|
|
18
4
|
*/
|
|
19
|
-
import { readFileSync } from 'fs';
|
|
20
|
-
import { resolve } from 'path';
|
|
21
|
-
import axios from 'axios';
|
|
22
5
|
import { loadEnv } from './utils/env-loader.js';
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import { getConfig, getConfigPath } from './utils/config-loader.js';
|
|
26
|
-
import { validateForJiraSyncAsync } from './utils/config-validator.js';
|
|
27
|
-
import { updateSpecJsonAfterJiraSync, } from './utils/spec-updater.js';
|
|
6
|
+
import { jiraSyncCommand } from '../src/presentation/commands/jira/sync.js';
|
|
7
|
+
import { syncTasksToJIRA, JIRAClient } from '../src/infrastructure/external-apis/atlassian/jira/index.js';
|
|
28
8
|
loadEnv();
|
|
29
|
-
/**
|
|
30
|
-
* リクエスト間のスリープ処理(レートリミット対策)
|
|
31
|
-
*/
|
|
32
|
-
function sleep(ms) {
|
|
33
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* リクエスト間の待機時間(ミリ秒)
|
|
37
|
-
* 環境変数 ATLASSIAN_REQUEST_DELAY で調整可能(デフォルト: 500ms)
|
|
38
|
-
*/
|
|
39
|
-
function getRequestDelay() {
|
|
40
|
-
return parseInt(process.env.ATLASSIAN_REQUEST_DELAY || '500', 10);
|
|
41
|
-
}
|
|
42
|
-
function extractStoryDetails(tasksContent, storyTitle) {
|
|
43
|
-
const details = { title: storyTitle };
|
|
44
|
-
// Story セクションを抽出(ReDoS対策: [\s\S]*? → [^]*? に変更)
|
|
45
|
-
const escapedTitle = storyTitle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
46
|
-
const storyPattern = new RegExp(`### Story [\\d.]+: ${escapedTitle}\\n([^]*?)(?=\\n### Story|\\n## Phase|$)`, 'i');
|
|
47
|
-
const storyMatch = tasksContent.match(storyPattern);
|
|
48
|
-
if (!storyMatch)
|
|
49
|
-
return details;
|
|
50
|
-
const storySection = storyMatch[1];
|
|
51
|
-
// 優先度抽出
|
|
52
|
-
const priorityMatch = storySection.match(/\*\*優先度\*\*:\s*(.+)/);
|
|
53
|
-
if (priorityMatch)
|
|
54
|
-
details.priority = priorityMatch[1].trim();
|
|
55
|
-
// 見積もり抽出
|
|
56
|
-
const estimateMatch = storySection.match(/\*\*見積もり\*\*:\s*(.+)/);
|
|
57
|
-
if (estimateMatch)
|
|
58
|
-
details.estimate = estimateMatch[1].trim();
|
|
59
|
-
// 担当抽出
|
|
60
|
-
const assigneeMatch = storySection.match(/\*\*担当\*\*:\s*(.+)/);
|
|
61
|
-
if (assigneeMatch)
|
|
62
|
-
details.assignee = assigneeMatch[1].trim();
|
|
63
|
-
// 期限抽出
|
|
64
|
-
const dueDateMatch = storySection.match(/\*\*期限\*\*:\s*(\d{4}-\d{2}-\d{2})/);
|
|
65
|
-
if (dueDateMatch)
|
|
66
|
-
details.dueDate = dueDateMatch[1];
|
|
67
|
-
// 説明抽出(改行あり・なし両方に対応)
|
|
68
|
-
const descriptionMatch = storySection.match(/\*\*説明\*\*:\s*\n?(.+?)(?=\n\*\*|$)/s);
|
|
69
|
-
if (descriptionMatch)
|
|
70
|
-
details.description = descriptionMatch[1].trim();
|
|
71
|
-
// 完了条件抽出
|
|
72
|
-
const criteriaMatch = storySection.match(/\*\*完了条件\*\*:\s*\n((?:- \[.\].*\n?)+)/);
|
|
73
|
-
if (criteriaMatch) {
|
|
74
|
-
details.acceptanceCriteria = criteriaMatch[1]
|
|
75
|
-
.split('\n')
|
|
76
|
-
.filter((line) => line.trim().startsWith('- ['))
|
|
77
|
-
.map((line) => line.replace(/^- \[.\]\s*/, '').trim())
|
|
78
|
-
.filter((line) => line.length > 0);
|
|
79
|
-
}
|
|
80
|
-
// サブタスク抽出
|
|
81
|
-
const subtasksMatch = storySection.match(/\*\*サブタスク\*\*:\s*\n((?:- \[.\].*\n?)+)/);
|
|
82
|
-
if (subtasksMatch) {
|
|
83
|
-
details.subtasks = subtasksMatch[1]
|
|
84
|
-
.split('\n')
|
|
85
|
-
.filter((line) => line.trim().startsWith('- ['))
|
|
86
|
-
.map((line) => line.replace(/^- \[.\]\s*/, '').trim())
|
|
87
|
-
.filter((line) => line.length > 0);
|
|
88
|
-
}
|
|
89
|
-
// 依存関係抽出
|
|
90
|
-
const dependenciesMatch = storySection.match(/\*\*依存関係\*\*:\s*(.+)/);
|
|
91
|
-
if (dependenciesMatch)
|
|
92
|
-
details.dependencies = dependenciesMatch[1].trim();
|
|
93
|
-
return details;
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* リッチなADF形式を生成
|
|
97
|
-
*/
|
|
98
|
-
function createRichADF(details, phaseLabel, githubUrl) {
|
|
99
|
-
const content = [];
|
|
100
|
-
// 説明セクション
|
|
101
|
-
if (details.description) {
|
|
102
|
-
content.push({
|
|
103
|
-
type: 'heading',
|
|
104
|
-
attrs: { level: 2 },
|
|
105
|
-
content: [{ type: 'text', text: '説明' }],
|
|
106
|
-
});
|
|
107
|
-
content.push({
|
|
108
|
-
type: 'paragraph',
|
|
109
|
-
content: [{ type: 'text', text: details.description }],
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
// メタデータセクション
|
|
113
|
-
const metadata = [];
|
|
114
|
-
if (details.priority)
|
|
115
|
-
metadata.push(`優先度: ${details.priority}`);
|
|
116
|
-
if (details.estimate)
|
|
117
|
-
metadata.push(`見積もり: ${details.estimate}`);
|
|
118
|
-
if (details.assignee)
|
|
119
|
-
metadata.push(`担当: ${details.assignee}`);
|
|
120
|
-
if (details.dependencies)
|
|
121
|
-
metadata.push(`依存関係: ${details.dependencies}`);
|
|
122
|
-
if (metadata.length > 0) {
|
|
123
|
-
content.push({
|
|
124
|
-
type: 'heading',
|
|
125
|
-
attrs: { level: 2 },
|
|
126
|
-
content: [{ type: 'text', text: 'メタデータ' }],
|
|
127
|
-
});
|
|
128
|
-
metadata.forEach((item) => {
|
|
129
|
-
content.push({
|
|
130
|
-
type: 'paragraph',
|
|
131
|
-
content: [{ type: 'text', text: item }],
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
// 完了条件セクション
|
|
136
|
-
if (details.acceptanceCriteria && details.acceptanceCriteria.length > 0) {
|
|
137
|
-
content.push({
|
|
138
|
-
type: 'heading',
|
|
139
|
-
attrs: { level: 2 },
|
|
140
|
-
content: [{ type: 'text', text: '完了条件' }],
|
|
141
|
-
});
|
|
142
|
-
const listItems = details.acceptanceCriteria.map((criterion) => ({
|
|
143
|
-
type: 'listItem',
|
|
144
|
-
content: [
|
|
145
|
-
{
|
|
146
|
-
type: 'paragraph',
|
|
147
|
-
content: [{ type: 'text', text: criterion }],
|
|
148
|
-
},
|
|
149
|
-
],
|
|
150
|
-
}));
|
|
151
|
-
content.push({
|
|
152
|
-
type: 'bulletList',
|
|
153
|
-
content: listItems,
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
// サブタスクセクション
|
|
157
|
-
if (details.subtasks && details.subtasks.length > 0) {
|
|
158
|
-
content.push({
|
|
159
|
-
type: 'heading',
|
|
160
|
-
attrs: { level: 2 },
|
|
161
|
-
content: [{ type: 'text', text: 'サブタスク' }],
|
|
162
|
-
});
|
|
163
|
-
const listItems = details.subtasks.map((subtask) => ({
|
|
164
|
-
type: 'listItem',
|
|
165
|
-
content: [
|
|
166
|
-
{
|
|
167
|
-
type: 'paragraph',
|
|
168
|
-
content: [{ type: 'text', text: subtask }],
|
|
169
|
-
},
|
|
170
|
-
],
|
|
171
|
-
}));
|
|
172
|
-
content.push({
|
|
173
|
-
type: 'bulletList',
|
|
174
|
-
content: listItems,
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
// フッター(Phase、GitHubリンク)
|
|
178
|
-
content.push({
|
|
179
|
-
type: 'rule',
|
|
180
|
-
});
|
|
181
|
-
content.push({
|
|
182
|
-
type: 'paragraph',
|
|
183
|
-
content: [
|
|
184
|
-
{ type: 'text', text: 'Phase: ', marks: [{ type: 'strong' }] },
|
|
185
|
-
{ type: 'text', text: phaseLabel },
|
|
186
|
-
],
|
|
187
|
-
});
|
|
188
|
-
content.push({
|
|
189
|
-
type: 'paragraph',
|
|
190
|
-
content: [
|
|
191
|
-
{ type: 'text', text: 'GitHub: ', marks: [{ type: 'strong' }] },
|
|
192
|
-
{
|
|
193
|
-
type: 'text',
|
|
194
|
-
text: githubUrl,
|
|
195
|
-
marks: [
|
|
196
|
-
{
|
|
197
|
-
type: 'link',
|
|
198
|
-
attrs: { href: githubUrl },
|
|
199
|
-
},
|
|
200
|
-
],
|
|
201
|
-
},
|
|
202
|
-
],
|
|
203
|
-
});
|
|
204
|
-
return {
|
|
205
|
-
type: 'doc',
|
|
206
|
-
version: 1,
|
|
207
|
-
content: content,
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* プレーンテキストをAtlassian Document Format(ADF)に変換
|
|
212
|
-
*/
|
|
213
|
-
function textToADF(text) {
|
|
214
|
-
// 改行で分割して段落を作成
|
|
215
|
-
const paragraphs = text.split('\n').filter((line) => line.trim().length > 0);
|
|
216
|
-
return {
|
|
217
|
-
type: 'doc',
|
|
218
|
-
version: 1,
|
|
219
|
-
content: paragraphs.map((para) => ({
|
|
220
|
-
type: 'paragraph',
|
|
221
|
-
content: [
|
|
222
|
-
{
|
|
223
|
-
type: 'text',
|
|
224
|
-
text: para.trim(),
|
|
225
|
-
},
|
|
226
|
-
],
|
|
227
|
-
})),
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
function getJIRAConfig() {
|
|
231
|
-
const url = process.env.ATLASSIAN_URL;
|
|
232
|
-
const email = process.env.ATLASSIAN_EMAIL;
|
|
233
|
-
const apiToken = process.env.ATLASSIAN_API_TOKEN;
|
|
234
|
-
if (!url || !email || !apiToken) {
|
|
235
|
-
throw new Error('Missing JIRA credentials in .env');
|
|
236
|
-
}
|
|
237
|
-
return { url, email, apiToken };
|
|
238
|
-
}
|
|
239
|
-
class JIRAClient {
|
|
240
|
-
baseUrl;
|
|
241
|
-
auth;
|
|
242
|
-
requestDelay;
|
|
243
|
-
constructor(config) {
|
|
244
|
-
this.baseUrl = `${config.url}/rest/api/3`;
|
|
245
|
-
this.auth = Buffer.from(`${config.email}:${config.apiToken}`).toString('base64');
|
|
246
|
-
this.requestDelay = getRequestDelay();
|
|
247
|
-
}
|
|
248
|
-
/**
|
|
249
|
-
* JQL検索でIssueを検索
|
|
250
|
-
* @throws 検索エラー時は例外を再スロー(呼び出し元で処理)
|
|
251
|
-
*/
|
|
252
|
-
async searchIssues(jql) {
|
|
253
|
-
// レートリミット対策: リクエスト前に待機
|
|
254
|
-
await sleep(this.requestDelay);
|
|
255
|
-
try {
|
|
256
|
-
// JIRA API v3の検索エンドポイントを使用
|
|
257
|
-
// GET /rest/api/3/search でJQL検索を実行(GETメソッドが推奨)
|
|
258
|
-
const response = await axios.get(`${this.baseUrl}/search`, {
|
|
259
|
-
params: {
|
|
260
|
-
jql,
|
|
261
|
-
maxResults: 100,
|
|
262
|
-
fields: 'summary,issuetype,status,key',
|
|
263
|
-
},
|
|
264
|
-
headers: {
|
|
265
|
-
Authorization: `Basic ${this.auth}`,
|
|
266
|
-
'Content-Type': 'application/json',
|
|
267
|
-
},
|
|
268
|
-
});
|
|
269
|
-
return response.data.issues || [];
|
|
270
|
-
}
|
|
271
|
-
catch (error) {
|
|
272
|
-
// エラーハンドリング改善
|
|
273
|
-
if (axios.isAxiosError(error)) {
|
|
274
|
-
const status = error.response?.status;
|
|
275
|
-
const errorMessages = error.response?.data?.errorMessages || [];
|
|
276
|
-
const message = errorMessages.join(', ') || error.message;
|
|
277
|
-
console.error(`Error searching issues (HTTP ${status}): ${message}`);
|
|
278
|
-
if (status === 410) {
|
|
279
|
-
console.error('💡 Hint: The search API endpoint returned 410 (Gone).');
|
|
280
|
-
console.error(' This may indicate the endpoint has been deprecated or disabled.');
|
|
281
|
-
console.error(' Check JIRA instance configuration or try alternative search methods.');
|
|
282
|
-
}
|
|
283
|
-
else if (status === 401) {
|
|
284
|
-
console.error('💡 Hint: Authentication failed. Check ATLASSIAN_API_TOKEN in .env');
|
|
285
|
-
}
|
|
286
|
-
else if (status === 403) {
|
|
287
|
-
console.error('💡 Hint: Permission denied. Check API token permissions in JIRA.');
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
else {
|
|
291
|
-
console.error('Error searching issues:', error instanceof Error ? error.message : error);
|
|
292
|
-
}
|
|
293
|
-
throw error; // エラーを再スローして呼び出し元で処理
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
async createIssue(payload) {
|
|
297
|
-
// レートリミット対策: リクエスト前に待機
|
|
298
|
-
await sleep(this.requestDelay);
|
|
299
|
-
const response = await axios.post(`${this.baseUrl}/issue`, payload, {
|
|
300
|
-
headers: {
|
|
301
|
-
Authorization: `Basic ${this.auth}`,
|
|
302
|
-
'Content-Type': 'application/json',
|
|
303
|
-
},
|
|
304
|
-
});
|
|
305
|
-
return response.data;
|
|
306
|
-
}
|
|
307
|
-
async updateIssue(issueKey, payload) {
|
|
308
|
-
// レートリミット対策: リクエスト前に待機
|
|
309
|
-
await sleep(this.requestDelay);
|
|
310
|
-
await axios.put(`${this.baseUrl}/issue/${issueKey}`, payload, {
|
|
311
|
-
headers: {
|
|
312
|
-
Authorization: `Basic ${this.auth}`,
|
|
313
|
-
'Content-Type': 'application/json',
|
|
314
|
-
},
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
/**
|
|
318
|
-
* JIRAチケットのステータスを変更(トランジション実行)
|
|
319
|
-
* @param issueKey JIRAチケットキー (例: "PROJ-123")
|
|
320
|
-
* @param transitionName 遷移先ステータス名 (例: "In Progress", "Ready for Review")
|
|
321
|
-
* @throws トランジションが見つからない場合はエラー
|
|
322
|
-
*/
|
|
323
|
-
async transitionIssue(issueKey, transitionName) {
|
|
324
|
-
// レートリミット対策: リクエスト前に待機
|
|
325
|
-
await sleep(this.requestDelay);
|
|
326
|
-
try {
|
|
327
|
-
// 1. 利用可能なトランジションを取得
|
|
328
|
-
const transitionsResponse = await axios.get(`${this.baseUrl}/issue/${issueKey}/transitions`, {
|
|
329
|
-
headers: {
|
|
330
|
-
Authorization: `Basic ${this.auth}`,
|
|
331
|
-
'Content-Type': 'application/json',
|
|
332
|
-
},
|
|
333
|
-
});
|
|
334
|
-
const transitions = transitionsResponse.data.transitions || [];
|
|
335
|
-
// 2. transitionNameに一致するトランジションIDを特定
|
|
336
|
-
// 名前の完全一致または部分一致で検索
|
|
337
|
-
const transition = transitions.find((t) => t.name.toLowerCase() === transitionName.toLowerCase() ||
|
|
338
|
-
t.name.toLowerCase().includes(transitionName.toLowerCase()));
|
|
339
|
-
if (!transition) {
|
|
340
|
-
const availableTransitions = transitions
|
|
341
|
-
.map((t) => t.name)
|
|
342
|
-
.join(', ');
|
|
343
|
-
throw new Error(`Transition "${transitionName}" not found for issue ${issueKey}. ` +
|
|
344
|
-
`Available transitions: ${availableTransitions || 'none'}`);
|
|
345
|
-
}
|
|
346
|
-
// レートリミット対策: リクエスト前に待機
|
|
347
|
-
await sleep(this.requestDelay);
|
|
348
|
-
// 3. トランジションを実行
|
|
349
|
-
await axios.post(`${this.baseUrl}/issue/${issueKey}/transitions`, {
|
|
350
|
-
transition: { id: transition.id },
|
|
351
|
-
}, {
|
|
352
|
-
headers: {
|
|
353
|
-
Authorization: `Basic ${this.auth}`,
|
|
354
|
-
'Content-Type': 'application/json',
|
|
355
|
-
},
|
|
356
|
-
});
|
|
357
|
-
console.log(`✅ ${issueKey} のステータスを「${transition.name}」に変更しました`);
|
|
358
|
-
}
|
|
359
|
-
catch (error) {
|
|
360
|
-
if (axios.isAxiosError(error)) {
|
|
361
|
-
const status = error.response?.status;
|
|
362
|
-
const errorMessages = error.response?.data?.errorMessages || [];
|
|
363
|
-
const message = errorMessages.join(', ') || error.message;
|
|
364
|
-
console.error(`Error transitioning issue ${issueKey} (HTTP ${status}): ${message}`);
|
|
365
|
-
if (status === 404) {
|
|
366
|
-
console.error(`💡 Hint: Issue ${issueKey} was not found. Check the issue key.`);
|
|
367
|
-
}
|
|
368
|
-
else if (status === 400) {
|
|
369
|
-
console.error('💡 Hint: The transition may not be valid from the current status.');
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
throw error;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
/**
|
|
376
|
-
* JIRAチケットにコメントを追加
|
|
377
|
-
* @param issueKey JIRAチケットキー
|
|
378
|
-
* @param commentText コメント内容
|
|
379
|
-
*/
|
|
380
|
-
async addComment(issueKey, commentText) {
|
|
381
|
-
// レートリミット対策: リクエスト前に待機
|
|
382
|
-
await sleep(this.requestDelay);
|
|
383
|
-
try {
|
|
384
|
-
// Atlassian Document Format (ADF) でコメントを作成
|
|
385
|
-
const commentBody = {
|
|
386
|
-
type: 'doc',
|
|
387
|
-
version: 1,
|
|
388
|
-
content: [
|
|
389
|
-
{
|
|
390
|
-
type: 'paragraph',
|
|
391
|
-
content: [
|
|
392
|
-
{
|
|
393
|
-
type: 'text',
|
|
394
|
-
text: commentText,
|
|
395
|
-
},
|
|
396
|
-
],
|
|
397
|
-
},
|
|
398
|
-
],
|
|
399
|
-
};
|
|
400
|
-
await axios.post(`${this.baseUrl}/issue/${issueKey}/comment`, {
|
|
401
|
-
body: commentBody,
|
|
402
|
-
}, {
|
|
403
|
-
headers: {
|
|
404
|
-
Authorization: `Basic ${this.auth}`,
|
|
405
|
-
'Content-Type': 'application/json',
|
|
406
|
-
},
|
|
407
|
-
});
|
|
408
|
-
console.log(`✅ ${issueKey} にコメントを追加しました`);
|
|
409
|
-
}
|
|
410
|
-
catch (error) {
|
|
411
|
-
if (axios.isAxiosError(error)) {
|
|
412
|
-
const status = error.response?.status;
|
|
413
|
-
const errorMessages = error.response?.data?.errorMessages || [];
|
|
414
|
-
const message = errorMessages.join(', ') || error.message;
|
|
415
|
-
console.error(`Error adding comment to ${issueKey} (HTTP ${status}): ${message}`);
|
|
416
|
-
if (status === 404) {
|
|
417
|
-
console.error(`💡 Hint: Issue ${issueKey} was not found. Check the issue key.`);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
throw error;
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
/**
|
|
424
|
-
* プロジェクトのIssue Type IDを取得
|
|
425
|
-
* @param projectKey プロジェクトキー
|
|
426
|
-
* @param issueTypeName Issue Type名(例: "Epic", "Story")
|
|
427
|
-
* @returns Issue Type ID
|
|
428
|
-
*/
|
|
429
|
-
async getIssueTypeId(projectKey, issueTypeName) {
|
|
430
|
-
await sleep(this.requestDelay);
|
|
431
|
-
try {
|
|
432
|
-
const response = await axios.get(`${this.baseUrl}/project/${projectKey}`, {
|
|
433
|
-
headers: {
|
|
434
|
-
Authorization: `Basic ${this.auth}`,
|
|
435
|
-
'Content-Type': 'application/json',
|
|
436
|
-
},
|
|
437
|
-
});
|
|
438
|
-
const issueTypes = (response.data.issueTypes || []);
|
|
439
|
-
const issueType = issueTypes.find((it) => it.name.toLowerCase() === issueTypeName.toLowerCase() ||
|
|
440
|
-
it.name === issueTypeName);
|
|
441
|
-
return issueType ? issueType.id : null;
|
|
442
|
-
}
|
|
443
|
-
catch (error) {
|
|
444
|
-
console.error(`Error getting issue type ID for ${issueTypeName}:`, error instanceof Error ? error.message : error);
|
|
445
|
-
return null;
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
/**
|
|
450
|
-
* リポジトリ名(repo部分のみ)を取得
|
|
451
|
-
* @param repository リポジトリURL(例: https://github.com/sk8metalme/michi.git)
|
|
452
|
-
* @returns リポジトリ名(例: michi)
|
|
453
|
-
*/
|
|
454
|
-
function extractRepoName(repository) {
|
|
455
|
-
// owner/repo 形式を抽出
|
|
456
|
-
const match = repository.match(/github\.com[:/]([\w.-]+\/[\w.-]+)(\.git)?/);
|
|
457
|
-
if (!match) {
|
|
458
|
-
// フォールバック: repository 全体を使用
|
|
459
|
-
return 'repo';
|
|
460
|
-
}
|
|
461
|
-
const ownerRepo = match[1]; // 例: sk8metalme/michi
|
|
462
|
-
const parts = ownerRepo.split('/');
|
|
463
|
-
return parts[1] || parts[0]; // repo部分のみ返す
|
|
464
|
-
}
|
|
465
|
-
/**
|
|
466
|
-
* JIRAチケットのタイトルプレフィックスを生成
|
|
467
|
-
* @param repoName リポジトリ名
|
|
468
|
-
* @param featureName 機能名
|
|
469
|
-
* @returns プレフィックス文字列(例: [michi][user-auth])
|
|
470
|
-
*/
|
|
471
|
-
function createTitlePrefix(repoName, featureName) {
|
|
472
|
-
return `[${repoName}][${featureName}]`;
|
|
473
|
-
}
|
|
474
|
-
/**
|
|
475
|
-
* Phase行からフェーズラベルを検出
|
|
476
|
-
* @param line Markdown行
|
|
477
|
-
* @returns フェーズラベル、または検出されない場合はnull
|
|
478
|
-
*/
|
|
479
|
-
function detectPhaseLabel(line) {
|
|
480
|
-
const phasePattern = /## Phase [\d.A-Z]+:\s*(.+?)(?:((.+?)))?/;
|
|
481
|
-
const phaseMatch = line.match(phasePattern);
|
|
482
|
-
if (!phaseMatch)
|
|
483
|
-
return null;
|
|
484
|
-
const phaseTitle = phaseMatch[1]; // フェーズタイトル全体
|
|
485
|
-
const phaseName = phaseMatch[2] || phaseTitle; // 括弧内のラベル(例: Requirements)または全体
|
|
486
|
-
// Phase番号を抽出(例: "0.1", "2", "A")
|
|
487
|
-
const phaseNumberMatch = line.match(/## Phase ([\d.A-Z]+):/);
|
|
488
|
-
const phaseNumber = phaseNumberMatch ? phaseNumberMatch[1] : '';
|
|
489
|
-
// フェーズ番号またはフェーズ名からラベルを決定
|
|
490
|
-
if (phaseNumber === '0.0' ||
|
|
491
|
-
phaseName.includes('初期化') ||
|
|
492
|
-
phaseName.toLowerCase().includes('init')) {
|
|
493
|
-
return 'spec-init';
|
|
494
|
-
}
|
|
495
|
-
else if (phaseNumber === '0.1' ||
|
|
496
|
-
phaseName.includes('要件定義') ||
|
|
497
|
-
phaseName.toLowerCase().includes('requirements')) {
|
|
498
|
-
return 'requirements';
|
|
499
|
-
}
|
|
500
|
-
else if (phaseNumber === '0.2' ||
|
|
501
|
-
phaseName.includes('設計') ||
|
|
502
|
-
phaseName.toLowerCase().includes('design')) {
|
|
503
|
-
return 'design';
|
|
504
|
-
}
|
|
505
|
-
else if (phaseNumber === '0.3' ||
|
|
506
|
-
phaseName.includes('テストタイプ') ||
|
|
507
|
-
phaseName.toLowerCase().includes('test-type') ||
|
|
508
|
-
phaseName.toLowerCase().includes('test type')) {
|
|
509
|
-
return 'test-type-selection';
|
|
510
|
-
}
|
|
511
|
-
else if (phaseNumber === '0.4' ||
|
|
512
|
-
phaseName.includes('テスト仕様') ||
|
|
513
|
-
phaseName.toLowerCase().includes('test-spec') ||
|
|
514
|
-
phaseName.toLowerCase().includes('test spec')) {
|
|
515
|
-
return 'test-spec';
|
|
516
|
-
}
|
|
517
|
-
else if (phaseNumber === '0.5' ||
|
|
518
|
-
phaseName.includes('タスク分割') ||
|
|
519
|
-
phaseName.toLowerCase().includes('tasks') ||
|
|
520
|
-
phaseName.toLowerCase().includes('task breakdown')) {
|
|
521
|
-
return 'spec-tasks';
|
|
522
|
-
}
|
|
523
|
-
else if (phaseNumber === '0.6' ||
|
|
524
|
-
phaseName.includes('JIRA') ||
|
|
525
|
-
phaseName.toLowerCase().includes('jira')) {
|
|
526
|
-
return 'jira-sync';
|
|
527
|
-
}
|
|
528
|
-
else if (phaseNumber === '1' ||
|
|
529
|
-
phaseName.includes('環境構築') ||
|
|
530
|
-
phaseName.toLowerCase().includes('environment') ||
|
|
531
|
-
phaseName.toLowerCase().includes('setup')) {
|
|
532
|
-
return 'environment-setup';
|
|
533
|
-
}
|
|
534
|
-
else if (phaseNumber === '2' ||
|
|
535
|
-
phaseName.includes('実装') ||
|
|
536
|
-
phaseName.includes('TDD') ||
|
|
537
|
-
phaseName.toLowerCase().includes('implementation')) {
|
|
538
|
-
return 'implementation';
|
|
539
|
-
}
|
|
540
|
-
else if (phaseNumber === 'A' ||
|
|
541
|
-
phaseNumber.toLowerCase() === 'a' ||
|
|
542
|
-
phaseName.includes('PR前') ||
|
|
543
|
-
phaseName.toLowerCase().includes('pr-test') ||
|
|
544
|
-
phaseName.toLowerCase().includes('pr test')) {
|
|
545
|
-
return 'phase-a';
|
|
546
|
-
}
|
|
547
|
-
else if (phaseNumber === '3' ||
|
|
548
|
-
phaseName.includes('追加QA') ||
|
|
549
|
-
phaseName.includes('QA') ||
|
|
550
|
-
phaseName.includes('試験') ||
|
|
551
|
-
phaseName.toLowerCase().includes('testing') ||
|
|
552
|
-
phaseName.toLowerCase().includes('additional qa')) {
|
|
553
|
-
return 'additional-qa';
|
|
554
|
-
}
|
|
555
|
-
else if (phaseNumber === 'B' ||
|
|
556
|
-
phaseNumber.toLowerCase() === 'b' ||
|
|
557
|
-
phaseName.includes('リリース準備テスト') ||
|
|
558
|
-
phaseName.toLowerCase().includes('release-test') ||
|
|
559
|
-
phaseName.toLowerCase().includes('release test')) {
|
|
560
|
-
return 'phase-b';
|
|
561
|
-
}
|
|
562
|
-
else if (phaseNumber === '4' ||
|
|
563
|
-
phaseName.includes('リリース準備') ||
|
|
564
|
-
phaseName.toLowerCase().includes('release-prep') ||
|
|
565
|
-
phaseName.toLowerCase().includes('release preparation')) {
|
|
566
|
-
return 'release-prep';
|
|
567
|
-
}
|
|
568
|
-
else if (phaseNumber === '5' ||
|
|
569
|
-
(phaseName.includes('リリース') && !phaseName.includes('準備')) ||
|
|
570
|
-
(phaseName.toLowerCase().includes('release') &&
|
|
571
|
-
!phaseName.toLowerCase().includes('prep'))) {
|
|
572
|
-
return 'release';
|
|
573
|
-
}
|
|
574
|
-
return null;
|
|
575
|
-
}
|
|
576
|
-
/**
|
|
577
|
-
* Story Issue Type IDを取得
|
|
578
|
-
* @param appConfig アプリケーション設定
|
|
579
|
-
* @param projectMeta プロジェクトメタデータ
|
|
580
|
-
* @param client JIRAクライアント
|
|
581
|
-
* @returns Story Issue Type ID
|
|
582
|
-
*/
|
|
583
|
-
async function getStoryIssueTypeId(appConfig, projectMeta, client) {
|
|
584
|
-
// StoryタイプのIDを動的に取得(日本語JIRAでは "ストーリー" という名前の場合がある)
|
|
585
|
-
let storyIssueTypeId = appConfig.jira?.issueTypes?.story || process.env.JIRA_ISSUE_TYPE_STORY;
|
|
586
|
-
console.log(`📋 Story Issue Type ID from config/env: ${storyIssueTypeId || 'not found'}`);
|
|
587
|
-
if (!storyIssueTypeId) {
|
|
588
|
-
console.log('🔍 Attempting to find Story issue type dynamically...');
|
|
589
|
-
const foundId = (await client.getIssueTypeId(projectMeta.jiraProjectKey, 'Story')) ||
|
|
590
|
-
(await client.getIssueTypeId(projectMeta.jiraProjectKey, 'ストーリー'));
|
|
591
|
-
storyIssueTypeId = foundId ?? undefined;
|
|
592
|
-
console.log(`📋 Story Issue Type ID from API: ${storyIssueTypeId || 'not found'}`);
|
|
593
|
-
}
|
|
594
|
-
if (!storyIssueTypeId) {
|
|
595
|
-
throw new Error('JIRA Story issue type ID is not configured and could not be found in project. ' +
|
|
596
|
-
'Please set JIRA_ISSUE_TYPE_STORY environment variable or configure it in .michi/config.json. ' +
|
|
597
|
-
'You can find the issue type ID in JIRA UI (Settings > Issues > Issue types) or via REST API: ' +
|
|
598
|
-
'GET https://your-domain.atlassian.net/rest/api/3/project/{projectKey}');
|
|
599
|
-
}
|
|
600
|
-
console.log(`✅ Using Story Issue Type ID: ${storyIssueTypeId}`);
|
|
601
|
-
return storyIssueTypeId;
|
|
602
|
-
}
|
|
603
|
-
/**
|
|
604
|
-
* Epic を取得または作成
|
|
605
|
-
* @param featureName 機能名
|
|
606
|
-
* @param spec spec.json の内容
|
|
607
|
-
* @param projectMeta プロジェクトメタデータ
|
|
608
|
-
* @param client JIRAクライアント
|
|
609
|
-
* @returns Epic キー
|
|
610
|
-
*/
|
|
611
|
-
async function getOrCreateEpic(featureName, spec, projectMeta, client) {
|
|
612
|
-
// 既存のEpicをチェック
|
|
613
|
-
if (spec.jira?.epicKey) {
|
|
614
|
-
console.log(`Existing Epic found: ${spec.jira.epicKey}`);
|
|
615
|
-
console.log('Skipping Epic creation (already exists)');
|
|
616
|
-
return { key: spec.jira.epicKey };
|
|
617
|
-
}
|
|
618
|
-
// Epic作成
|
|
619
|
-
console.log('Creating Epic...');
|
|
620
|
-
const repoName = extractRepoName(projectMeta.repository);
|
|
621
|
-
const titlePrefix = createTitlePrefix(repoName, featureName);
|
|
622
|
-
const epicSummary = `${titlePrefix} ${projectMeta.projectName}`;
|
|
623
|
-
// 同じタイトルのEpicがすでに存在するかJQLで検索
|
|
624
|
-
const jql = `project = ${projectMeta.jiraProjectKey} AND issuetype = Epic AND summary ~ "${featureName}"`;
|
|
625
|
-
let existingEpics = [];
|
|
626
|
-
try {
|
|
627
|
-
existingEpics = await client.searchIssues(jql);
|
|
628
|
-
}
|
|
629
|
-
catch (error) {
|
|
630
|
-
console.error('❌ Failed to search existing Epics:', error instanceof Error ? error.message : error);
|
|
631
|
-
console.error('⚠️ Cannot verify idempotency - proceeding with Epic creation');
|
|
632
|
-
console.error(' If Epic already exists, manual cleanup may be required');
|
|
633
|
-
// 検索失敗時はフォールバック: 新規作成を試みる(重複リスクあり)
|
|
634
|
-
existingEpics = [];
|
|
635
|
-
}
|
|
636
|
-
if (existingEpics.length > 0) {
|
|
637
|
-
console.log(`Found existing Epic with similar title: ${existingEpics[0].key}`);
|
|
638
|
-
console.log('Using existing Epic instead of creating new one');
|
|
639
|
-
return existingEpics[0];
|
|
640
|
-
}
|
|
641
|
-
// EpicタイプのIDを取得(日本語JIRAでは "エピック" という名前の場合がある)
|
|
642
|
-
const epicTypeId = (await client.getIssueTypeId(projectMeta.jiraProjectKey, 'Epic')) ||
|
|
643
|
-
(await client.getIssueTypeId(projectMeta.jiraProjectKey, 'エピック'));
|
|
644
|
-
if (!epicTypeId) {
|
|
645
|
-
throw new Error('Epic issue type not found in project. ' +
|
|
646
|
-
'Please ensure the project has Epic issue type enabled.');
|
|
647
|
-
}
|
|
648
|
-
const epicDescription = `機能: ${featureName}\nGitHub: ${projectMeta.repository}/tree/main/.kiro/specs/${featureName}`;
|
|
649
|
-
const epicPayload = {
|
|
650
|
-
fields: {
|
|
651
|
-
project: { key: projectMeta.jiraProjectKey },
|
|
652
|
-
summary: epicSummary,
|
|
653
|
-
description: textToADF(epicDescription), // ADF形式に変換
|
|
654
|
-
issuetype: { id: epicTypeId }, // IDを使用(nameではなく)
|
|
655
|
-
labels: projectMeta.confluenceLabels,
|
|
656
|
-
},
|
|
657
|
-
};
|
|
658
|
-
const epic = await client.createIssue(epicPayload);
|
|
659
|
-
console.log(`✅ Epic created: ${epic.key}`);
|
|
660
|
-
return epic;
|
|
661
|
-
}
|
|
662
|
-
async function syncTasksToJIRA(featureName) {
|
|
663
|
-
console.log(`Syncing tasks for feature: ${featureName}`);
|
|
664
|
-
// feature名のバリデーション(必須)
|
|
665
|
-
validateFeatureNameOrThrow(featureName);
|
|
666
|
-
// 実行前の必須設定値チェック(非同期版:Issue Type IDの存在チェック付き)
|
|
667
|
-
const validation = await validateForJiraSyncAsync();
|
|
668
|
-
if (validation.info.length > 0) {
|
|
669
|
-
validation.info.forEach((msg) => console.log(`ℹ️ ${msg}`));
|
|
670
|
-
}
|
|
671
|
-
if (validation.warnings.length > 0) {
|
|
672
|
-
console.warn('⚠️ Warnings:');
|
|
673
|
-
validation.warnings.forEach((warning) => console.warn(` ${warning}`));
|
|
674
|
-
}
|
|
675
|
-
if (validation.errors.length > 0) {
|
|
676
|
-
console.error('❌ Configuration errors:');
|
|
677
|
-
validation.errors.forEach((error) => console.error(` ${error}`));
|
|
678
|
-
const configPath = getConfigPath();
|
|
679
|
-
console.error(`\n設定ファイル: ${configPath}`);
|
|
680
|
-
throw new Error('JIRA同期に必要な設定値が不足しています。上記のエラーを確認して設定を修正してください。');
|
|
681
|
-
}
|
|
682
|
-
console.log(`⏳ Request delay: ${getRequestDelay()}ms (set ATLASSIAN_REQUEST_DELAY to adjust)`);
|
|
683
|
-
// 設定からissue type IDを取得(検索と作成の両方で使用)
|
|
684
|
-
const appConfig = getConfig();
|
|
685
|
-
const projectMeta = loadProjectMeta();
|
|
686
|
-
const config = getJIRAConfig();
|
|
687
|
-
const client = new JIRAClient(config);
|
|
688
|
-
// リポジトリ名を取得(タイトルプレフィックス用)
|
|
689
|
-
const repoName = extractRepoName(projectMeta.repository);
|
|
690
|
-
const titlePrefix = createTitlePrefix(repoName, featureName);
|
|
691
|
-
// StoryタイプのIDを取得
|
|
692
|
-
const storyIssueTypeId = await getStoryIssueTypeId(appConfig, projectMeta, client);
|
|
693
|
-
const tasksPath = resolve(`.kiro/specs/${featureName}/tasks.md`);
|
|
694
|
-
const tasksContent = readFileSync(tasksPath, 'utf-8');
|
|
695
|
-
// spec.jsonを読み込んで既存のEpicキーを確認
|
|
696
|
-
const specPath = resolve(`.kiro/specs/${featureName}/spec.json`);
|
|
697
|
-
let spec = {};
|
|
698
|
-
try {
|
|
699
|
-
spec = JSON.parse(readFileSync(specPath, 'utf-8'));
|
|
700
|
-
}
|
|
701
|
-
catch {
|
|
702
|
-
console.error('spec.json not found or invalid');
|
|
703
|
-
}
|
|
704
|
-
// Epic を取得または作成
|
|
705
|
-
const epic = await getOrCreateEpic(featureName, spec, projectMeta, client);
|
|
706
|
-
// 既存のStoryを検索(重複防止)
|
|
707
|
-
// ラベルで検索(summary検索では "Story: タイトル" 形式に一致しないため)
|
|
708
|
-
// issuetype検索にはIDを使用(名前は言語依存のため)
|
|
709
|
-
const storyJql = `project = ${projectMeta.jiraProjectKey} AND issuetype = ${storyIssueTypeId} AND labels = "${featureName}"`;
|
|
710
|
-
let existingStories = [];
|
|
711
|
-
try {
|
|
712
|
-
existingStories = await client.searchIssues(storyJql);
|
|
713
|
-
}
|
|
714
|
-
catch (error) {
|
|
715
|
-
console.error('❌ Failed to search existing Stories:', error instanceof Error ? error.message : error);
|
|
716
|
-
console.error('⚠️ Cannot verify idempotency - Story creation may result in duplicates');
|
|
717
|
-
console.error('⚠️ Continuing with story creation (duplicates may be created)...');
|
|
718
|
-
// 検索失敗時も処理を継続(既存ストーリーなしとして扱う)
|
|
719
|
-
existingStories = [];
|
|
720
|
-
}
|
|
721
|
-
const existingStorySummaries = new Set(existingStories
|
|
722
|
-
.filter((s) => s?.fields?.summary)
|
|
723
|
-
.map((s) => s.fields.summary));
|
|
724
|
-
const existingStoryKeys = new Set(existingStories
|
|
725
|
-
.filter((s) => s?.key)
|
|
726
|
-
.map((s) => s.key));
|
|
727
|
-
console.log(`Found ${existingStories.length} existing stories for this feature`);
|
|
728
|
-
// フェーズラベル検出用の正規表現
|
|
729
|
-
// Phase X: フェーズ名(ラベル)の形式を検出
|
|
730
|
-
// Phase番号: 数字(0, 1, 2...)、ドット付き数字(0.1, 0.2...)、英字(A, B)に対応
|
|
731
|
-
const phasePattern = /## Phase [\d.A-Z]+:\s*(.+?)(?:((.+?)))?/;
|
|
732
|
-
// Story作成(フェーズ検出付きパーサー)
|
|
733
|
-
const lines = tasksContent.split('\n');
|
|
734
|
-
let currentPhaseLabel = 'implementation'; // デフォルトは実装フェーズ
|
|
735
|
-
const createdStories = [];
|
|
736
|
-
for (let i = 0; i < lines.length; i++) {
|
|
737
|
-
const line = lines[i];
|
|
738
|
-
// フェーズ検出
|
|
739
|
-
const detectedPhase = detectPhaseLabel(line);
|
|
740
|
-
if (detectedPhase) {
|
|
741
|
-
currentPhaseLabel = detectedPhase;
|
|
742
|
-
// ログ出力用にphaseTitle と phaseNumber を抽出
|
|
743
|
-
const phaseMatch = line.match(phasePattern);
|
|
744
|
-
const phaseTitle = phaseMatch ? phaseMatch[1] : '';
|
|
745
|
-
const phaseNumberMatch = line.match(/## Phase ([\d.A-Z]+):/);
|
|
746
|
-
const phaseNumber = phaseNumberMatch ? phaseNumberMatch[1] : '';
|
|
747
|
-
console.log(`📌 Phase detected: ${phaseTitle} (number: ${phaseNumber}, label: ${currentPhaseLabel})`);
|
|
748
|
-
continue;
|
|
749
|
-
}
|
|
750
|
-
// Story検出
|
|
751
|
-
const storyMatch = line.match(/### Story [\d.]+: (.+)/);
|
|
752
|
-
if (!storyMatch)
|
|
753
|
-
continue;
|
|
754
|
-
const storyTitle = storyMatch[1];
|
|
755
|
-
const storySummary = `${titlePrefix} Story: ${storyTitle}`;
|
|
756
|
-
// 既に同じタイトルのStoryが存在するかチェック
|
|
757
|
-
if (existingStorySummaries.has(storySummary)) {
|
|
758
|
-
console.log(`Skipping Story (already exists): ${storyTitle}`);
|
|
759
|
-
const existing = existingStories.find((s) => s?.fields?.summary === storySummary);
|
|
760
|
-
if (existing) {
|
|
761
|
-
createdStories.push(existing.key);
|
|
762
|
-
existingStoryKeys.add(existing.key);
|
|
763
|
-
}
|
|
764
|
-
else {
|
|
765
|
-
console.warn(`⚠️ Warning: Story "${storyTitle}" is in summary set but not found in existingStories array`);
|
|
766
|
-
}
|
|
767
|
-
continue;
|
|
768
|
-
}
|
|
769
|
-
console.log(`Creating Story: ${storyTitle} [${currentPhaseLabel}]`);
|
|
770
|
-
try {
|
|
771
|
-
// Storyの詳細情報を抽出(新しい実装を使用)
|
|
772
|
-
const storyDetails = extractStoryDetails(tasksContent, storyTitle);
|
|
773
|
-
// GitHubリンク
|
|
774
|
-
const githubUrl = `${projectMeta.repository}/tree/main/.kiro/specs/${featureName}/tasks.md`;
|
|
775
|
-
// リッチなADF形式で説明文を生成
|
|
776
|
-
const richDescription = createRichADF(storyDetails, currentPhaseLabel, githubUrl);
|
|
777
|
-
// 優先度のマッピング(デフォルト: Medium)
|
|
778
|
-
const priorityMap = {
|
|
779
|
-
High: 'High',
|
|
780
|
-
Medium: 'Medium',
|
|
781
|
-
Low: 'Low',
|
|
782
|
-
};
|
|
783
|
-
const priority = storyDetails.priority && priorityMap[storyDetails.priority]
|
|
784
|
-
? priorityMap[storyDetails.priority]
|
|
785
|
-
: 'Medium';
|
|
786
|
-
// 見積もり(Story Points)を取得
|
|
787
|
-
let storyPoints;
|
|
788
|
-
if (storyDetails.estimate) {
|
|
789
|
-
const spMatch = storyDetails.estimate.match(/(\d+)\s*SP/);
|
|
790
|
-
if (spMatch) {
|
|
791
|
-
storyPoints = parseInt(spMatch[1], 10);
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
// JIRAペイロードを作成(issue type IDは既に取得済み)
|
|
795
|
-
const storyPayload = {
|
|
796
|
-
fields: {
|
|
797
|
-
project: { key: projectMeta.jiraProjectKey },
|
|
798
|
-
summary: storySummary,
|
|
799
|
-
description: richDescription, // リッチなADF形式
|
|
800
|
-
issuetype: { id: storyIssueTypeId },
|
|
801
|
-
labels: [
|
|
802
|
-
...projectMeta.confluenceLabels,
|
|
803
|
-
featureName,
|
|
804
|
-
currentPhaseLabel,
|
|
805
|
-
],
|
|
806
|
-
priority: { name: priority },
|
|
807
|
-
},
|
|
808
|
-
};
|
|
809
|
-
// 期限(Due Date)を設定
|
|
810
|
-
if (storyDetails.dueDate) {
|
|
811
|
-
storyPayload.fields.duedate = storyDetails.dueDate; // YYYY-MM-DD形式
|
|
812
|
-
}
|
|
813
|
-
// Story Pointsを設定(カスタムフィールド)
|
|
814
|
-
// 注意: JIRAプロジェクトによってカスタムフィールドIDが異なる場合があります
|
|
815
|
-
// 環境変数 JIRA_STORY_POINTS_FIELD で設定可能(例: customfield_10016)
|
|
816
|
-
if (storyPoints !== undefined) {
|
|
817
|
-
const storyPointsField = process.env.JIRA_STORY_POINTS_FIELD || 'customfield_10016';
|
|
818
|
-
storyPayload.fields[storyPointsField] = storyPoints;
|
|
819
|
-
}
|
|
820
|
-
// 担当者を設定(アカウントIDが必要な場合があるため、オプション)
|
|
821
|
-
// 注意: JIRAのアカウントIDが必要な場合があります
|
|
822
|
-
// if (storyInfo?.assignee) {
|
|
823
|
-
// storyPayload.fields.assignee = { name: storyInfo.assignee };
|
|
824
|
-
// }
|
|
825
|
-
const story = await client.createIssue(storyPayload);
|
|
826
|
-
console.log(` ✅ Story created: ${story.key} [${currentPhaseLabel}]`);
|
|
827
|
-
// 期限とStory Pointsの情報を表示
|
|
828
|
-
if (storyDetails.dueDate) {
|
|
829
|
-
console.log(` 期限: ${storyDetails.dueDate}`);
|
|
830
|
-
}
|
|
831
|
-
if (storyDetails.estimate) {
|
|
832
|
-
console.log(` 見積もり: ${storyDetails.estimate}`);
|
|
833
|
-
}
|
|
834
|
-
if (storyPoints !== undefined) {
|
|
835
|
-
console.log(` Story Points: ${storyPoints} SP`);
|
|
836
|
-
}
|
|
837
|
-
createdStories.push(story.key);
|
|
838
|
-
// 進捗表示(大量作成時の見通し向上)
|
|
839
|
-
if (createdStories.length % 5 === 0) {
|
|
840
|
-
console.log(` 📊 Progress: ${createdStories.length} stories created so far...`);
|
|
841
|
-
}
|
|
842
|
-
// Epic Linkは手動設定が必要(JIRA Cloudの制約)
|
|
843
|
-
console.log(` ℹ️ Epic: ${epic.key} に手動でリンクしてください`);
|
|
844
|
-
}
|
|
845
|
-
catch (error) {
|
|
846
|
-
console.error(` ❌ Failed to create Story "${storyTitle}":`, error instanceof Error ? error.message : error);
|
|
847
|
-
// JIRA APIエラーの詳細を表示
|
|
848
|
-
const errorObj = error;
|
|
849
|
-
if (errorObj.response?.data) {
|
|
850
|
-
console.error(' 📋 JIRA API Error Details:', JSON.stringify(errorObj.response.data, null, 2));
|
|
851
|
-
// Story Pointsフィールドのエラーの場合、警告を表示
|
|
852
|
-
if (errorObj.response.data.errors &&
|
|
853
|
-
Object.keys(errorObj.response.data.errors).some((key) => key.includes('customfield'))) {
|
|
854
|
-
console.error(' ⚠️ Story Pointsフィールドの設定に失敗しました。');
|
|
855
|
-
console.error(' 💡 環境変数 JIRA_STORY_POINTS_FIELD を正しいカスタムフィールドIDに設定してください。');
|
|
856
|
-
console.error(' 💡 JIRA管理画面でStory PointsのカスタムフィールドIDを確認してください。');
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
// エラーがあっても他のStoryの作成は継続
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
// 新規作成数と再利用数を正確に計算
|
|
863
|
-
const newStoryCount = createdStories.filter((key) => !existingStoryKeys.has(key)).length;
|
|
864
|
-
const reusedStoryCount = createdStories.filter((key) => existingStoryKeys.has(key)).length;
|
|
865
|
-
console.log('\n✅ JIRA sync completed');
|
|
866
|
-
console.log(` Epic: ${epic.key}`);
|
|
867
|
-
console.log(` Stories: ${createdStories.length} processed (${newStoryCount} new, ${reusedStoryCount} reused)`);
|
|
868
|
-
// spec.json を更新
|
|
869
|
-
const jiraBaseUrl = process.env.ATLASSIAN_URL || '';
|
|
870
|
-
try {
|
|
871
|
-
updateSpecJsonAfterJiraSync(featureName, {
|
|
872
|
-
projectKey: projectMeta.jiraProjectKey,
|
|
873
|
-
epicKey: epic.key,
|
|
874
|
-
epicUrl: `${jiraBaseUrl}/browse/${epic.key}`,
|
|
875
|
-
storyKeys: createdStories,
|
|
876
|
-
});
|
|
877
|
-
}
|
|
878
|
-
catch (error) {
|
|
879
|
-
console.warn(`⚠️ Failed to update spec.json after JIRA sync: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
880
|
-
// spec.json更新の失敗はスクリプト全体の失敗とはしない(JIRA同期は成功しているため)
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
9
|
// CLI実行
|
|
884
10
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
885
11
|
const args = process.argv.slice(2);
|
|
@@ -887,7 +13,7 @@ if (import.meta.url === `file://${process.argv[1]}`) {
|
|
|
887
13
|
console.error('Usage: npm run jira:sync <feature-name>');
|
|
888
14
|
process.exit(1);
|
|
889
15
|
}
|
|
890
|
-
|
|
16
|
+
jiraSyncCommand({ featureName: args[0] })
|
|
891
17
|
.then(() => process.exit(0))
|
|
892
18
|
.catch((error) => {
|
|
893
19
|
console.error('❌ JIRA sync failed:', error.message);
|