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.
- 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,42 +1,42 @@
|
|
|
1
1
|
# project-auto-wizard:managed-workflow
|
|
2
|
-
# Flutter Android
|
|
2
|
+
# Flutter Android test APK build workflow
|
|
3
3
|
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
4
|
+
# Run this workflow manually from a feature branch
|
|
5
|
+
# to build a test Android APK.
|
|
6
6
|
#
|
|
7
|
-
#
|
|
8
|
-
# - workflow_dispatch
|
|
9
|
-
# -
|
|
10
|
-
# -
|
|
11
|
-
# - GitHub API
|
|
12
|
-
# - APK
|
|
13
|
-
# -
|
|
14
|
-
# -
|
|
15
|
-
# - Firebase App Distribution
|
|
7
|
+
# Highlights:
|
|
8
|
+
# - Runs manually via workflow_dispatch or is triggered by repository_dispatch
|
|
9
|
+
# - The version is read dynamically from version.yml (same as production; builds are told apart by build number)
|
|
10
|
+
# - Extracts the issue number from the branch name automatically (YYYYMMDD_#issue-number_title format)
|
|
11
|
+
# - Fetches the issue through the GitHub API and includes it in the build info
|
|
12
|
+
# - Only produces the APK file (no Play Store deploy)
|
|
13
|
+
# - Uploaded as an artifact you can download (up to 500MB per artifact)
|
|
14
|
+
# - The artifact name includes the branch name so builds are easy to tell apart
|
|
15
|
+
# - Firebase App Distribution integration (when the FIREBASE_SERVICE_ACCOUNT_JSON_BASE64 secret exists)
|
|
16
16
|
#
|
|
17
|
-
#
|
|
18
|
-
# 1.
|
|
19
|
-
# 2.
|
|
20
|
-
# 3. "Run workflow"
|
|
21
|
-
# 4.
|
|
17
|
+
# Usage:
|
|
18
|
+
# 1. Check out a feature branch
|
|
19
|
+
# 2. Select this workflow in GitHub Actions
|
|
20
|
+
# 3. Click the "Run workflow" button
|
|
21
|
+
# 4. When the build finishes, download the APK from the artifacts
|
|
22
22
|
#
|
|
23
|
-
# GitHub Secrets (
|
|
23
|
+
# GitHub Secrets (all optional — the test APK builds even with none of them)
|
|
24
24
|
#
|
|
25
|
-
# Release Keystore (Play Store
|
|
26
|
-
# RELEASE_KEYSTORE_BASE64 (
|
|
27
|
-
# RELEASE_KEYSTORE_PASSWORD (
|
|
28
|
-
# RELEASE_KEY_ALIAS (
|
|
29
|
-
# RELEASE_KEY_PASSWORD (
|
|
25
|
+
# Release Keystore (same as the Play Store deploy; if missing, a warning is shown and the debug key is used):
|
|
26
|
+
# RELEASE_KEYSTORE_BASE64 (optional): release keystore file (base64)
|
|
27
|
+
# RELEASE_KEYSTORE_PASSWORD (optional): keystore password
|
|
28
|
+
# RELEASE_KEY_ALIAS (optional): key alias
|
|
29
|
+
# RELEASE_KEY_PASSWORD (optional): key password
|
|
30
30
|
#
|
|
31
|
-
#
|
|
32
|
-
# ENV_FILE (
|
|
33
|
-
# GOOGLE_SERVICES_JSON (
|
|
31
|
+
# Environment settings (optional):
|
|
32
|
+
# ENV_FILE (optional): contents of the .env file
|
|
33
|
+
# GOOGLE_SERVICES_JSON (optional): contents of google-services.json (when using Firebase)
|
|
34
34
|
#
|
|
35
|
-
# Firebase App Distribution (
|
|
36
|
-
# FIREBASE_SERVICE_ACCOUNT_JSON_BASE64 (
|
|
35
|
+
# Firebase App Distribution (optional):
|
|
36
|
+
# FIREBASE_SERVICE_ACCOUNT_JSON_BASE64 (optional): Firebase service account JSON (base64)
|
|
37
37
|
#
|
|
38
|
-
#
|
|
39
|
-
# Firebase
|
|
38
|
+
# Note: register the Secrets above under the repository Settings → Secrets and variables → Actions.
|
|
39
|
+
# To use the Firebase upload, also edit FIREBASE_APP_ID and FIREBASE_TESTER_GROUP in the env below.
|
|
40
40
|
|
|
41
41
|
name: PROJECT-Flutter-Android-Test-APK
|
|
42
42
|
|
|
@@ -49,30 +49,30 @@ on:
|
|
|
49
49
|
repository_dispatch:
|
|
50
50
|
types: [build-android-app]
|
|
51
51
|
|
|
52
|
-
#
|
|
52
|
+
# Declare the needed permissions explicitly so progress comments work even when the repository default is read-only
|
|
53
53
|
permissions:
|
|
54
54
|
contents: read
|
|
55
55
|
issues: write
|
|
56
56
|
pull-requests: write
|
|
57
57
|
|
|
58
|
-
#
|
|
58
|
+
# Project settings (edit the values below)
|
|
59
59
|
env:
|
|
60
|
-
# Flutter SDK
|
|
61
|
-
#
|
|
60
|
+
# Flutter SDK version — leave empty to use the latest stable channel (matches the SDK constraint of a fresh flutter create project).
|
|
61
|
+
# To pin a version, write it like "3.38.9". It must satisfy environment.sdk in pubspec.yaml.
|
|
62
62
|
FLUTTER_VERSION: ""
|
|
63
63
|
JAVA_VERSION: "__JAVA_VERSION__" # @wizard ask:17
|
|
64
|
-
# Flutter
|
|
64
|
+
# Flutter root path (relative to the repo root). "." for a single repo, "app" etc. for a monorepo — set automatically at install
|
|
65
65
|
FLUTTER_PROJECT_DIR: "." # @wizard auto:flutter-root
|
|
66
|
-
#
|
|
66
|
+
# How env vars are passed (dart-define | dotenv) — set automatically from the value chosen at install
|
|
67
67
|
ENV_MODE: "dart-define" # @wizard auto:flutter-env-mode
|
|
68
|
-
#
|
|
68
|
+
# Where to create .env in dotenv mode (relative to the Flutter root)
|
|
69
69
|
ENV_FILE_PATH: ".env"
|
|
70
70
|
FIREBASE_APP_ID: "{FIREBASE_APP_ID}"
|
|
71
71
|
FIREBASE_TESTER_GROUP: "{TESTER_GROUP}"
|
|
72
72
|
|
|
73
73
|
jobs:
|
|
74
74
|
prepare-test-build:
|
|
75
|
-
name:
|
|
75
|
+
name: Prepare test build
|
|
76
76
|
runs-on: ubuntu-latest
|
|
77
77
|
|
|
78
78
|
outputs:
|
|
@@ -89,19 +89,41 @@ jobs:
|
|
|
89
89
|
firebase_available: ${{ steps.firebase_check.outputs.available }}
|
|
90
90
|
|
|
91
91
|
steps:
|
|
92
|
-
|
|
92
|
+
# Fetch the message catalog from the triggering ref first — the feature branch being built may predate it
|
|
93
|
+
- name: Checkout messages
|
|
94
|
+
uses: actions/checkout@v7
|
|
95
|
+
with:
|
|
96
|
+
path: .paw-msg
|
|
97
|
+
sparse-checkout: |
|
|
98
|
+
.github/scripts/messages.py
|
|
99
|
+
version.yml
|
|
100
|
+
sparse-checkout-cone-mode: false
|
|
101
|
+
|
|
102
|
+
- name: Load messages
|
|
103
|
+
working-directory: ${{ github.workspace }}
|
|
104
|
+
run: |
|
|
105
|
+
cp .paw-msg/.github/scripts/messages.py "$RUNNER_TEMP/paw_messages.py"
|
|
106
|
+
LANG_CODE=$(cd .paw-msg && python3 "$RUNNER_TEMP/paw_messages.py" lang)
|
|
107
|
+
rm -rf .paw-msg
|
|
108
|
+
echo "PROJECT_AUTO_WIZARD_LANG=$LANG_CODE" >> "$GITHUB_ENV"
|
|
109
|
+
echo "PAW_MESSAGES_PY=$RUNNER_TEMP/paw_messages.py" >> "$GITHUB_ENV"
|
|
110
|
+
echo "PAW_MSG=$(PROJECT_AUTO_WIZARD_LANG=$LANG_CODE python3 "$RUNNER_TEMP/paw_messages.py" dump apk_test.)" >> "$GITHUB_ENV"
|
|
111
|
+
|
|
112
|
+
- name: Verify the branch exists up front
|
|
93
113
|
id: verify_branch
|
|
94
114
|
if: github.event_name == 'repository_dispatch'
|
|
95
115
|
uses: actions/github-script@v9
|
|
96
116
|
with:
|
|
97
117
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
98
118
|
script: |
|
|
119
|
+
const M = JSON.parse(process.env.PAW_MSG);
|
|
120
|
+
const msg = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
99
121
|
const branchName = '${{ github.event.client_payload.branch_name }}';
|
|
100
122
|
const prNumber = '${{ github.event.client_payload.pr_number }}';
|
|
101
123
|
const runId = '${{ github.run_id }}';
|
|
102
124
|
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`;
|
|
103
125
|
|
|
104
|
-
console.log(
|
|
126
|
+
console.log(msg('apk_test.branch_check_log', { branch: branchName }));
|
|
105
127
|
|
|
106
128
|
try {
|
|
107
129
|
await github.rest.repos.getBranch({
|
|
@@ -109,26 +131,26 @@ jobs:
|
|
|
109
131
|
repo: context.repo.repo,
|
|
110
132
|
branch: branchName
|
|
111
133
|
});
|
|
112
|
-
console.log(
|
|
134
|
+
console.log(msg('apk_test.branch_exists_log', { branch: branchName }));
|
|
113
135
|
} catch (error) {
|
|
114
136
|
if (error.status === 404) {
|
|
115
|
-
console.log(
|
|
137
|
+
console.log(msg('apk_test.branch_not_found_log', { branch: branchName }));
|
|
116
138
|
|
|
117
|
-
//
|
|
139
|
+
// Post an error comment
|
|
118
140
|
const body = [
|
|
119
|
-
'
|
|
141
|
+
msg('apk_test.branch_missing_title'),
|
|
120
142
|
'',
|
|
121
|
-
'
|
|
143
|
+
msg('apk_test.kv_head'),
|
|
122
144
|
'|------|-----|',
|
|
123
|
-
|
|
124
|
-
|
|
145
|
+
msg('apk_test.row_requested_branch', { branch: branchName }),
|
|
146
|
+
msg('apk_test.row_issue_pr', { number: prNumber }),
|
|
125
147
|
'',
|
|
126
|
-
'
|
|
127
|
-
'
|
|
128
|
-
'
|
|
129
|
-
'
|
|
148
|
+
msg('apk_test.hint_title'),
|
|
149
|
+
msg('apk_test.hint_pushed'),
|
|
150
|
+
msg('apk_test.hint_helper_branch'),
|
|
151
|
+
msg('apk_test.hint_typo'),
|
|
130
152
|
'',
|
|
131
|
-
|
|
153
|
+
msg('apk_test.workflow_log_link', { url: runUrl })
|
|
132
154
|
].join('\n');
|
|
133
155
|
|
|
134
156
|
await github.rest.issues.createComment({
|
|
@@ -138,9 +160,9 @@ jobs:
|
|
|
138
160
|
body: body
|
|
139
161
|
});
|
|
140
162
|
|
|
141
|
-
core.setFailed(
|
|
163
|
+
core.setFailed(msg('apk_test.branch_not_found_fail', { branch: branchName }));
|
|
142
164
|
} else {
|
|
143
|
-
core.setFailed(
|
|
165
|
+
core.setFailed(msg('apk_test.branch_check_error_fail', { error: error.message }));
|
|
144
166
|
}
|
|
145
167
|
}
|
|
146
168
|
|
|
@@ -149,21 +171,25 @@ jobs:
|
|
|
149
171
|
env:
|
|
150
172
|
FIREBASE_SECRET: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_JSON_BASE64 }}
|
|
151
173
|
run: |
|
|
174
|
+
m() { python3 "$PAW_MESSAGES_PY" get "$@"; }
|
|
152
175
|
if [ -n "$FIREBASE_SECRET" ]; then
|
|
153
176
|
echo "available=true" >> $GITHUB_OUTPUT
|
|
154
|
-
|
|
177
|
+
m apk_test.firebase_detected
|
|
155
178
|
else
|
|
156
179
|
echo "available=false" >> $GITHUB_OUTPUT
|
|
157
|
-
|
|
180
|
+
m apk_test.firebase_missing
|
|
158
181
|
fi
|
|
159
182
|
|
|
160
|
-
- name:
|
|
183
|
+
- name: Create the progress comment
|
|
161
184
|
id: progress_comment
|
|
162
185
|
if: github.event_name == 'repository_dispatch' && github.event.client_payload.pr_number != ''
|
|
163
186
|
uses: actions/github-script@v9
|
|
164
187
|
with:
|
|
165
188
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
166
189
|
script: |
|
|
190
|
+
const M = JSON.parse(process.env.PAW_MSG);
|
|
191
|
+
const msg = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
192
|
+
const row = (name, status, elapsed = '-') => `| ${msg('apk_test.step_' + name)} | ${msg('apk_test.st_' + status)} | ${elapsed} |`;
|
|
167
193
|
const prNumber = parseInt('${{ github.event.client_payload.pr_number }}');
|
|
168
194
|
const runId = '${{ github.run_id }}';
|
|
169
195
|
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`;
|
|
@@ -171,22 +197,22 @@ jobs:
|
|
|
171
197
|
const firebaseAvailable = '${{ steps.firebase_check.outputs.available }}' === 'true';
|
|
172
198
|
|
|
173
199
|
const rows = [
|
|
174
|
-
'
|
|
175
|
-
'
|
|
176
|
-
'
|
|
200
|
+
row('prepare', 'running'),
|
|
201
|
+
row('build', 'waiting'),
|
|
202
|
+
row('upload', 'waiting'),
|
|
177
203
|
];
|
|
178
204
|
if (firebaseAvailable) {
|
|
179
|
-
rows.push('
|
|
205
|
+
rows.push(row('firebase', 'waiting'));
|
|
180
206
|
}
|
|
181
207
|
|
|
182
208
|
const body = [
|
|
183
|
-
'
|
|
209
|
+
msg('apk_test.title_running'),
|
|
184
210
|
'',
|
|
185
|
-
'
|
|
211
|
+
msg('apk_test.table_header'),
|
|
186
212
|
'|------|------|----------|',
|
|
187
213
|
...rows,
|
|
188
214
|
'',
|
|
189
|
-
|
|
215
|
+
msg('apk_test.live_log', { url: runUrl })
|
|
190
216
|
].join('\n');
|
|
191
217
|
|
|
192
218
|
const { data: comment } = await github.rest.issues.createComment({
|
|
@@ -196,7 +222,7 @@ jobs:
|
|
|
196
222
|
body: body
|
|
197
223
|
});
|
|
198
224
|
|
|
199
|
-
console.log(
|
|
225
|
+
console.log(msg('apk_test.log_progress_created', { id: comment.id }));
|
|
200
226
|
core.setOutput('comment_id', comment.id.toString());
|
|
201
227
|
core.setOutput('start_time', startTime.toString());
|
|
202
228
|
|
|
@@ -208,59 +234,63 @@ jobs:
|
|
|
208
234
|
|
|
209
235
|
- name: Pull latest changes
|
|
210
236
|
run: |
|
|
237
|
+
m() { python3 "$PAW_MESSAGES_PY" get "$@"; }
|
|
211
238
|
BRANCH_NAME="${{ github.event_name == 'repository_dispatch' && github.event.client_payload.branch_name || github.ref_name }}"
|
|
212
|
-
|
|
213
|
-
git pull origin "$BRANCH_NAME" ||
|
|
239
|
+
m apk_test.pull_branch branch="$BRANCH_NAME"
|
|
240
|
+
git pull origin "$BRANCH_NAME" || m apk_test.pull_failed
|
|
214
241
|
|
|
215
|
-
- name:
|
|
242
|
+
- name: Extract issue info from the branch name
|
|
216
243
|
id: issue_info
|
|
217
244
|
run: |
|
|
218
|
-
|
|
245
|
+
m() { python3 "$PAW_MESSAGES_PY" get "$@"; }
|
|
246
|
+
# For repository_dispatch, take the branch name from client_payload
|
|
219
247
|
if [ "${{ github.event_name }}" == "repository_dispatch" ]; then
|
|
220
248
|
BRANCH_NAME="${{ github.event.client_payload.branch_name }}"
|
|
221
249
|
ISSUE_NUMBER="${{ github.event.client_payload.issue_number }}"
|
|
222
250
|
else
|
|
223
251
|
BRANCH_NAME="${{ github.ref_name }}"
|
|
224
|
-
#
|
|
252
|
+
# Extract the issue number from the branch name (`<date>_#<number>_...` format)
|
|
225
253
|
ISSUE_NUMBER=$(echo "$BRANCH_NAME" | sed -n 's/.*#\([0-9]*\).*/\1/p')
|
|
226
254
|
fi
|
|
227
255
|
|
|
228
|
-
|
|
256
|
+
m apk_test.branch_name_log branch="$BRANCH_NAME"
|
|
229
257
|
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT
|
|
230
258
|
|
|
231
259
|
if [ -z "$ISSUE_NUMBER" ]; then
|
|
232
|
-
|
|
260
|
+
m apk_test.issue_number_missing
|
|
233
261
|
echo "issue_url=" >> $GITHUB_OUTPUT
|
|
234
262
|
echo "issue_title=" >> $GITHUB_OUTPUT
|
|
235
263
|
echo "issue_number=" >> $GITHUB_OUTPUT
|
|
236
264
|
else
|
|
237
|
-
|
|
265
|
+
m apk_test.issue_number_extracted number="$ISSUE_NUMBER"
|
|
238
266
|
ISSUE_URL="https://github.com/${{ github.repository }}/issues/$ISSUE_NUMBER"
|
|
239
267
|
echo "issue_url=$ISSUE_URL" >> $GITHUB_OUTPUT
|
|
240
268
|
echo "issue_number=$ISSUE_NUMBER" >> $GITHUB_OUTPUT
|
|
241
269
|
|
|
242
|
-
#
|
|
243
|
-
|
|
270
|
+
# Fetch the issue info through the GitHub API
|
|
271
|
+
m apk_test.issue_fetching
|
|
244
272
|
ISSUE_RESPONSE=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
|
245
273
|
"https://api.github.com/repos/${{ github.repository }}/issues/$ISSUE_NUMBER")
|
|
246
274
|
|
|
247
|
-
|
|
275
|
+
NO_ISSUE_INFO="$(m apk_test.issue_title_default)"
|
|
276
|
+
ISSUE_TITLE=$(echo "$ISSUE_RESPONSE" | jq -r --arg d "$NO_ISSUE_INFO" '.title // $d')
|
|
248
277
|
ISSUE_STATE=$(echo "$ISSUE_RESPONSE" | jq -r '.state // "unknown"')
|
|
249
278
|
|
|
250
|
-
if [ "$ISSUE_TITLE" = "null" ] || [ "$ISSUE_TITLE" = "
|
|
251
|
-
|
|
279
|
+
if [ "$ISSUE_TITLE" = "null" ] || [ "$ISSUE_TITLE" = "$NO_ISSUE_INFO" ]; then
|
|
280
|
+
m apk_test.issue_not_found number="$ISSUE_NUMBER"
|
|
252
281
|
echo "issue_title=" >> $GITHUB_OUTPUT
|
|
253
282
|
else
|
|
254
|
-
|
|
255
|
-
|
|
283
|
+
m apk_test.issue_title_log title="$ISSUE_TITLE"
|
|
284
|
+
m apk_test.issue_state_log state="$ISSUE_STATE"
|
|
256
285
|
echo "issue_title=$ISSUE_TITLE" >> $GITHUB_OUTPUT
|
|
257
286
|
fi
|
|
258
287
|
fi
|
|
259
288
|
|
|
260
|
-
- name:
|
|
289
|
+
- name: Generate build info
|
|
261
290
|
id: build_info
|
|
262
291
|
run: |
|
|
263
|
-
|
|
292
|
+
m() { python3 "$PAW_MESSAGES_PY" get "$@"; }
|
|
293
|
+
# Get the version through version_manager.py (same approach as the production workflow)
|
|
264
294
|
VERSION=$(python3 .github/scripts/version_manager.py get | tail -n 1)
|
|
265
295
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
266
296
|
|
|
@@ -268,18 +298,18 @@ jobs:
|
|
|
268
298
|
COMMIT_SHORT=$(echo "$COMMIT_SHA" | cut -c1-7)
|
|
269
299
|
BUILD_DATE=$(date '+%Y-%m-%d %H:%M:%S')
|
|
270
300
|
|
|
271
|
-
# repository_dispatch
|
|
301
|
+
# For repository_dispatch events, use the PR number as the build number
|
|
272
302
|
if [ "${{ github.event_name }}" == "repository_dispatch" ]; then
|
|
273
303
|
BUILD_NUMBER="${{ github.event.client_payload.build_number }}"
|
|
274
304
|
PR_NUMBER="${{ github.event.client_payload.pr_number }}"
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
305
|
+
m apk_test.event_dispatch
|
|
306
|
+
m apk_test.event_pr_number pr="$PR_NUMBER"
|
|
307
|
+
m apk_test.event_build_number_pr build="$BUILD_NUMBER"
|
|
278
308
|
else
|
|
279
309
|
BUILD_NUMBER="${{ github.run_number }}"
|
|
280
310
|
PR_NUMBER=""
|
|
281
|
-
|
|
282
|
-
|
|
311
|
+
m apk_test.event_workflow_dispatch
|
|
312
|
+
m apk_test.event_build_number_default build="$BUILD_NUMBER"
|
|
283
313
|
fi
|
|
284
314
|
|
|
285
315
|
echo "commit_hash=$COMMIT_SHORT" >> $GITHUB_OUTPUT
|
|
@@ -287,16 +317,16 @@ jobs:
|
|
|
287
317
|
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
|
|
288
318
|
echo "build_date=$BUILD_DATE" >> $GITHUB_OUTPUT
|
|
289
319
|
|
|
290
|
-
|
|
291
|
-
|
|
320
|
+
m apk_test.build_info_header
|
|
321
|
+
m apk_test.build_info_build build="$BUILD_NUMBER"
|
|
292
322
|
if [ -n "$PR_NUMBER" ]; then
|
|
293
|
-
|
|
323
|
+
m apk_test.build_info_pr pr="$PR_NUMBER"
|
|
294
324
|
fi
|
|
295
|
-
|
|
296
|
-
|
|
325
|
+
m apk_test.build_info_commit commit="$COMMIT_SHORT"
|
|
326
|
+
m apk_test.build_info_date date="$BUILD_DATE"
|
|
297
327
|
|
|
298
328
|
build-android-test:
|
|
299
|
-
name: Android
|
|
329
|
+
name: Build Android test APK
|
|
300
330
|
runs-on: ubuntu-latest
|
|
301
331
|
needs: prepare-test-build
|
|
302
332
|
defaults:
|
|
@@ -304,6 +334,26 @@ jobs:
|
|
|
304
334
|
working-directory: ${{ env.FLUTTER_PROJECT_DIR }}
|
|
305
335
|
|
|
306
336
|
steps:
|
|
337
|
+
# Fetch the message catalog from the triggering ref first — the feature branch being built may predate it
|
|
338
|
+
- name: Checkout messages
|
|
339
|
+
uses: actions/checkout@v7
|
|
340
|
+
with:
|
|
341
|
+
path: .paw-msg
|
|
342
|
+
sparse-checkout: |
|
|
343
|
+
.github/scripts/messages.py
|
|
344
|
+
version.yml
|
|
345
|
+
sparse-checkout-cone-mode: false
|
|
346
|
+
|
|
347
|
+
- name: Load messages
|
|
348
|
+
working-directory: ${{ github.workspace }}
|
|
349
|
+
run: |
|
|
350
|
+
cp .paw-msg/.github/scripts/messages.py "$RUNNER_TEMP/paw_messages.py"
|
|
351
|
+
LANG_CODE=$(cd .paw-msg && python3 "$RUNNER_TEMP/paw_messages.py" lang)
|
|
352
|
+
rm -rf .paw-msg
|
|
353
|
+
echo "PROJECT_AUTO_WIZARD_LANG=$LANG_CODE" >> "$GITHUB_ENV"
|
|
354
|
+
echo "PAW_MESSAGES_PY=$RUNNER_TEMP/paw_messages.py" >> "$GITHUB_ENV"
|
|
355
|
+
echo "PAW_MSG=$(PROJECT_AUTO_WIZARD_LANG=$LANG_CODE python3 "$RUNNER_TEMP/paw_messages.py" dump apk_test.)" >> "$GITHUB_ENV"
|
|
356
|
+
|
|
307
357
|
- name: Checkout repository
|
|
308
358
|
uses: actions/checkout@v7
|
|
309
359
|
with:
|
|
@@ -313,7 +363,7 @@ jobs:
|
|
|
313
363
|
- name: Pull latest changes
|
|
314
364
|
run: git pull origin ${{ github.event_name == 'repository_dispatch' && github.event.client_payload.branch_name || github.ref_name }}
|
|
315
365
|
|
|
316
|
-
#
|
|
366
|
+
# Prepare env vars — a .env file when ENV_MODE=dotenv, otherwise a temp file outside the project (--dart-define-from-file)
|
|
317
367
|
- name: Prepare env file
|
|
318
368
|
env:
|
|
319
369
|
ENV_CONTENT: ${{ secrets.ENV_FILE || secrets.ENV }}
|
|
@@ -336,28 +386,29 @@ jobs:
|
|
|
336
386
|
RELEASE_KEY_ALIAS: ${{ secrets.RELEASE_KEY_ALIAS }}
|
|
337
387
|
RELEASE_KEY_PASSWORD: ${{ secrets.RELEASE_KEY_PASSWORD }}
|
|
338
388
|
run: |
|
|
339
|
-
|
|
340
|
-
#
|
|
389
|
+
m() { python3 "$PAW_MESSAGES_PY" get "$@"; }
|
|
390
|
+
# A test build must work without any setup — when a Secret is empty, keystore and key.properties are not created
|
|
391
|
+
# and the build uses the project's default signing (flutter create defaults to the debug key even for release). The key in use is logged.
|
|
341
392
|
MISSING=""
|
|
342
393
|
for name in RELEASE_KEYSTORE_BASE64 RELEASE_KEYSTORE_PASSWORD RELEASE_KEY_ALIAS RELEASE_KEY_PASSWORD; do
|
|
343
394
|
[ -n "${!name}" ] || MISSING="$MISSING $name"
|
|
344
395
|
done
|
|
345
396
|
if [ -n "$MISSING" ]; then
|
|
346
|
-
echo "::warning
|
|
397
|
+
echo "::warning::$(m apk_test.sign_debug_warning missing="$MISSING")"
|
|
347
398
|
echo "mode=debug" >> "$GITHUB_OUTPUT"
|
|
348
399
|
exit 0
|
|
349
400
|
fi
|
|
350
|
-
#
|
|
401
|
+
# A broken keystore with a value present is not skipped silently — fail here
|
|
351
402
|
mkdir -p android/keystore
|
|
352
403
|
printf '%s' "$RELEASE_KEYSTORE_BASE64" | base64 -d > android/keystore/key.jks
|
|
353
404
|
if [ ! -s android/keystore/key.jks ]; then
|
|
354
|
-
echo "::error
|
|
405
|
+
echo "::error::$(m apk_test.sign_keystore_empty)"
|
|
355
406
|
exit 1
|
|
356
407
|
fi
|
|
357
|
-
#
|
|
408
|
+
# Stop here if the password/alias does not match the keystore (instead of a long error in the gradle signing step)
|
|
358
409
|
keytool -list -keystore android/keystore/key.jks -storepass "$RELEASE_KEYSTORE_PASSWORD" -alias "$RELEASE_KEY_ALIAS" > /dev/null
|
|
359
410
|
echo "mode=release" >> "$GITHUB_OUTPUT"
|
|
360
|
-
|
|
411
|
+
m apk_test.sign_release_ok
|
|
361
412
|
ls -la android/keystore/
|
|
362
413
|
|
|
363
414
|
- name: Create key.properties
|
|
@@ -367,15 +418,16 @@ jobs:
|
|
|
367
418
|
KEY_ALIAS: ${{ secrets.RELEASE_KEY_ALIAS }}
|
|
368
419
|
KEY_PASSWORD: ${{ secrets.RELEASE_KEY_PASSWORD }}
|
|
369
420
|
run: |
|
|
421
|
+
m() { python3 "$PAW_MESSAGES_PY" get "$@"; }
|
|
370
422
|
cat > android/key.properties << EOF
|
|
371
423
|
storeFile=keystore/key.jks
|
|
372
424
|
storePassword=$STORE_PASSWORD
|
|
373
425
|
keyAlias=$KEY_ALIAS
|
|
374
426
|
keyPassword=$KEY_PASSWORD
|
|
375
427
|
EOF
|
|
376
|
-
|
|
428
|
+
m apk_test.key_properties_ok
|
|
377
429
|
|
|
378
|
-
# google-services.json
|
|
430
|
+
# Create google-services.json (optional)
|
|
379
431
|
- name: Create google-services.json
|
|
380
432
|
shell: bash
|
|
381
433
|
env:
|
|
@@ -429,12 +481,13 @@ jobs:
|
|
|
429
481
|
- name: Setup Gradle
|
|
430
482
|
working-directory: ${{ env.FLUTTER_PROJECT_DIR }}/android
|
|
431
483
|
run: |
|
|
432
|
-
|
|
484
|
+
m() { python3 "$PAW_MESSAGES_PY" get "$@"; }
|
|
485
|
+
# The default flutter create .gitignore does not commit gradlew — flutter build creates it when missing
|
|
433
486
|
if [ -f gradlew ]; then
|
|
434
487
|
chmod +x gradlew
|
|
435
488
|
echo "✅ Gradle wrapper permissions set"
|
|
436
489
|
else
|
|
437
|
-
|
|
490
|
+
m apk_test.gradlew_missing
|
|
438
491
|
fi
|
|
439
492
|
|
|
440
493
|
- name: Set up Java
|
|
@@ -448,13 +501,16 @@ jobs:
|
|
|
448
501
|
echo "✅ Java setup completed"
|
|
449
502
|
java -version
|
|
450
503
|
|
|
451
|
-
- name:
|
|
504
|
+
- name: Progress - prepare done
|
|
452
505
|
id: progress_step1
|
|
453
506
|
if: github.event_name == 'repository_dispatch' && needs.prepare-test-build.outputs.progress_comment_id != ''
|
|
454
507
|
uses: actions/github-script@v9
|
|
455
508
|
with:
|
|
456
509
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
457
510
|
script: |
|
|
511
|
+
const M = JSON.parse(process.env.PAW_MSG);
|
|
512
|
+
const msg = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
513
|
+
const row = (name, status, elapsed = '-') => `| ${msg('apk_test.step_' + name)} | ${msg('apk_test.st_' + status)} | ${elapsed} |`;
|
|
458
514
|
const commentId = parseInt('${{ needs.prepare-test-build.outputs.progress_comment_id }}');
|
|
459
515
|
const startTime = parseInt('${{ needs.prepare-test-build.outputs.progress_start_time }}');
|
|
460
516
|
const runId = '${{ github.run_id }}';
|
|
@@ -464,26 +520,26 @@ jobs:
|
|
|
464
520
|
const elapsed = Math.round((now - startTime) / 1000);
|
|
465
521
|
const minutes = Math.floor(elapsed / 60);
|
|
466
522
|
const seconds = elapsed % 60;
|
|
467
|
-
const elapsedStr = minutes > 0 ?
|
|
523
|
+
const elapsedStr = minutes > 0 ? msg('apk_test.elapsed_min_sec', { m: minutes, s: seconds }) : msg('apk_test.elapsed_sec', { s: seconds });
|
|
468
524
|
const firebaseAvailable = '${{ needs.prepare-test-build.outputs.firebase_available }}' === 'true';
|
|
469
525
|
|
|
470
526
|
const rows = [
|
|
471
|
-
|
|
472
|
-
'
|
|
473
|
-
'
|
|
527
|
+
row('prepare', 'done', elapsedStr),
|
|
528
|
+
row('build', 'running'),
|
|
529
|
+
row('upload', 'waiting'),
|
|
474
530
|
];
|
|
475
531
|
if (firebaseAvailable) {
|
|
476
|
-
rows.push('
|
|
532
|
+
rows.push(row('firebase', 'waiting'));
|
|
477
533
|
}
|
|
478
534
|
|
|
479
535
|
const body = [
|
|
480
|
-
'
|
|
536
|
+
msg('apk_test.title_running'),
|
|
481
537
|
'',
|
|
482
|
-
'
|
|
538
|
+
msg('apk_test.table_header'),
|
|
483
539
|
'|------|------|----------|',
|
|
484
540
|
...rows,
|
|
485
541
|
'',
|
|
486
|
-
|
|
542
|
+
msg('apk_test.live_log', { url: runUrl })
|
|
487
543
|
].join('\n');
|
|
488
544
|
|
|
489
545
|
await github.rest.issues.updateComment({
|
|
@@ -493,42 +549,43 @@ jobs:
|
|
|
493
549
|
body: body
|
|
494
550
|
});
|
|
495
551
|
|
|
496
|
-
console.log(
|
|
552
|
+
console.log(msg('apk_test.log_prepare_done', { elapsed: elapsedStr }));
|
|
497
553
|
core.setOutput('elapsed', elapsedStr);
|
|
498
554
|
core.setOutput('end_time', now.toString());
|
|
499
555
|
|
|
500
556
|
- name: Generate APK filename
|
|
501
557
|
id: apk_filename
|
|
502
558
|
run: |
|
|
559
|
+
m() { python3 "$PAW_MESSAGES_PY" get "$@"; }
|
|
503
560
|
REPO_NAME="${{ github.event.repository.name }}"
|
|
504
561
|
COMMIT_SHORT="${{ needs.prepare-test-build.outputs.commit_hash }}"
|
|
505
562
|
BUILD_NUMBER="${{ needs.prepare-test-build.outputs.build_number }}"
|
|
506
563
|
ISSUE_NUMBER="${{ needs.prepare-test-build.outputs.issue_number }}"
|
|
507
564
|
ISSUE_TITLE="${{ needs.prepare-test-build.outputs.issue_title }}"
|
|
508
565
|
|
|
509
|
-
#
|
|
566
|
+
# Clean up the issue title
|
|
510
567
|
CLEAN_TITLE=""
|
|
511
568
|
if [ -n "$ISSUE_TITLE" ]; then
|
|
512
569
|
CLEAN_TITLE="$ISSUE_TITLE"
|
|
513
|
-
# 1.
|
|
570
|
+
# 1. Remove emoji (Unicode emoji ranges)
|
|
514
571
|
CLEAN_TITLE=$(echo "$CLEAN_TITLE" | sed 's/[\xF0\x9F][\x80-\xBF][\x80-\xBF][\x80-\xBF]//g; s/[\xE2\x9C\xE2\x9A\xE2\xAD\xE2\x9D\xE2\x99\xE2\x98\xE2\x9E\xE2\xAC\xE2\xAB\xE2\xAC][\x80-\xBF][\x80-\xBF]//g; s/[\xE2\x80\x8D]//g; s/\xEF\xB8\x8F//g; s/\xE2\x83\xA3//g')
|
|
515
|
-
# 2.
|
|
572
|
+
# 2. Remove bracket tags [xxx]
|
|
516
573
|
CLEAN_TITLE=$(echo "$CLEAN_TITLE" | sed 's/\[[^]]*\]//g')
|
|
517
|
-
# 3.
|
|
574
|
+
# 3. Trim leading/trailing whitespace
|
|
518
575
|
CLEAN_TITLE=$(echo "$CLEAN_TITLE" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
519
|
-
# 4.
|
|
576
|
+
# 4. Whitespace -> _
|
|
520
577
|
CLEAN_TITLE=$(echo "$CLEAN_TITLE" | sed 's/[[:space:]]/_/g')
|
|
521
|
-
# 5.
|
|
578
|
+
# 5. Remove characters that are invalid in file names
|
|
522
579
|
CLEAN_TITLE=$(echo "$CLEAN_TITLE" | sed 's/[#\/\\:*?"<>|]//g')
|
|
523
|
-
# 6.
|
|
580
|
+
# 6. Collapse repeated underscores
|
|
524
581
|
CLEAN_TITLE=$(echo "$CLEAN_TITLE" | sed 's/__*/_/g; s/^_//; s/_$//')
|
|
525
|
-
# 7. 30
|
|
582
|
+
# 7. Limit to 30 characters
|
|
526
583
|
CLEAN_TITLE=$(echo "$CLEAN_TITLE" | cut -c1-30)
|
|
527
|
-
# 8.
|
|
584
|
+
# 8. Remove a trailing underscore
|
|
528
585
|
CLEAN_TITLE=$(echo "$CLEAN_TITLE" | sed 's/_$//')
|
|
529
586
|
fi
|
|
530
587
|
|
|
531
|
-
#
|
|
588
|
+
# Assemble the file name
|
|
532
589
|
if [ -n "$ISSUE_NUMBER" ] && [ -n "$CLEAN_TITLE" ]; then
|
|
533
590
|
APK_NAME="${REPO_NAME}-${ISSUE_NUMBER}-${BUILD_NUMBER}-${CLEAN_TITLE}-${COMMIT_SHORT}.apk"
|
|
534
591
|
elif [ -n "$ISSUE_NUMBER" ]; then
|
|
@@ -537,56 +594,62 @@ jobs:
|
|
|
537
594
|
APK_NAME="${REPO_NAME}-${BUILD_NUMBER}-${COMMIT_SHORT}.apk"
|
|
538
595
|
fi
|
|
539
596
|
|
|
540
|
-
#
|
|
597
|
+
# Artifact name (without the extension)
|
|
541
598
|
ARTIFACT_NAME="${APK_NAME%.apk}"
|
|
542
599
|
echo "artifact_name=$ARTIFACT_NAME" >> $GITHUB_OUTPUT
|
|
543
600
|
echo "apk_name=$APK_NAME" >> $GITHUB_OUTPUT
|
|
544
|
-
|
|
601
|
+
m apk_test.apk_filename_log name="$APK_NAME"
|
|
545
602
|
|
|
546
603
|
- name: Set test build version
|
|
547
604
|
run: |
|
|
605
|
+
m() { python3 "$PAW_MESSAGES_PY" get "$@"; }
|
|
548
606
|
VERSION="${{ needs.prepare-test-build.outputs.version }}"
|
|
549
607
|
BUILD_NUMBER="${{ needs.prepare-test-build.outputs.build_number }}"
|
|
550
|
-
|
|
608
|
+
m apk_test.version_set_log version="${VERSION}+${BUILD_NUMBER}"
|
|
551
609
|
sed -i "s/^version: .*/version: ${VERSION}+${BUILD_NUMBER}/" pubspec.yaml
|
|
552
|
-
|
|
610
|
+
m apk_test.pubspec_updated
|
|
553
611
|
grep "^version:" pubspec.yaml
|
|
554
612
|
|
|
555
|
-
# APK
|
|
613
|
+
# Build the APK (directly with flutter)
|
|
556
614
|
- name: Build APK
|
|
557
615
|
run: |
|
|
558
|
-
|
|
616
|
+
m() { python3 "$PAW_MESSAGES_PY" get "$@"; }
|
|
617
|
+
m apk_test.flutter_build_log
|
|
559
618
|
flutter build apk --release ${DART_DEFINE_FILE:+--dart-define-from-file="$DART_DEFINE_FILE"}
|
|
560
619
|
ls -la ./build/app/outputs/flutter-apk/ || true
|
|
561
620
|
echo "✅ APK built"
|
|
562
621
|
|
|
563
622
|
- name: Rename and Prepare APK
|
|
564
623
|
run: |
|
|
624
|
+
m() { python3 "$PAW_MESSAGES_PY" get "$@"; }
|
|
565
625
|
mkdir -p ./android/app/build/outputs/apk/release/
|
|
566
626
|
APK_NAME="${{ steps.apk_filename.outputs.apk_name }}"
|
|
567
627
|
mv ./build/app/outputs/flutter-apk/app-release.apk ./android/app/build/outputs/apk/release/${APK_NAME}
|
|
568
628
|
echo "✅ APK renamed to ${APK_NAME}"
|
|
569
629
|
ls -la ./android/app/build/outputs/apk/release/
|
|
570
630
|
|
|
571
|
-
# APK
|
|
631
|
+
# Check the APK file size
|
|
572
632
|
APK_SIZE=$(stat -c%s "./android/app/build/outputs/apk/release/${APK_NAME}" 2>/dev/null || stat -f%z "./android/app/build/outputs/apk/release/${APK_NAME}" 2>/dev/null || echo "0")
|
|
573
633
|
APK_SIZE_MB=$(echo "scale=2; $APK_SIZE / 1024 / 1024" | bc)
|
|
574
|
-
|
|
634
|
+
m apk_test.apk_size_log size="$APK_SIZE_MB"
|
|
575
635
|
|
|
576
|
-
#
|
|
636
|
+
# Check the artifact size limit (500MB)
|
|
577
637
|
if [ "$APK_SIZE" -gt 524288000 ]; then
|
|
578
|
-
|
|
638
|
+
m apk_test.apk_size_over size="$APK_SIZE_MB"
|
|
579
639
|
else
|
|
580
|
-
|
|
640
|
+
m apk_test.apk_size_ok size="$APK_SIZE_MB"
|
|
581
641
|
fi
|
|
582
642
|
|
|
583
|
-
- name:
|
|
643
|
+
- name: Progress - APK build done
|
|
584
644
|
id: progress_step2
|
|
585
645
|
if: github.event_name == 'repository_dispatch' && needs.prepare-test-build.outputs.progress_comment_id != ''
|
|
586
646
|
uses: actions/github-script@v9
|
|
587
647
|
with:
|
|
588
648
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
589
649
|
script: |
|
|
650
|
+
const M = JSON.parse(process.env.PAW_MSG);
|
|
651
|
+
const msg = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
652
|
+
const row = (name, status, elapsed = '-') => `| ${msg('apk_test.step_' + name)} | ${msg('apk_test.st_' + status)} | ${elapsed} |`;
|
|
590
653
|
const commentId = parseInt('${{ needs.prepare-test-build.outputs.progress_comment_id }}');
|
|
591
654
|
const step1EndTime = parseInt('${{ steps.progress_step1.outputs.end_time }}');
|
|
592
655
|
const step1Elapsed = '${{ steps.progress_step1.outputs.elapsed }}';
|
|
@@ -597,26 +660,26 @@ jobs:
|
|
|
597
660
|
const elapsed = Math.round((now - step1EndTime) / 1000);
|
|
598
661
|
const minutes = Math.floor(elapsed / 60);
|
|
599
662
|
const seconds = elapsed % 60;
|
|
600
|
-
const elapsedStr = minutes > 0 ?
|
|
663
|
+
const elapsedStr = minutes > 0 ? msg('apk_test.elapsed_min_sec', { m: minutes, s: seconds }) : msg('apk_test.elapsed_sec', { s: seconds });
|
|
601
664
|
const firebaseAvailable = '${{ needs.prepare-test-build.outputs.firebase_available }}' === 'true';
|
|
602
665
|
|
|
603
666
|
const rows = [
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
'
|
|
667
|
+
row('prepare', 'done', step1Elapsed || '-'),
|
|
668
|
+
row('build', 'done', elapsedStr),
|
|
669
|
+
row('upload', 'running'),
|
|
607
670
|
];
|
|
608
671
|
if (firebaseAvailable) {
|
|
609
|
-
rows.push('
|
|
672
|
+
rows.push(row('firebase', 'waiting'));
|
|
610
673
|
}
|
|
611
674
|
|
|
612
675
|
const body = [
|
|
613
|
-
'
|
|
676
|
+
msg('apk_test.title_running'),
|
|
614
677
|
'',
|
|
615
|
-
'
|
|
678
|
+
msg('apk_test.table_header'),
|
|
616
679
|
'|------|------|----------|',
|
|
617
680
|
...rows,
|
|
618
681
|
'',
|
|
619
|
-
|
|
682
|
+
msg('apk_test.live_log', { url: runUrl })
|
|
620
683
|
].join('\n');
|
|
621
684
|
|
|
622
685
|
await github.rest.issues.updateComment({
|
|
@@ -626,12 +689,13 @@ jobs:
|
|
|
626
689
|
body: body
|
|
627
690
|
});
|
|
628
691
|
|
|
629
|
-
console.log(
|
|
692
|
+
console.log(msg('apk_test.log_build_done', { elapsed: elapsedStr }));
|
|
630
693
|
core.setOutput('elapsed', elapsedStr);
|
|
631
694
|
core.setOutput('end_time', now.toString());
|
|
632
695
|
|
|
633
696
|
- name: Create build info file
|
|
634
697
|
run: |
|
|
698
|
+
m() { python3 "$PAW_MESSAGES_PY" get "$@"; }
|
|
635
699
|
BUILD_NUMBER="${{ needs.prepare-test-build.outputs.build_number }}"
|
|
636
700
|
PR_NUMBER="${{ needs.prepare-test-build.outputs.pr_number }}"
|
|
637
701
|
BRANCH_NAME="${{ github.event_name == 'repository_dispatch' && github.event.client_payload.branch_name || github.ref_name }}"
|
|
@@ -639,44 +703,42 @@ jobs:
|
|
|
639
703
|
COMMIT_SHORT="${{ needs.prepare-test-build.outputs.commit_hash }}"
|
|
640
704
|
BUILD_DATE=$(date '+%Y-%m-%d %H:%M:%S')
|
|
641
705
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
706
|
+
{
|
|
707
|
+
m apk_test.info_title
|
|
708
|
+
echo
|
|
709
|
+
m apk_test.info_build_number build="$BUILD_NUMBER"
|
|
710
|
+
} > build-info.txt
|
|
647
711
|
|
|
648
712
|
if [ -n "$PR_NUMBER" ]; then
|
|
649
|
-
|
|
650
|
-
PR 번호: #$PR_NUMBER
|
|
651
|
-
EOF
|
|
713
|
+
m apk_test.info_pr_number pr="$PR_NUMBER" >> build-info.txt
|
|
652
714
|
fi
|
|
653
715
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
#
|
|
716
|
+
{
|
|
717
|
+
m apk_test.info_branch branch="$BRANCH_NAME"
|
|
718
|
+
m apk_test.info_commit commit="$COMMIT_SHORT"
|
|
719
|
+
m apk_test.info_full_commit sha="$COMMIT_SHA"
|
|
720
|
+
m apk_test.info_date date="$BUILD_DATE"
|
|
721
|
+
echo
|
|
722
|
+
} >> build-info.txt
|
|
723
|
+
|
|
724
|
+
# Add the issue info when available
|
|
663
725
|
if [ -n "${{ needs.prepare-test-build.outputs.issue_number }}" ]; then
|
|
664
726
|
ISSUE_NUMBER="${{ needs.prepare-test-build.outputs.issue_number }}"
|
|
665
727
|
ISSUE_TITLE="${{ needs.prepare-test-build.outputs.issue_title }}"
|
|
666
728
|
ISSUE_URL="${{ needs.prepare-test-build.outputs.issue_url }}"
|
|
667
729
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
730
|
+
{
|
|
731
|
+
m apk_test.info_issue_header
|
|
732
|
+
echo "- #$ISSUE_NUMBER: $ISSUE_TITLE"
|
|
733
|
+
echo "- URL: $ISSUE_URL"
|
|
734
|
+
echo
|
|
735
|
+
} >> build-info.txt
|
|
674
736
|
fi
|
|
675
737
|
|
|
676
|
-
|
|
738
|
+
m apk_test.info_file_created
|
|
677
739
|
cat build-info.txt
|
|
678
740
|
|
|
679
|
-
#
|
|
741
|
+
# Create the build metadata file (for the comment-posting workflow)
|
|
680
742
|
- name: Create build metadata file
|
|
681
743
|
run: |
|
|
682
744
|
cat > build-metadata.json << EOF
|
|
@@ -689,7 +751,7 @@ jobs:
|
|
|
689
751
|
EOF
|
|
690
752
|
cat build-metadata.json
|
|
691
753
|
|
|
692
|
-
# APK
|
|
754
|
+
# Upload the APK and build info as an artifact (the name includes the branch name)
|
|
693
755
|
- name: Upload APK and build info as Artifact
|
|
694
756
|
id: upload_artifact
|
|
695
757
|
uses: actions/upload-artifact@v7
|
|
@@ -708,23 +770,47 @@ jobs:
|
|
|
708
770
|
uses: actions/github-script@v9
|
|
709
771
|
with:
|
|
710
772
|
script: |
|
|
773
|
+
const M = JSON.parse(process.env.PAW_MSG);
|
|
774
|
+
const msg = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
711
775
|
const step2EndTime = parseInt('${{ steps.progress_step2.outputs.end_time }}');
|
|
712
776
|
const now = Date.now();
|
|
713
777
|
const elapsed = Math.round((now - step2EndTime) / 1000);
|
|
714
778
|
const minutes = Math.floor(elapsed / 60);
|
|
715
779
|
const seconds = elapsed % 60;
|
|
716
|
-
const elapsedStr = minutes > 0 ?
|
|
780
|
+
const elapsedStr = minutes > 0 ? msg('apk_test.elapsed_min_sec', { m: minutes, s: seconds }) : msg('apk_test.elapsed_sec', { s: seconds });
|
|
717
781
|
core.setOutput('elapsed', elapsedStr);
|
|
718
782
|
core.setOutput('end_time', now.toString());
|
|
719
783
|
|
|
720
|
-
# Firebase App Distribution
|
|
784
|
+
# Firebase App Distribution upload (only when the secret exists)
|
|
721
785
|
- name: Setup Firebase credentials file
|
|
722
786
|
if: needs.prepare-test-build.outputs.firebase_available == 'true'
|
|
723
787
|
env:
|
|
724
788
|
FIREBASE_SA_BASE64: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_JSON_BASE64 }}
|
|
725
789
|
run: |
|
|
790
|
+
m() { python3 "$PAW_MESSAGES_PY" get "$@"; }
|
|
726
791
|
echo "$FIREBASE_SA_BASE64" | base64 --decode > firebase-service-account.json
|
|
727
|
-
|
|
792
|
+
m apk_test.firebase_creds_ok
|
|
793
|
+
|
|
794
|
+
- name: Prepare Firebase release notes
|
|
795
|
+
id: firebase_notes
|
|
796
|
+
if: needs.prepare-test-build.outputs.firebase_available == 'true'
|
|
797
|
+
env:
|
|
798
|
+
NOTES_BUILD_NUMBER: ${{ needs.prepare-test-build.outputs.build_number }}
|
|
799
|
+
NOTES_BRANCH: ${{ needs.prepare-test-build.outputs.branch_name }}
|
|
800
|
+
NOTES_COMMIT: ${{ needs.prepare-test-build.outputs.commit_hash }}
|
|
801
|
+
NOTES_ISSUE_NUMBER: ${{ needs.prepare-test-build.outputs.issue_number }}
|
|
802
|
+
NOTES_ISSUE_TITLE: ${{ needs.prepare-test-build.outputs.issue_title }}
|
|
803
|
+
run: |
|
|
804
|
+
m() { python3 "$PAW_MESSAGES_PY" get "$@"; }
|
|
805
|
+
# The release notes go through a multi-line step output so the wording follows the configured language
|
|
806
|
+
{
|
|
807
|
+
echo "notes<<PAW_NOTES_EOF"
|
|
808
|
+
m apk_test.fb_notes_build build="$NOTES_BUILD_NUMBER"
|
|
809
|
+
m apk_test.fb_notes_branch branch="$NOTES_BRANCH"
|
|
810
|
+
m apk_test.fb_notes_commit commit="$NOTES_COMMIT"
|
|
811
|
+
m apk_test.fb_notes_issue number="$NOTES_ISSUE_NUMBER" title="$NOTES_ISSUE_TITLE"
|
|
812
|
+
echo "PAW_NOTES_EOF"
|
|
813
|
+
} >> "$GITHUB_OUTPUT"
|
|
728
814
|
|
|
729
815
|
- name: Upload to Firebase App Distribution
|
|
730
816
|
id: firebase_upload
|
|
@@ -736,11 +822,7 @@ jobs:
|
|
|
736
822
|
serviceCredentialsFile: ${{ env.FLUTTER_PROJECT_DIR }}/firebase-service-account.json
|
|
737
823
|
groups: ${{ env.FIREBASE_TESTER_GROUP }}
|
|
738
824
|
file: ${{ env.FLUTTER_PROJECT_DIR }}/android/app/build/outputs/apk/release/${{ steps.apk_filename.outputs.apk_name }}
|
|
739
|
-
releaseNotes:
|
|
740
|
-
테스트 빌드 #${{ needs.prepare-test-build.outputs.build_number }}
|
|
741
|
-
브랜치: ${{ needs.prepare-test-build.outputs.branch_name }}
|
|
742
|
-
커밋: ${{ needs.prepare-test-build.outputs.commit_hash }}
|
|
743
|
-
이슈: #${{ needs.prepare-test-build.outputs.issue_number }} ${{ needs.prepare-test-build.outputs.issue_title }}
|
|
825
|
+
releaseNotes: ${{ steps.firebase_notes.outputs.notes }}
|
|
744
826
|
|
|
745
827
|
- name: Cleanup Firebase credentials
|
|
746
828
|
if: always() && needs.prepare-test-build.outputs.firebase_available == 'true'
|
|
@@ -750,12 +832,13 @@ jobs:
|
|
|
750
832
|
id: firebase_result
|
|
751
833
|
if: needs.prepare-test-build.outputs.firebase_available == 'true'
|
|
752
834
|
run: |
|
|
835
|
+
m() { python3 "$PAW_MESSAGES_PY" get "$@"; }
|
|
753
836
|
if [ "${{ steps.firebase_upload.outcome }}" == "success" ]; then
|
|
754
837
|
echo "status=success" >> $GITHUB_OUTPUT
|
|
755
|
-
|
|
838
|
+
m apk_test.firebase_upload_ok
|
|
756
839
|
else
|
|
757
840
|
echo "status=failure" >> $GITHUB_OUTPUT
|
|
758
|
-
|
|
841
|
+
m apk_test.firebase_upload_failed
|
|
759
842
|
fi
|
|
760
843
|
|
|
761
844
|
- name: Record Firebase upload time
|
|
@@ -764,20 +847,25 @@ jobs:
|
|
|
764
847
|
uses: actions/github-script@v9
|
|
765
848
|
with:
|
|
766
849
|
script: |
|
|
850
|
+
const M = JSON.parse(process.env.PAW_MSG);
|
|
851
|
+
const msg = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
767
852
|
const artifactEndTime = parseInt('${{ steps.artifact_time.outputs.end_time }}');
|
|
768
853
|
const now = Date.now();
|
|
769
854
|
const elapsed = Math.round((now - artifactEndTime) / 1000);
|
|
770
855
|
const minutes = Math.floor(elapsed / 60);
|
|
771
856
|
const seconds = elapsed % 60;
|
|
772
|
-
const elapsedStr = minutes > 0 ?
|
|
857
|
+
const elapsedStr = minutes > 0 ? msg('apk_test.elapsed_min_sec', { m: minutes, s: seconds }) : msg('apk_test.elapsed_sec', { s: seconds });
|
|
773
858
|
core.setOutput('elapsed', elapsedStr);
|
|
774
859
|
|
|
775
|
-
- name:
|
|
860
|
+
- name: Final progress update - success
|
|
776
861
|
if: success() && github.event_name == 'repository_dispatch' && github.event.client_payload.pr_number != '' && needs.prepare-test-build.outputs.progress_comment_id != ''
|
|
777
862
|
uses: actions/github-script@v9
|
|
778
863
|
with:
|
|
779
864
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
780
865
|
script: |
|
|
866
|
+
const M = JSON.parse(process.env.PAW_MSG);
|
|
867
|
+
const msg = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
868
|
+
const row = (name, status, elapsed = '-') => `| ${msg('apk_test.step_' + name)} | ${msg('apk_test.st_' + status)} | ${elapsed} |`;
|
|
781
869
|
const commentId = parseInt('${{ needs.prepare-test-build.outputs.progress_comment_id }}');
|
|
782
870
|
const startTime = parseInt('${{ needs.prepare-test-build.outputs.progress_start_time }}');
|
|
783
871
|
const step1Elapsed = '${{ steps.progress_step1.outputs.elapsed }}';
|
|
@@ -798,26 +886,26 @@ jobs:
|
|
|
798
886
|
const totalElapsed_s = Math.round((now - startTime) / 1000);
|
|
799
887
|
const totalMin = Math.floor(totalElapsed_s / 60);
|
|
800
888
|
const totalSec = totalElapsed_s % 60;
|
|
801
|
-
const totalElapsed = totalMin > 0 ?
|
|
889
|
+
const totalElapsed = totalMin > 0 ? msg('apk_test.elapsed_min_sec', { m: totalMin, s: totalSec }) : msg('apk_test.elapsed_sec', { s: totalSec });
|
|
802
890
|
|
|
803
891
|
const firebaseAvailable = '${{ needs.prepare-test-build.outputs.firebase_available }}' === 'true';
|
|
804
892
|
const firebaseSuccess = '${{ steps.firebase_result.outputs.status }}' === 'success';
|
|
805
893
|
|
|
806
894
|
const lines = [
|
|
807
|
-
'
|
|
895
|
+
msg('apk_test.title_done'),
|
|
808
896
|
'',
|
|
809
|
-
'
|
|
897
|
+
msg('apk_test.table_header'),
|
|
810
898
|
'|------|------|----------|',
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
899
|
+
row('prepare', 'done', step1Elapsed || '-'),
|
|
900
|
+
row('build', 'done', step2Elapsed || '-'),
|
|
901
|
+
row('upload', 'done', step3Elapsed || '-'),
|
|
814
902
|
];
|
|
815
903
|
|
|
816
904
|
if (firebaseAvailable) {
|
|
817
905
|
if (firebaseSuccess) {
|
|
818
|
-
lines.push(
|
|
906
|
+
lines.push(row('firebase', 'done', step4Elapsed || '-'));
|
|
819
907
|
} else {
|
|
820
|
-
lines.push(
|
|
908
|
+
lines.push(row('firebase', 'failed', step4Elapsed || '-'));
|
|
821
909
|
}
|
|
822
910
|
}
|
|
823
911
|
|
|
@@ -825,25 +913,25 @@ jobs:
|
|
|
825
913
|
|
|
826
914
|
lines.push(
|
|
827
915
|
'',
|
|
828
|
-
'
|
|
829
|
-
'
|
|
916
|
+
msg('apk_test.result_title'),
|
|
917
|
+
msg('apk_test.kv_head'),
|
|
830
918
|
'|------|-----|',
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
919
|
+
msg('apk_test.row_app_version', { version, build: buildNumber }),
|
|
920
|
+
msg('apk_test.row_branch', { branch: branchName }),
|
|
921
|
+
msg('apk_test.row_commit', { commit: commitHash }),
|
|
922
|
+
msg('apk_test.row_total', { elapsed: totalElapsed }),
|
|
835
923
|
'',
|
|
836
924
|
);
|
|
837
925
|
|
|
838
926
|
if (firebaseAvailable && firebaseSuccess) {
|
|
839
|
-
lines.push('
|
|
927
|
+
lines.push(msg('apk_test.firebase_installable'));
|
|
840
928
|
} else if (firebaseAvailable && !firebaseSuccess) {
|
|
841
|
-
lines.push('
|
|
929
|
+
lines.push(msg('apk_test.firebase_failed_hint'));
|
|
842
930
|
}
|
|
843
931
|
|
|
844
932
|
lines.push(
|
|
845
|
-
|
|
846
|
-
|
|
933
|
+
msg('apk_test.artifact_link', { url: artifactUrl }),
|
|
934
|
+
msg('apk_test.run_log_link', { url: runUrl })
|
|
847
935
|
);
|
|
848
936
|
|
|
849
937
|
const body = lines.join('\n');
|
|
@@ -855,25 +943,25 @@ jobs:
|
|
|
855
943
|
body: body
|
|
856
944
|
});
|
|
857
945
|
|
|
858
|
-
console.log(
|
|
946
|
+
console.log(msg('apk_test.log_success', { elapsed: totalElapsed }));
|
|
859
947
|
|
|
860
|
-
// PR
|
|
948
|
+
// If an issue is linked to the PR and differs from the PR number, comment on the issue too
|
|
861
949
|
if (issueNumber && issueNumber !== '' && parseInt(issueNumber) !== prNumber) {
|
|
862
950
|
const issueLines = [
|
|
863
|
-
'
|
|
951
|
+
msg('apk_test.issue_done_title'),
|
|
864
952
|
'',
|
|
865
|
-
|
|
866
|
-
|
|
953
|
+
msg('apk_test.issue_line_version', { version, build: buildNumber }),
|
|
954
|
+
msg('apk_test.issue_line_commit', { commit: commitHash }),
|
|
867
955
|
'',
|
|
868
956
|
];
|
|
869
957
|
|
|
870
958
|
if (firebaseAvailable && firebaseSuccess) {
|
|
871
|
-
issueLines.push('
|
|
959
|
+
issueLines.push(msg('apk_test.firebase_installable'));
|
|
872
960
|
} else if (firebaseAvailable && !firebaseSuccess) {
|
|
873
|
-
issueLines.push('
|
|
961
|
+
issueLines.push(msg('apk_test.firebase_failed_hint'));
|
|
874
962
|
}
|
|
875
963
|
|
|
876
|
-
issueLines.push(
|
|
964
|
+
issueLines.push(msg('apk_test.artifact_link', { url: artifactUrl }));
|
|
877
965
|
|
|
878
966
|
await github.rest.issues.createComment({
|
|
879
967
|
owner: context.repo.owner,
|
|
@@ -881,15 +969,18 @@ jobs:
|
|
|
881
969
|
issue_number: parseInt(issueNumber),
|
|
882
970
|
body: issueLines.join('\n')
|
|
883
971
|
});
|
|
884
|
-
console.log(
|
|
972
|
+
console.log(msg('apk_test.log_issue_success', { number: issueNumber }));
|
|
885
973
|
}
|
|
886
974
|
|
|
887
|
-
- name:
|
|
975
|
+
- name: Final progress update - failure
|
|
888
976
|
if: failure() && github.event_name == 'repository_dispatch' && github.event.client_payload.pr_number != '' && needs.prepare-test-build.outputs.progress_comment_id != ''
|
|
889
977
|
uses: actions/github-script@v9
|
|
890
978
|
with:
|
|
891
979
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
892
980
|
script: |
|
|
981
|
+
const M = JSON.parse(process.env.PAW_MSG);
|
|
982
|
+
const msg = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
983
|
+
const row = (name, status, elapsed = '-') => `| ${msg('apk_test.step_' + name)} | ${msg('apk_test.st_' + status)} | ${elapsed} |`;
|
|
893
984
|
const commentId = parseInt('${{ needs.prepare-test-build.outputs.progress_comment_id }}');
|
|
894
985
|
const startTime = parseInt('${{ needs.prepare-test-build.outputs.progress_start_time }}');
|
|
895
986
|
const step1EndTime = parseInt('${{ steps.progress_step1.outputs.end_time }}') || 0;
|
|
@@ -909,39 +1000,39 @@ jobs:
|
|
|
909
1000
|
const step2_s = Math.round((now - step1EndTime) / 1000);
|
|
910
1001
|
const s2Min = Math.floor(step2_s / 60);
|
|
911
1002
|
const s2Sec = step2_s % 60;
|
|
912
|
-
step2ElapsedStr = s2Min > 0 ?
|
|
1003
|
+
step2ElapsedStr = s2Min > 0 ? msg('apk_test.elapsed_min_sec', { m: s2Min, s: s2Sec }) : msg('apk_test.elapsed_sec', { s: s2Sec });
|
|
913
1004
|
}
|
|
914
1005
|
|
|
915
1006
|
const total_s = Math.round((now - startTime) / 1000);
|
|
916
1007
|
const tMin = Math.floor(total_s / 60);
|
|
917
1008
|
const tSec = total_s % 60;
|
|
918
|
-
const totalElapsed = tMin > 0 ?
|
|
1009
|
+
const totalElapsed = tMin > 0 ? msg('apk_test.elapsed_min_sec', { m: tMin, s: tSec }) : msg('apk_test.elapsed_sec', { s: tSec });
|
|
919
1010
|
|
|
920
1011
|
const firebaseAvailable = '${{ needs.prepare-test-build.outputs.firebase_available }}' === 'true';
|
|
921
1012
|
|
|
922
1013
|
const rows = [
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
'
|
|
1014
|
+
row('prepare', 'done', step1Elapsed || '-'),
|
|
1015
|
+
row('build', 'failed', step2ElapsedStr),
|
|
1016
|
+
row('upload', 'skipped'),
|
|
926
1017
|
];
|
|
927
1018
|
if (firebaseAvailable) {
|
|
928
|
-
rows.push('
|
|
1019
|
+
rows.push(row('firebase', 'skipped'));
|
|
929
1020
|
}
|
|
930
1021
|
|
|
931
1022
|
const body = [
|
|
932
|
-
'
|
|
1023
|
+
msg('apk_test.title_failed'),
|
|
933
1024
|
'',
|
|
934
|
-
'
|
|
1025
|
+
msg('apk_test.table_header'),
|
|
935
1026
|
'|------|------|----------|',
|
|
936
1027
|
...rows,
|
|
937
1028
|
'',
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1029
|
+
msg('apk_test.issue_line_version', { version, build: buildNumber }),
|
|
1030
|
+
msg('apk_test.fail_line_branch', { branch: branchName }),
|
|
1031
|
+
msg('apk_test.fail_line_total', { elapsed: totalElapsed }),
|
|
941
1032
|
'',
|
|
942
|
-
'
|
|
1033
|
+
msg('apk_test.build_error'),
|
|
943
1034
|
'',
|
|
944
|
-
|
|
1035
|
+
msg('apk_test.run_log_check_link', { url: runUrl })
|
|
945
1036
|
].join('\n');
|
|
946
1037
|
|
|
947
1038
|
await github.rest.issues.updateComment({
|
|
@@ -951,17 +1042,17 @@ jobs:
|
|
|
951
1042
|
body: body
|
|
952
1043
|
});
|
|
953
1044
|
|
|
954
|
-
console.log(
|
|
1045
|
+
console.log(msg('apk_test.log_failed', { elapsed: totalElapsed }));
|
|
955
1046
|
|
|
956
1047
|
if (issueNumber && issueNumber !== '' && parseInt(issueNumber) !== prNumber) {
|
|
957
1048
|
const issueBody = [
|
|
958
|
-
'
|
|
1049
|
+
msg('apk_test.issue_failed_title'),
|
|
959
1050
|
'',
|
|
960
|
-
|
|
1051
|
+
msg('apk_test.issue_line_version', { version, build: buildNumber }),
|
|
961
1052
|
'',
|
|
962
|
-
'
|
|
1053
|
+
msg('apk_test.build_error'),
|
|
963
1054
|
'',
|
|
964
|
-
|
|
1055
|
+
msg('apk_test.run_log_check_link', { url: runUrl })
|
|
965
1056
|
].join('\n');
|
|
966
1057
|
|
|
967
1058
|
await github.rest.issues.createComment({
|
|
@@ -970,27 +1061,29 @@ jobs:
|
|
|
970
1061
|
issue_number: parseInt(issueNumber),
|
|
971
1062
|
body: issueBody
|
|
972
1063
|
});
|
|
973
|
-
console.log(
|
|
1064
|
+
console.log(msg('apk_test.log_issue_failed', { number: issueNumber }));
|
|
974
1065
|
}
|
|
975
1066
|
|
|
976
1067
|
- name: Notify Build Success
|
|
977
1068
|
if: success()
|
|
978
1069
|
run: |
|
|
979
|
-
|
|
980
|
-
|
|
1070
|
+
m() { python3 "$PAW_MESSAGES_PY" get "$@"; }
|
|
1071
|
+
m apk_test.notify_ok
|
|
1072
|
+
m apk_test.notify_build_number build="${{ needs.prepare-test-build.outputs.build_number }}"
|
|
981
1073
|
if [ -n "${{ needs.prepare-test-build.outputs.pr_number }}" ]; then
|
|
982
|
-
|
|
1074
|
+
m apk_test.notify_pr pr="${{ needs.prepare-test-build.outputs.pr_number }}"
|
|
983
1075
|
fi
|
|
984
|
-
|
|
985
|
-
|
|
1076
|
+
m apk_test.notify_branch branch="${{ github.event_name == 'repository_dispatch' && github.event.client_payload.branch_name || github.ref_name }}"
|
|
1077
|
+
m apk_test.notify_commit commit="${{ needs.prepare-test-build.outputs.commit_hash }}"
|
|
986
1078
|
if [ -n "${{ needs.prepare-test-build.outputs.issue_url }}" ]; then
|
|
987
|
-
|
|
1079
|
+
m apk_test.notify_issue url="${{ needs.prepare-test-build.outputs.issue_url }}"
|
|
988
1080
|
fi
|
|
989
1081
|
echo ""
|
|
990
|
-
|
|
1082
|
+
m apk_test.notify_artifact_hint
|
|
991
1083
|
|
|
992
1084
|
- name: Notify on Failure
|
|
993
1085
|
if: failure()
|
|
994
1086
|
run: |
|
|
995
|
-
|
|
996
|
-
|
|
1087
|
+
m() { python3 "$PAW_MESSAGES_PY" get "$@"; }
|
|
1088
|
+
m apk_test.notify_fail
|
|
1089
|
+
m apk_test.check_logs
|