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,20 +1,20 @@
1
1
  # project-auto-wizard:managed-workflow
2
- # React CI/CD ๋ฐฐํฌ
3
- # {{MAIN_BRANCH}} ๋ธŒ๋žœ์น˜ ํ‘ธ์‹œ ์‹œ Docker ์ด๋ฏธ์ง€๋ฅผ ๋นŒ๋“œํ•˜๊ณ  ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค.
2
+ # React CI/CD deployment
3
+ # Builds a Docker image and deploys it when the {{MAIN_BRANCH}} branch is pushed.
4
4
  #
5
5
  # GitHub Secrets
6
- # ENV_FILE: .env ํŒŒ์ผ ๋‚ด์šฉ
7
- # DOCKERHUB_USERNAME: DockerHub ์‚ฌ์šฉ์ž๋ช…
8
- # DOCKERHUB_TOKEN: DockerHub ์•ก์„ธ์Šค ํ† ํฐ
9
- # SERVER_HOST: ๋ฐฐํฌ ์„œ๋ฒ„ ์ฃผ์†Œ
10
- # SERVER_USER: SSH ์‚ฌ์šฉ์ž๋ช…
11
- # SERVER_PASSWORD: SSH ๋น„๋ฐ€๋ฒˆํ˜ธ (SSH_AUTH_METHOD=password์ผ ๋•Œ)
12
- # SSH_KEY: SSH ๊ฐœ์ธํ‚ค .pem ๋‚ด์šฉ (SSH_AUTH_METHOD=key์ผ ๋•Œ, AWS EC2 ๋“ฑ)
13
- # PROJECT_DEPLOY_PORT (์„ ํƒ): ๋ฐฐํฌ ํฌํŠธ (๊ธฐ๋ณธ: 3000)
6
+ # ENV_FILE: contents of the .env file
7
+ # DOCKERHUB_USERNAME: DockerHub username
8
+ # DOCKERHUB_TOKEN: DockerHub access token
9
+ # SERVER_HOST: deploy server address
10
+ # SERVER_USER: SSH username
11
+ # SERVER_PASSWORD: SSH password (when SSH_AUTH_METHOD=password)
12
+ # SSH_KEY: contents of the SSH private key .pem (when SSH_AUTH_METHOD=key, e.g. AWS EC2)
13
+ # PROJECT_DEPLOY_PORT (optional): deploy port (default: 3000)
14
14
  #
15
- # ํ™˜๊ฒฝ๋ณ€์ˆ˜ (env ์„น์…˜์—์„œ ์„ค์ •)
16
- # SSH_AUTH_METHOD: SSH ์ธ์ฆ ๋ฐฉ์‹ password | key (๊ธฐ๋ณธ: password)
17
- # SSH_PORT (๊ธฐ๋ณธ: 2022), SSH_COMMAND_TIMEOUT (๊ธฐ๋ณธ: 600s), SSH_CONNECTION_TIMEOUT (๊ธฐ๋ณธ: 60s)
15
+ # Environment variables (set in the env section)
16
+ # SSH_AUTH_METHOD: SSH auth method password | key (default: password)
17
+ # SSH_PORT (default: 2022), SSH_COMMAND_TIMEOUT (default: 600s), SSH_CONNECTION_TIMEOUT (default: 60s)
18
18
 
19
19
  name: PROJECT-REACT-CICD
20
20
 
@@ -22,41 +22,42 @@ on:
22
22
  push:
23
23
  branches:
24
24
  - "{{MAIN_BRANCH}}"
25
- # @wizard paths-anchor (๋ชจ๋…ธ๋ ˆํฌ์ผ ๋•Œ integrator๊ฐ€ paths ํ•„ํ„ฐ๋ฅผ ์—ฌ๊ธฐ ์ฃผ์ž…)
25
+ # @wizard paths-anchor (for a monorepo the integrator injects the paths filter here)
26
26
  workflow_dispatch:
27
27
 
28
28
  env:
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
32
  DOCKER_IMAGE_PREFIX: "front-container"
33
33
  NODE_VERSION: "20.15.0"
34
34
  ENV_FILE_NAME: ".env"
35
35
 
