project-auto-wizard 0.15.0 → 0.16.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 (65) hide show
  1. package/README.ja.md +1 -1
  2. package/README.ko.md +1 -1
  3. package/README.md +2 -2
  4. package/README.zh-CN.md +1 -1
  5. package/package.json +1 -1
  6. package/payload/config/breaking-changes.json +31 -5
  7. package/payload/config/wizard-prompts.yml +0 -4
  8. package/payload/scripts/messages.py +162 -26
  9. package/payload/scripts/version_manager.py +69 -40
  10. package/payload/version.yml.template +6 -2
  11. package/payload/workflows/common/PROJECT-COMMON-AI-PR-SUMMARY.yaml +3 -0
  12. package/payload/workflows/common/PROJECT-COMMON-AUTO-CHANGELOG-CONTROL.yaml +64 -1
  13. package/payload/workflows/common/PROJECT-COMMON-README-VERSION-UPDATE.yaml +61 -12
  14. package/payload/workflows/common/PROJECT-COMMON-RELEASE-PUBLISH.yaml +46 -10
  15. package/payload/workflows/common/PROJECT-COMMON-VERSION-CONTROL.yaml +40 -11
  16. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-FIREBASE-CICD.yaml +24 -8
  17. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-PLAYSTORE-CICD.yaml +29 -10
  18. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-SELFHOSTED-CICD.yaml +57 -23
  19. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-TEST-APK.yaml +155 -72
  20. package/payload/workflows/flutter/PROJECT-FLUTTER-APP-BUILD-TRIGGER.yaml +49 -20
  21. package/payload/workflows/flutter/PROJECT-FLUTTER-CI.yaml +162 -62
  22. package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT.yaml +184 -87
  23. package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TESTFLIGHT.yaml +38 -15
  24. package/payload/workflows/go/PROJECT-GO-CI.yaml +14 -5
  25. package/payload/workflows/go/PROJECT-GO-PR-PREVIEW.yaml +375 -120
  26. package/payload/workflows/go/PROJECT-GO-SIMPLE-CICD.yaml +9 -4
  27. package/payload/workflows/python/PROJECT-PYTHON-CI.yaml +12 -4
  28. package/payload/workflows/python/PROJECT-PYTHON-PR-PREVIEW.yaml +375 -120
  29. package/payload/workflows/python/PROJECT-PYTHON-SIMPLE-CICD.yaml +9 -4
  30. package/payload/workflows/react/PROJECT-REACT-CI.yaml +38 -9
  31. package/payload/workflows/react/PROJECT-REACT-CICD.yaml +19 -5
  32. package/payload/workflows/spring/PROJECT-SPRING-CI.yml +71 -35
  33. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-NGINX-CICD.yaml +9 -6
  34. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-TRAEFIK-CICD.yaml +7 -4
  35. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-PR-PREVIEW.yaml +425 -144
  36. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-SIMPLE-CICD.yaml +7 -4
  37. package/src/cli/args.js +32 -22
  38. package/src/commands/doctor.js +20 -0
  39. package/src/commands/dry-run.js +9 -1
  40. package/src/commands/full.js +9 -4
  41. package/src/commands/interactive.js +29 -30
  42. package/src/commands/status.js +19 -5
  43. package/src/context.js +4 -2
  44. package/src/core/copy/simple.js +31 -0
  45. package/src/core/copy/workflows.js +2 -2
  46. package/src/core/deploy-style.js +1 -1
  47. package/src/core/detect.js +3 -2
  48. package/src/core/options.js +88 -0
  49. package/src/core/release-options.js +6 -23
  50. package/src/core/types.js +15 -8
  51. package/src/core/version-yml.js +68 -26
  52. package/src/i18n/catalog/en/cli.js +3 -1
  53. package/src/i18n/catalog/en/commands.js +15 -0
  54. package/src/i18n/catalog/en/core2.js +3 -0
  55. package/src/i18n/catalog/en/ui.js +1 -0
  56. package/src/i18n/catalog/ko/cli.js +3 -1
  57. package/src/i18n/catalog/ko/commands.js +15 -0
  58. package/src/i18n/catalog/ko/core2.js +3 -0
  59. package/src/i18n/catalog/ko/ui.js +1 -0
  60. package/src/index.js +7 -3
  61. package/src/ui/env-plan.js +1 -1
  62. package/src/ui/prompts.js +9 -5
  63. package/src/ui/status-cards.js +2 -2
  64. package/payload/workflows/next/PROJECT-NEXT-CI.yaml +0 -241
  65. package/payload/workflows/next/PROJECT-NEXT-CICD.yaml +0 -330
