project-auto-wizard 0.13.3 โ†’ 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/README.md +1 -1
  2. package/bin/project-auto-wizard.js +18 -4
  3. package/package.json +2 -2
  4. package/payload/config/breaking-changes.json +28 -14
  5. package/payload/config/wizard-prompts.yml +102 -46
  6. package/payload/flutter-app/android/fastlane/Fastfile.playstore +44 -32
  7. package/payload/flutter-app/ios/ExportOptions.plist +8 -8
  8. package/payload/flutter-app/ios/fastlane/Fastfile +57 -43
  9. package/payload/scripts/changelog_manager.py +296 -257
  10. package/payload/scripts/issue_helper.py +54 -50
  11. package/payload/scripts/messages.py +2279 -0
  12. package/payload/scripts/truncate_release_notes.py +7 -6
  13. package/payload/scripts/version_manager.py +64 -61
  14. package/payload/version.yml.template +2 -1
  15. package/payload/workflows/common/PROJECT-COMMON-AI-PR-SUMMARY.yaml +17 -12
  16. package/payload/workflows/common/PROJECT-COMMON-AUTO-CHANGELOG-CONTROL.yaml +59 -34
  17. package/payload/workflows/common/PROJECT-COMMON-ISSUE-HELPER.yaml +17 -15
  18. package/payload/workflows/common/PROJECT-COMMON-README-VERSION-UPDATE.yaml +17 -10
  19. package/payload/workflows/common/PROJECT-COMMON-RELEASE-PUBLISH.yaml +54 -44
  20. package/payload/workflows/common/PROJECT-COMMON-VERSION-CONTROL.yaml +24 -17
  21. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-FIREBASE-CICD.yaml +194 -184
  22. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-PLAYSTORE-CICD.yaml +226 -213
  23. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-SELFHOSTED-CICD.yaml +46 -42
  24. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-TEST-APK.yaml +334 -241
  25. package/payload/workflows/flutter/PROJECT-FLUTTER-APP-BUILD-TRIGGER.yaml +152 -128
  26. package/payload/workflows/flutter/PROJECT-FLUTTER-CI.yaml +246 -188
  27. package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT.yaml +353 -238
  28. package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TESTFLIGHT.yaml +96 -85
  29. package/payload/workflows/go/PROJECT-GO-CI.yaml +47 -36
  30. package/payload/workflows/go/PROJECT-GO-PR-PREVIEW.yaml +945 -508
  31. package/payload/workflows/go/PROJECT-GO-SIMPLE-CICD.yaml +155 -133
  32. package/payload/workflows/next/PROJECT-NEXT-CI.yaml +76 -60
  33. package/payload/workflows/next/PROJECT-NEXT-CICD.yaml +97 -77
  34. package/payload/workflows/python/PROJECT-PYTHON-CI.yaml +62 -47
  35. package/payload/workflows/python/PROJECT-PYTHON-PR-PREVIEW.yaml +942 -505
  36. package/payload/workflows/python/PROJECT-PYTHON-SIMPLE-CICD.yaml +148 -126
  37. package/payload/workflows/react/PROJECT-REACT-CI.yaml +86 -70
  38. package/payload/workflows/react/PROJECT-REACT-CICD.yaml +112 -92
  39. package/payload/workflows/spring/PROJECT-SPRING-CI.yml +112 -82
  40. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-NGINX-CICD.yaml +180 -150
  41. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-TRAEFIK-CICD.yaml +161 -131
  42. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-PR-PREVIEW.yaml +970 -549
  43. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-SIMPLE-CICD.yaml +193 -162
  44. package/src/cli/args.js +98 -52
  45. package/src/cli/help.js +8 -41
  46. package/src/commands/doctor.js +85 -89
  47. package/src/commands/dry-run.js +63 -43
  48. package/src/commands/full.js +79 -77
  49. package/src/commands/install-settings.js +16 -15
  50. package/src/commands/interactive-flutter.js +20 -19
  51. package/src/commands/interactive.js +135 -132
  52. package/src/commands/purge.js +47 -42
  53. package/src/commands/status.js +36 -36
  54. package/src/commands/uninstall.js +43 -41
  55. package/src/context.js +12 -11
  56. package/src/core/assets.js +12 -11
  57. package/src/core/baseline.js +27 -27
  58. package/src/core/branches.js +29 -27
  59. package/src/core/branding.js +7 -6
  60. package/src/core/breaking-check.js +22 -21
  61. package/src/core/breaking.js +15 -8
  62. package/src/core/copy/app-files.js +5 -4
  63. package/src/core/copy/flutter-app.js +8 -8
  64. package/src/core/copy/gitignore.js +58 -50
  65. package/src/core/copy/readme.js +45 -35
  66. package/src/core/copy/simple.js +16 -15
  67. package/src/core/copy/workflows.js +131 -124
  68. package/src/core/deploy-style.js +51 -48
  69. package/src/core/detect-fs.js +57 -57
  70. package/src/core/detect.js +67 -65
  71. package/src/core/errors.js +2 -2
  72. package/src/core/flutter-doctor.js +17 -16
  73. package/src/core/flutter-hooks.js +33 -32
  74. package/src/core/flutter-options.js +34 -33
  75. package/src/core/fsutil.js +12 -12
  76. package/src/core/installed-stores.js +4 -4
  77. package/src/core/logger.js +42 -40
  78. package/src/core/paths-resolve.js +88 -86
  79. package/src/core/paths.js +10 -10
  80. package/src/core/release-options.js +8 -8
  81. package/src/core/removal-exec.js +14 -13
  82. package/src/core/removal-plan.js +37 -37
  83. package/src/core/types.js +47 -47
  84. package/src/core/verify.js +44 -38
  85. package/src/core/version-yml.js +76 -68
  86. package/src/core/wizard-env.js +46 -46
  87. package/src/core/wizard-labels.js +63 -41
  88. package/src/i18n/catalog/en/cli.js +50 -0
  89. package/src/i18n/catalog/en/commands.js +187 -0
  90. package/src/i18n/catalog/en/copy.js +19 -0
  91. package/src/i18n/catalog/en/core.js +74 -0
  92. package/src/i18n/catalog/en/core2.js +15 -0
  93. package/src/i18n/catalog/en/ui.js +221 -0
  94. package/src/i18n/catalog/en.js +12 -0
  95. package/src/i18n/catalog/index.js +5 -0
  96. package/src/i18n/catalog/ko/cli.js +50 -0
  97. package/src/i18n/catalog/ko/commands.js +187 -0
  98. package/src/i18n/catalog/ko/copy.js +19 -0
  99. package/src/i18n/catalog/ko/core.js +74 -0
  100. package/src/i18n/catalog/ko/core2.js +15 -0
  101. package/src/i18n/catalog/ko/ui.js +221 -0
  102. package/src/i18n/catalog/ko.js +10 -0
  103. package/src/i18n/index.js +44 -0
  104. package/src/i18n/languages.js +9 -0
  105. package/src/index.js +128 -94
  106. package/src/ui/ansi.js +7 -7
  107. package/src/ui/banner.js +7 -6
  108. package/src/ui/env-plan.js +82 -81
  109. package/src/ui/prompts.js +97 -122
  110. package/src/ui/readline-engine.js +59 -58
  111. package/src/ui/status-cards.js +37 -31
  112. package/src/ui/summary.js +89 -88