36
- # SSH ์ธ์ฆ ๋ฐฉ์‹: "password"(Synologyยท์ผ๋ฐ˜ ์„œ๋ฒ„) | "key"(AWS EC2ยท.pem)
37
- # password โ†’ SERVER_PASSWORD secret ์‚ฌ์šฉ
38
- # key โ†’ SSH_KEY secret ์‚ฌ์šฉ (.pem ํŒŒ์ผ ์ „์ฒด ๋‚ด์šฉ์„ secret ๊ฐ’์œผ๋กœ)
36
+ # SSH auth method: "password" (Synology, generic servers) | "key" (AWS EC2, .pem)
37
+ # password -> uses the SERVER_PASSWORD secret
38
+ # key -> uses the SSH_KEY secret (the whole .pem file content as the secret value)
39
39
  SSH_AUTH_METHOD: "password" # @wizard ask:password
40
40
 
41
41
  SSH_PORT: "__SSH_PORT__" # @wizard ask:2022
42
- SSH_COMMAND_TIMEOUT: "600s" # SSH ๋ช…๋ น ์‹คํ–‰ ํƒ€์ž„์•„์›ƒ
43
- SSH_CONNECTION_TIMEOUT: "60s" # SSH ์—ฐ๊ฒฐ ํƒ€์ž„์•„์›ƒ
42
+ SSH_COMMAND_TIMEOUT: "600s" # SSH command execution timeout
43
+ SSH_CONNECTION_TIMEOUT: "60s" # SSH connection timeout
44
44
 
45
45
  jobs:
46
46
  build:
47
- name: React/Next.js ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋นŒ๋“œ
47
+ name: Build React/Next.js application
48
48
  runs-on: ubuntu-latest
49
- # ๋ชจ๋…ธ๋ ˆํฌ(--paths)๋ฉด ๊ทธ ํ•˜์œ„ ํด๋”์—์„œ ๋นŒ๋“œํ•œ๋‹ค
49
+ # In a monorepo (--paths), build inside that subfolder
50
50
  defaults:
51
51
  run:
52
52
  working-directory: ${{ env.PROJECT_PATH }}
53
53
 
54
54
  steps:
55
- - name: ์ฝ”๋“œ ์ฒดํฌ์•„์›ƒ
55
+ - name: Checkout repository
56
56
  uses: actions/checkout@v7
57
57
 
58
- # ํ•„์ˆ˜ SecretยทDockerfile์ด ์—†์œผ๋ฉด docker ๋กœ๊ทธ์ธ ๊ฐ™์€ ์„œ๋“œํŒŒํ‹ฐ ์˜ค๋ฅ˜ ๋Œ€์‹  ๋น ์ง„ ํ•ญ๋ชฉ์„ ์•Œ๋ ค ์ฃผ๊ณ  ๋ฉˆ์ถ˜๋‹ค
59
- - name: ๋ฐฐํฌ ์‚ฌ์ „ ์ ๊ฒ€ (SecretยทDockerfile)
58
+ # If a required Secret or the Dockerfile is missing, report the missing item and stop
59
+ # instead of failing later with a third-party error such as docker login
60
+ - name: Deploy pre-check (Secrets and Dockerfile)
60
61
  working-directory: ${{ env.PROJECT_PATH }}
61
62
  env:
62
63
  DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
@@ -67,11 +68,12 @@ jobs:
67
68
  SSH_KEY: ${{ secrets.SSH_KEY }}
68
69
  DOCKERFILE: Dockerfile
69
70
  run: |
71
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
70
72
  MISSING=""
71
73
  for NAME in DOCKERHUB_USERNAME DOCKERHUB_TOKEN SERVER_HOST SERVER_USER; do
72
74
  [ -n "${!NAME}" ] || MISSING="$MISSING $NAME"
73
75
  done
74
- # SSH_AUTH_METHOD=key๋ฉด SSH_KEY, ์•„๋‹ˆ๋ฉด SERVER_PASSWORD๊ฐ€ ํ•„์š”ํ•˜๋‹ค
76
+ # SSH_AUTH_METHOD=key needs SSH_KEY, otherwise SERVER_PASSWORD is required
75
77
  if [ "${SSH_AUTH_METHOD:-password}" = "key" ]; then
