gowalk-cicd 1.0.166 → 1.0.168
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 +116 -215
- package/action/action.yml +59 -362
- package/action/scripts/auto_detect.py +39 -60
- package/action/scripts/commit_bot_changes.sh +3 -26
- package/action/scripts/creds_store.py +10 -91
- package/action/scripts/mobile_inputs.cjs +6 -4
- package/action/scripts/native_cache.py +5 -1
- package/action/scripts/native_pods.py +44 -15
- package/action/scripts/native_pods_diagnostics.py +18 -3
- package/action/scripts/native_pods_process.py +5 -0
- package/action/scripts/prepare_crashlytics_build.py +22 -5
- package/action/scripts/prepare_signing.py +4 -6
- package/action/scripts/profile_manager.py +74 -165
- package/action/scripts/resolve_info_plist.py +7 -2
- package/action/scripts/resolve_marketing_version.py +9 -1
- package/action/scripts/set_app_store_whats_new.py +3 -4
- package/android-action/action.yml +6 -8
- package/android-action/flutter-setup/action.yml +46 -7
- package/android-action/scripts/android_build_diagnostics.py +53 -27
- package/android-action/scripts/crashlytics_symbols.py +4 -0
- package/android-action/scripts/gradle_wrapper.py +2 -1
- package/android-action/scripts/sign_bundle.py +10 -7
- package/backend-action/action.yml +38 -8
- package/backend-action/ensure_certificate.sh +23 -67
- package/backend-action/network_inventory.py +1 -1
- package/backend-action/network_pools.py +17 -25
- package/backend-action/remote_deploy.sh +35 -6
- package/bin/cli.mjs +3 -19
- package/docs/CANDIDATE_ARTIFACTS.md +11 -6
- package/docs/CONFIGURATION.md +3 -33
- package/docs/GRADLE_CACHE.md +8 -3
- package/package.json +17 -8
- package/src/config/build-steps.mjs +2 -1
- package/src/config/transaction.mjs +8 -4
- package/src/config/validation.mjs +10 -1
- package/src/config/workflows.mjs +17 -1
- package/src/install.mjs +65 -37
- package/templates/deploy-backend.yml +6 -1
- package/templates/deploy.yml +63 -78
- package/templates/history.json.gz +0 -0
- package/templates/mobile-candidate.yml +1 -2
- package/action/.daemux-version +0 -1
- package/action/prompts/generate_dependent_fields.prompt.yml +0 -78
- package/action/prompts/generate_descriptions.prompt.yml +0 -62
- package/action/scripts/app_context_scanner.py +0 -239
- package/action/scripts/asc_metadata_applier.py +0 -432
- package/action/scripts/asc_metadata_detector.py +0 -250
- package/action/scripts/autoupdate_check.sh +0 -61
- package/action/scripts/autoupdate_stage.py +0 -62
- package/action/scripts/cert_factory.py +0 -102
- package/action/scripts/certificate_failure.py +0 -47
- package/action/scripts/fixtures/single-size-ios-icon.json +0 -38
- package/action/scripts/metadata_constants.py +0 -102
- package/action/scripts/profile_store.py +0 -87
- package/action/scripts/source_maintenance_fixture.py +0 -58
- package/action/scripts/test_action_step_order.py +0 -83
- package/action/scripts/test_app_context_scanner.py +0 -167
- package/action/scripts/test_app_group_requirements.py +0 -83
- package/action/scripts/test_asc_build_history.py +0 -221
- package/action/scripts/test_asc_builds_prerelease.py +0 -219
- package/action/scripts/test_asc_common_timeouts.py +0 -121
- package/action/scripts/test_asc_metadata_applier.py +0 -990
- package/action/scripts/test_asc_metadata_detector.py +0 -445
- package/action/scripts/test_asc_network_diagnostics.py +0 -92
- package/action/scripts/test_auto_detect.py +0 -492
- package/action/scripts/test_autoupdate_stage.py +0 -107
- package/action/scripts/test_capabilities.py +0 -261
- package/action/scripts/test_certificate_cap_policy.py +0 -72
- package/action/scripts/test_certificate_failure.py +0 -64
- package/action/scripts/test_certificate_request.py +0 -62
- package/action/scripts/test_cfg_resolve_credentials.py +0 -48
- package/action/scripts/test_compute_next_version.py +0 -95
- package/action/scripts/test_compute_next_version_patch_backcompat.py +0 -41
- package/action/scripts/test_compute_next_version_strictness.py +0 -67
- package/action/scripts/test_crashlytics_dsyms.py +0 -211
- package/action/scripts/test_crashlytics_phase_effects.py +0 -30
- package/action/scripts/test_delivery_icons.py +0 -76
- package/action/scripts/test_delivery_preflight.py +0 -354
- package/action/scripts/test_fetch_versions.py +0 -163
- package/action/scripts/test_flutter_native_preparation.py +0 -103
- package/action/scripts/test_ground_truth_floor.py +0 -104
- package/action/scripts/test_keychain.py +0 -145
- package/action/scripts/test_manage_marketing_version.py +0 -134
- package/action/scripts/test_manage_marketing_version_autoroll.py +0 -158
- package/action/scripts/test_manage_marketing_version_floor.py +0 -170
- package/action/scripts/test_manage_marketing_version_match.py +0 -193
- package/action/scripts/test_mmv_409_classifier.py +0 -231
- package/action/scripts/test_mmv_autobump_persist_gate.py +0 -131
- package/action/scripts/test_mmv_decide_create.py +0 -158
- package/action/scripts/test_mmv_floor_check.py +0 -158
- package/action/scripts/test_mmv_floor_crosscheck.py +0 -132
- package/action/scripts/test_mmv_helpers.py +0 -57
- package/action/scripts/test_mmv_testflight_only.py +0 -147
- package/action/scripts/test_mobile_artifact_restore.py +0 -93
- package/action/scripts/test_mobile_artifacts.py +0 -92
- package/action/scripts/test_native_bundle.py +0 -97
- package/action/scripts/test_native_cache.py +0 -37
- package/action/scripts/test_native_dependency_guard.py +0 -116
- package/action/scripts/test_native_dependency_wiring.py +0 -70
- package/action/scripts/test_native_pods.py +0 -151
- package/action/scripts/test_native_pods_diagnostics.py +0 -86
- package/action/scripts/test_native_pods_process.py +0 -41
- package/action/scripts/test_native_pods_retry.py +0 -182
- package/action/scripts/test_native_pods_timeout.py +0 -34
- package/action/scripts/test_native_prepare_evidence.py +0 -76
- package/action/scripts/test_next_build_number.py +0 -207
- package/action/scripts/test_pbxproj_editor.py +0 -153
- package/action/scripts/test_prepare_crashlytics.py +0 -281
- package/action/scripts/test_profile_app_groups.py +0 -103
- package/action/scripts/test_profile_reuse.py +0 -113
- package/action/scripts/test_read_config_auto_detect.py +0 -257
- package/action/scripts/test_registry_managed_signing.py +0 -116
- package/action/scripts/test_resolve_info_plist.py +0 -120
- package/action/scripts/test_resolve_marketing_version.py +0 -298
- package/action/scripts/test_retained_signing_identity.py +0 -110
- package/action/scripts/test_reuse_stale_editable.py +0 -182
- package/action/scripts/test_set_app_store_whats_new.py +0 -71
- package/action/scripts/test_signing_source_boundary.py +0 -82
- package/action/scripts/test_source_maintenance.py +0 -122
- package/action/scripts/test_source_preflight.py +0 -226
- package/action/scripts/test_team_fallback_wiring.py +0 -157
- package/action/scripts/test_team_resolver.py +0 -249
- package/action/scripts/test_testflight_version_slot_wiring.py +0 -75
- package/action/scripts/test_upload_build.py +0 -267
- package/action/scripts/test_upload_checksums.py +0 -74
- package/action/scripts/test_write_marketing_version.py +0 -101
- package/action/scripts/tests_common.py +0 -167
- package/android-action/.daemux-version +0 -1
- package/android-action/scripts/bitrise_deploy.py +0 -160
- package/android-action/scripts/crashlytics_bootstrap_test_support.py +0 -60
- package/android-action/scripts/fixtures/flutter_test_loopback.dart +0 -58
- package/android-action/scripts/flutter_manifest_fixture.py +0 -164
- package/android-action/scripts/test_android_build_diagnostics.py +0 -145
- package/android-action/scripts/test_android_config.py +0 -281
- package/android-action/scripts/test_bitrise_deploy.py +0 -124
- package/android-action/scripts/test_crashlytics_bootstrap.py +0 -97
- package/android-action/scripts/test_crashlytics_prebuild.py +0 -40
- package/android-action/scripts/test_crashlytics_symbols.py +0 -212
- package/android-action/scripts/test_early_play_workflow.py +0 -82
- package/android-action/scripts/test_flutter_archive.py +0 -109
- package/android-action/scripts/test_flutter_archive_cache.py +0 -84
- package/android-action/scripts/test_flutter_archive_setup.py +0 -67
- package/android-action/scripts/test_flutter_archive_size.py +0 -28
- package/android-action/scripts/test_flutter_cache_setup.py +0 -108
- package/android-action/scripts/test_flutter_download_budget.py +0 -145
- package/android-action/scripts/test_flutter_manifest.py +0 -108
- package/android-action/scripts/test_flutter_manifest_scope.py +0 -44
- package/android-action/scripts/test_flutter_obfuscation.py +0 -115
- package/android-action/scripts/test_flutter_origin_retry.py +0 -66
- package/android-action/scripts/test_flutter_release_cache.py +0 -94
- package/android-action/scripts/test_flutter_release_cache_scope.py +0 -49
- package/android-action/scripts/test_flutter_transfer_progress.py +0 -81
- package/android-action/scripts/test_gradle_wrapper.py +0 -261
- package/android-action/scripts/test_play_connect_retry.py +0 -115
- package/android-action/scripts/test_play_inventory.py +0 -98
- package/android-action/scripts/test_play_preflight.py +0 -100
- package/android-action/scripts/test_play_preflight_transport.py +0 -96
- package/android-action/scripts/test_resolve_play_readiness.py +0 -109
- package/android-action/scripts/test_select_jdk.py +0 -213
- package/android-action/scripts/test_sign_bundle.py +0 -82
- package/android-action/scripts/test_version_override.py +0 -153
- package/backend-action/.daemux-version +0 -1
- package/backend-action/certificate_vhost.py +0 -259
- package/backend-action/network_provider_test_fixture.py +0 -30
- package/backend-action/network_test_fixture.py +0 -57
- package/backend-action/nginx_test_fixture.py +0 -98
- package/backend-action/test_certificate_vhost.py +0 -453
- package/backend-action/test_edge_health.py +0 -75
- package/backend-action/test_edge_inputs.py +0 -79
- package/backend-action/test_edge_nginx.py +0 -125
- package/backend-action/test_edge_vhost.py +0 -112
- package/backend-action/test_identity_artifact.py +0 -77
- package/backend-action/test_identity_diagnostics.py +0 -101
- package/backend-action/test_identity_failures.py +0 -56
- package/backend-action/test_network_builtins.py +0 -28
- package/backend-action/test_network_diagnostics.py +0 -77
- package/backend-action/test_network_docker.py +0 -129
- package/backend-action/test_network_fixture_evidence.py +0 -23
- package/backend-action/test_network_inventory.py +0 -241
- package/backend-action/test_network_ipam_gateway.py +0 -46
- package/backend-action/test_network_noop.py +0 -64
- package/backend-action/test_network_owned_inventory.py +0 -128
- package/backend-action/test_network_prepare.py +0 -120
- package/backend-action/test_network_provider.py +0 -162
- package/backend-action/test_network_races.py +0 -73
- package/backend-action/test_network_rule_diagnostics.py +0 -69
- package/backend-action/test_network_runtime.py +0 -49
- package/backend-action/test_network_selected.py +0 -153
- package/backend-action/test_runtime_env.py +0 -229
- package/scripts/lib/checks.mjs +0 -73
- package/scripts/lib/coordination.mjs +0 -39
- package/scripts/lib/discovery.mjs +0 -27
- package/scripts/lib/github.mjs +0 -85
- package/scripts/lib/repository.mjs +0 -82
- package/scripts/lib/state.mjs +0 -39
- package/scripts/upgrade-org.mjs +0 -81
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# gowalk-cicd
|
|
2
2
|
|
|
3
|
-
One installer for iOS TestFlight
|
|
4
|
-
|
|
3
|
+
One installer for iOS TestFlight and Android Google Play delivery, plus the
|
|
4
|
+
optional backend deploy. It supports native Swift/SwiftUI iOS projects, native Kotlin/Gradle
|
|
5
5
|
Android projects, and Flutter apps. Provision encrypted repository secrets, validate a
|
|
6
6
|
task candidate, and promote its release intent. Store builds and uploads run only in GitHub Actions.
|
|
7
7
|
|
|
8
8
|
App-specific workflow settings live in `.gowalk-cicd.yml`. The installer migrates supported
|
|
9
9
|
existing settings once and regenerates managed workflows without replacing custom behavior.
|
|
10
|
-
See [configuration
|
|
10
|
+
See [configuration](docs/CONFIGURATION.md).
|
|
11
11
|
|
|
12
12
|
## Install
|
|
13
13
|
|
|
@@ -23,12 +23,18 @@ Writes three core things into your repo:
|
|
|
23
23
|
- `.github/actions/android-app/` — Android build/sign action (Flutter or Gradle)
|
|
24
24
|
- `.github/workflows/deploy.yml` — workflow that builds and deploys both platforms
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
The installer no longer adds `.github/workflows/deploy-web.yml`. On re-adoption it
|
|
27
|
+
removes a `deploy-web.yml` that is still byte-for-byte the generated file and has no
|
|
28
|
+
overrides in `.gowalk-cicd.yml`; a customized one keeps upgrading (see
|
|
29
|
+
[Flutter web release](#flutter-web-release)).
|
|
30
30
|
|
|
31
|
-
Re-run the same command anytime to pull the latest version.
|
|
31
|
+
Re-run the same command anytime to pull the latest version. The vendored action
|
|
32
|
+
directories then mirror the package: a file the package no longer ships is deleted,
|
|
33
|
+
except the `.daemux-version` markers and any file a workflow under
|
|
34
|
+
`.github/workflows/` still names by path (the installer prints what it kept and
|
|
35
|
+
removed; `--dry-run` deletes nothing). Tests and fixtures are not shipped. A
|
|
36
|
+
workflow the package does not manage that fails to parse is skipped with
|
|
37
|
+
`[warn] skipped .github/workflows/<file>: <code>` instead of aborting the install.
|
|
32
38
|
|
|
33
39
|
Ready task PRs build shipping binaries alongside validation; the protected merge promotes matching
|
|
34
40
|
binaries through the existing store upload paths. See [candidate artifact reuse](docs/CANDIDATE_ARTIFACTS.md)
|
|
@@ -92,6 +98,11 @@ job. This bounds individual cache segments, not the total cache or SDK download,
|
|
|
92
98
|
and keeps existing cache keys. A successfully installed SDK is saved before app
|
|
93
99
|
checks run, so a later test/build failure does not force another cold SDK download.
|
|
94
100
|
Failed setup never saves an SDK cache; pub dependencies retain their job-end save.
|
|
101
|
+
Pull-request runs (`refs/pull/*`, which includes every candidate build) restore these caches
|
|
102
|
+
but never save them; task branches and the default branch still save. When the caller names
|
|
103
|
+
no Flutter version, a committed `.flutter-version` (`x.y.z`, a regular file of at most 64 bytes)
|
|
104
|
+
pins the SDK; a symlink or malformed pin fails with `Invalid project Flutter pin`, and no file
|
|
105
|
+
keeps the channel's latest release.
|
|
95
106
|
|
|
96
107
|
Native dependency preparation uses a committed `Gemfile` and `Gemfile.lock` beside
|
|
97
108
|
the selected iOS project, falling back to the repository root. It installs missing
|
|
@@ -109,9 +120,16 @@ Pods and verifies the selected workspace before release configuration. Preserve
|
|
|
109
120
|
order in customized validation and deployment workflows; updating action directories
|
|
110
121
|
alone cannot repair a configuration step that runs before the action.
|
|
111
122
|
|
|
123
|
+
The iOS action then skips `bundle install` and `pod install` when the Pods are already in
|
|
124
|
+
sync: `Pods/Manifest.lock` equals `Podfile.lock`, the lock's `PODFILE CHECKSUM` matches the
|
|
125
|
+
Podfile, every local `:path:` pod exists, a workspace exists and xcodegen did not just
|
|
126
|
+
generate the project. Its receipt then reports `pods: in_sync`, and its own native Pods
|
|
127
|
+
cache is not restored or saved for that run.
|
|
128
|
+
|
|
112
129
|
## Flutter web release
|
|
113
130
|
|
|
114
|
-
|
|
131
|
+
A repository whose `.gowalk-cicd.yml` customizes `deploy-web.yml` keeps it.
|
|
132
|
+
That workflow runs on changes to Flutter source,
|
|
115
133
|
web assets, package metadata, localization config, or the workflow itself. It
|
|
116
134
|
also supports manual dispatch. The build uses `GITHUB_RUN_NUMBER` as its build
|
|
117
135
|
number and uploads the complete `build/web` directory as a release artifact.
|
|
@@ -211,13 +229,24 @@ wires an nginx vhost + Let's Encrypt cert for the API domain, and health-checks.
|
|
|
211
229
|
Hosts with several existing Let's Encrypt accounts select one deterministically,
|
|
212
230
|
and a domain deploy fails unless its public HTTPS certificate and health route validate.
|
|
213
231
|
Changing a container's published port preserves its existing HTTPS configuration; nginx must accept
|
|
214
|
-
the change, or the previous vhost is restored and the deploy fails.
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
when
|
|
232
|
+
the change, or the previous vhost is restored and the deploy fails.
|
|
233
|
+
When the domain's vhost has exactly one `ssl_certificate`, and that file exists, stays valid for more
|
|
234
|
+
than a day and lists `DNS:<domain>` in its subjectAltName, the deploy runs neither Certbot nor an nginx
|
|
235
|
+
reload and logs `certificate state=current`. Otherwise an existing certificate is installed for the
|
|
236
|
+
domain (repairing older HTTP-only vhosts too) or a new one is issued, both with `certbot --nginx`.
|
|
237
|
+
Every Certbot call runs under `flock -w 900 /run/gowalk-certbot.lock`, so deploys on one host take
|
|
238
|
+
turns; when the host's renew timer holds Certbot's own lock, the call retries every 10 s for up to
|
|
239
|
+
10 minutes. Vhost writes with their nginx test and reload, and the host port reservation, run under
|
|
240
|
+
the host nginx lock `/run/app-robot-nginx.lock` (`flock -w 120`), which the panel's domain applier also
|
|
241
|
+
takes. After a healthy deploy the replaced build's images are pruned
|
|
242
|
+
(`docker image prune -f --filter label=com.docker.compose.project=<app>`); a refusal because another
|
|
243
|
+
prune is running defers it to the next deploy.
|
|
244
|
+
|
|
245
|
+
Each app gets one stable loopback port, reserved once in the host's `.env` as
|
|
246
|
+
`BACKEND_HTTP_PORT` (starting at `20000 + cksum(app) % 10000`, skipping ports other apps reserved or
|
|
247
|
+
already bound). A Compose file opts in by publishing `127.0.0.1:${BACKEND_HTTP_PORT:-}:<container-port>`;
|
|
248
|
+
a redeploy then leaves the nginx upstream unchanged. A literal `127.0.0.1:<port>:<container-port>`
|
|
249
|
+
keeps working as before.
|
|
221
250
|
|
|
222
251
|
Requirements on the consumer repo:
|
|
223
252
|
|
|
@@ -228,6 +257,11 @@ Requirements on the consumer repo:
|
|
|
228
257
|
never bake secrets in. A generated `.env` (with `POSTGRES_PASSWORD`) is created
|
|
229
258
|
on the host on first deploy and preserved across deploys (rsync excludes it).
|
|
230
259
|
- Repo **secret** `BACKEND_DEPLOY_SSH_KEY` (a private key with access to the host).
|
|
260
|
+
- Repo **variable** `BACKEND_DEPLOY_KNOWN_HOSTS` (recommended): `known_hosts` lines for the exact
|
|
261
|
+
host string the workflow connects to (`BACKEND_DEPLOY_HOST`, for example
|
|
262
|
+
`138.197.36.107 ssh-ed25519 AAAA...`). Deploys then require that key
|
|
263
|
+
(`StrictHostKeyChecking=yes`). While it is empty the job trusts `ssh-keyscan` and prints one
|
|
264
|
+
`backend_host_key_unpinned` warning.
|
|
231
265
|
- Repo **secret** `BACKEND_RUNTIME_ENV` (optional): newline-delimited `KEY=value`
|
|
232
266
|
runtime secrets. The action writes it as mode 0600 on the host and passes it
|
|
233
267
|
to Compose without copying values into the repository or action log.
|
|
@@ -238,10 +272,15 @@ Requirements on the consumer repo:
|
|
|
238
272
|
Malformed or ambiguous multiline structures refuse before deployment. Transport is bounded
|
|
239
273
|
to 1 MiB of UTF-8 input and 512 KiB per value, uses private SSH stdin, and atomically replaces
|
|
240
274
|
`.runtime.env`; application sync preserves the last installed file if validation fails.
|
|
241
|
-
- Repo **
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
275
|
+
- Repo **variable** `BACKEND_API_DOMAIN`: the bound API host name (for example
|
|
276
|
+
`api.<app-domain>`); its DNS A record must point at the host for the cert.
|
|
277
|
+
**Backend Deploy runs only when it is set**: a repository with no bound backend
|
|
278
|
+
origin holds no deploy key, so `deploy-backend.yml` is skipped and the feature-branch
|
|
279
|
+
`backend-preview` deploy ends with a `backend_origin_unbound` notice.
|
|
280
|
+
- Repo **variables** (optional): `BACKEND_APP_NAME` (defaults to the repo name),
|
|
281
|
+
`BACKEND_HEALTH_PATH` (default `/health`), `BACKEND_DEPLOY_HOST` (default
|
|
282
|
+
`138.197.36.107`). The action refuses an `api-domain` that is not a lowercase DNS
|
|
283
|
+
name, a `health-path` outside `/[A-Za-z0-9_./-]*` and a malformed `cert-email`.
|
|
245
284
|
|
|
246
285
|
The action directory is canonical here (like the iOS/Android actions): edit it in
|
|
247
286
|
`backend-action/`, never in a consumer's vendored copy.
|
|
@@ -354,7 +393,17 @@ rather than a failure, so it reads as a flake rather than an out-of-memory.
|
|
|
354
393
|
|
|
355
394
|
Before building, the Android job caps `-Xmx` at 4 GB and `MaxMetaspaceSize` at
|
|
356
395
|
2 GB in the checkout, with a `::warning::` naming the original value. Projects
|
|
357
|
-
already at or below those numbers are left untouched.
|
|
396
|
+
already at or below those numbers are left untouched. A runner with at least
|
|
397
|
+
16 GiB of `MemTotal` (for example an 8-core `ANDROID_RUNNER`) keeps the app's own
|
|
398
|
+
settings. Linux only.
|
|
399
|
+
|
|
400
|
+
### Android runner size
|
|
401
|
+
|
|
402
|
+
The Android job runs on `${{ vars.ANDROID_RUNNER || 'ubuntu-24.04' }}`. Set the
|
|
403
|
+
repository or organization variable `ANDROID_RUNNER` to a larger hosted runner
|
|
404
|
+
label to shorten the release build; unset it before deleting that runner. The
|
|
405
|
+
variable is not a build input: setting, changing or removing it never discards a
|
|
406
|
+
candidate binary.
|
|
358
407
|
|
|
359
408
|
### When Play will not accept a release for review
|
|
360
409
|
|
|
@@ -428,12 +477,11 @@ the situation and whose **message** is one line of JSON carrying a versioned
|
|
|
428
477
|
| `source_maintenance_pending` | `gowalk-cicd/source-maintenance-pending.v1` | `repo`, `base_sha`, `head_sha`, `branch`, `run_id` |
|
|
429
478
|
| `apple_build_upload_failed` (error) | `gowalk-cicd/apple-build-upload-failed.v2` | `category`, `stage`, `receipt_available`, receipt identifiers (`cfBundleVersion`, `upload_id`, `file_id`, `state`, `provider_status`, `provider_code`, `provider_pointer`), `action` |
|
|
430
479
|
| `flutter_download_failed` (error) | `gowalk-cicd/flutter-download-failed.v1` | `phase`, `curl_exit`, `http_status`, `proxy_status`, `attempts`, `retained_bytes` |
|
|
431
|
-
| `android_build_failed` (error) | `gowalk-cicd/android-build-failed.v1` | `phase`, `exit_code`, `signals` (fixed observed patterns; empty means unclassified) |
|
|
480
|
+
| `android_build_failed` (error) | `gowalk-cicd/android-build-failed.v1` | `phase`, `exit_code`, `signals` (fixed observed patterns; empty means unclassified), optional `hosts`, `artifacts` and `excerpt` (error lines plus the next line, URL userinfo removed, at most 4 KB) |
|
|
432
481
|
|
|
433
|
-
Android release compilers
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
with `phase` and `elapsed_seconds`; successful compiler output is not republished.
|
|
482
|
+
Android release compilers stream their output to the job log inside `::stop-commands::` markers,
|
|
483
|
+
so no build line can act as a workflow command. Their failure signals describe observed error
|
|
484
|
+
patterns, not retry permission or a unique root cause.
|
|
437
485
|
|
|
438
486
|
Native bundle and Pods failures emit `native_prepare_failed` with schema
|
|
439
487
|
`gowalk-cicd/native-prepare-failed.v1`, `phase`, a fixed refusal `code` and fixed observed `signals`.
|
|
@@ -565,10 +613,11 @@ reliably fit. The failure surfaces far from its cause:
|
|
|
565
613
|
zip I/O error: No space left on device
|
|
566
614
|
```
|
|
567
615
|
|
|
568
|
-
The Android job
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
and
|
|
616
|
+
The Android job prints `df -h /` and does nothing more when `/` already has
|
|
617
|
+
40 GB or more free (a larger runner). Otherwise it removes the preinstalled
|
|
618
|
+
toolchains a Flutter build never uses (.NET, GHC, PowerShell, Swift, Chromium)
|
|
619
|
+
and prunes Docker images in the background, reclaiming roughly 25 GB while the
|
|
620
|
+
JDK, Gradle restore and Flutter setup run. Linux only. npm survives on purpose: the
|
|
572
621
|
[Crashlytics symbol upload](#crashlytics-symbol-delivery-firebase_app_id) runs
|
|
573
622
|
the Firebase CLI through `npx`.
|
|
574
623
|
|
|
@@ -621,56 +670,12 @@ Both stores pick up per-locale release notes from committed files:
|
|
|
621
670
|
the deploy workflow passes it to the Play upload and the notes ship with
|
|
622
671
|
every release; when absent, releases upload without notes as before.
|
|
623
672
|
|
|
624
|
-
## Android delivery via Bitrise (alternative mode)
|
|
625
|
-
|
|
626
|
-
Use this when the Android **upload keystore password lives in Bitrise** (not in
|
|
627
|
-
the repo) — the GitHub runner then cannot sign the AAB locally. In this mode the
|
|
628
|
-
Android job triggers a Bitrise workflow (which holds the keystore + Play
|
|
629
|
-
service-account secrets) over the Bitrise API and waits for it, mirroring the
|
|
630
|
-
build result back into the GitHub Actions run. iOS still ships via GitHub
|
|
631
|
-
Actions as normal.
|
|
632
|
-
|
|
633
|
-
Enable it by committing `creds/bitrise.json`:
|
|
634
|
-
|
|
635
|
-
```json
|
|
636
|
-
{
|
|
637
|
-
"enabled": true,
|
|
638
|
-
"app_slug": "8b2a7a24-....",
|
|
639
|
-
"workflow": "android-deploy",
|
|
640
|
-
"branch": "main",
|
|
641
|
-
"api_token": "bitpat_...."
|
|
642
|
-
}
|
|
643
|
-
```
|
|
644
|
-
|
|
645
|
-
- `app_slug` — the Bitrise app slug (from the app's Bitrise URL or
|
|
646
|
-
`GET https://api.bitrise.io/v0.1/apps`).
|
|
647
|
-
- `workflow` — the Bitrise workflow that builds, signs, and runs
|
|
648
|
-
`google-play-deploy` (default `android-deploy`).
|
|
649
|
-
- `branch` — optional; defaults to the pushed ref.
|
|
650
|
-
- `api_token` — a Bitrise personal access token. Committing it to a **private**
|
|
651
|
-
repo's `creds/` follows the same trust model as the ASC `.p8`. For non-private
|
|
652
|
-
repos, omit it here and set the `BITRISE_API_TOKEN` Actions secret instead.
|
|
653
|
-
|
|
654
|
-
When `creds/bitrise.json` is present with `enabled: true`, the local
|
|
655
|
-
build/sign/upload steps are skipped and `bitrise_deploy.py` drives the Bitrise
|
|
656
|
-
build; otherwise the local path above runs unchanged.
|
|
657
|
-
|
|
658
|
-
The Bitrise `android-deploy` workflow must produce a versionCode higher than
|
|
659
|
-
what is already on Play. The convention used by this fleet is a `+200` offset
|
|
660
|
-
over `$BITRISE_BUILD_NUMBER` via a `change-android-versioncode-and-versionname`
|
|
661
|
-
step, with the versionName read from `pubspec.yaml`.
|
|
662
|
-
|
|
663
673
|
## Sharing one distribution cert across a team's apps
|
|
664
674
|
|
|
665
|
-
The iOS action
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
its cached cert already revoked by a sibling, mints a new one, and revokes
|
|
670
|
-
another. The symptom is a "Your Certificate Has Been Revoked" email on nearly
|
|
671
|
-
every deploy.
|
|
672
|
-
|
|
673
|
-
Fix: apps in the same Apple team should **share one cert**. A fleet registry can
|
|
675
|
+
The iOS action signs with the retained Apple Distribution identity in `creds/`
|
|
676
|
+
(cert alive + NotAfter > 30 days) and never creates or revokes a certificate.
|
|
677
|
+
Apple caps a team at **2** distribution certs, so apps in the same Apple team
|
|
678
|
+
should **share one cert**. A fleet registry can
|
|
674
679
|
provision the same `creds/cert.p12` + `creds/cert.meta.json` into every repo of
|
|
675
680
|
that team (an Apple Distribution cert is team-scoped, not app-scoped, so one
|
|
676
681
|
cert signs them all). Registry provisioning must also write
|
|
@@ -683,9 +688,10 @@ The marker is a fail-closed ownership boundary: the action may reuse the
|
|
|
683
688
|
identity and create per-app provisioning profiles, but it never creates,
|
|
684
689
|
replaces, or revokes a registry-managed distribution certificate. Missing,
|
|
685
690
|
partially written, corrupt, expired, Apple-revoked, or resource-ID/P12-mismatched
|
|
686
|
-
managed material aborts with a reconciliation error.
|
|
687
|
-
marker
|
|
688
|
-
|
|
691
|
+
managed material aborts with a reconciliation error. A legacy repo without the
|
|
692
|
+
marker whose retained identity is missing or unusable fails with
|
|
693
|
+
`apple_signing_identity_required` (`gowalk-cicd/apple-signing-identity-required.v1`)
|
|
694
|
+
and keeps its existing signing files.
|
|
689
695
|
|
|
690
696
|
## How it works
|
|
691
697
|
|
|
@@ -770,9 +776,7 @@ package produces — the Android App Bundle and the iOS archive — is compiled
|
|
|
770
776
|
config key that turns it off. Native Swift and Kotlin/Gradle apps are
|
|
771
777
|
unaffected: the flag belongs to the Dart compiler and they have no Dart code.
|
|
772
778
|
Flutter web builds are also untouched — `flutter build web` has no such flag;
|
|
773
|
-
dart2js minifies release output instead.
|
|
774
|
-
[Bitrise](#android-delivery-via-bitrise-alternative-mode) is built by Bitrise's
|
|
775
|
-
workflow, not by this action; put the same two flags in that workflow.
|
|
779
|
+
dart2js minifies release output instead.
|
|
776
780
|
|
|
777
781
|
What it does: the Dart AOT compiler replaces class, function and library names
|
|
778
782
|
with short random identifiers, so the app's Dart symbols cannot be read out of
|
|
@@ -877,19 +881,16 @@ preserving each app's custom checks and artifact retention settings. An isolated
|
|
|
877
881
|
4. **Computes the next build number** by querying ASC for the latest uploaded
|
|
878
882
|
build and incrementing.
|
|
879
883
|
5. **Provisions signing** at runtime: reconciles the App ID's capabilities with
|
|
880
|
-
the target's entitlements (see below), then
|
|
881
|
-
Distribution
|
|
882
|
-
`CI-<bundle_id
|
|
883
|
-
|
|
884
|
+
the target's entitlements (see below), then signs with the retained Apple
|
|
885
|
+
Distribution identity and the per-target App Store provisioning profile named
|
|
886
|
+
`CI-<bundle_id>` that App Store Connect already holds, creating the profile
|
|
887
|
+
when it is missing or stale. Patches the `.pbxproj` to use Manual signing
|
|
888
|
+
against those profiles.
|
|
884
889
|
6. **Archives** with `xcodebuild archive`, exports the IPA, and uploads via
|
|
885
890
|
Apple's build-upload REST API.
|
|
886
891
|
7. **Sets "What's New"** on every declared localization (reads
|
|
887
892
|
`fastlane/metadata/ios/<locale>/release_notes.txt` if present, or from the
|
|
888
893
|
`app-store-whats-new` input).
|
|
889
|
-
8. **Auto-fills empty App Store metadata** (name, subtitle, keywords,
|
|
890
|
-
description, promotional text, what's new) via GitHub Models AI, on every
|
|
891
|
-
locale that has gaps. See [AI metadata auto-fill](#ai-metadata-auto-fill)
|
|
892
|
-
below.
|
|
893
894
|
|
|
894
895
|
The iOS action requires only the p8. Everything else is derived.
|
|
895
896
|
|
|
@@ -919,17 +920,16 @@ Before creating a profile, the action reads the target's
|
|
|
919
920
|
ID — Push Notifications, Associated Domains, HealthKit, SiriKit, HomeKit,
|
|
920
921
|
network extensions and the other plain on/off toggles.
|
|
921
922
|
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
before a capability was turned on — whether by this action or
|
|
926
|
-
developer portal —
|
|
927
|
-
failing on a capability the App ID already has.
|
|
923
|
+
An existing `CI-<bundle_id>` profile is found by name and reused only when it
|
|
924
|
+
is ACTIVE, issued for the current certificate, more than 30 days from expiry,
|
|
925
|
+
and carries those same entitlements. Otherwise it is deleted and regenerated, so
|
|
926
|
+
a profile issued before a capability was turned on — whether by this action or
|
|
927
|
+
by you in the developer portal — is never reused.
|
|
928
928
|
|
|
929
929
|
App Groups require registration and assignment to each participating App ID through
|
|
930
930
|
the account's Apple Developer console. The action reads the literal identifiers from
|
|
931
|
-
each archive target's entitlements and verifies their exact membership in both
|
|
932
|
-
and fresh profiles. A stale
|
|
931
|
+
each archive target's entitlements and verifies their exact membership in both reused
|
|
932
|
+
and fresh profiles. A stale profile regenerates; a fresh profile missing a required group
|
|
933
933
|
fails before installation with `apple_app_groups_required`, schema
|
|
934
934
|
`gowalk-cicd/apple-app-groups-required.v1`, containing the bundle ID and missing groups.
|
|
935
935
|
Complete those assignments through the scoped console and rerun CI. This check creates
|
|
@@ -948,63 +948,6 @@ Two other classes of capability are **not** enabled automatically, and each gets
|
|
|
948
948
|
→ <your App ID>**. Until then the archive fails with `Provisioning profile
|
|
949
949
|
"CI-<bundle>" doesn't include the App Attest capability`.
|
|
950
950
|
|
|
951
|
-
## AI metadata auto-fill
|
|
952
|
-
|
|
953
|
-
On every run, after the TestFlight upload succeeds, the action:
|
|
954
|
-
|
|
955
|
-
1. Queries App Store Connect for every `appInfoLocalization` and
|
|
956
|
-
`appStoreVersionLocalization` on the editable version.
|
|
957
|
-
2. Computes the set of empty fields per locale (URL fields are always
|
|
958
|
-
skipped — you must set those manually in ASC).
|
|
959
|
-
3. Scans your repo for context (README, Info.plist, dependency files, top
|
|
960
|
-
Swift files) and feeds it to `openai/gpt-4o` via GitHub Models with a
|
|
961
|
-
strict JSON schema.
|
|
962
|
-
4. PATCHes only the fields that were empty — never overwrites existing
|
|
963
|
-
content.
|
|
964
|
-
|
|
965
|
-
Fully idempotent: a second run with no empty fields skips the AI step
|
|
966
|
-
entirely (zero requests, zero PATCHes).
|
|
967
|
-
|
|
968
|
-
### Requirement: `permissions: models: read`
|
|
969
|
-
|
|
970
|
-
`actions/ai-inference` needs the `models: read` permission. The template
|
|
971
|
-
workflow written by `npx gowalk-cicd` already includes it:
|
|
972
|
-
|
|
973
|
-
```yaml
|
|
974
|
-
permissions:
|
|
975
|
-
contents: read
|
|
976
|
-
models: read
|
|
977
|
-
```
|
|
978
|
-
|
|
979
|
-
**Existing consumers must add this block to their `deploy.yml`** at the
|
|
980
|
-
workflow or job level. If it's missing, the AI step fails open with a
|
|
981
|
-
`::warning::` and the rest of the workflow continues unaffected.
|
|
982
|
-
|
|
983
|
-
### Rate limits
|
|
984
|
-
|
|
985
|
-
GitHub Models free tier allows **50 `gpt-4o` requests per day** (10 per
|
|
986
|
-
minute). One workflow run = one request. If you run many apps from the
|
|
987
|
-
same GitHub account, or trigger several builds per day, switch to the
|
|
988
|
-
cheaper mini model:
|
|
989
|
-
|
|
990
|
-
```yaml
|
|
991
|
-
- uses: ./.github/actions/swift-app
|
|
992
|
-
with:
|
|
993
|
-
ai-metadata-model: openai/gpt-4o-mini
|
|
994
|
-
```
|
|
995
|
-
|
|
996
|
-
`gpt-4o-mini` has a much higher free-tier quota.
|
|
997
|
-
|
|
998
|
-
### Disabling AI metadata
|
|
999
|
-
|
|
1000
|
-
Pass `ai-metadata: 'false'` to skip the AI steps entirely:
|
|
1001
|
-
|
|
1002
|
-
```yaml
|
|
1003
|
-
- uses: ./.github/actions/swift-app
|
|
1004
|
-
with:
|
|
1005
|
-
ai-metadata: 'false'
|
|
1006
|
-
```
|
|
1007
|
-
|
|
1008
951
|
## Update
|
|
1009
952
|
|
|
1010
953
|
```bash
|
|
@@ -1012,7 +955,8 @@ npx --yes gowalk-cicd
|
|
|
1012
955
|
```
|
|
1013
956
|
|
|
1014
957
|
Overwrites both vendored actions and `.github/workflows/deploy.yml` with the
|
|
1015
|
-
latest versions
|
|
958
|
+
latest versions, and deletes vendored files the package no longer ships (see
|
|
959
|
+
[Install](#install)). Because the actions are vendored locally, builds use the
|
|
1016
960
|
reviewed copy in your app repository; updates arrive through this npm package.
|
|
1017
961
|
|
|
1018
962
|
## Override config (rare)
|
|
@@ -1040,22 +984,14 @@ common ones:
|
|
|
1040
984
|
| `bundle-id` | Override the auto-detected bundle identifier |
|
|
1041
985
|
| `team-id` | Override the auto-detected team ID |
|
|
1042
986
|
| `app-store-apple-id` | Numeric ASC app ID (override auto-lookup) |
|
|
1043
|
-
| `certificate-cap-policy` |
|
|
987
|
+
| `certificate-cap-policy` | Deprecated and ignored: CI never creates or revokes certificates. |
|
|
1044
988
|
| `run-tests` | `false` to skip the simulator test stage |
|
|
1045
989
|
| `uses-non-exempt-encryption` | Value for `ITSAppUsesNonExemptEncryption` |
|
|
1046
990
|
| `archive` | `false` to build-only (PR runs without secrets) |
|
|
1047
991
|
| `upload` | `false` to archive but not upload to TestFlight |
|
|
1048
992
|
| `manage-app-store-version` | `false` to upload without creating/editing the App Store release slot |
|
|
1049
993
|
| `app-store-whats-new` | Inline "What's New" text (overrides files) |
|
|
1050
|
-
| `ai-metadata` |
|
|
1051
|
-
| `ai-metadata-model` | GitHub Models model id (default `openai/gpt-4o`) |
|
|
1052
|
-
|
|
1053
|
-
Certificate creation sends the complete PEM CSR in Apple's `csrContent` field, including its framing and newlines.
|
|
1054
|
-
Certificate creation refusals emit `apple_certificate_rejected` with schema
|
|
1055
|
-
`gowalk-cicd/apple-certificate-rejected.v1`, `operation`, `http_status`, `reason` and `error_codes`.
|
|
1056
|
-
HTTP 409 is classified as `certificate_limit` only when Apple's returned detail identifies the limit;
|
|
1057
|
-
otherwise it remains `unclassified_conflict`. Codes come from a fixed allowlist. Raw provider text and
|
|
1058
|
-
CSR data are excluded. Neither outcome permits automatic certificate deletion or another creation attempt.
|
|
994
|
+
| `ai-metadata`, `ai-metadata-model` | Deprecated and ignored: the action no longer writes App Store metadata with AI. |
|
|
1059
995
|
|
|
1060
996
|
## First-time app setup
|
|
1061
997
|
|
|
@@ -1067,10 +1003,9 @@ inside GitHub Actions.
|
|
|
1067
1003
|
Once the app exists, all subsequent builds and uploads are fully automated via
|
|
1068
1004
|
the ASC API key.
|
|
1069
1005
|
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
commits any completed cache files, then re-raises the failure so the private key is not lost.
|
|
1006
|
+
CI never creates, lists for deletion or revokes an Apple Distribution certificate; it
|
|
1007
|
+
signs only with the retained identity (see
|
|
1008
|
+
[Sharing one distribution cert](#sharing-one-distribution-cert-across-a-teams-apps)).
|
|
1074
1009
|
|
|
1075
1010
|
## Troubleshooting
|
|
1076
1011
|
|
|
@@ -1162,29 +1097,13 @@ generated pbxproj). Either move `MARKETING_VERSION` under
|
|
|
1162
1097
|
`settings.base` in `project.yml`, or pin
|
|
1163
1098
|
`marketing-version-auto-bump: 'none'` and bump manually.
|
|
1164
1099
|
|
|
1165
|
-
##
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
`gowalk-cicd
|
|
1170
|
-
`.
|
|
1171
|
-
|
|
1172
|
-
on a verified task branch (under both `.github/actions/swift-app/` and
|
|
1173
|
-
`.github/actions/android-app/`).
|
|
1174
|
-
`.github/workflows/deploy.yml` is NEVER auto-committed — see
|
|
1175
|
-
"deploy.yml is not auto-updated" below.
|
|
1176
|
-
|
|
1177
|
-
| Aspect | Behaviour |
|
|
1178
|
-
|--------|-----------|
|
|
1179
|
-
| Trigger | Push to default branch only (PR / branch runs do nothing) |
|
|
1180
|
-
| Landing | The app session adopts the exact receipt on its current task branch and uses the protected PR |
|
|
1181
|
-
| Isolation | CI leaves HEAD and worktree bytes intact; no default-branch push or rebase |
|
|
1182
|
-
| Candidates | Action updates and later version changes have separate verified receipts |
|
|
1183
|
-
| Failure mode | npm discovery remains optional; unconfirmed source preservation fails the job |
|
|
1184
|
-
|
|
1185
|
-
The shipped `deploy.yml` watches only the release intent. Adopting an action-directory
|
|
1186
|
-
update on its own therefore does not launch another mobile upload. Review and adopt the template
|
|
1187
|
-
as well as the action directories to enable this behavior in an existing consumer.
|
|
1100
|
+
## Updates
|
|
1101
|
+
|
|
1102
|
+
CI never updates the vendored actions: the `auto-update` input is deprecated and
|
|
1103
|
+
ignored. A repository adopts a new release only when its task runs
|
|
1104
|
+
`npx --yes gowalk-cicd` and lands the result through the protected PR. The
|
|
1105
|
+
`.daemux-version` markers the installer writes name the release the vendored
|
|
1106
|
+
actions came from.
|
|
1188
1107
|
|
|
1189
1108
|
### deploy.yml is not auto-updated
|
|
1190
1109
|
|
|
@@ -1194,9 +1113,9 @@ of `contents: write` — this is a built-in safeguard against CI
|
|
|
1194
1113
|
self-modification. When a new version of `gowalk-cicd`
|
|
1195
1114
|
requires `deploy.yml` schema changes (e.g., new permissions, new
|
|
1196
1115
|
paths-ignore entries), the action's release notes will call this out
|
|
1197
|
-
and the app session runs the
|
|
1116
|
+
and the app session runs the `npx --yes gowalk-cicd` adoption in its task
|
|
1198
1117
|
workspace, preserving app-specific workflow inputs and landing the full change through
|
|
1199
|
-
its checked PR.
|
|
1118
|
+
its checked PR.
|
|
1200
1119
|
|
|
1201
1120
|
Changes that need that manual run:
|
|
1202
1121
|
|
|
@@ -1207,24 +1126,6 @@ Changes that need that manual run:
|
|
|
1207
1126
|
passed to both actions. Until it is, setting the variable does nothing.
|
|
1208
1127
|
See [Crashlytics symbol upload](#crashlytics-symbol-delivery-firebase_app_id).
|
|
1209
1128
|
|
|
1210
|
-
### Opt out
|
|
1211
|
-
|
|
1212
|
-
Pin the vendored copy by passing `auto-update: 'false'` to the action:
|
|
1213
|
-
|
|
1214
|
-
```yaml
|
|
1215
|
-
- uses: ./.github/actions/swift-app
|
|
1216
|
-
with:
|
|
1217
|
-
auto-update: 'false'
|
|
1218
|
-
```
|
|
1219
|
-
|
|
1220
|
-
### First-run bootstrap
|
|
1221
|
-
|
|
1222
|
-
The marker is written by `npx gowalk-cicd` itself. A repo
|
|
1223
|
-
without a marker (e.g. an old hand-vendored copy) will be treated as
|
|
1224
|
-
out-of-date on its first run, after which updates land incrementally.
|
|
1225
|
-
Run `npx --yes gowalk-cicd` once locally if you want to skip
|
|
1226
|
-
even that first auto-bootstrap.
|
|
1227
|
-
|
|
1228
1129
|
## License
|
|
1229
1130
|
|
|
1230
1131
|
MIT
|