@@ -1,80 +1,81 @@
1
1
  # project-auto-wizard:managed-workflow
2
- # Python FastAPI CI/CD ๋ฐฐํฌ (SSH + Docker)
3
- # {{MAIN_BRANCH}} ๋ธŒ๋žœ์น˜ ํ‘ธ์‹œ ์‹œ Docker ์ด๋ฏธ์ง€๋ฅผ ๋นŒ๋“œํ•˜๊ณ 
4
- # SSH๋กœ ์ ‘์† ๊ฐ€๋Šฅํ•œ ์„œ๋ฒ„(SynologyยทAWS EC2ยทVPS ๋“ฑ)์— ์ž๋™ ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค.
2
+ # Python FastAPI CI/CD deployment (SSH + Docker)
3
+ # Builds a Docker image when the {{MAIN_BRANCH}} branch is pushed and
4
+ # deploys it automatically to any server reachable over SSH (Synology, AWS EC2, VPS, ...).
5
5
  #
6
- # ํ•„์ˆ˜ GitHub Secrets
7
- # ENV_FILE: .env ํŒŒ์ผ ๋‚ด์šฉ
8
- # DOCKERHUB_USERNAME: DockerHub ์‚ฌ์šฉ์ž๋ช…
9
- # DOCKERHUB_TOKEN: DockerHub ์•ก์„ธ์Šค ํ† ํฐ
10
- # SERVER_HOST: ๋ฐฐํฌ ์„œ๋ฒ„ ์ฃผ์†Œ
11
- # SERVER_USER: SSH ์‚ฌ์šฉ์ž๋ช…
12
- # SERVER_PASSWORD: SSH ๋น„๋ฐ€๋ฒˆํ˜ธ (SSH_AUTH_METHOD=password์ผ ๋•Œ)
13
- # SSH_KEY: SSH ๊ฐœ์ธํ‚ค .pem ๋‚ด์šฉ (SSH_AUTH_METHOD=key์ผ ๋•Œ, AWS EC2 ๋“ฑ)
6
+ # Required GitHub Secrets
7
+ # ENV_FILE: contents of the .env file
8
+ # DOCKERHUB_USERNAME: DockerHub username
9
+ # DOCKERHUB_TOKEN: DockerHub access token
10
+ # SERVER_HOST: deploy server address
11
+ # SERVER_USER: SSH username
12
+ # SERVER_PASSWORD: SSH password (when SSH_AUTH_METHOD=password)
13
+ # SSH_KEY: contents of the SSH private key .pem (when SSH_AUTH_METHOD=key, e.g. AWS EC2)
14
14
  #
15
- # ํ™˜๊ฒฝ๋ณ€์ˆ˜๋Š” ์•„๋ž˜ env ์„น์…˜์—์„œ ์„ค์ •ํ•˜๋ฉฐ, ํ•ญ๋ชฉ๋ณ„ ์„ค๋ช…๊ณผ ๊ธฐ๋ณธ๊ฐ’์€ ๊ฐ ์ค„์— ์ ํ˜€ ์žˆ์Šต๋‹ˆ๋‹ค.
16
- # HEALTHCHECK_PATH ์˜ˆ์‹œ: FastAPI "/docs", ์ปค์Šคํ…€ "/api/v1/health"
15
+ # Environment variables are set in the env section below; each line has its description and default.
16
+ # HEALTHCHECK_PATH examples: FastAPI "/docs", custom "/api/v1/health"
17
17
 
18
18
  name: PROJECT-PYTHON-SIMPLE-CICD
19
19
 
20
20
  on:
21
21
  push:
22
22
  branches:
23
- - "{{MAIN_BRANCH}}" # ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ
24
- # @wizard paths-anchor (๋ชจ๋…ธ๋ ˆํฌ์ผ ๋•Œ integrator๊ฐ€ paths ํ•„ํ„ฐ๋ฅผ ์—ฌ๊ธฐ ์ฃผ์ž…)
25
- workflow_dispatch: # ์ˆ˜๋™ ์‹คํ–‰ ํ—ˆ์šฉ
23
+ - "{{MAIN_BRANCH}}" # production deploy
24
+ # @wizard paths-anchor (for a monorepo the integrator injects the paths filter here)
25
+ workflow_dispatch: # allow manual runs
26
26
 
27
27
  env:
28
- # ํ”„๋กœ์ ํŠธ ๊ณ ์œ  ์‹๋ณ„์ž
28
+ # Unique project identifier
29
29
  PROJECT_NAME: "__PROJECT_NAME__" # @wizard ask:@repo
30
- # ๋ชจ๋…ธ๋ ˆํฌ(--paths)์—์„œ ์ด ํ”„๋กœ์ ํŠธ๊ฐ€ ์žˆ๋Š” ํ•˜์œ„ ๊ฒฝ๋กœ. ๋นŒ๋“œยทDocker context์˜ ๊ธฐ์ค€ ('.'์ด๋ฉด ๋ ˆํฌ ๋ฃจํŠธ)
30
+ # Subdirectory of this project in a monorepo (--paths). Base for the build and Docker context ('.' means the repo root)
31
31
  PROJECT_PATH: "." # @wizard auto:project-path