76
78
  [ -n "$SSH_KEY" ] || MISSING="$MISSING SSH_KEY"
77
79
  else
@@ -79,33 +81,34 @@ jobs:
79
81
  fi
80
82
  FAILED=false
81
83
  if [ -n "$MISSING" ]; then
82
- echo "::error title=ํ•„์ˆ˜ Secret ๋ˆ„๋ฝ::๋“ฑ๋ก๋˜์ง€ ์•Š์€ GitHub Secret:$MISSING โ€” Settings โ†’ Secrets and variables โ†’ Actions์—์„œ ๋“ฑ๋กํ•˜์„ธ์š”"
84
+ echo "::error title=$(m cicd.precheck_secret_title)::$(m cicd.precheck_secret_body missing="$MISSING")"
83
85
  FAILED=true
84
86
  fi
85
87
  if [ ! -f "$DOCKERFILE" ]; then
86
- echo "::error title=Dockerfile ์—†์Œ::${PROJECT_PATH}/${DOCKERFILE#./} ํŒŒ์ผ์ด ์—†์Šต๋‹ˆ๋‹ค. ์ด ์›Œํฌํ”Œ๋กœ์šฐ๋Š” Docker ์ด๋ฏธ์ง€๋กœ ๋ฐฐํฌํ•˜๋ฏ€๋กœ Dockerfile์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค (์„œ๋ฒ„ ๋ฐฐํฌ๋ฅผ ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ด ์›Œํฌํ”Œ๋กœ์šฐ ํŒŒ์ผ์„ ์‚ญ์ œํ•˜์„ธ์š”)"
88
+ echo "::error title=$(m cicd.precheck_dockerfile_title)::$(m cicd.precheck_dockerfile_body path="${PROJECT_PATH}/${DOCKERFILE#./}")"
87
89
  FAILED=true
88
90
  fi
89
91
  if [ "$FAILED" = "true" ]; then
90
92
  exit 1
91
93
  fi
92
- echo "โœ… ์‚ฌ์ „ ์ ๊ฒ€ ํ†ต๊ณผ: ํ•„์ˆ˜ Secret๊ณผ Dockerfile์ด ๋ชจ๋‘ ์žˆ์Šต๋‹ˆ๋‹ค"
94
+ m cicd.precheck_ok
93
95
 
94
- - name: Node.js ์„ค์ •
96
+ - name: Set up Node.js
95
97
  uses: actions/setup-node@v7
96
98
  with:
97
99
  node-version: ${{ env.NODE_VERSION }}
98
100
  cache: 'npm'
99
101
  cache-dependency-path: ${{ env.PROJECT_PATH }}/package-lock.json
100
102
 
101
- - name: ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํŒŒ์ผ ์ƒ์„ฑ (${{ env.ENV_FILE_NAME }})
103
+ - name: Create environment file (${{ env.ENV_FILE_NAME }})
102
104
  run: |
105
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
103
106
  cat << 'EOF' > ./${{ env.ENV_FILE_NAME }}
104
107
  ${{ secrets.ENV_FILE || secrets.ENV }}
105
108
  EOF
106
- echo "โœ… ${{ env.ENV_FILE_NAME }} ํŒŒ์ผ ์ƒ์„ฑ ์™„๋ฃŒ"
109
+ m cicd.env_file_created file="${{ env.ENV_FILE_NAME }}"
107
110
 
108
- - name: npm ์˜์กด์„ฑ ์บ์‹ฑ
111
+ - name: Cache npm dependencies
109
112
  uses: actions/cache@v6
110
113
  with:
111
114
  path: ~/.npm
@@ -113,7 +116,7 @@ jobs:
113
116
  restore-keys: |
114
117
  ${{ runner.os }}-npm-
115
118
 
116
- - name: node_modules ์บ์‹ฑ
119
+ - name: Cache node_modules
117
120
  id: node-modules-cache
118
121
  uses: actions/cache@v6
119
122
  with:
@@ -122,11 +125,11 @@ jobs:
122
125
  restore-keys: |
123
126
  ${{ runner.os }}-node-modules-
124
127
 
125
- - name: ์˜์กด์„ฑ ์„ค์น˜
128
+ - name: Install dependencies
126
129
  if: steps.node-modules-cache.outputs.cache-hit != 'true'
127
130
  run: npm ci
128
131
 
129
- - name: Next.js ๋นŒ๋“œ ์บ์‹ฑ
132
+ - name: Cache Next.js build
130
133
  uses: actions/cache@v6
131
134
  with:
132
135
  path: ${{ env.PROJECT_PATH }}/.next/cache
@@ -138,10 +141,10 @@ jobs:
138
141
  - name: Build with npm
139
142
  run: npm run build
140
143
 
141
- - name: Docker ๋นŒ๋“œํ™˜๊ฒฝ ์„ค์ •
144
+ - name: Set up Docker Buildx
142
145
  uses: docker/setup-buildx-action@v3
143
146
 
144
- - name: DockerHub ๋กœ๊ทธ์ธ
147
+ - name: Log in to DockerHub
145
148
  uses: docker/login-action@v3
146
149
  with:
147
150
  username: ${{ secrets.DOCKERHUB_USERNAME }}
@@ -155,7 +158,7 @@ jobs:
155
158
  restore-keys: |
156
159
  ${{ runner.os }}-buildx-
157
160
 
158
- - name: Docker ์ด๋ฏธ์ง€ ๋นŒ๋“œ ๋ฐ ํ‘ธ์‹œ
161
+ - name: Build and push Docker image
159
162
  uses: docker/build-push-action@v5
160
163
  with:
161
164
  context: ${{ env.PROJECT_PATH }}
@@ -171,11 +174,25 @@ jobs:
171
174
  mv /tmp/.buildx-cache-new /tmp/.buildx-cache
172
175
 
173
176
  deploy:
174
- name: ์›๊ฒฉ ์„œ๋ฒ„ ๋ฐฐํฌ
177
+ name: Deploy to remote server
175
178
  needs: build
176
179
  runs-on: ubuntu-latest
177
180
 
178
181
  steps:
182
+ # The deploy script runs on the remote server, so the messages are resolved here
183
+ # and handed to it through env vars (PAW_M_*)
184
+ - name: Checkout message catalog
185
+ uses: actions/checkout@v7
186
+ with:
187
+ sparse-checkout: |
188
+ .github/scripts/messages.py
189
+ version.yml
190
+ sparse-checkout-cone-mode: false
191
+
192
+ - name: Load messages
193
+ run: |
194
+ 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"
195
+
179
196
  - name: Deploy
180
197
  uses: appleboy/ssh-action@v1.0.3
181
198
  env:
@@ -192,76 +209,79 @@ jobs:
192
209
  script: |
193
210
  set -e
194
211
 
195
- # ๋ฐฐํฌ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ •
196
- echo "๐Ÿ”ง ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ •.."
212
+ # Fill the {name} placeholders of a message template (usage: m "template" name=value ...)
213
+ m() { local s="$1" kv; shift; for kv in "$@"; do s="${s//\{${kv%%=*}\}/${kv#*=}}"; done; printf '%s\n' "$s"; }
214
+
215
+ # Set deploy environment variables
216
+ m "${{ env.PAW_M_cicd_setup_env }}"
197
217
  export PATH=$PATH:/usr/local/bin
198
218
  export PW=${{ secrets.SERVER_PASSWORD }}
199
219
 
200
- # SSH ์ธ์ฆ ๋ฐฉ์‹์— ๋”ฐ๋ฅธ sudo ์ถ”์ƒํ™”
201
- # password ๋ชจ๋“œ: echo $PW | sudo -S (Synology ๋“ฑ sudo ๋น„๋ฐ€๋ฒˆํ˜ธ ํ•„์š” ์„œ๋ฒ„)
202
- # key ๋ชจ๋“œ: sudo ์ง์ ‘ (AWS EC2 ๋“ฑ passwordless sudo ์„œ๋ฒ„)
220
+ # sudo abstraction per SSH auth method
221
+ # password mode: echo $PW | sudo -S (servers that need a sudo password, e.g. Synology)
222
+ # key mode: plain sudo (passwordless-sudo servers, e.g. AWS EC2)
203
223
  SSH_AUTH_METHOD="${SSH_AUTH_METHOD:-password}"
204
224
  if [ "${SSH_AUTH_METHOD}" = "key" ]; then
205
225
  SUDO() { sudo "$@"; }
206
226
  else
207
227
  SUDO() { echo "$PW" | sudo -S "$@"; }
208
228
  fi
209
- echo "๐Ÿ” SSH ์ธ์ฆ ๋ฐฉ์‹: ${SSH_AUTH_METHOD}"
229
+ m "${{ env.PAW_M_cicd_ssh_auth }}" method="${SSH_AUTH_METHOD}"
210
230
 
211
- # GitHub์—์„œ ์ „๋‹ฌ๋ฐ›์€ ๋ธŒ๋žœ์น˜๋ช…
231
+ # Branch name passed from GitHub
212
232
  BRANCH=${{ github.ref_name }}
213
233
 
214
- # ํ”„๋กœ์ ํŠธ ์„ค์ •
234
+ # Project settings
215
235
  PROJECT_NAME="${{ env.PROJECT_NAME }}"
216
236
 
217
- # ๋ธŒ๋žœ์น˜๋ณ„ ํฌํŠธ ๋ฐ ์ปจํ…Œ์ด๋„ˆ๋ช… ์„ค์ •
218
- # ๊ธฐ๋ณธ๊ฐ’ ์„ค์ •
237
+ # Per-branch port and container name
238
+ # Defaults
219
239
  PORT=3000
220
240
  CONTAINER_NAME="${PROJECT_NAME}-front"
221
241
 
222
- # ๋ธŒ๋žœ์น˜์— ๋”ฐ๋ฅธ ํ™˜๊ฒฝ๋ณ„ ์„ค์ •
242
+ # Per-branch environment settings
223
243
  if [ "$BRANCH" == "{{MAIN_BRANCH}}" ]; then
224
- # ๐Ÿš€ ๋ฐฐํฌ ํ™˜๊ฒฝ ({{MAIN_BRANCH}} ๋ธŒ๋žœ์น˜)
225
- # GitHub Secrets์˜ PROJECT_DEPLOY_PORT ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์‚ฌ์šฉ
226
- # ์„ค์ •๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด ๊ธฐ๋ณธ๊ฐ’ 3000 ์‚ฌ์šฉ
244
+ # ๐Ÿš€ Deploy environment ({{MAIN_BRANCH}} branch)
245
+ # Uses the PROJECT_DEPLOY_PORT value from GitHub Secrets
246
+ # Falls back to 3000 when it is not set
227
247
  PORT=${{ secrets.PROJECT_DEPLOY_PORT || '3000' }}
228
248
  CONTAINER_NAME="${PROJECT_NAME}-front-deploy"
229
- echo "๐Ÿš€ ๋ฐฐํฌ ํ™˜๊ฒฝ์œผ๋กœ ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค (๋ธŒ๋žœ์น˜: $BRANCH)"
249
+ m "${{ env.PAW_M_cicd_deploy_start }}" branch="$BRANCH"
230
250
 
231
251
  else
232
- # ๊ธฐํƒ€ ๋ธŒ๋žœ์น˜ (์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ธŒ๋žœ์น˜)
233
- echo "โš ๏ธ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๋ธŒ๋žœ์น˜์ž…๋‹ˆ๋‹ค: $BRANCH"
234
- echo "์ด ์›Œํฌํ”Œ๋กœ์šฐ๋Š” {{MAIN_BRANCH}} ๋ธŒ๋žœ์น˜๋งŒ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค."
235
- echo "on.push.branches์—์„œ ์ง€์›ํ•  ๋ธŒ๋žœ์น˜๋ฅผ ์„ค์ •ํ•˜์„ธ์š”."
252
+ # Any other branch (unexpected)
253
+ m "${{ env.PAW_M_cicd_branch_unsupported }}" branch="$BRANCH"
254
+ m "${{ env.PAW_M_cicd_branch_only }}" branch="{{MAIN_BRANCH}}"
255
+ m "${{ env.PAW_M_cicd_branch_hint }}"
236
256
  exit 1
237
257
  fi
238
258
 
239
- # ์„ค์ • ์ •๋ณด ์ถœ๋ ฅ
240
- echo "๐Ÿ“‹ ๋ฐฐํฌ ์„ค์ • ์ •๋ณด:"
241
- echo " - ๋ธŒ๋žœ์น˜: $BRANCH"
242
- echo " - ํ”„๋กœ์ ํŠธ: $PROJECT_NAME"
243
- echo " - ์ปจํ…Œ์ด๋„ˆ ์ด๋ฆ„: $CONTAINER_NAME"
244
- echo " - ํฌํŠธ: $PORT"
245
- echo " - Docker ์ด๋ฏธ์ง€: ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}-${{ env.DOCKER_IMAGE_PREFIX }}:${BRANCH}"
259
+ # Print the settings
260
+ m "${{ env.PAW_M_cicd_config_title }}"
261
+ m "${{ env.PAW_M_cicd_config_branch }}" branch="$BRANCH"
262
+ m "${{ env.PAW_M_cicd_config_project }}" project="$PROJECT_NAME"
263
+ m "${{ env.PAW_M_cicd_config_container }}" container="$CONTAINER_NAME"
264
+ m "${{ env.PAW_M_cicd_config_port }}" port="$PORT"
265
+ m "${{ env.PAW_M_cicd_config_image }}" image="${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}-${{ env.DOCKER_IMAGE_PREFIX }}:${BRANCH}"
246
266
 
247
- # Docker ์ด๋ฏธ์ง€ ํ’€ (Pull)
248
- echo "โฌ‡๏ธ Docker ์ด๋ฏธ์ง€ ํ’€: ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}-${{ env.DOCKER_IMAGE_PREFIX }}:${BRANCH}"
267
+ # Pull the Docker image
268
+ m "${{ env.PAW_M_cicd_pull_image }}" image="${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}-${{ env.DOCKER_IMAGE_PREFIX }}:${BRANCH}"
249
269
  SUDO docker pull ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}-${{ env.DOCKER_IMAGE_PREFIX }}:${BRANCH}
