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,29 +1,29 @@
1
1
  # project-auto-wizard:managed-workflow
2
- # Flutter Android Play Store 내부 테스트 배포 워크플로우
2
+ # Flutter Android Play Store internal testing deploy workflow
3
3
  #
4
- # {{MAIN_BRANCH}} 브랜치 푸시 시 Android AAB를 빌드하고
5
- # Play Store 내부 테스트에 자동 배포합니다.
4
+ # On a push to the {{MAIN_BRANCH}} branch, builds the Android AAB and
5
+ # deploys it to Play Store internal testing.
6
6
  #
7
- # 필수 GitHub Secrets
8
- # ENV_FILE 또는 ENV: .env 파일 내용 (둘 중 하나, ENV_FILE 우선)
9
- # RELEASE_KEYSTORE_BASE64: 서명용 keystore (base64)
10
- # RELEASE_KEYSTORE_PASSWORD: keystore 비밀번호
7
+ # Required GitHub Secrets
8
+ # ENV_FILE or ENV: contents of the .env file (either one; ENV_FILE takes precedence)
9
+ # RELEASE_KEYSTORE_BASE64: signing keystore (base64)
10
+ # RELEASE_KEYSTORE_PASSWORD: keystore password
11
11
  # RELEASE_KEY_ALIAS: key alias
12
- # RELEASE_KEY_PASSWORD: key 비밀번호
13
- # GOOGLE_SERVICES_JSON (선택): Firebase google-services.json
14
- # GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_BASE64: Play Console 서비스 계정 (base64)
15
- # ANDROID_PACKAGE_NAME: 앱 패키지명 (Secret 우선, 없으면 Variable) — fastlane에 PACKAGE_NAME으로 전달
12
+ # RELEASE_KEY_PASSWORD: key password
13
+ # GOOGLE_SERVICES_JSON (optional): Firebase google-services.json
14
+ # GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_BASE64: Play Console service account (base64)
15
+ # ANDROID_PACKAGE_NAME: app package name (Secret first, otherwise Variable) - passed to fastlane as PACKAGE_NAME
16
16
 
17
17
  name: PROJECT-FLUTTER-ANDROID-PLAYSTORE-INTERNAL-CICD
18
18
 
19
19
  on:
20
20
  push:
21
21
  branches: ["{{MAIN_BRANCH}}"]
22
- # @wizard paths-anchor (모노레포일 때 integrator가 paths 필터를 여기 주입)
22
+ # @wizard paths-anchor (in a monorepo the installer injects a paths filter here)
23
23
  workflow_dispatch:
24
24
  inputs:
25
25
  deploy_mode:
26
- description: "배포 모드 (store_only=internal까지 / store_prepare=production draft / store_submit=심사 자동등록)"
26
+ description: "Deploy mode (store_only = up to internal / store_prepare = production draft / store_submit = auto-submit for review)"
27
27
  required: false
28
28
  default: "store_only" # @wizard auto:android-deploy-mode
29
29
  type: choice
@@ -32,32 +32,32 @@ on:
32
32
  - store_prepare
33
33
  - store_submit
34
34
 
35
- # 프로젝트별 설정 (아래 값들을 수정하세요)
35
+ # Project settings (edit the values below)
36
36
  env:
37
- # 프로젝트 이름
37
+ # Project name
38
38
  APP_ARTIFACT_NAME: "__APP_ARTIFACT_NAME__" # @wizard ask:@repo
39
- # Flutter/Java 버전
40
- # Flutter SDK 버전 — 비워 두면 stable 채널 최신을 쓴다(최신 flutter create 프로젝트의 SDK 제약과 맞음).
41
- # 특정 버전에 고정하려면 "3.38.9"처럼 적는다. pubspec.yaml의 environment.sdk 범위를 만족해야 한다.
39
+ # Flutter/Java versions
40
+ # Flutter SDK version - leave empty to use the latest stable channel (matches the SDK constraint of a fresh flutter create project).
41
+ # To pin a version, write it like "3.38.9". It must satisfy the environment.sdk range in pubspec.yaml.
42
42
  FLUTTER_VERSION: ""
43
43
  JAVA_VERSION: "__JAVA_VERSION__" # @wizard ask:17
44
44
  PROJECT_TYPE: "flutter"
45
- # Flutter 루트 경로(레포 루트 기준). 단일레포면 ".", 모노레포면 "app" 등.
46
- # 통합 시점에 integrator의 flutter-root resolver가 project_paths.flutter 값으로 1회 치환.
45
+ # Flutter root path (relative to the repo root): "." for a single repo, "app" etc. for a monorepo.
46
+ # At integration time the integrator's flutter-root resolver substitutes the project_paths.flutter value once.
47
47
  FLUTTER_PROJECT_DIR: "." # @wizard auto:flutter-root
48
- # 환경변수 전달 방식 (dart-define | dotenv) — 설치 시 선택값으로 자동 설정
48
+ # How env vars are passed (dart-define | dotenv) - set automatically from the install-time choice
49
49
  ENV_MODE: "dart-define" # @wizard auto:flutter-env-mode
50
- # 배포 모드 (store_only | store_prepare | store_submit) — 마지막 폴백값은 설치 시 선택값으로 설정, 변수·수동 입력이 항상 우선
50
+ # Deploy mode (store_only | store_prepare | store_submit) - the last fallback is set from the install-time choice; the variable and manual input always take precedence
51
51
  DEPLOY_MODE: ${{ github.event.inputs.deploy_mode || vars.ANDROID_DEPLOY_MODE || 'store_only' }} # @wizard fallback:android-deploy-mode
52
52
 
53
53
  jobs:
54
54
  prepare-build:
55
- name: 환경 설정 및 준비
55
+ name: Environment setup and preparation
56
56
  runs-on: ubuntu-latest
57
57
  defaults:
58
58
  run:
59
59
  working-directory: ${{ env.FLUTTER_PROJECT_DIR }}
60
- # CHANGELOG 워크플로우가 성공한 경우에만 실행
60
+ # Run only when the CHANGELOG workflow succeeded
61
61
  if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name != 'workflow_run' }}
62
62
 
63
63
  outputs:
@@ -72,9 +72,9 @@ jobs:
72
72
  ref: "{{MAIN_BRANCH}}"
73
73
  fetch-depth: 0
74
74
 
75
- # 서명·업로드 Secret이 없으면 빌드를 한참 진행한 뒤에야 실패하므로, 빠진 이름을 먼저 모두 알려 주고 멈춘다
76
- # GOOGLE_SERVICES_JSON은 선택이라 점검하지 않는다
77
- - name: 배포 사전 점검 (Secret)
75
+ # Without the signing/upload Secrets the run would only fail well into the build, so report all missing names first and stop
76
+ # GOOGLE_SERVICES_JSON is optional, so it is not checked
77
+ - name: Pre-deploy check (Secrets)
78
78
  env:
79
79
  RELEASE_KEYSTORE_BASE64: ${{ secrets.RELEASE_KEYSTORE_BASE64 }}
80
80
  RELEASE_KEYSTORE_PASSWORD: ${{ secrets.RELEASE_KEYSTORE_PASSWORD }}
@@ -83,17 +83,18 @@ jobs:
83
83
  GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_BASE64: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_BASE64 }}
84
84
  ANDROID_PACKAGE_NAME: ${{ secrets.ANDROID_PACKAGE_NAME || vars.ANDROID_PACKAGE_NAME }}
85
85
  run: |
86
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
86
87
  MISSING=""
87
88
  for NAME in RELEASE_KEYSTORE_BASE64 RELEASE_KEYSTORE_PASSWORD RELEASE_KEY_ALIAS RELEASE_KEY_PASSWORD GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_BASE64; do
88
89
  [ -n "${!NAME}" ] || MISSING="$MISSING $NAME"
89
90
  done
90
- # 패키지명은 Secret 대신 Variable로 등록해도 된다
91
- [ -n "$ANDROID_PACKAGE_NAME" ] || MISSING="$MISSING ANDROID_PACKAGE_NAME(Secret 또는 Variable)"
91
+ # The package name may be registered as a Variable instead of a Secret
92
+ [ -n "$ANDROID_PACKAGE_NAME" ] || MISSING="$MISSING ANDROID_PACKAGE_NAME(Secret or Variable)"
92
93
  if [ -n "$MISSING" ]; then
93
- echo "::error title=필수 Secret 누락::등록되지 않은 GitHub Secret:$MISSING — Settings → Secrets and variables → Actions에서 등록하세요"
94
+ echo "::error title=$(m flutter_a.precheck_missing_title)::$(m flutter_a.precheck_missing_body missing="$MISSING")"
94
95
  exit 1
95
96
  fi
96
- echo "✅ 사전 점검 통과: 필수 Secret이 모두 있습니다"
97
+ m flutter_a.precheck_passed
97
98
 
98
99
  - name: Pull latest changes
99
100
  run: git pull origin {{MAIN_BRANCH}}
@@ -133,63 +134,65 @@ jobs:
133
134
  dart run build_runner build --delete-conflicting-outputs
134
135
  fi
135
136
 
136
- - name: 현재 버전 정보 가져오기
137
+ - name: Get current version
137
138
  id: current_version
138
- working-directory: ${{ github.workspace }} # version_manager.py가 레포 루트 version.yml을 읽어야 함
139
+ working-directory: ${{ github.workspace }} # version_manager.py must read the repo-root version.yml
139
140
  run: |
140
- # VERSION 가져오기 (x.y.z 형식)
141
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
142
+ # Get VERSION (x.y.z format)
141
143
  VERSION=$(python3 .github/scripts/version_manager.py get | tail -n 1)
142
144
 
143
- # VERSION_CODE 가져오기 (version.yml에서 관리되는 단순 증가 번호)
145
+ # Get VERSION_CODE (a simple incrementing number managed in version.yml)
144
146
  VERSION_CODE=$(python3 .github/scripts/version_manager.py get-code | tail -n 1)
145
147
 
146
- # 결과 출력
148
+ # Print the result
147
149
  echo "✅ VERSION: $VERSION"
148
150
  echo "✅ VERSION_CODE: $VERSION_CODE"
149
- echo "🔧 프로젝트 타입: ${{ env.PROJECT_TYPE }}"
151
+ m flutter_a.project_type project_type="${{ env.PROJECT_TYPE }}"
150
152
 
151
- # GitHub outputs 설정
153
+ # Set GitHub outputs
152
154
  echo "version=$VERSION" >> $GITHUB_OUTPUT
153
155
  echo "version_code=$VERSION_CODE" >> $GITHUB_OUTPUT
154
156
  echo "project_type=${{ env.PROJECT_TYPE }}" >> $GITHUB_OUTPUT
155
157
 
156
- # 환경변수로도 설정 (스크립트에서 사용)
158
+ # Also set as environment variables (used by scripts)
157
159
  echo "VERSION=$VERSION" >> $GITHUB_ENV
158
160
  echo "VERSION_CODE=$VERSION_CODE" >> $GITHUB_ENV
159
161
  echo "TODAY=$(date '+%Y-%m-%d')" >> $GITHUB_ENV
160
162
  echo "TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV
161
163
  echo "PROJECT_TYPE=${{ env.PROJECT_TYPE }}" >> $GITHUB_ENV
162
164
 
163
- - name: 릴리즈 노트 생성
165
+ - name: Generate release notes
164
166
  id: release_notes
165
- working-directory: ${{ github.workspace }} # CHANGELOG.json·changelog_manager.py·final_release_notes.txt(upload 짝)는 레포 루트 기준
167
+ working-directory: ${{ github.workspace }} # CHANGELOG.json, changelog_manager.py and final_release_notes.txt (paired with the upload) are relative to the repo root
166
168
  run: |
169
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
167
170
  VERSION="${{ steps.current_version.outputs.version }}"
168
171
 
169
172
  if [ -f "CHANGELOG.json" ]; then
170
- echo "📄 CHANGELOG.json에서 v$VERSION 릴리즈 노트 추출 중..."
171
- # CHANGELOG.md 생성
173
+ m flutter_a.extracting_v_release_notes_changelog version="$VERSION"
174
+ # Generate CHANGELOG.md
172
175
  python3 ./.github/scripts/changelog_manager.py generate-md
173
176
 
174
- # changelog_manager.py export로 릴리즈 노트 추출
177
+ # Extract the release notes with changelog_manager.py export
175
178
  python3 ./.github/scripts/changelog_manager.py export --version $VERSION --output final_release_notes.txt
176
179
 
177
180
  if [ -s final_release_notes.txt ]; then
178
- echo "✅ 릴리즈 노트 추출 성공!"
179
- echo "📋 추출된 릴리즈 노트:"
181
+ m flutter_a.release_notes_extracted
182
+ m flutter_a.extracted_release_notes
180
183
  echo "----------------------------------------"
181
184
  cat final_release_notes.txt
182
185
  echo "----------------------------------------"
183
186
  echo "RELEASE_NOTES_FOUND=true" >> $GITHUB_ENV
184
187
  else