32
- # ๋ชจ๋…ธ๋ ˆํฌ(PROJECT_PATH๊ฐ€ '.'์ด ์•„๋‹˜)์—์„œ๋Š” ์ด๋ฏธ์ง€ยท์ปจํ…Œ์ด๋„ˆยท๋„๋ฉ”์ธ ์ด๋ฆ„์— '-python'๋ฅผ ๋ถ™์—ฌ
33
- # ๊ฐ™์€ ๋ ˆํฌ์˜ ๋‹ค๋ฅธ ํƒ€์ž… ์„œ๋น„์Šค์™€ ์ด๋ฆ„์ด ๊ฒน์น˜์ง€ ์•Š๊ฒŒ ํ•œ๋‹ค (์˜ˆ: my-app-python)
32
+ # In a monorepo (PROJECT_PATH is not '.') '-python' is appended to the image, container and domain names
33
+ # so they do not collide with services of other types in the same repo (e.g. my-app-python)
34
34
 
35
- # ํฌํŠธ ์„ค์ •
35
+ # Port settings
36
36
  DEPLOY_PORT: "__DEPLOY_PORT__" # @wizard ask:8000
37
37
 
38
- # ์ปจํ…Œ์ด๋„ˆ ์ด๋ฆ„ ์„ค์ • (๋น„์›Œ๋‘๋ฉด PROJECT_NAME ์‚ฌ์šฉ)
38
+ # Container name (uses PROJECT_NAME when empty)
39
39
  CONTAINER_NAME: ""
40
40
 
41
- # ๋ณผ๋ฅจ ๋งˆ์šดํŠธ ์„ค์ • (๋นˆ๊ฐ’์ด๋ฉด ๋งˆ์šดํŠธ ์•ˆํ•จ)
41
+ # Volume mount settings (no mount when empty)
42
42
  ENABLE_VOLUME_MOUNT: "false" # @wizard ask:false
43
43
  VOLUME_HOST_PATH: "/volume1/projects/__PROJECT_NAME__" # @wizard ask:/volume1/projects/__PROJECT_NAME__
44
44
  VOLUME_CONTAINER_PATH: "/mnt/__PROJECT_NAME__" # @wizard ask:/mnt/__PROJECT_NAME__
45
45
 
46
- # SSH ์ธ์ฆ ๋ฐฉ์‹: "password"(Synologyยท์ผ๋ฐ˜ ์„œ๋ฒ„) | "key"(AWS EC2ยท.pem)
47
- # password โ†’ SERVER_PASSWORD secret ์‚ฌ์šฉ
48
- # key โ†’ SSH_KEY secret ์‚ฌ์šฉ (.pem ํŒŒ์ผ ์ „์ฒด ๋‚ด์šฉ์„ secret ๊ฐ’์œผ๋กœ)
46
+ # SSH auth method: "password" (Synology, generic servers) | "key" (AWS EC2, .pem)
47
+ # password -> uses the SERVER_PASSWORD secret
48
+ # key -> uses the SSH_KEY secret (the whole .pem file content as the secret value)
49
49
  SSH_AUTH_METHOD: "password" # @wizard ask:password
50
50
 
51
- # SSH ์—ฐ๊ฒฐ ์„ค์ •
51
+ # SSH connection settings
52
52
  SSH_PORT: "__SSH_PORT__" # @wizard ask:2022
53
- SSH_COMMAND_TIMEOUT: "600s" # SSH ๋ช…๋ น ์‹คํ–‰ ํƒ€์ž„์•„์›ƒ
54
- SSH_CONNECTION_TIMEOUT: "60s" # SSH ์—ฐ๊ฒฐ ํƒ€์ž„์•„์›ƒ
53
+ SSH_COMMAND_TIMEOUT: "600s" # SSH command execution timeout
54
+ SSH_CONNECTION_TIMEOUT: "60s" # SSH connection timeout
55
55
 
56
- # ์ปจํ…Œ์ด๋„ˆ ํฌํŠธ ์„ค์ •
57
- CONTAINER_INTERNAL_PORT: "8000" # FastAPI ๋‚ด๋ถ€ ํฌํŠธ
56
+ # Container port settings
57
+ CONTAINER_INTERNAL_PORT: "8000" # FastAPI internal port
58
58
 
59
- # ํ—ฌ์Šค์ฒดํฌ ์„ค์ •
60
- HEALTHCHECK_WAIT_SECONDS: "10" # ์ปจํ…Œ์ด๋„ˆ ์ดˆ๊ธฐํ™” ๋Œ€๊ธฐ ์‹œ๊ฐ„ (์ดˆ)
61
- HEALTHCHECK_PATH: "/docs" # HTTP ์—”๋“œํฌ์ธํŠธ ๊ฒฝ๋กœ (๋น„์–ด์žˆ์œผ๋ฉด ๋กœ๊ทธ ํŒจํ„ด๋งŒ ์‚ฌ์šฉ)
62
- HEALTHCHECK_MAX_RETRIES: "5" # HTTP ์žฌ์‹œ๋„ ํšŸ์ˆ˜
63
- HEALTHCHECK_RETRY_INTERVAL: "3" # ์žฌ์‹œ๋„ ๊ฐ„๊ฒฉ (์ดˆ)
64
- HEALTHCHECK_LOG_PATTERN: "Uvicorn running on" # Fallback ๋กœ๊ทธ ๊ฒ€์ƒ‰ ํŒจํ„ด
59
+ # Health check settings
60
+ HEALTHCHECK_WAIT_SECONDS: "10" # wait for container initialization (seconds)
61
+ HEALTHCHECK_PATH: "/docs" # HTTP endpoint path (only the log pattern is used when empty)
62
+ HEALTHCHECK_MAX_RETRIES: "5" # HTTP retry count
63
+ HEALTHCHECK_RETRY_INTERVAL: "3" # retry interval (seconds)
64
+ HEALTHCHECK_LOG_PATTERN: "Uvicorn running on" # Fallback log search pattern
65
65
 
66
66
  jobs:
