gowalk-cicd 1.0.116 → 1.0.117
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/action/.daemux-version +1 -1
- package/android-action/.daemux-version +1 -1
- package/android-action/flutter-setup/action.yml +8 -0
- package/android-action/scripts/flutter_manifest.py +24 -1
- package/android-action/scripts/test_flutter_download_budget.py +42 -0
- package/android-action/scripts/test_google_bootstrap_wiring.py +11 -1
- package/backend-action/.daemux-version +1 -1
- package/package.json +1 -1
- package/templates/deploy.yml +9 -0
package/action/.daemux-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.117
|
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.117
|
|
@@ -49,6 +49,13 @@ inputs:
|
|
|
49
49
|
description: Git clone source
|
|
50
50
|
required: false
|
|
51
51
|
default: https://github.com/flutter/flutter.git
|
|
52
|
+
archive-budget-seconds:
|
|
53
|
+
description: >-
|
|
54
|
+
Seconds the proxied SDK archive transfer may take. Raise it in a release
|
|
55
|
+
job, whose own timeout is far longer than a validation job's; the helper
|
|
56
|
+
clamps it and the partial archive is cached either way.
|
|
57
|
+
required: false
|
|
58
|
+
default: ''
|
|
52
59
|
outputs:
|
|
53
60
|
CHANNEL:
|
|
54
61
|
value: ${{ steps.flutter-action.outputs.CHANNEL }}
|
|
@@ -196,6 +203,7 @@ runs:
|
|
|
196
203
|
${{ inputs.cache == 'true' && format('{0}/gowalk-flutter-archives', runner.temp) || '' }}
|
|
197
204
|
GOWALK_FLUTTER_RELEASE_CACHE: ${{ steps.release-metadata.outputs.path }}
|
|
198
205
|
GOWALK_FLUTTER_RELEASE_PIN: ${{ steps.release-metadata.outputs.pin }}
|
|
206
|
+
GOWALK_FLUTTER_ARCHIVE_BUDGET_S: ${{ inputs.archive-budget-seconds }}
|
|
199
207
|
with:
|
|
200
208
|
channel: ${{ steps.flutter-action.outputs.CHANNEL }}
|
|
201
209
|
flutter-version: ${{ steps.flutter-action.outputs.VERSION }}
|
|
@@ -9,6 +9,29 @@ import time
|
|
|
9
9
|
from urllib.parse import urlsplit
|
|
10
10
|
|
|
11
11
|
import flutter_download
|
|
12
|
+
|
|
13
|
+
#: Seconds an archive transfer may take before its receipt is published. The
|
|
14
|
+
#: enclosing job's own room is the only thing that bounds it usefully, and the
|
|
15
|
+
#: two differ by a factor of three: a validation job must report inside 30
|
|
16
|
+
#: minutes, while a release job has 45-60. A default-branch deploy cannot
|
|
17
|
+
#: restore the SDK cache a task branch built (GitHub scopes branch caches away
|
|
18
|
+
#: from the default branch), so it downloads the whole archive through the
|
|
19
|
+
#: account's residential exit at a few hundred KB/s — and a fixed 20-minute cap
|
|
20
|
+
#: made that a guaranteed failure: obd-scanner's release retained 428 MB of its
|
|
21
|
+
#: archive, failed on curl 28, and shipped nothing (2026-09-09).
|
|
22
|
+
ARCHIVE_BUDGET_S = 1200
|
|
23
|
+
MAX_ARCHIVE_BUDGET_S = 3000
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def archive_budget() -> int:
|
|
27
|
+
"""The archive deadline, from ``GOWALK_FLUTTER_ARCHIVE_BUDGET_S`` when the
|
|
28
|
+
workflow declares one. Clamped: never below the current default, never
|
|
29
|
+
beyond a release job's own timeout."""
|
|
30
|
+
try:
|
|
31
|
+
declared = int(os.environ.get("GOWALK_FLUTTER_ARCHIVE_BUDGET_S", "") or ARCHIVE_BUDGET_S)
|
|
32
|
+
except ValueError:
|
|
33
|
+
return ARCHIVE_BUDGET_S
|
|
34
|
+
return max(ARCHIVE_BUDGET_S, min(declared, MAX_ARCHIVE_BUDGET_S))
|
|
12
35
|
import flutter_archive_cache
|
|
13
36
|
import flutter_release_cache
|
|
14
37
|
|
|
@@ -23,7 +46,7 @@ def download(arguments: list[str], directory: Path) -> int:
|
|
|
23
46
|
if kind == "archive":
|
|
24
47
|
flutter_download.archive_digest()
|
|
25
48
|
child_env = {**os.environ, "NO_PROXY": "", "no_proxy": ""}
|
|
26
|
-
deadline, code, http, proxy_http = time.monotonic() + (60 if kind == "manifest" else
|
|
49
|
+
deadline, code, http, proxy_http = time.monotonic() + (60 if kind == "manifest" else archive_budget()), 1, 0, 0
|
|
27
50
|
destination = directory / "download"
|
|
28
51
|
destination.touch(mode=0o600, exist_ok=True)
|
|
29
52
|
destination.chmod(0o600)
|
|
@@ -38,5 +38,47 @@ class DownloadBudgetTests(unittest.TestCase):
|
|
|
38
38
|
self.assertNotIn("fixture-secret", error.getvalue())
|
|
39
39
|
|
|
40
40
|
|
|
41
|
+
class ArchiveBudgetTests(unittest.TestCase):
|
|
42
|
+
def test_a_release_job_may_declare_more_archive_room_than_a_validation_job(self):
|
|
43
|
+
with patch.dict(os.environ, {}, clear=False):
|
|
44
|
+
os.environ.pop("GOWALK_FLUTTER_ARCHIVE_BUDGET_S", None)
|
|
45
|
+
self.assertEqual(flutter_manifest.archive_budget(), 1200)
|
|
46
|
+
os.environ["GOWALK_FLUTTER_ARCHIVE_BUDGET_S"] = "2100"
|
|
47
|
+
self.assertEqual(flutter_manifest.archive_budget(), 2100)
|
|
48
|
+
# Never shorter than the default, never past a release job's timeout,
|
|
49
|
+
# and a malformed value is the default rather than a refusal.
|
|
50
|
+
os.environ["GOWALK_FLUTTER_ARCHIVE_BUDGET_S"] = "60"
|
|
51
|
+
self.assertEqual(flutter_manifest.archive_budget(), 1200)
|
|
52
|
+
os.environ["GOWALK_FLUTTER_ARCHIVE_BUDGET_S"] = "999999"
|
|
53
|
+
self.assertEqual(flutter_manifest.archive_budget(), 3000)
|
|
54
|
+
os.environ["GOWALK_FLUTTER_ARCHIVE_BUDGET_S"] = "not-a-number"
|
|
55
|
+
self.assertEqual(flutter_manifest.archive_budget(), 1200)
|
|
56
|
+
os.environ["GOWALK_FLUTTER_ARCHIVE_BUDGET_S"] = ""
|
|
57
|
+
self.assertEqual(flutter_manifest.archive_budget(), 1200)
|
|
58
|
+
|
|
59
|
+
def test_a_declared_budget_actually_extends_the_transfer_deadline(self):
|
|
60
|
+
elapsed = [0.0]
|
|
61
|
+
|
|
62
|
+
def transfer(_url, destination, _kind, remaining, _env):
|
|
63
|
+
elapsed[0] += min(600, remaining)
|
|
64
|
+
with destination.open("ab") as output:
|
|
65
|
+
output.write(b"partial")
|
|
66
|
+
return 28, 200, 200
|
|
67
|
+
|
|
68
|
+
with tempfile.TemporaryDirectory() as directory, contextlib.redirect_stderr(io.StringIO()):
|
|
69
|
+
with patch.dict(os.environ, HTTPS_PROXY="http://fixture:secret@localhost:1",
|
|
70
|
+
GOWALK_FLUTTER_ARCHIVE_SHA256="a" * 64,
|
|
71
|
+
GOWALK_FLUTTER_ARCHIVE_BUDGET_S="2100"):
|
|
72
|
+
with patch.object(flutter_manifest.time, "monotonic", side_effect=lambda: elapsed[0]), \
|
|
73
|
+
patch.object(flutter_manifest.time, "sleep", side_effect=lambda seconds: None), \
|
|
74
|
+
patch.object(flutter_manifest.flutter_download, "transfer", side_effect=transfer):
|
|
75
|
+
flutter_manifest.download(["--connect-timeout", "15", "--retry", "5",
|
|
76
|
+
"https://fixture.invalid/flutter_infra_release/releases/stable/linux/sdk.tar.xz"],
|
|
77
|
+
Path(directory))
|
|
78
|
+
# The declared deadline bounds the pass, not the two 600 s attempts a
|
|
79
|
+
# 1200 s default allowed: the last attempt gets the remaining 300 s.
|
|
80
|
+
self.assertEqual(elapsed[0], 2100)
|
|
81
|
+
|
|
82
|
+
|
|
41
83
|
if __name__ == "__main__":
|
|
42
84
|
unittest.main()
|
|
@@ -20,6 +20,9 @@ class BootstrapWiringTests(unittest.TestCase):
|
|
|
20
20
|
if step is install:
|
|
21
21
|
expected_env["GOWALK_FLUTTER_ARCHIVE_CACHE"] = (
|
|
22
22
|
"${{ inputs.cache == 'true' && format('{0}/gowalk-flutter-archives', runner.temp) || '' }}")
|
|
23
|
+
# Only the step that actually transfers the archive carries the
|
|
24
|
+
# caller's declared budget; the dry-run resolve must not.
|
|
25
|
+
expected_env["GOWALK_FLUTTER_ARCHIVE_BUDGET_S"] = "${{ inputs.archive-budget-seconds }}"
|
|
23
26
|
self.assertEqual(step["env"], expected_env)
|
|
24
27
|
self.assertEqual(step["with"]["cache"], "false")
|
|
25
28
|
self.assertEqual(step["with"]["pub-cache"], "false")
|
|
@@ -38,6 +41,11 @@ class BootstrapWiringTests(unittest.TestCase):
|
|
|
38
41
|
self.assertEqual(job["env"]["GOOGLE_STORE_PROXY_URL"],
|
|
39
42
|
"${{ secrets.GOOGLE_STORE_PROXY_URL }}")
|
|
40
43
|
self.assertNotIn("continue-on-error", step)
|
|
44
|
+
# A release job runs on the default branch, which cannot
|
|
45
|
+
# restore a task branch's SDK cache, so it declares the
|
|
46
|
+
# archive room its own timeout allows (2026-09-09).
|
|
47
|
+
if name == "deploy.yml" and int(job.get("timeout-minutes", 0)) >= 45:
|
|
48
|
+
self.assertEqual(step["with"]["archive-budget-seconds"], "2100")
|
|
41
49
|
self.assertEqual(checked, 3)
|
|
42
50
|
setup = yaml.safe_load((ROOT / "android-action/flutter-setup/action.yml").read_text())
|
|
43
51
|
steps = setup["runs"]["steps"]
|
|
@@ -65,7 +73,9 @@ class BootstrapWiringTests(unittest.TestCase):
|
|
|
65
73
|
setup = yaml.safe_load((ROOT / "android-action/flutter-setup/action.yml").read_text())
|
|
66
74
|
inputs = {"channel", "flutter-version", "flutter-version-file", "architecture", "cache", "cache-key",
|
|
67
75
|
"cache-path", "pub-cache", "pub-cache-key", "pub-cache-path", "dry-run", "git-source"}
|
|
68
|
-
|
|
76
|
+
# `archive-budget-seconds` is this action's own knob, not one of the
|
|
77
|
+
# official action's inputs: it reaches the transfer as an env var.
|
|
78
|
+
self.assertEqual(set(setup["inputs"]), inputs | {"archive-budget-seconds"})
|
|
69
79
|
resolve = next(step for step in setup["runs"]["steps"] if step.get("id") == "flutter-action")
|
|
70
80
|
for name in inputs - {"cache", "pub-cache", "dry-run"}:
|
|
71
81
|
self.assertEqual(resolve["with"][name], "${{ inputs." + name + " }}")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.117
|
package/package.json
CHANGED
package/templates/deploy.yml
CHANGED
|
@@ -101,6 +101,12 @@ jobs:
|
|
|
101
101
|
with:
|
|
102
102
|
channel: stable
|
|
103
103
|
cache: true
|
|
104
|
+
# A release runs on the default branch, which cannot restore the SDK
|
|
105
|
+
# cache a task branch built, so it downloads the whole archive through
|
|
106
|
+
# the account exit. This job has an hour; the helper's own 20-minute
|
|
107
|
+
# default belongs to a validation job and turned that download into a
|
|
108
|
+
# guaranteed failure (obd-scanner, 2026-09-09: 428 MB retained, curl 28).
|
|
109
|
+
archive-budget-seconds: '2100'
|
|
104
110
|
- name: Retain CocoaPods cache process scope
|
|
105
111
|
id: pods-cache-scope
|
|
106
112
|
if: ${{ steps.flutter.outputs.enabled == 'true' }}
|
|
@@ -411,6 +417,9 @@ jobs:
|
|
|
411
417
|
with:
|
|
412
418
|
channel: stable
|
|
413
419
|
cache: true
|
|
420
|
+
# 35 of this job's 45 minutes; see the iOS job for why a release needs
|
|
421
|
+
# more archive room than a validation run.
|
|
422
|
+
archive-budget-seconds: '2100'
|
|
414
423
|
# Flutter apps can depend on private git packages. Most repos in this fleet
|
|
415
424
|
# embed a PAT directly in the pubspec URL, which publishes the token into
|
|
416
425
|
# source and into every fork of the lockfile. Setting the optional
|