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 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
 
@@ -1 +1 @@
1
- 1.0.130
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: # the file a redirect writes, not a command
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: # a redirect belongs to the command it follows
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.130
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
- upload(program, env, directory, processRunner.execute, 3600000, cancelled,
45
- (attempt, result) => console.log(diagnostics.annotation(attempt, result))));
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.130
1
+ 1.0.132
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gowalk-cicd",
3
- "version": "1.0.130",
3
+ "version": "1.0.132",
4
4
  "description": "Zero-config GitHub Actions delivery for iOS TestFlight and Android Google Play.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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 }}