67
- # Job: ๋นŒ๋“œ
67
+ # Job: build
68
68
  build:
69
- name: Python FastAPI ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋นŒ๋“œ
69
+ name: Build Python FastAPI application
70
70
  runs-on: ubuntu-latest
71
71
 
72
72
  steps:
73
- - name: ์ฝ”๋“œ ์ฒดํฌ์•„์›ƒ
73
+ - name: Checkout repository
74
74
  uses: actions/checkout@v7
75
75
 
76
- # ํ•„์ˆ˜ SecretยทDockerfile์ด ์—†์œผ๋ฉด docker ๋กœ๊ทธ์ธ ๊ฐ™์€ ์„œ๋“œํŒŒํ‹ฐ ์˜ค๋ฅ˜ ๋Œ€์‹  ๋น ์ง„ ํ•ญ๋ชฉ์„ ์•Œ๋ ค ์ฃผ๊ณ  ๋ฉˆ์ถ˜๋‹ค
77
- - name: ๋ฐฐํฌ ์‚ฌ์ „ ์ ๊ฒ€ (SecretยทDockerfile)
76
+ # If a required Secret or the Dockerfile is missing, report the missing item and stop
77
+ # instead of failing later with a third-party error such as docker login
78
+ - name: Deploy pre-check (Secrets and Dockerfile)
78
79
  working-directory: ${{ env.PROJECT_PATH }}
79
80
  env:
80
81
  DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
@@ -85,11 +86,12 @@ jobs:
85
86
  SSH_KEY: ${{ secrets.SSH_KEY }}
86
87
  DOCKERFILE: Dockerfile
87
88
  run: |
89
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
88
90
  MISSING=""
89
91
  for NAME in DOCKERHUB_USERNAME DOCKERHUB_TOKEN SERVER_HOST SERVER_USER; do
90
92
  [ -n "${!NAME}" ] || MISSING="$MISSING $NAME"
91
93
  done
92
- # SSH_AUTH_METHOD=key๋ฉด SSH_KEY, ์•„๋‹ˆ๋ฉด SERVER_PASSWORD๊ฐ€ ํ•„์š”ํ•˜๋‹ค
94
+ # SSH_AUTH_METHOD=key needs SSH_KEY, otherwise SERVER_PASSWORD is required
93
95
  if [ "${SSH_AUTH_METHOD:-password}" = "key" ]; then
94
96
  [ -n "$SSH_KEY" ] || MISSING="$MISSING SSH_KEY"
95
97
  else
@@ -97,78 +99,95 @@ jobs:
97
99
  fi
98
100
  FAILED=false
99
101
  if [ -n "$MISSING" ]; then
100
- echo "::error title=ํ•„์ˆ˜ Secret ๋ˆ„๋ฝ::๋“ฑ๋ก๋˜์ง€ ์•Š์€ GitHub Secret:$MISSING โ€” Settings โ†’ Secrets and variables โ†’ Actions์—์„œ ๋“ฑ๋กํ•˜์„ธ์š”"
102
+ echo "::error title=$(m cicd.precheck_secret_title)::$(m cicd.precheck_secret_body missing="$MISSING")"
101
103
  FAILED=true
102
104
  fi
103
105
  if [ ! -f "$DOCKERFILE" ]; then
104
- echo "::error title=Dockerfile ์—†์Œ::${PROJECT_PATH}/${DOCKERFILE#./} ํŒŒ์ผ์ด ์—†์Šต๋‹ˆ๋‹ค. ์ด ์›Œํฌํ”Œ๋กœ์šฐ๋Š” Docker ์ด๋ฏธ์ง€๋กœ ๋ฐฐํฌํ•˜๋ฏ€๋กœ Dockerfile์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค (์„œ๋ฒ„ ๋ฐฐํฌ๋ฅผ ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ด ์›Œํฌํ”Œ๋กœ์šฐ ํŒŒ์ผ์„ ์‚ญ์ œํ•˜์„ธ์š”)"
106
+ echo "::error title=$(m cicd.precheck_dockerfile_title)::$(m cicd.precheck_dockerfile_body path="${PROJECT_PATH}/${DOCKERFILE#./}")"
105
107
  FAILED=true
106
108
  fi
107
109
  if [ "$FAILED" = "true" ]; then
108
110
  exit 1
109
111
  fi
110
- echo "โœ… ์‚ฌ์ „ ์ ๊ฒ€ ํ†ต๊ณผ: ํ•„์ˆ˜ Secret๊ณผ Dockerfile์ด ๋ชจ๋‘ ์žˆ์Šต๋‹ˆ๋‹ค"
112
+ m cicd.precheck_ok
111
113
 
112
- - name: ๋””์Šคํฌ ๊ณต๊ฐ„ ํ™•๋ณด
114
+ - name: Free up disk space
113
115
  run: |
114
- echo "๐Ÿ“Š ๋นŒ๋“œ ์ „ ๋””์Šคํฌ ์‚ฌ์šฉ๋Ÿ‰:"
116
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
117
+ m cicd.disk_before
115
118
  df -h
116
119
 
117
- echo "๐Ÿงน ๋ถˆํ•„์š”ํ•œ ํŒŒ์ผ ์ •๋ฆฌ ์ค‘..."
120
+ m cicd.disk_cleaning
118
121
  sudo rm -rf /usr/share/dotnet || true
119
122
  sudo rm -rf /opt/ghc || true
120
123
  sudo rm -rf /usr/local/share/boost || true
121
124
  sudo rm -rf "$AGENT_TOOLSDIRECTORY" || true
122
125
 
123
- echo "๐Ÿณ Docker ์‹œ์Šคํ…œ ์ •๋ฆฌ ์ค‘..."
126
+ m cicd.disk_docker_prune
124
127
  docker system prune -af --volumes || true
125
128
 
126
- echo "๐Ÿ“Š ์ •๋ฆฌ ํ›„ ๋””์Šคํฌ ์‚ฌ์šฉ๋Ÿ‰:"
129
+ m cicd.disk_after_cleanup
127
130
  df -h
128
131
 
129
- - name: .env ํŒŒ์ผ ์ƒ์„ฑ
132
+ - name: Create .env file
130
133
  working-directory: ${{ env.PROJECT_PATH }}
131
134
  run: |
135
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
132
136
  cat > .env << 'EOF'
133
137
  ${{ secrets.ENV_FILE }}
134
138
  EOF
135
- echo "โœ… .env ํŒŒ์ผ์ด ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค"
139
+ m cicd.dotenv_created
136
140
 
137
- - name: Docker ๋นŒ๋“œํ™˜๊ฒฝ ์„ค์ •
141
+ - name: Set up Docker Buildx
138
142
  uses: docker/setup-buildx-action@v3
139
143
 
140
- - name: DockerHub ๋กœ๊ทธ์ธ
144
+ - name: Log in to DockerHub
141
145
  uses: docker/login-action@v3
142
146
  with:
143
147
  username: ${{ secrets.DOCKERHUB_USERNAME }}
144
148
  password: ${{ secrets.DOCKERHUB_TOKEN }}
145
149
 
146
- - name: Docker ์ด๋ฏธ์ง€ ๋นŒ๋“œ ๋ฐ ํ‘ธ์‹œ
150
+ - name: Build and push Docker image
147
151
  uses: docker/build-push-action@v5
148
152
  with:
149
153
  context: ${{ env.PROJECT_PATH }}
150
154
  file: ${{ env.PROJECT_PATH }}/Dockerfile
151
155
  push: true
152
156
  tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.PROJECT_PATH != '.' && format('{0}-python', env.PROJECT_NAME) || env.PROJECT_NAME }}:${{ github.ref_name }}
