project-auto-wizard 0.13.2 → 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.
- package/README.md +1 -1
- package/bin/project-auto-wizard.js +18 -4
- package/package.json +2 -2
- package/payload/config/breaking-changes.json +28 -14
- package/payload/config/wizard-prompts.yml +102 -46
- package/payload/flutter-app/android/fastlane/Fastfile.playstore +44 -32
- package/payload/flutter-app/ios/ExportOptions.plist +8 -8
- package/payload/flutter-app/ios/fastlane/Fastfile +57 -43
- package/payload/scripts/changelog_manager.py +296 -257
- package/payload/scripts/issue_helper.py +54 -50
- package/payload/scripts/messages.py +2279 -0
- package/payload/scripts/truncate_release_notes.py +7 -6
- package/payload/scripts/version_manager.py +64 -61
- package/payload/version.yml.template +2 -1
- package/payload/workflows/common/PROJECT-COMMON-AI-PR-SUMMARY.yaml +17 -12
- package/payload/workflows/common/PROJECT-COMMON-AUTO-CHANGELOG-CONTROL.yaml +59 -34
- package/payload/workflows/common/PROJECT-COMMON-ISSUE-HELPER.yaml +17 -15
- package/payload/workflows/common/PROJECT-COMMON-README-VERSION-UPDATE.yaml +17 -10
- package/payload/workflows/common/PROJECT-COMMON-RELEASE-PUBLISH.yaml +54 -44
- package/payload/workflows/common/PROJECT-COMMON-VERSION-CONTROL.yaml +24 -17
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-FIREBASE-CICD.yaml +194 -184
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-PLAYSTORE-CICD.yaml +226 -213
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-SELFHOSTED-CICD.yaml +46 -42
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-TEST-APK.yaml +334 -241
- package/payload/workflows/flutter/PROJECT-FLUTTER-APP-BUILD-TRIGGER.yaml +152 -128
- package/payload/workflows/flutter/PROJECT-FLUTTER-CI.yaml +246 -188
- package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT.yaml +353 -238
- package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TESTFLIGHT.yaml +96 -85
- package/payload/workflows/go/PROJECT-GO-CI.yaml +47 -36
- package/payload/workflows/go/PROJECT-GO-PR-PREVIEW.yaml +945 -508
- package/payload/workflows/go/PROJECT-GO-SIMPLE-CICD.yaml +155 -133
- package/payload/workflows/next/PROJECT-NEXT-CI.yaml +76 -60
- package/payload/workflows/next/PROJECT-NEXT-CICD.yaml +97 -77
- package/payload/workflows/python/PROJECT-PYTHON-CI.yaml +62 -47
- package/payload/workflows/python/PROJECT-PYTHON-PR-PREVIEW.yaml +942 -505
- package/payload/workflows/python/PROJECT-PYTHON-SIMPLE-CICD.yaml +148 -126
- package/payload/workflows/react/PROJECT-REACT-CI.yaml +86 -70
- package/payload/workflows/react/PROJECT-REACT-CICD.yaml +112 -92
- package/payload/workflows/spring/PROJECT-SPRING-CI.yml +112 -82
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-NGINX-CICD.yaml +180 -150
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-TRAEFIK-CICD.yaml +161 -131
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-PR-PREVIEW.yaml +970 -549
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-SIMPLE-CICD.yaml +193 -162
- package/src/cli/args.js +98 -52
- package/src/cli/help.js +8 -41
- package/src/commands/doctor.js +85 -89
- package/src/commands/dry-run.js +63 -43
- package/src/commands/full.js +79 -77
- package/src/commands/install-settings.js +16 -15
- package/src/commands/interactive-flutter.js +20 -19
- package/src/commands/interactive.js +135 -132
- package/src/commands/purge.js +47 -42
- package/src/commands/status.js +36 -36
- package/src/commands/uninstall.js +43 -41
- package/src/context.js +12 -11
- package/src/core/assets.js +12 -11
- package/src/core/baseline.js +27 -27
- package/src/core/branches.js +29 -27
- package/src/core/branding.js +7 -6
- package/src/core/breaking-check.js +22 -21
- package/src/core/breaking.js +15 -8
- package/src/core/copy/app-files.js +5 -4
- package/src/core/copy/flutter-app.js +8 -8
- package/src/core/copy/gitignore.js +58 -50
- package/src/core/copy/readme.js +45 -35
- package/src/core/copy/simple.js +16 -15
- package/src/core/copy/workflows.js +131 -124
- package/src/core/deploy-style.js +51 -48
- package/src/core/detect-fs.js +57 -57
- package/src/core/detect.js +67 -65
- package/src/core/errors.js +2 -2
- package/src/core/flutter-doctor.js +17 -16
- package/src/core/flutter-hooks.js +33 -32
- package/src/core/flutter-options.js +34 -33
- package/src/core/fsutil.js +12 -12
- package/src/core/installed-stores.js +4 -4
- package/src/core/logger.js +42 -40
- package/src/core/paths-resolve.js +88 -86
- package/src/core/paths.js +10 -10
- package/src/core/release-options.js +8 -8
- package/src/core/removal-exec.js +14 -13
- package/src/core/removal-plan.js +37 -37
- package/src/core/types.js +47 -47
- package/src/core/verify.js +44 -38
- package/src/core/version-yml.js +76 -68
- package/src/core/wizard-env.js +46 -46
- package/src/core/wizard-labels.js +63 -41
- package/src/i18n/catalog/en/cli.js +50 -0
- package/src/i18n/catalog/en/commands.js +187 -0
- package/src/i18n/catalog/en/copy.js +19 -0
- package/src/i18n/catalog/en/core.js +74 -0
- package/src/i18n/catalog/en/core2.js +15 -0
- package/src/i18n/catalog/en/ui.js +221 -0
- package/src/i18n/catalog/en.js +12 -0
- package/src/i18n/catalog/index.js +5 -0
- package/src/i18n/catalog/ko/cli.js +50 -0
- package/src/i18n/catalog/ko/commands.js +187 -0
- package/src/i18n/catalog/ko/copy.js +19 -0
- package/src/i18n/catalog/ko/core.js +74 -0
- package/src/i18n/catalog/ko/core2.js +15 -0
- package/src/i18n/catalog/ko/ui.js +221 -0
- package/src/i18n/catalog/ko.js +10 -0
- package/src/i18n/index.js +44 -0
- package/src/i18n/languages.js +9 -0
- package/src/index.js +128 -94
- package/src/ui/ansi.js +7 -7
- package/src/ui/banner.js +7 -6
- package/src/ui/env-plan.js +82 -81
- package/src/ui/prompts.js +97 -122
- package/src/ui/readline-engine.js +59 -58
- package/src/ui/status-cards.js +37 -31
- package/src/ui/summary.js +89 -88
|
@@ -1,56 +1,56 @@
|
|
|
1
1
|
# project-auto-wizard:managed-workflow
|
|
2
|
-
# Flutter iOS TestFlight
|
|
2
|
+
# Flutter iOS TestFlight deploy workflow
|
|
3
3
|
#
|
|
4
|
-
#
|
|
4
|
+
# Builds the Flutter iOS app and deploys it to TestFlight automatically.
|
|
5
5
|
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
6
|
+
# The config files (ios/fastlane/Fastfile, ios/ExportOptions.plist) are installed by
|
|
7
|
+
# project-auto-wizard only when missing; existing files are never overwritten.
|
|
8
8
|
#
|
|
9
|
-
#
|
|
10
|
-
# 1. flutter build ios --no-codesign (Flutter
|
|
11
|
-
# 2. xcodebuild archive (Xcode
|
|
12
|
-
# 3. xcodebuild -exportArchive (IPA
|
|
13
|
-
# 4. fastlane deploy (ios/fastlane/Fastfile
|
|
9
|
+
# Build pipeline:
|
|
10
|
+
# 1. flutter build ios --no-codesign (Flutter build)
|
|
11
|
+
# 2. xcodebuild archive (create the Xcode archive)
|
|
12
|
+
# 3. xcodebuild -exportArchive (create the IPA using ExportOptions.plist)
|
|
13
|
+
# 4. fastlane deploy (uses ios/fastlane/Fastfile; TestFlight or review submission depending on DEPLOY_MODE)
|
|
14
14
|
#
|
|
15
|
-
#
|
|
15
|
+
# Required GitHub Secrets
|
|
16
16
|
#
|
|
17
|
-
# Apple
|
|
18
|
-
# APPLE_CERTIFICATE_BASE64: .p12
|
|
19
|
-
# APPLE_CERTIFICATE_PASSWORD: .p12
|
|
20
|
-
# APPLE_PROVISIONING_PROFILE_BASE64: .mobileprovision
|
|
21
|
-
# IOS_PROVISIONING_PROFILE_NAME:
|
|
17
|
+
# Apple certificate & provisioning profile:
|
|
18
|
+
# APPLE_CERTIFICATE_BASE64: .p12 certificate (base64 encoded)
|
|
19
|
+
# APPLE_CERTIFICATE_PASSWORD: .p12 certificate password
|
|
20
|
+
# APPLE_PROVISIONING_PROFILE_BASE64: .mobileprovision file (base64 encoded)
|
|
21
|
+
# IOS_PROVISIONING_PROFILE_NAME: provisioning profile name
|
|
22
22
|
#
|
|
23
23
|
# App Store Connect API:
|
|
24
|
-
# APP_STORE_CONNECT_API_KEY_ID: API Key ID (10
|
|
25
|
-
# APP_STORE_CONNECT_ISSUER_ID: Issuer ID (UUID
|
|
26
|
-
# APP_STORE_CONNECT_API_KEY_BASE64: AuthKey_XXXXXX.p8
|
|
27
|
-
# IOS_BUNDLE_ID (Secret
|
|
28
|
-
# store_prepare/store_submit
|
|
24
|
+
# APP_STORE_CONNECT_API_KEY_ID: API Key ID (10 characters)
|
|
25
|
+
# APP_STORE_CONNECT_ISSUER_ID: Issuer ID (UUID format)
|
|
26
|
+
# APP_STORE_CONNECT_API_KEY_BASE64: AuthKey_XXXXXX.p8 file (base64 encoded)
|
|
27
|
+
# IOS_BUNDLE_ID (Secret first, otherwise Variable): app bundle ID —
|
|
28
|
+
# required when using store_prepare/store_submit (the Fastfile stops with a clear error if empty)
|
|
29
29
|
#
|
|
30
|
-
#
|
|
31
|
-
# ENV_FILE (
|
|
32
|
-
# SECRETS_XCCONFIG (
|
|
30
|
+
# Environment settings (optional):
|
|
31
|
+
# ENV_FILE (optional): contents of the .env file
|
|
32
|
+
# SECRETS_XCCONFIG (optional): contents of ios/Flutter/Secrets.xcconfig
|
|
33
33
|
#
|
|
34
|
-
#
|
|
34
|
+
# Initial setup
|
|
35
35
|
#
|
|
36
|
-
# 1. GitHub Secrets
|
|
36
|
+
# 1. Configure the GitHub Secrets (see the list above)
|
|
37
37
|
#
|
|
38
|
-
# 2. ios/ExportOptions.plist
|
|
38
|
+
# 2. Fill in the placeholders in ios/ExportOptions.plist (team ID, bundle ID, provisioning profile name) and commit:
|
|
39
39
|
# git add ios/
|
|
40
|
-
# git commit -m "chore: iOS TestFlight
|
|
40
|
+
# git commit -m "chore: add iOS TestFlight deploy settings"
|
|
41
41
|
#
|
|
42
|
-
# 3. {{MAIN_BRANCH}}
|
|
42
|
+
# 3. Push to the {{MAIN_BRANCH}} branch to start a deploy
|
|
43
43
|
|
|
44
44
|
name: PROJECT-iOS-TestFlight-Deploy
|
|
45
45
|
|
|
46
46
|
on:
|
|
47
47
|
push:
|
|
48
48
|
branches: ["{{MAIN_BRANCH}}"]
|
|
49
|
-
# @wizard paths-anchor (
|
|
49
|
+
# @wizard paths-anchor (in a monorepo the installer injects a paths filter here)
|
|
50
50
|
workflow_dispatch:
|
|
51
51
|
inputs:
|
|
52
52
|
deploy_mode:
|
|
53
|
-
description: "
|
|
53
|
+
description: "Deploy mode (store_only=up to TestFlight / store_prepare=right before ASC submission / store_submit=auto-submit for review)"
|
|
54
54
|
required: false
|
|
55
55
|
default: "store_only" # @wizard auto:ios-deploy-mode
|
|
56
56
|
type: choice
|
|
@@ -59,30 +59,30 @@ on:
|
|
|
59
59
|
- store_prepare
|
|
60
60
|
- store_submit
|
|
61
61
|
|
|
62
|
-
#
|
|
62
|
+
# Project settings (edit the values below)
|
|
63
63
|
env:
|
|
64
64
|
FLUTTER_PROJECT_DIR: "." # @wizard auto:flutter-root
|
|
65
|
-
#
|
|
65
|
+
# How env vars are passed (dart-define | dotenv) — set automatically from the value chosen at install
|
|
66
66
|
ENV_MODE: "dart-define" # @wizard auto:flutter-env-mode
|
|
67
|
-
# Flutter SDK
|
|
68
|
-
#
|
|
67
|
+
# Flutter SDK version — leave empty to use the latest stable channel (matches the SDK constraint of a fresh flutter create project).
|
|
68
|
+
# To pin a version, write it like "3.38.9". It must satisfy environment.sdk in pubspec.yaml.
|
|
69
69
|
FLUTTER_VERSION: ""
|
|
70
70
|
XCODE_VERSION: "26.0"
|
|
71
71
|
PROJECT_TYPE: "flutter"
|
|
72
72
|
|
|
73
|
-
#
|
|
74
|
-
#
|
|
73
|
+
# Env file settings
|
|
74
|
+
# Where to create the .env file in dotenv mode (relative to the Flutter root)
|
|
75
75
|
ENV_FILE_PATH: ".env"
|
|
76
76
|
|
|
77
|
-
# TestFlight
|
|
77
|
+
# TestFlight changelog settings
|
|
78
78
|
SKIP_WAITING_FOR_BUILD_PROCESSING: "false"
|
|
79
79
|
|
|
80
|
-
#
|
|
80
|
+
# Deploy mode (store_only | store_prepare | store_submit)
|
|
81
81
|
DEPLOY_MODE: ${{ github.event.inputs.deploy_mode || vars.IOS_DEPLOY_MODE || 'store_only' }} # @wizard fallback:ios-deploy-mode
|
|
82
82
|
|
|
83
83
|
jobs:
|
|
84
84
|
prepare-build:
|
|
85
|
-
name:
|
|
85
|
+
name: Set up environment
|
|
86
86
|
runs-on: macos-26
|
|
87
87
|
defaults:
|
|
88
88
|
run:
|
|
@@ -104,8 +104,8 @@ jobs:
|
|
|
104
104
|
- name: Pull latest changes
|
|
105
105
|
run: git pull origin {{MAIN_BRANCH}}
|
|
106
106
|
|
|
107
|
-
#
|
|
108
|
-
- name:
|
|
107
|
+
# Report every missing setting up front, before importing certificates or building — otherwise the macOS runner builds for a long time and fails at an unrelated step
|
|
108
|
+
- name: Validate deploy settings
|
|
109
109
|
env:
|
|
110
110
|
APPLE_CERTIFICATE_BASE64: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
|
|
111
111
|
APPLE_PROVISIONING_PROFILE_BASE64: ${{ secrets.APPLE_PROVISIONING_PROFILE_BASE64 }}
|
|
@@ -114,6 +114,7 @@ jobs:
|
|
|
114
114
|
APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}
|
|
115
115
|
APP_STORE_CONNECT_API_KEY_BASE64: ${{ secrets.APP_STORE_CONNECT_API_KEY_BASE64 }}
|
|
116
116
|
run: |
|
|
117
|
+
m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
|
|
117
118
|
FAILED=0
|
|
118
119
|
MISSING=""
|
|
119
120
|
for name in APPLE_CERTIFICATE_BASE64 APPLE_PROVISIONING_PROFILE_BASE64 IOS_PROVISIONING_PROFILE_NAME \
|
|
@@ -121,23 +122,23 @@ jobs:
|
|
|
121
122
|
[ -n "${!name}" ] || MISSING="$MISSING $name"
|
|
122
123
|
done
|
|
123
124
|
if [ -n "$MISSING" ]; then
|
|
124
|
-
echo "::error
|
|
125
|
+
echo "::error::$(m ios_testflight.secrets_missing missing="$MISSING")"
|
|
125
126
|
FAILED=1
|
|
126
127
|
fi
|
|
127
128
|
if [ ! -f ios/ExportOptions.plist ]; then
|
|
128
|
-
echo "::error
|
|
129
|
+
echo "::error::$(m ios_testflight.export_options_missing)"
|
|
129
130
|
FAILED=1
|
|
130
131
|
elif grep -Eq '__[A-Z][A-Z0-9_]*__' ios/ExportOptions.plist; then
|
|
131
|
-
echo "::error
|
|
132
|
+
echo "::error::$(m ios_testflight.export_options_placeholders)"
|
|
132
133
|
grep -En '__[A-Z][A-Z0-9_]*__' ios/ExportOptions.plist
|
|
133
134
|
FAILED=1
|
|
134
135
|
fi
|
|
135
136
|
if [ ! -f ios/fastlane/Fastfile ]; then
|
|
136
|
-
echo "::error
|
|
137
|
+
echo "::error::$(m ios_testflight.fastfile_missing_error)"
|
|
137
138
|
FAILED=1
|
|
138
139
|
fi
|
|
139
140
|
[ "$FAILED" -eq 0 ] || exit 1
|
|
140
|
-
|
|
141
|
+
m ios_testflight.preflight_ok
|
|
141
142
|
|
|
142
143
|
- name: Select Xcode version
|
|
143
144
|
run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app/Contents/Developer
|
|
@@ -195,18 +196,20 @@ jobs:
|
|
|
195
196
|
|
|
196
197
|
- name: Install CocoaPods
|
|
197
198
|
run: |
|
|
198
|
-
|
|
199
|
+
m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
|
|
200
|
+
# A default project without plugins has no Podfile — flutter build creates one once a plugin is added
|
|
199
201
|
if [ -f ios/Podfile ]; then
|
|
200
202
|
gem install cocoapods
|
|
201
203
|
(cd ios && pod install)
|
|
202
204
|
else
|
|
203
|
-
|
|
205
|
+
m ios_testflight.podfile_skip
|
|
204
206
|
fi
|
|
205
207
|
|
|
206
|
-
- name:
|
|
208
|
+
- name: Get current version
|
|
207
209
|
id: current_version
|
|
208
|
-
working-directory: ${{ github.workspace }} # version_manager.py
|
|
210
|
+
working-directory: ${{ github.workspace }} # version_manager.py must read version.yml at the repo root
|
|
209
211
|
run: |
|
|
212
|
+
m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
|
|
210
213
|
VERSION=$(python3 .github/scripts/version_manager.py get | tail -n 1)
|
|
211
214
|
BUILD_NUMBER=$(python3 .github/scripts/version_manager.py get-code | tail -n 1)
|
|
212
215
|
|
|
@@ -214,12 +217,13 @@ jobs:
|
|
|
214
217
|
echo "build_number=$BUILD_NUMBER" >> $GITHUB_OUTPUT
|
|
215
218
|
echo "project_type=${{ env.PROJECT_TYPE }}" >> $GITHUB_OUTPUT
|
|
216
219
|
|
|
217
|
-
|
|
220
|
+
m ios_testflight.version_info version="$VERSION" build="$BUILD_NUMBER"
|
|
218
221
|
|
|
219
|
-
- name:
|
|
222
|
+
- name: Generate release notes
|
|
220
223
|
id: release_notes
|
|
221
|
-
working-directory: ${{ github.workspace }} # CHANGELOG.json
|
|
224
|
+
working-directory: ${{ github.workspace }} # CHANGELOG.json, changelog_manager.py and final_release_notes.txt (paired with the upload step) are relative to the repo root
|
|
222
225
|
run: |
|
|
226
|
+
m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
|
|
223
227
|
VERSION="${{ steps.current_version.outputs.version }}"
|
|
224
228
|
|
|
225
229
|
if [ -f "CHANGELOG.json" ]; then
|
|
@@ -230,11 +234,11 @@ jobs:
|
|
|
230
234
|
echo "RELEASE_NOTES_FOUND=true" >> $GITHUB_ENV
|
|
231
235
|
else
|
|
232
236
|
echo "RELEASE_NOTES_FOUND=false" >> $GITHUB_ENV
|
|
233
|
-
|
|
237
|
+
m ios_testflight.default_notes version="$VERSION" > final_release_notes.txt
|
|
234
238
|
fi
|
|
235
239
|
else
|
|
236
240
|
echo "RELEASE_NOTES_FOUND=false" >> $GITHUB_ENV
|
|
237
|
-
|
|
241
|
+
m ios_testflight.default_notes version="$VERSION" > final_release_notes.txt
|
|
238
242
|
fi
|
|
239
243
|
|
|
240
244
|
- name: Upload release notes
|
|
@@ -257,9 +261,9 @@ jobs:
|
|
|
257
261
|
retention-days: 1
|
|
258
262
|
if-no-files-found: error
|
|
259
263
|
|
|
260
|
-
# iOS
|
|
264
|
+
# iOS build (uses xcodebuild directly)
|
|
261
265
|
build-ios:
|
|
262
|
-
name: iOS
|
|
266
|
+
name: Build iOS app
|
|
263
267
|
runs-on: macos-26
|
|
264
268
|
defaults:
|
|
265
269
|
run:
|
|
@@ -281,7 +285,7 @@ jobs:
|
|
|
281
285
|
|
|
282
286
|
- name: Install iOS device platform
|
|
283
287
|
env:
|
|
284
|
-
# xcode-select
|
|
288
|
+
# xcode-select alone does not propagate to subprocesses, so set it explicitly
|
|
285
289
|
DEVELOPER_DIR: /Applications/Xcode_${{ env.XCODE_VERSION }}.app/Contents/Developer
|
|
286
290
|
run: |
|
|
287
291
|
echo "=== iPhoneOS.platform check ==="
|
|
@@ -345,12 +349,13 @@ jobs:
|
|
|
345
349
|
|
|
346
350
|
- name: Install CocoaPods
|
|
347
351
|
run: |
|
|
348
|
-
|
|
352
|
+
m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
|
|
353
|
+
# A default project without plugins has no Podfile — flutter build creates one once a plugin is added
|
|
349
354
|
if [ -f ios/Podfile ]; then
|
|
350
355
|
gem install cocoapods
|
|
351
356
|
(cd ios && pod install)
|
|
352
357
|
else
|
|
353
|
-
|
|
358
|
+
m ios_testflight.podfile_skip
|
|
354
359
|
fi
|
|
355
360
|
|
|
356
361
|
- name: Import Code-Signing Certificates
|
|
@@ -369,21 +374,22 @@ jobs:
|
|
|
369
374
|
|
|
370
375
|
- name: Verify ExportOptions.plist
|
|
371
376
|
run: |
|
|
377
|
+
m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
|
|
372
378
|
cd ios
|
|
373
379
|
if [ ! -f "ExportOptions.plist" ]; then
|
|
374
380
|
exit 1
|
|
375
381
|
fi
|
|
376
|
-
#
|
|
382
|
+
# If the placeholders in the installer-generated template are not filled in, xcodebuild ends with a hard-to-read error
|
|
377
383
|
if grep -Eq '__[A-Z][A-Z0-9_]*__' ExportOptions.plist; then
|
|
378
|
-
|
|
384
|
+
m ios_testflight.plist_placeholders
|
|
379
385
|
grep -En '__[A-Z][A-Z0-9_]*__' ExportOptions.plist
|
|
380
|
-
|
|
386
|
+
m ios_testflight.plist_placeholders_hint
|
|
381
387
|
exit 1
|
|
382
388
|
fi
|
|
383
389
|
|
|
384
390
|
- name: Flutter build (no codesign)
|
|
385
391
|
env:
|
|
386
|
-
# xcode-select
|
|
392
|
+
# xcode-select alone does not propagate to subprocesses, so set it explicitly
|
|
387
393
|
DEVELOPER_DIR: /Applications/Xcode_${{ env.XCODE_VERSION }}.app/Contents/Developer
|
|
388
394
|
run: |
|
|
389
395
|
flutter build ios --release --no-codesign \
|
|
@@ -394,7 +400,7 @@ jobs:
|
|
|
394
400
|
- name: Create Archive
|
|
395
401
|
env:
|
|
396
402
|
IOS_PROVISIONING_PROFILE_NAME: ${{ secrets.IOS_PROVISIONING_PROFILE_NAME }}
|
|
397
|
-
# xcode-select
|
|
403
|
+
# xcode-select alone does not propagate to subprocesses, so set it explicitly
|
|
398
404
|
DEVELOPER_DIR: /Applications/Xcode_${{ env.XCODE_VERSION }}.app/Contents/Developer
|
|
399
405
|
run: |
|
|
400
406
|
cd ios
|
|
@@ -423,9 +429,9 @@ jobs:
|
|
|
423
429
|
retention-days: 1
|
|
424
430
|
if-no-files-found: error
|
|
425
431
|
|
|
426
|
-
# TestFlight
|
|
432
|
+
# TestFlight deploy (uses ios/fastlane/Fastfile)
|
|
427
433
|
deploy-testflight:
|
|
428
|
-
name: TestFlight
|
|
434
|
+
name: Deploy to TestFlight
|
|
429
435
|
runs-on: macos-26
|
|
430
436
|
defaults:
|
|
431
437
|
run:
|
|
@@ -458,21 +464,23 @@ jobs:
|
|
|
458
464
|
|
|
459
465
|
- name: Verify Fastfile exists
|
|
460
466
|
run: |
|
|
467
|
+
m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
|
|
461
468
|
if [ ! -f "ios/fastlane/Fastfile" ]; then
|
|
462
|
-
|
|
463
|
-
|
|
469
|
+
m ios_testflight.fastfile_missing
|
|
470
|
+
m ios_testflight.fastfile_missing_hint
|
|
464
471
|
exit 1
|
|
465
472
|
fi
|
|
466
|
-
|
|
473
|
+
m ios_testflight.fastfile_ok
|
|
467
474
|
|
|
468
475
|
- name: Install Fastlane
|
|
469
476
|
working-directory: ${{ env.FLUTTER_PROJECT_DIR }}/ios
|
|
470
477
|
run: |
|
|
471
|
-
|
|
478
|
+
m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
|
|
479
|
+
# Use the repository's Gemfile as-is if it lists fastlane (committing Gemfile.lock is recommended). Otherwise generate one.
|
|
472
480
|
if [ -f Gemfile ] && grep -Eq "['\"]fastlane['\"]" Gemfile; then
|
|
473
|
-
|
|
481
|
+
m ios_testflight.gemfile_repo
|
|
474
482
|
else
|
|
475
|
-
# multi_json: google-apis transitive
|
|
483
|
+
# multi_json: works around an upstream bug where a google-apis transitive dependency omits it from its gemspec (Gem::LoadError)
|
|
476
484
|
printf 'source "https://rubygems.org"\ngem "fastlane"\ngem "multi_json"\n' > Gemfile
|
|
477
485
|
fi
|
|
478
486
|
bundle install
|
|
@@ -484,24 +492,25 @@ jobs:
|
|
|
484
492
|
APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}
|
|
485
493
|
SKIP_WAITING_FOR_BUILD_PROCESSING: ${{ env.SKIP_WAITING_FOR_BUILD_PROCESSING }}
|
|
486
494
|
run: |
|
|
487
|
-
|
|
495
|
+
m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
|
|
496
|
+
# Find the IPA by absolute path
|
|
488
497
|
IPA_PATH=$(find "$GITHUB_WORKSPACE/${FLUTTER_PROJECT_DIR}/ios/build/ipa" -name "*.ipa" | head -1)
|
|
489
498
|
echo "📦 Found IPA at: $IPA_PATH"
|
|
490
499
|
|
|
491
500
|
if [ ! -f "$IPA_PATH" ]; then
|
|
492
|
-
|
|
501
|
+
m ios_testflight.ipa_missing; ls -la ios/build/ipa/ || true; exit 1
|
|
493
502
|
fi
|
|
494
503
|
|
|
495
|
-
#
|
|
504
|
+
# Prepare release notes (final_release_notes.txt and the truncate script are relative to the repo root — use absolute paths since working-directory is FLUTTER_PROJECT_DIR)
|
|
496
505
|
if [ -f "$GITHUB_WORKSPACE/final_release_notes.txt" ]; then
|
|
497
|
-
# App Store Connect "What to Test"
|
|
506
|
+
# Truncate to the App Store Connect "What to Test" limit (4000 bytes), with a margin (3800 bytes)
|
|
498
507
|
python3 "$GITHUB_WORKSPACE/.github/scripts/truncate_release_notes.py" "$GITHUB_WORKSPACE/final_release_notes.txt" 3800 byte
|
|
499
508
|
RELEASE_NOTES=$(cat "$GITHUB_WORKSPACE/final_release_notes.txt")
|
|
500
509
|
echo "📝 Release Notes:"
|
|
501
510
|
echo "$RELEASE_NOTES"
|
|
502
511
|
else
|
|
503
|
-
RELEASE_NOTES="
|
|
504
|
-
|
|
512
|
+
RELEASE_NOTES="$(m ios_testflight.default_notes version="${{ needs.prepare-build.outputs.version }}")"
|
|
513
|
+
m ios_testflight.default_notes_echo notes="$RELEASE_NOTES"
|
|
505
514
|
fi
|
|
506
515
|
|
|
507
516
|
export APP_STORE_CONNECT_API_KEY_ID="${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}"
|
|
@@ -521,13 +530,15 @@ jobs:
|
|
|
521
530
|
- name: Notify TestFlight Upload Success
|
|
522
531
|
if: success()
|
|
523
532
|
run: |
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
533
|
+
m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
|
|
534
|
+
m ios_testflight.upload_ok
|
|
535
|
+
m ios_testflight.upload_version version="${{ needs.prepare-build.outputs.version }}"
|
|
536
|
+
m ios_testflight.upload_build build="${{ needs.prepare-build.outputs.build_number }}"
|
|
537
|
+
m ios_testflight.upload_commit sha="${{ github.sha }}"
|
|
528
538
|
|
|
529
539
|
- name: Notify on Failure
|
|
530
540
|
if: failure()
|
|
531
541
|
run: |
|
|
532
|
-
|
|
533
|
-
|
|
542
|
+
m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
|
|
543
|
+
m ios_testflight.upload_failed
|
|
544
|
+
m ios_testflight.check_logs
|
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
# project-auto-wizard:managed-workflow
|
|
2
|
-
# Go
|
|
3
|
-
# -
|
|
4
|
-
# -
|
|
5
|
-
# -
|
|
2
|
+
# Go build verification workflow (CI only)
|
|
3
|
+
# - Verifies with go build/vet/test/lint on push/PR to the {{DEVELOP_BRANCH}} branch
|
|
4
|
+
# - Needs no Dockerfile, so it also works for Go projects that are not deployed (CLI tools, libraries, ...)
|
|
5
|
+
# - Uses the go directive version from go.mod automatically (no hardcoded version)
|
|
6
6
|
|
|
7
7
|
name: PROJECT-GO-CI
|
|
8
8
|
|
|
9
9
|
on:
|
|
10
10
|
push:
|
|
11
11
|
branches:
|
|
12
|
-
- "{{DEVELOP_BRANCH}}" # {{DEVELOP_BRANCH}}
|
|
12
|
+
- "{{DEVELOP_BRANCH}}" # build verification on push to the {{DEVELOP_BRANCH}} branch
|
|
13
13
|
pull_request:
|
|
14
14
|
branches:
|
|
15
|
-
- "{{DEVELOP_BRANCH}}" # {{DEVELOP_BRANCH}}
|
|
16
|
-
workflow_dispatch: #
|
|
15
|
+
- "{{DEVELOP_BRANCH}}" # build verification on PRs to the {{DEVELOP_BRANCH}} branch
|
|
16
|
+
workflow_dispatch: # allow manual runs
|
|
17
17
|
|
|
18
18
|
env:
|
|
19
|
-
#
|
|
19
|
+
# Unique project identifier
|
|
20
20
|
PROJECT_NAME: "__PROJECT_NAME__" # @wizard ask:@repo
|
|
21
|
-
#
|
|
21
|
+
# Subdirectory of this project in a monorepo ('.' means always verify)
|
|
22
22
|
PROJECT_PATH: "." # @wizard auto:project-path
|
|
23
23
|
|
|
24
24
|
jobs:
|
|
25
|
-
#
|
|
25
|
+
# Change detection (in a monorepo, checks whether this project's path changed)
|
|
26
26
|
changes:
|
|
27
|
-
name:
|
|
27
|
+
name: Detect changes
|
|
28
28
|
runs-on: ubuntu-latest
|
|
29
29
|
permissions:
|
|
30
30
|
contents: read
|
|
@@ -35,81 +35,92 @@ jobs:
|
|
|
35
35
|
- name: Checkout repository
|
|
36
36
|
uses: actions/checkout@v7
|
|
37
37
|
|
|
38
|
-
- name:
|
|
38
|
+
- name: Check whether the project path changed
|
|
39
39
|
id: filter
|
|
40
40
|
if: ${{ github.event_name != 'workflow_dispatch' }}
|
|
41
41
|
uses: dorny/paths-filter@v4
|
|
42
42
|
with:
|
|
43
|
-
# push
|
|
44
|
-
#
|
|
43
|
+
# A push only looks at this push's range (against the previous commit, 'before'). Left empty it would be the cumulative diff against the default branch.
|
|
44
|
+
# The first push of a new branch (before is 0) and PRs get an empty value -> default behavior (against the default branch / PR base)
|
|
45
45
|
base: ${{ github.event_name == 'push' && github.event.before != '0000000000000000000000000000000000000000' && github.event.before || '' }}
|
|
46
46
|
filters: |
|
|
47
47
|
project:
|
|
48
48
|
- '${{ env.PROJECT_PATH == '.' && '**' || format('{0}/**', env.PROJECT_PATH) }}'
|
|
49
49
|
|
|
50
|
-
# Job:
|
|
50
|
+
# Job: build verification
|
|
51
51
|
build-check:
|
|
52
|
-
name: Go
|
|
52
|
+
name: Go build verification
|
|
53
53
|
runs-on: ubuntu-latest
|
|
54
54
|
needs: changes
|
|
55
55
|
if: ${{ github.event_name == 'workflow_dispatch' || needs.changes.outputs.project == 'true' }}
|
|
56
|
-
#
|
|
56
|
+
# In a monorepo (--paths), build inside that subfolder
|
|
57
57
|
defaults:
|
|
58
58
|
run:
|
|
59
59
|
working-directory: ${{ env.PROJECT_PATH }}
|
|
60
60
|
|
|
61
61
|
steps:
|
|
62
|
-
- name:
|
|
62
|
+
- name: Checkout repository
|
|
63
63
|
uses: actions/checkout@v7
|
|
64
64
|
|
|
65
|
-
#
|
|
66
|
-
- name: Go
|
|
65
|
+
# Automatically use the go directive version from go.mod
|
|
66
|
+
- name: Set up Go
|
|
67
67
|
uses: actions/setup-go@v7
|
|
68
68
|
with:
|
|
69
69
|
go-version-file: ${{ env.PROJECT_PATH }}/go.mod
|
|
70
70
|
cache-dependency-path: ${{ env.PROJECT_PATH }}/go.sum
|
|
71
71
|
cache: true
|
|
72
72
|
|
|
73
|
-
- name: go build
|
|
73
|
+
- name: Verify go build
|
|
74
74
|
run: go build ./...
|
|
75
75
|
|
|
76
|
-
- name: go vet
|
|
76
|
+
- name: Verify go vet
|
|
77
77
|
run: go vet ./...
|
|
78
78
|
|
|
79
|
-
- name: go test
|
|
79
|
+
- name: Run go test
|
|
80
80
|
run: go test ./...
|
|
81
81
|
|
|
82
|
-
# golangci-lint v8
|
|
83
|
-
#
|
|
82
|
+
# golangci-lint-action v8 requires golangci-lint v2; if .golangci.yml is in the v1 format
|
|
83
|
+
# the project has to adjust it. version: latest picks up the newest v2 patch automatically
|
|
84
84
|
- name: golangci-lint
|
|
85
85
|
uses: golangci/golangci-lint-action@v8
|
|
86
86
|
with:
|
|
87
87
|
version: latest
|
|
88
88
|
working-directory: ${{ env.PROJECT_PATH }}
|
|
89
89
|
|
|
90
|
-
- name:
|
|
90
|
+
- name: Build verification complete
|
|
91
91
|
run: |
|
|
92
|
-
|
|
92
|
+
m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
|
|
93
|
+
m cibuild.go_done
|
|
93
94
|
echo ""
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
m cibuild.info_title
|
|
96
|
+
m cibuild.info_project project="${{ env.PROJECT_NAME }}"
|
|
97
|
+
m cibuild.info_branch branch="${{ github.ref_name }}"
|
|
98
|
+
m cibuild.info_commit sha="${{ github.sha }}"
|
|
99
|
+
m cibuild.info_time time="$(date '+%Y-%m-%d %H:%M:%S')"
|
|
99
100
|
|
|
100
|
-
# Job: CI Gate (
|
|
101
|
+
# Job: CI Gate (the single job to register as a required check)
|
|
101
102
|
ci-gate:
|
|
102
103
|
name: CI Gate
|
|
103
104
|
if: ${{ always() }}
|
|
104
105
|
needs: [changes, build-check]
|
|
105
106
|
runs-on: ubuntu-latest
|
|
106
107
|
steps:
|
|
107
|
-
|
|
108
|
+
# Only the message catalog is needed here, so check out just that
|
|
109
|
+
- name: Checkout message catalog
|
|
110
|
+
uses: actions/checkout@v7
|
|
111
|
+
with:
|
|
112
|
+
sparse-checkout: |
|
|
113
|
+
.github/scripts/messages.py
|
|
114
|
+
version.yml
|
|
115
|
+
sparse-checkout-cone-mode: false
|
|
116
|
+
|
|
117
|
+
- name: Aggregate results
|
|
108
118
|
env:
|
|
109
119
|
RESULTS: ${{ toJSON(needs.*.result) }}
|
|
110
120
|
run: |
|
|
111
|
-
|
|
121
|
+
m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
|
|
122
|
+
m cibuild.gate_results results="$RESULTS"
|
|
112
123
|
if echo "$RESULTS" | grep -Eq '"(failure|cancelled)"'; then
|
|
113
|
-
|
|
124
|
+
m cibuild.gate_failed
|
|
114
125
|
exit 1
|
|
115
126
|
fi
|