@@ -35,6 +35,13 @@
35
35
  # trigger and workflow_dispatch is dispatched too. A PAT or human merge
36
36
  # already fired the push event, so those are left alone (no double deploy).
37
37
  #
38
+ # The trunk-based docs commit is pushed with fetch -> rebase -> push retries.
39
+ # If README.md conflicts with a concurrent README commit (a date refresh),
40
+ # the remote README is kept and the released version line is reapplied, so
41
+ # a README conflict never stops the tag and the Release from being created.
42
+ # README-VERSION-UPDATE skips its own push run in trunk-based mode; this
43
+ # workflow dispatches it after publishing instead.
44
+ #
38
45
  # Release-confirm pattern: "chore(release):" — keep in sync with
39
46
  # PROJECT-COMMON-AUTO-CHANGELOG-CONTROL and PROJECT-COMMON-VERSION-CONTROL.
40
47
  #
@@ -94,6 +101,7 @@ jobs:
94
101
  - name: Detect branch mode
95
102
  id: mode
96
103
  run: |
104
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
97
105
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
98
106
  # scoped to the metadata: -> template: -> branches: chain so an
99
107
  # unrelated top-level "mode:" key can never hijack the value
@@ -104,6 +112,7 @@ jobs:
104
112
  - name: Release gate
105
113
  id: gate
106
114
  run: |
115
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
107
116
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
108
117
  MODE="${{ steps.mode.outputs.mode }}"
109
118
  EVENT="${{ github.event_name }}"
@@ -167,6 +176,7 @@ jobs:
167
176
  steps.mode.outputs.mode == 'trunk-based' &&
168
177
  github.event_name == 'push'
169
178
  run: |
179
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
170
180
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
171
181
  # scoped to the metadata: -> template: -> options: chain so an
172
182
  # unrelated "semver_auto:" key can never hijack the value
@@ -181,6 +191,7 @@ jobs:
181
191
  steps.mode.outputs.mode == 'trunk-based' &&
182
192
  github.event_name == 'push'
183
193
  run: |
194
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
184
195
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
185
196
  # scoped to the metadata: -> template: -> options: chain so an
186
197
  # unrelated "copilot_ai:" key can never hijack the value
@@ -209,6 +220,7 @@ jobs:
209
220
  GITHUB_TOKEN: ${{ github.token }}
210
221
  COPILOT_AI: ${{ steps.copilot_options.outputs.copilot_ai }}
211
222
  run: |
223
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
212
224
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
213
225
  # Idempotency: on a re-run of a failed job the checked-out HEAD may
214
226
  # already be this workflow's own docs commit — never bump twice.
@@ -297,8 +309,12 @@ jobs:
297
309
  else
298
310
  git commit -m "chore(version): release v${NEW_VERSION} docs [skip ci]"
299
311
 
300
- # Race-condition guard: pull-rebase then push (up to 3 retries)
301
- MAX_RETRIES=3
312
+ # >>> push-with-retry
313
+ # Race-condition guard: fetch -> rebase -> push, retried. A concurrent
314
+ # README-only commit (date refresh) touches the same version line and
315
+ # conflicts on rebase; the remote README is kept and this run's version
316
+ # line is reapplied, so a README conflict never blocks the release.
317
+ MAX_RETRIES=5
302
318
  RETRY_COUNT=0
303
319
  PUSH_SUCCESS=false
304
320
 
@@ -310,22 +326,36 @@ jobs:
310
326
  PUSH_SUCCESS=true
311
327
  echo "$(m wf_release.docs_pushed)"
312
328
  break
313
- else
314
- echo "$(m wf_common.push_failed_syncing)"
315
- if git pull --rebase origin {{MAIN_BRANCH}}; then
316
- echo "$(m wf_common.rebase_ok)"
317
- else
318
- echo "$(m wf_common.rebase_failed)"
319
- git rebase --abort 2>/dev/null || true
320
- exit 1
329
+ fi
330
+
331
+ echo "$(m wf_common.push_failed_syncing)"
332
+ git fetch origin {{MAIN_BRANCH}}
333
+ if git rebase origin/{{MAIN_BRANCH}}; then
334
+ echo "$(m wf_common.rebase_ok)"
335
+ continue
336
+ fi
337
+
338
+ # Only README.md conflicting: "ours" is the remote side during a rebase
339
+ if [ "$(git diff --name-only --diff-filter=U)" = "README.md" ]; then
340
+ git checkout --ours -- README.md
341
+ python3 -c 'import sys; sys.path.insert(0, ".github/scripts"); import version_manager as vm; vm.update_readme_version(vm.get_current_version())' || true
342
+ git add README.md
343
+ if GIT_EDITOR=true git rebase --continue; then
344
+ echo "$(m wf_common.readme_conflict_resolved)"
345
+ continue
321
346
  fi