153
- # GitHub Actions ์บ์‹œ ์‚ฌ์šฉ (๋กœ์ปฌ ๋””์Šคํฌ ๊ณต๊ฐ„ ์ ˆ์•ฝ)
157
+ # Use the GitHub Actions cache (saves local disk space)
154
158
  cache-from: type=gha
155
159
  cache-to: type=gha,mode=max
156
160
 
157
- - name: ๋นŒ๋“œ ํ›„ ์ •๋ฆฌ
161
+ - name: Clean up after build
158
162
  if: always()
159
163
  run: |
160
- echo "๐Ÿงน ๋นŒ๋“œ ํ›„ ์ •๋ฆฌ ์ค‘..."
164
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
165
+ m cicd.post_build_cleanup
161
166
  docker system prune -f || true
162
- echo "๐Ÿ“Š ์ตœ์ข… ๋””์Šคํฌ ์‚ฌ์šฉ๋Ÿ‰:"
167
+ m cicd.disk_final
163
168
  df -h
164
169
 
165
- # Job: ๋ฐฐํฌ
170
+ # Job: deploy
166
171
  deploy:
167
- name: ์›๊ฒฉ ์„œ๋ฒ„ ๋ฐฐํฌ
172
+ name: Deploy to remote server
168
173
  needs: build
169
174
  runs-on: ubuntu-latest
170
175
 
171
176
  steps:
177
+ # The deploy script runs on the remote server, so the messages are resolved here
178
+ # and handed to it through env vars (PAW_M_*)
179
+ - name: Checkout message catalog
180
+ uses: actions/checkout@v7
181
+ with:
182
+ sparse-checkout: |
183
+ .github/scripts/messages.py
184
+ version.yml
185
+ sparse-checkout-cone-mode: false
186
+
187
+ - name: Load messages
188
+ run: |
189
+ python3 .github/scripts/messages.py dump cicd. | PYTHONIOENCODING=utf-8 python3 -c 'import json,sys; [print("PAW_M_" + k.replace(".", "_") + "=" + v) for k, v in json.load(sys.stdin).items()]' >> "$GITHUB_ENV"
190
+
172
191
  - name: Deploy
173
192
  uses: appleboy/ssh-action@v1.0.3
174
193
  env:
@@ -185,76 +204,79 @@ jobs:
185
204
  script: |
186
205
  set -e
187
206
 
188
- # ๋ฐฐํฌ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ •
189
- echo "๐Ÿ”ง ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ •.."
207
+ # Fill the {name} placeholders of a message template (usage: m "template" name=value ...)
208
+ m() { local s="$1" kv; shift; for kv in "$@"; do s="${s//\{${kv%%=*}\}/${kv#*=}}"; done; printf '%s\n' "$s"; }
209
+
210
+ # Set deploy environment variables
211
+ m "${{ env.PAW_M_cicd_setup_env }}"
190
212
  export PATH=$PATH:/usr/local/bin
191
213
  export PW=${{ secrets.SERVER_PASSWORD }}
192
214
 
193
- # SSH ์ธ์ฆ ๋ฐฉ์‹์— ๋”ฐ๋ฅธ sudo ์ถ”์ƒํ™”
194
- # password ๋ชจ๋“œ: echo $PW | sudo -S (Synology ๋“ฑ sudo ๋น„๋ฐ€๋ฒˆํ˜ธ ํ•„์š” ์„œ๋ฒ„)
195
- # key ๋ชจ๋“œ: sudo ์ง์ ‘ (AWS EC2 ๋“ฑ passwordless sudo ์„œ๋ฒ„)
215
+ # sudo abstraction per SSH auth method
216
+ # password mode: echo $PW | sudo -S (servers that need a sudo password, e.g. Synology)
217
+ # key mode: plain sudo (passwordless-sudo servers, e.g. AWS EC2)
196
218
  SSH_AUTH_METHOD="${SSH_AUTH_METHOD:-password}"
197
219
  if [ "${SSH_AUTH_METHOD}" = "key" ]; then
198
220
  SUDO() { sudo "$@"; }
199
221
  else
200
222
  SUDO() { echo "$PW" | sudo -S "$@"; }
201
223
  fi
202
- echo "๐Ÿ” SSH ์ธ์ฆ ๋ฐฉ์‹: ${SSH_AUTH_METHOD}"
224
+ m "${{ env.PAW_M_cicd_ssh_auth }}" method="${SSH_AUTH_METHOD}"
203
225
 
204
226
  BRANCH=${{ github.ref_name }}
205
227
 
206
228
  PROJECT_NAME="${{ env.PROJECT_PATH != '.' && format('{0}-python', env.PROJECT_NAME) || env.PROJECT_NAME }}"
207
229
 
