moai-adk 0.4.5__py3-none-any.whl → 0.20.1__py3-none-any.whl
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.
Potentially problematic release.
This version of moai-adk might be problematic. Click here for more details.
- moai_adk/__init__.py +1 -1
- moai_adk/__main__.py +74 -1
- moai_adk/cli/commands/__init__.py +1 -1
- moai_adk/cli/commands/analyze.py +119 -0
- moai_adk/cli/commands/backup.py +25 -1
- moai_adk/cli/commands/doctor.py +31 -5
- moai_adk/cli/commands/improve_user_experience.py +307 -0
- moai_adk/cli/commands/init.py +111 -10
- moai_adk/cli/commands/status.py +33 -3
- moai_adk/cli/commands/update.py +921 -130
- moai_adk/cli/commands/validate_links.py +120 -0
- moai_adk/cli/prompts/init_prompts.py +22 -87
- moai_adk/core/analysis/__init__.py +9 -0
- moai_adk/core/analysis/session_analyzer.py +388 -0
- moai_adk/core/analysis/tag_chain_analyzer.py +344 -0
- moai_adk/core/analysis/tag_chain_repair.py +879 -0
- moai_adk/core/config/__init__.py +19 -0
- moai_adk/core/config/migration.py +235 -0
- moai_adk/core/git/__init__.py +1 -1
- moai_adk/core/git/branch.py +1 -1
- moai_adk/core/git/commit.py +1 -1
- moai_adk/core/git/manager.py +1 -1
- moai_adk/core/issue_creator.py +313 -0
- moai_adk/core/mcp/setup.py +56 -0
- moai_adk/core/mcp/setup_old.py +296 -0
- moai_adk/core/project/backup_utils.py +1 -1
- moai_adk/core/project/checker.py +2 -2
- moai_adk/core/project/detector.py +211 -12
- moai_adk/core/project/initializer.py +85 -15
- moai_adk/core/project/phase_executor.py +76 -13
- moai_adk/core/project/validator.py +13 -13
- moai_adk/core/quality/__init__.py +1 -1
- moai_adk/core/quality/trust_checker.py +1 -1
- moai_adk/core/quality/validators/__init__.py +1 -1
- moai_adk/core/quality/validators/base_validator.py +1 -1
- moai_adk/core/tags/__init__.py +86 -0
- moai_adk/core/tags/auto_corrector.py +693 -0
- moai_adk/core/tags/ci_validator.py +463 -0
- moai_adk/core/tags/cli.py +283 -0
- moai_adk/core/tags/generator.py +109 -0
- moai_adk/core/tags/inserter.py +99 -0
- moai_adk/core/tags/mapper.py +126 -0
- moai_adk/core/tags/parser.py +76 -0
- moai_adk/core/tags/policy_validator.py +580 -0
- moai_adk/core/tags/pre_commit_validator.py +421 -0
- moai_adk/core/tags/reporter.py +956 -0
- moai_adk/core/tags/rollback_manager.py +525 -0
- moai_adk/core/tags/tags.py +149 -0
- moai_adk/core/tags/validator.py +897 -0
- moai_adk/core/template/__init__.py +1 -1
- moai_adk/core/template/backup.py +1 -1
- moai_adk/core/template/merger.py +50 -1
- moai_adk/core/template/processor.py +119 -13
- moai_adk/core/template_engine.py +268 -0
- moai_adk/templates/.claude/agents/alfred/backend-expert.md +348 -0
- moai_adk/templates/.claude/agents/alfred/cc-manager.md +209 -944
- moai_adk/templates/.claude/agents/alfred/database-expert.md +352 -0
- moai_adk/templates/.claude/agents/alfred/debug-helper.md +34 -5
- moai_adk/templates/.claude/agents/alfred/devops-expert.md +464 -0
- moai_adk/templates/.claude/agents/alfred/doc-syncer.md +38 -8
- moai_adk/templates/.claude/agents/alfred/format-expert.md +469 -0
- moai_adk/templates/.claude/agents/alfred/frontend-expert.md +357 -0
- moai_adk/templates/.claude/agents/alfred/git-manager.md +128 -9
- moai_adk/templates/.claude/agents/alfred/implementation-planner.md +104 -6
- moai_adk/templates/.claude/agents/alfred/project-manager.md +88 -16
- moai_adk/templates/.claude/agents/alfred/quality-gate.md +36 -9
- moai_adk/templates/.claude/agents/alfred/security-expert.md +270 -0
- moai_adk/templates/.claude/agents/alfred/skill-factory.md +865 -0
- moai_adk/templates/.claude/agents/alfred/spec-builder.md +214 -43
- moai_adk/templates/.claude/agents/alfred/tag-agent.md +111 -9
- moai_adk/templates/.claude/agents/alfred/tdd-implementer.md +309 -160
- moai_adk/templates/.claude/agents/alfred/trust-checker.md +36 -7
- moai_adk/templates/.claude/agents/alfred/ui-ux-expert.md +605 -0
- moai_adk/templates/.claude/commands/alfred/0-project.md +393 -966
- moai_adk/templates/.claude/commands/alfred/1-plan.md +651 -367
- moai_adk/templates/.claude/commands/alfred/2-run.md +388 -241
- moai_adk/templates/.claude/commands/alfred/3-sync.md +1921 -410
- moai_adk/templates/.claude/commands/alfred/9-feedback.md +153 -0
- moai_adk/templates/.claude/commands/alfred/release-new.md +3604 -0
- moai_adk/templates/.claude/hooks/alfred/core/project.py +484 -20
- moai_adk/templates/.claude/hooks/alfred/core/timeout.py +136 -0
- moai_adk/templates/.claude/hooks/alfred/core/ttl_cache.py +108 -0
- moai_adk/templates/.claude/hooks/alfred/core/version_cache.py +198 -0
- moai_adk/templates/.claude/hooks/alfred/handlers/__init__.py +14 -6
- moai_adk/templates/.claude/hooks/alfred/post_tool__enable_streaming_ui.py +50 -0
- moai_adk/templates/.claude/hooks/alfred/post_tool__log_changes.py +93 -0
- moai_adk/templates/.claude/hooks/alfred/post_tool__tag_auto_corrector.py +407 -0
- moai_adk/templates/.claude/hooks/alfred/pre_tool__auto_checkpoint.py +99 -0
- moai_adk/templates/.claude/hooks/alfred/pre_tool__realtime_tag_monitor.py +335 -0
- moai_adk/templates/.claude/hooks/alfred/pre_tool__tag_policy_validator.py +325 -0
- moai_adk/templates/.claude/hooks/alfred/session_end__cleanup.py +93 -0
- moai_adk/templates/.claude/hooks/alfred/session_start__auto_cleanup.py +580 -0
- moai_adk/templates/.claude/hooks/alfred/session_start__show_project_info.py +298 -0
- moai_adk/templates/.claude/hooks/alfred/shared/core/__init__.py +170 -0
- moai_adk/templates/.claude/hooks/alfred/{core → shared/core}/checkpoint.py +3 -3
- moai_adk/templates/.claude/hooks/alfred/{core → shared/core}/context.py +5 -5
- moai_adk/templates/.claude/hooks/alfred/shared/core/project.py +749 -0
- moai_adk/templates/.claude/hooks/alfred/shared/core/tags.py +230 -0
- moai_adk/templates/.claude/hooks/alfred/shared/core/version_cache.py +198 -0
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/__init__.py +21 -0
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/daily_analysis.py +351 -0
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/notification.py +154 -0
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/session.py +174 -0
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/tool.py +87 -0
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/user.py +61 -0
- moai_adk/templates/.claude/hooks/alfred/user_prompt__jit_load_docs.py +111 -0
- moai_adk/templates/.claude/hooks/alfred/utils/__init__.py +1 -0
- moai_adk/templates/.claude/hooks/alfred/utils/hook_config.py +94 -0
- moai_adk/templates/.claude/hooks/alfred/utils/timeout.py +161 -0
- moai_adk/templates/.claude/output-styles/alfred/alfred-moai-adk-beginner.md +267 -0
- moai_adk/templates/.claude/output-styles/alfred/keating-personal-tutor.md +440 -0
- moai_adk/templates/.claude/output-styles/alfred/r2d2-agentic-coding.md +583 -0
- moai_adk/templates/.claude/settings.json +96 -14
- moai_adk/templates/.claude/skills/moai-alfred-agent-guide/SKILL.md +70 -0
- moai_adk/templates/.claude/skills/moai-alfred-agent-guide/examples.md +62 -0
- moai_adk/templates/.claude/skills/moai-alfred-agent-guide/reference.md +242 -0
- moai_adk/templates/.claude/skills/moai-alfred-ask-user-questions/SKILL.md +237 -0
- moai_adk/templates/.claude/skills/moai-alfred-ask-user-questions/examples.md +871 -0
- moai_adk/templates/.claude/skills/moai-alfred-ask-user-questions/reference.md +653 -0
- moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/README.md +162 -0
- moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/SKILL.md +227 -0
- moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/examples.md +354 -0
- moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/reference.md +158 -0
- moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/SKILL.md +179 -79
- moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/examples.md +117 -0
- moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/scripts/pre-review-check.sh +62 -0
- moai_adk/templates/.claude/skills/moai-alfred-config-schema/SKILL.md +132 -0
- moai_adk/templates/.claude/skills/moai-alfred-config-schema/examples.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-config-schema/reference.md +444 -0
- moai_adk/templates/.claude/skills/moai-alfred-context-budget/SKILL.md +62 -0
- moai_adk/templates/.claude/skills/moai-alfred-context-budget/examples.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-context-budget/reference.md +405 -0
- moai_adk/templates/.claude/skills/moai-alfred-dev-guide/SKILL.md +51 -0
- moai_adk/templates/.claude/skills/moai-alfred-dev-guide/examples.md +355 -0
- moai_adk/templates/.claude/skills/moai-alfred-dev-guide/reference.md +239 -0
- moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/SKILL.md +323 -0
- moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/examples.md +286 -0
- moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/reference.md +126 -0
- moai_adk/templates/.claude/skills/moai-alfred-issue-labels/SKILL.md +229 -0
- moai_adk/templates/.claude/skills/moai-alfred-issue-labels/examples.md +4 -0
- moai_adk/templates/.claude/skills/moai-alfred-issue-labels/reference.md +150 -0
- moai_adk/templates/.claude/skills/moai-alfred-language-detection/SKILL.md +87 -73
- moai_adk/templates/.claude/skills/moai-alfred-language-detection/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-alfred-language-detection/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-personas/README.md +42 -0
- moai_adk/templates/.claude/skills/moai-alfred-personas/SKILL.md +429 -0
- moai_adk/templates/.claude/skills/moai-alfred-personas/examples.md +520 -0
- moai_adk/templates/.claude/skills/moai-alfred-personas/reference.md +405 -0
- moai_adk/templates/.claude/skills/moai-alfred-practices/SKILL.md +89 -0
- moai_adk/templates/.claude/skills/moai-alfred-practices/examples.md +122 -0
- moai_adk/templates/.claude/skills/moai-alfred-practices/reference.md +369 -0
- moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/SKILL.md +508 -0
- moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/examples.md +481 -0
- moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/reference.md +100 -0
- moai_adk/templates/.claude/skills/moai-alfred-rules/SKILL.md +77 -0
- moai_adk/templates/.claude/skills/moai-alfred-rules/examples.md +265 -0
- moai_adk/templates/.claude/skills/moai-alfred-rules/reference.md +539 -0
- moai_adk/templates/.claude/skills/moai-alfred-session-state/SKILL.md +320 -0
- moai_adk/templates/.claude/skills/moai-alfred-session-state/examples.md +4 -0
- moai_adk/templates/.claude/skills/moai-alfred-session-state/reference.md +84 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/README.md +137 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/SKILL.md +219 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/examples/validate-spec.sh +161 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/examples.md +541 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/reference.md +622 -0
- moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/SKILL.md +19 -0
- moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/examples.md +4 -0
- moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/reference.md +211 -0
- moai_adk/templates/.claude/skills/moai-alfred-workflow/SKILL.md +288 -0
- moai_adk/templates/.claude/skills/moai-cc-agents/SKILL.md +269 -0
- moai_adk/templates/.claude/skills/moai-cc-agents/templates/agent-template.md +32 -0
- moai_adk/templates/.claude/skills/moai-cc-claude-md/SKILL.md +298 -0
- moai_adk/templates/.claude/skills/moai-cc-claude-md/templates/CLAUDE-template.md +26 -0
- moai_adk/templates/.claude/skills/moai-cc-commands/SKILL.md +307 -0
- moai_adk/templates/.claude/skills/moai-cc-commands/templates/command-template.md +21 -0
- moai_adk/templates/.claude/skills/moai-cc-hooks/SKILL.md +252 -0
- moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/pre-bash-check.sh +19 -0
- moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/preserve-permissions.sh +19 -0
- moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/validate-bash-command.py +24 -0
- moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/SKILL.md +199 -0
- moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/templates/settings-mcp-template.json +39 -0
- moai_adk/templates/.claude/skills/moai-cc-memory/SKILL.md +316 -0
- moai_adk/templates/.claude/skills/moai-cc-memory/templates/session-summary-template.md +18 -0
- moai_adk/templates/.claude/skills/moai-cc-settings/SKILL.md +263 -0
- moai_adk/templates/.claude/skills/moai-cc-settings/templates/settings-complete-template.json +30 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/CHECKLIST.md +482 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/EXAMPLES.md +303 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/INTERACTIVE-DISCOVERY.md +524 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/METADATA.md +477 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/PARALLEL-ANALYSIS-REPORT.md +429 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/PYTHON-VERSION-MATRIX.md +391 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL-FACTORY-WORKFLOW.md +431 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL-UPDATE-ADVISOR.md +577 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL.md +273 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/STEP-BY-STEP-GUIDE.md +466 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/STRUCTURE.md +583 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/WEB-RESEARCH.md +526 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/reference.md +608 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/scripts/generate-structure.sh +328 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/scripts/validate-skill.sh +312 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/SKILL_TEMPLATE.md +245 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/examples-template.md +285 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/reference-template.md +278 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/scripts-template.sh +303 -0
- moai_adk/templates/.claude/skills/moai-cc-skills/SKILL.md +291 -0
- moai_adk/templates/.claude/skills/moai-cc-skills/templates/SKILL-template.md +15 -0
- moai_adk/templates/.claude/skills/moai-change-logger/SKILL.md +563 -0
- moai_adk/templates/.claude/skills/moai-design-systems/SKILL.md +802 -0
- moai_adk/templates/.claude/skills/moai-design-systems/examples.md +1238 -0
- moai_adk/templates/.claude/skills/moai-design-systems/reference.md +673 -0
- moai_adk/templates/.claude/skills/moai-domain-backend/SKILL.md +234 -43
- moai_adk/templates/.claude/skills/moai-domain-backend/examples.md +1633 -0
- moai_adk/templates/.claude/skills/moai-domain-backend/reference.md +660 -0
- moai_adk/templates/.claude/skills/moai-domain-cli-tool/SKILL.md +97 -69
- moai_adk/templates/.claude/skills/moai-domain-cli-tool/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-cli-tool/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-data-science/SKILL.md +97 -72
- moai_adk/templates/.claude/skills/moai-domain-data-science/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-data-science/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-database/SKILL.md +97 -74
- moai_adk/templates/.claude/skills/moai-domain-database/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-database/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-devops/SKILL.md +98 -74
- moai_adk/templates/.claude/skills/moai-domain-devops/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-devops/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/SKILL.md +102 -73
- moai_adk/templates/.claude/skills/moai-domain-frontend/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-domain-ml/SKILL.md +97 -73
- moai_adk/templates/.claude/skills/moai-domain-ml/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-ml/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-mobile-app/SKILL.md +97 -67
- moai_adk/templates/.claude/skills/moai-domain-mobile-app/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-mobile-app/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-security/SKILL.md +97 -79
- moai_adk/templates/.claude/skills/moai-domain-security/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-security/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-web-api/SKILL.md +97 -71
- moai_adk/templates/.claude/skills/moai-domain-web-api/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-web-api/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-essentials-debug/SKILL.md +265 -64
- moai_adk/templates/.claude/skills/moai-essentials-debug/examples.md +1064 -0
- moai_adk/templates/.claude/skills/moai-essentials-debug/reference.md +1047 -0
- moai_adk/templates/.claude/skills/moai-essentials-perf/SKILL.md +87 -78
- moai_adk/templates/.claude/skills/moai-essentials-perf/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-essentials-perf/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-essentials-refactor/SKILL.md +87 -70
- moai_adk/templates/.claude/skills/moai-essentials-refactor/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-essentials-refactor/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-essentials-review/SKILL.md +87 -86
- moai_adk/templates/.claude/skills/moai-essentials-review/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-essentials-review/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-ears/SKILL.md +80 -62
- moai_adk/templates/.claude/skills/moai-foundation-ears/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-ears/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-git/SKILL.md +207 -50
- moai_adk/templates/.claude/skills/moai-foundation-git/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-git/reference.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-langs/SKILL.md +90 -71
- moai_adk/templates/.claude/skills/moai-foundation-langs/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-langs/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-specs/SKILL.md +78 -58
- moai_adk/templates/.claude/skills/moai-foundation-specs/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-specs/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-tags/SKILL.md +78 -51
- moai_adk/templates/.claude/skills/moai-foundation-tags/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-tags/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-trust/.!11330!examples.md +0 -0
- moai_adk/templates/.claude/skills/moai-foundation-trust/SKILL.md +253 -32
- moai_adk/templates/.claude/skills/moai-foundation-trust/examples.md +0 -0
- moai_adk/templates/.claude/skills/moai-foundation-trust/reference.md +1099 -0
- moai_adk/templates/.claude/skills/moai-jit-docs-enhanced/SKILL.md +460 -0
- moai_adk/templates/.claude/skills/moai-lang-c/SKILL.md +98 -74
- moai_adk/templates/.claude/skills/moai-lang-c/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-c/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-cpp/SKILL.md +98 -76
- moai_adk/templates/.claude/skills/moai-lang-cpp/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-cpp/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/SKILL.md +2358 -70
- moai_adk/templates/.claude/skills/moai-lang-csharp/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-dart/SKILL.md +2962 -68
- moai_adk/templates/.claude/skills/moai-lang-dart/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-dart/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-go/SKILL.md +1898 -70
- moai_adk/templates/.claude/skills/moai-lang-go/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-go/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-java/SKILL.md +1465 -68
- moai_adk/templates/.claude/skills/moai-lang-java/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-java/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-javascript/SKILL.md +2364 -66
- moai_adk/templates/.claude/skills/moai-lang-javascript/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-javascript/reference.md +32 -0
- moai_adk/templates/.claude/skills/moai-lang-kotlin/SKILL.md +1630 -69
- moai_adk/templates/.claude/skills/moai-lang-kotlin/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-kotlin/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-php/SKILL.md +89 -61
- moai_adk/templates/.claude/skills/moai-lang-php/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-php/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-python/SKILL.md +735 -66
- moai_adk/templates/.claude/skills/moai-lang-python/examples.md +624 -0
- moai_adk/templates/.claude/skills/moai-lang-python/reference.md +316 -0
- moai_adk/templates/.claude/skills/moai-lang-r/SKILL.md +97 -73
- moai_adk/templates/.claude/skills/moai-lang-r/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-r/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-ruby/SKILL.md +98 -73
- moai_adk/templates/.claude/skills/moai-lang-ruby/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-ruby/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-rust/SKILL.md +1834 -70
- moai_adk/templates/.claude/skills/moai-lang-rust/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-rust/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-scala/SKILL.md +99 -74
- moai_adk/templates/.claude/skills/moai-lang-scala/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-scala/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-shell/SKILL.md +97 -74
- moai_adk/templates/.claude/skills/moai-lang-shell/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-shell/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-sql/SKILL.md +98 -74
- moai_adk/templates/.claude/skills/moai-lang-sql/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-sql/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-swift/SKILL.md +1959 -69
- moai_adk/templates/.claude/skills/moai-lang-swift/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-swift/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-template/SKILL.md +348 -0
- moai_adk/templates/.claude/skills/moai-lang-template/VARIABLES.md +98 -0
- moai_adk/templates/.claude/skills/moai-lang-typescript/SKILL.md +1230 -66
- moai_adk/templates/.claude/skills/moai-lang-typescript/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-typescript/reference.md +34 -0
- moai_adk/templates/.claude/skills/moai-learning-optimizer/SKILL.md +575 -0
- moai_adk/templates/.claude/skills/moai-project-batch-questions/README.md +50 -0
- moai_adk/templates/.claude/skills/moai-project-batch-questions/SKILL.md +304 -0
- moai_adk/templates/.claude/skills/moai-project-batch-questions/examples.md +417 -0
- moai_adk/templates/.claude/skills/moai-project-batch-questions/reference.md +704 -0
- moai_adk/templates/.claude/skills/moai-project-config-manager/README.md +87 -0
- moai_adk/templates/.claude/skills/moai-project-config-manager/SKILL.md +552 -0
- moai_adk/templates/.claude/skills/moai-project-config-manager/examples.md +1109 -0
- moai_adk/templates/.claude/skills/moai-project-config-manager/reference.md +514 -0
- moai_adk/templates/.claude/skills/moai-project-config-manager/validate.py +106 -0
- moai_adk/templates/.claude/skills/moai-project-documentation/README.md +11 -0
- moai_adk/templates/.claude/skills/moai-project-documentation/SKILL.md +622 -0
- moai_adk/templates/.claude/skills/moai-project-documentation/examples.md +20 -0
- moai_adk/templates/.claude/skills/moai-project-documentation/reference.md +12 -0
- moai_adk/templates/.claude/skills/moai-project-language-initializer/README.md +152 -0
- moai_adk/templates/.claude/skills/moai-project-language-initializer/SKILL.md +285 -0
- moai_adk/templates/.claude/skills/moai-project-language-initializer/examples.md +333 -0
- moai_adk/templates/.claude/skills/moai-project-language-initializer/reference.md +386 -0
- moai_adk/templates/.claude/skills/moai-project-template-optimizer/README.md +49 -0
- moai_adk/templates/.claude/skills/moai-project-template-optimizer/SKILL.md +319 -0
- moai_adk/templates/.claude/skills/moai-project-template-optimizer/examples.md +58 -0
- moai_adk/templates/.claude/skills/moai-project-template-optimizer/reference.md +123 -0
- moai_adk/templates/.claude/skills/moai-session-info/SKILL.md +314 -0
- moai_adk/templates/.claude/skills/moai-streaming-ui/SKILL.md +552 -0
- moai_adk/templates/.claude/skills/moai-tag-policy-validator/SKILL.md +570 -0
- moai_adk/templates/.git-hooks/pre-commit +66 -0
- moai_adk/templates/.git-hooks/pre-push +255 -0
- moai_adk/templates/.github/workflows/c-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/cpp-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/csharp-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/dart-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/go-tag-validation.yml +130 -0
- moai_adk/templates/.github/workflows/java-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/javascript-tag-validation.yml +135 -0
- moai_adk/templates/.github/workflows/kotlin-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/moai-gitflow.yml +166 -3
- moai_adk/templates/.github/workflows/moai-release-create.yml +100 -0
- moai_adk/templates/.github/workflows/moai-release-pipeline.yml +188 -0
- moai_adk/templates/.github/workflows/php-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/python-tag-validation.yml +118 -0
- moai_adk/templates/.github/workflows/release.yml +118 -0
- moai_adk/templates/.github/workflows/ruby-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/rust-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/shell-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/spec-issue-sync.yml +338 -0
- moai_adk/templates/.github/workflows/swift-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/tag-report.yml +269 -0
- moai_adk/templates/.github/workflows/tag-validation.yml +186 -0
- moai_adk/templates/.github/workflows/typescript-tag-validation.yml +154 -0
- moai_adk/templates/.mcp.json +31 -0
- moai_adk/templates/.moai/config.json +80 -7
- moai_adk/templates/CLAUDE.md +562 -546
- moai_adk/utils/banner.py +5 -5
- moai_adk/utils/common.py +294 -0
- moai_adk/utils/link_validator.py +235 -0
- moai_adk/utils/logger.py +8 -8
- moai_adk/utils/user_experience.py +451 -0
- moai_adk-0.20.1.dist-info/METADATA +233 -0
- moai_adk-0.20.1.dist-info/RECORD +404 -0
- moai_adk/templates/.claude/hooks/alfred/README.md +0 -230
- moai_adk/templates/.claude/hooks/alfred/alfred_hooks.py +0 -156
- moai_adk/templates/.claude/hooks/alfred/core/__init__.py +0 -85
- moai_adk/templates/.claude/hooks/alfred/handlers/notification.py +0 -25
- moai_adk/templates/.claude/hooks/alfred/handlers/session.py +0 -92
- moai_adk/templates/.claude/hooks/alfred/handlers/tool.py +0 -70
- moai_adk/templates/.claude/hooks/alfred/handlers/user.py +0 -41
- moai_adk/templates/.claude/output-styles/alfred/agentic-coding.md +0 -636
- moai_adk/templates/.claude/output-styles/alfred/moai-adk-learning.md +0 -692
- moai_adk/templates/.claude/output-styles/alfred/study-with-alfred.md +0 -470
- moai_adk/templates/.claude/skills/moai-alfred-debugger-pro/SKILL.md +0 -103
- moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/SKILL.md +0 -103
- moai_adk/templates/.claude/skills/moai-alfred-git-workflow/SKILL.md +0 -95
- moai_adk/templates/.claude/skills/moai-alfred-performance-optimizer/SKILL.md +0 -105
- moai_adk/templates/.claude/skills/moai-alfred-refactoring-coach/SKILL.md +0 -97
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/SKILL.md +0 -97
- moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/SKILL.md +0 -90
- moai_adk/templates/.claude/skills/moai-alfred-trust-validation/SKILL.md +0 -99
- moai_adk/templates/.claude/skills/moai-alfred-tui-survey/SKILL.md +0 -87
- moai_adk/templates/.claude/skills/moai-alfred-tui-survey/examples.md +0 -62
- moai_adk/templates/.claude/skills/moai-claude-code/SKILL.md +0 -94
- moai_adk/templates/.claude/skills/moai-claude-code/examples.md +0 -513
- moai_adk/templates/.claude/skills/moai-claude-code/reference.md +0 -433
- moai_adk/templates/.claude/skills/moai-claude-code/templates/agent-full.md +0 -332
- moai_adk/templates/.claude/skills/moai-claude-code/templates/command-full.md +0 -384
- moai_adk/templates/.claude/skills/moai-claude-code/templates/plugin-full.json +0 -363
- moai_adk/templates/.claude/skills/moai-claude-code/templates/settings-full.json +0 -595
- moai_adk/templates/.claude/skills/moai-claude-code/templates/skill-full.md +0 -496
- moai_adk/templates/.claude/skills/moai-lang-clojure/SKILL.md +0 -100
- moai_adk/templates/.claude/skills/moai-lang-elixir/SKILL.md +0 -99
- moai_adk/templates/.claude/skills/moai-lang-haskell/SKILL.md +0 -100
- moai_adk/templates/.claude/skills/moai-lang-julia/SKILL.md +0 -98
- moai_adk/templates/.claude/skills/moai-lang-lua/SKILL.md +0 -98
- moai_adk/templates/.github/PULL_REQUEST_TEMPLATE.md +0 -69
- moai_adk/templates/.moai/memory/development-guide.md +0 -344
- moai_adk/templates/.moai/memory/gitflow-protection-policy.md +0 -220
- moai_adk/templates/.moai/memory/spec-metadata.md +0 -356
- moai_adk/templates/.moai/project/product.md +0 -161
- moai_adk/templates/.moai/project/structure.md +0 -156
- moai_adk/templates/.moai/project/tech.md +0 -227
- moai_adk/templates/__init__.py +0 -2
- moai_adk-0.4.5.dist-info/METADATA +0 -369
- moai_adk-0.4.5.dist-info/RECORD +0 -152
- {moai_adk-0.4.5.dist-info → moai_adk-0.20.1.dist-info}/WHEEL +0 -0
- {moai_adk-0.4.5.dist-info → moai_adk-0.20.1.dist-info}/entry_points.txt +0 -0
- {moai_adk-0.4.5.dist-info → moai_adk-0.20.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,3604 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: awesome:release-new
|
|
3
|
+
description: 패키지 배포 및 GitHub 릴리즈 자동화
|
|
4
|
+
argument-hint: "[patch|minor|major] [--dry-run] [--testpypi] - 버전 타입, --dry-run으로 시뮬레이션, --testpypi로 테스트 배포"
|
|
5
|
+
tools: Read, Write, Edit, Bash(git:*), Bash(gh:*), Bash(python:*), Bash(uv:*), Task
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# 🚀 Awesome Release Automation (Python)
|
|
9
|
+
|
|
10
|
+
**Python 패키지 릴리즈 자동화 커맨드** - pyproject.toml 기반, PyPI 배포
|
|
11
|
+
|
|
12
|
+
**버전 관리 방식**: SSOT (Single Source of Truth)
|
|
13
|
+
- ✅ 버전은 `pyproject.toml` 한 곳에만 존재
|
|
14
|
+
- ✅ `__init__.py`는 `importlib.metadata`로 자동 로드
|
|
15
|
+
- ✅ 버전 업데이트는 `pyproject.toml`만 수정
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 🎯 커맨드 목적
|
|
20
|
+
|
|
21
|
+
Python 패키지의 릴리즈 프로세스를 완전 자동화:
|
|
22
|
+
1. **품질 검증** (pytest, ruff, mypy, 보안 스캔)
|
|
23
|
+
2. **버전 업데이트** (pyproject.toml만, SSOT 방식)
|
|
24
|
+
3. Git 커밋 및 태그 생성
|
|
25
|
+
4. PyPI 배포 (uv publish 또는 twine)
|
|
26
|
+
5. GitHub Release 생성 (자동)
|
|
27
|
+
|
|
28
|
+
**인수**: `$ARGUMENTS` (예: `patch`, `minor`, `major`, `--dry-run`)
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## ⚙️ Dry-Run 모드 가이드
|
|
33
|
+
|
|
34
|
+
**Dry-Run 모드**는 릴리즈 프로세스를 **시뮬레이션만 수행**하고 실제 변경은 하지 않습니다.
|
|
35
|
+
|
|
36
|
+
### 사용 방법
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# 기본 사용
|
|
40
|
+
/awesome:release-new [patch|minor|major] --dry-run
|
|
41
|
+
|
|
42
|
+
# 예시
|
|
43
|
+
/awesome:release-new minor --dry-run # 시뮬레이션: minor 버전 릴리즈
|
|
44
|
+
/awesome:release-new patch --dry-run # 시뮬레이션: patch 버전 릴리즈
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Dry-Run 모드에서 수행되는 작업
|
|
48
|
+
|
|
49
|
+
✅ **실제 실행 (변경 없음)**:
|
|
50
|
+
- 품질 검증 (Phase 0): pytest, ruff, mypy, bandit, pip-audit 실행
|
|
51
|
+
- 버전 계산 및 분석
|
|
52
|
+
- Git 로그 분석
|
|
53
|
+
- 릴리즈 계획 보고서 생성
|
|
54
|
+
- 변경사항 요약
|
|
55
|
+
|
|
56
|
+
❌ **실제 실행 안 함 (시뮬레이션만)**:
|
|
57
|
+
- ~~파일 수정 (pyproject.toml)~~
|
|
58
|
+
- ~~Git 커밋 생성~~
|
|
59
|
+
- ~~Git 태그 생성~~
|
|
60
|
+
- ~~GitHub PR 생성~~
|
|
61
|
+
- ~~GitHub Release 생성~~
|
|
62
|
+
- ~~PyPI 배포~~
|
|
63
|
+
|
|
64
|
+
### Dry-Run 결과 리포트
|
|
65
|
+
|
|
66
|
+
Dry-Run 모드 완료 시, 다음과 같은 시뮬레이션 리포트를 출력합니다:
|
|
67
|
+
|
|
68
|
+
```markdown
|
|
69
|
+
🔬 Dry-Run 시뮬레이션 완료 (실제 변경 없음)
|
|
70
|
+
|
|
71
|
+
📊 시뮬레이션 계획:
|
|
72
|
+
|
|
73
|
+
Phase 1: 버전 분석
|
|
74
|
+
- ✅ 현재 버전: v0.13.0
|
|
75
|
+
- ✅ 목표 버전: v0.13.1 (patch)
|
|
76
|
+
- ✅ 변경사항: 5개 커밋 (3 fix, 2 docs)
|
|
77
|
+
|
|
78
|
+
Phase 2: GitFlow PR 병합
|
|
79
|
+
- ✅ develop → main PR 생성 (Draft)
|
|
80
|
+
- ✅ PR Ready for Review로 전환
|
|
81
|
+
- ✅ GitHub에서 병합 (대기)
|
|
82
|
+
|
|
83
|
+
Phase 3: GitHub Actions 자동 릴리즈
|
|
84
|
+
- ✅ Git 태그 생성: v0.13.1
|
|
85
|
+
- ✅ GitHub Release 생성: v0.13.1
|
|
86
|
+
- ✅ PyPI 배포 시작 (자동)
|
|
87
|
+
|
|
88
|
+
🎯 실제 릴리즈 명령:
|
|
89
|
+
/awesome:release-new patch
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### 실제 릴리즈 실행
|
|
93
|
+
|
|
94
|
+
Dry-Run 결과가 만족스러우면, `--dry-run` 플래그를 제외하고 실행하세요:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Dry-Run 먼저 확인
|
|
98
|
+
/awesome:release-new minor --dry-run
|
|
99
|
+
|
|
100
|
+
# 결과가 좋으면 실제 릴리즈 실행
|
|
101
|
+
/awesome:release-new minor
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 📋 릴리즈 정보 포맷 표준화
|
|
107
|
+
|
|
108
|
+
릴리즈 정보는 일관된 형식으로 제공되어야 합니다. 모든 릴리즈는 다음 표준을 따릅니다.
|
|
109
|
+
|
|
110
|
+
### 릴리즈 정보 구성 (영어 & 한국어)
|
|
111
|
+
|
|
112
|
+
모든 릴리즈는 **영어와 한국어** 두 언어로 작성되어야 합니다.
|
|
113
|
+
|
|
114
|
+
**구성 순서**:
|
|
115
|
+
1. 🚀 Major Features (주요 기능) - 영어/한국어
|
|
116
|
+
2. 📊 Release Statistics (릴리즈 통계)
|
|
117
|
+
3. 🧪 Quality Assurance (품질 보증)
|
|
118
|
+
4. 💻 Installation Guide (설치 가이드) - **uv tool 중심**
|
|
119
|
+
5. 🔗 Documentation (문서)
|
|
120
|
+
6. 🔄 Migration & Compatibility (호환성)
|
|
121
|
+
7. 👏 Credits (크레딧)
|
|
122
|
+
|
|
123
|
+
### 설치 가이드 표준 형식
|
|
124
|
+
|
|
125
|
+
#### ✅ 추천 방식: uv tool (CLI 도구)
|
|
126
|
+
|
|
127
|
+
```markdown
|
|
128
|
+
### 🎯 Recommended: CLI Tool Usage
|
|
129
|
+
|
|
130
|
+
Use `uv tool` to install moai-adk as a standalone command-line tool (recommended):
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# Install as CLI tool
|
|
134
|
+
uv tool install moai-adk==X.Y.Z
|
|
135
|
+
|
|
136
|
+
# Verify installation
|
|
137
|
+
moai-adk --version
|
|
138
|
+
|
|
139
|
+
# Use as CLI command
|
|
140
|
+
moai-adk /alfred:1-plan "새 기능"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Advantages**:
|
|
144
|
+
- ✅ Works anywhere (global command)
|
|
145
|
+
- ✅ Isolated environment (no conflicts)
|
|
146
|
+
- ✅ Easy to update: `uv tool upgrade moai-adk`
|
|
147
|
+
- ✅ Recommended for most users
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### 대체 방식 1: Python 라이브러리 (pip)
|
|
151
|
+
|
|
152
|
+
```markdown
|
|
153
|
+
### 📚 Alternative: Python Library
|
|
154
|
+
|
|
155
|
+
If you need to use moai-adk as a Python library in your project:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
# Install with pip (standard)
|
|
159
|
+
pip install moai-adk==X.Y.Z
|
|
160
|
+
|
|
161
|
+
# Use in Python code
|
|
162
|
+
from moai_adk import Alfred
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Use this if**:
|
|
166
|
+
- You're building on top of moai-adk
|
|
167
|
+
- You need to import moai-adk in your Python code
|
|
168
|
+
- You're managing it as a project dependency
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
#### 대체 방식 2: Python 라이브러리 (uv pip - 빠른 설치)
|
|
172
|
+
|
|
173
|
+
```markdown
|
|
174
|
+
# Or install with uv (faster)
|
|
175
|
+
uv pip install moai-adk==X.Y.Z
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### GitHub Release 기본 템플릿
|
|
179
|
+
|
|
180
|
+
```markdown
|
|
181
|
+
## 🚀 Major Features
|
|
182
|
+
|
|
183
|
+
### 1. [Feature Name]
|
|
184
|
+
[Feature description]
|
|
185
|
+
|
|
186
|
+
**Key Benefits**:
|
|
187
|
+
- Benefit 1
|
|
188
|
+
- Benefit 2
|
|
189
|
+
- Benefit 3
|
|
190
|
+
|
|
191
|
+
## 📊 Release Statistics
|
|
192
|
+
|
|
193
|
+
| Metric | Value |
|
|
194
|
+
|--------|-------|
|
|
195
|
+
| **Commits** | X since vX.Y.Z |
|
|
196
|
+
| **Files Changed** | X files |
|
|
197
|
+
| **Lines Added** | X |
|
|
198
|
+
| **Lines Removed** | X |
|
|
199
|
+
|
|
200
|
+
## 🧪 Quality Assurance
|
|
201
|
+
|
|
202
|
+
✅ **Testing**:
|
|
203
|
+
- X tests passed (Y% pass rate)
|
|
204
|
+
- Z tests skipped
|
|
205
|
+
- 0 test failures
|
|
206
|
+
|
|
207
|
+
✅ **Code Quality**:
|
|
208
|
+
- 0 security issues
|
|
209
|
+
- 0 type errors
|
|
210
|
+
- X minor linting issues (non-blocking)
|
|
211
|
+
|
|
212
|
+
## 💻 Installation Guide
|
|
213
|
+
|
|
214
|
+
### 🎯 Recommended: CLI Tool Usage
|
|
215
|
+
|
|
216
|
+
[See template above]
|
|
217
|
+
|
|
218
|
+
### 📚 Alternative: Python Library
|
|
219
|
+
|
|
220
|
+
[See template above]
|
|
221
|
+
|
|
222
|
+
## 🔄 Migration & Compatibility
|
|
223
|
+
|
|
224
|
+
**Breaking Changes**: [None/List]
|
|
225
|
+
**Deprecations**: [None/List]
|
|
226
|
+
**Migration Required**: [No/Yes with details]
|
|
227
|
+
**Backward Compatible**: ✅ Yes
|
|
228
|
+
|
|
229
|
+
## 👏 Credits
|
|
230
|
+
|
|
231
|
+
Released with Claude Code
|
|
232
|
+
|
|
233
|
+
Co-Authored-By: 🎩 Alfred@MoAI
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### 언어 규칙
|
|
237
|
+
|
|
238
|
+
| 항목 | 영어 | 한국어 | 예시 |
|
|
239
|
+
|------|------|--------|------|
|
|
240
|
+
| **Feature 제목** | 영어 | 선택 | "Multi-Language Translation" |
|
|
241
|
+
| **설명문** | 영어 + 한국어 혼합 | 괄호로 구분 | "Multi-Language Runtime Translation System (다국어 런타임 번역)" |
|
|
242
|
+
| **Installation** | 영어 (코드는 동일) | 코드만 표시 | 코드 블록은 언어 중립적 |
|
|
243
|
+
| **Benefits** | 영어 | 선택 옵션 | 영어로 주요 내용, 필요시 한국어 추가 |
|
|
244
|
+
| **표 헤더** | 영어 | 필요시 이중 제공 | "Metric \| Value" 또는 "항목 \| 값" |
|
|
245
|
+
|
|
246
|
+
### 예시: v0.16.0 포맷
|
|
247
|
+
|
|
248
|
+
**GitHub Release 예시**:
|
|
249
|
+
```markdown
|
|
250
|
+
## 🚀 Major Features
|
|
251
|
+
|
|
252
|
+
### 1. 🌐 Multi-Language Runtime Translation System
|
|
253
|
+
Single English source with unlimited language support via runtime translation.
|
|
254
|
+
(단일 영어 소스에서 무제한 언어 지원)
|
|
255
|
+
|
|
256
|
+
**Key Benefits**:
|
|
257
|
+
- Zero code modification for language support
|
|
258
|
+
- Unlimited language support (Korean, Japanese, Chinese, Spanish, etc.)
|
|
259
|
+
- Dynamic variable mapping for localization
|
|
260
|
+
- Consistent terminology across all languages
|
|
261
|
+
|
|
262
|
+
### 2. 🏗️ Master-Clone Pattern Architecture
|
|
263
|
+
...
|
|
264
|
+
|
|
265
|
+
## 💻 Installation Guide
|
|
266
|
+
|
|
267
|
+
### 🎯 Recommended: CLI Tool Usage
|
|
268
|
+
|
|
269
|
+
Use `uv tool` to install moai-adk as a standalone command-line tool (recommended):
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
uv tool install moai-adk==0.16.0
|
|
273
|
+
moai-adk --version
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### 📚 Alternative: Python Library
|
|
277
|
+
|
|
278
|
+
If you need to use moai-adk as a Python library:
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
pip install moai-adk==0.16.0
|
|
282
|
+
# or
|
|
283
|
+
uv pip install moai-adk==0.16.0
|
|
284
|
+
```
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### CHANGELOG.md 포맷
|
|
288
|
+
|
|
289
|
+
**CHANGELOG.md의 Installation 섹션**:
|
|
290
|
+
|
|
291
|
+
```markdown
|
|
292
|
+
### 💻 Installation
|
|
293
|
+
|
|
294
|
+
**Using uv tool** (recommended for CLI usage):
|
|
295
|
+
```bash
|
|
296
|
+
uv tool install moai-adk==X.Y.Z
|
|
297
|
+
moai-adk --version
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
**Using pip** (if you need Python library):
|
|
301
|
+
```bash
|
|
302
|
+
pip install moai-adk==X.Y.Z
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**Using uv pip** (faster Python library installation):
|
|
306
|
+
```bash
|
|
307
|
+
uv pip install moai-adk==X.Y.Z
|
|
308
|
+
```
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### 일관성 체크리스트
|
|
312
|
+
|
|
313
|
+
각 릴리즈 전에 다음 항목을 확인하세요:
|
|
314
|
+
|
|
315
|
+
- [ ] Feature 섹션: 3개 이상의 주요 기능 기술
|
|
316
|
+
- [ ] 각 Feature: 1-2 문장 설명 + Benefits 나열
|
|
317
|
+
- [ ] Installation: uv tool **먼저**, pip/uv pip는 **대체 방식**으로
|
|
318
|
+
- [ ] Quality: 테스트, 보안, 타입 체크, 커버리지 포함
|
|
319
|
+
- [ ] Statistics: 커밋, 파일, 라인 수 포함
|
|
320
|
+
- [ ] Migration: Breaking changes 명시
|
|
321
|
+
- [ ] Credits: Claude Code + Alfred 크레딧 포함
|
|
322
|
+
- [ ] Links: CHANGELOG, 문서 링크 포함
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## 🧪 TestPyPI 배포 (테스트 배포)
|
|
327
|
+
|
|
328
|
+
**TestPyPI**는 PyPI의 테스트 환경입니다. 실제 릴리즈 전에 패키지를 테스트 환경에 배포하여 검증할 수 있습니다.
|
|
329
|
+
|
|
330
|
+
### TestPyPI란?
|
|
331
|
+
|
|
332
|
+
- **목적**: 실제 사용자에게 영향을 주지 않고 패키지 배포를 테스트
|
|
333
|
+
- **URL**: https://test.pypi.org/
|
|
334
|
+
- **특징**:
|
|
335
|
+
- 실제 PyPI와 동일한 환경
|
|
336
|
+
- 실제 배포 전 검증용
|
|
337
|
+
- 테스트 패키지는 30일 후 자동 삭제
|
|
338
|
+
- 독립적인 패키지 저장소 (실제 PyPI와 분리)
|
|
339
|
+
|
|
340
|
+
### 사용 방법
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
# TestPyPI로 테스트 배포
|
|
344
|
+
/awesome:release-new minor --testpypi
|
|
345
|
+
|
|
346
|
+
# Dry-Run + TestPyPI 조합
|
|
347
|
+
/awesome:release-new minor --dry-run --testpypi
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### TestPyPI 배포 워크플로우
|
|
351
|
+
|
|
352
|
+
```
|
|
353
|
+
/awesome:release-new [version] --testpypi
|
|
354
|
+
↓
|
|
355
|
+
Phase 0: 품질 검증 (동일)
|
|
356
|
+
├─ pytest, ruff, mypy, bandit, pip-audit
|
|
357
|
+
↓
|
|
358
|
+
Phase 1: 버전 분석 (동일)
|
|
359
|
+
├─ 버전 계산, Git 로그 분석
|
|
360
|
+
↓
|
|
361
|
+
Phase 1.5: 릴리즈 계획 보고서 (수정됨)
|
|
362
|
+
├─ "PyPI 배포" → "TestPyPI 배포" 표시
|
|
363
|
+
↓
|
|
364
|
+
Phase 2: PR 관리 (생략됨)
|
|
365
|
+
├─ GitHub PR/Release 생성 안 함
|
|
366
|
+
↓
|
|
367
|
+
Phase 3: TestPyPI 배포 (수정됨)
|
|
368
|
+
├─ Git 태그 생성 안 함
|
|
369
|
+
├─ GitHub Release 생성 안 함
|
|
370
|
+
└─ TestPyPI에만 배포
|
|
371
|
+
↓
|
|
372
|
+
✅ TestPyPI 배포 완료
|
|
373
|
+
└─ 설치 테스트 링크 제공
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### TestPyPI 설정 (초기 설정 한 번만)
|
|
377
|
+
|
|
378
|
+
#### 1단계: TestPyPI 토큰 생성
|
|
379
|
+
|
|
380
|
+
https://test.pypi.org/manage/account/token/ 에서:
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
# PyPI 토큰 생성
|
|
384
|
+
# - Scope: "Entire account (all projects)"
|
|
385
|
+
# - 토큰 형식: pypi-AgEIcHlwaS5vcmcCJ...
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
#### 2단계: 로컬 환경 설정
|
|
389
|
+
|
|
390
|
+
```bash
|
|
391
|
+
# .pypirc 파일 생성 (~/.pypirc)
|
|
392
|
+
cat > ~/.pypirc << 'EOF'
|
|
393
|
+
[distutils]
|
|
394
|
+
index-servers =
|
|
395
|
+
pypi
|
|
396
|
+
testpypi
|
|
397
|
+
|
|
398
|
+
[pypi]
|
|
399
|
+
repository = https://upload.pypi.org/legacy/
|
|
400
|
+
username = __token__
|
|
401
|
+
password = pypi-AgEIcHlwaS5vcmcCJ...
|
|
402
|
+
|
|
403
|
+
[testpypi]
|
|
404
|
+
repository = https://test.pypi.org/legacy/
|
|
405
|
+
username = __token__
|
|
406
|
+
password = pypi-AgEIcHlwaS5vcmcCJ...
|
|
407
|
+
EOF
|
|
408
|
+
|
|
409
|
+
chmod 600 ~/.pypirc
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
또는 환경 변수 사용:
|
|
413
|
+
|
|
414
|
+
```bash
|
|
415
|
+
# ~/.bashrc 또는 ~/.zshrc에 추가
|
|
416
|
+
export UV_PUBLISH_TOKEN_TESTPYPI="pypi-AgEIcHlwaS5vcmcCJ..."
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### TestPyPI 배포 실행 단계
|
|
420
|
+
|
|
421
|
+
#### Step 1: 테스트 배포 실행
|
|
422
|
+
|
|
423
|
+
```bash
|
|
424
|
+
# TestPyPI로 배포
|
|
425
|
+
/awesome:release-new patch --testpypi
|
|
426
|
+
|
|
427
|
+
# 출력 예:
|
|
428
|
+
# 🧪 TestPyPI 배포 모드 활성화
|
|
429
|
+
# 📊 버전 정보: v0.13.1
|
|
430
|
+
# ✅ 품질 검증 통과
|
|
431
|
+
# 📤 TestPyPI에 배포 중...
|
|
432
|
+
# ✅ TestPyPI 배포 완료!
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
#### Step 2: TestPyPI에서 패키지 확인
|
|
436
|
+
|
|
437
|
+
```bash
|
|
438
|
+
# TestPyPI 프로젝트 페이지
|
|
439
|
+
https://test.pypi.org/project/moai-adk/0.13.1/
|
|
440
|
+
|
|
441
|
+
# 명령줄에서 확인
|
|
442
|
+
pip index versions moai-adk -i https://test.pypi.org/simple/
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
#### Step 3: TestPyPI에서 설치 테스트
|
|
446
|
+
|
|
447
|
+
```bash
|
|
448
|
+
# 임시 가상환경 생성
|
|
449
|
+
python -m venv /tmp/test_moai
|
|
450
|
+
source /tmp/test_moai/bin/activate
|
|
451
|
+
|
|
452
|
+
# TestPyPI에서 설치
|
|
453
|
+
pip install --index-url https://test.pypi.org/simple/ moai-adk==0.13.1
|
|
454
|
+
|
|
455
|
+
# 기본 테스트
|
|
456
|
+
moai-adk --version
|
|
457
|
+
|
|
458
|
+
# 테스트 완료 후 정리
|
|
459
|
+
deactivate
|
|
460
|
+
rm -rf /tmp/test_moai
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
#### Step 4: 테스트 완료 후 실제 배포
|
|
464
|
+
|
|
465
|
+
테스트가 만족스러우면 실제 PyPI에 배포:
|
|
466
|
+
|
|
467
|
+
```bash
|
|
468
|
+
# --testpypi 없이 실행
|
|
469
|
+
/awesome:release-new patch
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### TestPyPI 배포 예시
|
|
473
|
+
|
|
474
|
+
#### 예시 1: 신규 마이너 버전 테스트
|
|
475
|
+
|
|
476
|
+
```bash
|
|
477
|
+
# v0.14.0 테스트 배포
|
|
478
|
+
/awesome:release-new minor --testpypi
|
|
479
|
+
|
|
480
|
+
# TestPyPI에서 확인
|
|
481
|
+
pip install --index-url https://test.pypi.org/simple/ moai-adk==0.14.0
|
|
482
|
+
|
|
483
|
+
# 테스트 완료 후 실제 배포
|
|
484
|
+
/awesome:release-new minor
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
#### 예시 2: 긴급 패치 검증
|
|
488
|
+
|
|
489
|
+
```bash
|
|
490
|
+
# 긴급 패치 미리 테스트
|
|
491
|
+
/awesome:release-new patch --testpypi
|
|
492
|
+
|
|
493
|
+
# TestPyPI에서 설치 및 테스트
|
|
494
|
+
pip install --index-url https://test.pypi.org/simple/ moai-adk==0.13.1
|
|
495
|
+
|
|
496
|
+
# 문제 없으면 실제 배포
|
|
497
|
+
/awesome:release-new patch
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
#### 예시 3: Dry-Run + TestPyPI 조합
|
|
501
|
+
|
|
502
|
+
```bash
|
|
503
|
+
# 먼저 시뮬레이션
|
|
504
|
+
/awesome:release-new minor --dry-run
|
|
505
|
+
|
|
506
|
+
# 그 다음 TestPyPI로 테스트
|
|
507
|
+
/awesome:release-new minor --testpypi
|
|
508
|
+
|
|
509
|
+
# 최종 실제 배포
|
|
510
|
+
/awesome:release-new minor
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
### TestPyPI 배포 시 주의사항
|
|
514
|
+
|
|
515
|
+
#### ✅ TestPyPI 배포의 장점
|
|
516
|
+
|
|
517
|
+
- 실제 배포 전 검증 가능
|
|
518
|
+
- 다른 사용자에게 영향 없음
|
|
519
|
+
- 패키지 메타데이터 확인 가능
|
|
520
|
+
- 설치 테스트로 의존성 확인 가능
|
|
521
|
+
|
|
522
|
+
#### ⚠️ TestPyPI 배포 시 주의사항
|
|
523
|
+
|
|
524
|
+
- **GitHub PR/Release 생성 안 함**: TestPyPI 배포는 develop 브랜치용 (main 병합 안 함)
|
|
525
|
+
- **Git 태그 생성 안 함**: 테스트 버전이므로 정식 태그 생성 안 함
|
|
526
|
+
- **PyPI에는 배포 안 함**: TestPyPI에만 배포 (main 배포 안 함)
|
|
527
|
+
- **일반 사용자에게 공개 안 함**: TestPyPI 패키지는 비공개 상태
|
|
528
|
+
- **토큰 관리**: TestPyPI 토큰은 별도로 관리 필수
|
|
529
|
+
|
|
530
|
+
### TestPyPI 트러블슈팅
|
|
531
|
+
|
|
532
|
+
#### Q: TestPyPI 토큰이 작동하지 않습니다
|
|
533
|
+
|
|
534
|
+
**A**: 토큰 형식 확인:
|
|
535
|
+
|
|
536
|
+
```bash
|
|
537
|
+
# 토큰은 반드시 "pypi-" 접두사로 시작
|
|
538
|
+
echo $UV_PUBLISH_TOKEN_TESTPYPI
|
|
539
|
+
# 출력: pypi-AgEIcHlwaS5vcmcCJ...
|
|
540
|
+
|
|
541
|
+
# 만료된 토큰인 경우 새로 생성
|
|
542
|
+
# https://test.pypi.org/manage/account/token/
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
#### Q: TestPyPI에 배포했는데 설치가 안 됩니다
|
|
546
|
+
|
|
547
|
+
**A**: 인덱스 URL 확인:
|
|
548
|
+
|
|
549
|
+
```bash
|
|
550
|
+
# TestPyPI 인덱스 URL 정확하게
|
|
551
|
+
pip install --index-url https://test.pypi.org/simple/ moai-adk==VERSION
|
|
552
|
+
|
|
553
|
+
# 또는 .pip/pip.conf 확인
|
|
554
|
+
cat ~/.config/pip/pip.conf
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
#### Q: TestPyPI에 배포된 패키지를 삭제하고 싶습니다
|
|
558
|
+
|
|
559
|
+
**A**: TestPyPI 웹에서 Yank 수행:
|
|
560
|
+
|
|
561
|
+
```
|
|
562
|
+
https://test.pypi.org/project/moai-adk/0.13.1/
|
|
563
|
+
→ "Release History" → "Yank this version"
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
## 📋 실행 흐름
|
|
569
|
+
|
|
570
|
+
## 🔧 파라미터 처리 및 Dry-Run 모드 초기화
|
|
571
|
+
|
|
572
|
+
### 파라미터 파싱
|
|
573
|
+
|
|
574
|
+
```bash
|
|
575
|
+
# 인수 처리
|
|
576
|
+
# $ARGUMENTS에서 version_type, dry_run, testpypi 플래그 분리
|
|
577
|
+
|
|
578
|
+
# 기본값
|
|
579
|
+
VERSION_TYPE="patch"
|
|
580
|
+
DRY_RUN=false
|
|
581
|
+
TEST_PYPI=false
|
|
582
|
+
|
|
583
|
+
# 인수 파싱
|
|
584
|
+
for arg in $ARGUMENTS; do
|
|
585
|
+
case "$arg" in
|
|
586
|
+
patch|minor|major)
|
|
587
|
+
VERSION_TYPE="$arg"
|
|
588
|
+
;;
|
|
589
|
+
--dry-run)
|
|
590
|
+
DRY_RUN=true
|
|
591
|
+
;;
|
|
592
|
+
--testpypi)
|
|
593
|
+
TEST_PYPI=true
|
|
594
|
+
;;
|
|
595
|
+
*)
|
|
596
|
+
echo "⚠️ 알 수 없는 인수: $arg"
|
|
597
|
+
echo "사용법: /awesome:release-new [patch|minor|major] [--dry-run] [--testpypi]"
|
|
598
|
+
exit 1
|
|
599
|
+
;;
|
|
600
|
+
esac
|
|
601
|
+
done
|
|
602
|
+
|
|
603
|
+
# Dry-Run과 TestPyPI 동시 지정 확인
|
|
604
|
+
if [ "$DRY_RUN" = "true" ] && [ "$TEST_PYPI" = "true" ]; then
|
|
605
|
+
echo "ℹ️ Dry-Run + TestPyPI 모드"
|
|
606
|
+
echo " 버전 분석은 수행하지만, TestPyPI 배포는 시뮬레이션만 합니다"
|
|
607
|
+
fi
|
|
608
|
+
|
|
609
|
+
# 설정 출력
|
|
610
|
+
echo "🚀 릴리즈 설정:"
|
|
611
|
+
echo " - 버전 타입: $VERSION_TYPE"
|
|
612
|
+
|
|
613
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
614
|
+
echo " - 모드: 🔬 Dry-Run (시뮬레이션)"
|
|
615
|
+
else
|
|
616
|
+
echo " - 모드: 실제 릴리즈"
|
|
617
|
+
fi
|
|
618
|
+
|
|
619
|
+
if [ "$TEST_PYPI" = "true" ]; then
|
|
620
|
+
echo " - 배포 대상: 🧪 TestPyPI (테스트 환경)"
|
|
621
|
+
else
|
|
622
|
+
echo " - 배포 대상: PyPI (프로덕션)"
|
|
623
|
+
fi
|
|
624
|
+
|
|
625
|
+
echo ""
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### Dry-Run 모드 함수 정의
|
|
629
|
+
|
|
630
|
+
Dry-Run 모드에서는 실제 파일/Git 수정을 방지하기 위해 래퍼 함수를 사용합니다:
|
|
631
|
+
|
|
632
|
+
```bash
|
|
633
|
+
# Git 커밋 래퍼 (dry-run 모드에서는 로깅만)
|
|
634
|
+
git_commit_if_needed() {
|
|
635
|
+
local message="$1"
|
|
636
|
+
|
|
637
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
638
|
+
echo " [DRY-RUN] Git 커밋 예정: $message"
|
|
639
|
+
else
|
|
640
|
+
git add -A
|
|
641
|
+
git commit -m "$message"
|
|
642
|
+
fi
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
# Git 태그 래퍼 (dry-run 모드에서는 로깅만)
|
|
646
|
+
git_tag_if_needed() {
|
|
647
|
+
local tag="$1"
|
|
648
|
+
local message="$2"
|
|
649
|
+
|
|
650
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
651
|
+
echo " [DRY-RUN] Git 태그 예정: $tag - $message"
|
|
652
|
+
else
|
|
653
|
+
git tag -a "$tag" -m "$message"
|
|
654
|
+
git push origin "$tag"
|
|
655
|
+
fi
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
# GitHub PR 생성 래퍼 (dry-run 모드에서는 로깅만)
|
|
659
|
+
gh_pr_create_if_needed() {
|
|
660
|
+
local title="$1"
|
|
661
|
+
local body="$2"
|
|
662
|
+
|
|
663
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
664
|
+
echo " [DRY-RUN] GitHub PR 생성 예정: $title"
|
|
665
|
+
else
|
|
666
|
+
gh pr create --title "$title" --body "$body" --draft
|
|
667
|
+
fi
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
# 파일 수정 래퍼 (dry-run 모드에서는 로깅만)
|
|
671
|
+
file_modify_if_needed() {
|
|
672
|
+
local file="$1"
|
|
673
|
+
local new_value="$2"
|
|
674
|
+
|
|
675
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
676
|
+
echo " [DRY-RUN] 파일 수정 예정: $file"
|
|
677
|
+
else
|
|
678
|
+
# 실제 파일 수정 로직
|
|
679
|
+
# sed, cat 등을 사용하여 파일 수정
|
|
680
|
+
echo "$new_value" > "$file"
|
|
681
|
+
fi
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
# PyPI 배포 래퍼 (TestPyPI vs 실제 PyPI)
|
|
685
|
+
pypi_publish_if_needed() {
|
|
686
|
+
local version="$1"
|
|
687
|
+
|
|
688
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
689
|
+
if [ "$TEST_PYPI" = "true" ]; then
|
|
690
|
+
echo " [DRY-RUN] TestPyPI 배포 예정: moai-adk==$version"
|
|
691
|
+
else
|
|
692
|
+
echo " [DRY-RUN] PyPI 배포 예정: moai-adk==$version"
|
|
693
|
+
fi
|
|
694
|
+
else
|
|
695
|
+
if [ "$TEST_PYPI" = "true" ]; then
|
|
696
|
+
echo "📤 TestPyPI에 배포 중..."
|
|
697
|
+
uv publish --publish-url https://test.pypi.org/legacy/
|
|
698
|
+
echo "✅ TestPyPI 배포 완료!"
|
|
699
|
+
echo "🔗 TestPyPI 프로젝트: https://test.pypi.org/project/moai-adk/$version/"
|
|
700
|
+
echo "📦 설치 테스트: pip install --index-url https://test.pypi.org/simple/ moai-adk==$version"
|
|
701
|
+
else
|
|
702
|
+
echo "📤 PyPI에 배포 중..."
|
|
703
|
+
uv publish
|
|
704
|
+
echo "✅ PyPI 배포 완료!"
|
|
705
|
+
echo "🔗 PyPI 프로젝트: https://pypi.org/project/moai-adk/$version/"
|
|
706
|
+
fi
|
|
707
|
+
fi
|
|
708
|
+
}
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
### Dry-Run 요약 수집
|
|
712
|
+
|
|
713
|
+
Dry-Run 모드에서 수행될 모든 작업을 수집하여 마지막에 요약 보고서를 생성합니다:
|
|
714
|
+
|
|
715
|
+
```bash
|
|
716
|
+
# Dry-Run 작업 로그 파일
|
|
717
|
+
DRY_RUN_ACTIONS="/tmp/dry_run_actions_$$.log"
|
|
718
|
+
|
|
719
|
+
# Dry-Run 작업 기록
|
|
720
|
+
log_dry_run_action() {
|
|
721
|
+
local action="$1"
|
|
722
|
+
echo "[$(date '+%H:%M:%S')] $action" >> "$DRY_RUN_ACTIONS"
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
# Dry-Run 작업 요약 출력
|
|
726
|
+
print_dry_run_summary() {
|
|
727
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
728
|
+
echo ""
|
|
729
|
+
echo "================================"
|
|
730
|
+
|
|
731
|
+
if [ "$TEST_PYPI" = "true" ]; then
|
|
732
|
+
echo "🔬 Dry-Run + 🧪 TestPyPI 시뮬레이션 완료"
|
|
733
|
+
else
|
|
734
|
+
echo "🔬 Dry-Run 시뮬레이션 완료"
|
|
735
|
+
fi
|
|
736
|
+
|
|
737
|
+
echo "================================"
|
|
738
|
+
echo ""
|
|
739
|
+
echo "예정된 작업 목록:"
|
|
740
|
+
if [ -f "$DRY_RUN_ACTIONS" ]; then
|
|
741
|
+
cat "$DRY_RUN_ACTIONS"
|
|
742
|
+
fi
|
|
743
|
+
echo ""
|
|
744
|
+
echo "⚠️ 위의 작업들은 시뮬레이션만 수행되었으며, 실제로 적용되지 않았습니다."
|
|
745
|
+
echo ""
|
|
746
|
+
|
|
747
|
+
if [ "$TEST_PYPI" = "true" ]; then
|
|
748
|
+
echo "TestPyPI 배포를 진행하려면 다음 명령을 실행하세요:"
|
|
749
|
+
echo "/awesome:release-new $VERSION_TYPE --testpypi"
|
|
750
|
+
echo ""
|
|
751
|
+
echo "또는 실제 PyPI 배포를 진행하려면:"
|
|
752
|
+
echo "/awesome:release-new $VERSION_TYPE"
|
|
753
|
+
else
|
|
754
|
+
echo "실제 릴리즈를 진행하려면 다음 명령을 실행하세요:"
|
|
755
|
+
echo "/awesome:release-new $VERSION_TYPE"
|
|
756
|
+
fi
|
|
757
|
+
|
|
758
|
+
echo ""
|
|
759
|
+
|
|
760
|
+
# 정리
|
|
761
|
+
rm -f "$DRY_RUN_ACTIONS"
|
|
762
|
+
exit 0
|
|
763
|
+
fi
|
|
764
|
+
}
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
---
|
|
768
|
+
|
|
769
|
+
### Phase 0: 품질 검증 (자동, 필수)
|
|
770
|
+
1. 테스트 실행 및 커버리지 검증 (`pytest --cov`)
|
|
771
|
+
2. 린트 검사 (`ruff check`)
|
|
772
|
+
3. 타입 체크 (`mypy`)
|
|
773
|
+
4. 보안 스캔 (`bandit`, `pip-audit`)
|
|
774
|
+
|
|
775
|
+
**검증 실패 시**: 릴리즈 중단, 문제 해결 후 재시도
|
|
776
|
+
|
|
777
|
+
**🔬 Dry-Run 모드에서**: Phase 0은 **실제 실행**됩니다 (품질 검증은 항상 수행되어야 하므로)
|
|
778
|
+
- Dry-Run 모드에서도 테스트, 린트, 타입, 보안 검사를 모두 실행합니다
|
|
779
|
+
- 검증 실패 시 Dry-Run도 중단됩니다
|
|
780
|
+
|
|
781
|
+
### Phase 1: 버전 분석 및 검증
|
|
782
|
+
1. 현재 프로젝트 버전 확인 (pyproject.toml, __init__.py)
|
|
783
|
+
2. 목표 버전 결정 (인수 또는 자동 증가)
|
|
784
|
+
3. Git 상태 확인 (커밋 가능 여부)
|
|
785
|
+
4. 변경사항 요약
|
|
786
|
+
|
|
787
|
+
### Phase 1.5: 사용자 확인
|
|
788
|
+
- **릴리즈 계획 보고서** 생성 및 승인 대기
|
|
789
|
+
- 사용자 응답: "진행" / "수정 [내용]" / "중단"
|
|
790
|
+
|
|
791
|
+
### Phase 2: GitFlow PR 병합 (develop → main)
|
|
792
|
+
**📋 워크플로우:**
|
|
793
|
+
1. develop 브랜치 확인 (release는 develop에서 시작)
|
|
794
|
+
2. main 브랜치 최신화 (git fetch origin main:main)
|
|
795
|
+
3. GitHub PR 생성 (develop → main, Draft 상태)
|
|
796
|
+
4. PR을 Ready for Review로 전환
|
|
797
|
+
5. **CodeRabbit AI 자동 리뷰 완료** (품질 80% 이상 자동 승인)
|
|
798
|
+
6. **GitHub에서 PR 병합** (로컬이 아닌 GitHub 웹에서 병합)
|
|
799
|
+
|
|
800
|
+
⚠️ **중요**: PR 병합은 **GitHub 웹 인터페이스에서만** 수행합니다. 로컬에서 직접 push를 하면 안 됩니다.
|
|
801
|
+
|
|
802
|
+
### Phase 3: GitHub Actions 자동 릴리즈 (CI/CD 자동화)
|
|
803
|
+
**⚠️ CRITICAL**: Phase 3은 이제 모두 **GitHub Actions**에서 자동으로 처리됩니다!
|
|
804
|
+
|
|
805
|
+
PR이 main에 병합되면, GitHub Actions 워크플로우가 자동으로:
|
|
806
|
+
1. ✅ 버전 파일 업데이트 (pyproject.toml)
|
|
807
|
+
2. ✅ Git 커밋 및 Annotated Tag 생성
|
|
808
|
+
3. ✅ PyPI 배포 (uv publish)
|
|
809
|
+
4. ✅ GitHub Release 생성 및 공개
|
|
810
|
+
|
|
811
|
+
**로컬에서 할 작업은 없습니다!** GitHub Actions가 모든 것을 처리합니다.
|
|
812
|
+
|
|
813
|
+
---
|
|
814
|
+
|
|
815
|
+
## 🧪 Phase 0: 품질 검증 (필수 통과)
|
|
816
|
+
|
|
817
|
+
릴리즈 전 모든 품질 기준을 자동으로 검증합니다. **하나라도 실패 시 릴리즈 중단**됩니다.
|
|
818
|
+
|
|
819
|
+
### 🤖 CodeRabbit AI 자동 리뷰 통합
|
|
820
|
+
|
|
821
|
+
**MoAI-ADK의 모든 PR은 이미 CodeRabbit으로 자동 리뷰됨:**
|
|
822
|
+
|
|
823
|
+
```
|
|
824
|
+
PR 생성 (feature branch)
|
|
825
|
+
↓
|
|
826
|
+
CodeRabbit 자동 리뷰 (1-2분)
|
|
827
|
+
├─ 코드 품질 분석
|
|
828
|
+
├─ 보안 이슈 검출
|
|
829
|
+
├─ 테스트 커버리지 확인
|
|
830
|
+
└─ 자동 승인 (Pro - 80% 이상 품질)
|
|
831
|
+
↓
|
|
832
|
+
개발자가 PR 병합 (이미 승인됨)
|
|
833
|
+
↓
|
|
834
|
+
develop → main 병합 (GitFlow)
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
> **📋 CodeRabbit 설정**: `.coderabbit.yaml` 및 `.github/CODERABBIT_SETUP.md` 참고
|
|
838
|
+
> - 자동 리뷰 활성화 (모든 브랜치)
|
|
839
|
+
> - Agentic Chat 상호작용 가능
|
|
840
|
+
> - 자동 승인 (Pro 기능, 80% 임계값)
|
|
841
|
+
> - Auto-fix 제안 (한 클릭 적용)
|
|
842
|
+
|
|
843
|
+
### Phase 0.0: CodeRabbit 리뷰 결과 확인
|
|
844
|
+
|
|
845
|
+
**이미 수행된 AI 리뷰 검증:**
|
|
846
|
+
|
|
847
|
+
```bash
|
|
848
|
+
# develop 브랜치의 최근 PR 확인
|
|
849
|
+
gh pr list --base develop --state merged --json title,author,createdAt --limit 5
|
|
850
|
+
|
|
851
|
+
# 또는 마지막 PR의 CodeRabbit 코멘트 확인
|
|
852
|
+
gh pr view --json comments --template '{{range .comments}}{{if .author.login | contains "coderabbit"}}{{.body}}{{end}}{{end}}'
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
**CodeRabbit이 검증한 항목:**
|
|
856
|
+
- ✅ 코드 품질 (디자인 패턴, 가독성, 유지보수성)
|
|
857
|
+
- ✅ 보안 (OWASP Top 10, 취약점 검출)
|
|
858
|
+
- ✅ 테스트 (커버리지, 엣지 케이스)
|
|
859
|
+
- ✅ 문서화 (Docstring, 주석 품질)
|
|
860
|
+
- ✅ 성능 (알고리즘 최적화, 복잡도)
|
|
861
|
+
|
|
862
|
+
> **Skill 통합**: 자세한 검증 절차는 `Skill("moai-awesome-release-verify")`를 참고하세요.
|
|
863
|
+
> - Python 환경 확인 (3.13+)
|
|
864
|
+
> - pytest, ruff, mypy, bandit, pip-audit 검증
|
|
865
|
+
> - Git 상태 확인
|
|
866
|
+
|
|
867
|
+
### 0.1 Python 환경 확인
|
|
868
|
+
|
|
869
|
+
**Python 인터프리터 확인**:
|
|
870
|
+
```bash
|
|
871
|
+
# Python 버전 확인 (>=3.13 필요)
|
|
872
|
+
python_version=$(python --version 2>&1 | awk '{print $2}')
|
|
873
|
+
echo "🐍 Python 버전: $python_version"
|
|
874
|
+
|
|
875
|
+
# pyproject.toml의 requires-python 확인
|
|
876
|
+
required_python=$(rg "^requires-python = " pyproject.toml | awk -F'"' '{print $2}')
|
|
877
|
+
echo "📋 요구 Python 버전: $required_python"
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
**패키지 매니저 감지**:
|
|
881
|
+
```bash
|
|
882
|
+
# uv 우선, 없으면 pip 사용
|
|
883
|
+
if command -v uv &>/dev/null; then
|
|
884
|
+
PKG_MANAGER="uv"
|
|
885
|
+
echo "📦 패키지 매니저: uv (권장)"
|
|
886
|
+
else
|
|
887
|
+
PKG_MANAGER="pip"
|
|
888
|
+
echo "📦 패키지 매니저: pip (기본)"
|
|
889
|
+
fi
|
|
890
|
+
```
|
|
891
|
+
|
|
892
|
+
### 0.2 테스트 실행 (필수)
|
|
893
|
+
|
|
894
|
+
**pytest 실행 및 커버리지 검증**:
|
|
895
|
+
```bash
|
|
896
|
+
echo "🧪 테스트 실행 중..."
|
|
897
|
+
|
|
898
|
+
# pytest 실행 (커버리지 포함)
|
|
899
|
+
pytest tests/ --cov --cov-report=term-missing
|
|
900
|
+
|
|
901
|
+
if [ $? -ne 0 ]; then
|
|
902
|
+
echo "❌ 테스트 실패: 모든 테스트가 통과해야 합니다"
|
|
903
|
+
echo "→ pytest tests/ 실행하여 문제를 해결하세요"
|
|
904
|
+
exit 1
|
|
905
|
+
fi
|
|
906
|
+
|
|
907
|
+
# 커버리지 확인 (85% 이상)
|
|
908
|
+
coverage=$(pytest tests/ --cov --cov-report=term-missing | grep "TOTAL" | awk '{print $4}' | sed 's/%//')
|
|
909
|
+
|
|
910
|
+
if [ "$coverage" -lt 85 ]; then
|
|
911
|
+
echo "⚠️ 테스트 커버리지 부족: ${coverage}% (목표: 85%)"
|
|
912
|
+
echo "→ 추가 테스트 작성을 권장하지만 계속 진행합니다"
|
|
913
|
+
else
|
|
914
|
+
echo "✅ 테스트 통과 (커버리지: ${coverage}%)"
|
|
915
|
+
fi
|
|
916
|
+
```
|
|
917
|
+
|
|
918
|
+
**검증 항목**:
|
|
919
|
+
- ✅ 모든 테스트 케이스 통과
|
|
920
|
+
- ✅ 커버리지 ≥85% (권장, 경고만)
|
|
921
|
+
- ❌ 테스트 실패 시 중단
|
|
922
|
+
|
|
923
|
+
### 0.3 린트 검사 (필수)
|
|
924
|
+
|
|
925
|
+
**ruff 린트 실행**:
|
|
926
|
+
```bash
|
|
927
|
+
echo "🔍 린트 검사 중..."
|
|
928
|
+
|
|
929
|
+
# ruff check 실행
|
|
930
|
+
ruff check src/ tests/
|
|
931
|
+
|
|
932
|
+
if [ $? -ne 0 ]; then
|
|
933
|
+
echo "❌ 린트 오류: 코드 스타일 위반이 있습니다"
|
|
934
|
+
echo "→ ruff check --fix src/ tests/로 자동 수정 시도"
|
|
935
|
+
exit 1
|
|
936
|
+
fi
|
|
937
|
+
|
|
938
|
+
echo "✅ 린트 통과"
|
|
939
|
+
```
|
|
940
|
+
|
|
941
|
+
**검증 항목**:
|
|
942
|
+
- ✅ 린트 규칙 위반 없음
|
|
943
|
+
- ✅ 코드 스타일 일관성
|
|
944
|
+
- ❌ 린트 오류 시 중단
|
|
945
|
+
|
|
946
|
+
### 0.4 타입 체크 (권장)
|
|
947
|
+
|
|
948
|
+
**mypy 타입 체크**:
|
|
949
|
+
```bash
|
|
950
|
+
echo "🔤 타입 체크 중..."
|
|
951
|
+
|
|
952
|
+
# mypy 실행 (missing imports 무시)
|
|
953
|
+
mypy src/moai_adk --ignore-missing-imports
|
|
954
|
+
|
|
955
|
+
if [ $? -ne 0 ]; then
|
|
956
|
+
echo "⚠️ 타입 오류: TypeScript와 달리 Python은 경고만 표시"
|
|
957
|
+
echo "→ mypy src/moai_adk 실행하여 확인"
|
|
958
|
+
# 중단하지 않음
|
|
959
|
+
else
|
|
960
|
+
echo "✅ 타입 체크 통과"
|
|
961
|
+
fi
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
**검증 항목**:
|
|
965
|
+
- ✅ 타입 오류 없음
|
|
966
|
+
- ⚠️ 타입 오류는 경고만 (중단하지 않음)
|
|
967
|
+
|
|
968
|
+
### 0.5 보안 스캔 (권장)
|
|
969
|
+
|
|
970
|
+
**보안 스캔 스크립트 실행**:
|
|
971
|
+
```bash
|
|
972
|
+
echo "🔒 보안 스캔 중..."
|
|
973
|
+
|
|
974
|
+
# 보안 스캔 스크립트 실행
|
|
975
|
+
python scripts/security-scan.py
|
|
976
|
+
|
|
977
|
+
if [ $? -ne 0 ]; then
|
|
978
|
+
echo "⚠️ 보안 취약점 발견: 검토 권장"
|
|
979
|
+
echo "→ scripts/security-scan.py 결과 확인"
|
|
980
|
+
# 중단하지 않음
|
|
981
|
+
else
|
|
982
|
+
echo "✅ 보안 스캔 통과"
|
|
983
|
+
fi
|
|
984
|
+
```
|
|
985
|
+
|
|
986
|
+
**검증 항목**:
|
|
987
|
+
- ✅ pip-audit: 의존성 취약점 없음
|
|
988
|
+
- ✅ bandit: 코드 보안 이슈 없음
|
|
989
|
+
- ⚠️ 취약점 발견 시 경고만 (중단하지 않음)
|
|
990
|
+
|
|
991
|
+
### 0.5.5 의존성 업데이트 확인 (권장)
|
|
992
|
+
|
|
993
|
+
**주요 의존성 업데이트 체크**:
|
|
994
|
+
```bash
|
|
995
|
+
echo "📦 의존성 업데이트 확인 중..."
|
|
996
|
+
|
|
997
|
+
# uv pip list --outdated 로 업데이트 가능한 패키지 확인
|
|
998
|
+
OUTDATED=$(uv pip list --outdated --format=json 2>/dev/null)
|
|
999
|
+
|
|
1000
|
+
if [ -z "$OUTDATED" ] || [ "$OUTDATED" = "[]" ]; then
|
|
1001
|
+
echo "✅ 모든 의존성이 최신 버전입니다"
|
|
1002
|
+
else
|
|
1003
|
+
# 주요 버전 업그레이드 (breaking changes 가능) 감지
|
|
1004
|
+
echo "$OUTDATED" | python -c "
|
|
1005
|
+
import json, sys
|
|
1006
|
+
try:
|
|
1007
|
+
outdated = json.load(sys.stdin)
|
|
1008
|
+
|
|
1009
|
+
# 주요 버전 업그레이드 감지
|
|
1010
|
+
major_updates = []
|
|
1011
|
+
minor_updates = []
|
|
1012
|
+
|
|
1013
|
+
for pkg in outdated:
|
|
1014
|
+
current = pkg['version'].split('.')
|
|
1015
|
+
latest = pkg['latest_version'].split('.')
|
|
1016
|
+
|
|
1017
|
+
# Major version 비교
|
|
1018
|
+
if int(current[0]) < int(latest[0]):
|
|
1019
|
+
major_updates.append((pkg['name'], pkg['version'], pkg['latest_version']))
|
|
1020
|
+
elif len(current) > 1 and len(latest) > 1 and int(current[1]) < int(latest[1]):
|
|
1021
|
+
minor_updates.append((pkg['name'], pkg['version'], pkg['latest_version']))
|
|
1022
|
+
|
|
1023
|
+
if major_updates:
|
|
1024
|
+
print('⚠️ 주요 버전 업그레이드 가능 (breaking changes 주의):')
|
|
1025
|
+
for name, old, new in major_updates:
|
|
1026
|
+
print(f' - {name}: {old} → {new}')
|
|
1027
|
+
print(' → 릴리즈 전에 호환성 검증 권장')
|
|
1028
|
+
print()
|
|
1029
|
+
|
|
1030
|
+
if minor_updates:
|
|
1031
|
+
print('ℹ️ 부분 버전 업그레이드 가능:')
|
|
1032
|
+
for name, old, new in minor_updates[:5]: # 최대 5개만 표시
|
|
1033
|
+
print(f' - {name}: {old} → {new}')
|
|
1034
|
+
if len(minor_updates) > 5:
|
|
1035
|
+
print(f' ... 그 외 {len(minor_updates) - 5}개')
|
|
1036
|
+
|
|
1037
|
+
if not major_updates and not minor_updates:
|
|
1038
|
+
print('✅ 모든 의존성이 최신 버전입니다')
|
|
1039
|
+
except:
|
|
1040
|
+
print('✅ 의존성 버전 확인 완료')
|
|
1041
|
+
" || echo "✅ 의존성 버전 확인 완료"
|
|
1042
|
+
fi
|
|
1043
|
+
```
|
|
1044
|
+
|
|
1045
|
+
**주의사항**:
|
|
1046
|
+
- ⚠️ Major version 업그레이드 발견 시: 릴리즈 전 호환성 테스트 권장
|
|
1047
|
+
- ℹ️ Minor version 업그레이드는 일반적으로 안전함
|
|
1048
|
+
- 보안 패치는 가능한 빨리 적용 권장
|
|
1049
|
+
|
|
1050
|
+
### 0.6 품질 검증 요약
|
|
1051
|
+
|
|
1052
|
+
**성공 시 요약**:
|
|
1053
|
+
```markdown
|
|
1054
|
+
✅ 품질 검증 완료
|
|
1055
|
+
|
|
1056
|
+
- 🐍 Python: 3.13.x
|
|
1057
|
+
- 📦 패키지 매니저: uv
|
|
1058
|
+
- ✅ 테스트: 통과 (커버리지 87%)
|
|
1059
|
+
- ✅ 린트: 통과 (ruff)
|
|
1060
|
+
- ✅ 타입: 통과 (mypy)
|
|
1061
|
+
- ✅ 보안: 통과 (bandit + pip-audit)
|
|
1062
|
+
|
|
1063
|
+
→ Phase 1으로 진행합니다...
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
**실패 시 중단**:
|
|
1067
|
+
```markdown
|
|
1068
|
+
❌ 품질 검증 실패
|
|
1069
|
+
|
|
1070
|
+
릴리즈를 진행할 수 없습니다. 다음 문제를 해결하세요:
|
|
1071
|
+
|
|
1072
|
+
- ❌ 테스트: 3개 실패
|
|
1073
|
+
→ pytest tests/ 실행 결과 확인
|
|
1074
|
+
→ tests/auth.test.py:45 - AssertionError
|
|
1075
|
+
|
|
1076
|
+
- ❌ 린트: 12개 오류
|
|
1077
|
+
→ ruff check --fix src/ tests/로 자동 수정
|
|
1078
|
+
→ src/utils.py:23 - Unused variable 'foo'
|
|
1079
|
+
|
|
1080
|
+
문제 해결 후 다시 시도하세요:
|
|
1081
|
+
/awesome:release-new {VERSION_TYPE}
|
|
1082
|
+
```
|
|
1083
|
+
|
|
1084
|
+
---
|
|
1085
|
+
|
|
1086
|
+
## 🔍 Phase 1: 버전 분석 및 검증
|
|
1087
|
+
|
|
1088
|
+
### 1.1 프로젝트 정보 수집
|
|
1089
|
+
|
|
1090
|
+
**버전 정보 읽기 (SSOT 방식)**:
|
|
1091
|
+
```bash
|
|
1092
|
+
# pyproject.toml에서 버전 읽기 (SSOT - 유일한 진실의 출처)
|
|
1093
|
+
current_version=$(rg "^version = " pyproject.toml | awk -F'"' '{print $2}')
|
|
1094
|
+
echo "📌 현재 버전 (pyproject.toml): $current_version"
|
|
1095
|
+
|
|
1096
|
+
# 설치된 패키지 버전 확인 (검증용)
|
|
1097
|
+
installed_version=$(python -c "from importlib.metadata import version; print(version('moai-adk'))" 2>/dev/null || echo "N/A")
|
|
1098
|
+
echo "📦 설치된 버전: $installed_version"
|
|
1099
|
+
|
|
1100
|
+
# 버전 일치 여부 확인
|
|
1101
|
+
if [ "$current_version" != "$installed_version" ] && [ "$installed_version" != "N/A" ]; then
|
|
1102
|
+
echo "⚠️ 경고: pyproject.toml과 설치된 버전이 다릅니다"
|
|
1103
|
+
echo "→ pyproject.toml: $current_version"
|
|
1104
|
+
echo "→ 설치된 버전: $installed_version"
|
|
1105
|
+
echo "→ 해결: uv pip install -e . --force-reinstall --no-deps"
|
|
1106
|
+
fi
|
|
1107
|
+
|
|
1108
|
+
# __init__.py는 자동 로드 (확인만)
|
|
1109
|
+
echo "ℹ️ __init__.py는 importlib.metadata로 자동 로드 (수정 불필요)"
|
|
1110
|
+
```
|
|
1111
|
+
|
|
1112
|
+
**Git 상태 확인**:
|
|
1113
|
+
```bash
|
|
1114
|
+
# Git 상태
|
|
1115
|
+
git status --short
|
|
1116
|
+
git log --oneline -5
|
|
1117
|
+
|
|
1118
|
+
# 브랜치 확인
|
|
1119
|
+
current_branch=$(git branch --show-current)
|
|
1120
|
+
echo "🌿 현재 브랜치: $current_branch"
|
|
1121
|
+
|
|
1122
|
+
# 미커밋 변경사항 확인
|
|
1123
|
+
if [ -n "$(git status --short)" ]; then
|
|
1124
|
+
echo "⚠️ 미커밋 변경사항 있음 (자동 커밋 예정)"
|
|
1125
|
+
fi
|
|
1126
|
+
```
|
|
1127
|
+
|
|
1128
|
+
### 1.2 목표 버전 결정
|
|
1129
|
+
|
|
1130
|
+
**인수 파싱 로직**:
|
|
1131
|
+
```bash
|
|
1132
|
+
# $1 = version_type (patch, minor, major)
|
|
1133
|
+
VERSION_TYPE="${1:-patch}" # 기본값: patch
|
|
1134
|
+
|
|
1135
|
+
echo "🎯 버전 타입: $VERSION_TYPE"
|
|
1136
|
+
```
|
|
1137
|
+
|
|
1138
|
+
**버전 증가 로직** (Python 스크립트):
|
|
1139
|
+
```python
|
|
1140
|
+
# semver_bump.py
|
|
1141
|
+
import sys
|
|
1142
|
+
|
|
1143
|
+
def bump_version(current: str, bump_type: str) -> str:
|
|
1144
|
+
major, minor, patch = map(int, current.split("."))
|
|
1145
|
+
|
|
1146
|
+
if bump_type == "patch":
|
|
1147
|
+
return f"{major}.{minor}.{patch + 1}"
|
|
1148
|
+
elif bump_type == "minor":
|
|
1149
|
+
return f"{major}.{minor + 1}.0"
|
|
1150
|
+
elif bump_type == "major":
|
|
1151
|
+
return f"{major + 1}.0.0"
|
|
1152
|
+
else:
|
|
1153
|
+
raise ValueError(f"Invalid bump type: {bump_type}")
|
|
1154
|
+
|
|
1155
|
+
if __name__ == "__main__":
|
|
1156
|
+
current = sys.argv[1]
|
|
1157
|
+
bump_type = sys.argv[2]
|
|
1158
|
+
print(bump_version(current, bump_type))
|
|
1159
|
+
```
|
|
1160
|
+
|
|
1161
|
+
**버전 계산**:
|
|
1162
|
+
```bash
|
|
1163
|
+
# Python 스크립트 사용
|
|
1164
|
+
new_version=$(python -c "
|
|
1165
|
+
current = '$current_version'
|
|
1166
|
+
bump_type = '$VERSION_TYPE'
|
|
1167
|
+
|
|
1168
|
+
major, minor, patch = map(int, current.split('.'))
|
|
1169
|
+
|
|
1170
|
+
if bump_type == 'patch':
|
|
1171
|
+
new = f'{major}.{minor}.{patch + 1}'
|
|
1172
|
+
elif bump_type == 'minor':
|
|
1173
|
+
new = f'{major}.{minor + 1}.0'
|
|
1174
|
+
elif bump_type == 'major':
|
|
1175
|
+
new = f'{major + 1}.0.0'
|
|
1176
|
+
else:
|
|
1177
|
+
new = current
|
|
1178
|
+
|
|
1179
|
+
print(new)
|
|
1180
|
+
")
|
|
1181
|
+
|
|
1182
|
+
echo "📊 버전 변경: $current_version → $new_version"
|
|
1183
|
+
```
|
|
1184
|
+
|
|
1185
|
+
**🔬 Dry-Run 모드에서**: 버전 계산만 수행되고, 실제 파일 수정은 하지 않습니다.
|
|
1186
|
+
|
|
1187
|
+
### 1.3 변경사항 분석
|
|
1188
|
+
|
|
1189
|
+
**Git 로그 분석**:
|
|
1190
|
+
```bash
|
|
1191
|
+
# 마지막 릴리즈 태그 찾기
|
|
1192
|
+
last_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
|
1193
|
+
|
|
1194
|
+
if [ -n "$last_tag" ]; then
|
|
1195
|
+
echo "🏷️ 마지막 릴리즈: $last_tag"
|
|
1196
|
+
# 마지막 릴리즈 이후 커밋 목록
|
|
1197
|
+
commits=$(git log $last_tag..HEAD --oneline --pretty=format:"- %s (%h)")
|
|
1198
|
+
else
|
|
1199
|
+
echo "🏷️ 첫 릴리즈"
|
|
1200
|
+
# 전체 커밋 목록 (최근 20개)
|
|
1201
|
+
commits=$(git log --oneline --pretty=format:"- %s (%h)" | head -20)
|
|
1202
|
+
fi
|
|
1203
|
+
|
|
1204
|
+
echo "📝 변경사항:"
|
|
1205
|
+
echo "$commits"
|
|
1206
|
+
```
|
|
1207
|
+
|
|
1208
|
+
**변경 타입 분류** (Git 커밋 메시지 기준):
|
|
1209
|
+
```bash
|
|
1210
|
+
# 이모지 기반 분류 (MoAI-ADK 커밋 메시지 표준)
|
|
1211
|
+
added=$(echo "$commits" | grep -E "^- (✨|🎉|🚀)" || echo "")
|
|
1212
|
+
fixed=$(echo "$commits" | grep -E "^- (🐛|🔥|🩹)" || echo "")
|
|
1213
|
+
docs=$(echo "$commits" | grep -E "^- (📝|📚|📖)" || echo "")
|
|
1214
|
+
refactor=$(echo "$commits" | grep -E "^- (♻️|🔨|🔧)" || echo "")
|
|
1215
|
+
test=$(echo "$commits" | grep -E "^- (✅|🧪)" || echo "")
|
|
1216
|
+
```
|
|
1217
|
+
|
|
1218
|
+
### 1.4 릴리즈 계획 보고서 생성
|
|
1219
|
+
|
|
1220
|
+
```markdown
|
|
1221
|
+
## 🚀 릴리즈 계획 보고서: v{new_version}
|
|
1222
|
+
|
|
1223
|
+
### 🧪 품질 검증 결과 (Phase 0)
|
|
1224
|
+
- ✅ 테스트: 통과 (커버리지 87%)
|
|
1225
|
+
- ✅ 린트: 통과 (ruff)
|
|
1226
|
+
- ✅ 타입: 통과 (mypy)
|
|
1227
|
+
- ✅ 보안: 통과 (bandit + pip-audit)
|
|
1228
|
+
|
|
1229
|
+
### 📊 버전 정보
|
|
1230
|
+
- **현재 버전**: v{current_version}
|
|
1231
|
+
- **목표 버전**: v{new_version}
|
|
1232
|
+
- **버전 타입**: {VERSION_TYPE}
|
|
1233
|
+
- **릴리즈 날짜**: {YYYY-MM-DD}
|
|
1234
|
+
|
|
1235
|
+
### 📁 프로젝트 정보
|
|
1236
|
+
- **프로젝트**: moai-adk
|
|
1237
|
+
- **현재 브랜치**: {current_branch}
|
|
1238
|
+
- **마지막 커밋**: {git log -1 --oneline}
|
|
1239
|
+
|
|
1240
|
+
### 📝 변경사항 요약
|
|
1241
|
+
{마지막 릴리즈 이후 커밋 목록}
|
|
1242
|
+
|
|
1243
|
+
#### ✨ Added (N개)
|
|
1244
|
+
{added 커밋}
|
|
1245
|
+
|
|
1246
|
+
#### 🐛 Fixed (N개)
|
|
1247
|
+
{fixed 커밋}
|
|
1248
|
+
|
|
1249
|
+
#### 📝 Documentation (N개)
|
|
1250
|
+
{docs 커밋}
|
|
1251
|
+
|
|
1252
|
+
### 🔄 업데이트할 파일 (SSOT)
|
|
1253
|
+
- [ ] pyproject.toml: version = "{current_version}" → "{new_version}" (SSOT)
|
|
1254
|
+
- [ ] src/moai_adk/__init__.py: 수정 불필요 (importlib.metadata로 자동 로드)
|
|
1255
|
+
|
|
1256
|
+
### 🚀 릴리즈 작업
|
|
1257
|
+
- [ ] Git 커밋: `🔖 RELEASE: v{new_version}`
|
|
1258
|
+
- [ ] Git 태그: `v{new_version}` (Annotated)
|
|
1259
|
+
- [ ] PyPI 배포: `uv publish`
|
|
1260
|
+
- [ ] GitHub Release: `gh release create` (Draft)
|
|
1261
|
+
|
|
1262
|
+
### ⚠️ 주의사항
|
|
1263
|
+
- 현재 브랜치: {current_branch} (main 권장)
|
|
1264
|
+
- 미커밋 변경: {N개 파일} (자동 커밋 예정)
|
|
1265
|
+
|
|
1266
|
+
---
|
|
1267
|
+
**승인 요청**: 위 계획으로 릴리즈를 진행하시겠습니까?
|
|
1268
|
+
("진행", "수정 [내용]", "중단" 중 선택)
|
|
1269
|
+
```
|
|
1270
|
+
|
|
1271
|
+
**🔬 Dry-Run 모드에서**: 위의 릴리즈 계획 보고서가 출력되며, 사용자 승인을 기다리지 않습니다.
|
|
1272
|
+
- 대신 "실제 릴리즈 명령"이 표시되어 사용자가 확인 후 실행할 수 있게 합니다.
|
|
1273
|
+
|
|
1274
|
+
---
|
|
1275
|
+
|
|
1276
|
+
## 🔄 Phase 2: Branch Merge and PR Management
|
|
1277
|
+
|
|
1278
|
+
**전제조건**: Phase 1에서 사용자가 "진행"을 선택한 경우만 실행
|
|
1279
|
+
|
|
1280
|
+
**🔬 Dry-Run 모드에서**: Phase 2는 **완전히 건너뜁니다**
|
|
1281
|
+
- GitHub PR 생성 단계를 시뮬레이션하고 로깅만 합니다
|
|
1282
|
+
- 실제 GitHub API 호출을 하지 않습니다
|
|
1283
|
+
- 대신 "다음 단계: GitHub에서 PR 병합" 메시지를 표시합니다
|
|
1284
|
+
|
|
1285
|
+
**워크플로우 자동 감지**:
|
|
1286
|
+
- ✅ **GitFlow 모드**: develop 브랜치 존재 시 (feature → develop → main)
|
|
1287
|
+
- ✅ **Simplified 모드**: develop 브랜치 없을 시 (feature → main)
|
|
1288
|
+
|
|
1289
|
+
**핵심 원칙**:
|
|
1290
|
+
- ✅ **PR은 GitHub CLI(`gh pr create`)로 생성**
|
|
1291
|
+
- ✅ **CodeRabbit AI가 자동으로 리뷰 및 승인**
|
|
1292
|
+
- ✅ **PR 병합은 GitHub 웹에서만 수행 (로컬 merge 금지)**
|
|
1293
|
+
- ✅ **PR 병합 후 GitHub Actions가 자동으로 Phase 3 실행**
|
|
1294
|
+
|
|
1295
|
+
**모드 감지**:
|
|
1296
|
+
- **Personal 모드**: PR 단계 자동 건너뜀 (로컬 개발용)
|
|
1297
|
+
- **Team 모드**: full GitFlow PR 프로세스 실행
|
|
1298
|
+
|
|
1299
|
+
### Step 2.0: 프로젝트 모드 및 워크플로우 감지 (자동)
|
|
1300
|
+
|
|
1301
|
+
**Mode 및 Workflow 자동 감지**:
|
|
1302
|
+
```bash
|
|
1303
|
+
# 1. 프로젝트 모드 감지 (.moai/config.json)
|
|
1304
|
+
project_mode=$(rg '"mode":\s*"([^"]+)"' .moai/config.json -o '$1' | head -1)
|
|
1305
|
+
echo "🎭 프로젝트 모드: $project_mode"
|
|
1306
|
+
|
|
1307
|
+
if [ "$project_mode" = "personal" ]; then
|
|
1308
|
+
echo "ℹ️ Personal 모드: PR 단계를 자동으로 건너뜁니다 (로컬 개발용)"
|
|
1309
|
+
echo "→ Phase 3 (릴리즈 실행)로 직접 진행합니다..."
|
|
1310
|
+
# Phase 3으로 자동 점프 (PR 단계 건너뜀)
|
|
1311
|
+
return 0
|
|
1312
|
+
fi
|
|
1313
|
+
|
|
1314
|
+
echo "🔀 Team 모드: Branch merge 프로세스 실행"
|
|
1315
|
+
echo ""
|
|
1316
|
+
|
|
1317
|
+
# 2. GitFlow 워크플로우 감지 (develop 브랜치 존재 여부)
|
|
1318
|
+
if git show-ref --verify --quiet refs/heads/develop; then
|
|
1319
|
+
WORKFLOW_MODE="gitflow"
|
|
1320
|
+
BASE_BRANCH="develop"
|
|
1321
|
+
TARGET_BRANCH="main"
|
|
1322
|
+
echo "📋 Workflow: GitFlow (develop → main)"
|
|
1323
|
+
echo " - Feature branches merge to: develop"
|
|
1324
|
+
echo " - Releases merge from: develop → main"
|
|
1325
|
+
else
|
|
1326
|
+
WORKFLOW_MODE="simplified"
|
|
1327
|
+
BASE_BRANCH="main"
|
|
1328
|
+
TARGET_BRANCH="main"
|
|
1329
|
+
echo "📋 Workflow: Simplified (feature → main)"
|
|
1330
|
+
echo " - Feature branches merge to: main"
|
|
1331
|
+
echo " - Releases deploy from: main"
|
|
1332
|
+
fi
|
|
1333
|
+
|
|
1334
|
+
echo ""
|
|
1335
|
+
```
|
|
1336
|
+
|
|
1337
|
+
### Step 2.1: 현재 브랜치 확인 및 검증
|
|
1338
|
+
|
|
1339
|
+
**브랜치 검증** (Team 모드만, 워크플로우 감지):
|
|
1340
|
+
```bash
|
|
1341
|
+
current_branch=$(git branch --show-current)
|
|
1342
|
+
echo "🌿 현재 브랜치: $current_branch"
|
|
1343
|
+
|
|
1344
|
+
if [ "$WORKFLOW_MODE" = "gitflow" ]; then
|
|
1345
|
+
# GitFlow: develop 브랜치에서 시작 권장
|
|
1346
|
+
if [ "$current_branch" != "$BASE_BRANCH" ]; then
|
|
1347
|
+
echo "⚠️ GitFlow 모드에서는 $BASE_BRANCH 브랜치에서 릴리즈를 시작하는 것을 권장합니다"
|
|
1348
|
+
echo "→ 현재 브랜치: $current_branch"
|
|
1349
|
+
read -p "계속 진행하시겠습니까? (y/n): " continue_anyway
|
|
1350
|
+
if [ "$continue_anyway" != "y" ]; then
|
|
1351
|
+
echo "→ git checkout $BASE_BRANCH 실행 후 재시도"
|
|
1352
|
+
exit 1
|
|
1353
|
+
fi
|
|
1354
|
+
else
|
|
1355
|
+
echo "✅ $BASE_BRANCH 브랜치 확인 완료"
|
|
1356
|
+
fi
|
|
1357
|
+
else
|
|
1358
|
+
# Simplified: feature 브랜치에서 바로 main으로 PR
|
|
1359
|
+
echo "✅ Simplified 모드: $current_branch에서 $TARGET_BRANCH로 PR 생성"
|
|
1360
|
+
fi
|
|
1361
|
+
```
|
|
1362
|
+
|
|
1363
|
+
### Step 2.2: main 브랜치 최신화
|
|
1364
|
+
|
|
1365
|
+
**main 브랜치 동기화**:
|
|
1366
|
+
```bash
|
|
1367
|
+
echo "🔄 main 브랜치 최신화 중..."
|
|
1368
|
+
|
|
1369
|
+
# origin/main 최신 상태 확인
|
|
1370
|
+
git fetch origin main:main
|
|
1371
|
+
|
|
1372
|
+
if [ $? -ne 0 ]; then
|
|
1373
|
+
echo "⚠️ main 브랜치 동기화 실패"
|
|
1374
|
+
echo "→ git fetch origin main:main 실행 확인"
|
|
1375
|
+
fi
|
|
1376
|
+
|
|
1377
|
+
echo "✅ main 브랜치 최신화 완료"
|
|
1378
|
+
```
|
|
1379
|
+
|
|
1380
|
+
### Step 2.3: GitHub PR 생성 (Draft)
|
|
1381
|
+
|
|
1382
|
+
**develop → main PR 생성**:
|
|
1383
|
+
```bash
|
|
1384
|
+
echo "📝 Creating GitHub PR (develop → main)..."
|
|
1385
|
+
|
|
1386
|
+
# PR title and description (English only)
|
|
1387
|
+
pr_title="🔖 Release v{new_version} | {VERSION_TYPE} | {Release Description}"
|
|
1388
|
+
|
|
1389
|
+
pr_body="## GitFlow Release PR
|
|
1390
|
+
|
|
1391
|
+
### 📊 Release Information
|
|
1392
|
+
- **Version**: v{new_version}
|
|
1393
|
+
- **Type**: {VERSION_TYPE}
|
|
1394
|
+
- **Date**: {YYYY-MM-DD}
|
|
1395
|
+
|
|
1396
|
+
### 📝 Changelog
|
|
1397
|
+
{Commits since last release}
|
|
1398
|
+
|
|
1399
|
+
### 🧪 Quality Assurance
|
|
1400
|
+
- ✅ Tests: {TEST_RESULT}
|
|
1401
|
+
- ✅ Linting: {LINT_RESULT}
|
|
1402
|
+
- ✅ Type Checking: {TYPE_RESULT}
|
|
1403
|
+
- ✅ Security Scan: {SECURITY_RESULT}
|
|
1404
|
+
|
|
1405
|
+
### 🚀 Release Steps
|
|
1406
|
+
- [x] PR created from develop
|
|
1407
|
+
- [ ] CodeRabbit AI review (automatic)
|
|
1408
|
+
- [ ] Merge to main (manual)
|
|
1409
|
+
- [ ] Tag creation (automatic)
|
|
1410
|
+
- [ ] PyPI deployment (automatic)
|
|
1411
|
+
- [ ] GitHub Release publication (automatic)
|
|
1412
|
+
|
|
1413
|
+
---
|
|
1414
|
+
|
|
1415
|
+
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
|
1416
|
+
|
|
1417
|
+
Co-Authored-By: Alfred <alfred@mo.ai.kr>"
|
|
1418
|
+
|
|
1419
|
+
# Create PR with gh CLI (Draft)
|
|
1420
|
+
echo "⏳ Creating GitHub PR..."
|
|
1421
|
+
|
|
1422
|
+
# NOTE: --label release은 GitHub Actions moai-release-pipeline.yml에서 감지하여
|
|
1423
|
+
# 자동으로 Tag 생성 및 GitHub Release 생성을 트리거합니다
|
|
1424
|
+
# 이는 "🔖 RELEASE:" 커밋 패턴보다 더 신뢰할 수 있습니다 (실패율 <5%)
|
|
1425
|
+
|
|
1426
|
+
gh pr create \
|
|
1427
|
+
--base main \
|
|
1428
|
+
--head develop \
|
|
1429
|
+
--title "$pr_title" \
|
|
1430
|
+
--body "$pr_body" \
|
|
1431
|
+
--label release \
|
|
1432
|
+
--draft 2>&1
|
|
1433
|
+
|
|
1434
|
+
pr_exit_code=$?
|
|
1435
|
+
|
|
1436
|
+
if [ $pr_exit_code -ne 0 ]; then
|
|
1437
|
+
echo ""
|
|
1438
|
+
echo "⚠️ GitHub PR 생성 실패"
|
|
1439
|
+
echo ""
|
|
1440
|
+
echo "가능한 원인:"
|
|
1441
|
+
echo "1️⃣ 인증 오류: gh auth status 확인"
|
|
1442
|
+
echo "2️⃣ 중복 PR: 이미 존재하는 PR 확인"
|
|
1443
|
+
echo "3️⃣ 커밋 차이 없음: develop과 main이 같은 상태"
|
|
1444
|
+
echo "4️⃣ 네트워크 오류: 인터넷 연결 확인"
|
|
1445
|
+
echo ""
|
|
1446
|
+
echo "다음 중 선택:"
|
|
1447
|
+
echo "1. 수동으로 GitHub에서 PR 생성 후 진행"
|
|
1448
|
+
echo "2. PR 없이 직접 릴리즈 진행"
|
|
1449
|
+
read -p "선택 (1 또는 2): " pr_fallback
|
|
1450
|
+
|
|
1451
|
+
if [ "$pr_fallback" = "1" ]; then
|
|
1452
|
+
echo ""
|
|
1453
|
+
read -p "PR 생성이 완료되었나요? (yes/no): " pr_complete
|
|
1454
|
+
if [ "$pr_complete" != "yes" ]; then
|
|
1455
|
+
echo "❌ PR 생성 필요. 먼저 GitHub에서 PR을 생성하세요."
|
|
1456
|
+
exit 1
|
|
1457
|
+
fi
|
|
1458
|
+
pr_number=$(gh pr list --head develop --base main --json number -q '.[0].number' 2>/dev/null || echo "")
|
|
1459
|
+
if [ -z "$pr_number" ]; then
|
|
1460
|
+
echo "⚠️ PR을 찾을 수 없습니다. 계속 진행하겠습니다..."
|
|
1461
|
+
pr_number="unknown"
|
|
1462
|
+
fi
|
|
1463
|
+
else
|
|
1464
|
+
echo "→ PR 없이 릴리즈를 진행합니다 (로컬 모드)"
|
|
1465
|
+
pr_number="none"
|
|
1466
|
+
fi
|
|
1467
|
+
else
|
|
1468
|
+
echo "✅ GitHub PR이 생성되었습니다"
|
|
1469
|
+
# PR 번호 추출
|
|
1470
|
+
pr_number=$(gh pr list --head develop --base main --json number -q '.[0].number' 2>/dev/null || echo "")
|
|
1471
|
+
if [ -z "$pr_number" ]; then
|
|
1472
|
+
pr_number="latest"
|
|
1473
|
+
fi
|
|
1474
|
+
echo "✅ PR #$pr_number 생성됨 (Draft 상태)"
|
|
1475
|
+
echo "→ PR 링크: https://github.com/modu-ai/moai-adk/pull/$pr_number"
|
|
1476
|
+
fi
|
|
1477
|
+
```
|
|
1478
|
+
|
|
1479
|
+
### Step 2.3.5: 🤖 CodeRabbit 자동 리뷰 & 승인 (자동 실행)
|
|
1480
|
+
|
|
1481
|
+
**PR 생성 후 CodeRabbit 자동 실행:**
|
|
1482
|
+
|
|
1483
|
+
```bash
|
|
1484
|
+
echo "🤖 CodeRabbit AI 자동 리뷰 시작 (1-2분 소요)..."
|
|
1485
|
+
|
|
1486
|
+
# CodeRabbit이 자동으로:
|
|
1487
|
+
# 1. 코드 품질 분석
|
|
1488
|
+
# 2. 보안 이슈 검출
|
|
1489
|
+
# 3. 테스트 커버리지 확인
|
|
1490
|
+
# 4. 품질 80% 이상 시 자동 승인 (Pro 기능)
|
|
1491
|
+
|
|
1492
|
+
# PR 리뷰 대기
|
|
1493
|
+
for i in {1..12}; do
|
|
1494
|
+
sleep 10
|
|
1495
|
+
|
|
1496
|
+
review_status=$(gh pr view $pr_number --json reviews --jq '.reviews | length')
|
|
1497
|
+
comments=$(gh pr view $pr_number --json comments --jq '.comments[] | select(.author.login == "coderabbitai") | .body' 2>/dev/null | head -1)
|
|
1498
|
+
|
|
1499
|
+
if [ -n "$comments" ]; then
|
|
1500
|
+
echo "✅ CodeRabbit 리뷰 완료!"
|
|
1501
|
+
echo "→ PR #$pr_number: https://github.com/modu-ai/moai-adk/pull/$pr_number"
|
|
1502
|
+
break
|
|
1503
|
+
fi
|
|
1504
|
+
|
|
1505
|
+
echo "⏳ CodeRabbit 리뷰 중... (${i}/12)"
|
|
1506
|
+
done
|
|
1507
|
+
|
|
1508
|
+
# CodeRabbit 자동 승인 확인
|
|
1509
|
+
approval_status=$(gh pr view $pr_number --json reviewDecision --jq '.reviewDecision')
|
|
1510
|
+
|
|
1511
|
+
if [ "$approval_status" = "APPROVED" ]; then
|
|
1512
|
+
echo "✅ CodeRabbit이 자동 승인했습니다! (품질 80% 이상)"
|
|
1513
|
+
echo "→ PR이 병합 가능 상태입니다"
|
|
1514
|
+
else
|
|
1515
|
+
echo "ℹ️ CodeRabbit 리뷰 완료 (추가 수정 제안 있음)"
|
|
1516
|
+
echo "→ PR 코멘트 확인 후 수정 진행"
|
|
1517
|
+
fi
|
|
1518
|
+
```
|
|
1519
|
+
|
|
1520
|
+
**CodeRabbit 자동 승인 조건:**
|
|
1521
|
+
- ✅ 코드 품질 점수: 80% 이상
|
|
1522
|
+
- ✅ 보안 이슈: 중대 문제 없음
|
|
1523
|
+
- ✅ 테스트 커버리지: 85% 이상 (권장)
|
|
1524
|
+
- ✅ Agentic Chat: 개발자가 추가 질문 가능
|
|
1525
|
+
|
|
1526
|
+
### Step 2.4: PR Ready for Review로 전환
|
|
1527
|
+
|
|
1528
|
+
**Draft → Ready 상태 변경** (PR이 존재할 때만):
|
|
1529
|
+
```bash
|
|
1530
|
+
if [ "$pr_number" = "none" ] || [ "$pr_number" = "unknown" ]; then
|
|
1531
|
+
echo "ℹ️ PR이 없으므로 Ready 전환 단계를 건너뜁니다"
|
|
1532
|
+
else
|
|
1533
|
+
echo "📋 PR을 Ready for Review로 전환 중..."
|
|
1534
|
+
|
|
1535
|
+
gh pr ready $pr_number 2>/dev/null
|
|
1536
|
+
|
|
1537
|
+
if [ $? -ne 0 ]; then
|
|
1538
|
+
echo "⚠️ PR 상태 변경 실패 (이미 Ready 상태일 수 있음)"
|
|
1539
|
+
echo "→ GitHub에서 확인: https://github.com/modu-ai/moai-adk/pulls"
|
|
1540
|
+
else
|
|
1541
|
+
echo "✅ PR이 Ready for Review 상태로 변경되었습니다"
|
|
1542
|
+
echo "🤖 CodeRabbit 자동 리뷰가 이미 완료되었습니다"
|
|
1543
|
+
fi
|
|
1544
|
+
fi
|
|
1545
|
+
```
|
|
1546
|
+
|
|
1547
|
+
### Step 2.5: 자동 병합 또는 사용자 승인
|
|
1548
|
+
|
|
1549
|
+
**병합 방식 선택**:
|
|
1550
|
+
```bash
|
|
1551
|
+
echo "🤔 PR 병합 방식을 선택하세요:"
|
|
1552
|
+
echo "1. 자동 병합 (gh pr merge로 즉시 병합)"
|
|
1553
|
+
echo "2. 수동 승인 (GitHub에서 리뷰 후 병합)"
|
|
1554
|
+
read -p "선택 (1 또는 2): " merge_choice
|
|
1555
|
+
|
|
1556
|
+
if [ "$merge_choice" = "1" ]; then
|
|
1557
|
+
echo "🔄 자동 병합 중..."
|
|
1558
|
+
|
|
1559
|
+
gh pr merge $pr_number \
|
|
1560
|
+
--merge \
|
|
1561
|
+
--auto
|
|
1562
|
+
|
|
1563
|
+
if [ $? -eq 0 ]; then
|
|
1564
|
+
echo "✅ PR이 자동 병합 대기 상태로 설정되었습니다"
|
|
1565
|
+
else
|
|
1566
|
+
echo "❌ 자동 병합 설정 실패"
|
|
1567
|
+
echo "→ GitHub에서 수동으로 병합하세요"
|
|
1568
|
+
exit 1
|
|
1569
|
+
fi
|
|
1570
|
+
else
|
|
1571
|
+
echo "⏳ GitHub에서 리뷰 후 병합해주세요"
|
|
1572
|
+
echo "→ PR 링크: https://github.com/modu-ai/moai-adk/pull/$pr_number"
|
|
1573
|
+
echo "→ 병합 완료 후 다시 릴리즈 명령 실행"
|
|
1574
|
+
exit 0
|
|
1575
|
+
fi
|
|
1576
|
+
```
|
|
1577
|
+
|
|
1578
|
+
### Step 2.6: 병합 완료 확인
|
|
1579
|
+
|
|
1580
|
+
**main 브랜치 업데이트**:
|
|
1581
|
+
```bash
|
|
1582
|
+
echo "⏳ PR 병합 완료 대기 중..."
|
|
1583
|
+
|
|
1584
|
+
# 최대 30초 동안 병합 상태 확인
|
|
1585
|
+
for i in {1..6}; do
|
|
1586
|
+
sleep 5
|
|
1587
|
+
merge_status=$(gh pr view $pr_number --json mergeStateStatus -q '.mergeStateStatus')
|
|
1588
|
+
|
|
1589
|
+
if [ "$merge_status" = "MERGED" ]; then
|
|
1590
|
+
echo "✅ PR이 성공적으로 병합되었습니다"
|
|
1591
|
+
|
|
1592
|
+
# main 브랜치 로컬 업데이트
|
|
1593
|
+
git fetch origin
|
|
1594
|
+
git checkout main
|
|
1595
|
+
git pull origin main
|
|
1596
|
+
|
|
1597
|
+
echo "✅ main 브랜치가 최신화되었습니다"
|
|
1598
|
+
return 0
|
|
1599
|
+
fi
|
|
1600
|
+
done
|
|
1601
|
+
|
|
1602
|
+
echo "⚠️ PR 병합 확인 시간 초과"
|
|
1603
|
+
echo "→ GitHub에서 병합 상태 확인 후 수동으로 계속하세요"
|
|
1604
|
+
```
|
|
1605
|
+
|
|
1606
|
+
### Step 2.7: SPEC 기반 체인지로그 생성 (Feature-Accumulation 지원)
|
|
1607
|
+
|
|
1608
|
+
**목적**: 2-4주 개발 주기에서 누적된 기능들을 사용자 친화적으로 요약하기
|
|
1609
|
+
|
|
1610
|
+
**체인지로그 생성 스크립트**:
|
|
1611
|
+
```bash
|
|
1612
|
+
echo "📝 Phase 2.7: SPEC-기반 체인지로그 생성 중..."
|
|
1613
|
+
|
|
1614
|
+
# 변수 설정
|
|
1615
|
+
LAST_MINOR_TAG=$(git describe --tags --abbrev=0 --match "v*.*.0" 2>/dev/null || echo "")
|
|
1616
|
+
CURRENT_VERSION="$new_version"
|
|
1617
|
+
|
|
1618
|
+
# 빌드 데이터 저장소
|
|
1619
|
+
CHANGELOG_DATA=".moai/temp/changelog-$CURRENT_VERSION.md"
|
|
1620
|
+
mkdir -p .moai/temp
|
|
1621
|
+
|
|
1622
|
+
echo "## 🎉 What's New in v$CURRENT_VERSION" > "$CHANGELOG_DATA"
|
|
1623
|
+
echo "" >> "$CHANGELOG_DATA"
|
|
1624
|
+
|
|
1625
|
+
if [ -z "$LAST_MINOR_TAG" ]; then
|
|
1626
|
+
echo "⚠️ 이전 minor 버전을 찾을 수 없습니다. 전체 기능 목록 생성..."
|
|
1627
|
+
LAST_MINOR_TAG=$(git rev-list --max-parents=0 HEAD)
|
|
1628
|
+
else
|
|
1629
|
+
echo "📊 마지막 릴리즈: $LAST_MINOR_TAG"
|
|
1630
|
+
echo "현재 버전: v$CURRENT_VERSION"
|
|
1631
|
+
echo ""
|
|
1632
|
+
fi
|
|
1633
|
+
|
|
1634
|
+
# 커밋에서 SPEC ID 추출 (예: @SPEC:AUTH-001)
|
|
1635
|
+
echo "🔍 SPEC 문서 검색 중..."
|
|
1636
|
+
|
|
1637
|
+
SPEC_IDS=$(git log $LAST_MINOR_TAG..HEAD --oneline 2>/dev/null | \
|
|
1638
|
+
grep -o '@SPEC:[A-Z_][A-Z_0-9]*-[0-9]\{3\}' | \
|
|
1639
|
+
sed 's/@SPEC:/SPEC-/' | \
|
|
1640
|
+
sort -u)
|
|
1641
|
+
|
|
1642
|
+
SPEC_COUNT=$(echo "$SPEC_IDS" | grep -c "SPEC" || echo 0)
|
|
1643
|
+
echo "✅ 발견된 SPEC: $SPEC_COUNT개"
|
|
1644
|
+
echo ""
|
|
1645
|
+
|
|
1646
|
+
# 카테고리별 기능 수집
|
|
1647
|
+
declare -A FEATURES_BY_CATEGORY
|
|
1648
|
+
|
|
1649
|
+
for SPEC_ID in $SPEC_IDS; do
|
|
1650
|
+
SPEC_DIR=".moai/specs/$SPEC_ID"
|
|
1651
|
+
|
|
1652
|
+
if [ -f "$SPEC_DIR/spec.md" ]; then
|
|
1653
|
+
# SPEC ID에서 카테고리 추출 (예: SPEC-UPDATE-001 → UPDATE)
|
|
1654
|
+
CATEGORY=$(echo "$SPEC_ID" | sed 's/^SPEC-//' | sed 's/-[0-9]*$//')
|
|
1655
|
+
|
|
1656
|
+
# SPEC 제목 추출
|
|
1657
|
+
TITLE=$(grep '^# @SPEC:' "$SPEC_DIR/spec.md" 2>/dev/null | sed 's/^# @SPEC:[^ ]* //' || echo "N/A")
|
|
1658
|
+
|
|
1659
|
+
# 짧은 설명 추출 (첫 번째 단락)
|
|
1660
|
+
SUMMARY=$(grep -A 2 '## Overview\|## 개요' "$SPEC_DIR/spec.md" 2>/dev/null | tail -1 | head -c 100)
|
|
1661
|
+
|
|
1662
|
+
# Acceptance criteria 개수 세기
|
|
1663
|
+
CRITERIA_COUNT=$(grep -c '✅\|- WHEN\|- GIVEN\|### ' "$SPEC_DIR/acceptance.md" 2>/dev/null || echo "0")
|
|
1664
|
+
|
|
1665
|
+
# 카테고리별 저장
|
|
1666
|
+
if [ -z "${FEATURES_BY_CATEGORY[$CATEGORY]}" ]; then
|
|
1667
|
+
FEATURES_BY_CATEGORY[$CATEGORY]="- **[$SPEC_ID]** $TITLE\n"
|
|
1668
|
+
else
|
|
1669
|
+
FEATURES_BY_CATEGORY[$CATEGORY]+="- **[$SPEC_ID]** $TITLE\n"
|
|
1670
|
+
fi
|
|
1671
|
+
fi
|
|
1672
|
+
done
|
|
1673
|
+
|
|
1674
|
+
# 카테고리별로 체인지로그 작성
|
|
1675
|
+
for CATEGORY in $(echo "${!FEATURES_BY_CATEGORY[@]}" | tr ' ' '\n' | sort); do
|
|
1676
|
+
echo "### 🔹 $CATEGORY" >> "$CHANGELOG_DATA"
|
|
1677
|
+
echo -e "${FEATURES_BY_CATEGORY[$CATEGORY]}" >> "$CHANGELOG_DATA"
|
|
1678
|
+
echo "" >> "$CHANGELOG_DATA"
|
|
1679
|
+
done
|
|
1680
|
+
|
|
1681
|
+
# 버그 수정 요약
|
|
1682
|
+
echo "### 🐛 Bug Fixes" >> "$CHANGELOG_DATA"
|
|
1683
|
+
BUG_FIX_COUNT=$(git log $LAST_MINOR_TAG..HEAD --oneline 2>/dev/null | \
|
|
1684
|
+
grep -c 'fix\|Fix\|FIX' || echo "0")
|
|
1685
|
+
echo "- Fixed $BUG_FIX_COUNT bugs and improvements" >> "$CHANGELOG_DATA"
|
|
1686
|
+
echo "" >> "$CHANGELOG_DATA"
|
|
1687
|
+
|
|
1688
|
+
# 성능 개선
|
|
1689
|
+
echo "### ⚡ Performance" >> "$CHANGELOG_DATA"
|
|
1690
|
+
PERF_COUNT=$(git log $LAST_MINOR_TAG..HEAD --oneline 2>/dev/null | \
|
|
1691
|
+
grep -c 'perf\|optimi\|Optimi' || echo "0")
|
|
1692
|
+
echo "- $PERF_COUNT performance optimizations" >> "$CHANGELOG_DATA"
|
|
1693
|
+
echo "" >> "$CHANGELOG_DATA"
|
|
1694
|
+
|
|
1695
|
+
# 테스트 커버리지
|
|
1696
|
+
echo "### 🧪 Quality Metrics" >> "$CHANGELOG_DATA"
|
|
1697
|
+
if [ -f "pyproject.toml" ]; then
|
|
1698
|
+
COVERAGE=$(grep -i 'coverage\|test' pyproject.toml | head -1 || echo "✅ Comprehensive test coverage")
|
|
1699
|
+
echo "- $COVERAGE" >> "$CHANGELOG_DATA"
|
|
1700
|
+
fi
|
|
1701
|
+
echo "" >> "$CHANGELOG_DATA"
|
|
1702
|
+
|
|
1703
|
+
# 모니터링 정보 출력
|
|
1704
|
+
echo "📄 생성된 체인지로그:"
|
|
1705
|
+
cat "$CHANGELOG_DATA"
|
|
1706
|
+
echo ""
|
|
1707
|
+
|
|
1708
|
+
# GitHub Release에서 사용하기 위해 환경변수 저장
|
|
1709
|
+
echo "SPEC_CHANGELOG=$CHANGELOG_DATA" >> "$GITHUB_OUTPUT" 2>/dev/null || true
|
|
1710
|
+
|
|
1711
|
+
echo "✅ 체인지로그 생성 완료"
|
|
1712
|
+
echo "→ 파일: $CHANGELOG_DATA"
|
|
1713
|
+
```
|
|
1714
|
+
|
|
1715
|
+
**주의사항**:
|
|
1716
|
+
- ✅ SPEC 문서가 있어야 기능 정보 추출 가능
|
|
1717
|
+
- ✅ `.moai/specs/SPEC-*/` 디렉토리 구조 필요
|
|
1718
|
+
- ✅ 생성된 파일은 GitHub Release 생성 시 자동으로 포함됨
|
|
1719
|
+
|
|
1720
|
+
---
|
|
1721
|
+
|
|
1722
|
+
## 🚀 Phase 3: GitHub Actions 자동 릴리즈 실행
|
|
1723
|
+
|
|
1724
|
+
**⚠️ 주의**: Phase 3은 부분적으로 **자동화**되어 있습니다. 몇 가지 수동 단계가 필요할 수 있습니다.
|
|
1725
|
+
|
|
1726
|
+
### 🤖 GitHub Actions 자동 워크플로우
|
|
1727
|
+
|
|
1728
|
+
PR이 main 브랜치에 병합되면, GitHub Actions의 여러 워크플로우가 실행됩니다:
|
|
1729
|
+
|
|
1730
|
+
**자동 실행 워크플로우**:
|
|
1731
|
+
1. ✅ **moai-gitflow.yml** (PR 병합 시 자동 트리거)
|
|
1732
|
+
- Release commit 감지 (🔖 RELEASE: 패턴)
|
|
1733
|
+
- Git Tag 생성
|
|
1734
|
+
- GitHub Release 생성 (Draft)
|
|
1735
|
+
|
|
1736
|
+
2. ✅ **release.yml** (GitHub Release published 시 자동 트리거)
|
|
1737
|
+
- 패키지 빌드 (uv build)
|
|
1738
|
+
- PyPI 배포 (uv publish with PYPI_API_TOKEN)
|
|
1739
|
+
|
|
1740
|
+
**⚠️ 주의**: Release Pipeline이 merge commit을 감지하지 못할 수 있습니다.
|
|
1741
|
+
- GitHub merge commit 형식: "Merge pull request #XX..."
|
|
1742
|
+
- Release Pattern: "🔖 RELEASE: v..." (PR 설명에 있어야 감지됨)
|
|
1743
|
+
|
|
1744
|
+
### 모니터링 방법
|
|
1745
|
+
|
|
1746
|
+
**Step 1: Release Pipeline 실행 확인** (merge 후 1-2초)
|
|
1747
|
+
```bash
|
|
1748
|
+
# GitHub Actions 실행 상태 확인
|
|
1749
|
+
gh run list --branch main --limit 5 --json name,status,conclusion
|
|
1750
|
+
|
|
1751
|
+
# 최신 Release Pipeline 상세 정보
|
|
1752
|
+
gh run view $(gh run list --branch main --limit 1 --json databaseId -q '.[0].databaseId') --json jobs
|
|
1753
|
+
```
|
|
1754
|
+
|
|
1755
|
+
**Step 2: Release 생성 확인** (5-10초)
|
|
1756
|
+
```bash
|
|
1757
|
+
# GitHub Release Draft 확인
|
|
1758
|
+
gh release list --limit 3
|
|
1759
|
+
|
|
1760
|
+
# 특정 버전 Release 상세 정보
|
|
1761
|
+
gh release view v{new_version}
|
|
1762
|
+
```
|
|
1763
|
+
|
|
1764
|
+
**Step 3: PyPI 배포 확인** (30-60초)
|
|
1765
|
+
```bash
|
|
1766
|
+
# PyPI API로 패키지 버전 확인
|
|
1767
|
+
curl -s https://pypi.org/pypi/moai-adk/json | python3 -c "import sys, json; data=json.load(sys.stdin); print('Latest:', data['info']['version'])"
|
|
1768
|
+
|
|
1769
|
+
# 또는 PyPI 페이지 직접 확인
|
|
1770
|
+
open https://pypi.org/project/moai-adk/
|
|
1771
|
+
```
|
|
1772
|
+
|
|
1773
|
+
### ✨ 완료 확인
|
|
1774
|
+
|
|
1775
|
+
릴리즈가 성공적으로 완료되면 다음 모두 확인:
|
|
1776
|
+
|
|
1777
|
+
- ✅ GitHub Release 페이지: `https://github.com/modu-ai/moai-adk/releases/tag/v{new_version}`
|
|
1778
|
+
- ✅ PyPI 패키지: `https://pypi.org/project/moai-adk/{new_version}`
|
|
1779
|
+
- ✅ Git 태그: `git tag -l "v{new_version}"`
|
|
1780
|
+
- ✅ GitHub Actions: moai-gitflow.yml + release.yml 모두 success
|
|
1781
|
+
|
|
1782
|
+
**설치 테스트**:
|
|
1783
|
+
```bash
|
|
1784
|
+
# uv로 설치 테스트
|
|
1785
|
+
uv tool install moai-adk=={new_version}
|
|
1786
|
+
moai-adk --version
|
|
1787
|
+
```
|
|
1788
|
+
|
|
1789
|
+
---
|
|
1790
|
+
|
|
1791
|
+
## 🚀 Step 3.1 (참고): 버전 파일 업데이트 - GitHub Actions가 자동 수행
|
|
1792
|
+
|
|
1793
|
+
**⚠️ 중요**: MoAI-ADK는 **SSOT (Single Source of Truth)** 버전 관리를 사용합니다.
|
|
1794
|
+
|
|
1795
|
+
**버전 관리 구조**:
|
|
1796
|
+
```python
|
|
1797
|
+
# pyproject.toml (SSOT - 유일한 진실의 출처)
|
|
1798
|
+
version = "0.4.0"
|
|
1799
|
+
|
|
1800
|
+
# src/moai_adk/__init__.py (동적 로드)
|
|
1801
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
1802
|
+
|
|
1803
|
+
try:
|
|
1804
|
+
__version__ = version("moai-adk") # pyproject.toml에서 자동 로드
|
|
1805
|
+
except PackageNotFoundError:
|
|
1806
|
+
__version__ = "0.4.0-dev"
|
|
1807
|
+
```
|
|
1808
|
+
|
|
1809
|
+
**업데이트 방법**:
|
|
1810
|
+
|
|
1811
|
+
**1. pyproject.toml만 업데이트** (Edit 도구 사용):
|
|
1812
|
+
```bash
|
|
1813
|
+
# OLD: version = "0.3.0"
|
|
1814
|
+
# NEW: version = "0.3.1"
|
|
1815
|
+
```
|
|
1816
|
+
|
|
1817
|
+
**2. __init__.py는 수정하지 않음** (자동으로 새 버전 읽기)
|
|
1818
|
+
```bash
|
|
1819
|
+
# ❌ 수정 금지: __init__.py는 importlib.metadata로 자동 로드
|
|
1820
|
+
# ✅ pyproject.toml만 수정하면 자동으로 반영됨
|
|
1821
|
+
```
|
|
1822
|
+
|
|
1823
|
+
**3. editable install 재설치** (버전 메타데이터 업데이트):
|
|
1824
|
+
```bash
|
|
1825
|
+
uv pip install -e . --force-reinstall --no-deps
|
|
1826
|
+
```
|
|
1827
|
+
|
|
1828
|
+
### Step 3.1.5: 패키지 템플릿 동기화 (Post-Release Sync)
|
|
1829
|
+
|
|
1830
|
+
**커밋 전에 템플릿 파일 업데이트** (`Step 3.1 직후, Step 3.2 커밋 전`):
|
|
1831
|
+
|
|
1832
|
+
```bash
|
|
1833
|
+
echo "🔄 패키지 템플릿 동기화 중..."
|
|
1834
|
+
echo ""
|
|
1835
|
+
|
|
1836
|
+
# 프로젝트 정보 읽기 (.moai/config.json)
|
|
1837
|
+
PROJECT_NAME=$(rg '"name":\s*"([^"]+)"' .moai/config.json -o '$1' | head -1)
|
|
1838
|
+
PROJECT_OWNER=$(rg '"nickname":\s*"([^"]+)"' .moai/config.json -o '$1' | head -1)
|
|
1839
|
+
PROJECT_LOCALE=$(rg '"locale":\s*"([^"]+)"' .moai/config.json -o '$1' | head -1)
|
|
1840
|
+
PROJECT_LANGUAGE=$(rg '"language":\s*"([^"]+)"' .moai/config.json -o '$1' | head -1)
|
|
1841
|
+
|
|
1842
|
+
echo "📌 프로젝트 정보:"
|
|
1843
|
+
echo " - 이름: $PROJECT_NAME"
|
|
1844
|
+
echo " - Owner: $PROJECT_OWNER"
|
|
1845
|
+
echo " - Locale: $PROJECT_LOCALE"
|
|
1846
|
+
echo " - Language: $PROJECT_LANGUAGE"
|
|
1847
|
+
echo ""
|
|
1848
|
+
|
|
1849
|
+
# 템플릿 경로
|
|
1850
|
+
TEMPLATE_DIR="src/moai_adk/templates"
|
|
1851
|
+
TEMPLATE_CLAUDE="$TEMPLATE_DIR/.claude"
|
|
1852
|
+
TEMPLATE_MOAI="$TEMPLATE_DIR/.moai"
|
|
1853
|
+
|
|
1854
|
+
# 1️⃣ .claude/ 동기화
|
|
1855
|
+
echo "1️⃣ .claude/ 디렉토리 동기화 중..."
|
|
1856
|
+
|
|
1857
|
+
if [ ! -d "$TEMPLATE_CLAUDE" ]; then
|
|
1858
|
+
echo "⚠️ 템플릿 .claude/ 디렉토리를 찾을 수 없습니다"
|
|
1859
|
+
echo "→ 경로: $TEMPLATE_CLAUDE"
|
|
1860
|
+
else
|
|
1861
|
+
# .claude/ 디렉토리 전체 복사 (덮어쓰기)
|
|
1862
|
+
cp -rv "$TEMPLATE_CLAUDE/" ".claude/" 2>&1 | grep -E "^'[^']+' -> " | wc -l | xargs echo " ✅ 파일 동기화:"
|
|
1863
|
+
|
|
1864
|
+
# 백업 생성
|
|
1865
|
+
echo " 📦 백업 생성 중..."
|
|
1866
|
+
mkdir -p .moai-backups/pre-sync/
|
|
1867
|
+
cp -r .claude/.claude-backup .moai-backups/pre-sync/claude-$(date +%Y%m%d-%H%M%S) 2>/dev/null || true
|
|
1868
|
+
fi
|
|
1869
|
+
|
|
1870
|
+
echo ""
|
|
1871
|
+
|
|
1872
|
+
# 2️⃣ .moai/ 동기화 (config, project, memory 만)
|
|
1873
|
+
echo "2️⃣ .moai/ 디렉토리 동기화 중 (config, project, memory)..."
|
|
1874
|
+
|
|
1875
|
+
if [ ! -d "$TEMPLATE_MOAI" ]; then
|
|
1876
|
+
echo "⚠️ 템플릿 .moai/ 디렉토리를 찾을 수 없습니다"
|
|
1877
|
+
echo "→ 경로: $TEMPLATE_MOAI"
|
|
1878
|
+
else
|
|
1879
|
+
# 선택적 디렉토리만 동기화 (specs 제외)
|
|
1880
|
+
for subdir in config project memory; do
|
|
1881
|
+
if [ -d "$TEMPLATE_MOAI/$subdir" ]; then
|
|
1882
|
+
cp -rv "$TEMPLATE_MOAI/$subdir/" ".moai/$subdir/" 2>&1 | grep -E "^'[^']+' -> " | wc -l | xargs echo " ✅ .moai/$subdir - 파일 동기화:"
|
|
1883
|
+
fi
|
|
1884
|
+
done
|
|
1885
|
+
|
|
1886
|
+
# 백업 생성
|
|
1887
|
+
echo " 📦 백업 생성 중..."
|
|
1888
|
+
mkdir -p .moai-backups/pre-sync/
|
|
1889
|
+
cp -r .moai/.moai-backup .moai-backups/pre-sync/moai-$(date +%Y%m%d-%H%M%S) 2>/dev/null || true
|
|
1890
|
+
fi
|
|
1891
|
+
|
|
1892
|
+
echo ""
|
|
1893
|
+
|
|
1894
|
+
# 3️⃣ CLAUDE.md 템플릿 변수 치환
|
|
1895
|
+
echo "3️⃣ CLAUDE.md 변수 치환 중..."
|
|
1896
|
+
|
|
1897
|
+
TEMPLATE_CLAUDE_MD="$TEMPLATE_DIR/CLAUDE.md"
|
|
1898
|
+
|
|
1899
|
+
if [ -f "$TEMPLATE_CLAUDE_MD" ]; then
|
|
1900
|
+
# CLAUDE.md 복사
|
|
1901
|
+
cp "$TEMPLATE_CLAUDE_MD" CLAUDE.md
|
|
1902
|
+
|
|
1903
|
+
# .moai/config.json에서 추가 정보 추출
|
|
1904
|
+
CONVERSATION_LANGUAGE=$(rg '"conversation_language":\s*"([^"]+)"' .moai/config.json -o '$1' | head -1)
|
|
1905
|
+
CONVERSATION_LANGUAGE_NAME=$(rg '"conversation_language_name":\s*"([^"]+)"' .moai/config.json -o '$1' | head -1)
|
|
1906
|
+
CODEBASE_LANGUAGE=$(rg '"language":\s*"([^"]+)"' .moai/config.json -o '$1' | head -1)
|
|
1907
|
+
|
|
1908
|
+
# 변수 치환 (sed 사용, 플레이스홀더 기반)
|
|
1909
|
+
# {{project_name}} → $PROJECT_NAME
|
|
1910
|
+
sed -i '' "s|{{project_name}}|$PROJECT_NAME|g" CLAUDE.md
|
|
1911
|
+
sed -i '' "s|{{project_owner}}|$PROJECT_OWNER|g" CLAUDE.md
|
|
1912
|
+
sed -i '' "s|{{locale}}|$PROJECT_LOCALE|g" CLAUDE.md
|
|
1913
|
+
sed -i '' "s|{{conversation_language}}|$CONVERSATION_LANGUAGE|g" CLAUDE.md
|
|
1914
|
+
sed -i '' "s|{{conversation_language_name}}|$CONVERSATION_LANGUAGE_NAME|g" CLAUDE.md
|
|
1915
|
+
sed -i '' "s|{{codebase_language}}|$CODEBASE_LANGUAGE|g" CLAUDE.md
|
|
1916
|
+
|
|
1917
|
+
# 대문자 플레이스홀더도 처리
|
|
1918
|
+
sed -i '' "s|{{PROJECT_NAME}}|$PROJECT_NAME|g" CLAUDE.md
|
|
1919
|
+
sed -i '' "s|{{PROJECT_OWNER}}|$PROJECT_OWNER|g" CLAUDE.md
|
|
1920
|
+
sed -i '' "s|{{PROJECT_LOCALE}}|$PROJECT_LOCALE|g" CLAUDE.md
|
|
1921
|
+
|
|
1922
|
+
echo " ✅ CLAUDE.md 생성 완료"
|
|
1923
|
+
echo " - project_name: $PROJECT_NAME"
|
|
1924
|
+
echo " - project_owner: $PROJECT_OWNER"
|
|
1925
|
+
echo " - locale: $PROJECT_LOCALE"
|
|
1926
|
+
echo " - conversation_language: $CONVERSATION_LANGUAGE"
|
|
1927
|
+
echo " - conversation_language_name: $CONVERSATION_LANGUAGE_NAME"
|
|
1928
|
+
echo " - codebase_language: $CODEBASE_LANGUAGE"
|
|
1929
|
+
else
|
|
1930
|
+
echo "⚠️ 템플릿 CLAUDE.md를 찾을 수 없습니다"
|
|
1931
|
+
fi
|
|
1932
|
+
|
|
1933
|
+
echo ""
|
|
1934
|
+
echo "📢 동기화 완료!"
|
|
1935
|
+
echo "→ 다음 단계: Git 커밋 (버전 + 템플릿 파일 포함)"
|
|
1936
|
+
```
|
|
1937
|
+
|
|
1938
|
+
**동기화 검증 체크리스트**:
|
|
1939
|
+
- ✅ `.claude/` 디렉토리 업데이트됨 (agents, commands, hooks, output-styles, skills, settings.json)
|
|
1940
|
+
- ✅ `.moai/project/` 업데이트됨 (product.md, structure.md, tech.md)
|
|
1941
|
+
- ✅ `.moai/memory/` 업데이트됨 (개발 가이드, SPEC 메타데이터)
|
|
1942
|
+
- ✅ `CLAUDE.md` 생성되고 변수 치환됨 (프로젝트명, Owner, 언어)
|
|
1943
|
+
- ✅ 백업 생성됨 (`.moai-backups/pre-sync/`)
|
|
1944
|
+
|
|
1945
|
+
### Step 3.1.6: 템플릿 동기화 검증 (Integrity Check)
|
|
1946
|
+
|
|
1947
|
+
**목적**: 템플릿이 제대로 동기화되었는지 검증하고 불일치 항목 보고
|
|
1948
|
+
|
|
1949
|
+
**검증 스크립트**:
|
|
1950
|
+
```bash
|
|
1951
|
+
echo "🔍 Step 3.1.6: 템플릿 동기화 검증 중..."
|
|
1952
|
+
echo ""
|
|
1953
|
+
|
|
1954
|
+
TEMPLATE_DIR="src/moai_adk/templates"
|
|
1955
|
+
TEMPLATE_CLAUDE="$TEMPLATE_DIR/.claude"
|
|
1956
|
+
TEMPLATE_MOAI="$TEMPLATE_DIR/.moai"
|
|
1957
|
+
|
|
1958
|
+
# 1️⃣ .claude/ 동기화 검증
|
|
1959
|
+
echo "1️⃣ .claude/ 디렉토리 검증..."
|
|
1960
|
+
|
|
1961
|
+
if [ -d "$TEMPLATE_CLAUDE" ] && [ -d ".claude" ]; then
|
|
1962
|
+
# 디렉토리 간 diff 수행 (바이너리 제외)
|
|
1963
|
+
DIFF_COUNT=$(diff -r "$TEMPLATE_CLAUDE" ".claude" \
|
|
1964
|
+
--exclude='*.pyc' --exclude='__pycache__' \
|
|
1965
|
+
--exclude='.DS_Store' 2>/dev/null | wc -l)
|
|
1966
|
+
|
|
1967
|
+
if [ "$DIFF_COUNT" -eq 0 ]; then
|
|
1968
|
+
echo " ✅ .claude/ 완벽하게 동기화됨"
|
|
1969
|
+
else
|
|
1970
|
+
echo " ⚠️ .claude/ 차이 감지됨 ($DIFF_COUNT 라인)"
|
|
1971
|
+
echo " → 첫 5개 차이:"
|
|
1972
|
+
diff -r "$TEMPLATE_CLAUDE" ".claude" \
|
|
1973
|
+
--exclude='*.pyc' --exclude='__pycache__' \
|
|
1974
|
+
--exclude='.DS_Store' 2>/dev/null | head -5
|
|
1975
|
+
fi
|
|
1976
|
+
else
|
|
1977
|
+
echo " ⚠️ .claude/ 디렉토리 구조 문제"
|
|
1978
|
+
fi
|
|
1979
|
+
|
|
1980
|
+
echo ""
|
|
1981
|
+
|
|
1982
|
+
# 2️⃣ .moai/ 구성 파일 검증
|
|
1983
|
+
echo "2️⃣ .moai/ 구성 파일 검증..."
|
|
1984
|
+
|
|
1985
|
+
for FILE in config.json; do
|
|
1986
|
+
if [ -f ".moai/$FILE" ] && [ -f "$TEMPLATE_MOAI/$FILE" ]; then
|
|
1987
|
+
if diff ".moai/$FILE" "$TEMPLATE_MOAI/$FILE" > /dev/null 2>&1; then
|
|
1988
|
+
echo " ✅ .moai/$FILE 최신 버전"
|
|
1989
|
+
else
|
|
1990
|
+
echo " ⚠️ .moai/$FILE 버전 차이 있음"
|
|
1991
|
+
echo " → 수동 검토 권장"
|
|
1992
|
+
fi
|
|
1993
|
+
fi
|
|
1994
|
+
done
|
|
1995
|
+
|
|
1996
|
+
echo ""
|
|
1997
|
+
|
|
1998
|
+
# 3️⃣ CLAUDE.md 검증
|
|
1999
|
+
echo "3️⃣ CLAUDE.md 검증..."
|
|
2000
|
+
|
|
2001
|
+
if [ -f "CLAUDE.md" ]; then
|
|
2002
|
+
# 템플릿 변수 치환 확인
|
|
2003
|
+
UNREPLACED_VARS=$(grep -c '{{' CLAUDE.md 2>/dev/null || echo "0")
|
|
2004
|
+
|
|
2005
|
+
if [ "$UNREPLACED_VARS" -eq 0 ]; then
|
|
2006
|
+
echo " ✅ CLAUDE.md 변수 치환 완료"
|
|
2007
|
+
else
|
|
2008
|
+
echo " ❌ CLAUDE.md에 미치환 변수 $UNREPLACED_VARS개 발견"
|
|
2009
|
+
grep '{{' CLAUDE.md | head -3
|
|
2010
|
+
exit 1
|
|
2011
|
+
fi
|
|
2012
|
+
|
|
2013
|
+
# 파일 크기 검증
|
|
2014
|
+
CLAUDE_SIZE=$(wc -c < CLAUDE.md)
|
|
2015
|
+
if [ "$CLAUDE_SIZE" -gt 500 ]; then
|
|
2016
|
+
echo " ✅ CLAUDE.md 파일 크기 정상 ($CLAUDE_SIZE bytes)"
|
|
2017
|
+
else
|
|
2018
|
+
echo " ⚠️ CLAUDE.md 파일이 너무 작음 ($CLAUDE_SIZE bytes)"
|
|
2019
|
+
fi
|
|
2020
|
+
else
|
|
2021
|
+
echo " ⚠️ CLAUDE.md가 생성되지 않음"
|
|
2022
|
+
fi
|
|
2023
|
+
|
|
2024
|
+
echo ""
|
|
2025
|
+
|
|
2026
|
+
# 4️⃣ 설정 스키마 버전 검증
|
|
2027
|
+
echo "4️⃣ 설정 스키마 버전 검증..."
|
|
2028
|
+
|
|
2029
|
+
if [ -f ".moai/config.json" ] && [ -f "$TEMPLATE_MOAI/config.json" ]; then
|
|
2030
|
+
LOCAL_VERSION=$(grep '"version"' .moai/config.json | head -1 | grep -o '[0-9.]*' | head -1 || echo "unknown")
|
|
2031
|
+
TEMPLATE_VERSION=$(grep '"version"' "$TEMPLATE_MOAI/config.json" | head -1 | grep -o '[0-9.]*' | head -1 || echo "unknown")
|
|
2032
|
+
|
|
2033
|
+
if [ "$LOCAL_VERSION" = "$TEMPLATE_VERSION" ]; then
|
|
2034
|
+
echo " ✅ 설정 스키마 버전 일치: $LOCAL_VERSION"
|
|
2035
|
+
else
|
|
2036
|
+
echo " ⚠️ 설정 스키마 버전 불일치"
|
|
2037
|
+
echo " - Local: $LOCAL_VERSION"
|
|
2038
|
+
echo " - Template: $TEMPLATE_VERSION"
|
|
2039
|
+
echo " → 설정 마이그레이션 확인 필요"
|
|
2040
|
+
fi
|
|
2041
|
+
fi
|
|
2042
|
+
|
|
2043
|
+
echo ""
|
|
2044
|
+
|
|
2045
|
+
# 5️⃣ 안전성 검증 (백업 확인)
|
|
2046
|
+
echo "5️⃣ 백업 파일 검증..."
|
|
2047
|
+
|
|
2048
|
+
if [ -d ".moai-backups/pre-sync" ]; then
|
|
2049
|
+
BACKUP_COUNT=$(ls .moai-backups/pre-sync/ | wc -l)
|
|
2050
|
+
echo " ✅ 백업 디렉토리 생성됨 ($BACKUP_COUNT개 항목)"
|
|
2051
|
+
else
|
|
2052
|
+
echo " ⚠️ 백업 디렉토리가 생성되지 않음"
|
|
2053
|
+
fi
|
|
2054
|
+
|
|
2055
|
+
echo ""
|
|
2056
|
+
|
|
2057
|
+
# 최종 검증 결과
|
|
2058
|
+
echo "✅ 템플릿 동기화 검증 완료"
|
|
2059
|
+
echo ""
|
|
2060
|
+
echo "📝 다음 단계:"
|
|
2061
|
+
echo " 1. 로컬 .claude/, .moai/ 파일 검토"
|
|
2062
|
+
echo " 2. CLAUDE.md에 프로젝트 지침 추가 (선택사항)"
|
|
2063
|
+
echo " 3. git add -A && git commit"
|
|
2064
|
+
echo " 4. GitHub에 푸시"
|
|
2065
|
+
```
|
|
2066
|
+
|
|
2067
|
+
**검증 항목**:
|
|
2068
|
+
- ✅ Package template (.claude/)과 Local (.claude/) 동기화 상태
|
|
2069
|
+
- ✅ 설정 파일 (.moai/config.json) 버전 호환성
|
|
2070
|
+
- ✅ CLAUDE.md 템플릿 변수 완전 치환
|
|
2071
|
+
- ✅ 파일 백업 생성 확인
|
|
2072
|
+
- ⚠️ 불일치 항목 발견 시 경고
|
|
2073
|
+
|
|
2074
|
+
---
|
|
2075
|
+
|
|
2076
|
+
## 🤖 GitHub Actions의 자동화 (부분적)
|
|
2077
|
+
|
|
2078
|
+
### ⚠️ 현실적인 자동화 한계
|
|
2079
|
+
|
|
2080
|
+
GitHub Actions는 **이상적으로는** 다음 모든 단계를 자동으로 처리해야 하지만, **실제로는** 몇 가지 수동 개입이 필요할 수 있습니다:
|
|
2081
|
+
|
|
2082
|
+
```
|
|
2083
|
+
이상적인 흐름:
|
|
2084
|
+
PR 병합 → moai-gitflow.yml 감지 → Tag 생성 → Release 생성 → release.yml 트리거 → PyPI 배포
|
|
2085
|
+
|
|
2086
|
+
현실적인 흐름:
|
|
2087
|
+
PR 병합 → moai-gitflow.yml (merge commit 감지 실패) → 수동 개입 필요
|
|
2088
|
+
또는 Release Pipeline 수정 필요
|
|
2089
|
+
또는 수동 배포 필요
|
|
2090
|
+
```
|
|
2091
|
+
|
|
2092
|
+
**자동화가 작동하는 조건**:
|
|
2093
|
+
1. ✅ Release commit 감지: PR 본문에 "🔖 RELEASE: v..." 포함
|
|
2094
|
+
2. ✅ Release Pipeline 실행: moai-release-pipeline.yml이 패턴 감지
|
|
2095
|
+
3. ✅ PyPI 배포: release.yml이 GitHub Release (published) 감지
|
|
2096
|
+
|
|
2097
|
+
**자동화가 실패하는 경우**:
|
|
2098
|
+
1. ❌ merge commit 형식이 Release Pattern을 감지하지 못함 (가장 흔함)
|
|
2099
|
+
2. ❌ GitHub Release가 Draft 상태로 남아있음
|
|
2100
|
+
3. ❌ PYPI_API_TOKEN 미설정
|
|
2101
|
+
|
|
2102
|
+
### ✅ 자동화가 정상 작동 시 처리 단계
|
|
2103
|
+
|
|
2104
|
+
PR이 main에 병합되고 Release Pipeline이 정상 작동하면:
|
|
2105
|
+
|
|
2106
|
+
### ✅ Step 3.2a: SPEC Issue Auto-Detection (실행 필수)
|
|
2107
|
+
|
|
2108
|
+
**⚠️ CRITICAL**: 이 단계를 반드시 실행하여 SPEC 이슈가 자동으로 닫히도록 해야 합니다.
|
|
2109
|
+
|
|
2110
|
+
**SPEC 이슈 자동 감지 및 Closes 참조 생성:**
|
|
2111
|
+
```bash
|
|
2112
|
+
echo "🔍 Detecting SPEC issues for auto-close..."
|
|
2113
|
+
|
|
2114
|
+
# 1. .moai/specs 디렉토리에서 SPEC ID 찾기
|
|
2115
|
+
SPEC_ID=$(find .moai/specs -maxdepth 2 -name "spec.md" -exec rg '@SPEC:[A-Z]+-[A-Z]+-\d+' --only-matching {} \; 2>/dev/null | head -1 | sed 's/@SPEC://')
|
|
2116
|
+
|
|
2117
|
+
if [ -z "$SPEC_ID" ]; then
|
|
2118
|
+
echo "ℹ️ No SPEC detected for this release"
|
|
2119
|
+
CLOSE_ISSUE_LINE=""
|
|
2120
|
+
else
|
|
2121
|
+
echo "✅ SPEC detected: $SPEC_ID"
|
|
2122
|
+
|
|
2123
|
+
# 2. GitHub에서 해당 SPEC 이슈 찾기 (title에 SPEC ID 포함된 것)
|
|
2124
|
+
SPEC_ISSUE=$(gh issue list --search "$SPEC_ID in:title" --state open --json number -q '.[0].number' 2>/dev/null)
|
|
2125
|
+
|
|
2126
|
+
if [ -z "$SPEC_ISSUE" ]; then
|
|
2127
|
+
echo "ℹ️ No open GitHub issue found for $SPEC_ID"
|
|
2128
|
+
echo "→ Skipping auto-close (issue may already be closed or not exist)"
|
|
2129
|
+
CLOSE_ISSUE_LINE=""
|
|
2130
|
+
else
|
|
2131
|
+
echo "✅ Found open issue: #$SPEC_ISSUE ($SPEC_ID)"
|
|
2132
|
+
echo "→ Will add 'Closes #$SPEC_ISSUE' to commit message"
|
|
2133
|
+
CLOSE_ISSUE_LINE="\n\nCloses #${SPEC_ISSUE}"
|
|
2134
|
+
fi
|
|
2135
|
+
fi
|
|
2136
|
+
|
|
2137
|
+
echo ""
|
|
2138
|
+
echo "📝 Commit message will include:"
|
|
2139
|
+
if [ -n "$CLOSE_ISSUE_LINE" ]; then
|
|
2140
|
+
echo " - @SPEC:$SPEC_ID (TAG reference for traceability)"
|
|
2141
|
+
echo " - Closes #$SPEC_ISSUE (GitHub auto-close trigger)"
|
|
2142
|
+
else
|
|
2143
|
+
echo " - Standard release message (no SPEC issue to close)"
|
|
2144
|
+
fi
|
|
2145
|
+
```
|
|
2146
|
+
|
|
2147
|
+
**검증 체크리스트:**
|
|
2148
|
+
- ✅ SPEC ID 감지 확인 (e.g., SPEC-DOCS-004)
|
|
2149
|
+
- ✅ GitHub issue 번호 확인 (e.g., #116)
|
|
2150
|
+
- ✅ "Closes #XX" 문구 생성 확인
|
|
2151
|
+
- ⚠️ 실패 시: 수동으로 issue 번호 확인 후 CLOSE_ISSUE_LINE 설정
|
|
2152
|
+
|
|
2153
|
+
### ✅ Step 3.2b: Git 커밋 생성 (SPEC 이슈 참조 포함)
|
|
2154
|
+
|
|
2155
|
+
**릴리즈 커밋 메시지 생성 및 커밋:**
|
|
2156
|
+
```bash
|
|
2157
|
+
echo "📝 Creating release commit..."
|
|
2158
|
+
|
|
2159
|
+
# 커밋 메시지 생성 (CLOSE_ISSUE_LINE 포함)
|
|
2160
|
+
COMMIT_MSG="🔖 RELEASE: v${new_version}
|
|
2161
|
+
|
|
2162
|
+
Release v${new_version}
|
|
2163
|
+
|
|
2164
|
+
**변경사항**:
|
|
2165
|
+
- 버전 관리 (SSOT): pyproject.toml ${current_version} → ${new_version}
|
|
2166
|
+
- 템플릿 동기화 (자동)
|
|
2167
|
+
- CLAUDE.md: 프로젝트 변수 적용
|
|
2168
|
+
|
|
2169
|
+
**SPEC Reference**:
|
|
2170
|
+
@SPEC:${SPEC_ID}${CLOSE_ISSUE_LINE}
|
|
2171
|
+
|
|
2172
|
+
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
|
2173
|
+
|
|
2174
|
+
Co-Authored-By: Alfred <alfred@mo.ai.kr>"
|
|
2175
|
+
|
|
2176
|
+
# Git commit 실행
|
|
2177
|
+
git add pyproject.toml uv.lock
|
|
2178
|
+
git commit -m "$COMMIT_MSG"
|
|
2179
|
+
|
|
2180
|
+
if [ $? -eq 0 ]; then
|
|
2181
|
+
echo "✅ Release commit created: $(git rev-parse --short HEAD)"
|
|
2182
|
+
echo "📌 Commit message preview:"
|
|
2183
|
+
git log -1 --pretty=format:"%B"
|
|
2184
|
+
else
|
|
2185
|
+
echo "❌ Failed to create release commit"
|
|
2186
|
+
exit 1
|
|
2187
|
+
fi
|
|
2188
|
+
```
|
|
2189
|
+
|
|
2190
|
+
**효과:**
|
|
2191
|
+
- ✅ GitHub가 merge 시 자동으로 issue #XX를 close
|
|
2192
|
+
- ✅ SPEC 문서와 GitHub Issue의 라이프사이클 자동 동기화
|
|
2193
|
+
- ✅ 개발자의 수동 close 작업 제거
|
|
2194
|
+
- ✅ @TAG와 Closes 참조 모두 포함으로 완벽한 traceability
|
|
2195
|
+
|
|
2196
|
+
### ✅ Step 3.3: Git Annotated Tag 생성 (자동)
|
|
2197
|
+
GitHub Actions가 자동으로 생성:
|
|
2198
|
+
```
|
|
2199
|
+
v{new_version}
|
|
2200
|
+
|
|
2201
|
+
Release v{new_version}
|
|
2202
|
+
Released: {YYYY-MM-DD}
|
|
2203
|
+
```
|
|
2204
|
+
|
|
2205
|
+
### ✅ Step 3.4: 패키지 빌드 (자동)
|
|
2206
|
+
GitHub Actions가 `uv build` 실행하여 wheel과 tar.gz 생성
|
|
2207
|
+
|
|
2208
|
+
### ✅ Step 3.5: PyPI 배포 (자동)
|
|
2209
|
+
GitHub Actions가 `uv publish` 실행하여 PyPI에 배포
|
|
2210
|
+
|
|
2211
|
+
**🔒 보안**: PyPI 토큰은 GitHub Secrets에서 관리되므로, 로컬에서 설정할 필요 없음
|
|
2212
|
+
|
|
2213
|
+
### ✅ Step 3.6: GitHub Release 생성 (자동)
|
|
2214
|
+
|
|
2215
|
+
#### 📋 Release Notes Format Guide
|
|
2216
|
+
|
|
2217
|
+
**Title Format** (English only):
|
|
2218
|
+
```
|
|
2219
|
+
🔖 v[VERSION] | [TYPE] | [Release Title]
|
|
2220
|
+
|
|
2221
|
+
Examples:
|
|
2222
|
+
🔖 v0.5.4 | patch | Feature Enhancement & uv Standardization
|
|
2223
|
+
🔖 v0.6.0 | minor | New Skill System Implementation
|
|
2224
|
+
🔖 v1.0.0 | major | First Stable Release
|
|
2225
|
+
```
|
|
2226
|
+
|
|
2227
|
+
⚠️ **Important**: All release information must be in **English only** for international consistency.
|
|
2228
|
+
|
|
2229
|
+
**Release Notes Structure** (English only):
|
|
2230
|
+
|
|
2231
|
+
```
|
|
2232
|
+
# 🎉 Release v[VERSION] | [TYPE] | [Release Title]
|
|
2233
|
+
|
|
2234
|
+
**Version**: v[VERSION]
|
|
2235
|
+
**Type**: [patch | minor | major]
|
|
2236
|
+
**Release Date**: YYYY-MM-DD
|
|
2237
|
+
|
|
2238
|
+
## What's Changed
|
|
2239
|
+
|
|
2240
|
+
### ✨ New Features (N)
|
|
2241
|
+
- Feature 1 description
|
|
2242
|
+
- Feature 2 description
|
|
2243
|
+
|
|
2244
|
+
### 🐛 Bug Fixes (N)
|
|
2245
|
+
- Bug fix 1 description
|
|
2246
|
+
- Bug fix 2 description
|
|
2247
|
+
|
|
2248
|
+
### ♻️ Improvements (N)
|
|
2249
|
+
- Improvement 1 description
|
|
2250
|
+
- Improvement 2 description
|
|
2251
|
+
|
|
2252
|
+
### 📚 Documentation (N)
|
|
2253
|
+
- Documentation 1 update
|
|
2254
|
+
- Documentation 2 update
|
|
2255
|
+
|
|
2256
|
+
## Quality Assurance Results
|
|
2257
|
+
|
|
2258
|
+
| Metric | Result | Status |
|
|
2259
|
+
|--------|--------|--------|
|
|
2260
|
+
| Tests Passed | X/X (Y%) | ✅ Passed |
|
|
2261
|
+
| Code Coverage | Y% | ✅ Target Met |
|
|
2262
|
+
| Linting | 0 errors | ✅ Passed |
|
|
2263
|
+
| Type Checking | 0 issues | ✅ Passed |
|
|
2264
|
+
| Security Scan | 0 vulnerabilities | ✅ Passed |
|
|
2265
|
+
|
|
2266
|
+
## Installation
|
|
2267
|
+
|
|
2268
|
+
### Using uv (Recommended)
|
|
2269
|
+
\`\`\`bash
|
|
2270
|
+
uv tool install moai-adk==[VERSION]
|
|
2271
|
+
\`\`\`
|
|
2272
|
+
|
|
2273
|
+
### Using pip (Legacy)
|
|
2274
|
+
\`\`\`bash
|
|
2275
|
+
pip install moai-adk==[VERSION]
|
|
2276
|
+
\`\`\`
|
|
2277
|
+
|
|
2278
|
+
## Full Changelog
|
|
2279
|
+
|
|
2280
|
+
Compare all changes: [v[PREV]...v[VERSION]](https://github.com/modu-ai/moai-adk/compare/v[PREV]...v[VERSION])
|
|
2281
|
+
|
|
2282
|
+
## Contributors
|
|
2283
|
+
|
|
2284
|
+
Thanks to all contributors who made this release possible.
|
|
2285
|
+
|
|
2286
|
+
---
|
|
2287
|
+
|
|
2288
|
+
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
|
2289
|
+
|
|
2290
|
+
Co-Authored-By: Alfred <alfred@mo.ai.kr>
|
|
2291
|
+
```
|
|
2292
|
+
|
|
2293
|
+
#### 작성 팁
|
|
2294
|
+
|
|
2295
|
+
- ✅ **Use clear English throughout**
|
|
2296
|
+
- ✅ **Highlight changes compared to previous version**
|
|
2297
|
+
- ✅ **Use consistent terminology**
|
|
2298
|
+
- ✅ **Include accurate metrics** (test pass rate, coverage)
|
|
2299
|
+
- ✅ **Verify links** (v[PREV] and v[VERSION] accurately)
|
|
2300
|
+
|
|
2301
|
+
**Create Release with gh CLI** (English only):
|
|
2302
|
+
```bash
|
|
2303
|
+
# Generate release notes (use template above)
|
|
2304
|
+
release_title="🔖 v{new_version} | {VERSION_TYPE} | {Release Title}"
|
|
2305
|
+
|
|
2306
|
+
release_notes="# 🎉 Release v{new_version} | {VERSION_TYPE}
|
|
2307
|
+
|
|
2308
|
+
**Version**: v{new_version}
|
|
2309
|
+
**Type**: {VERSION_TYPE}
|
|
2310
|
+
**Release Date**: $(date +%Y-%m-%d)
|
|
2311
|
+
|
|
2312
|
+
## What's Changed
|
|
2313
|
+
|
|
2314
|
+
### ✨ New Features (N)
|
|
2315
|
+
- Feature 1 description
|
|
2316
|
+
- Feature 2 description
|
|
2317
|
+
|
|
2318
|
+
### 🐛 Bug Fixes (N)
|
|
2319
|
+
- Bug fix 1 description
|
|
2320
|
+
- Bug fix 2 description
|
|
2321
|
+
|
|
2322
|
+
### ♻️ Improvements (N)
|
|
2323
|
+
- Improvement 1 description
|
|
2324
|
+
- Improvement 2 description
|
|
2325
|
+
|
|
2326
|
+
### 📚 Documentation (N)
|
|
2327
|
+
- Documentation 1 update
|
|
2328
|
+
- Documentation 2 update
|
|
2329
|
+
|
|
2330
|
+
## Quality Assurance Results
|
|
2331
|
+
|
|
2332
|
+
| Metric | Result | Status |
|
|
2333
|
+
|--------|--------|--------|
|
|
2334
|
+
| Tests Passed | X/X (Y%) | ✅ Passed |
|
|
2335
|
+
| Code Coverage | Y% | ✅ Target Met |
|
|
2336
|
+
| Linting | 0 errors | ✅ Passed |
|
|
2337
|
+
| Type Checking | 0 issues | ✅ Passed |
|
|
2338
|
+
| Security Scan | 0 vulnerabilities | ✅ Passed |
|
|
2339
|
+
|
|
2340
|
+
## Installation
|
|
2341
|
+
|
|
2342
|
+
### Using uv (Recommended)
|
|
2343
|
+
\`\`\`bash
|
|
2344
|
+
uv tool install moai-adk=={new_version}
|
|
2345
|
+
\`\`\`
|
|
2346
|
+
|
|
2347
|
+
### Using pip (Legacy)
|
|
2348
|
+
\`\`\`bash
|
|
2349
|
+
pip install moai-adk=={new_version}
|
|
2350
|
+
\`\`\`
|
|
2351
|
+
|
|
2352
|
+
## Full Changelog
|
|
2353
|
+
|
|
2354
|
+
Compare all changes: [v{current_version}...v{new_version}](https://github.com/modu-ai/moai-adk/compare/v{current_version}...v{new_version})
|
|
2355
|
+
|
|
2356
|
+
## Contributors
|
|
2357
|
+
|
|
2358
|
+
Thanks to all contributors who made this release possible.
|
|
2359
|
+
|
|
2360
|
+
---
|
|
2361
|
+
|
|
2362
|
+
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
|
2363
|
+
|
|
2364
|
+
Co-Authored-By: Alfred <alfred@mo.ai.kr>"
|
|
2365
|
+
|
|
2366
|
+
# Create GitHub Release (Draft, English only)
|
|
2367
|
+
gh release create "v{new_version}" \
|
|
2368
|
+
--title "$release_title" \
|
|
2369
|
+
--notes "$release_notes" \
|
|
2370
|
+
--draft
|
|
2371
|
+
|
|
2372
|
+
echo "ℹ️ GitHub Release created as Draft"
|
|
2373
|
+
echo "→ https://github.com/modu-ai/moai-adk/releases/tag/v{new_version}"
|
|
2374
|
+
echo "→ Verify content and publish the release..."
|
|
2375
|
+
```
|
|
2376
|
+
|
|
2377
|
+
### Step 3.7: Publish GitHub Release (Draft → Published)
|
|
2378
|
+
|
|
2379
|
+
**Convert Draft Release to Published**:
|
|
2380
|
+
```bash
|
|
2381
|
+
# Change GitHub Release Draft to Published
|
|
2382
|
+
echo "📢 Publishing GitHub Release..."
|
|
2383
|
+
gh release edit "v{new_version}" --draft=false
|
|
2384
|
+
|
|
2385
|
+
if [ $? -ne 0 ]; then
|
|
2386
|
+
echo "❌ Failed to publish GitHub Release"
|
|
2387
|
+
echo "→ Check: gh CLI authentication status"
|
|
2388
|
+
echo "→ Solution: gh auth login or gh auth refresh"
|
|
2389
|
+
exit 1
|
|
2390
|
+
fi
|
|
2391
|
+
|
|
2392
|
+
echo "✅ GitHub Release Published!"
|
|
2393
|
+
echo "→ Latest releases: https://github.com/modu-ai/moai-adk/releases"
|
|
2394
|
+
echo "→ Release page: https://github.com/modu-ai/moai-adk/releases/tag/v{new_version}"
|
|
2395
|
+
```
|
|
2396
|
+
|
|
2397
|
+
**Verification Checklist**:
|
|
2398
|
+
- ✅ Verify Draft status before publishing
|
|
2399
|
+
- ✅ Confirm "Latest" release is updated
|
|
2400
|
+
- ✅ Verify GitHub Release page is public
|
|
2401
|
+
|
|
2402
|
+
---
|
|
2403
|
+
|
|
2404
|
+
### Step 3.8: Final Report
|
|
2405
|
+
|
|
2406
|
+
```markdown
|
|
2407
|
+
# ✅ Release Complete: v{new_version}
|
|
2408
|
+
|
|
2409
|
+
## Release Results
|
|
2410
|
+
✅ Version updated (pyproject.toml)
|
|
2411
|
+
✅ Git tag created and pushed: v{new_version}
|
|
2412
|
+
✅ Package built (dist/)
|
|
2413
|
+
✅ Deployed to PyPI (https://pypi.org/project/moai-adk/{new_version}/)
|
|
2414
|
+
✅ GitHub Release published (https://github.com/modu-ai/moai-adk/releases/tag/v{new_version})
|
|
2415
|
+
|
|
2416
|
+
## Next Steps
|
|
2417
|
+
1. Verify GitHub Release page
|
|
2418
|
+
2. Execute Step 3.9: Post-Release Cleanup
|
|
2419
|
+
3. Start planning next feature with /alfred:1-plan
|
|
2420
|
+
|
|
2421
|
+
## Installation Test
|
|
2422
|
+
```bash
|
|
2423
|
+
# Test installation with uv tool (Recommended)
|
|
2424
|
+
uv tool install moai-adk=={new_version}
|
|
2425
|
+
moai-adk --version
|
|
2426
|
+
|
|
2427
|
+
# Or install with pip (Legacy)
|
|
2428
|
+
# pip install moai-adk=={new_version}
|
|
2429
|
+
# moai-adk --version
|
|
2430
|
+
```
|
|
2431
|
+
```
|
|
2432
|
+
|
|
2433
|
+
### Step 3.10: 패키지 템플릿 동기화 및 변수 최적화 (필수)
|
|
2434
|
+
|
|
2435
|
+
**⚠️ CRITICAL**: PyPI 배포 완료 후 반드시 실행. 로컬 프로젝트에 최신 패키지 템플릿을 동기화합니다.
|
|
2436
|
+
|
|
2437
|
+
**목적**:
|
|
2438
|
+
- 패키지 템플릿 (`src/moai_adk/templates/`)의 최신 변경사항을 로컬 프로젝트에 반영
|
|
2439
|
+
- `config.json` 버전 및 메타데이터 최적화
|
|
2440
|
+
- CLAUDE.md 프로젝트 지침 업데이트
|
|
2441
|
+
- 패키지 템플릿이 source of truth 원칙 유지
|
|
2442
|
+
|
|
2443
|
+
**패키지 템플릿 동기화 스크립트:**
|
|
2444
|
+
|
|
2445
|
+
```bash
|
|
2446
|
+
echo "🔄 패키지 템플릿 동기화 및 최적화 중..."
|
|
2447
|
+
echo ""
|
|
2448
|
+
|
|
2449
|
+
# 1️⃣ 버전 정보 수집
|
|
2450
|
+
CURRENT_VERSION=$(rg "^version = " pyproject.toml -A0 -o '$1' | head -1 | sed 's/version = "\(.*\)"/\1/')
|
|
2451
|
+
echo "📌 배포 완료 버전: v$CURRENT_VERSION"
|
|
2452
|
+
echo ""
|
|
2453
|
+
|
|
2454
|
+
# 2️⃣ 패키지 템플릿 디렉토리 경로 설정
|
|
2455
|
+
TEMPLATE_DIR="src/moai_adk/templates"
|
|
2456
|
+
TEMPLATE_CONFIG="$TEMPLATE_DIR/.moai/config.json"
|
|
2457
|
+
|
|
2458
|
+
if [ ! -f "$TEMPLATE_CONFIG" ]; then
|
|
2459
|
+
echo "❌ 패키지 템플릿을 찾을 수 없습니다: $TEMPLATE_CONFIG"
|
|
2460
|
+
exit 1
|
|
2461
|
+
fi
|
|
2462
|
+
|
|
2463
|
+
echo "📦 패키지 템플릿 위치: $TEMPLATE_DIR"
|
|
2464
|
+
echo ""
|
|
2465
|
+
|
|
2466
|
+
# 3️⃣ .claude/ 동기화 (agents, commands, hooks, output-styles)
|
|
2467
|
+
echo "1️⃣ .claude/ 디렉토리 동기화 중..."
|
|
2468
|
+
|
|
2469
|
+
for subdir in agents commands hooks output-styles; do
|
|
2470
|
+
if [ -d "$TEMPLATE_DIR/.claude/$subdir" ]; then
|
|
2471
|
+
cp -r "$TEMPLATE_DIR/.claude/$subdir" .claude/ 2>/dev/null
|
|
2472
|
+
file_count=$(find .claude/$subdir -type f | wc -l)
|
|
2473
|
+
echo " ✅ .claude/$subdir - $file_count 파일 동기화됨"
|
|
2474
|
+
fi
|
|
2475
|
+
done
|
|
2476
|
+
|
|
2477
|
+
# settings.json 동기화
|
|
2478
|
+
if [ -f "$TEMPLATE_DIR/.claude/settings.json" ]; then
|
|
2479
|
+
cp "$TEMPLATE_DIR/.claude/settings.json" .claude/
|
|
2480
|
+
echo " ✅ .claude/settings.json 동기화됨"
|
|
2481
|
+
fi
|
|
2482
|
+
|
|
2483
|
+
echo ""
|
|
2484
|
+
|
|
2485
|
+
# 4️⃣ .moai/memory/ 동기화 (개발 가이드, 규칙, 실습 문서)
|
|
2486
|
+
echo "2️⃣ .moai/memory/ 디렉토리 동기화 중..."
|
|
2487
|
+
|
|
2488
|
+
if [ -d "$TEMPLATE_DIR/.moai/memory" ]; then
|
|
2489
|
+
cp -r "$TEMPLATE_DIR/.moai/memory" .moai/
|
|
2490
|
+
file_count=$(find .moai/memory -type f | wc -l)
|
|
2491
|
+
echo " ✅ .moai/memory - $file_count 파일 동기화됨"
|
|
2492
|
+
fi
|
|
2493
|
+
|
|
2494
|
+
echo ""
|
|
2495
|
+
|
|
2496
|
+
# 5️⃣ 버전 최적화 (.moai/config.json)
|
|
2497
|
+
echo "3️⃣ config.json 버전 및 메타데이터 최적화 중..."
|
|
2498
|
+
|
|
2499
|
+
# 패키지 템플릿의 config.json에서 최신 구조 읽기
|
|
2500
|
+
TEMPLATE_VERSION=$(rg '"version":\s*"([^"]+)"' "$TEMPLATE_CONFIG" -o '$1' | head -1)
|
|
2501
|
+
|
|
2502
|
+
# 로컬 config.json 업데이트
|
|
2503
|
+
# - moai.version 업데이트 (배포된 실제 버전으로)
|
|
2504
|
+
# - language section 구조화
|
|
2505
|
+
# - project section 정규화
|
|
2506
|
+
|
|
2507
|
+
python3 << 'EOF'
|
|
2508
|
+
import json
|
|
2509
|
+
import sys
|
|
2510
|
+
from pathlib import Path
|
|
2511
|
+
|
|
2512
|
+
config_path = Path(".moai/config.json")
|
|
2513
|
+
if not config_path.exists():
|
|
2514
|
+
print("❌ .moai/config.json을 찾을 수 없습니다")
|
|
2515
|
+
sys.exit(1)
|
|
2516
|
+
|
|
2517
|
+
with open(config_path) as f:
|
|
2518
|
+
config = json.load(f)
|
|
2519
|
+
|
|
2520
|
+
# 버전 업데이트 (배포된 버전)
|
|
2521
|
+
config["moai"]["version"] = "CURRENT_VERSION"
|
|
2522
|
+
|
|
2523
|
+
# version_check 섹션 추가
|
|
2524
|
+
if "version_check" not in config["moai"]:
|
|
2525
|
+
config["moai"]["update_check_frequency"] = "daily"
|
|
2526
|
+
config["moai"]["version_check"] = {
|
|
2527
|
+
"enabled": True,
|
|
2528
|
+
"cache_ttl_hours": 24
|
|
2529
|
+
}
|
|
2530
|
+
|
|
2531
|
+
# language section 구조화 (있으면 유지, 없으면 추가)
|
|
2532
|
+
if "language" not in config:
|
|
2533
|
+
config["language"] = {
|
|
2534
|
+
"conversation_language": config["project"].get("conversation_language", "en"),
|
|
2535
|
+
"conversation_language_name": config["project"].get("conversation_language_name", "English")
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2538
|
+
# project section 정규화 (중복 제거)
|
|
2539
|
+
if "conversation_language" in config["project"]:
|
|
2540
|
+
del config["project"]["conversation_language"]
|
|
2541
|
+
if "conversation_language_name" in config["project"]:
|
|
2542
|
+
del config["project"]["conversation_language_name"]
|
|
2543
|
+
if "user_nickname" in config["project"]:
|
|
2544
|
+
del config["project"]["user_nickname"]
|
|
2545
|
+
if "template_version" in config["project"]:
|
|
2546
|
+
del config["project"]["template_version"]
|
|
2547
|
+
|
|
2548
|
+
# 저장
|
|
2549
|
+
with open(config_path, "w") as f:
|
|
2550
|
+
json.dump(config, f, indent=2, ensure_ascii=False)
|
|
2551
|
+
f.write("\n")
|
|
2552
|
+
|
|
2553
|
+
print(" ✅ config.json 최적화 완료")
|
|
2554
|
+
print(f" - moai.version: {config['moai']['version']}")
|
|
2555
|
+
print(f" - language section 정규화됨")
|
|
2556
|
+
print(f" - project section 정규화됨 (중복 제거)")
|
|
2557
|
+
EOF
|
|
2558
|
+
|
|
2559
|
+
# 변수 치환 (CURRENT_VERSION → 실제 버전)
|
|
2560
|
+
sed -i '' "s/CURRENT_VERSION/$CURRENT_VERSION/g" .moai/config.json
|
|
2561
|
+
|
|
2562
|
+
echo ""
|
|
2563
|
+
|
|
2564
|
+
# 6️⃣ CLAUDE.md 동기화 및 변수 치환
|
|
2565
|
+
echo "4️⃣ CLAUDE.md 프로젝트 지침 업데이트 중..."
|
|
2566
|
+
|
|
2567
|
+
TEMPLATE_CLAUDE_MD="$TEMPLATE_DIR/CLAUDE.md"
|
|
2568
|
+
|
|
2569
|
+
if [ -f "$TEMPLATE_CLAUDE_MD" ]; then
|
|
2570
|
+
# CLAUDE.md 복사
|
|
2571
|
+
cp "$TEMPLATE_CLAUDE_MD" CLAUDE.md
|
|
2572
|
+
|
|
2573
|
+
# .moai/config.json에서 프로젝트 정보 추출
|
|
2574
|
+
PROJECT_NAME=$(rg '"name":\s*"([^"]+)"' .moai/config.json -o '$1' | head -1)
|
|
2575
|
+
PROJECT_LOCALE=$(rg '"locale":\s*"([^"]+)"' .moai/config.json -o '$1' | head -1)
|
|
2576
|
+
CONVERSATION_LANGUAGE=$(rg '"conversation_language":\s*"([^"]+)"' .moai/config.json -o '$1' | head -1)
|
|
2577
|
+
CONVERSATION_LANGUAGE_NAME=$(rg '"conversation_language_name":\s*"([^"]+)"' .moai/config.json -o '$1' | head -1)
|
|
2578
|
+
CODEBASE_LANGUAGE=$(rg '"language":\s*"([^"]+)"' .moai/config.json -o '$1' | head -1)
|
|
2579
|
+
|
|
2580
|
+
# 변수 치환 (소문자, 대문자, {{}} 형식 모두 처리)
|
|
2581
|
+
sed -i '' "s|{{project_name}}|$PROJECT_NAME|g" CLAUDE.md
|
|
2582
|
+
sed -i '' "s|{{PROJECT_NAME}}|$PROJECT_NAME|g" CLAUDE.md
|
|
2583
|
+
sed -i '' "s|{{locale}}|$PROJECT_LOCALE|g" CLAUDE.md
|
|
2584
|
+
sed -i '' "s|{{LOCALE}}|$PROJECT_LOCALE|g" CLAUDE.md
|
|
2585
|
+
sed -i '' "s|{{conversation_language}}|$CONVERSATION_LANGUAGE|g" CLAUDE.md
|
|
2586
|
+
sed -i '' "s|{{conversation_language_name}}|$CONVERSATION_LANGUAGE_NAME|g" CLAUDE.md
|
|
2587
|
+
sed -i '' "s|{{codebase_language}}|$CODEBASE_LANGUAGE|g" CLAUDE.md
|
|
2588
|
+
sed -i '' "s|{{CODEBASE_LANGUAGE}}|$CODEBASE_LANGUAGE|g" CLAUDE.md
|
|
2589
|
+
|
|
2590
|
+
echo " ✅ CLAUDE.md 업데이트 완료"
|
|
2591
|
+
echo " - project_name: $PROJECT_NAME"
|
|
2592
|
+
echo " - locale: $PROJECT_LOCALE"
|
|
2593
|
+
echo " - conversation_language: $CONVERSATION_LANGUAGE"
|
|
2594
|
+
echo " - codebase_language: $CODEBASE_LANGUAGE"
|
|
2595
|
+
fi
|
|
2596
|
+
|
|
2597
|
+
echo ""
|
|
2598
|
+
echo "✅ 패키지 템플릿 동기화 및 최적화 완료!"
|
|
2599
|
+
echo ""
|
|
2600
|
+
echo "📋 동기화 체크리스트:"
|
|
2601
|
+
echo " ✅ .claude/ (agents, commands, hooks, output-styles, settings.json)"
|
|
2602
|
+
echo " ✅ .moai/memory/ (CLAUDE-RULES.md, DEVELOPMENT-GUIDE.md, etc.)"
|
|
2603
|
+
echo " ✅ .moai/config.json (버전, 언어, 메타데이터 최적화)"
|
|
2604
|
+
echo " ✅ CLAUDE.md (프로젝트 변수 치환)"
|
|
2605
|
+
echo ""
|
|
2606
|
+
echo "→ 다음 단계: Git 커밋 (Step 3.11)"
|
|
2607
|
+
```
|
|
2608
|
+
|
|
2609
|
+
**검증 체크리스트:**
|
|
2610
|
+
- ✅ `.claude/agents/`, `.claude/commands/`, `.claude/hooks/` 최신 파일
|
|
2611
|
+
- ✅ `.moai/memory/` 개발 가이드 최신화
|
|
2612
|
+
- ✅ `config.json` 버전: v{new_version}
|
|
2613
|
+
- ✅ `config.json` 구조: language section 분리, project section 정규화
|
|
2614
|
+
- ✅ `CLAUDE.md` 프로젝트 변수 자동 치환
|
|
2615
|
+
- ✅ 모든 변경사항이 staged 상태 준비
|
|
2616
|
+
|
|
2617
|
+
---
|
|
2618
|
+
|
|
2619
|
+
### Step 3.11: 패키지 템플릿 동기화 커밋 (필수)
|
|
2620
|
+
|
|
2621
|
+
**목적**:
|
|
2622
|
+
- Step 3.10에서 동기화한 패키지 템플릿을 Git에 커밋
|
|
2623
|
+
- 로컬 프로젝트가 패키지 템플릿과 동일한 상태로 유지
|
|
2624
|
+
- 버전 번호와 메타데이터 최적화 기록
|
|
2625
|
+
|
|
2626
|
+
**패키지 템플릿 동기화 커밋 스크립트:**
|
|
2627
|
+
|
|
2628
|
+
```bash
|
|
2629
|
+
echo "📝 패키지 템플릿 동기화 커밋 생성 중..."
|
|
2630
|
+
echo ""
|
|
2631
|
+
|
|
2632
|
+
# 1️⃣ 변경사항 확인
|
|
2633
|
+
echo "📊 변경된 파일 목록:"
|
|
2634
|
+
git status --short | grep -E "\.claude/|\.moai/|CLAUDE.md" | head -20
|
|
2635
|
+
|
|
2636
|
+
echo ""
|
|
2637
|
+
|
|
2638
|
+
# 2️⃣ 파일 staging
|
|
2639
|
+
echo "📦 변경사항 staging 중..."
|
|
2640
|
+
|
|
2641
|
+
git add .claude/
|
|
2642
|
+
git add .moai/config.json
|
|
2643
|
+
git add .moai/memory/
|
|
2644
|
+
git add CLAUDE.md
|
|
2645
|
+
|
|
2646
|
+
staged_count=$(git diff --cached --name-only | wc -l)
|
|
2647
|
+
echo " ✅ $staged_count개 파일 staged"
|
|
2648
|
+
|
|
2649
|
+
echo ""
|
|
2650
|
+
|
|
2651
|
+
# 3️⃣ 커밋 메시지 생성 (영문만)
|
|
2652
|
+
COMMIT_MSG="chore: Synchronize package templates to local project after release
|
|
2653
|
+
|
|
2654
|
+
- Sync .claude/ (agents, commands, hooks, output-styles, settings.json)
|
|
2655
|
+
- Sync .moai/memory/ (development guides, rules, practices)
|
|
2656
|
+
- Update .moai/config.json: version v${CURRENT_VERSION}, optimize structure
|
|
2657
|
+
- Update CLAUDE.md: project variables substitution
|
|
2658
|
+
- Maintain package template as source of truth (src/moai_adk/templates/)
|
|
2659
|
+
|
|
2660
|
+
**File Changes**:
|
|
2661
|
+
- .claude/: Alfred agents, commands, hooks, output styles
|
|
2662
|
+
- .moai/: Project configuration, development documentation
|
|
2663
|
+
- CLAUDE.md: Project directives with substituted variables
|
|
2664
|
+
|
|
2665
|
+
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
|
2666
|
+
|
|
2667
|
+
Co-Authored-By: Alfred <alfred@mo.ai.kr>"
|
|
2668
|
+
|
|
2669
|
+
# 4️⃣ 커밋 실행
|
|
2670
|
+
echo "💾 커밋 생성 중..."
|
|
2671
|
+
git commit -m "$COMMIT_MSG"
|
|
2672
|
+
|
|
2673
|
+
if [ $? -eq 0 ]; then
|
|
2674
|
+
COMMIT_HASH=$(git rev-parse --short HEAD)
|
|
2675
|
+
echo " ✅ 커밋 생성 완료: $COMMIT_HASH"
|
|
2676
|
+
echo ""
|
|
2677
|
+
echo "📝 커밋 메시지:"
|
|
2678
|
+
git log -1 --pretty=format:"%B"
|
|
2679
|
+
echo ""
|
|
2680
|
+
else
|
|
2681
|
+
echo "⚠️ 커밋 실패 (변경사항 없을 수 있음)"
|
|
2682
|
+
fi
|
|
2683
|
+
|
|
2684
|
+
echo ""
|
|
2685
|
+
echo "✅ 패키지 템플릿 동기화 커밋 완료!"
|
|
2686
|
+
echo "→ 다음 단계: Push to remote (선택 사항) 또는 Step 3.12 (Post-Release Cleanup)"
|
|
2687
|
+
```
|
|
2688
|
+
|
|
2689
|
+
**검증 체크리스트:**
|
|
2690
|
+
- ✅ 변경된 파일이 모두 staged 상태
|
|
2691
|
+
- ✅ 커밋 메시지: 영문으로 작성, Alfred 공동저자 포함
|
|
2692
|
+
- ✅ 커밋 해시 기록됨
|
|
2693
|
+
|
|
2694
|
+
**참고사항:**
|
|
2695
|
+
- ℹ️ 이 커밋은 develop/main 브랜치에 추가됨
|
|
2696
|
+
- ℹ️ PyPI 배포는 이미 완료된 상태
|
|
2697
|
+
- ℹ️ 패키지 사용자에게는 영향 없음 (코드 변경 없음)
|
|
2698
|
+
|
|
2699
|
+
---
|
|
2700
|
+
|
|
2701
|
+
### Step 3.12: Post-Release Cleanup (필수)
|
|
2702
|
+
- 저장소 상태 정리
|
|
2703
|
+
- 다음 개발 사이클 준비
|
|
2704
|
+
|
|
2705
|
+
**Cleanup 스크립트:**
|
|
2706
|
+
```bash
|
|
2707
|
+
echo "🧹 Starting post-release cleanup..."
|
|
2708
|
+
echo ""
|
|
2709
|
+
|
|
2710
|
+
# 1. 현재 브랜치 확인
|
|
2711
|
+
CURRENT_BRANCH=$(git branch --show-current)
|
|
2712
|
+
echo "📍 Currently on: $CURRENT_BRANCH"
|
|
2713
|
+
|
|
2714
|
+
# 2. develop 브랜치 존재 여부 확인
|
|
2715
|
+
if git show-ref --verify --quiet refs/heads/develop; then
|
|
2716
|
+
TARGET_BRANCH="develop"
|
|
2717
|
+
echo "🎯 Target branch: develop (GitFlow mode)"
|
|
2718
|
+
else
|
|
2719
|
+
TARGET_BRANCH="main"
|
|
2720
|
+
echo "🎯 Target branch: main (Simplified mode)"
|
|
2721
|
+
fi
|
|
2722
|
+
|
|
2723
|
+
# 3. target 브랜치로 전환 및 최신화
|
|
2724
|
+
echo "🔄 Switching to $TARGET_BRANCH..."
|
|
2725
|
+
git checkout $TARGET_BRANCH
|
|
2726
|
+
|
|
2727
|
+
if [ $? -ne 0 ]; then
|
|
2728
|
+
echo "❌ Failed to checkout $TARGET_BRANCH"
|
|
2729
|
+
exit 1
|
|
2730
|
+
fi
|
|
2731
|
+
|
|
2732
|
+
echo "⬇️ Pulling latest changes from origin/$TARGET_BRANCH..."
|
|
2733
|
+
git pull origin $TARGET_BRANCH
|
|
2734
|
+
|
|
2735
|
+
# 4. 병합된 로컬 브랜치 삭제
|
|
2736
|
+
echo ""
|
|
2737
|
+
echo "🗑️ Identifying merged local branches..."
|
|
2738
|
+
MERGED_BRANCHES=$(git branch --merged | grep -v "^\*" | grep -v "\bmain\b" | grep -v "\bdevelop\b" | xargs)
|
|
2739
|
+
|
|
2740
|
+
if [ -n "$MERGED_BRANCHES" ]; then
|
|
2741
|
+
echo "Found merged branches:"
|
|
2742
|
+
echo "$MERGED_BRANCHES" | tr ' ' '\n' | sed 's/^/ - /'
|
|
2743
|
+
echo ""
|
|
2744
|
+
|
|
2745
|
+
for branch in $MERGED_BRANCHES; do
|
|
2746
|
+
git branch -d "$branch" 2>/dev/null
|
|
2747
|
+
if [ $? -eq 0 ]; then
|
|
2748
|
+
echo " ✅ Deleted local branch: $branch"
|
|
2749
|
+
fi
|
|
2750
|
+
done
|
|
2751
|
+
else
|
|
2752
|
+
echo " ℹ️ No merged local branches to clean up"
|
|
2753
|
+
fi
|
|
2754
|
+
|
|
2755
|
+
# 5. 병합된 원격 브랜치 삭제
|
|
2756
|
+
echo ""
|
|
2757
|
+
echo "🌐 Identifying merged remote branches..."
|
|
2758
|
+
REMOTE_MERGED=$(git branch -r --merged origin/$TARGET_BRANCH | grep -v "HEAD" | grep -v "\bmain\b" | grep -v "\bdevelop\b" | sed 's|origin/||' | xargs)
|
|
2759
|
+
|
|
2760
|
+
if [ -n "$REMOTE_MERGED" ]; then
|
|
2761
|
+
echo "Found merged remote branches:"
|
|
2762
|
+
echo "$REMOTE_MERGED" | tr ' ' '\n' | sed 's/^/ - origin\//'
|
|
2763
|
+
echo ""
|
|
2764
|
+
|
|
2765
|
+
for branch in $REMOTE_MERGED; do
|
|
2766
|
+
# Skip if branch doesn't exist on remote
|
|
2767
|
+
if git ls-remote --heads origin "$branch" | grep -q "$branch"; then
|
|
2768
|
+
git push origin --delete "$branch" 2>/dev/null
|
|
2769
|
+
if [ $? -eq 0 ]; then
|
|
2770
|
+
echo " ✅ Deleted remote branch: origin/$branch"
|
|
2771
|
+
else
|
|
2772
|
+
echo " ⚠️ Failed to delete remote branch: origin/$branch (may require permissions)"
|
|
2773
|
+
fi
|
|
2774
|
+
fi
|
|
2775
|
+
done
|
|
2776
|
+
else
|
|
2777
|
+
echo " ℹ️ No merged remote branches to clean up"
|
|
2778
|
+
fi
|
|
2779
|
+
|
|
2780
|
+
# 6. 최종 상태 확인
|
|
2781
|
+
echo ""
|
|
2782
|
+
echo "📊 Final repository status:"
|
|
2783
|
+
echo ""
|
|
2784
|
+
echo "📍 Current branch: $(git branch --show-current)"
|
|
2785
|
+
echo "🌲 Local branches:"
|
|
2786
|
+
git branch | sed 's/^/ /'
|
|
2787
|
+
echo ""
|
|
2788
|
+
echo "🌐 Remote branches:"
|
|
2789
|
+
git branch -r | grep -v "HEAD" | sed 's/^/ /'
|
|
2790
|
+
echo ""
|
|
2791
|
+
|
|
2792
|
+
# 7. 선택적: dist/ 디렉토리 정리
|
|
2793
|
+
if [ -d "dist" ]; then
|
|
2794
|
+
echo "🗂️ dist/ directory found (build artifacts)"
|
|
2795
|
+
read -p "Delete dist/ directory? (y/n): " delete_dist
|
|
2796
|
+
if [ "$delete_dist" = "y" ]; then
|
|
2797
|
+
rm -rf dist/
|
|
2798
|
+
echo " ✅ Deleted dist/"
|
|
2799
|
+
else
|
|
2800
|
+
echo " ℹ️ Keeping dist/"
|
|
2801
|
+
fi
|
|
2802
|
+
fi
|
|
2803
|
+
|
|
2804
|
+
echo ""
|
|
2805
|
+
echo "✅ Post-release cleanup complete!"
|
|
2806
|
+
echo ""
|
|
2807
|
+
echo "🚀 Repository is ready for next development cycle!"
|
|
2808
|
+
echo "→ Start planning next feature: /alfred:1-plan \"Feature name\""
|
|
2809
|
+
```
|
|
2810
|
+
|
|
2811
|
+
**검증 체크리스트:**
|
|
2812
|
+
- ✅ develop 또는 main 브랜치로 복귀 확인
|
|
2813
|
+
- ✅ 병합된 feature 브랜치 삭제 확인 (local)
|
|
2814
|
+
- ✅ 병합된 feature 브랜치 삭제 확인 (remote)
|
|
2815
|
+
- ✅ 로컬 저장소 최신 상태 확인
|
|
2816
|
+
- ✅ dist/ 디렉토리 정리 (선택 사항)
|
|
2817
|
+
|
|
2818
|
+
**참고사항:**
|
|
2819
|
+
- ⚠️ 원격 브랜치 삭제는 권한이 필요할 수 있습니다
|
|
2820
|
+
- ⚠️ 삭제 전 브랜치가 실제로 병합되었는지 자동 확인됩니다
|
|
2821
|
+
- ℹ️ main/develop 브랜치는 자동으로 보호됩니다 (삭제 안 됨)
|
|
2822
|
+
|
|
2823
|
+
### ✨ Release Complete!
|
|
2824
|
+
|
|
2825
|
+
All deployment and cleanup tasks have been successfully completed.
|
|
2826
|
+
|
|
2827
|
+
**Next Steps**:
|
|
2828
|
+
```bash
|
|
2829
|
+
# You are now on develop/main branch
|
|
2830
|
+
# Start planning next feature
|
|
2831
|
+
/alfred:1-plan "New feature name"
|
|
2832
|
+
```
|
|
2833
|
+
|
|
2834
|
+
---
|
|
2835
|
+
|
|
2836
|
+
## 🛡️ 안전 장치
|
|
2837
|
+
|
|
2838
|
+
### 사전 검증
|
|
2839
|
+
|
|
2840
|
+
**필수 조건 체크**:
|
|
2841
|
+
```bash
|
|
2842
|
+
# Git 저장소 확인
|
|
2843
|
+
[ -d .git ] || { echo "❌ Git 저장소가 아닙니다"; exit 1; }
|
|
2844
|
+
|
|
2845
|
+
# pyproject.toml 존재 확인 (SSOT)
|
|
2846
|
+
[ -f pyproject.toml ] || { echo "❌ pyproject.toml이 없습니다"; exit 1; }
|
|
2847
|
+
|
|
2848
|
+
# __init__.py 존재 확인 (importlib.metadata 사용 여부 확인)
|
|
2849
|
+
[ -f src/moai_adk/__init__.py ] || { echo "❌ __init__.py가 없습니다"; exit 1; }
|
|
2850
|
+
|
|
2851
|
+
# editable install 확인 (SSOT 방식)
|
|
2852
|
+
python -c "from importlib.metadata import version; version('moai-adk')" 2>/dev/null || {
|
|
2853
|
+
echo "⚠️ 패키지가 설치되지 않았습니다"
|
|
2854
|
+
echo "→ uv pip install -e . 실행 필요"
|
|
2855
|
+
}
|
|
2856
|
+
|
|
2857
|
+
# gh CLI 인증 확인
|
|
2858
|
+
gh auth status 2>/dev/null || echo "⚠️ gh CLI 미인증 (GitHub Release 생략)"
|
|
2859
|
+
```
|
|
2860
|
+
|
|
2861
|
+
### 🔄 GitHub Actions 실패 시 롤백
|
|
2862
|
+
|
|
2863
|
+
GitHub Actions에서 릴리즈가 실패한 경우:
|
|
2864
|
+
|
|
2865
|
+
**1️⃣ 원인 파악**:
|
|
2866
|
+
```bash
|
|
2867
|
+
# GitHub Actions 로그 확인
|
|
2868
|
+
gh run view <RUN_ID> --log
|
|
2869
|
+
|
|
2870
|
+
# 또는 특정 워크플로우 상태 확인
|
|
2871
|
+
gh run list --branch main --limit 5 --json name,status,conclusion
|
|
2872
|
+
|
|
2873
|
+
# 최신 실행 상세 정보
|
|
2874
|
+
gh run view $(gh run list --branch main --limit 1 --json databaseId -q '.[0].databaseId') --json jobs
|
|
2875
|
+
```
|
|
2876
|
+
|
|
2877
|
+
**2️⃣ Release Pipeline 미감지 문제**:
|
|
2878
|
+
```bash
|
|
2879
|
+
# 증상: moai-gitflow.yml이 "skipped" 상태
|
|
2880
|
+
# 원인: merge commit이 Release 패턴을 감지하지 못함
|
|
2881
|
+
|
|
2882
|
+
# 해결책 1: .github/workflows/moai-release-pipeline.yml 수정
|
|
2883
|
+
# 라인 37-38: grep -q "^🔖 RELEASE:" → grep -q "🔖 RELEASE:"
|
|
2884
|
+
# (^ 제거로 패턴 위치 제약 해제)
|
|
2885
|
+
|
|
2886
|
+
# 해결책 2: 수동 배포 (긴급)
|
|
2887
|
+
git tag -a v{new_version} -m "Release v{new_version}" <COMMIT_SHA>
|
|
2888
|
+
git push origin v{new_version}
|
|
2889
|
+
gh release create v{new_version} --title "Release v{new_version}" --notes "[노트]"
|
|
2890
|
+
```
|
|
2891
|
+
|
|
2892
|
+
**3️⃣ PyPI 배포 실패**:
|
|
2893
|
+
```bash
|
|
2894
|
+
# 증상: release.yml이 failed 또는 skipped
|
|
2895
|
+
# 원인: PYPI_API_TOKEN 미설정 또는 GitHub Release 미생성
|
|
2896
|
+
|
|
2897
|
+
# 해결책 1: GitHub Release 공개 (draft → published)
|
|
2898
|
+
gh release edit v{new_version} --draft=false
|
|
2899
|
+
|
|
2900
|
+
# 해결책 2: 수동 PyPI 배포
|
|
2901
|
+
python3 -m build dist/
|
|
2902
|
+
uv publish dist/moai_adk-{new_version}*.whl dist/moai_adk-{new_version}.tar.gz
|
|
2903
|
+
```
|
|
2904
|
+
|
|
2905
|
+
**4️⃣ PR 복귀 (모든 자동화 실패 시)**:
|
|
2906
|
+
```bash
|
|
2907
|
+
# PR #XX를 revert (GitHub 웹에서 수동)
|
|
2908
|
+
# 또는 CLI로
|
|
2909
|
+
git revert <COMMIT_HASH>
|
|
2910
|
+
git push upstream develop
|
|
2911
|
+
```
|
|
2912
|
+
|
|
2913
|
+
**5️⃣ 태그/Release 정리** (GitHub Actions가 이미 생성한 경우):
|
|
2914
|
+
```bash
|
|
2915
|
+
# 로컬 태그 삭제
|
|
2916
|
+
git tag -d v{new_version}
|
|
2917
|
+
git fetch origin
|
|
2918
|
+
|
|
2919
|
+
# GitHub Release 삭제
|
|
2920
|
+
gh release delete v{new_version} --yes
|
|
2921
|
+
|
|
2922
|
+
# 원격 태그 삭제
|
|
2923
|
+
git push origin :refs/tags/v{new_version}
|
|
2924
|
+
```
|
|
2925
|
+
|
|
2926
|
+
**6️⃣ 문제 해결 후 재시도**:
|
|
2927
|
+
```bash
|
|
2928
|
+
# develop에서 문제 수정
|
|
2929
|
+
git checkout develop
|
|
2930
|
+
# ... 문제 해결 ...
|
|
2931
|
+
git commit -m "fix: Release issue"
|
|
2932
|
+
git push upstream develop
|
|
2933
|
+
|
|
2934
|
+
# Phase 2부터 재시작
|
|
2935
|
+
/awesome:release-new patch
|
|
2936
|
+
```
|
|
2937
|
+
|
|
2938
|
+
⚠️ **PyPI 배포는 롤백 불가**:
|
|
2939
|
+
- 이미 배포된 버전은 PyPI에서 삭제할 수 없음
|
|
2940
|
+
- 버전 번호 변경 후 새로 배포해야 함
|
|
2941
|
+
- 필요 시 yanked 버전으로 표시 (PyPI 웹 대시보드)
|
|
2942
|
+
|
|
2943
|
+
### 에러 처리
|
|
2944
|
+
|
|
2945
|
+
**주요 에러 케이스**:
|
|
2946
|
+
|
|
2947
|
+
1. **Release Pipeline 미감지** (가장 흔함)
|
|
2948
|
+
- 증상: moai-gitflow.yml이 "skipped" 상태
|
|
2949
|
+
- 원인: merge commit의 첫 줄이 "Merge pull request..."
|
|
2950
|
+
- 해결: 라인 37에서 grep -q "^🔖" → grep -q "🔖" 변경
|
|
2951
|
+
- 대체: 수동으로 git tag + gh release create 실행
|
|
2952
|
+
|
|
2953
|
+
2. **PyPI 배포 실패**
|
|
2954
|
+
- 증상: release.yml이 failed 또는 skipped
|
|
2955
|
+
- 원인: PYPI_API_TOKEN 미설정 또는 GitHub Release Draft
|
|
2956
|
+
- 해결: gh release edit v{VERSION} --draft=false
|
|
2957
|
+
- 대체: uv publish 또는 twine upload 로컬 실행
|
|
2958
|
+
|
|
2959
|
+
3. **버전 충돌**
|
|
2960
|
+
- 증상: git tag -a 실패 (tag already exists)
|
|
2961
|
+
- 확인: git tag -l "v{VERSION}"
|
|
2962
|
+
- 해결: 버전 번호 증가 후 재시도
|
|
2963
|
+
|
|
2964
|
+
4. **gh CLI 실패**
|
|
2965
|
+
- 증상: GitHub Release 생성 불가
|
|
2966
|
+
- 확인: gh auth status
|
|
2967
|
+
- 해결: gh auth login 또는 gh auth refresh
|
|
2968
|
+
|
|
2969
|
+
5. **PyPI API 토큰 오류**
|
|
2970
|
+
- 증상: uv publish 실패 (authentication failed)
|
|
2971
|
+
- 확인: echo $UV_PUBLISH_TOKEN
|
|
2972
|
+
- 해결: PyPI에서 새 토큰 생성 후 GitHub Secrets 업데이트
|
|
2973
|
+
|
|
2974
|
+
---
|
|
2975
|
+
|
|
2976
|
+
## 📊 최종 보고서 형식
|
|
2977
|
+
|
|
2978
|
+
```markdown
|
|
2979
|
+
🎉 릴리즈 v{new_version} 완료!
|
|
2980
|
+
|
|
2981
|
+
✅ 완료된 작업
|
|
2982
|
+
|
|
2983
|
+
1. 품질 검증 (CodeRabbit AI) ✅
|
|
2984
|
+
- 자동 코드 리뷰: 완료 (모든 PR)
|
|
2985
|
+
- 자동 승인: ✅ (품질 80% 이상)
|
|
2986
|
+
- 보안 검사: ✅ (취약점 0개)
|
|
2987
|
+
- 테스트 커버리지: {COVERAGE}%
|
|
2988
|
+
|
|
2989
|
+
2. GitFlow PR 병합 ✅
|
|
2990
|
+
- 브랜치: develop → main
|
|
2991
|
+
- PR #: {PR_NUMBER}
|
|
2992
|
+
- CodeRabbit 자동 승인: ✅
|
|
2993
|
+
- 병합 타입: Merge Commit
|
|
2994
|
+
|
|
2995
|
+
3. 버전 업데이트 (SSOT) ✅
|
|
2996
|
+
- pyproject.toml: {old} → {new} (SSOT)
|
|
2997
|
+
- __init__.py: 자동 로드 (importlib.metadata)
|
|
2998
|
+
|
|
2999
|
+
4. Git 작업 ✅
|
|
3000
|
+
- 커밋: {COMMIT_HASH}
|
|
3001
|
+
- 태그: v{new_version}
|
|
3002
|
+
- 푸시: origin/main ✅
|
|
3003
|
+
|
|
3004
|
+
5. 배포 ✅
|
|
3005
|
+
- PyPI: moai-adk@{new_version} ✅
|
|
3006
|
+
- GitHub Release (Draft): https://github.com/modu-ai/moai-adk/releases/tag/v{new_version} ✅
|
|
3007
|
+
|
|
3008
|
+
---
|
|
3009
|
+
|
|
3010
|
+
📦 릴리즈 정보
|
|
3011
|
+
|
|
3012
|
+
- **버전**: v{new_version}
|
|
3013
|
+
- **타입**: {VERSION_TYPE}
|
|
3014
|
+
- **날짜**: {YYYY-MM-DD}
|
|
3015
|
+
- **커밋**: {COMMIT_HASH}
|
|
3016
|
+
- **브랜치**: main (develop에서 병합)
|
|
3017
|
+
- **변경사항**: {N}개 커밋
|
|
3018
|
+
|
|
3019
|
+
🔗 링크
|
|
3020
|
+
|
|
3021
|
+
- GitHub PR: https://github.com/modu-ai/moai-adk/pull/{PR_NUMBER}
|
|
3022
|
+
- PyPI: https://pypi.org/project/moai-adk/{new_version}
|
|
3023
|
+
- GitHub Release: https://github.com/modu-ai/moai-adk/releases/tag/v{new_version}
|
|
3024
|
+
|
|
3025
|
+
---
|
|
3026
|
+
|
|
3027
|
+
🚀 다음 단계
|
|
3028
|
+
|
|
3029
|
+
- [ ] GitHub Release Draft 검토 및 게시
|
|
3030
|
+
- [ ] 사용자 공지 (필요 시)
|
|
3031
|
+
- [ ] develop 브랜치 정리 (선택 사항)
|
|
3032
|
+
- [ ] 다음 개발 사이클 시작
|
|
3033
|
+
|
|
3034
|
+
모든 작업이 성공적으로 완료되었습니다! 🎉
|
|
3035
|
+
|
|
3036
|
+
---
|
|
3037
|
+
|
|
3038
|
+
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
|
3039
|
+
|
|
3040
|
+
Co-Authored-By: Alfred <alfred@mo.ai.kr>
|
|
3041
|
+
```
|
|
3042
|
+
|
|
3043
|
+
---
|
|
3044
|
+
|
|
3045
|
+
## 🔧 고급 옵션
|
|
3046
|
+
|
|
3047
|
+
### 환경 변수
|
|
3048
|
+
|
|
3049
|
+
```bash
|
|
3050
|
+
# PyPI 토큰 설정 (uv publish) - pypi- 접두사 필수!
|
|
3051
|
+
export UV_PUBLISH_TOKEN="pypi-AgEIcHlwaS5vcmcCJ..."
|
|
3052
|
+
|
|
3053
|
+
# 또는 .pypirc 파일 사용 (~/.pypirc)
|
|
3054
|
+
# [pypi]
|
|
3055
|
+
# username = __token__
|
|
3056
|
+
# password = pypi-AgEIcHlwaS5vcmcCJ...
|
|
3057
|
+
|
|
3058
|
+
# GitHub Enterprise 사용 시
|
|
3059
|
+
export GH_HOST="github.company.com"
|
|
3060
|
+
|
|
3061
|
+
# dry-run 모드
|
|
3062
|
+
export DRY_RUN=true
|
|
3063
|
+
```
|
|
3064
|
+
|
|
3065
|
+
### 플래그 지원
|
|
3066
|
+
|
|
3067
|
+
```bash
|
|
3068
|
+
# PyPI 배포 건너뛰기
|
|
3069
|
+
/awesome:release-new patch --skip-pypi
|
|
3070
|
+
|
|
3071
|
+
# GitHub Release 건너뛰기
|
|
3072
|
+
/awesome:release-new minor --skip-github
|
|
3073
|
+
|
|
3074
|
+
# 자동 승인 (Phase 1 건너뜀, 위험!)
|
|
3075
|
+
/awesome:release-new major --auto-confirm
|
|
3076
|
+
|
|
3077
|
+
# 품질 검증 건너뛰기 (매우 위험!)
|
|
3078
|
+
/awesome:release-new patch --skip-quality
|
|
3079
|
+
```
|
|
3080
|
+
|
|
3081
|
+
---
|
|
3082
|
+
|
|
3083
|
+
## 💡 사용 예시
|
|
3084
|
+
|
|
3085
|
+
### 기본 사용
|
|
3086
|
+
|
|
3087
|
+
```bash
|
|
3088
|
+
# 패치 버전 증가 (기본값)
|
|
3089
|
+
/awesome:release-new
|
|
3090
|
+
/awesome:release-new patch
|
|
3091
|
+
|
|
3092
|
+
# 마이너 버전 증가
|
|
3093
|
+
/awesome:release-new minor
|
|
3094
|
+
|
|
3095
|
+
# 메이저 버전 증가
|
|
3096
|
+
/awesome:release-new major
|
|
3097
|
+
```
|
|
3098
|
+
|
|
3099
|
+
### 고급 사용
|
|
3100
|
+
|
|
3101
|
+
```bash
|
|
3102
|
+
# PyPI 배포 없이 GitHub Release만
|
|
3103
|
+
/awesome:release-new patch --skip-pypi
|
|
3104
|
+
|
|
3105
|
+
# 빠른 패치 릴리즈 (자동 승인)
|
|
3106
|
+
/awesome:release-new patch --auto-confirm
|
|
3107
|
+
```
|
|
3108
|
+
|
|
3109
|
+
---
|
|
3110
|
+
|
|
3111
|
+
## 📋 체크리스트
|
|
3112
|
+
|
|
3113
|
+
**릴리즈 전 확인사항**:
|
|
3114
|
+
- [ ] 모든 테스트 통과 (`pytest tests/`)
|
|
3115
|
+
- [ ] 린트 검사 통과 (`ruff check .`)
|
|
3116
|
+
- [ ] Git 브랜치: main 권장
|
|
3117
|
+
- [ ] 미커밋 변경사항 정리
|
|
3118
|
+
- [ ] pyproject.toml 필드 확인
|
|
3119
|
+
|
|
3120
|
+
**릴리즈 후 확인사항**:
|
|
3121
|
+
- [ ] PyPI 패키지 설치 테스트
|
|
3122
|
+
- [ ] GitHub Release 노트 검토
|
|
3123
|
+
- [ ] Git 태그 확인 (`git tag -l "v*"`)
|
|
3124
|
+
- [ ] 다음 버전 계획
|
|
3125
|
+
|
|
3126
|
+
---
|
|
3127
|
+
|
|
3128
|
+
## 🛠️ 기술 스택
|
|
3129
|
+
|
|
3130
|
+
- **Git**: 커밋, 태그, 푸시
|
|
3131
|
+
- **uv**: 빌드 및 PyPI 배포 (권장)
|
|
3132
|
+
- **gh CLI**: GitHub Release 자동화
|
|
3133
|
+
- **pytest**: 테스트 및 커버리지
|
|
3134
|
+
- **ruff**: 린트
|
|
3135
|
+
- **mypy**: 타입 체크
|
|
3136
|
+
- **bandit/pip-audit**: 보안 스캔
|
|
3137
|
+
|
|
3138
|
+
---
|
|
3139
|
+
|
|
3140
|
+
---
|
|
3141
|
+
|
|
3142
|
+
## 🔬 Dry-Run 모드 상세 설명
|
|
3143
|
+
|
|
3144
|
+
**Dry-Run 모드**는 릴리즈 프로세스를 **완전하게 시뮬레이션**하여, 실제 릴리즈 전에 모든 단계를 미리 확인할 수 있게 해줍니다.
|
|
3145
|
+
|
|
3146
|
+
### 사용 시나리오
|
|
3147
|
+
|
|
3148
|
+
#### Scenario 1: 처음 릴리즈하는 경우
|
|
3149
|
+
|
|
3150
|
+
```bash
|
|
3151
|
+
# Dry-Run으로 먼저 확인
|
|
3152
|
+
/awesome:release-new minor --dry-run
|
|
3153
|
+
|
|
3154
|
+
# 출력 예:
|
|
3155
|
+
# 🔬 Dry-Run 모드 활성화
|
|
3156
|
+
# 📊 시뮬레이션 계획:
|
|
3157
|
+
# ...
|
|
3158
|
+
# 실제 릴리즈를 진행하려면:
|
|
3159
|
+
# /awesome:release-new minor
|
|
3160
|
+
|
|
3161
|
+
# 결과가 만족스러우면 실제 실행
|
|
3162
|
+
/awesome:release-new minor
|
|
3163
|
+
```
|
|
3164
|
+
|
|
3165
|
+
#### Scenario 2: 자동화된 파이프라인 전에 검증
|
|
3166
|
+
|
|
3167
|
+
```bash
|
|
3168
|
+
# CI/CD 파이프라인이 있는 경우, 수동으로 한 번 Dry-Run으로 검증
|
|
3169
|
+
/awesome:release-new patch --dry-run
|
|
3170
|
+
|
|
3171
|
+
# 검증 후 CI/CD 트리거
|
|
3172
|
+
gh workflow run release.yml
|
|
3173
|
+
```
|
|
3174
|
+
|
|
3175
|
+
#### Scenario 3: 버전 계획 검토
|
|
3176
|
+
|
|
3177
|
+
```bash
|
|
3178
|
+
# 세 가지 버전 타입을 모두 시뮬레이션해서 비교
|
|
3179
|
+
/awesome:release-new patch --dry-run # v0.13.1
|
|
3180
|
+
/awesome:release-new minor --dry-run # v0.14.0
|
|
3181
|
+
/awesome:release-new major --dry-run # v1.0.0
|
|
3182
|
+
```
|
|
3183
|
+
|
|
3184
|
+
### Dry-Run 모드 실행 순서
|
|
3185
|
+
|
|
3186
|
+
```
|
|
3187
|
+
/awesome:release-new [version] --dry-run
|
|
3188
|
+
↓
|
|
3189
|
+
Phase 0: 품질 검증 (실제 실행)
|
|
3190
|
+
├─ pytest 실행
|
|
3191
|
+
├─ ruff 린트
|
|
3192
|
+
├─ mypy 타입 체크
|
|
3193
|
+
└─ bandit + pip-audit 보안 스캔
|
|
3194
|
+
↓
|
|
3195
|
+
Phase 1: 버전 분석 (시뮬레이션)
|
|
3196
|
+
├─ 현재/목표 버전 계산
|
|
3197
|
+
├─ Git 로그 분석
|
|
3198
|
+
└─ 변경사항 요약
|
|
3199
|
+
↓
|
|
3200
|
+
Phase 1.5: 릴리즈 계획 보고서 (출력, 승인 대기 없음)
|
|
3201
|
+
├─ 버전 변경사항
|
|
3202
|
+
├─ 예정된 파일 수정
|
|
3203
|
+
└─ 예정된 Git 작업
|
|
3204
|
+
↓
|
|
3205
|
+
Phase 2: PR 관리 (시뮬레이션만)
|
|
3206
|
+
├─ [DRY-RUN] GitHub PR 생성 예정
|
|
3207
|
+
└─ [DRY-RUN] GitHub 웹에서 병합 필요
|
|
3208
|
+
↓
|
|
3209
|
+
Phase 3: 자동 릴리즈 (실행 안 함)
|
|
3210
|
+
├─ [DRY-RUN] Git 태그 생성 예정
|
|
3211
|
+
├─ [DRY-RUN] GitHub Release 생성 예정
|
|
3212
|
+
└─ [DRY-RUN] PyPI 배포 예정
|
|
3213
|
+
↓
|
|
3214
|
+
🔬 Dry-Run 시뮬레이션 완료
|
|
3215
|
+
└─ 실제 릴리즈 명령 제시
|
|
3216
|
+
```
|
|
3217
|
+
|
|
3218
|
+
### Dry-Run 모드에서 출력되는 정보
|
|
3219
|
+
|
|
3220
|
+
#### Phase 0 출력 (실제)
|
|
3221
|
+
|
|
3222
|
+
```bash
|
|
3223
|
+
🐍 Python 버전: 3.13.0
|
|
3224
|
+
📦 패키지 매니저: uv
|
|
3225
|
+
🧪 테스트 실행 중...
|
|
3226
|
+
✅ 테스트 통과 (커버리지 87%)
|
|
3227
|
+
🔍 린트 검사 중...
|
|
3228
|
+
✅ 린트 통과
|
|
3229
|
+
🔤 타입 체크 중...
|
|
3230
|
+
✅ 타입 체크 통과
|
|
3231
|
+
🔒 보안 스캔 중...
|
|
3232
|
+
✅ 보안 스캔 통과
|
|
3233
|
+
```
|
|
3234
|
+
|
|
3235
|
+
#### Phase 1 출력 (시뮬레이션)
|
|
3236
|
+
|
|
3237
|
+
```bash
|
|
3238
|
+
📌 현재 버전 (pyproject.toml): 0.13.0
|
|
3239
|
+
📊 버전 변경: 0.13.0 → 0.14.0
|
|
3240
|
+
🏷️ 마지막 릴리즈: v0.13.0
|
|
3241
|
+
📝 변경사항: 5개 커밋
|
|
3242
|
+
- feat(spec): Add new features (#155)
|
|
3243
|
+
- fix: Resolve issue (#152)
|
|
3244
|
+
- docs: Update documentation
|
|
3245
|
+
- refactor: Code optimization
|
|
3246
|
+
- test: Add test coverage
|
|
3247
|
+
```
|
|
3248
|
+
|
|
3249
|
+
#### Phase 1.5-3 출력 (시뮬레이션 로그)
|
|
3250
|
+
|
|
3251
|
+
```
|
|
3252
|
+
🔬 릴리즈 계획 보고서
|
|
3253
|
+
📊 버전 정보
|
|
3254
|
+
- 현재 버전: v0.13.0
|
|
3255
|
+
- 목표 버전: v0.14.0
|
|
3256
|
+
- 버전 타입: minor
|
|
3257
|
+
|
|
3258
|
+
[DRY-RUN] 파일 수정 예정: pyproject.toml
|
|
3259
|
+
[DRY-RUN] Git 커밋 예정: 🔖 RELEASE: v0.14.0
|
|
3260
|
+
[DRY-RUN] Git 태그 예정: v0.14.0
|
|
3261
|
+
[DRY-RUN] GitHub PR 생성 예정: Release v0.14.0
|
|
3262
|
+
[DRY-RUN] GitHub Release 생성 예정: v0.14.0
|
|
3263
|
+
```
|
|
3264
|
+
|
|
3265
|
+
#### 최종 요약 (Dry-Run만)
|
|
3266
|
+
|
|
3267
|
+
```
|
|
3268
|
+
================================
|
|
3269
|
+
🔬 Dry-Run 시뮬레이션 완료
|
|
3270
|
+
================================
|
|
3271
|
+
|
|
3272
|
+
예정된 작업 목록:
|
|
3273
|
+
[12:34:56] 파일 수정 예정: pyproject.toml
|
|
3274
|
+
[12:34:56] Git 커밋 예정: 🔖 RELEASE: v0.14.0
|
|
3275
|
+
[12:34:56] Git 태그 예정: v0.14.0 - Release v0.14.0
|
|
3276
|
+
[12:34:56] GitHub PR 생성 예정: Release v0.14.0
|
|
3277
|
+
|
|
3278
|
+
⚠️ 위의 작업들은 시뮬레이션만 수행되었으며, 실제로 적용되지 않았습니다.
|
|
3279
|
+
|
|
3280
|
+
실제 릴리즈를 진행하려면 다음 명령을 실행하세요:
|
|
3281
|
+
/awesome:release-new minor
|
|
3282
|
+
```
|
|
3283
|
+
|
|
3284
|
+
### Dry-Run 모드 주의사항
|
|
3285
|
+
|
|
3286
|
+
#### ✅ Dry-Run에서 안전한 작업
|
|
3287
|
+
|
|
3288
|
+
- Phase 0 (품질 검증)은 **실제 실행**됩니다
|
|
3289
|
+
- 테스트 실행 중 코드 수정 필요할 수 있음 주의
|
|
3290
|
+
- 테스트 실패 시 Dry-Run도 중단됨
|
|
3291
|
+
- 모든 분석 및 계획은 부작용 없음
|
|
3292
|
+
- Git 로그 조회는 읽기만 함
|
|
3293
|
+
|
|
3294
|
+
#### ⚠️ Dry-Run에서 실행 안 되는 작업
|
|
3295
|
+
|
|
3296
|
+
- **파일 수정**: pyproject.toml 버전 변경 안 함
|
|
3297
|
+
- **Git 커밋**: 커밋 생성 안 함
|
|
3298
|
+
- **Git 태그**: 태그 생성 안 함
|
|
3299
|
+
- **GitHub API**: PR, Release 생성 안 함
|
|
3300
|
+
- **PyPI 배포**: 패키지 배포 안 함
|
|
3301
|
+
|
|
3302
|
+
### 트러블슈팅
|
|
3303
|
+
|
|
3304
|
+
#### Q: Dry-Run에서 테스트가 실패했습니다
|
|
3305
|
+
|
|
3306
|
+
**A**: 실제 Dry-Run 전에 로컬에서 테스트를 수정하세요:
|
|
3307
|
+
```bash
|
|
3308
|
+
# 먼저 테스트 실행
|
|
3309
|
+
pytest tests/
|
|
3310
|
+
|
|
3311
|
+
# 문제 해결 후
|
|
3312
|
+
/awesome:release-new [version] --dry-run
|
|
3313
|
+
```
|
|
3314
|
+
|
|
3315
|
+
#### Q: Dry-Run 결과가 이상합니다
|
|
3316
|
+
|
|
3317
|
+
**A**: 최신 코드와 의존성을 확인하세요:
|
|
3318
|
+
```bash
|
|
3319
|
+
# 최신 코드 pull
|
|
3320
|
+
git pull origin main
|
|
3321
|
+
|
|
3322
|
+
# 의존성 업데이트
|
|
3323
|
+
uv pip install -e .
|
|
3324
|
+
uv pip install --no-deps -e .
|
|
3325
|
+
|
|
3326
|
+
# 다시 시도
|
|
3327
|
+
/awesome:release-new [version] --dry-run
|
|
3328
|
+
```
|
|
3329
|
+
|
|
3330
|
+
#### Q: 실제 릴리즈를 진행했는데 뭔가 빠진 것 같습니다
|
|
3331
|
+
|
|
3332
|
+
**A**: 다음번에는 꼭 Dry-Run을 먼저 실행하세요:
|
|
3333
|
+
```bash
|
|
3334
|
+
# 실패한 버전 다시 테스트
|
|
3335
|
+
/awesome:release-new patch --dry-run
|
|
3336
|
+
|
|
3337
|
+
# 확인 후
|
|
3338
|
+
/awesome:release-new patch
|
|
3339
|
+
```
|
|
3340
|
+
|
|
3341
|
+
---
|
|
3342
|
+
|
|
3343
|
+
## 🔄 로컬 자동 업데이트 및 테스트
|
|
3344
|
+
|
|
3345
|
+
**로컬 자동 업데이트** 기능은 새로운 릴리즈가 PyPI에 배포되면, 로컬 개발 환경의 moai-adk 패키지를 자동으로 최신 버전으로 업데이트하고 테스트합니다.
|
|
3346
|
+
|
|
3347
|
+
### 언제 사용하는가?
|
|
3348
|
+
|
|
3349
|
+
1. **새로운 릴리즈 완료 후**: 실제 배포된 패키지가 설치 가능한지 검증
|
|
3350
|
+
2. **자동화된 릴리즈 파이프라인**: GitHub Actions 완료 후 자동으로 로컬 테스트
|
|
3351
|
+
3. **멀티 환경 테스트**: 다양한 Python 버전에서 패키지 호환성 확인
|
|
3352
|
+
|
|
3353
|
+
### 설정 방법
|
|
3354
|
+
|
|
3355
|
+
로컬 자동 업데이트는 다음 환경 변수로 제어됩니다:
|
|
3356
|
+
|
|
3357
|
+
```bash
|
|
3358
|
+
# ~/.bashrc 또는 ~/.zshrc에 추가
|
|
3359
|
+
export MOAI_AUTO_UPDATE=true # 자동 업데이트 활성화
|
|
3360
|
+
export MOAI_AUTO_UPDATE_TIMEOUT=300 # 업데이트 대기 시간 (초, 기본값 300)
|
|
3361
|
+
export MOAI_AUTO_UPDATE_RETRY=10 # 재시도 횟수 (기본값 10)
|
|
3362
|
+
export MOAI_PYTHON_VERSIONS="3.11 3.12 3.13" # 테스트할 Python 버전
|
|
3363
|
+
```
|
|
3364
|
+
|
|
3365
|
+
### 자동 업데이트 워크플로우
|
|
3366
|
+
|
|
3367
|
+
```bash
|
|
3368
|
+
# 릴리즈 완료 (자동 업데이트 활성화 상태)
|
|
3369
|
+
/awesome:release-new minor
|
|
3370
|
+
|
|
3371
|
+
→ Phase 0: 품질 검증
|
|
3372
|
+
→ Phase 1: 버전 분석
|
|
3373
|
+
→ Phase 2: PR 관리
|
|
3374
|
+
→ Phase 3: GitHub Actions 자동 릴리즈
|
|
3375
|
+
|
|
3376
|
+
[PyPI 배포 완료 후]
|
|
3377
|
+
|
|
3378
|
+
→ Phase 4: 로컬 자동 업데이트 (신규!)
|
|
3379
|
+
├─ PyPI에서 신규 버전 감지
|
|
3380
|
+
├─ 로컬 가상환경에서 최신 버전 설치
|
|
3381
|
+
├─ 기본 호환성 테스트 실행
|
|
3382
|
+
├─ CLI 버전 검증
|
|
3383
|
+
└─ 테스트 결과 리포트
|
|
3384
|
+
|
|
3385
|
+
✅ 로컬 자동 업데이트 완료
|
|
3386
|
+
```
|
|
3387
|
+
|
|
3388
|
+
### 자동 업데이트 실행 단계
|
|
3389
|
+
|
|
3390
|
+
#### Step 1: 로컬 버전 확인
|
|
3391
|
+
|
|
3392
|
+
```bash
|
|
3393
|
+
# 현재 설치된 moai-adk 버전 확인
|
|
3394
|
+
moai-adk --version
|
|
3395
|
+
|
|
3396
|
+
# 출력 예:
|
|
3397
|
+
# moai-adk version 0.13.0
|
|
3398
|
+
```
|
|
3399
|
+
|
|
3400
|
+
#### Step 2: PyPI에서 신규 버전 감지
|
|
3401
|
+
|
|
3402
|
+
```bash
|
|
3403
|
+
# PyPI에서 최신 버전 확인 (최대 5분 대기)
|
|
3404
|
+
pip index versions moai-adk
|
|
3405
|
+
|
|
3406
|
+
# 만약 최신 버전이 아직 감지되지 않으면 대기
|
|
3407
|
+
# 기본값: 10회 재시도, 30초 간격
|
|
3408
|
+
```
|
|
3409
|
+
|
|
3410
|
+
#### Step 3: 임시 가상환경에서 테스트 설치
|
|
3411
|
+
|
|
3412
|
+
```bash
|
|
3413
|
+
# 임시 테스트 환경 생성
|
|
3414
|
+
python -m venv /tmp/moai_test_$VERSION
|
|
3415
|
+
|
|
3416
|
+
# 최신 버전 설치 (캐시 제외)
|
|
3417
|
+
source /tmp/moai_test_$VERSION/bin/activate
|
|
3418
|
+
pip install moai-adk==$VERSION --no-cache-dir
|
|
3419
|
+
|
|
3420
|
+
# 설치 확인
|
|
3421
|
+
moai-adk --version
|
|
3422
|
+
```
|
|
3423
|
+
|
|
3424
|
+
#### Step 4: 호환성 검증
|
|
3425
|
+
|
|
3426
|
+
```bash
|
|
3427
|
+
# moai-adk 기본 명령 테스트
|
|
3428
|
+
moai-adk --help
|
|
3429
|
+
moai-adk --version
|
|
3430
|
+
|
|
3431
|
+
# 프로젝트 초기화 시뮬레이션
|
|
3432
|
+
moai-adk init --dry-run
|
|
3433
|
+
|
|
3434
|
+
# 임시 환경 정리
|
|
3435
|
+
deactivate
|
|
3436
|
+
rm -rf /tmp/moai_test_$VERSION
|
|
3437
|
+
```
|
|
3438
|
+
|
|
3439
|
+
### 자동 업데이트 옵션
|
|
3440
|
+
|
|
3441
|
+
#### 옵션 1: 활성화/비활성화
|
|
3442
|
+
|
|
3443
|
+
```bash
|
|
3444
|
+
# 자동 업데이트 활성화
|
|
3445
|
+
export MOAI_AUTO_UPDATE=true
|
|
3446
|
+
/awesome:release-new minor
|
|
3447
|
+
|
|
3448
|
+
# 자동 업데이트 비활성화 (기본값)
|
|
3449
|
+
export MOAI_AUTO_UPDATE=false
|
|
3450
|
+
/awesome:release-new minor
|
|
3451
|
+
```
|
|
3452
|
+
|
|
3453
|
+
#### 옵션 2: 대기 시간 조정
|
|
3454
|
+
|
|
3455
|
+
```bash
|
|
3456
|
+
# 5분(300초) 대기 (기본값)
|
|
3457
|
+
export MOAI_AUTO_UPDATE_TIMEOUT=300
|
|
3458
|
+
|
|
3459
|
+
# 10분(600초) 대기
|
|
3460
|
+
export MOAI_AUTO_UPDATE_TIMEOUT=600
|
|
3461
|
+
|
|
3462
|
+
# 즉시 테스트 (권장하지 않음, 보통 실패)
|
|
3463
|
+
export MOAI_AUTO_UPDATE_TIMEOUT=0
|
|
3464
|
+
```
|
|
3465
|
+
|
|
3466
|
+
#### 옵션 3: 재시도 횟수 조정
|
|
3467
|
+
|
|
3468
|
+
```bash
|
|
3469
|
+
# 10회 재시도, 30초 간격 (기본값, 총 5분)
|
|
3470
|
+
export MOAI_AUTO_UPDATE_RETRY=10
|
|
3471
|
+
|
|
3472
|
+
# 20회 재시도, 30초 간격 (총 10분)
|
|
3473
|
+
export MOAI_AUTO_UPDATE_RETRY=20
|
|
3474
|
+
|
|
3475
|
+
# 재시도 없음 (1회만 시도)
|
|
3476
|
+
export MOAI_AUTO_UPDATE_RETRY=1
|
|
3477
|
+
```
|
|
3478
|
+
|
|
3479
|
+
#### 옵션 4: 다중 Python 버전 테스트
|
|
3480
|
+
|
|
3481
|
+
```bash
|
|
3482
|
+
# Python 3.11, 3.12, 3.13에서 모두 테스트
|
|
3483
|
+
export MOAI_PYTHON_VERSIONS="3.11 3.12 3.13"
|
|
3484
|
+
|
|
3485
|
+
# Python 3.13만 테스트
|
|
3486
|
+
export MOAI_PYTHON_VERSIONS="3.13"
|
|
3487
|
+
|
|
3488
|
+
# 특정 경로의 Python 버전 테스트
|
|
3489
|
+
export MOAI_PYTHON_VERSIONS="/usr/bin/python3.11 /usr/bin/python3.12"
|
|
3490
|
+
```
|
|
3491
|
+
|
|
3492
|
+
### 자동 업데이트 실행 예시
|
|
3493
|
+
|
|
3494
|
+
#### 예시 1: 기본 설정으로 자동 업데이트
|
|
3495
|
+
|
|
3496
|
+
```bash
|
|
3497
|
+
# ~/.bashrc에 설정
|
|
3498
|
+
export MOAI_AUTO_UPDATE=true
|
|
3499
|
+
|
|
3500
|
+
# 릴리즈 실행
|
|
3501
|
+
/awesome:release-new minor
|
|
3502
|
+
|
|
3503
|
+
# 출력 예:
|
|
3504
|
+
# ...
|
|
3505
|
+
# 🚀 PyPI 배포 완료!
|
|
3506
|
+
# 🔄 로컬 자동 업데이트 시작...
|
|
3507
|
+
# ⏳ PyPI CDN 대기 중... (1/10)
|
|
3508
|
+
# ⏳ PyPI CDN 대기 중... (2/10)
|
|
3509
|
+
# ✅ moai-adk 0.14.0 감지됨
|
|
3510
|
+
# 📦 테스트 환경에서 설치 중...
|
|
3511
|
+
# ✅ 설치 성공: moai-adk==0.14.0
|
|
3512
|
+
# 🧪 호환성 테스트 중...
|
|
3513
|
+
# ✅ 모든 테스트 통과
|
|
3514
|
+
# 🎉 로컬 자동 업데이트 완료!
|
|
3515
|
+
```
|
|
3516
|
+
|
|
3517
|
+
#### 예시 2: 멀티 버전 테스트
|
|
3518
|
+
|
|
3519
|
+
```bash
|
|
3520
|
+
# ~/.bashrc에 설정
|
|
3521
|
+
export MOAI_AUTO_UPDATE=true
|
|
3522
|
+
export MOAI_PYTHON_VERSIONS="3.11 3.12 3.13"
|
|
3523
|
+
|
|
3524
|
+
# 릴리즈 실행
|
|
3525
|
+
/awesome:release-new patch
|
|
3526
|
+
|
|
3527
|
+
# 출력 예:
|
|
3528
|
+
# ...
|
|
3529
|
+
# 🔄 Python 3.11에서 테스트 중...
|
|
3530
|
+
# ✅ Python 3.11: 테스트 통과
|
|
3531
|
+
# 🔄 Python 3.12에서 테스트 중...
|
|
3532
|
+
# ✅ Python 3.12: 테스트 통과
|
|
3533
|
+
# 🔄 Python 3.13에서 테스트 중...
|
|
3534
|
+
# ✅ Python 3.13: 테스트 통과
|
|
3535
|
+
# 🎉 모든 버전에서 테스트 통과!
|
|
3536
|
+
```
|
|
3537
|
+
|
|
3538
|
+
### 자동 업데이트 트러블슈팅
|
|
3539
|
+
|
|
3540
|
+
#### Q: PyPI에서 새 버전이 감지되지 않습니다
|
|
3541
|
+
|
|
3542
|
+
**A**: PyPI CDN 전파 대기 시간 증가:
|
|
3543
|
+
|
|
3544
|
+
```bash
|
|
3545
|
+
# 대기 시간을 10분으로 증가
|
|
3546
|
+
export MOAI_AUTO_UPDATE_TIMEOUT=600
|
|
3547
|
+
/awesome:release-new patch
|
|
3548
|
+
```
|
|
3549
|
+
|
|
3550
|
+
#### Q: 호환성 테스트가 실패했습니다
|
|
3551
|
+
|
|
3552
|
+
**A**: 테스트 환경 로그 확인:
|
|
3553
|
+
|
|
3554
|
+
```bash
|
|
3555
|
+
# 마지막 테스트 로그 확인
|
|
3556
|
+
cat /tmp/moai_auto_update_*.log
|
|
3557
|
+
|
|
3558
|
+
# 문제 해결 후 수동 테스트
|
|
3559
|
+
python -m venv /tmp/test_manual
|
|
3560
|
+
source /tmp/test_manual/bin/activate
|
|
3561
|
+
pip install moai-adk==[VERSION]
|
|
3562
|
+
moai-adk --version
|
|
3563
|
+
deactivate
|
|
3564
|
+
rm -rf /tmp/test_manual
|
|
3565
|
+
```
|
|
3566
|
+
|
|
3567
|
+
#### Q: 특정 Python 버전에서만 테스트하고 싶습니다
|
|
3568
|
+
|
|
3569
|
+
**A**: 환경 변수로 Python 버전 지정:
|
|
3570
|
+
|
|
3571
|
+
```bash
|
|
3572
|
+
# Python 3.13만 테스트
|
|
3573
|
+
export MOAI_PYTHON_VERSIONS="3.13"
|
|
3574
|
+
/awesome:release-new minor
|
|
3575
|
+
|
|
3576
|
+
# 또는 절대 경로 사용
|
|
3577
|
+
export MOAI_PYTHON_VERSIONS="/usr/local/bin/python3.13"
|
|
3578
|
+
/awesome:release-new minor
|
|
3579
|
+
```
|
|
3580
|
+
|
|
3581
|
+
#### Q: 자동 업데이트를 완전히 비활성화하려면?
|
|
3582
|
+
|
|
3583
|
+
**A**: 환경 변수 비활성화:
|
|
3584
|
+
|
|
3585
|
+
```bash
|
|
3586
|
+
# 현재 세션에서만 비활성화
|
|
3587
|
+
export MOAI_AUTO_UPDATE=false
|
|
3588
|
+
|
|
3589
|
+
# 또는 bashrc/zshrc에서 주석 처리
|
|
3590
|
+
# export MOAI_AUTO_UPDATE=true
|
|
3591
|
+
```
|
|
3592
|
+
|
|
3593
|
+
---
|
|
3594
|
+
|
|
3595
|
+
## 📚 참고 자료
|
|
3596
|
+
|
|
3597
|
+
- [Semantic Versioning](https://semver.org/)
|
|
3598
|
+
- [PEP 621 (pyproject.toml)](https://peps.python.org/pep-0621/)
|
|
3599
|
+
- [uv Documentation](https://github.com/astral-sh/uv)
|
|
3600
|
+
- [gh CLI Docs](https://cli.github.com/manual/)
|
|
3601
|
+
|
|
3602
|
+
---
|
|
3603
|
+
|
|
3604
|
+
**cc-manager 에이전트를 통해 이 커맨드를 자동 실행하세요!**
|