322
347
  fi
348
+
349
+ echo "$(m wf_common.rebase_failed)"
350
+ git rebase --abort 2>/dev/null || true
351
+ exit 1
323
352
  done
324
353
 
325
354
  if [ "$PUSH_SUCCESS" = false ]; then
326
355
  echo "$(m wf_common.push_gave_up max_retries="$MAX_RETRIES")"
327
356
  exit 1
328
357
  fi
358
+ # <<< push-with-retry
329
359
  fi
330
360
 
331
361
  - name: Resolve version + idempotency guard
@@ -334,6 +364,7 @@ jobs:
334
364
  env:
335
365
  GH_TOKEN: ${{ github.token }}
336
366
  run: |
367
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
337
368
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
338
369
  VERSION=$(python3 .github/scripts/version_manager.py get | tail -n 1)
339
370
  if [ -z "$VERSION" ]; then
@@ -365,6 +396,7 @@ jobs:
365
396
  - name: Create and push tag
366
397
  if: steps.gate.outputs.proceed == 'true' && steps.version.outputs.tag_exists != 'true'
367
398
  run: |
399
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
368
400
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
369
401
  VERSION="${{ steps.version.outputs.version }}"
370
402
  git tag "v$VERSION"
@@ -376,6 +408,7 @@ jobs:
376
408
  env:
377
409
  GH_TOKEN: ${{ github.token }}
378
410
  run: |
411
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
379
412
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
380
413
  VERSION="${{ steps.version.outputs.version }}"
381
414
 
@@ -415,6 +448,7 @@ jobs:
415
448
  # default token.
416
449
  GH_TOKEN: ${{ secrets.WORKFLOW_PAT || github.token }}
417
450
  run: |
451
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
418
452
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
419
453
  VERSION="${{ steps.version.outputs.version }}"
420
454
  gh release create "v$VERSION" --title "v$VERSION" --notes-file notes.md
@@ -430,6 +464,7 @@ jobs:
430
464
  env:
431
465
  GH_TOKEN: ${{ github.token }}
432
466
  run: |
467
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
433
468
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
434
469
  if gh workflow run PROJECT-COMMON-README-VERSION-UPDATE.yaml --ref {{MAIN_BRANCH}}; then
435
470
  echo "$(m wf_release.readme_dispatch_ok)"
@@ -457,6 +492,7 @@ jobs:
457
492
  RELEASE_VERSION: ${{ steps.version.outputs.version }}
458
493
  MAIN_BRANCH: "{{MAIN_BRANCH}}"
459
494
  run: |
495
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
460
496
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
461
497
  # Merge commit of this version's release PR - releases that are not merges
462
498
  # (safety-net bump, manual republish) were already deployed by a human push,
@@ -66,6 +66,7 @@ jobs:
66
66
  - name: Release merge / mode guard
67
67
  id: release_guard
68
68
  run: |
69
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
69
70
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
70
71
  SKIP="false"
71
72
 
@@ -104,6 +105,7 @@ jobs:
104
105
  id: current_version
105
106
  if: steps.release_guard.outputs.skip != 'true'
106
107
  run: |
108
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
107
109
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
108
110
  CURRENT_VERSION=$(python3 .github/scripts/version_manager.py get | tail -n 1)
109
111
  if [ -z "$CURRENT_VERSION" ]; then
@@ -117,6 +119,7 @@ jobs:
117
119
  id: version
118
120
  if: steps.release_guard.outputs.skip != 'true'
119
121
  run: |
122
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
120
123
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
121
124
  NEW_VERSION=$(python3 .github/scripts/version_manager.py increment | tail -n 1)
122
125
  if [ -z "$NEW_VERSION" ]; then
@@ -131,6 +134,7 @@ jobs:
131
134
  id: project_info
132
135
  if: steps.release_guard.outputs.skip != 'true'
133
136
  run: |
137
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
134
138
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
135
139
  if [ -f "version.yml" ]; then