250
270
 
251
- # ๊ธฐ์กด ์ปจํ…Œ์ด๋„ˆ ์ •๋ฆฌ
252
- echo "๐Ÿงน ์ปจํ…Œ์ด๋„ˆ $CONTAINER_NAME ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ ์ค‘..."
271
+ # Clean up the existing container
272
+ m "${{ env.PAW_M_cicd_container_check }}" container="$CONTAINER_NAME"
253
273
 
254
- # ๋™์ผํ•œ ์ด๋ฆ„์˜ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ
274
+ # Check whether a container with the same name exists
255
275
  if SUDO docker ps -a --format '{{.Names}}' | grep -Eq "^${CONTAINER_NAME}\$"; then
256
- echo "โš ๏ธ ์ปจํ…Œ์ด๋„ˆ $CONTAINER_NAME ์ด(๊ฐ€) ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์ค‘์ง€ ๋ฐ ์‚ญ์ œ ์ค‘..."
276
+ m "${{ env.PAW_M_cicd_container_exists }}" container="$CONTAINER_NAME"
257
277
  SUDO docker rm -f $CONTAINER_NAME
258
- echo "โœ… ์ปจํ…Œ์ด๋„ˆ $CONTAINER_NAME ์ด(๊ฐ€) ์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."
278
+ m "${{ env.PAW_M_cicd_container_removed }}" container="$CONTAINER_NAME"
259
279
  else