185
- echo "❌ 릴리즈 노트 추출 실패"
188
+ m flutter_a.failed_extract_release_notes
186
189
  echo "RELEASE_NOTES_FOUND=false" >> $GITHUB_ENV
187
- echo "v$VERSION 업데이트" > final_release_notes.txt
190
+ m flutter_a.default_release_note version="$VERSION" > final_release_notes.txt
188
191
  fi
189
192
  else
190
- echo "⚠️ CHANGELOG.json 파일이 없습니다. 기본 릴리즈 노트를 사용합니다."
193
+ m flutter_a.changelog_json_not_found_using
191
194
  echo "RELEASE_NOTES_FOUND=false" >> $GITHUB_ENV
192
- echo "v$VERSION 업데이트" > final_release_notes.txt
195
+ m flutter_a.default_release_note version="$VERSION" > final_release_notes.txt
193
196
  fi
194
197
 
195
198
  - name: Upload release notes
@@ -200,8 +203,8 @@ jobs:
200
203
  retention-days: 1
201
204
  if-no-files-found: error
202
205
 
203
- # 프로젝트 파일들을 아티팩트로 업로드
204
- # .env는 보안상 아티팩트에 포함하지 않고, 각 job에서 secrets로 재생성
206
+ # Upload the project files as an artifact
207
+ # .env is not included in the artifact for security; each job recreates it from secrets
205
208
  - name: Upload project files
206
209
  uses: actions/upload-artifact@v7
207
210
  with:
@@ -214,7 +217,7 @@ jobs:
214
217
  if-no-files-found: error
215
218
 
216
219
  build-android:
217
- name: Android AAB 빌드
220
+ name: Build Android AAB
218
221
  runs-on: ubuntu-latest
219
222
  needs: prepare-build
220
223
  defaults:
@@ -237,7 +240,7 @@ jobs:
237
240
  name: project-files
238
241
  path: ${{ env.FLUTTER_PROJECT_DIR }}
239
242
 
240
- # 환경변수 준비 (보안을 위해 아티팩트가 아닌 시크릿에서 생성) — ENV_MODE=dotenv면 .env 파일, dart-define이면 임시 파일
243
+ # Prepare env vars (created from secrets rather than the artifact, for security) - a .env file when ENV_MODE=dotenv, a temp file for dart-define
241
244
  - name: Prepare env file
242
245
  env:
243
246
  ENV_CONTENT: ${{ secrets.ENV_FILE || secrets.ENV }}
@@ -259,35 +262,37 @@ jobs:
259
262
  RELEASE_KEY_ALIAS: ${{ secrets.RELEASE_KEY_ALIAS }}
260
263
  RELEASE_KEY_PASSWORD: ${{ secrets.RELEASE_KEY_PASSWORD }}
261
264
  run: |
262
- # 빈 Secret으로 빈 keystore를 만들면 어떤 키로 서명됐는지 알 수 없거나 뒤 단계에서 엉뚱한 오류로 끝난다
265
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
266
+ # An empty keystore built from an empty Secret leaves it unclear which key signed the build, or ends in a misleading error in a later step
263
267
  MISSING=""
264
268
  for name in RELEASE_KEYSTORE_BASE64 RELEASE_KEYSTORE_PASSWORD RELEASE_KEY_ALIAS RELEASE_KEY_PASSWORD; do
265
269
  [ -n "${!name}" ] || MISSING="$MISSING $name"
266
270
  done
267
271
  if [ -n "$MISSING" ]; then
268
- echo "::error::서명 Secret이 비어 있습니다:$MISSING (워크플로우 상단 주석 참고)"
272
+ echo "::error::$(m flutter_a.signing_secrets_empty missing="$MISSING")"
269
273
  exit 1
270
274
  fi
271
275
  mkdir -p android/app/keystore
272
276
  printf '%s' "$RELEASE_KEYSTORE_BASE64" | base64 -d > android/app/keystore/key.jks
273
277
  if [ ! -s android/app/keystore/key.jks ]; then
274
- echo "::error::RELEASE_KEYSTORE_BASE64를 디코딩한 keystore가 비어 있습니다"
278
+ echo "::error::$(m flutter_a.keystore_decoded_empty)"
275
279
  exit 1
276
280
  fi
277
- echo "✅ Release Keystore 생성 완료"
281
+ m flutter_a.release_keystore_created
278
282
  ls -la android/app/keystore/
279
283
 
280
284
  - name: Create key.properties
281
285
  run: |
286
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
282
287
  cat > android/key.properties << EOF
283
288
  storeFile=app/keystore/key.jks
284
289
  storePassword=${{ secrets.RELEASE_KEYSTORE_PASSWORD }}
285
290
  keyAlias=${{ secrets.RELEASE_KEY_ALIAS }}
286
291
  keyPassword=${{ secrets.RELEASE_KEY_PASSWORD }}
287
292
  EOF
288
- echo "✅ key.properties 생성 완료"
293
+ m flutter_a.key_properties_created
289
294
 
290
- # google-services.json 생성 (선택) — 비어 있으면 빈 파일을 만들지 않는다
295
+ # Create google-services.json (optional) - no empty file is written when the Secret is empty
291
296
  - name: Create google-services.json
292
297
  env:
293
298
  GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }}
@@ -339,55 +344,57 @@ jobs:
339
344
 
340
345
  - name: Configure Android build for release
341
346
  run: |
342
- # build.gradle.kts에 release 서명 설정이 없으면 추가
347
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
348
+ # Add the release signing config to build.gradle.kts if it is missing
343
349
  if ! grep -q "signingConfigs" android/app/build.gradle.kts; then
344
- echo "⚠️ build.gradle.kts에 서명 설정 추가 필요"
345
- # 서명 설정은 이미 되어있다고 가정 (수동으로 미리 설정해야 함)
350
+ m flutter_a.signing_config_must_added_build
351
+ # Assume signing is already configured (it must be set up manually beforehand)
346
352
  fi
347
- echo "✅ Android 빌드 설정 확인 완료"
353
+ m flutter_a.android_build_config_check_complete
348
354
 
349
- # pubspec.yaml은 x.y.z 형식 그대로 유지
350
- # Flutter build 명령어의 --build-name, --build-number 플래그가 pubspec.yaml을 오버라이드함
355
+ # Keep pubspec.yaml in the x.y.z format as is
356
+ # The --build-name and --build-number flags of flutter build override pubspec.yaml
351
357
 
352
358
  - name: Build Android App Bundle (AAB)
353
359
  run: |
360
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
354
361
  VERSION_NAME="${{ needs.prepare-build.outputs.version }}"
355
362
  VERSION_CODE="${{ needs.prepare-build.outputs.version_code }}"
356
363
 
357
364
  echo "=========================================="