136
140
  PROJECT_TYPES=$(grep "^project_types:" version.yml 2>/dev/null | sed -E 's/.*\[([^]]*)\].*/\1/' | tr -d '" ')
@@ -154,6 +158,7 @@ jobs:
154
158
  AI_API_BASE_URL: ${{ vars.AI_API_BASE_URL }}
155
159
  AI_MODEL: ${{ vars.AI_MODEL }}
156
160
  run: |
161
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
157
162
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
158
163
  NEW_VERSION="${{ steps.version.outputs.new_version }}"
159
164
 
@@ -188,6 +193,7 @@ jobs:
188
193
  id: commit_push
189
194
  if: steps.release_guard.outputs.skip != 'true'
190
195
  run: |
196
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
191
197
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
192
198
  git config --local user.email "action@github.com"
193
199
  git config --local user.name "GitHub Action"
@@ -206,8 +212,12 @@ jobs:
206
212
  COMMIT_MSG="chore(version): bump to v${NEW_VERSION} [skip ci]"
207
213
 
208
214
  if git commit -m "$COMMIT_MSG"; then
209
- # Race-condition guard: pull-rebase then push (up to 3 retries)
210
- MAX_RETRIES=3
215
+ # >>> push-with-retry
216
+ # Race-condition guard: fetch -> rebase -> push, retried. A concurrent
217
+ # README-only commit (date refresh) touches the same version line and
218
+ # conflicts on rebase; the remote README is kept and this run's version
219
+ # line is reapplied, so a README conflict never blocks the release.
220
+ MAX_RETRIES=5
211
221
  RETRY_COUNT=0
212
222
  PUSH_SUCCESS=false
213
223
 
@@ -219,22 +229,36 @@ jobs:
219
229
  PUSH_SUCCESS=true
220
230
  echo "$(m wf_version.bump_pushed)"
221
231
  break
222
- else
223
- echo "$(m wf_common.push_failed_syncing)"
224
- if git pull --rebase origin {{MAIN_BRANCH}}; then
225
- echo "$(m wf_common.rebase_ok)"
226
- else
227
- echo "$(m wf_common.rebase_failed)"
228
- git rebase --abort 2>/dev/null || true
229
- exit 1
232
+ fi
233
+
234
+ echo "$(m wf_common.push_failed_syncing)"
235
+ git fetch origin {{MAIN_BRANCH}}
236
+ if git rebase origin/{{MAIN_BRANCH}}; then
237
+ echo "$(m wf_common.rebase_ok)"
238
+ continue
239
+ fi
240
+
241
+ # Only README.md conflicting: "ours" is the remote side during a rebase
242
+ if [ "$(git diff --name-only --diff-filter=U)" = "README.md" ]; then
243
+ git checkout --ours -- README.md
244
+ python3 -c 'import sys; sys.path.insert(0, ".github/scripts"); import version_manager as vm; vm.update_readme_version(vm.get_current_version())' || true
245
+ git add README.md
246
+ if GIT_EDITOR=true git rebase --continue; then
247
+ echo "$(m wf_common.readme_conflict_resolved)"
248
+ continue
230
249
  fi
231
250
  fi
251
+
252
+ echo "$(m wf_common.rebase_failed)"
253
+ git rebase --abort 2>/dev/null || true
254
+ exit 1
232
255
  done
233
256
 
234
257
  if [ "$PUSH_SUCCESS" = false ]; then
235
258
  echo "$(m wf_common.push_gave_up max_retries="$MAX_RETRIES")"
236
259
  exit 1
237
260
  fi
261
+ # <<< push-with-retry
238
262
  echo "pushed=true" >> "$GITHUB_OUTPUT"
239
263
  else
240
264
  echo "$(m wf_version.commit_failed)"
@@ -248,6 +272,7 @@ jobs:
248
272
  env:
249
273
  GH_TOKEN: ${{ github.token }}
250
274
  run: |
275
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
251
276
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
252
277
  gh workflow run PROJECT-COMMON-RELEASE-PUBLISH.yaml --ref {{MAIN_BRANCH}}
253
278
  echo "$(m wf_version.release_publish_triggered)"
@@ -260,6 +285,7 @@ jobs:
260
285
  # so only a warning is left.
261
286
  if: steps.release_guard.outputs.skip != 'true' && steps.commit_push.outputs.pushed == 'true'
262
287
  run: |
288
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
263
289
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
264
290
  DEVELOP_BRANCH="{{DEVELOP_BRANCH}}"
