gowalk-cicd 1.0.130 → 1.0.132
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 +5 -0
- package/action/.daemux-version +1 -1
- package/action/scripts/prepare_crashlytics_build.py +6 -2
- package/action/scripts/test_crashlytics_phase_effects.py +30 -0
- package/android-action/.daemux-version +1 -1
- package/android-action/play-upload/action.yml +3 -0
- package/android-action/play-upload/release_intent.cjs +21 -0
- package/android-action/play-upload/run.cjs +8 -4
- package/backend-action/.daemux-version +1 -1
- package/package.json +1 -1
- package/templates/deploy.yml +1 -3
package/CLAUDE.md
CHANGED
|
@@ -417,6 +417,11 @@ node /path/to/gowalk-cicd/bin/cli.mjs
|
|
|
417
417
|
recorded immediately in repository deployment receipts; retries reuse their prior-run evidence.
|
|
418
418
|
An uncertain upload never starts another binary automatically. Preserve its signed artifact,
|
|
419
419
|
complete exact provider readback/recovery through scoped tooling, then reconcile its receipt.
|
|
420
|
+
The local Android workflow supplies `mobileReleaseIntentScript` to the upload wrapper instead
|
|
421
|
+
of marking `uploading` before acquiring Play ownership. A refused owner leaves the release
|
|
422
|
+
record at `building`; the wrapper records intent inside its acquired lease before provider
|
|
423
|
+
dispatch. Adopt both the action and workflow wiring; action-only updates preserve older
|
|
424
|
+
workflows' intent handling. Never clear an existing `uploading` marker on an owner refusal.
|
|
420
425
|
Actions without `MOBILE_RELEASE_DEPLOYMENT_ID` preserve legacy consumer behavior. All new
|
|
421
426
|
receipt helper reads are fixed-origin GitHub requests; Apple/Google still use their assigned exits.
|
|
422
427
|
|
package/action/.daemux-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.132
|
|
@@ -67,13 +67,17 @@ def commands(script: str) -> list[list[str]] | None:
|
|
|
67
67
|
current = []
|
|
68
68
|
target = False
|
|
69
69
|
for token in tokens:
|
|
70
|
-
if target:
|
|
70
|
+
if target:
|
|
71
71
|
target = False
|
|
72
72
|
continue
|
|
73
73
|
if token.startswith("#"):
|
|
74
74
|
break
|
|
75
75
|
if token and set(token) <= OPERATOR:
|
|
76
|
-
if set(token) & REDIRECT:
|
|
76
|
+
if set(token) & REDIRECT:
|
|
77
|
+
# Only the deferred uploader's effects belong to the removed operation.
|
|
78
|
+
# A redirected builtin/assignment can produce another required build input.
|
|
79
|
+
if not uploads_symbols(current):
|
|
80
|
+
return None
|
|
77
81
|
target = True
|
|
78
82
|
continue
|
|
79
83
|
if current:
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""An upload-only rewrite must preserve commands that also produce other build inputs."""
|
|
2
|
+
import copy
|
|
3
|
+
import unittest
|
|
4
|
+
|
|
5
|
+
import prepare_crashlytics_build as build
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class PhaseEffectTests(unittest.TestCase):
|
|
9
|
+
def test_redirected_builtins_are_build_work_even_without_another_executable(self):
|
|
10
|
+
for command in ('echo public > Generated.swift', 'echo enabled >> build.env',
|
|
11
|
+
': > generated.config', 'BUILD=release > generated.config'):
|
|
12
|
+
with self.subTest(command=command):
|
|
13
|
+
script = command + '\nupload-symbols -gsp app.plist -p ios symbols'
|
|
14
|
+
self.assertFalse(build.dedicated(script))
|
|
15
|
+
document = {'objects': {'phase': {'isa': 'PBXShellScriptBuildPhase',
|
|
16
|
+
'name': 'Crashlytics and generated input', 'shellScript': script}}}
|
|
17
|
+
original = copy.deepcopy(document)
|
|
18
|
+
with self.assertRaisesRegex(ValueError, 'shares the build phase'):
|
|
19
|
+
build.rewrite(document)
|
|
20
|
+
self.assertEqual(document, original)
|
|
21
|
+
|
|
22
|
+
def test_supported_generated_guards_remain_upload_only(self):
|
|
23
|
+
self.assertTrue(build.dedicated(
|
|
24
|
+
'if [ -f "$PODS_ROOT/FirebaseCrashlytics/upload-symbols" ]; then\n'
|
|
25
|
+
'"$PODS_ROOT/FirebaseCrashlytics/upload-symbols" -gsp app.plist -p ios symbols\n'
|
|
26
|
+
'else echo "warning: upload-symbols absent"; fi'))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
if __name__ == '__main__':
|
|
30
|
+
unittest.main()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.132
|
|
@@ -23,6 +23,9 @@ inputs:
|
|
|
23
23
|
inAppUpdatePriority:
|
|
24
24
|
description: In-app update priority.
|
|
25
25
|
default: '0'
|
|
26
|
+
mobileReleaseIntentScript:
|
|
27
|
+
description: Committed mobile_release.cjs path, invoked after acquiring the package owner and before upload.
|
|
28
|
+
default: ''
|
|
26
29
|
outputs:
|
|
27
30
|
review-pending:
|
|
28
31
|
description: True only after a successful explicitly requested review-hold retry.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// The workflow supplies its committed release helper; Play ownership precedes the write marker.
|
|
2
|
+
const {spawn} = require('node:child_process');
|
|
3
|
+
|
|
4
|
+
function begin(env) {
|
|
5
|
+
const script = env.INPUT_MOBILERELEASEINTENTSCRIPT;
|
|
6
|
+
// Older workflows record their own intent. Unwired consumers retain that behavior.
|
|
7
|
+
if (!script || !env.MOBILE_RELEASE_DEPLOYMENT_ID) return;
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
const child = spawn(process.execPath, [script, 'begin-upload', 'android'], {env, stdio: 'ignore'});
|
|
10
|
+
// Keep the owner cancellation handler responsive while its bounded marker write settles.
|
|
11
|
+
const timer = setTimeout(() => child.kill('SIGKILL'), 120000);
|
|
12
|
+
child.once('error', () => { clearTimeout(timer); reject(Error('mobile_release_intent_unconfirmed')); });
|
|
13
|
+
child.once('close', (code, signal) => {
|
|
14
|
+
clearTimeout(timer);
|
|
15
|
+
if (code !== 0 || signal) reject(Error('mobile_release_intent_unconfirmed'));
|
|
16
|
+
else resolve();
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = {begin};
|
|
@@ -5,6 +5,7 @@ const source = require('./source.cjs');
|
|
|
5
5
|
const processRunner = require('./process.cjs');
|
|
6
6
|
const owner = require('./owner.cjs');
|
|
7
7
|
const diagnostics = require('./diagnostics.cjs');
|
|
8
|
+
const releaseIntent = require('./release_intent.cjs');
|
|
8
9
|
|
|
9
10
|
async function upload(program, env, directory, execute = processRunner.execute, timeout = 3600000,
|
|
10
11
|
cancelled = () => false, report = () => {}) {
|
|
@@ -40,14 +41,17 @@ async function main() {
|
|
|
40
41
|
if (!env.RUNNER_TEMP || !env.GITHUB_OUTPUT) throw new Error('runner_context_required');
|
|
41
42
|
directory = mkdtempSync(join(env.RUNNER_TEMP, 'gowalk-play-upload-'));
|
|
42
43
|
const program = await source.prepare(directory);
|
|
43
|
-
receipt = await owner.withOwner(env, env.INPUT_PACKAGENAME, cancelled =>
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
receipt = await owner.withOwner(env, env.INPUT_PACKAGENAME, async cancelled => {
|
|
45
|
+
if (cancelled()) return {ok: false, code: 'upload_cancelled', attempts: 0, review_pending: false};
|
|
46
|
+
await releaseIntent.begin(env);
|
|
47
|
+
return upload(program, env, directory, processRunner.execute, 3600000, cancelled,
|
|
48
|
+
(attempt, result) => console.log(diagnostics.annotation(attempt, result)));
|
|
49
|
+
});
|
|
46
50
|
} catch (error) {
|
|
47
51
|
if (owner.codes.includes(error.message)) console.log(owner.annotation(error.message, undefined,
|
|
48
52
|
error.detail || (typeof error.releaseUnverified === 'string' ? error.releaseUnverified : undefined)));
|
|
49
53
|
const allowed = ['assigned_proxy_required', 'runner_context_required', 'uploader_integrity_refused',
|
|
50
|
-
'uploader_source_unavailable', ...owner.codes];
|
|
54
|
+
'uploader_source_unavailable', 'mobile_release_intent_unconfirmed', ...owner.codes];
|
|
51
55
|
receipt = {ok: false, code: allowed.includes(error.message) ? error.message : 'uploader_failed',
|
|
52
56
|
attempts: 0, review_pending: false};
|
|
53
57
|
if (owner.codes.includes(error.message) && error.operationResult) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.132
|
package/package.json
CHANGED
package/templates/deploy.yml
CHANGED
|
@@ -550,9 +550,6 @@ jobs:
|
|
|
550
550
|
# The wrapper verifies the unchanged pinned official uploader and classifies
|
|
551
551
|
# its immediate result. Only explicit expired/deleted edits retry normally;
|
|
552
552
|
# only Play's explicit review-hold refusal changes the review flag.
|
|
553
|
-
- name: Record Android upload intent
|
|
554
|
-
if: ${{ steps.mode.outputs.mode == 'local' && steps.play.outputs.ready == 'true' }}
|
|
555
|
-
run: node .github/actions/swift-app/scripts/mobile_release.cjs begin-upload android
|
|
556
553
|
- name: Upload Android release to Google Play
|
|
557
554
|
id: play-upload
|
|
558
555
|
if: ${{ steps.mode.outputs.mode == 'local' && steps.play.outputs.ready == 'true' }}
|
|
@@ -561,6 +558,7 @@ jobs:
|
|
|
561
558
|
GOOGLE_STORE_PROXY_URL: ${{ secrets.GOOGLE_STORE_PROXY_URL }}
|
|
562
559
|
GITHUB_TOKEN: ${{ github.token }}
|
|
563
560
|
with:
|
|
561
|
+
mobileReleaseIntentScript: ${{ github.workspace }}/.github/actions/swift-app/scripts/mobile_release.cjs
|
|
564
562
|
serviceAccountJson: ${{ steps.android.outputs.play-service-account }}
|
|
565
563
|
packageName: ${{ steps.android.outputs.package-name }}
|
|
566
564
|
releaseFiles: ${{ steps.android.outputs.bundle-path }}
|