358
- echo "🚀 AAB 빌드 시작"
365
+ m flutter_a.starting_aab_build
359
366
  echo "=========================================="
360
- echo "🎯 빌드 버전: $VERSION_NAME"
361
- echo "🎯 빌드 코드: $VERSION_CODE"
367
+ m flutter_a.build_version version_name="$VERSION_NAME"
368
+ m flutter_a.build_code version_code="$VERSION_CODE"
362
369
 
363
- # 입력 검증
370
+ # Validate inputs
364
371
  if [ -z "$VERSION_NAME" ] || [ -z "$VERSION_CODE" ]; then
365
- echo "❌ VERSION_NAME 또는 VERSION_CODE가 비어있습니다!"
372
+ m flutter_a.version_name_or_version_code
366
373
  exit 1
367
374
  fi
368
375
 
369
- # Flutter 환경 정보 출력
370
- echo "🔍 Flutter 환경 정보:"
376
+ # Print Flutter environment info
377
+ m flutter_a.flutter_environment_info
371
378
  flutter --version
372
379
  flutter doctor -v | head -20
373
380
 
374
- # 빌드 디렉토리 정리
375
- echo "🧹 이전 빌드 결과물 정리..."
381
+ # Clean the build directory
382
+ m flutter_a.cleaning_previous_build_output
376
383
  rm -rf build/app/outputs/bundle/release/
377
384
  mkdir -p build/app/outputs/bundle/release/
378
385
 
379
- # Flutter clean 및 pub get
380
- echo "🔄 Flutter clean 및 의존성 재설치..."
386
+ # Flutter clean and pub get
387
+ m flutter_a.running_flutter_clean_reinstalling_dependencies
381
388
  flutter clean
382
389
  flutter pub get
383
390
  if grep -q "build_runner" pubspec.yaml; then
384
391
  dart run build_runner build --delete-conflicting-outputs
385
392
  fi
386
393
 
387
- # local.properties에 버전 정보 추가 (Flutter 플래그가 무시되는 문제 해결)
388
- echo "🔧 local.properties에 버전 정보 설정..."
394
+ # Add version info to local.properties (works around the Flutter flags being ignored)
395
+ m flutter_a.setting_version_info_local_properties
389
396
 
390
- # 기존 local.properties가 있으면 버전 정보 제거
397
+ # Remove existing version info if local.properties exists
391
398
  if [ -f "android/local.properties" ]; then
392
399
  grep -v "flutter.versionName\|flutter.versionCode" android/local.properties > android/local.properties.tmp || true
393
400
  mv android/local.properties.tmp android/local.properties
@@ -395,24 +402,24 @@ jobs:
395
402
  touch android/local.properties
396
403
  fi
397
404
 
398
- # 버전 정보 추가
405
+ # Add version info
399
406
  echo "flutter.versionName=$VERSION_NAME" >> android/local.properties
400
407
  echo "flutter.versionCode=$VERSION_CODE" >> android/local.properties
401
408
 
402
- echo "✅ local.properties 업데이트 완료"
403
- echo "📋 버전 정보: VERSION_NAME=$VERSION_NAME, VERSION_CODE=$VERSION_CODE"
409
+ m flutter_a.local_properties_updated
410
+ m flutter_a.version_info_version_name_version version_name="$VERSION_NAME" version_code="$VERSION_CODE"
404
411
 
405
- # Gradle 성능 최적화 설정
412
+ # Gradle performance tuning
406
413
  export GRADLE_OPTS="-Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.workers.max=4"
407
414
  export JAVA_OPTS="-Xmx4g"
408
- echo "✅ Gradle 최적화 설정 완료"
415
+ m flutter_a.gradle_tuning_applied
409
416
 
410
- # Flutter build 명령어에 버전 정보 전달
411
- # --build-name과 --build-number 플래그가 pubspec.yaml의 version을 오버라이드함
412
- # pubspec.yaml은 x.y.z 형식 유지, VERSION_CODE는 version.yml에서 자동 관리
413
- echo "🔨 Flutter build 실행..."
414
- echo "📋 명령어: flutter build appbundle --release --build-name=$VERSION_NAME --build-number=$VERSION_CODE --verbose"
415
- echo "⏱️ 빌드 시작 시간: $(date '+%Y-%m-%d %H:%M:%S')"
417
+ # Pass the version info to the flutter build command
418
+ # The --build-name and --build-number flags override the version in pubspec.yaml
419
+ # pubspec.yaml stays in x.y.z format; VERSION_CODE is managed automatically in version.yml
420
+ m flutter_a.running_flutter_build
421
+ m flutter_a.command_flutter_build_appbundle_release version_name="$VERSION_NAME" version_code="$VERSION_CODE"
422
+ m flutter_a.build_start_time cmd1="$(date '+%Y-%m-%d %H:%M:%S')"
416
423
 
417
424
  flutter build appbundle \
418
425
  --release \
@@ -424,144 +431,144 @@ jobs:
424
431
  BUILD_EXIT_CODE=$?
425
432
 
426
433
  if [ $BUILD_EXIT_CODE -ne 0 ]; then
427
- echo "❌ Flutter build 실패! Exit code: $BUILD_EXIT_CODE"
428
- echo "🔍 빌드 디렉토리 상태:"
429
- find build/ -name "*.aab" -o -name "*.apk" 2>/dev/null || echo "AAB/APK 파일을 찾을 수 없습니다"
434
+ m flutter_a.flutter_build_failed_exit_code build_exit_code="$BUILD_EXIT_CODE"
435
+ m flutter_a.build_directory_state
436
+ find build/ -name "*.aab" -o -name "*.apk" 2>/dev/null || m flutter_a.aab_apk_not_found
430
437
  exit 1
431
438
  fi
432
439
 
433
- echo "✅ Flutter build 성공!"
440
+ m flutter_a.flutter_build_succeeded
434
441
 
435
- # 빌드 결과 확인
436
- echo "🔍 빌드 결과 확인:"
442
+ # Check the build result
443
+ m flutter_a.checking_build_result
437
444
  ls -lah build/app/outputs/bundle/release/
438
445
 
439
- # AAB 파일 존재 확인
446
+ # Check that the AAB file exists
440
447
  AAB_FILE="build/app/outputs/bundle/release/app-release.aab"
441
448
  if [ ! -f "$AAB_FILE" ]; then