208
- # ํฌํŠธ ๋ฐ ์ปจํ…Œ์ด๋„ˆ๋ช… ์„ค์ •
230
+ # Port and container name
209
231
  PORT=${{ env.DEPLOY_PORT }}
210
232
 
211
233
  if [ -z "${{ env.CONTAINER_NAME }}" ]; then
212
234
  CONTAINER_NAME="${PROJECT_NAME}"
213
- echo "โ„น๏ธ CONTAINER_NAME์ด ์„ค์ •๋˜์ง€ ์•Š์•„ PROJECT_NAME์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค: $CONTAINER_NAME"
235
+ m "${{ env.PAW_M_cicd_container_default }}" container="$CONTAINER_NAME"
214
236
  else
215
237
  CONTAINER_NAME="${{ env.CONTAINER_NAME }}"
216
- echo "โ„น๏ธ ์‚ฌ์šฉ์ž ์ง€์ • CONTAINER_NAME ์‚ฌ์šฉ: $CONTAINER_NAME"
238
+ m "${{ env.PAW_M_cicd_container_custom }}" container="$CONTAINER_NAME"
217
239
  fi
218
240
 
219
- echo "๐Ÿš€ ๋ฐฐํฌ ํ™˜๊ฒฝ์œผ๋กœ ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค (๋ธŒ๋žœ์น˜: $BRANCH)"
241
+ m "${{ env.PAW_M_cicd_deploy_start }}" branch="$BRANCH"
220
242
 
221
- echo "๐Ÿ“‹ ๋ฐฐํฌ ์„ค์ • ์ •๋ณด:"
222
- echo " - ๋ธŒ๋žœ์น˜: $BRANCH"
223
- echo " - ํ”„๋กœ์ ํŠธ: $PROJECT_NAME"
224
- echo " - ์ปจํ…Œ์ด๋„ˆ ์ด๋ฆ„: $CONTAINER_NAME"
225
- echo " - ํฌํŠธ: $PORT"
226
- echo " - Docker ์ด๋ฏธ์ง€: ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:${BRANCH}"
243
+ m "${{ env.PAW_M_cicd_config_title }}"
244
+ m "${{ env.PAW_M_cicd_config_branch }}" branch="$BRANCH"
245
+ m "${{ env.PAW_M_cicd_config_project }}" project="$PROJECT_NAME"
246
+ m "${{ env.PAW_M_cicd_config_container }}" container="$CONTAINER_NAME"
247
+ m "${{ env.PAW_M_cicd_config_port }}" port="$PORT"
248
+ m "${{ env.PAW_M_cicd_config_image }}" image="${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:${BRANCH}"
227
249
 
228
- # Docker ์ด๋ฏธ์ง€ ํ’€ (Pull)
229
- echo "โฌ‡๏ธ Docker ์ด๋ฏธ์ง€ ํ’€: ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:${BRANCH}"
250
+ # Pull the Docker image
251
+ m "${{ env.PAW_M_cicd_pull_image }}" image="${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:${BRANCH}"
230
252
  SUDO docker pull ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:${BRANCH}
231
253
 
232
- # ๊ธฐ์กด ์ปจํ…Œ์ด๋„ˆ ์ •๋ฆฌ
233
- echo "๐Ÿงน ์ปจํ…Œ์ด๋„ˆ $CONTAINER_NAME ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ ์ค‘..."
254
+ # Clean up the existing container
255
+ m "${{ env.PAW_M_cicd_container_check }}" container="$CONTAINER_NAME"
234
256
 
235
257
  if SUDO docker ps -a --format '{{.Names}}' | grep -Eq "^${CONTAINER_NAME}\$"; then
236
- echo "โš ๏ธ ์ปจํ…Œ์ด๋„ˆ $CONTAINER_NAME ์ด(๊ฐ€) ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์ค‘์ง€ ๋ฐ ์‚ญ์ œ ์ค‘..."
258
+ m "${{ env.PAW_M_cicd_container_exists }}" container="$CONTAINER_NAME"
237
259
  SUDO docker rm -f $CONTAINER_NAME
238
- echo "โœ… ์ปจํ…Œ์ด๋„ˆ $CONTAINER_NAME ์ด(๊ฐ€) ์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."
260
+ m "${{ env.PAW_M_cicd_container_removed }}" container="$CONTAINER_NAME"
239
261
  else
240
- echo "โ„น๏ธ ์กด์žฌํ•˜๋Š” ์ปจํ…Œ์ด๋„ˆ $CONTAINER_NAME ์ด(๊ฐ€) ์—†์Šต๋‹ˆ๋‹ค."
262
+ m "${{ env.PAW_M_cicd_container_none }}" container="$CONTAINER_NAME"
241
263
  fi
242
264
 
243
- # ์ƒˆ ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰
244
- echo "๐Ÿš€ ์ƒˆ๋กœ์šด ์ปจํ…Œ์ด๋„ˆ $CONTAINER_NAME ์‹คํ–‰ ์ค‘..."
265
+ # Start the new container
266
+ m "${{ env.PAW_M_cicd_container_run }}" container="$CONTAINER_NAME"
245
267
 
246
- # .env ํŒŒ์ผ์€ ์ด๋ฏธ Docker ์ด๋ฏธ์ง€์— ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค
268
+ # The .env file is already baked into the Docker image
247
269
 
248
270
  VOLUME_OPTS="-v /etc/localtime:/etc/localtime:ro"
249
271
  if [ "${{ env.ENABLE_VOLUME_MOUNT }}" == "true" ]; then
250
272
  if [ ! -d "${{ env.VOLUME_HOST_PATH }}" ]; then
251
- echo "๐Ÿ“ ๋ณผ๋ฅจ ๋งˆ์šดํŠธ ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ: ${{ env.VOLUME_HOST_PATH }}"
273
+ m "${{ env.PAW_M_cicd_volume_mkdir }}" path="${{ env.VOLUME_HOST_PATH }}"
252
274
  SUDO mkdir -p "${{ env.VOLUME_HOST_PATH }}"
253
275
  fi
254
276
  VOLUME_OPTS="$VOLUME_OPTS -v ${{ env.VOLUME_HOST_PATH }}:${{ env.VOLUME_CONTAINER_PATH }}"