265
291
  NEW_VERSION="${{ steps.version.outputs.new_version }}"
@@ -293,10 +319,13 @@ jobs:
293
319
 
294
320
  - name: Summary
295
321
  if: always()
322
+ env:
323
+ PAW_REF_NAME: ${{ github.ref_name }}
296
324
  run: |
325
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
297
326
  m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
298
327
  echo "$(m wf_version.finished)"
299
328
  echo "$(m wf_version.sum_skipped skip="${{ steps.release_guard.outputs.skip }}")"
300
329
  echo "$(m wf_version.sum_previous current_version="${{ steps.current_version.outputs.current_version }}")"
301
330
  echo "$(m wf_version.sum_new new_version="${{ steps.version.outputs.new_version }}")"
302
- echo "$(m wf_version.sum_branch ref_name="${{ github.ref_name }}")"
331
+ echo "$(m wf_version.sum_branch ref_name="$PAW_REF_NAME")"
@@ -96,6 +96,7 @@ jobs:
96
96
  RELEASE_KEY_PASSWORD: ${{ secrets.RELEASE_KEY_PASSWORD }}
97
97
  FIREBASE_SERVICE_ACCOUNT_JSON_BASE64: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_JSON_BASE64 }}
98
98
  run: |
99
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
99
100
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
100
101
  MISSING=""
101
102
  for NAME in RELEASE_KEYSTORE_BASE64 RELEASE_KEYSTORE_PASSWORD RELEASE_KEY_ALIAS RELEASE_KEY_PASSWORD FIREBASE_SERVICE_ACCOUNT_JSON_BASE64; do
@@ -123,14 +124,16 @@ jobs:
123
124
  env:
124
125
  ENV_CONTENT: ${{ secrets.ENV_FILE || secrets.ENV }}
125
126
  run: |
127
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
128
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
126
129
  if [ "$ENV_MODE" = "dotenv" ]; then
127
130
  printf '%s\n' "$ENV_CONTENT" > .env
128
- echo ".env file created"
131
+ m wf_flutter.dotenv_created
129
132
  elif [ -n "$ENV_CONTENT" ]; then
130
133
  DART_DEFINE_FILE="$RUNNER_TEMP/dart-define.env"
131
134
  printf '%s\n' "$ENV_CONTENT" > "$DART_DEFINE_FILE"
132
135
  echo "DART_DEFINE_FILE=$DART_DEFINE_FILE" >> "$GITHUB_ENV"
133
- echo "dart-define file prepared"
136
+ m wf_flutter.dart_define_prepared
134
137
  fi
135
138
 
136
139
  - name: Set up Flutter
@@ -158,6 +161,7 @@ jobs:
158
161
  id: current_version
159
162
  working-directory: ${{ github.workspace }} # version_manager.py must read the repo-root version.yml
160
163
  run: |
164
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
161
165
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
162
166
  # Get VERSION (x.y.z format)
163
167
  VERSION=$(python3 .github/scripts/version_manager.py get | tail -n 1)
@@ -179,13 +183,14 @@ jobs:
179
183
  echo "VERSION=$VERSION" >> $GITHUB_ENV
180
184
  echo "VERSION_CODE=$VERSION_CODE" >> $GITHUB_ENV
181
185
  echo "TODAY=$(date '+%Y-%m-%d')" >> $GITHUB_ENV
182
- echo "TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV
186
+ echo "TIMESTAMP=$(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_ENV
183
187
  echo "PROJECT_TYPE=${{ env.PROJECT_TYPE }}" >> $GITHUB_ENV
184
188
 
185
189
  - name: Generate release notes
186
190
  id: release_notes
187
191
  working-directory: ${{ github.workspace }} # CHANGELOG.json, changelog_manager.py and final_release_notes.txt (paired with the upload) are relative to the repo root
188
192
  run: |
193
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
189
194
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
190
195
  VERSION="${{ steps.current_version.outputs.version }}"
191
196
 
@@ -263,14 +268,16 @@ jobs:
263
268
  env:
264
269
  ENV_CONTENT: ${{ secrets.ENV_FILE || secrets.ENV }}
265
270
  run: |
271
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
272
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
266
273
  if [ "$ENV_MODE" = "dotenv" ]; then
267
274
  printf '%s\n' "$ENV_CONTENT" > .env
268
- echo ".env file created"
275
+ m wf_flutter.dotenv_created
269
276
  elif [ -n "$ENV_CONTENT" ]; then