442
- echo "❌ AAB 파일이 생성되지 않았습니다!"
443
- echo "🔍 전체 빌드 디렉토리 내용:"
444
- find build/ -type f -name "*.aab" -o -name "*.apk" 2>/dev/null || echo "AAB/APK 파일을 찾을 수 없습니다"
445
- echo "🔍 outputs 디렉토리 구조:"
446
- find build/app/outputs/ -type f 2>/dev/null || echo "outputs 디렉토리가 없습니다"
449
+ m flutter_a.aab_file_not_created
450
+ m flutter_a.full_build_directory_contents
451
+ find build/ -type f -name "*.aab" -o -name "*.apk" 2>/dev/null || m flutter_a.aab_apk_not_found
452
+ m flutter_a.outputs_directory_structure
453
+ find build/app/outputs/ -type f 2>/dev/null || m flutter_a.outputs_directory_does_not_exist
447
454
  exit 1
448
455
  fi
449
456
 
450
- echo "✅ AAB 파일 생성 확인"
451
- echo "📱 AAB 파일 크기: $(du -h "$AAB_FILE" | cut -f1)"
452
- echo "📋 AAB 파일 정보: $(ls -lah "$AAB_FILE")"
457
+ m flutter_a.aab_file_creation_confirmed
458
+ m flutter_a.aab_file_size cmd1="$(du -h "$AAB_FILE" | cut -f1)"
459
+ m flutter_a.aab_file_info cmd1="$(ls -lah "$AAB_FILE")"
453
460
 
454
- # bundletool 다운로드 및 설치
455
- echo "📦 bundletool 다운로드 중..."
461
+ # Download and install bundletool
462
+ m flutter_a.downloading_bundletool
456
463
  BUNDLETOOL_VERSION="1.15.6"
457
464
  BUNDLETOOL_URL="https://github.com/google/bundletool/releases/download/${BUNDLETOOL_VERSION}/bundletool-all-${BUNDLETOOL_VERSION}.jar"
458
465
 
459
- echo "📋 다운로드 URL: $BUNDLETOOL_URL"
466
+ m flutter_a.download_url bundletool_url="$BUNDLETOOL_URL"
460
467
  wget -q "$BUNDLETOOL_URL" -O bundletool.jar
461
468
 
462
469
  if [ ! -f "bundletool.jar" ]; then
463
- echo "❌ bundletool 다운로드 실패"
464
- echo "🔄 대체 URL로 재시도..."
470
+ m flutter_a.bundletool_download_failed
471
+ m flutter_a.retrying_fallback_url
465
472
  wget -q "https://github.com/google/bundletool/releases/latest/download/bundletool-all-1.15.6.jar" -O bundletool.jar
466
473
 
467
474
  if [ ! -f "bundletool.jar" ]; then
468
- echo "❌ bundletool 다운로드 완전 실패"
475
+ m flutter_a.bundletool_download_failed_completely
469
476
  exit 1
470
477
  fi
471
478
  fi
472
479
 
473
- echo "✅ bundletool 다운로드 완료"
474
- echo "📋 bundletool 파일 크기: $(du -h bundletool.jar | cut -f1)"
480
+ m flutter_a.bundletool_downloaded
481
+ m flutter_a.bundletool_file_size cmd1="$(du -h bundletool.jar | cut -f1)"
475
482
 
476
- # Java 환경 확인
477
- echo "🔍 Java 환경 확인:"
483
+ # Check the Java environment
484
+ m flutter_a.checking_java_environment
478
485
  java -version
479
486
 
480
- # AAB 파일 내부의 실제 버전 정보 확인
481
- # Flutter CLI 플래그로 전달한 VERSION_CODE가 제대로 적용되었는지 검증
487
+ # Check the actual version info inside the AAB file
488
+ # Verify that the VERSION_CODE passed via the Flutter CLI flags was applied correctly
482
489
  echo "=========================================="
483
- echo "🔍 AAB 파일 내부 버전 정보 검증"
490
+ m flutter_a.verifying_version_info_inside_aab
484
491
  echo "=========================================="
485
492
 
486
- # AndroidManifest.xml에서 버전 정보 추출
487
- echo "📋 AAB에서 실제 버전 정보 추출 중..."
488
- echo "📋 실행할 명령어: java -jar bundletool.jar dump manifest --bundle='$AAB_FILE'"
493
+ # Extract the version info from AndroidManifest.xml
494
+ m flutter_a.extracting_actual_version_info_aab
495
+ m flutter_a.command_run_java_jar_bundletool aab_file="$AAB_FILE"
489
496
 
490
497
  MANIFEST_OUTPUT=$(java -jar bundletool.jar dump manifest --bundle="$AAB_FILE" 2>&1)
491
498
  MANIFEST_EXIT_CODE=$?
492
499
 
493
- echo "📋 bundletool 실행 결과 (Exit code: $MANIFEST_EXIT_CODE):"
500
+ m flutter_a.bundletool_result_exit_code manifest_exit_code="$MANIFEST_EXIT_CODE"
494
501
  echo "$MANIFEST_OUTPUT"
495
502
 
496
503
  if [ $MANIFEST_EXIT_CODE -eq 0 ]; then
497
- echo "✅ Manifest 추출 성공"
504
+ m flutter_a.manifest_extracted
498
505
 
499
- # 실제 버전 코드와 버전 이름 추출
506
+ # Extract the actual version code and version name
500
507
  ACTUAL_VERSION_CODE=$(echo "$MANIFEST_OUTPUT" | grep -o 'android:versionCode="[0-9]*"' | grep -o '[0-9]*' | head -1)
501
508
  ACTUAL_VERSION_NAME=$(echo "$MANIFEST_OUTPUT" | grep -o 'android:versionName="[^"]*"' | sed 's/android:versionName="//;s/"//' | head -1)
502
509
 
503
- echo "🎯 버전 정보 비교:"
504
- echo " 예상 VERSION_CODE: '$VERSION_CODE'"
505
- echo " 실제 VERSION_CODE: '$ACTUAL_VERSION_CODE'"
506
- echo " 예상 VERSION_NAME: '$VERSION_NAME'"
507
- echo " 실제 VERSION_NAME: '$ACTUAL_VERSION_NAME'"
510
+ m flutter_a.version_info_comparison
511
+ m flutter_a.expected_version_code version_code="$VERSION_CODE"
512
+ m flutter_a.actual_version_code actual_version_code="$ACTUAL_VERSION_CODE"
513
+ m flutter_a.expected_version_name version_name="$VERSION_NAME"
514
+ m flutter_a.actual_version_name actual_version_name="$ACTUAL_VERSION_NAME"
508
515
 
509
- # VERSION_CODE 검증 - version.yml에서 관리되는 단순 증가 번호
516
+ # Verify VERSION_CODE - a simple incrementing number managed in version.yml
510
517
  if [ -z "$ACTUAL_VERSION_CODE" ]; then
