gowalk-cicd 1.0.81 → 1.0.83
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/CLAUDE.md +7 -1
- package/README.md +4 -3
- package/action/.daemux-version +1 -1
- package/action/action.yml +7 -66
- package/action/scripts/cache_scope.cjs +2 -0
- package/action/scripts/commit_bot_changes.sh +0 -3
- package/action/scripts/test_action_step_order.py +2 -2
- package/action/scripts/test_signing_source_boundary.py +82 -0
- package/android-action/.daemux-version +1 -1
- package/android-action/scripts/cache_scope.cjs +2 -0
- package/backend-action/.daemux-version +1 -1
- package/package.json +1 -1
- package/templates/deploy.yml +45 -3
package/CLAUDE.md
CHANGED
|
@@ -118,7 +118,9 @@ node /path/to/gowalk-cicd/bin/cli.mjs
|
|
|
118
118
|
(`IOS_DISTRIBUTION_P12_BASE64`, `IOS_DISTRIBUTION_CERT_META_BASE64`,
|
|
119
119
|
`IOS_DISTRIBUTION_CERT_REGISTRY_BASE64`), and the Android keystore, properties
|
|
120
120
|
and Play service account into an ephemeral runner checkout.
|
|
121
|
-
Tracked `creds/` files remain a backward-compatible fallback.
|
|
121
|
+
Tracked `creds/` files remain a backward-compatible read fallback. Refreshed signing
|
|
122
|
+
files stay ephemeral and are never staged; `persist-signing-cache` is ignored.
|
|
123
|
+
Version source staged before signing is preserved separately with its original index bytes.
|
|
122
124
|
- Never revoke a distribution certificate automatically, including legacy caches.
|
|
123
125
|
`certificate-cap-policy` accepts only `fail`; a full cap requires registry reconciliation.
|
|
124
126
|
- Keep preinstalled Android SDK/NDKs. Every Gradle test/build and SDK download runs
|
|
@@ -158,6 +160,10 @@ node /path/to/gowalk-cicd/bin/cli.mjs
|
|
|
158
160
|
errors still fail the job. Never use `continue-on-error` or a timeout around all SDK setup
|
|
159
161
|
to hide an optional cache failure. Do not alter cache keys or disable caches as part of
|
|
160
162
|
this timeout handling.
|
|
163
|
+
- Gradle caches use explicit checksum-pinned restore/save actions, each optional and bounded
|
|
164
|
+
to two minutes. Preserve setup-java's key inputs and absolute cache paths to reuse existing
|
|
165
|
+
caches. Java setup, builds and store uploads remain mandatory; save runs after delivery.
|
|
166
|
+
The cache-only preloader also admits the pinned `restore-only`/`save-only` entrypoints.
|
|
161
167
|
- GitHub artifact uploads have their own checksum-pinned `artifact_env.cjs` process scope.
|
|
162
168
|
It reuses the cache transport's approved HTTPS request guard, then removes inherited proxy
|
|
163
169
|
variables only inside the official `upload-artifact` process. Unknown programs/origins refuse;
|
package/README.md
CHANGED
|
@@ -62,9 +62,10 @@ the reusable Apple Distribution identity:
|
|
|
62
62
|
All three distribution-identity values are base64 so their exact bytes—and the
|
|
63
63
|
registry digests over those bytes—survive the secret round trip. The workflow
|
|
64
64
|
materializes them with mode `0600` only in the ephemeral runner
|
|
65
|
-
checkout.
|
|
66
|
-
composite action
|
|
67
|
-
|
|
65
|
+
checkout. Refreshed signing files are never staged or committed by the
|
|
66
|
+
composite action, including when a legacy workflow passes `persist-signing-cache: true`.
|
|
67
|
+
That input is retained as an ignored compatibility input. The distribution identity
|
|
68
|
+
files come from the signing registry provisioner; pass their paths to the secret tooling without printing
|
|
68
69
|
their contents.
|
|
69
70
|
|
|
70
71
|
Legacy private repositories can still provide the API key at:
|
package/action/.daemux-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.83
|
package/action/action.yml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Note: this file is ~800 lines, above the project's 400-line composite-
|
|
2
2
|
# action guideline. The size pre-dates the cert-caching feature; the
|
|
3
|
-
# signing
|
|
3
|
+
# signing preparation, the AI-metadata phases, and the
|
|
4
4
|
# export / upload chunk are candidates for extraction into separate
|
|
5
5
|
# scripts under ``scripts/`` (similar to how prepare_signing.py /
|
|
6
6
|
# cert_factory.py / keychain.py / profile_io.py split the cert +
|
|
@@ -59,10 +59,10 @@ inputs:
|
|
|
59
59
|
default: "fail"
|
|
60
60
|
persist-signing-cache:
|
|
61
61
|
description: >
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
DEPRECATED (ignored). Signing files remain in the ephemeral checkout;
|
|
63
|
+
the action never stages refreshed credentials, including legacy caches.
|
|
64
64
|
required: false
|
|
65
|
-
default: "
|
|
65
|
+
default: "false"
|
|
66
66
|
upload:
|
|
67
67
|
description: "Set to 'false' to stop after producing the IPA"
|
|
68
68
|
required: false
|
|
@@ -509,70 +509,11 @@ runs:
|
|
|
509
509
|
set -e
|
|
510
510
|
echo "SIGNING_PREP_EXIT=$signing_exit" >> "$GITHUB_ENV"
|
|
511
511
|
if [ "$signing_exit" -ne 0 ]; then
|
|
512
|
-
echo "::error::Signing preparation failed; preserving
|
|
512
|
+
echo "::error::Signing preparation failed; preserving staged source before failing."
|
|
513
513
|
fi
|
|
514
514
|
|
|
515
|
-
#
|
|
516
|
-
#
|
|
517
|
-
# credential paths; it never pushes them or bypasses branch protection.
|
|
518
|
-
# A version bump is preserved separately from the earlier action update.
|
|
519
|
-
|
|
520
|
-
- name: Stage refreshed signing identity
|
|
521
|
-
# Only stage on push to the default branch — PR runs and feature
|
|
522
|
-
# branches must NOT mutate creds/ (they'd race the default branch
|
|
523
|
-
# commit and clutter PR diffs). The signing identity is a long-lived
|
|
524
|
-
# artifact owned by the canonical branch.
|
|
525
|
-
if: ${{ inputs.archive == 'true'
|
|
526
|
-
&& inputs.persist-signing-cache == 'true'
|
|
527
|
-
&& github.event_name == 'push'
|
|
528
|
-
&& github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }}
|
|
529
|
-
shell: bash
|
|
530
|
-
working-directory: ${{ github.workspace }}
|
|
531
|
-
run: |
|
|
532
|
-
set -euo pipefail
|
|
533
|
-
# Default checkout is shallow (fetch-depth=1). Pushing back to the
|
|
534
|
-
# default branch needs a full ref so git can rebase on top of any
|
|
535
|
-
# commits that landed since checkout — promote to a full clone.
|
|
536
|
-
# Either form may fail on already-deep checkouts; ignore non-zero.
|
|
537
|
-
git fetch --unshallow 2>/dev/null \
|
|
538
|
-
|| git fetch --depth=2147483647 2>/dev/null \
|
|
539
|
-
|| true
|
|
540
|
-
git config user.name 'github-actions[bot]'
|
|
541
|
-
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
|
|
542
|
-
# Stage ONLY the specific files prepare_signing.py manages — never
|
|
543
|
-
# `creds/` wholesale. The user's ASC .p8 key is already tracked
|
|
544
|
-
# (committed separately at setup) so `git add` of new files leaves
|
|
545
|
-
# it alone, but `creds/` may also hold notes, build artifacts, or
|
|
546
|
-
# other unmanaged files we MUST NOT commit. Each `git add -f`
|
|
547
|
-
# bypasses any consumer .gitignore that hides creds/. Missing
|
|
548
|
-
# files (shouldn't happen given step ordering, but defensive)
|
|
549
|
-
# produce a non-zero exit which we swallow — the commit-step is
|
|
550
|
-
# the source of truth for "is there anything to commit".
|
|
551
|
-
git add -f -- creds/cert.p12 2>/dev/null || true
|
|
552
|
-
git add -f -- creds/cert.meta.json 2>/dev/null || true
|
|
553
|
-
git add -f -- creds/cert.registry.json 2>/dev/null || true
|
|
554
|
-
git add -f -- creds/profiles.manifest.json 2>/dev/null || true
|
|
555
|
-
# The whole profiles/ directory is action-managed (one
|
|
556
|
-
# .mobileprovision per signable bundle, GC'd when bundles are
|
|
557
|
-
# removed); staging the directory picks up adds + removes in one
|
|
558
|
-
# shot. Force-flag overrides any creds/profiles/ ignore rule.
|
|
559
|
-
git add -f -- creds/profiles/ 2>/dev/null || true
|
|
560
|
-
# Marketing-version auto-bump: NOTHING TO DO HERE.
|
|
561
|
-
# version_utils.write_marketing_version() does an immediate
|
|
562
|
-
# `git add -f -- <path>` right after the write, which captures
|
|
563
|
-
# the post-bump, pre-prepare_signing state in the index.
|
|
564
|
-
# prepare_signing.py later mutates the working-tree pbxproj
|
|
565
|
-
# for manual-signing settings, but those edits land only in
|
|
566
|
-
# the working tree -- the index keeps the version bump alone.
|
|
567
|
-
# The marker at $RUNNER_TEMP/swift-app-mv-bumped is for log /
|
|
568
|
-
# diagnostics; we surface it here so CI logs show exactly
|
|
569
|
-
# which file mmv touched.
|
|
570
|
-
bump_marker="$RUNNER_TEMP/swift-app-mv-bumped"
|
|
571
|
-
if [ -f "$bump_marker" ]; then
|
|
572
|
-
echo "auto-bump: marker present; the following file(s) were"
|
|
573
|
-
echo "auto-bumped and pre-staged by version_utils:"
|
|
574
|
-
sed 's/^/ /' "$bump_marker"
|
|
575
|
-
fi
|
|
515
|
+
# Signing files remain in the ephemeral checkout for archive/export.
|
|
516
|
+
# Only version changes staged before prepare_signing enter source maintenance.
|
|
576
517
|
|
|
577
518
|
- name: Commit + push staged bot changes
|
|
578
519
|
# Any marketing-version auto-bump the version step staged is preserved.
|
|
@@ -5,6 +5,8 @@ const {basename, dirname, join} = require('node:path');
|
|
|
5
5
|
const hashes = new Map([
|
|
6
6
|
['restore', 'a49301428b4c5477522c00f6464566457ed327d64ae5f80f8c12e762fb2ea9a2'],
|
|
7
7
|
['save', 'b969065795aaf5c6d20ba158e910be5d353eefb02eb2785263eb32e13090c066'],
|
|
8
|
+
['restore-only', '6255afaa3956351b8cfefc1e82f026b4db418a10678a8eaddf3d6c55f81744de'],
|
|
9
|
+
['save-only', '7fb63f90f06ce6a10f39d40a113f99791bffdedad5394cdad5b4dfaa644559cb'],
|
|
8
10
|
]);
|
|
9
11
|
const artifactHash = '168c44946cba03564808c19b83a72601e6d1d6f57081dbd2d6e2ea1cedc522f5';
|
|
10
12
|
const proxyKeys = ['HTTP_PROXY', 'HTTPS_PROXY', 'http_proxy', 'https_proxy', 'ALL_PROXY', 'all_proxy'];
|
|
@@ -9,13 +9,11 @@ if git diff --cached --quiet; then
|
|
|
9
9
|
fi
|
|
10
10
|
|
|
11
11
|
staged="$(git diff --cached --name-only)"
|
|
12
|
-
has_cert=0
|
|
13
12
|
has_auto=0
|
|
14
13
|
has_bump=0
|
|
15
14
|
# autoupdate_check.sh deliberately does NOT stage .github/workflows/deploy.yml
|
|
16
15
|
# (GITHUB_TOKEN cannot push workflow-file changes), so we only need to detect
|
|
17
16
|
# action/ paths to classify the commit as an autoupdate.
|
|
18
|
-
if grep -qE '^creds/' <<<"$staged"; then has_cert=1; fi
|
|
19
17
|
if grep -qE '^\.github/actions/(swift-app|android-app)/' <<<"$staged"; then has_auto=1; fi
|
|
20
18
|
# marketing-version-auto-bump (mmv_floor_check) writes the bumped value
|
|
21
19
|
# into the project's source-of-truth (resolved by version_utils):
|
|
@@ -34,7 +32,6 @@ fi
|
|
|
34
32
|
# Build a subject that lists every concern that actually fired. Avoids a
|
|
35
33
|
# 2^N case explosion by composing components in a stable order.
|
|
36
34
|
parts=()
|
|
37
|
-
if [[ $has_cert -eq 1 ]]; then parts+=("refresh signing identity"); fi
|
|
38
35
|
if [[ $has_auto -eq 1 ]]; then parts+=("autoupdate app-ci"); fi
|
|
39
36
|
if [[ $has_bump -eq 1 ]]; then parts+=("bump MARKETING_VERSION"); fi
|
|
40
37
|
if [[ ${#parts[@]} -eq 0 ]]; then
|
|
@@ -61,9 +61,9 @@ class TestActionStepOrder(unittest.TestCase):
|
|
|
61
61
|
self.assertIn("format('refs/heads/{0}', github.event.repository.default_branch)", block)
|
|
62
62
|
self.assertIn('bash "$BOT_SCRIPTS_DIR/commit_bot_changes.sh"', commit)
|
|
63
63
|
self.assertIn("GITHUB_REF_NAME: ${{ github.ref_name }}", commit)
|
|
64
|
-
#
|
|
64
|
+
# Version source is preserved after ephemeral signing preparation.
|
|
65
65
|
self.assertIn("Commit + push staged bot changes", self.names)
|
|
66
|
-
self.assertLess(self.names.index("
|
|
66
|
+
self.assertLess(self.names.index("Prepare signing (cert + keychain + per-target profiles + pbxproj)"),
|
|
67
67
|
self.names.index("Commit + push staged bot changes"))
|
|
68
68
|
|
|
69
69
|
def test_every_script_and_prompt_is_read_from_the_snapshot(self) -> None:
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""Run the action's signing-to-maintenance steps against a protected Git remote."""
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import subprocess
|
|
4
|
+
import textwrap
|
|
5
|
+
|
|
6
|
+
from source_maintenance_fixture import MaintenanceFixture
|
|
7
|
+
from test_action_step_order import step_block, step_names
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
ACTION = Path(__file__).resolve().parents[1]
|
|
11
|
+
PREPARE = "Prepare signing (cert + keychain + per-target profiles + pbxproj)"
|
|
12
|
+
RERAISE = "Re-raise signing preparation failure"
|
|
13
|
+
FILES = ("cert.p12", "cert.meta.json", "cert.registry.json", "profiles.manifest.json",
|
|
14
|
+
"profiles/app.mobileprovision")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SigningSourceBoundaryTests(MaintenanceFixture):
|
|
18
|
+
def setUp(self):
|
|
19
|
+
super().setUp()
|
|
20
|
+
snapshot = self.root / "action"
|
|
21
|
+
scripts = snapshot / "scripts"
|
|
22
|
+
scripts.mkdir(parents=True)
|
|
23
|
+
(scripts / "prepare_signing.py").write_text(
|
|
24
|
+
"from pathlib import Path\nimport os\n"
|
|
25
|
+
f"for name in {FILES!r}:\n"
|
|
26
|
+
" p = Path('creds') / name\n p.parent.mkdir(parents=True, exist_ok=True)\n"
|
|
27
|
+
" p.write_text('synthetic-signing-material')\n"
|
|
28
|
+
"p = Path('project.yml')\np.write_text(p.read_text() + 'signing: ephemeral\\n')\n"
|
|
29
|
+
"raise SystemExit(int(os.environ.get('FIXTURE_SIGNING_EXIT', '0')))\n")
|
|
30
|
+
(self.repo / ".git/info/exclude").write_text("creds/\n")
|
|
31
|
+
self.env.update({"SWIFT_APP_ACTION": str(snapshot), "RUNNER_TEMP": str(self.root),
|
|
32
|
+
"GITHUB_ENV": str(self.root / "environment"),
|
|
33
|
+
"BOT_SCRIPTS_DIR": str(ACTION / "scripts")})
|
|
34
|
+
self.source = (ACTION / "action.yml").read_text()
|
|
35
|
+
|
|
36
|
+
def run_signing_to_maintenance(self):
|
|
37
|
+
names = step_names(self.source)
|
|
38
|
+
selected = names[names.index(PREPARE):names.index(RERAISE)]
|
|
39
|
+
result = None
|
|
40
|
+
for name in selected:
|
|
41
|
+
block = step_block(self.source, name)
|
|
42
|
+
script = textwrap.dedent(block.split(" run: ", 1)[1])
|
|
43
|
+
if script.startswith("|\n"):
|
|
44
|
+
script = textwrap.dedent(script[2:])
|
|
45
|
+
result = subprocess.run(["bash", "-e", "-o", "pipefail", "-c", script],
|
|
46
|
+
cwd=self.repo, env=self.env, capture_output=True, text=True, timeout=15)
|
|
47
|
+
if result.returncode:
|
|
48
|
+
return result
|
|
49
|
+
return result
|
|
50
|
+
|
|
51
|
+
def assert_ephemeral_signing(self):
|
|
52
|
+
for name in FILES:
|
|
53
|
+
self.assertEqual((self.repo / "creds" / name).read_text(), "synthetic-signing-material")
|
|
54
|
+
self.assertEqual(self.git("ls-files", "creds"), "")
|
|
55
|
+
self.assertEqual(self.git("diff", "--cached", "--name-only"), "")
|
|
56
|
+
self.assertEqual(self.git("rev-parse", "HEAD").strip(), self.base)
|
|
57
|
+
|
|
58
|
+
def test_legacy_true_input_keeps_signing_out_of_version_candidate(self):
|
|
59
|
+
# All steps for archive=true/default-branch push/persist-signing-cache=true run.
|
|
60
|
+
self.stage()
|
|
61
|
+
receipt = self.receipt(self.run_signing_to_maintenance())
|
|
62
|
+
self.assertEqual(self.git("diff", "--name-only", self.base, receipt["head_sha"]), "project.yml\n")
|
|
63
|
+
self.assertEqual(self.git("show", receipt["head_sha"] + ":project.yml"), "version: 1.1\n")
|
|
64
|
+
self.assertEqual((self.repo / "project.yml").read_text(), "version: 1.1\nsigning: ephemeral\n")
|
|
65
|
+
self.assert_ephemeral_signing()
|
|
66
|
+
|
|
67
|
+
def test_signing_without_source_changes_needs_no_maintenance_candidate(self):
|
|
68
|
+
result = self.run_signing_to_maintenance()
|
|
69
|
+
self.assertEqual(result.returncode, 0, result.stderr)
|
|
70
|
+
self.assertEqual(len(self.git("ls-remote", "--heads", "origin").splitlines()), 1)
|
|
71
|
+
self.assert_ephemeral_signing()
|
|
72
|
+
|
|
73
|
+
def test_signing_failure_stays_visible_after_source_preservation(self):
|
|
74
|
+
self.stage()
|
|
75
|
+
self.env["FIXTURE_SIGNING_EXIT"] = "7"
|
|
76
|
+
self.receipt(self.run_signing_to_maintenance())
|
|
77
|
+
self.assertIn("SIGNING_PREP_EXIT=7\n", Path(self.env["GITHUB_ENV"]).read_text())
|
|
78
|
+
script = textwrap.dedent(step_block(self.source, RERAISE).split(" run: |\n", 1)[1])
|
|
79
|
+
result = subprocess.run(["bash", "-e", "-c", script], cwd=self.repo,
|
|
80
|
+
env={**self.env, "SIGNING_PREP_EXIT": "7"}, capture_output=True, text=True)
|
|
81
|
+
self.assertEqual(result.returncode, 7)
|
|
82
|
+
self.assert_ephemeral_signing()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.83
|
|
@@ -5,6 +5,8 @@ const {basename, dirname, join} = require('node:path');
|
|
|
5
5
|
const hashes = new Map([
|
|
6
6
|
['restore', 'a49301428b4c5477522c00f6464566457ed327d64ae5f80f8c12e762fb2ea9a2'],
|
|
7
7
|
['save', 'b969065795aaf5c6d20ba158e910be5d353eefb02eb2785263eb32e13090c066'],
|
|
8
|
+
['restore-only', '6255afaa3956351b8cfefc1e82f026b4db418a10678a8eaddf3d6c55f81744de'],
|
|
9
|
+
['save-only', '7fb63f90f06ce6a10f39d40a113f99791bffdedad5394cdad5b4dfaa644559cb'],
|
|
8
10
|
]);
|
|
9
11
|
const artifactHash = '168c44946cba03564808c19b83a72601e6d1d6f57081dbd2d6e2ea1cedc522f5';
|
|
10
12
|
const proxyKeys = ['HTTP_PROXY', 'HTTPS_PROXY', 'http_proxy', 'https_proxy', 'ALL_PROXY', 'all_proxy'];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.83
|
package/package.json
CHANGED
package/templates/deploy.yml
CHANGED
|
@@ -181,8 +181,6 @@ jobs:
|
|
|
181
181
|
# is locked in review. Default-branch deploys retain metadata automation.
|
|
182
182
|
manage-app-store-version: >-
|
|
183
183
|
${{ github.ref_name == github.event.repository.default_branch && 'true' || 'false' }}
|
|
184
|
-
persist-signing-cache: >-
|
|
185
|
-
${{ steps.ios_credentials.outputs.source == 'encrypted' && 'false' || 'true' }}
|
|
186
184
|
# Repository variable FIREBASE_APP_ID: the app's Firebase App ID(s),
|
|
187
185
|
# comma-separated when it ships both platforms. With an iOS id the
|
|
188
186
|
# action uploads the archive's dSYMs to Crashlytics before TestFlight.
|
|
@@ -348,7 +346,35 @@ jobs:
|
|
|
348
346
|
with:
|
|
349
347
|
distribution: temurin
|
|
350
348
|
java-version: ${{ steps.jdk.outputs.version }}
|
|
351
|
-
|
|
349
|
+
# Keep Java setup mandatory; optional caches have no unbounded post step.
|
|
350
|
+
- name: Retain Gradle cache scope
|
|
351
|
+
id: gradle_scope
|
|
352
|
+
if: ${{ steps.mode.outputs.mode == 'local' }}
|
|
353
|
+
continue-on-error: true
|
|
354
|
+
shell: bash
|
|
355
|
+
run: |
|
|
356
|
+
node .github/actions/android-app/scripts/cache_scope.cjs --snapshot
|
|
357
|
+
node - <<'NODE'
|
|
358
|
+
require('fs').appendFileSync(process.env.GITHUB_OUTPUT,
|
|
359
|
+
`home=${require('os').homedir()}\narch=${process.arch}\n`);
|
|
360
|
+
NODE
|
|
361
|
+
- name: Restore Gradle dependencies
|
|
362
|
+
id: gradle_cache
|
|
363
|
+
if: ${{ steps.mode.outputs.mode == 'local' && steps.gradle_scope.outcome == 'success' }}
|
|
364
|
+
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25
|
|
365
|
+
continue-on-error: true
|
|
366
|
+
timeout-minutes: 2
|
|
367
|
+
env:
|
|
368
|
+
NODE_OPTIONS: --require "${{ steps.gradle_scope.outputs.preloader }}"
|
|
369
|
+
SEGMENT_DOWNLOAD_TIMEOUT_MINS: '1'
|
|
370
|
+
with:
|
|
371
|
+
path: |
|
|
372
|
+
${{ steps.gradle_scope.outputs.home }}/.gradle/caches
|
|
373
|
+
${{ steps.gradle_scope.outputs.home }}/.gradle/wrapper
|
|
374
|
+
key: >-
|
|
375
|
+
${{ format('setup-java-{0}-{1}-gradle-{2}', runner.os, steps.gradle_scope.outputs.arch,
|
|
376
|
+
hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'buildSrc/**/Versions.kt',
|
|
377
|
+
'buildSrc/**/Dependencies.kt', 'gradle/*.versions.toml', '**/versions.properties')) }}
|
|
352
378
|
- name: Set up Flutter
|
|
353
379
|
if: ${{ steps.mode.outputs.mode == 'local' && steps.flutter.outputs.enabled == 'true' }}
|
|
354
380
|
uses: ./.github/actions/android-app/flutter-setup
|
|
@@ -518,6 +544,22 @@ jobs:
|
|
|
518
544
|
run: |
|
|
519
545
|
echo "::notice title=play_review_pending::{\"schema\":\"gowalk-cicd/play-review-pending.v1\",\"package\":\"${PACKAGE}\",\"track\":\"${TRACK}\",\"version_code\":\"${VERSION_CODE}\"}"
|
|
520
546
|
|
|
547
|
+
- name: Save Gradle dependencies
|
|
548
|
+
if: >-
|
|
549
|
+
${{ success() && steps.mode.outputs.mode == 'local'
|
|
550
|
+
&& steps.gradle_cache.outputs.cache-primary-key != ''
|
|
551
|
+
&& steps.gradle_cache.outputs.cache-hit != 'true' }}
|
|
552
|
+
uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25
|
|
553
|
+
continue-on-error: true
|
|
554
|
+
timeout-minutes: 2
|
|
555
|
+
env:
|
|
556
|
+
NODE_OPTIONS: --require "${{ steps.gradle_scope.outputs.preloader }}"
|
|
557
|
+
with:
|
|
558
|
+
path: |
|
|
559
|
+
${{ steps.gradle_scope.outputs.home }}/.gradle/caches
|
|
560
|
+
${{ steps.gradle_scope.outputs.home }}/.gradle/wrapper
|
|
561
|
+
key: ${{ steps.gradle_cache.outputs.cache-primary-key }}
|
|
562
|
+
|
|
521
563
|
# GitHub only registers a newly added workflow after it reaches the default
|
|
522
564
|
# branch. A brand-new app's feature branch therefore cannot dispatch the
|
|
523
565
|
# separate Backend Deploy workflow yet. Reuse this already-registered mobile
|