270
277
  DART_DEFINE_FILE="$RUNNER_TEMP/dart-define.env"
271
278
  printf '%s\n' "$ENV_CONTENT" > "$DART_DEFINE_FILE"
272
279
  echo "DART_DEFINE_FILE=$DART_DEFINE_FILE" >> "$GITHUB_ENV"
273
- echo "dart-define file prepared"
280
+ m wf_flutter.dart_define_prepared
274
281
  fi
275
282
 
276
283
  - name: Setup Release Keystore
@@ -280,6 +287,7 @@ jobs:
280
287
  RELEASE_KEY_ALIAS: ${{ secrets.RELEASE_KEY_ALIAS }}
281
288
  RELEASE_KEY_PASSWORD: ${{ secrets.RELEASE_KEY_PASSWORD }}
282
289
  run: |
290
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
283
291
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
284
292
  # 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
285
293
  MISSING=""
@@ -301,6 +309,7 @@ jobs:
301
309
 
302
310
  - name: Create key.properties
303
311
  run: |
312
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
304
313
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
305
314
  cat > android/key.properties << EOF
306
315
  storeFile=app/keystore/key.jks
@@ -315,12 +324,14 @@ jobs:
315
324
  env:
316
325
  GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }}
317
326
  run: |
327
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
328
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
318
329
  if [ -n "$GOOGLE_SERVICES_JSON" ]; then
319
330
  mkdir -p android/app
320
331
  printf '%s' "$GOOGLE_SERVICES_JSON" > android/app/google-services.json
321
- echo "✅ google-services.json created"
332
+ m wf_flutter.google_services_created
322
333
  else
323
- echo "ℹ️ GOOGLE_SERVICES_JSON secret not provided, skipping"
334
+ m wf_flutter.google_services_skipped
324
335
  fi
325
336
 
326
337
  - name: Set up Flutter
@@ -362,6 +373,7 @@ jobs:
362
373
 
363
374
  - name: Configure Android build for release
364
375
  run: |
376
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
365
377
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
366
378
  # Add the release signing config to build.gradle.kts if it is missing
367
379
  if ! grep -q "signingConfigs" android/app/build.gradle.kts; then
@@ -375,6 +387,7 @@ jobs:
375
387
 
376
388
  - name: Build Android App Bundle (AAB)
377
389
  run: |
390
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
378
391
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
379
392
  VERSION_NAME="${{ needs.prepare-build.outputs.version }}"
380
393
  VERSION_CODE="${{ needs.prepare-build.outputs.version_code }}"
@@ -437,7 +450,7 @@ jobs:
437
450
  # pubspec.yaml stays in x.y.z format; VERSION_CODE is managed automatically in version.yml
438
451
  m flutter_a.running_flutter_build
439
452
  m flutter_a.command_flutter_build_appbundle_release version_name="$VERSION_NAME" version_code="$VERSION_CODE"
440
- m flutter_a.build_start_time cmd1="$(date '+%Y-%m-%d %H:%M:%S')"
453
+ m flutter_a.build_start_time cmd1="$(date -u '+%Y-%m-%d %H:%M:%S UTC')"
441
454
 
442
455
  flutter build appbundle \
443
456
  --release \
@@ -624,6 +637,7 @@ jobs:
624
637
  env:
625
638
  SERVICE_ACCOUNT_BASE64: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_JSON_BASE64 }}
626
639
  run: |
640
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
627
641
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
628
642
  if [ -z "$SERVICE_ACCOUNT_BASE64" ]; then
629
643
  echo "::error::$(m flutter_a.firebase_service_account_json_base64)"
@@ -658,6 +672,7 @@ jobs:
658
672
  - name: Notify Firebase Upload Success
659
673
  if: success()
660
674
  run: |
675
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
661
676
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
662
677
  m flutter_a.firebase_app_distribution_deployment_succeeded
663
678
  m flutter_a.version version="${{ needs.prepare-build.outputs.version }}" version_code="${{ needs.prepare-build.outputs.version_code }}"
@@ -671,6 +686,7 @@ jobs:
671
686
  - name: Notify on Failure
672
687
  if: failure()
673
688
  run: |
689
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
674
690
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
675
691
  m flutter_a.firebase_app_distribution_deployment_failed
676
692
  m flutter_a.please_check_logs
@@ -83,6 +83,7 @@ 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
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
86
87
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
87
88
  MISSING=""