511
- echo "❌ 치명적 오류: AAB에서 VERSION_CODE를 추출할 수 없습니다!"
512
- echo "🔍 전체 Manifest 내용:"
518
+ m flutter_a.fatal_error_version_code_could
519
+ m flutter_a.full_manifest_contents
513
520
  echo "$MANIFEST_OUTPUT"
514
521
  exit 1
515
522
  elif [ "$ACTUAL_VERSION_CODE" != "$VERSION_CODE" ]; then
516
- echo "❌ 치명적 오류: AAB의 VERSION_CODE가 예상과 다릅니다!"
517
- echo " 이는 Google Play에서 '이미 사용된 버전 코드' 오류를 발생시킵니다."
523
+ m flutter_a.fatal_error_version_code_aab
524
+ m flutter_a.google_play_would_reject_version
518
525
  echo ""
519
- echo "🔍 디버깅 정보:"
520
- echo " version.yml의 VERSION_CODE: $VERSION_CODE"
521
- echo " AAB 파일 내부의 VERSION_CODE: $ACTUAL_VERSION_CODE"
526
+ m flutter_a.debugging_info
527
+ m flutter_a.version_code_version_yml version_code="$VERSION_CODE"
528
+ m flutter_a.version_code_inside_aab_file actual_version_code="$ACTUAL_VERSION_CODE"
522
529
  echo ""
523
- echo " Flutter build 명령어에 전달된 플래그:"
530
+ m flutter_a.flags_passed_flutter_build_command
524
531
  echo " --build-name='$VERSION_NAME'"
525
532
  echo " --build-number='$VERSION_CODE'"
526
533
  echo ""
527
- echo " 전체 Manifest 내용:"
534
+ m flutter_a.full_manifest_contents_2
528
535
  echo "$MANIFEST_OUTPUT" | grep -E "versionCode|versionName|package"
529
536
  exit 1
530
537
  else
531
- echo "✅ VERSION_CODE 검증 성공: $ACTUAL_VERSION_CODE"
538
+ m flutter_a.version_code_check_passed actual_version_code="$ACTUAL_VERSION_CODE"
532
539
  fi
533
540
 
534
- # 버전 이름도 확인 (경고만)
541
+ # Check the version name too (warning only)
535
542
  if [ -z "$ACTUAL_VERSION_NAME" ]; then
536
- echo "⚠️ 경고: AAB에서 VERSION_NAME을 추출할 수 없습니다"
543
+ m flutter_a.warning_version_name_could_not
537
544
  elif [ "$ACTUAL_VERSION_NAME" != "$VERSION_NAME" ]; then
538
- echo "⚠️ 경고: VERSION_NAME이 예상과 다릅니다 (치명적이지 않음)"
539
- echo " 예상: '$VERSION_NAME', 실제: '$ACTUAL_VERSION_NAME'"
545
+ m flutter_a.warning_version_name_differs_expected
546
+ m flutter_a.expected_actual version_name="$VERSION_NAME" actual_version_name="$ACTUAL_VERSION_NAME"
540
547
  else
541
- echo "✅ VERSION_NAME 검증 성공: $ACTUAL_VERSION_NAME"
548
+ m flutter_a.version_name_check_passed actual_version_name="$ACTUAL_VERSION_NAME"
542
549
  fi
543
550
 
544
551
  else
545
- echo "❌ bundletool로 Manifest 추출 실패"
546
- echo "🔄 대체 방법으로 검증 시도..."
552
+ m flutter_a.failed_extract_manifest_bundletool
553
+ m flutter_a.trying_verify_another_way
547
554
 
548
- # unzip으로 직접 확인 시도
549
- echo "📋 unzip을 사용한 직접 추출 시도..."
555
+ # Try checking directly with unzip
556
+ m flutter_a.trying_direct_extraction_unzip
550
557
  UNZIP_OUTPUT=$(unzip -p "$AAB_FILE" base/manifest/AndroidManifest.xml 2>/dev/null | strings | grep -E "versionCode|versionName")
551
558
 
552
559
  if [ -n "$UNZIP_OUTPUT" ]; then
553
- echo "✅ unzip으로 버전 정보 추출 성공:"
560
+ m flutter_a.version_info_extracted_unzip
554
561
  echo "$UNZIP_OUTPUT"
555
562
  else
556
- echo "❌ unzip을 사용한 직접 추출도 실패"
557
- echo "⚠️ AAB 검증을 건너뛰고 계속 진행합니다."
563
+ m flutter_a.direct_extraction_unzip_failed_too
564
+ m flutter_a.skipping_aab_verification_continuing
558
565
  fi
559
566
  fi
560
567
 
561
568
  echo "=========================================="
562
- echo "✅ AAB 빌드 및 검증 완료"
563
- echo "🎯 최종 AAB: $AAB_FILE"
564
- echo "📱 파일 크기: $(du -h "$AAB_FILE" | cut -f1)"
569
+ m flutter_a.aab_build_verification_complete
570
+ m flutter_a.final_aab aab_file="$AAB_FILE"
571
+ m flutter_a.file_size cmd1="$(du -h "$AAB_FILE" | cut -f1)"
565
572
  echo "=========================================="
566
573
 
567
574
  - name: Upload AAB artifact
@@ -573,7 +580,7 @@ jobs:
573
580
  if-no-files-found: error
574
581
 
575
582
  deploy-playstore:
576
- name: Play Store 내부 테스트 배포
583
+ name: Deploy to Play Store internal testing
577
584
  runs-on: ubuntu-latest
578
585
  needs: [prepare-build, build-android]
579
586
  defaults:
@@ -591,13 +598,14 @@ jobs:
591
598
  env:
592
599
  SERVICE_ACCOUNT_BASE64: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_BASE64 }}
593
600
  run: |
601
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
594
602
  if [ -z "$SERVICE_ACCOUNT_BASE64" ]; then
595
- echo "::error::GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_BASE64 Secret이 비어 있습니다"
603
+ echo "::error::$(m flutter_a.google_play_service_account_json)"
596
604
  exit 1
597
605
  fi
598
606
  mkdir -p ~/.config/gcloud
599
607
  printf '%s' "$SERVICE_ACCOUNT_BASE64" | base64 --decode > ~/.config/gcloud/service-account.json
600
- echo "✅ Service Account JSON 설정 완료"
608
+ m flutter_a.service_account_json_configured
601
609
 
602
610
  - name: Download AAB artifact
603
611
  uses: actions/download-artifact@v8
@@ -619,25 +627,27 @@ jobs:
619
627
  - name: Install Fastlane
620
628
  working-directory: ${{ env.FLUTTER_PROJECT_DIR }}/android
