gowalk-cicd 1.0.106 → 1.0.108

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
@@ -188,10 +188,10 @@ node /path/to/gowalk-cicd/bin/cli.mjs
188
188
  URL/pin/schema/release fields are checked before reuse. Blank, wildcard and version-file inputs
189
189
  resolve online. Missing or invalid metadata falls back to the required proxied GET; missing
190
190
  account transport still refuses even with a warm cache. SDK keys and checksum checks stay unchanged.
191
- - Gradle caches use explicit checksum-pinned restore/save actions, each optional and bounded
192
- to two minutes. Preserve setup-java's key inputs and absolute cache paths to reuse existing
193
- caches. Java setup, builds and store uploads remain mandatory; save runs after delivery.
194
- The cache-only preloader also admits the pinned `restore-only`/`save-only` entrypoints.
191
+ - Gradle caches use checksum-pinned restore/save actions, each optional and bounded to two minutes.
192
+ Preserve setup-java's complete keys, inputs and absolute paths; restore the same OS/architecture prefix.
193
+ Failed releases save distinct partial keys unless cancelled; completed keys require success. Builds remain required.
194
+ Only pinned cache entrypoints get cache transport; see [cache behavior](docs/GRADLE_CACHE.md) before adoption.
195
195
  - GitHub artifact uploads have their own checksum-pinned `artifact_env.cjs` process scope.
196
196
  It reuses the cache transport's approved HTTPS request guard, then removes inherited proxy
197
197
  variables only inside the official `upload-artifact` process. Unknown programs/origins refuse;
package/README.md CHANGED
@@ -40,11 +40,12 @@ Merge the exact validated candidate through the repository's protected PR. Only
40
40
  web, documentation and tooling landings do not trigger a store build. Backend and web retain
41
41
  their own workflows. Web compilation no longer starts just because a plugin version marker changed.
42
42
 
43
- The intent binds committed source and a digest of repository variables. A changed source input
44
- or compiled variable refuses before builds; prepare a new intent after the repair. Native iOS
43
+ The intent binds committed source and effective organization/repository variables, with repository
44
+ precedence. A changed source input or compiled variable refuses before builds; prepare a new intent after the repair. Native iOS
45
45
  and Android directories are scoped to their own platform. Unknown inputs, embedded editors,
46
46
  assets, scripts, dependency locks and backend-generated resources remain in the conservative
47
- source fingerprint. There is no blanket editor/backend exclusion from the input proof.
47
+ source fingerprint. Documents remain inputs because an app may bundle them. There is no blanket
48
+ editor/backend exclusion from the input proof. These conservative hashes do not add push triggers.
48
49
 
49
50
  The gate records each platform in GitHub deployment receipts, scoped to that input fingerprint.
50
51
  A confirmed upload is reused on subsequent attempts and emits `mobile_upload_reused` with the
@@ -1 +1 @@
1
- 1.0.106
1
+ 1.0.108
@@ -10,7 +10,8 @@ const digest = value => createHash('sha256').update(value).digest('hex');
10
10
 