88
89
  for NAME in RELEASE_KEYSTORE_BASE64 RELEASE_KEYSTORE_PASSWORD RELEASE_KEY_ALIAS RELEASE_KEY_PASSWORD GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_BASE64; do
@@ -103,14 +104,16 @@ jobs:
103
104
  env:
104
105
  ENV_CONTENT: ${{ secrets.ENV_FILE || secrets.ENV }}
105
106
  run: |
107
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
108
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
106
109
  if [ "$ENV_MODE" = "dotenv" ]; then
107
110
  printf '%s\n' "$ENV_CONTENT" > .env
108
- echo ".env file created"
111
+ m wf_flutter.dotenv_created
109
112
  elif [ -n "$ENV_CONTENT" ]; then
110
113
  DART_DEFINE_FILE="$RUNNER_TEMP/dart-define.env"
111
114
  printf '%s\n' "$ENV_CONTENT" > "$DART_DEFINE_FILE"
112
115
  echo "DART_DEFINE_FILE=$DART_DEFINE_FILE" >> "$GITHUB_ENV"
113
- echo "dart-define file prepared"
116
+ m wf_flutter.dart_define_prepared
114
117
  fi
115
118
 
116
119
  - name: Set up Flutter
@@ -138,6 +141,7 @@ jobs:
138
141
  id: current_version
139
142
  working-directory: ${{ github.workspace }} # version_manager.py must read the repo-root version.yml
140
143
  run: |
144
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
141
145
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
142
146
  # Get VERSION (x.y.z format)
143
147
  VERSION=$(python3 .github/scripts/version_manager.py get | tail -n 1)
@@ -159,13 +163,14 @@ jobs:
159
163
  echo "VERSION=$VERSION" >> $GITHUB_ENV
160
164
  echo "VERSION_CODE=$VERSION_CODE" >> $GITHUB_ENV
161
165
  echo "TODAY=$(date '+%Y-%m-%d')" >> $GITHUB_ENV
162
- echo "TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV
166
+ echo "TIMESTAMP=$(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_ENV
163
167
  echo "PROJECT_TYPE=${{ env.PROJECT_TYPE }}" >> $GITHUB_ENV
164
168
 
165
169
  - name: Generate release notes
166
170
  id: release_notes
167
171
  working-directory: ${{ github.workspace }} # CHANGELOG.json, changelog_manager.py and final_release_notes.txt (paired with the upload) are relative to the repo root
168
172
  run: |
173
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
169
174
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
170
175
  VERSION="${{ steps.current_version.outputs.version }}"
171
176
 
@@ -245,14 +250,16 @@ jobs:
245
250
  env:
246
251
  ENV_CONTENT: ${{ secrets.ENV_FILE || secrets.ENV }}
247
252
  run: |
253
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
254
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
248
255
  if [ "$ENV_MODE" = "dotenv" ]; then
249
256
  printf '%s\n' "$ENV_CONTENT" > .env
250
- echo ".env file created"
257
+ m wf_flutter.dotenv_created
251
258
  elif [ -n "$ENV_CONTENT" ]; then
252
259
  DART_DEFINE_FILE="$RUNNER_TEMP/dart-define.env"
253
260
  printf '%s\n' "$ENV_CONTENT" > "$DART_DEFINE_FILE"
254
261
  echo "DART_DEFINE_FILE=$DART_DEFINE_FILE" >> "$GITHUB_ENV"
255
- echo "dart-define file prepared"
262
+ m wf_flutter.dart_define_prepared
256
263
  fi
257
264
 
258
265
  - name: Setup Release Keystore
@@ -262,6 +269,7 @@ jobs:
262
269
  RELEASE_KEY_ALIAS: ${{ secrets.RELEASE_KEY_ALIAS }}
263
270
  RELEASE_KEY_PASSWORD: ${{ secrets.RELEASE_KEY_PASSWORD }}
264
271
  run: |
272
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
265
273
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
266
274
  # 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
267
275
  MISSING=""
@@ -283,6 +291,7 @@ jobs:
283
291
 
284
292
  - name: Create key.properties
285
293
  run: |
294
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
286
295
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
287
296
  cat > android/key.properties << EOF
288
297
  storeFile=app/keystore/key.jks
@@ -297,12 +306,14 @@ jobs:
297
306
  env:
298
307
  GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }}
299
308
  run: |
309
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
310
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
300
311
  if [ -n "$GOOGLE_SERVICES_JSON" ]; then
301
312
  mkdir -p android/app