621
629
  run: |
622
- # 저장소의 Gemfile에 fastlane이 있으면 그대로 쓴다 (Gemfile.lock 커밋 권장). 없으면 생성한다.
630
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
631
+ # If the repository Gemfile has fastlane, use it as is (committing Gemfile.lock is recommended). Otherwise create one.
623
632
  if [ -f Gemfile ] && grep -Eq "['\"]fastlane['\"]" Gemfile; then
624
- echo "ℹ️ 저장소의 Gemfile을 사용합니다"
633
+ m flutter_a.using_repository_gemfile
625
634
  else
626
- # multi_json: google-apis transitive 의존성이 선언 누락한 upstream 버그 회피 (gemspec 미선언 → Gem::LoadError)
635
+ # multi_json: works around an upstream bug where a google-apis transitive dependency is not declared (missing from the gemspec -> Gem::LoadError)
627
636
  printf 'source "https://rubygems.org"\ngem "fastlane"\ngem "multi_json"\n' > Gemfile
628
637
  fi
629
638
  bundle install
630
- echo "✅ Fastlane 설치 완료 (Bundler)"
639
+ m flutter_a.fastlane_installed_bundler
631
640
  bundle exec fastlane --version
632
641
 
633
- # Fastfile 복사 (Play Store 배포용)
634
- # android/fastlane/Fastfile.playstore를 사용하여 일관성 유지
642
+ # Copy the Fastfile (for Play Store deployment)
643
+ # Use android/fastlane/Fastfile.playstore to stay consistent
635
644
  - name: Copy Fastfile for Play Store
636
645
  run: |
646
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
637
647
  mkdir -p android/fastlane
638
648
  cp android/fastlane/Fastfile.playstore android/fastlane/Fastfile
639
- echo "✅ Fastfile 복사 완료 (Fastfile.playstore → Fastfile)"
640
- echo "📋 Fastfile 내용:"
649
+ m flutter_a.fastfile_copied_fastfile_playstore_fastfile
650
+ m flutter_a.fastfile_contents
641
651
  cat android/fastlane/Fastfile
642
652
 
643
653
  - name: Upload to Play Store Internal Testing
@@ -645,53 +655,54 @@ jobs:
645
655
  DEPLOY_MODE: ${{ env.DEPLOY_MODE }}
646
656
  PACKAGE_NAME: ${{ secrets.ANDROID_PACKAGE_NAME || vars.ANDROID_PACKAGE_NAME }}
647
657
  run: |
658
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
648
659
  echo "=========================================="
649
- echo "🚀 Play Store 배포 시작"
660
+ m flutter_a.starting_play_store_deployment
650
661
  echo "=========================================="
651
- echo "🕐 배포 시작 시간: $(date '+%Y-%m-%d %H:%M:%S')"
662
+ m flutter_a.deploy_start_time cmd1="$(date '+%Y-%m-%d %H:%M:%S')"
652
663
  echo "🔍 GitHub Run Number: ${{ github.run_number }}"
653
664
  echo "🔍 GitHub SHA: ${{ github.sha }}"
654
665
 
655
- # 환경 변수 초기화 및 검증
666
+ # Initialize and validate environment variables
656
667
  VERSION_CODE="${{ needs.prepare-build.outputs.version_code }}"
657
668
  VERSION_NAME="${{ needs.prepare-build.outputs.version }}"
658
669
 
659
- echo "📋 배포 대상 버전 정보:"
670
+ m flutter_a.version_info_deploy
660
671
  echo " VERSION_NAME: '$VERSION_NAME'"
661
672
  echo " VERSION_CODE: '$VERSION_CODE'"
662
673
 
663
- # 입력 검증
674
+ # Validate inputs
664
675
  if [ -z "$VERSION_NAME" ] || [ -z "$VERSION_CODE" ]; then
665
- echo "❌ 치명적 오류: VERSION_NAME 또는 VERSION_CODE가 비어있습니다!"
676
+ m flutter_a.fatal_error_version_name_or
666
677
  echo "VERSION_NAME: '$VERSION_NAME'"
667
678
  echo "VERSION_CODE: '$VERSION_CODE'"
668
- echo "이는 prepare-build 작업에서 출력이 제대로 전달되지 않았음을 의미합니다."
679
+ m flutter_a.means_prepare_build_job_did
669
680
  exit 1
670
681
  fi
671
682
 
672
- # AAB 파일 절대 경로 찾기
683
+ # Find the absolute path of the AAB file
673
684
  AAB_PATH=$(realpath build/app/outputs/bundle/release/app-release.aab)
674
- echo "📦 AAB 파일 경로: $AAB_PATH"
685
+ m flutter_a.aab_file_path aab_path="$AAB_PATH"
675
686
 
676
687
  if [ ! -f "$AAB_PATH" ]; then
677
- echo "❌ AAB 파일을 찾을 수 없습니다!"
678
- echo "🔍 빌드 디렉토리 내용:"
679
- ls -la build/app/outputs/bundle/release/ || echo "디렉토리가 존재하지 않습니다"
680
- echo "🔍 전체 빌드 디렉토리 구조:"
681
- find build/ -name "*.aab" -o -name "*.apk" 2>/dev/null || echo "AAB/APK 파일을 찾을 수 없습니다"
688
+ m flutter_a.aab_file_not_found
689
+ m flutter_a.build_directory_contents
690
+ ls -la build/app/outputs/bundle/release/ || m flutter_a.directory_does_not_exist
691
+ m flutter_a.full_build_directory_structure
692
+ find build/ -name "*.aab" -o -name "*.apk" 2>/dev/null || m flutter_a.aab_apk_not_found
682
693
  exit 1
683
694
  fi
684
695
 
685
- echo "✅ AAB 파일 존재 확인"
686
- echo "📋 AAB 파일 정보: $(ls -lah "$AAB_PATH")"
687
- echo "📱 AAB 파일 크기: $(du -h "$AAB_PATH" | cut -f1)"
696
+ m flutter_a.aab_file_exists
697
+ m flutter_a.aab_file_info cmd1="$(ls -lah "$AAB_PATH")"
698
+ m flutter_a.aab_file_size cmd1="$(du -h "$AAB_PATH" | cut -f1)"
688
699
 
689
- # 배포 전 AAB 버전 검증
700
+ # Verify the AAB version before deploying
690
701
  echo "=========================================="
691
- echo "🔍 AAB 버전 검증 중..."
702
+ m flutter_a.verifying_aab_version
692
703
  echo "=========================================="
693
704
 
694
- # bundletool 다운로드
705
+ # Download bundletool
695
706
  if [ ! -f "bundletool.jar" ]; then