260
- echo "โ„น๏ธ ์กด์žฌํ•˜๋Š” ์ปจํ…Œ์ด๋„ˆ $CONTAINER_NAME ์ด(๊ฐ€) ์—†์Šต๋‹ˆ๋‹ค."
280
+ m "${{ env.PAW_M_cicd_container_none }}" container="$CONTAINER_NAME"
261
281
  fi
262
282
 
263
- # ์ƒˆ ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰
264
- echo "๐Ÿš€ ์ƒˆ๋กœ์šด ์ปจํ…Œ์ด๋„ˆ $CONTAINER_NAME ์‹คํ–‰ ์ค‘..."
283
+ # Start the new container
284
+ m "${{ env.PAW_M_cicd_container_run }}" container="$CONTAINER_NAME"
265
285
 
266
286
  SUDO docker run -d \
267
287
  -p ${PORT}:3000 \
@@ -270,27 +290,27 @@ jobs:
270
290
  -v /etc/localtime:/etc/localtime:ro \
271
291
  ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}-${{ env.DOCKER_IMAGE_PREFIX }}:${BRANCH}
272
292
 
273
- # ๋ฐฐํฌ ์™„๋ฃŒ ํ™•์ธ
274
- echo "โœ… ๋ฐฐํฌ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!"
293
+ # Confirm the deployment
294
+ m "${{ env.PAW_M_cicd_deploy_done }}"
275
295
  echo ""
