gowalk-cicd 1.0.4 → 1.0.5
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
CHANGED
|
@@ -147,7 +147,7 @@ configuration for either:
|
|
|
147
147
|
|---|---|---|
|
|
148
148
|
| Detected by | `pubspec.yaml` at the repo root | `settings.gradle(.kts)` + `gradlew` at the root or under `android/` |
|
|
149
149
|
| App module | `android/app` | the one module applying `com.android.application` (version-catalog aliases are resolved; a module named `app` wins a tie against a wear/automotive sibling) |
|
|
150
|
-
| Tests (`run-tests`) | `flutter analyze` + `flutter test` |
|
|
150
|
+
| Tests (`run-tests`) | `flutter analyze` + `flutter test` | `gradlew test` (all variants, all modules) |
|
|
151
151
|
| Build | `flutter build appbundle --release` | `<module>:bundleRelease` |
|
|
152
152
|
| Toolchain installed | Flutter + JDK 17 | JDK 21 only |
|
|
153
153
|
|
package/action/.daemux-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.5
|
|
@@ -52,8 +52,15 @@ from cfg_io import log, notice
|
|
|
52
52
|
APP_PRODUCT_TYPE = "com.apple.product-type.application"
|
|
53
53
|
# Timeouts (seconds) — xcodebuild can hang on missing toolchains or
|
|
54
54
|
# package resolution. CI should fail fast rather than spin forever.
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
#
|
|
56
|
+
# The first xcodebuild invocation on a cold runner also resolves the Swift
|
|
57
|
+
# Package Manager graph, and a project that depends on firebase-ios-sdk spends
|
|
58
|
+
# minutes cloning before it prints a single scheme. That is legitimate work,
|
|
59
|
+
# not a hang, so `-list` gets a budget that survives it and a one-shot
|
|
60
|
+
# pre-resolution retry (see _list_schemes) rather than a tighter deadline.
|
|
61
|
+
LIST_TIMEOUT = 180
|
|
62
|
+
SETTINGS_TIMEOUT = 300
|
|
63
|
+
RESOLVE_TIMEOUT = 900
|
|
57
64
|
|
|
58
65
|
# Process-local caches keyed by (project, workspace_file) or
|
|
59
66
|
# (project, workspace_file, scheme, configuration). Cleared between test
|
|
@@ -221,6 +228,39 @@ def _pick_by_basename(matches: list[Path], workspace: Path, label: str) -> Path:
|
|
|
221
228
|
return matches[0]
|
|
222
229
|
|
|
223
230
|
|
|
231
|
+
def _resolve_package_dependencies(
|
|
232
|
+
workspace: Path, project: str, workspace_file: str
|
|
233
|
+
) -> bool:
|
|
234
|
+
"""Resolve the SPM graph once so later xcodebuild calls are cheap.
|
|
235
|
+
|
|
236
|
+
Returns True when resolution finished (regardless of exit status — a
|
|
237
|
+
project with no packages still exits cleanly and a partial resolve may
|
|
238
|
+
be enough for ``-list``), False when it could not be run at all.
|
|
239
|
+
"""
|
|
240
|
+
cmd = ["xcodebuild", "-resolvePackageDependencies"]
|
|
241
|
+
if workspace_file:
|
|
242
|
+
cmd += ["-workspace", workspace_file]
|
|
243
|
+
elif project:
|
|
244
|
+
cmd += ["-project", project]
|
|
245
|
+
else:
|
|
246
|
+
return False
|
|
247
|
+
log("auto-detect: pre-resolving Swift package dependencies")
|
|
248
|
+
try:
|
|
249
|
+
result = subprocess.run(
|
|
250
|
+
cmd, cwd=str(workspace), capture_output=True, text=True,
|
|
251
|
+
timeout=RESOLVE_TIMEOUT,
|
|
252
|
+
)
|
|
253
|
+
except (OSError, subprocess.TimeoutExpired) as exc:
|
|
254
|
+
log(f"auto-detect: xcodebuild -resolvePackageDependencies failed: {exc!r}")
|
|
255
|
+
return False
|
|
256
|
+
if result.returncode != 0:
|
|
257
|
+
log(
|
|
258
|
+
f"auto-detect: xcodebuild -resolvePackageDependencies returned "
|
|
259
|
+
f"{result.returncode}: {result.stderr.strip()[:500]}"
|
|
260
|
+
)
|
|
261
|
+
return True
|
|
262
|
+
|
|
263
|
+
|
|
224
264
|
def _list_schemes(
|
|
225
265
|
workspace: Path, project: str, workspace_file: str
|
|
226
266
|
) -> Optional[list[str]]:
|
|
@@ -243,7 +283,27 @@ def _list_schemes(
|
|
|
243
283
|
cmd, cwd=str(workspace), capture_output=True, text=True,
|
|
244
284
|
timeout=LIST_TIMEOUT,
|
|
245
285
|
)
|
|
246
|
-
except
|
|
286
|
+
except subprocess.TimeoutExpired as exc:
|
|
287
|
+
# Almost always SPM resolution rather than a hang: `-list` implicitly
|
|
288
|
+
# resolves the package graph, and a cold Firebase/GoogleSignIn clone
|
|
289
|
+
# outlasts any deadline short enough to still catch a real hang. Pay
|
|
290
|
+
# for the resolve once, explicitly, then retry. Swallowing this is what
|
|
291
|
+
# produced the downstream "MARKETING_VERSION for scheme=" failure --
|
|
292
|
+
# an empty scheme reads as "project has none", not "we never asked".
|
|
293
|
+
log(f"auto-detect: xcodebuild -list timed out: {exc!r}")
|
|
294
|
+
if not _resolve_package_dependencies(workspace, project, workspace_file):
|
|
295
|
+
_list_cache[key] = None
|
|
296
|
+
return None
|
|
297
|
+
try:
|
|
298
|
+
result = subprocess.run(
|
|
299
|
+
cmd, cwd=str(workspace), capture_output=True, text=True,
|
|
300
|
+
timeout=LIST_TIMEOUT,
|
|
301
|
+
)
|
|
302
|
+
except (OSError, subprocess.TimeoutExpired) as retry_exc:
|
|
303
|
+
log(f"auto-detect: xcodebuild -list failed after resolve: {retry_exc!r}")
|
|
304
|
+
_list_cache[key] = None
|
|
305
|
+
return None
|
|
306
|
+
except OSError as exc:
|
|
247
307
|
log(f"auto-detect: xcodebuild -list failed: {exc!r}")
|
|
248
308
|
_list_cache[key] = None
|
|
249
309
|
return None
|
|
@@ -9,6 +9,7 @@ All tests run offline. xcodebuild invocations are stubbed through
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
11
|
import json
|
|
12
|
+
import subprocess
|
|
12
13
|
import sys
|
|
13
14
|
import tempfile
|
|
14
15
|
import unittest
|
|
@@ -318,6 +319,54 @@ class AutoDetectSchemeTests(unittest.TestCase):
|
|
|
318
319
|
scheme = auto_detect.auto_detect_scheme(root, "Proj.xcodeproj", "")
|
|
319
320
|
self.assertIsNone(scheme)
|
|
320
321
|
|
|
322
|
+
def test_resolves_packages_and_retries_when_list_times_out(self):
|
|
323
|
+
# `-list` implicitly resolves the SPM graph, so a cold runner cloning
|
|
324
|
+
# firebase-ios-sdk blows the deadline on the first call. Treating that
|
|
325
|
+
# as "no schemes" is what left SCHEME empty and failed the build much
|
|
326
|
+
# later, on an unrelated-looking MARKETING_VERSION error.
|
|
327
|
+
calls: list[str] = []
|
|
328
|
+
|
|
329
|
+
def fake_run(cmd, **kw):
|
|
330
|
+
if "-resolvePackageDependencies" in cmd:
|
|
331
|
+
calls.append("resolve")
|
|
332
|
+
result = mock.MagicMock()
|
|
333
|
+
result.returncode = 0
|
|
334
|
+
result.stdout = ""
|
|
335
|
+
return result
|
|
336
|
+
if "-list" in cmd:
|
|
337
|
+
calls.append("list")
|
|
338
|
+
if calls.count("list") == 1:
|
|
339
|
+
raise subprocess.TimeoutExpired(cmd, auto_detect.LIST_TIMEOUT)
|
|
340
|
+
result = mock.MagicMock()
|
|
341
|
+
result.returncode = 0
|
|
342
|
+
result.stdout = self._list_output(["MyApp"])
|
|
343
|
+
return result
|
|
344
|
+
result = mock.MagicMock()
|
|
345
|
+
result.returncode = 0
|
|
346
|
+
result.stdout = self._show_settings(APP_TYPE)
|
|
347
|
+
return result
|
|
348
|
+
|
|
349
|
+
root = Path("/tmp/repo")
|
|
350
|
+
with mock.patch.object(auto_detect.subprocess, "run", side_effect=fake_run):
|
|
351
|
+
scheme = auto_detect.auto_detect_scheme(root, "Proj.xcodeproj", "")
|
|
352
|
+
|
|
353
|
+
self.assertEqual(scheme, "MyApp")
|
|
354
|
+
self.assertEqual(calls[:3], ["list", "resolve", "list"])
|
|
355
|
+
|
|
356
|
+
def test_gives_up_when_list_times_out_again_after_resolving(self):
|
|
357
|
+
def fake_run(cmd, **kw):
|
|
358
|
+
if "-resolvePackageDependencies" in cmd:
|
|
359
|
+
result = mock.MagicMock()
|
|
360
|
+
result.returncode = 0
|
|
361
|
+
result.stdout = ""
|
|
362
|
+
return result
|
|
363
|
+
raise subprocess.TimeoutExpired(cmd, auto_detect.LIST_TIMEOUT)
|
|
364
|
+
|
|
365
|
+
root = Path("/tmp/repo")
|
|
366
|
+
with mock.patch.object(auto_detect.subprocess, "run", side_effect=fake_run):
|
|
367
|
+
scheme = auto_detect.auto_detect_scheme(root, "Proj.xcodeproj", "")
|
|
368
|
+
self.assertIsNone(scheme)
|
|
369
|
+
|
|
321
370
|
|
|
322
371
|
class AutoDetectBundleIdTests(unittest.TestCase):
|
|
323
372
|
"""auto_detect_bundle_id: extract PRODUCT_BUNDLE_IDENTIFIER from showBuildSettings."""
|
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.5
|
|
@@ -109,13 +109,19 @@ runs:
|
|
|
109
109
|
# resolve_android.py has already rewritten versionCode/versionName in the
|
|
110
110
|
# module build file, so these are plain Gradle invocations with no extra
|
|
111
111
|
# properties for the project to have to opt into reading.
|
|
112
|
+
# `test` is the aggregate task ("Run unit tests for all variants") and is the
|
|
113
|
+
# only one guaranteed to exist: AGP only creates testXUnitTest tasks for the
|
|
114
|
+
# variants it enables, and AGP 9 disables the release unit test variant by
|
|
115
|
+
# default, so `:app:testReleaseUnitTest` is simply absent in many projects.
|
|
116
|
+
# Running it unqualified also mirrors `flutter test`, which covers the whole
|
|
117
|
+
# package rather than one module.
|
|
112
118
|
- name: Test Android app
|
|
113
119
|
if: ${{ steps.config.outputs.project_kind == 'gradle' && inputs.run-tests == 'true' }}
|
|
114
120
|
shell: bash
|
|
115
121
|
working-directory: ${{ steps.config.outputs.gradle_root || '.' }}
|
|
116
122
|
run: |
|
|
117
123
|
chmod +x ./gradlew
|
|
118
|
-
./gradlew
|
|
124
|
+
./gradlew test --console=plain --stacktrace
|
|
119
125
|
|
|
120
126
|
- name: Build release Android App Bundle with Gradle
|
|
121
127
|
if: ${{ steps.config.outputs.project_kind == 'gradle' }}
|