302
313
  printf '%s' "$GOOGLE_SERVICES_JSON" > android/app/google-services.json
303
- echo "✅ google-services.json created"
314
+ m wf_flutter.google_services_created
304
315
  else
305
- echo "ℹ️ GOOGLE_SERVICES_JSON secret not provided, skipping"
316
+ m wf_flutter.google_services_skipped
306
317
  fi
307
318
 
308
319
  - name: Set up Flutter
@@ -344,6 +355,7 @@ jobs:
344
355
 
345
356
  - name: Configure Android build for release
346
357
  run: |
358
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
347
359
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
348
360
  # Add the release signing config to build.gradle.kts if it is missing
349
361
  if ! grep -q "signingConfigs" android/app/build.gradle.kts; then
@@ -357,6 +369,7 @@ jobs:
357
369
 
358
370
  - name: Build Android App Bundle (AAB)
359
371
  run: |
372
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
360
373
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
361
374
  VERSION_NAME="${{ needs.prepare-build.outputs.version }}"
362
375
  VERSION_CODE="${{ needs.prepare-build.outputs.version_code }}"
@@ -419,7 +432,7 @@ jobs:
419
432
  # pubspec.yaml stays in x.y.z format; VERSION_CODE is managed automatically in version.yml
420
433
  m flutter_a.running_flutter_build
421
434
  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')"
435
+ m flutter_a.build_start_time cmd1="$(date -u '+%Y-%m-%d %H:%M:%S UTC')"
423
436
 
424
437
  flutter build appbundle \
425
438
  --release \
@@ -598,6 +611,7 @@ jobs:
598
611
  env:
599
612
  SERVICE_ACCOUNT_BASE64: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_BASE64 }}
600
613
  run: |
614
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
601
615
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
602
616
  if [ -z "$SERVICE_ACCOUNT_BASE64" ]; then
603
617
  echo "::error::$(m flutter_a.google_play_service_account_json)"
@@ -627,6 +641,7 @@ jobs:
627
641
  - name: Install Fastlane
628
642
  working-directory: ${{ env.FLUTTER_PROJECT_DIR }}/android
629
643
  run: |
644
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
630
645
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
631
646
  # If the repository Gemfile has fastlane, use it as is (committing Gemfile.lock is recommended). Otherwise create one.
632
647
  if [ -f Gemfile ] && grep -Eq "['\"]fastlane['\"]" Gemfile; then
@@ -643,6 +658,7 @@ jobs:
643
658
  # Use android/fastlane/Fastfile.playstore to stay consistent
644
659
  - name: Copy Fastfile for Play Store
645
660
  run: |
661
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
646
662
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
647
663
  mkdir -p android/fastlane
648
664
  cp android/fastlane/Fastfile.playstore android/fastlane/Fastfile
@@ -655,12 +671,13 @@ jobs:
655
671
  DEPLOY_MODE: ${{ env.DEPLOY_MODE }}
656
672
  PACKAGE_NAME: ${{ secrets.ANDROID_PACKAGE_NAME || vars.ANDROID_PACKAGE_NAME }}
657
673
  run: |
674
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
658
675
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
659
676
  echo "=========================================="
660
677
  m flutter_a.starting_play_store_deployment
661
678
  echo "=========================================="
662
- m flutter_a.deploy_start_time cmd1="$(date '+%Y-%m-%d %H:%M:%S')"
663
- echo "🔍 GitHub Run Number: ${{ github.run_number }}"
679
+ m flutter_a.deploy_start_time cmd1="$(date -u '+%Y-%m-%d %H:%M:%S UTC')"
680
+ m wf_flutter.run_number number="${{ github.run_number }}"
664
681
  echo "🔍 GitHub SHA: ${{ github.sha }}"
665
682
 
666
683
  # Initialize and validate environment variables
@@ -768,6 +785,7 @@ jobs:
768
785
  - name: Notify Play Store Upload Success
769
786
  if: success()
770
787
  run: |
788
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
771
789
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
772
790
  m flutter_a.play_store_internal_testing_deployment
773
791
  m flutter_a.version version="${{ needs.prepare-build.outputs.version }}" version_code="${{ needs.prepare-build.outputs.version_code }}"
@@ -781,6 +799,7 @@ jobs:
781
799
  - name: Notify on Failure
782
800
  if: failure()
783
801
  run: |
802
+ [ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
784
803
  m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
785
804
  m flutter_a.play_store_deployment_failed
786
805
  m flutter_a.please_check_logs