11
11
  function input(name, platform) {
12
12
  if (name === INTENT || name.startsWith('.factory/progress/') || name.startsWith('creds/')) return false;
13
- if (/^(README|CHANGELOG|AGENTS|CLAUDE)\.md$/.test(name) || /^docs\/.*\.md$/.test(name)) return false;
13
+ // Documents may be bundled resources or test inputs. Promotion is explicit, so
14
+ // retaining them here cannot make an ordinary documentation push deploy mobile.
14
15
  if (platform === 'ios' && name.startsWith('android/')) return false;
15
16
  if (platform === 'android' && name.startsWith('ios/')) return false;
16
17
  // Backend and web deployment alone never promote a mobile release. Their source
@@ -1 +1 @@
1
- 1.0.106
1
+ 1.0.108
@@ -1 +1 @@
1
- 1.0.106
1
+ 1.0.108
@@ -0,0 +1,32 @@
1
+ # Gradle dependency retention
2
+
3
+ The mobile release workflow retains completed dependency downloads even when its build or a
4
+ later store operation fails. Both cache operations remain optional and bounded to two minutes;
5
+ a cache result cannot turn a failed build or upload green. Cancelled jobs and workflows reusing
6
+ a confirmed upload do not save Gradle caches.
7
+
8
+ Successful jobs preserve the original setup-java complete key, dependency inputs and absolute
9
+ cache paths. Failed jobs save a distinct `-partial-<run_id>-<attempt>` suffix instead, so a
10
+ partial download cannot occupy the immutable completed key or prevent a later full save.
11
+ Restoration first uses the complete key, then the existing same-OS/architecture key prefix.
12
+ Required Gradle work resolves any still-missing dependencies through the assigned account exit.
13
+ The pinned cache preloader remains confined to the official cache processes.
14
+
15
+ GitHub caches are branch-scoped: task branches cannot restore sibling branches' caches, while
16
+ default-branch caches can serve subsequent task branches. The normal default-branch release
17
+ therefore retains useful downloads after failure as well as after successful delivery. It
18
+ adds no warming workflow, extra main validation, upload retry or release dispatch.
19
+
20
+ On adoption, preserve app-specific dependency inputs, platforms and existing restore identities.
21
+ Candidate and release workflows need compatible keys, paths and compression versions to share
22
+ default-branch caches. An app's custom prefix needs an explicit compatible fallback; changing a
23
+ package pin alone does not update custom workflow bytes. Keep the current task branch and its
24
+ cache while repairing a failed candidate; do not rotate branches merely to retry it.
25
+
26
+ Verify the actual cache's branch, key, size and restore/save result. A successful cache action
27
+ does not itself prove a hit or a complete dependency graph. Never transfer task-branch caches
28
+ into a trusted default-branch scope by bypassing GitHub's restrictions.
29
+
30
+ See [GitHub's cache restrictions and key matching][cache-rules].
31
+
32
+ [cache-rules]: https://docs.github.com/en/actions/reference/workflows-and-actions/dependency-caching
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gowalk-cicd",
3
- "version": "1.0.106",
3
+ "version": "1.0.108",
4
4
  "description": "Zero-config GitHub Actions delivery for iOS TestFlight and Android Google Play.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -20,7 +20,8 @@
20
20
  "!backend-action/**/*.py[cod]",
21
21
  "templates/",
22
22
  "README.md",
23
- "CLAUDE.md"
23
+ "CLAUDE.md",
24
+ "docs/GRADLE_CACHE.md"
24
25
  ],
25
26
  "keywords": [
26
27
  "ios",
package/src/release.mjs CHANGED
@@ -2,6 +2,29 @@
2
2
  import {execFileSync} from 'node:child_process';
3
3
  import inputs from '../action/scripts/mobile_inputs.cjs';
4
4
 
5
+ export function variables(repository, execute) {
6
+ const info = JSON.parse(execute('gh', ['api', `repos/${repository}`]));
7
+ if (info.full_name !== repository || !['User', 'Organization'].includes(info.owner?.type)) {
8
+ throw Error('mobile_release_repository_unverified');
9
+ }
10
+ const scopes = info.owner.type === 'Organization' ? ['organization-variables', 'variables'] : ['variables'];
11
+ const result = {};
12
+ for (const scope of scopes) {
13
+ const pages = JSON.parse(execute('gh', ['api', `repos/${repository}/actions/${scope}?per_page=100`,
14
+ '--paginate', '--slurp']));
15
+ if (!Array.isArray(pages) || pages.some(page => !Array.isArray(page.variables))) {
16
+ throw Error('mobile_release_configuration_unverified');
17
+ }
18
+ for (const row of pages.flatMap(page => page.variables)) {
19
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(row.name) || typeof row.value !== 'string') {
20
+ throw Error('mobile_release_configuration_unverified');
21
+ }
22
+ result[row.name] = row.value;
23
+ }
24
+ }
25
+ return result;
26
+ }
27
+
5
28
  export function release(platform) {
6
29
  const execute = (command, args) => execFileSync(command, args, {
7
30
  encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 60000,
@@ -9,8 +32,5 @@ export function release(platform) {
9
32
  const remote = execute('git', ['remote', 'get-url', 'origin']);
10
33
  const match = /^(?:git@github\.com:|https:\/\/github\.com\/)([\w.-]+\/[\w.-]+?)(?:\.git)?$/.exec(remote);
11
34
  if (!match) throw Error('mobile_release_repository_unverified');
12
- const pages = JSON.parse(execute('gh', ['api', `repos/${match[1]}/actions/variables?per_page=100`,
13
- '--paginate', '--slurp']));
14
- const variables = Object.fromEntries(pages.flatMap(page => page.variables).map(row => [row.name, row.value]));
15
- return inputs.create(platform === 'both' ? ['ios', 'android'] : [platform], variables);
35
+ return inputs.create(platform === 'both' ? ['ios', 'android'] : [platform], variables(match[1], execute));
16
36
  }
@@ -403,6 +403,8 @@ jobs:
403
403
  ${{ format('setup-java-{0}-{1}-gradle-{2}', runner.os, steps.gradle_scope.outputs.arch,
404
404
  hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'buildSrc/**/Versions.kt',
405
405
  'buildSrc/**/Dependencies.kt', 'gradle/*.versions.toml', '**/versions.properties')) }}
406
+ restore-keys: >-
407
+ ${{ format('setup-java-{0}-{1}-gradle-', runner.os, steps.gradle_scope.outputs.arch) }}
406
408
  - name: Set up Flutter
407
409
  if: ${{ steps.mode.outputs.mode == 'local' && steps.flutter.outputs.enabled == 'true' }}
408
410
  uses: ./.github/actions/android-app/flutter-setup
@@ -581,7 +583,7 @@ jobs:
581
583
 
582
584
  - name: Save Gradle dependencies
583
585
  if: >-
584
- ${{ success() && steps.mode.outputs.mode == 'local'
586
+ ${{ !cancelled() && steps.mode.outputs.mode == 'local'
585
587
  && steps.gradle_cache.outputs.cache-primary-key != ''
586
588
  && steps.gradle_cache.outputs.cache-hit != 'true' }}
587
589
  uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25
@@ -593,7 +595,10 @@ jobs:
593
595
  path: |
594
596
  ${{ steps.gradle_scope.outputs.home }}/.gradle/caches
595
597
  ${{ steps.gradle_scope.outputs.home }}/.gradle/wrapper
596
- key: ${{ steps.gradle_cache.outputs.cache-primary-key }}
598
+ key: >-
599
+ ${{ job.status == 'success' && steps.gradle_cache.outputs.cache-primary-key
600
+ || format('{0}-partial-{1}-{2}', steps.gradle_cache.outputs.cache-primary-key,
601
+ github.run_id, github.run_attempt) }}
597
602
 
598
603
  # GitHub only registers a newly added workflow after it reaches the default
599
604
  # branch. A brand-new app's feature branch therefore cannot dispatch the