696
707
  wget -q "https://github.com/google/bundletool/releases/download/1.15.6/bundletool-all-1.15.6.jar" -O bundletool.jar
697
708
  fi
@@ -703,52 +714,52 @@ jobs:
703
714
  FINAL_VERSION_CODE=$(echo "$MANIFEST_OUTPUT" | grep -o 'android:versionCode="[0-9]*"' | grep -o '[0-9]*' | head -1)
704
715
  FINAL_VERSION_NAME=$(echo "$MANIFEST_OUTPUT" | grep -o 'android:versionName="[^"]*"' | sed 's/android:versionName="//;s/"//' | head -1)
705
716
 
706
- echo "📋 AAB 버전: $FINAL_VERSION_NAME (코드: $FINAL_VERSION_CODE)"
717
+ m flutter_a.aab_version_code final_version_name="$FINAL_VERSION_NAME" final_version_code="$FINAL_VERSION_CODE"
707
718
 
708
- # VERSION_CODE 검증
719
+ # Verify VERSION_CODE
709
720
  if [ "$FINAL_VERSION_CODE" != "$VERSION_CODE" ]; then
710
- echo "❌ 오류: AAB 버전 코드가 예상과 다릅니다! (예상: $VERSION_CODE, 실제: $FINAL_VERSION_CODE)"
721
+ m flutter_a.error_aab_version_code_not version_code="$VERSION_CODE" final_version_code="$FINAL_VERSION_CODE"
711
722
  exit 1
712
723
  fi
713
724
 
714
- echo "✅ 버전 검증 성공"
725
+ m flutter_a.version_check_passed
715
726
  else
716
- echo "⚠️ 버전 검증 실패, 배포 계속 진행"
727
+ m flutter_a.version_check_failed_continuing_deployment
717
728
  fi
718
729
  fi
719
730
 
720
- # Release notes 준비
731
+ # Prepare the release notes
721
732
  CHANGELOG_DIR="android/fastlane/metadata/android/ko-KR/changelogs"
722
733
  mkdir -p "$CHANGELOG_DIR"
723
734
 
724
735
  if [ -f "$GITHUB_WORKSPACE/final_release_notes.txt" ]; then
725
- # Google Play release notes 한도(500 글자)에 맞춰 절단 (마진 두어 480자)
726
- # final_release_notes.txt·truncate 스크립트는 레포 루트 기준 — working-directory가 FLUTTER_PROJECT_DIR이므로 절대경로 사용
736
+ # Truncate to the Google Play release notes limit (500 characters) with some margin (480)
737
+ # final_release_notes.txt and the truncate script are relative to the repo root - working-directory is FLUTTER_PROJECT_DIR, so use absolute paths
727
738
  python3 "$GITHUB_WORKSPACE/.github/scripts/truncate_release_notes.py" "$GITHUB_WORKSPACE/final_release_notes.txt" 480 char
728
739
  cp "$GITHUB_WORKSPACE/final_release_notes.txt" "$CHANGELOG_DIR/${VERSION_CODE}.txt"
729
- echo "✅ Changelog 준비 완료 (버전 코드: $VERSION_CODE)"
740
+ m flutter_a.changelog_ready_version_code version_code="$VERSION_CODE"
730
741
  else
731
- echo "v$VERSION_NAME 업데이트" > "$CHANGELOG_DIR/${VERSION_CODE}.txt"
732
- echo "⚠️ 기본 Changelog 생성 (버전 코드: $VERSION_CODE)"
742
+ m flutter_a.default_release_note_name version_name="$VERSION_NAME" > "$CHANGELOG_DIR/${VERSION_CODE}.txt"
743
+ m flutter_a.created_default_changelog_version_code version_code="$VERSION_CODE"
733
744
  fi
734
745
 
735
- # Service Account JSON 파일 확인
746
+ # Check the Service Account JSON file
736
747
  GOOGLE_PLAY_JSON_KEY="$HOME/.config/gcloud/service-account.json"
737
748
  if [ ! -f "$GOOGLE_PLAY_JSON_KEY" ]; then
738
- echo "❌ Service Account JSON 파일을 찾을 수 없습니다"
749
+ m flutter_a.service_account_json_file_not
739
750
  exit 1
740
751
  fi
741
752
 
742
- # 환경변수 설정
753
+ # Set environment variables
743
754
  export AAB_PATH="$AAB_PATH"
744
755
  export GOOGLE_PLAY_JSON_KEY="$GOOGLE_PLAY_JSON_KEY"
745
756
  export VERSION_NAME="$VERSION_NAME"
746
757
  export VERSION_CODE="$VERSION_CODE"
747
758
 
748
- # 배포 실행
759
+ # Run the deployment
749
760
  echo "=========================================="
750
- echo "🚀 Play Store 배포 실행"
751
- echo "🎯 버전: $VERSION_NAME (코드: $VERSION_CODE)"
761
+ m flutter_a.running_play_store_deployment
762
+ m flutter_a.version_code version_name="$VERSION_NAME" version_code="$VERSION_CODE"
752
763
  echo "=========================================="
753
764
 
754
765
  cd android
@@ -757,17 +768,19 @@ jobs:
757
768
  - name: Notify Play Store Upload Success
758
769
  if: success()
759
770
  run: |
760
- echo "✅ Play Store 내부 테스트 배포 성공!"
761
- echo "버전: ${{ needs.prepare-build.outputs.version }} (${{ needs.prepare-build.outputs.version_code }})"
762
- echo "커밋: ${{ github.sha }}"
771
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
772
+ m flutter_a.play_store_internal_testing_deployment
773
+ m flutter_a.version version="${{ needs.prepare-build.outputs.version }}" version_code="${{ needs.prepare-build.outputs.version_code }}"
774
+ m flutter_a.commit sha="${{ github.sha }}"
763
775
  echo ""
764
- echo "📱 테스터 확인 방법:"
765
- echo "1. Play Console → 테스트 및 출시 → 내부 테스트"
766
- echo "2. 테스터에게 테스트 링크 공유"
767
- # Play Console URL은 프로젝트별로 다르므로 별도 설정 필요
776
+ m flutter_a.how_testers_check_build
777
+ m flutter_a.play_console_test_release_internal
778
+ m flutter_a.share_test_link_your_testers
779
+ # The Play Console URL differs per project, so it needs separate setup
768
780
 
769
781
  - name: Notify on Failure
770
782
  if: failure()
771
783
  run: |
772
- echo "❌ Play Store 배포 실패!"
773
- echo "로그를 확인해주세요."
784
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
785
+ m flutter_a.play_store_deployment_failed
786
+ m flutter_a.please_check_logs