gowalk-cicd 1.0.33 → 1.0.35
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 +17 -7
- package/action/.daemux-version +1 -1
- package/action/action.yml +24 -2
- package/action/scripts/test_testflight_version_slot_wiring.py +50 -0
- package/android-action/.daemux-version +1 -1
- package/backend-action/.daemux-version +1 -1
- package/package.json +1 -1
- package/templates/deploy.yml +35 -10
package/README.md
CHANGED
|
@@ -184,11 +184,11 @@ sent for review from the Google Play Console UI.
|
|
|
184
184
|
```
|
|
185
185
|
|
|
186
186
|
That fails the whole upload, so the bundle you just built never reaches Play at
|
|
187
|
-
all.
|
|
188
|
-
and leaves it waiting, then
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
187
|
+
all. After an ordinary fresh-edit retry, the final retry re-uploads with
|
|
188
|
+
`changesNotSentForReview`, which lands the bundle and leaves it waiting, then
|
|
189
|
+
emits a `::warning::` naming the package. The delivery system can then complete
|
|
190
|
+
the console-only **Send changes for review** action through the app's leased
|
|
191
|
+
AdsPower profile.
|
|
192
192
|
|
|
193
193
|
In the ordinary case the first upload submits normally and the retry is skipped.
|
|
194
194
|
|
|
@@ -204,8 +204,10 @@ long enough outlives one:
|
|
|
204
204
|
|
|
205
205
|
Neither says anything about the build, which is signed and retained by that
|
|
206
206
|
point. The upload step therefore runs with `continue-on-error` and a second
|
|
207
|
-
attempt follows when the first fails
|
|
208
|
-
|
|
207
|
+
ordinary attempt follows when the first fails. This preserves automatic review
|
|
208
|
+
submission while opening a fresh edit. Only when that retry also fails does a
|
|
209
|
+
third attempt use `changesNotSentForReview`; setting that flag on an ordinary
|
|
210
|
+
app is itself a Play validation error.
|
|
209
211
|
|
|
210
212
|
One caveat this makes explicit: **nothing else should hold an edit open on the
|
|
211
213
|
same package while a deploy runs.** A script that polls `edits.insert` /
|
|
@@ -437,6 +439,13 @@ The iOS composite action runs on `macos-15` and:
|
|
|
437
439
|
|
|
438
440
|
The iOS action requires only the p8. Everything else is derived.
|
|
439
441
|
|
|
442
|
+
Feature-branch runs installed from the standard workflow still archive and
|
|
443
|
+
upload to TestFlight, but pass `manage-app-store-version: 'false'`. This keeps
|
|
444
|
+
branch validation independent of the editable App Store release slot, so a
|
|
445
|
+
build can upload while the current release is locked in review. Default-branch
|
|
446
|
+
runs retain version creation and metadata automation. Direct action callers
|
|
447
|
+
keep the historical behavior because the new input defaults to `true`.
|
|
448
|
+
|
|
440
449
|
### App ID capabilities
|
|
441
450
|
|
|
442
451
|
A provisioning profile carries only the capabilities enabled on its App ID.
|
|
@@ -570,6 +579,7 @@ common ones:
|
|
|
570
579
|
| `uses-non-exempt-encryption` | Value for `ITSAppUsesNonExemptEncryption` |
|
|
571
580
|
| `archive` | `false` to build-only (PR runs without secrets) |
|
|
572
581
|
| `upload` | `false` to archive but not upload to TestFlight |
|
|
582
|
+
| `manage-app-store-version` | `false` to upload without creating/editing the App Store release slot |
|
|
573
583
|
| `app-store-whats-new` | Inline "What's New" text (overrides files) |
|
|
574
584
|
| `ai-metadata` | `false` to disable AI auto-fill of empty ASC metadata |
|
|
575
585
|
| `ai-metadata-model` | GitHub Models model id (default `openai/gpt-4o`) |
|
package/action/.daemux-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.35
|
package/action/action.yml
CHANGED
|
@@ -71,6 +71,13 @@ inputs:
|
|
|
71
71
|
secrets. When 'false', `upload` is ignored.
|
|
72
72
|
required: false
|
|
73
73
|
default: "true"
|
|
74
|
+
manage-app-store-version:
|
|
75
|
+
description: >
|
|
76
|
+
Set to 'false' to archive and upload a TestFlight build without creating
|
|
77
|
+
or editing an App Store version. App Store metadata automation is skipped.
|
|
78
|
+
This is useful for feature-branch validation while a release is in review.
|
|
79
|
+
required: false
|
|
80
|
+
default: "true"
|
|
74
81
|
run-tests:
|
|
75
82
|
description: "Set to 'false' to skip the simulator test stage"
|
|
76
83
|
required: false
|
|
@@ -289,7 +296,7 @@ runs:
|
|
|
289
296
|
| tee -a "$GITHUB_ENV"
|
|
290
297
|
|
|
291
298
|
- name: Resolve App Store version slot (REUSE or CREATE)
|
|
292
|
-
if: ${{ inputs.archive == 'true' }}
|
|
299
|
+
if: ${{ inputs.archive == 'true' && inputs.manage-app-store-version == 'true' }}
|
|
293
300
|
shell: bash
|
|
294
301
|
env:
|
|
295
302
|
APP_STORE_APPLE_ID: ${{ inputs.app-store-apple-id || env.CFG_APP_STORE_APPLE_ID }}
|
|
@@ -335,6 +342,18 @@ runs:
|
|
|
335
342
|
echo "APP_STORE_VERSION_ID=$APP_STORE_VERSION_ID" >> "$GITHUB_ENV"
|
|
336
343
|
echo "Using marketing version $MARKETING_VERSION build $BUILD_NUMBER (decision=$DECISION_JSON)"
|
|
337
344
|
|
|
345
|
+
- name: Resolve TestFlight build number
|
|
346
|
+
if: ${{ inputs.archive == 'true' && inputs.manage-app-store-version == 'false' }}
|
|
347
|
+
shell: bash
|
|
348
|
+
env:
|
|
349
|
+
APP_STORE_APPLE_ID: ${{ inputs.app-store-apple-id || env.CFG_APP_STORE_APPLE_ID }}
|
|
350
|
+
run: |
|
|
351
|
+
set -o pipefail
|
|
352
|
+
BUILD_NUMBER=$(python3 "${{ github.action_path }}/scripts/next_build_number.py")
|
|
353
|
+
echo "BUILD_NUMBER=$BUILD_NUMBER" >> "$GITHUB_ENV"
|
|
354
|
+
echo "APP_STORE_VERSION_ID=" >> "$GITHUB_ENV"
|
|
355
|
+
echo "Using marketing version $MARKETING_VERSION build $BUILD_NUMBER without an App Store version slot"
|
|
356
|
+
|
|
338
357
|
- name: Notice on deprecated profile-name input
|
|
339
358
|
if: ${{ inputs.archive == 'true' && inputs.profile-name != '' }}
|
|
340
359
|
shell: bash
|
|
@@ -714,7 +733,9 @@ runs:
|
|
|
714
733
|
|
|
715
734
|
- name: Detect empty ASC metadata fields
|
|
716
735
|
id: detect_metadata
|
|
717
|
-
if:
|
|
736
|
+
if: >-
|
|
737
|
+
${{ inputs.archive == 'true' && inputs.upload == 'true'
|
|
738
|
+
&& inputs.manage-app-store-version == 'true' && inputs.ai-metadata != 'false' }}
|
|
718
739
|
shell: bash
|
|
719
740
|
env:
|
|
720
741
|
APP_STORE_APPLE_ID: ${{ inputs.app-store-apple-id || env.CFG_APP_STORE_APPLE_ID }}
|
|
@@ -969,6 +990,7 @@ runs:
|
|
|
969
990
|
# with the default (CFG_WHATS_NEW), preserving any AI-generated notes.
|
|
970
991
|
- name: Set App Store "What's New"
|
|
971
992
|
if: ${{ inputs.archive == 'true' && inputs.upload == 'true'
|
|
993
|
+
&& inputs.manage-app-store-version == 'true'
|
|
972
994
|
&& (inputs.app-store-whats-new != '' || env.CFG_WHATS_NEW != '') }}
|
|
973
995
|
shell: bash
|
|
974
996
|
env:
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import unittest
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
ACTION_YAML = Path(__file__).resolve().parents[1] / "action.yml"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def step_block(source: str, name: str) -> str:
|
|
10
|
+
pattern = rf" - name: {re.escape(name)}\n(?P<body>.*?)(?=\n - name:|\Z)"
|
|
11
|
+
match = re.search(pattern, source, re.DOTALL)
|
|
12
|
+
if match is None:
|
|
13
|
+
raise AssertionError(f"missing action step: {name}")
|
|
14
|
+
return match.group("body")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TestTestFlightVersionSlotWiring(unittest.TestCase):
|
|
18
|
+
@classmethod
|
|
19
|
+
def setUpClass(cls) -> None:
|
|
20
|
+
cls.source = ACTION_YAML.read_text(encoding="utf-8")
|
|
21
|
+
|
|
22
|
+
def test_opt_out_is_backward_compatible(self) -> None:
|
|
23
|
+
self.assertRegex(
|
|
24
|
+
self.source,
|
|
25
|
+
r"(?m)^ manage-app-store-version:\n(?: .*\n)*? default: \"true\"$",
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
def test_opt_out_skips_store_version_but_keeps_build_number(self) -> None:
|
|
29
|
+
store_slot = step_block(self.source, "Resolve App Store version slot (REUSE or CREATE)")
|
|
30
|
+
testflight = step_block(self.source, "Resolve TestFlight build number")
|
|
31
|
+
|
|
32
|
+
self.assertIn("inputs.manage-app-store-version == 'true'", store_slot)
|
|
33
|
+
self.assertIn("inputs.manage-app-store-version == 'false'", testflight)
|
|
34
|
+
self.assertIn(
|
|
35
|
+
"APP_STORE_APPLE_ID: ${{ inputs.app-store-apple-id || env.CFG_APP_STORE_APPLE_ID }}",
|
|
36
|
+
testflight,
|
|
37
|
+
)
|
|
38
|
+
self.assertIn("next_build_number.py", testflight)
|
|
39
|
+
self.assertNotIn("manage_marketing_version.py", testflight)
|
|
40
|
+
|
|
41
|
+
def test_metadata_requires_a_managed_store_version(self) -> None:
|
|
42
|
+
detector = step_block(self.source, "Detect empty ASC metadata fields")
|
|
43
|
+
whats_new = step_block(self.source, 'Set App Store "What\'s New"')
|
|
44
|
+
|
|
45
|
+
self.assertIn("inputs.manage-app-store-version == 'true'", detector)
|
|
46
|
+
self.assertIn("inputs.manage-app-store-version == 'true'", whats_new)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if __name__ == "__main__":
|
|
50
|
+
unittest.main()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.35
|
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.35
|
package/package.json
CHANGED
package/templates/deploy.yml
CHANGED
|
@@ -113,6 +113,11 @@ jobs:
|
|
|
113
113
|
workspace: ${{ steps.flutter.outputs.enabled == 'true' && 'ios/Runner.xcworkspace' || '' }}
|
|
114
114
|
scheme: ${{ steps.flutter.outputs.enabled == 'true' && 'Runner' || '' }}
|
|
115
115
|
run-tests: 'false' # tests belong to the CI gate, not the deploy path
|
|
116
|
+
# A feature-branch TestFlight build must not create or mutate a live
|
|
117
|
+
# App Store version. That also lets it upload while the current version
|
|
118
|
+
# is locked in review. Default-branch deploys retain metadata automation.
|
|
119
|
+
manage-app-store-version: >-
|
|
120
|
+
${{ github.ref_name == github.event.repository.default_branch && 'true' || 'false' }}
|
|
116
121
|
|
|
117
122
|
android:
|
|
118
123
|
name: Android Google Play
|
|
@@ -358,20 +363,40 @@ jobs:
|
|
|
358
363
|
${{ vars.GOOGLE_PLAY_STATUS == 'inProgress' && (vars.GOOGLE_PLAY_USER_FRACTION || '0.2') || '' }}
|
|
359
364
|
whatsNewDirectory: ${{ hashFiles('distribution/whatsnew/**') != '' && 'distribution/whatsnew' || '' }}
|
|
360
365
|
|
|
361
|
-
#
|
|
362
|
-
#
|
|
363
|
-
#
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
# bundle never lands at all.
|
|
368
|
-
- name: Retry Google Play upload without auto-submit
|
|
369
|
-
id: play-upload-retry
|
|
366
|
+
# A failed action does not expose a machine-readable Play error code. Retry once
|
|
367
|
+
# with the ordinary review mode first: that opens a fresh edit and repairs an edit
|
|
368
|
+
# that expired during a slow upload without changing submission semantics.
|
|
369
|
+
- name: Retry Google Play upload with a fresh edit
|
|
370
|
+
id: play-upload-fresh-retry
|
|
371
|
+
continue-on-error: true
|
|
370
372
|
if: >-
|
|
371
373
|
${{ steps.mode.outputs.mode == 'local'
|
|
372
374
|
&& steps.play.outputs.ready == 'true'
|
|
373
375
|
&& steps.play-upload.outcome == 'failure' }}
|
|
374
376
|
uses: r0adkll/upload-google-play@e738b9dd8f2476ea806d921b64aacd24f34515a5 # v1.1.5
|
|
377
|
+
with:
|
|
378
|
+
serviceAccountJson: ${{ steps.android.outputs.play-service-account }}
|
|
379
|
+
packageName: ${{ steps.android.outputs.package-name }}
|
|
380
|
+
releaseFiles: ${{ steps.android.outputs.bundle-path }}
|
|
381
|
+
tracks: ${{ vars.GOOGLE_PLAY_TRACK || 'internal' }}
|
|
382
|
+
status: ${{ vars.GOOGLE_PLAY_STATUS || 'completed' }}
|
|
383
|
+
userFraction: >-
|
|
384
|
+
${{ vars.GOOGLE_PLAY_STATUS == 'inProgress' && (vars.GOOGLE_PLAY_USER_FRACTION || '0.2') || '' }}
|
|
385
|
+
whatsNewDirectory: >-
|
|
386
|
+
${{ hashFiles('distribution/whatsnew/**') != '' && 'distribution/whatsnew' || '' }}
|
|
387
|
+
|
|
388
|
+
# If the ordinary fresh-edit retry also fails, Play may be requiring the
|
|
389
|
+
# changesNotSentForReview mode used after a policy rejection. A third, fresh edit
|
|
390
|
+
# is intentionally reserved for that case. Setting the flag on the edit-expiry
|
|
391
|
+
# retry is invalid for apps whose changes are submitted automatically.
|
|
392
|
+
- name: Retry Google Play upload without auto-submit
|
|
393
|
+
id: play-upload-review-retry
|
|
394
|
+
if: >-
|
|
395
|
+
${{ steps.mode.outputs.mode == 'local'
|
|
396
|
+
&& steps.play.outputs.ready == 'true'
|
|
397
|
+
&& steps.play-upload.outcome == 'failure'
|
|
398
|
+
&& steps.play-upload-fresh-retry.outcome == 'failure' }}
|
|
399
|
+
uses: r0adkll/upload-google-play@e738b9dd8f2476ea806d921b64aacd24f34515a5 # v1.1.5
|
|
375
400
|
with:
|
|
376
401
|
serviceAccountJson: ${{ steps.android.outputs.play-service-account }}
|
|
377
402
|
packageName: ${{ steps.android.outputs.package-name }}
|
|
@@ -385,7 +410,7 @@ jobs:
|
|
|
385
410
|
changesNotSentForReview: true
|
|
386
411
|
|
|
387
412
|
- name: Say what still needs a human
|
|
388
|
-
if: ${{ always() && steps.play-upload-retry.outcome == 'success' }}
|
|
413
|
+
if: ${{ always() && steps.play-upload-review-retry.outcome == 'success' }}
|
|
389
414
|
shell: bash
|
|
390
415
|
run: |
|
|
391
416
|
echo "::warning::Play would not accept this release for review automatically, so it was \
|