276
- echo "๐Ÿ“‹ ๋ฐฐํฌ ๊ฒฐ๊ณผ ์š”์•ฝ:"
277
- echo " ๐ŸŽฏ ํ”„๋กœ์ ํŠธ: $PROJECT_NAME"
278
- echo " ๐ŸŒฟ ๋ธŒ๋žœ์น˜: $BRANCH"
279
- echo " ๐Ÿณ ์ปจํ…Œ์ด๋„ˆ: $CONTAINER_NAME"
280
- echo " ๐ŸŒ ํฌํŠธ: $PORT"
281
- echo " โฐ ๋ฐฐํฌ ์‹œ๊ฐ„: $(date '+%Y-%m-%d %H:%M:%S')"
296
+ m "${{ env.PAW_M_cicd_summary_title }}"
297
+ m "${{ env.PAW_M_cicd_summary_project }}" project="$PROJECT_NAME"
298
+ m "${{ env.PAW_M_cicd_summary_branch }}" branch="$BRANCH"
299
+ m "${{ env.PAW_M_cicd_summary_container }}" container="$CONTAINER_NAME"
300
+ m "${{ env.PAW_M_cicd_summary_port }}" port="$PORT"
301
+ m "${{ env.PAW_M_cicd_summary_time }}" time="$(date '+%Y-%m-%d %H:%M:%S')"
282
302
  echo ""