255
- echo "๐Ÿ“ฆ ๋ณผ๋ฅจ ๋งˆ์šดํŠธ ํ™œ์„ฑํ™”: $VOLUME_OPTS"
277
+ m "${{ env.PAW_M_cicd_volume_on }}" opts="$VOLUME_OPTS"
256
278
  else
257
- echo "โ„น๏ธ ๋ณผ๋ฅจ ๋งˆ์šดํŠธ ๋น„ํ™œ์„ฑํ™”๋จ"
279
+ m "${{ env.PAW_M_cicd_volume_off }}"
258
280
  fi
259
281
 
260
282
  SUDO docker run -d \
@@ -264,84 +286,84 @@ jobs:
264
286
  $VOLUME_OPTS \
265
287
  ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:${BRANCH}
266
288
 
267
- # ์ปจํ…Œ์ด๋„ˆ ํ—ฌ์Šค์ฒดํฌ
268
- echo "โณ ์ปจํ…Œ์ด๋„ˆ ์ดˆ๊ธฐํ™” ๋Œ€๊ธฐ ์ค‘... (${{ env.HEALTHCHECK_WAIT_SECONDS }}์ดˆ)"
289
+ # Container health check
290
+ m "${{ env.PAW_M_cicd_health_wait }}" seconds="${{ env.HEALTHCHECK_WAIT_SECONDS }}"
269
291
  sleep ${{ env.HEALTHCHECK_WAIT_SECONDS }}
270
292
 
271
- # 1๋‹จ๊ณ„: ์ปจํ…Œ์ด๋„ˆ ํ”„๋กœ์„ธ์Šค ํ™•์ธ
272
- echo "๐Ÿฅ ์ปจํ…Œ์ด๋„ˆ ํ—ฌ์Šค์ฒดํฌ ์ค‘..."
293
+ # Step 1: check the container process
294
+ m "${{ env.PAW_M_cicd_health_check }}"
273
295
  if ! SUDO docker ps --format '{{.Names}}' | grep -Eq "^${CONTAINER_NAME}\$"; then
274
- echo "โŒ ์ปจํ…Œ์ด๋„ˆ $CONTAINER_NAME ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค"
296
+ m "${{ env.PAW_M_cicd_health_no_process }}" container="$CONTAINER_NAME"
275
297
  SUDO docker logs --tail 50 $CONTAINER_NAME || true
276
298
  exit 1
277
299
  fi
278
- echo "โœ… ์ปจํ…Œ์ด๋„ˆ ํ”„๋กœ์„ธ์Šค ์‹คํ–‰ ํ™•์ธ ์™„๋ฃŒ"
300
+ m "${{ env.PAW_M_cicd_health_process_ok }}"
279
301
 
280
- # 2๋‹จ๊ณ„: HTTP ์—”๋“œํฌ์ธํŠธ ์ฒดํฌ (์„ค์ •๋œ ๊ฒฝ์šฐ)
302
+ # Step 2: check the HTTP endpoint (when configured)
281
303
  HEALTHCHECK_SUCCESS=false
282
304
  if [ -n "${{ env.HEALTHCHECK_PATH }}" ]; then
283
- echo "๐ŸŒ HTTP ํ—ฌ์Šค์ฒดํฌ ์‹œ์ž‘: http://localhost:${PORT}${{ env.HEALTHCHECK_PATH }}"
305
+ m "${{ env.PAW_M_cicd_http_start }}" url="http://localhost:${PORT}${{ env.HEALTHCHECK_PATH }}"
284
306
 
285
307
  for i in $(seq 1 ${{ env.HEALTHCHECK_MAX_RETRIES }}); do
286
- echo " ์‹œ๋„ $i/${{ env.HEALTHCHECK_MAX_RETRIES }}..."
308
+ m "${{ env.PAW_M_cicd_http_try }}" i="$i" max="${{ env.HEALTHCHECK_MAX_RETRIES }}"
287
309
 
288
310
  HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:${PORT}${{ env.HEALTHCHECK_PATH }} || echo "000")
289
311
 
290
312
  if [ "$HTTP_CODE" = "200" ]; then
291
- echo "โœ… HTTP ํ—ฌ์Šค์ฒดํฌ ์„ฑ๊ณต (์‘๋‹ต ์ฝ”๋“œ: $HTTP_CODE)"
313
+ m "${{ env.PAW_M_cicd_http_ok }}" code="$HTTP_CODE"
292
314
  HEALTHCHECK_SUCCESS=true
293
315
  break
294
316
  else
295
- echo "โš ๏ธ HTTP ํ—ฌ์Šค์ฒดํฌ ์‹คํŒจ (์‘๋‹ต ์ฝ”๋“œ: $HTTP_CODE)"
317
+ m "${{ env.PAW_M_cicd_http_fail }}" code="$HTTP_CODE"
296
318
  if [ $i -lt ${{ env.HEALTHCHECK_MAX_RETRIES }} ]; then
297
- echo " ${{ env.HEALTHCHECK_RETRY_INTERVAL }}์ดˆ ํ›„ ์žฌ์‹œ๋„..."
319
+ m "${{ env.PAW_M_cicd_http_retry }}" interval="${{ env.HEALTHCHECK_RETRY_INTERVAL }}"
298
320
  sleep ${{ env.HEALTHCHECK_RETRY_INTERVAL }}
299
321
  fi
300
322
  fi
301
323
  done
302
324
 
303
- # HTTP ์ฒดํฌ ์‹คํŒจ ์‹œ fallback์œผ๋กœ ๋กœ๊ทธ ํŒจํ„ด ๋งค์นญ
325
+ # If the HTTP check fails, fall back to log pattern matching
304
326
  if [ "$HEALTHCHECK_SUCCESS" = "false" ]; then
305
- echo "โš ๏ธ HTTP ํ—ฌ์Šค์ฒดํฌ ์ตœ์ข… ์‹คํŒจ, ๋กœ๊ทธ ํŒจํ„ด ๋งค์นญ์œผ๋กœ fallback..."
327
+ m "${{ env.PAW_M_cicd_http_final_fail }}"
306
328
  fi
307
329
  else
308
- echo "โ„น๏ธ HEALTHCHECK_PATH๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•„ ๋กœ๊ทธ ํŒจํ„ด ๋งค์นญ๋งŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค"
330
+ m "${{ env.PAW_M_cicd_http_skipped }}"
309
331
  fi
310
332
 
311
- # 3๋‹จ๊ณ„: ๋กœ๊ทธ ํŒจํ„ด ๋งค์นญ (HTTP ์‹คํŒจ ์‹œ ๋˜๋Š” HTTP ์ฒดํฌ ๋น„ํ™œ์„ฑํ™” ์‹œ)
333
+ # Step 3: log pattern matching (when HTTP failed or the HTTP check is disabled)
312
334
  if [ "$HEALTHCHECK_SUCCESS" = "false" ]; then
313
- echo "๐Ÿ“‹ ๋กœ๊ทธ ํŒจํ„ด ๋งค์นญ ์‹œ์ž‘: '${{ env.HEALTHCHECK_LOG_PATTERN }}'"
335
+ m "${{ env.PAW_M_cicd_log_start }}" pattern="${{ env.HEALTHCHECK_LOG_PATTERN }}"
314
336
 
315
337
  if SUDO docker logs $CONTAINER_NAME 2>&1 | grep -q "${{ env.HEALTHCHECK_LOG_PATTERN }}"; then
316
- echo "โœ… ๋กœ๊ทธ ํŒจํ„ด ๋งค์นญ ์„ฑ๊ณต: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ •์ƒ์ ์œผ๋กœ ์‹œ์ž‘๋˜์—ˆ์Šต๋‹ˆ๋‹ค"
338
+ m "${{ env.PAW_M_cicd_log_ok }}"
317
339
  HEALTHCHECK_SUCCESS=true
318
340
  else
319
- echo "โŒ ๋กœ๊ทธ ํŒจํ„ด ๋งค์นญ ์‹คํŒจ: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ๋กœ๊ทธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค"
341
+ m "${{ env.PAW_M_cicd_log_fail }}"
320
342
  echo ""
321
- echo "๐Ÿ“‹ ๋””๋ฒ„๊น… ์ •๋ณด:"
322
- echo " - ๊ฒ€์ƒ‰ ํŒจํ„ด: ${{ env.HEALTHCHECK_LOG_PATTERN }}"
323
- echo " - ์ปจํ…Œ์ด๋„ˆ: $CONTAINER_NAME"
324
- echo " - ์ด๋ฏธ์ง€: ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:${BRANCH}"
325
- echo " - ํฌํŠธ: ${PORT}:${{ env.CONTAINER_INTERNAL_PORT }}"
326
- echo " - ๋ณผ๋ฅจ: $VOLUME_OPTS"
343
+ m "${{ env.PAW_M_cicd_debug_title }}"
344
+ m "${{ env.PAW_M_cicd_debug_pattern }}" pattern="${{ env.HEALTHCHECK_LOG_PATTERN }}"
345
+ m "${{ env.PAW_M_cicd_debug_container }}" container="$CONTAINER_NAME"
346
+ m "${{ env.PAW_M_cicd_debug_image }}" image="${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:${BRANCH}"
347
+ m "${{ env.PAW_M_cicd_debug_port }}" port="${PORT}:${{ env.CONTAINER_INTERNAL_PORT }}"
348
+ m "${{ env.PAW_M_cicd_debug_volume }}" volume="$VOLUME_OPTS"
327
349
  echo ""
328
- echo "๐Ÿ“‹ ์ปจํ…Œ์ด๋„ˆ ๋กœ๊ทธ (์ตœ๊ทผ 50์ค„):"
350
+ m "${{ env.PAW_M_cicd_debug_logs }}"
329
351
  SUDO docker logs --tail 50 $CONTAINER_NAME || true
330
352
  exit 1
331
353
  fi
332
354
  fi
333
355
 
334
356
  if [ "$HEALTHCHECK_SUCCESS" = "true" ]; then
335
- echo "โœ… ํ—ฌ์Šค์ฒดํฌ ์™„๋ฃŒ: ์ปจํ…Œ์ด๋„ˆ $CONTAINER_NAME ์ด(๊ฐ€) ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰ ์ค‘์ž…๋‹ˆ๋‹ค"
357
+ m "${{ env.PAW_M_cicd_health_done }}" container="$CONTAINER_NAME"
336
358
  fi
337
359
 
338
- echo "โœ… ๋ฐฐํฌ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!"
360
+ m "${{ env.PAW_M_cicd_deploy_done }}"
339
361
  echo ""
340
- echo "๐Ÿ“‹ ๋ฐฐํฌ ๊ฒฐ๊ณผ ์š”์•ฝ:"
341
- echo " ๐ŸŽฏ ํ”„๋กœ์ ํŠธ: $PROJECT_NAME"
342
- echo " ๐ŸŒฟ ๋ธŒ๋žœ์น˜: $BRANCH"
343
- echo " ๐Ÿณ ์ปจํ…Œ์ด๋„ˆ: $CONTAINER_NAME"
344
- echo " ๐ŸŒ ํฌํŠธ: $PORT"
345
- echo " โฐ ๋ฐฐํฌ ์‹œ๊ฐ„: $(date '+%Y-%m-%d %H:%M:%S')"
362
+ m "${{ env.PAW_M_cicd_summary_title }}"
363
+ m "${{ env.PAW_M_cicd_summary_project }}" project="$PROJECT_NAME"
364
+ m "${{ env.PAW_M_cicd_summary_branch }}" branch="$BRANCH"
365
+ m "${{ env.PAW_M_cicd_summary_container }}" container="$CONTAINER_NAME"
366
+ m "${{ env.PAW_M_cicd_summary_port }}" port="$PORT"
367
+ m "${{ env.PAW_M_cicd_summary_time }}" time="$(date '+%Y-%m-%d %H:%M:%S')"
346
368
  echo ""
347
- echo "๐Ÿ”— ์ ‘์† URL: http://${{ secrets.SERVER_HOST }}:${PORT}/docs"
369
+ m "${{ env.PAW_M_cicd_summary_url }}" url="http://${{ secrets.SERVER_HOST }}:${PORT}/docs"