283
- echo "๐Ÿ”— ์ ‘์† URL: http://${{ secrets.SERVER_HOST }}:${PORT}"
303
+ m "${{ env.PAW_M_cicd_summary_url }}" url="http://${{ secrets.SERVER_HOST }}:${PORT}"
284
304
 
285
- # ์‚ฌ์šฉ ์˜ˆ์‹œ - {{MAIN_BRANCH}} ๋ธŒ๋žœ์น˜ ์‚ฌ์šฉ
305
+ # Usage example - using the {{MAIN_BRANCH}} branch
286
306
  #
287
- # ํ˜„์žฌ ์„ค์ •: {{MAIN_BRANCH}} ๋ธŒ๋žœ์น˜์— pushํ•  ๋•Œ ์ž๋™ ๋ฐฐํฌ
307
+ # Current setup: deploys automatically on push to the {{MAIN_BRANCH}} branch
288
308
  #
289
- # ๋ธŒ๋žœ์น˜๋ณ„ ํฌํŠธ:
290
- # - {{MAIN_BRANCH}}: 3000 (PROJECT_DEPLOY_PORT secret์œผ๋กœ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ)
309
+ # Port per branch:
310
+ # - {{MAIN_BRANCH}}: 3000 (can be changed with the PROJECT_DEPLOY_PORT secret)
291
311
  #
292
- # ํ•„์š”ํ•œ Secrets:
293
- # - REACT_ENV_FILE, DOCKERHUB_*, SERVER_* (ํ•„์ˆ˜)
294
- # - PROJECT_DEPLOY_PORT (์„ ํƒ, ๊ธฐ๋ณธ๊ฐ’: 3000)
312
+ # Required Secrets:
313
+ # - REACT_ENV_FILE, DOCKERHUB_*, SERVER_* (required)
314
+ # - PROJECT_DEPLOY_PORT (optional, default: 3000)
295
315
  #
296
316