@invarn/cibuild 2.6.5 → 2.6.7
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/dist/cli.cjs +10 -10
- package/dist/src/commands/android-gms-guard.test.d.ts +9 -0
- package/dist/src/commands/android-gms-guard.test.d.ts.map +1 -0
- package/dist/src/commands/android-gms-guard.test.js +78 -0
- package/dist/src/commands/android-java-version.test.d.ts +12 -0
- package/dist/src/commands/android-java-version.test.d.ts.map +1 -0
- package/dist/src/commands/android-java-version.test.js +95 -0
- package/dist/src/commands/android-scanner.d.ts +84 -0
- package/dist/src/commands/android-scanner.d.ts.map +1 -1
- package/dist/src/commands/android-scanner.js +195 -7
- package/dist/src/commands/build.d.ts.map +1 -1
- package/dist/src/commands/build.js +5 -5
- package/dist/src/yaml/cache-key-missing-file.test.d.ts +12 -0
- package/dist/src/yaml/cache-key-missing-file.test.d.ts.map +1 -0
- package/dist/src/yaml/cache-key-missing-file.test.js +116 -0
- package/dist/src/yaml/converter.d.ts.map +1 -1
- package/dist/src/yaml/converter.js +32 -2
- package/dist/src/yaml/env-resolver.d.ts +13 -0
- package/dist/src/yaml/env-resolver.d.ts.map +1 -1
- package/dist/src/yaml/env-resolver.js +28 -8
- package/dist/src/yaml/steps/android.d.ts.map +1 -1
- package/dist/src/yaml/steps/android.js +17 -1
- package/dist/src/yaml/steps/steps.test.js +32 -0
- package/package.json +1 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A plugin applied inside `if (file("…").exists()) { … }` is conditional on a
|
|
3
|
+
* file the build may not have. Counting it as a hard credential requirement
|
|
4
|
+
* sends the user looking for a file the build never asks for — and, when the
|
|
5
|
+
* same rule is used to predict outcomes, reports projects as blocked that
|
|
6
|
+
* build green with no credential at all.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=android-gms-guard.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"android-gms-guard.test.d.ts","sourceRoot":"","sources":["../../../src/commands/android-gms-guard.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A plugin applied inside `if (file("…").exists()) { … }` is conditional on a
|
|
3
|
+
* file the build may not have. Counting it as a hard credential requirement
|
|
4
|
+
* sends the user looking for a file the build never asks for — and, when the
|
|
5
|
+
* same rule is used to predict outcomes, reports projects as blocked that
|
|
6
|
+
* build green with no credential at all.
|
|
7
|
+
*/
|
|
8
|
+
import { describe, test, expect } from '@jest/globals';
|
|
9
|
+
import { stripExistenceGuardedBlocks } from './android-scanner.js';
|
|
10
|
+
describe('stripExistenceGuardedBlocks', () => {
|
|
11
|
+
test('removes a Kotlin DSL existence guard and its body', () => {
|
|
12
|
+
const content = `
|
|
13
|
+
plugins {
|
|
14
|
+
id("com.android.application")
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (file("google-services.json").exists()) {
|
|
18
|
+
apply(plugin = libs.plugins.gms.googleServices.get().pluginId)
|
|
19
|
+
}
|
|
20
|
+
`;
|
|
21
|
+
const stripped = stripExistenceGuardedBlocks(content);
|
|
22
|
+
expect(stripped).toContain('com.android.application');
|
|
23
|
+
expect(stripped).not.toContain('googleServices');
|
|
24
|
+
});
|
|
25
|
+
test('removes a Groovy existence guard', () => {
|
|
26
|
+
const content = `
|
|
27
|
+
if (file('google-services.json').exists()) {
|
|
28
|
+
apply plugin: 'com.google.gms.google-services'
|
|
29
|
+
}
|
|
30
|
+
`;
|
|
31
|
+
expect(stripExistenceGuardedBlocks(content)).not.toContain('google-services');
|
|
32
|
+
});
|
|
33
|
+
test('removes a guard qualified by a project receiver', () => {
|
|
34
|
+
const content = `
|
|
35
|
+
if (rootProject.file("app/google-services.json").exists()) {
|
|
36
|
+
apply(plugin = "com.google.gms.google-services")
|
|
37
|
+
}
|
|
38
|
+
`;
|
|
39
|
+
expect(stripExistenceGuardedBlocks(content)).not.toContain('google-services');
|
|
40
|
+
});
|
|
41
|
+
test('keeps nested braces inside the guard body together', () => {
|
|
42
|
+
const content = `
|
|
43
|
+
if (file("google-services.json").exists()) {
|
|
44
|
+
android { buildTypes { release { } } }
|
|
45
|
+
apply(plugin = "com.google.gms.google-services")
|
|
46
|
+
}
|
|
47
|
+
val keep = "after"
|
|
48
|
+
`;
|
|
49
|
+
const stripped = stripExistenceGuardedBlocks(content);
|
|
50
|
+
expect(stripped).not.toContain('google-services');
|
|
51
|
+
expect(stripped).toContain('val keep = "after"');
|
|
52
|
+
});
|
|
53
|
+
test('is not fooled by a brace inside a string literal', () => {
|
|
54
|
+
const content = `
|
|
55
|
+
if (file("google-services.json").exists()) {
|
|
56
|
+
val template = "\${'{'}not a block"
|
|
57
|
+
apply(plugin = "com.google.gms.google-services")
|
|
58
|
+
}
|
|
59
|
+
val keep = "after"
|
|
60
|
+
`;
|
|
61
|
+
const stripped = stripExistenceGuardedBlocks(content);
|
|
62
|
+
expect(stripped).not.toContain('google-services');
|
|
63
|
+
expect(stripped).toContain('val keep = "after"');
|
|
64
|
+
});
|
|
65
|
+
test('leaves an unguarded declaration exactly where it was', () => {
|
|
66
|
+
const content = `
|
|
67
|
+
plugins {
|
|
68
|
+
id("com.google.gms.google-services")
|
|
69
|
+
}
|
|
70
|
+
`;
|
|
71
|
+
expect(stripExistenceGuardedBlocks(content)).toBe(content);
|
|
72
|
+
});
|
|
73
|
+
test('leaves content alone when the guard never closes', () => {
|
|
74
|
+
const content = 'if (file("google-services.json").exists()) {\n apply(plugin = "x")\n';
|
|
75
|
+
expect(stripExistenceGuardedBlocks(content)).toBe(content);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
//# sourceMappingURL=android-gms-guard.test.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which JDK a generated Android pipeline asks for.
|
|
3
|
+
*
|
|
4
|
+
* Two constraints decide it and the old `Math.max(detected ?? 17, 17)` knew
|
|
5
|
+
* neither: build machines install a fixed set of JDKs, and Gradle refuses to
|
|
6
|
+
* start on a JDK newer than it knows about. Naming a JDK that is not
|
|
7
|
+
* installed fails at "Set the Java version", before a line compiles; raising
|
|
8
|
+
* a project onto a JDK its Gradle cannot run makes an old wrapper
|
|
9
|
+
* unbuildable by construction.
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=android-java-version.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"android-java-version.test.d.ts","sourceRoot":"","sources":["../../../src/commands/android-java-version.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which JDK a generated Android pipeline asks for.
|
|
3
|
+
*
|
|
4
|
+
* Two constraints decide it and the old `Math.max(detected ?? 17, 17)` knew
|
|
5
|
+
* neither: build machines install a fixed set of JDKs, and Gradle refuses to
|
|
6
|
+
* start on a JDK newer than it knows about. Naming a JDK that is not
|
|
7
|
+
* installed fails at "Set the Java version", before a line compiles; raising
|
|
8
|
+
* a project onto a JDK its Gradle cannot run makes an old wrapper
|
|
9
|
+
* unbuildable by construction.
|
|
10
|
+
*/
|
|
11
|
+
import { describe, test, expect } from '@jest/globals';
|
|
12
|
+
import { AVAILABLE_JAVA_VERSIONS, gradleJavaCeiling, gradleJavaFloor, javaVersionProblem, parseGradleWrapperVersion, runnableJavaVersion, } from './android-scanner.js';
|
|
13
|
+
describe('parseGradleWrapperVersion', () => {
|
|
14
|
+
test('reads the version out of a distributionUrl', () => {
|
|
15
|
+
expect(parseGradleWrapperVersion('distributionUrl=https\\://services.gradle.org/distributions/gradle-8.9-bin.zip')).toBe('8.9');
|
|
16
|
+
});
|
|
17
|
+
test('reads an -all distribution and a three-part version', () => {
|
|
18
|
+
expect(parseGradleWrapperVersion('distributionUrl=https\\://services.gradle.org/distributions/gradle-5.2.1-all.zip')).toBe('5.2.1');
|
|
19
|
+
});
|
|
20
|
+
test('reads a release-candidate version', () => {
|
|
21
|
+
expect(parseGradleWrapperVersion('distributionUrl=https\\://services.gradle.org/distributions/gradle-9.0-rc-1-bin.zip')).toBe('9.0-rc-1');
|
|
22
|
+
});
|
|
23
|
+
test('returns undefined for a properties file that pins nothing', () => {
|
|
24
|
+
expect(parseGradleWrapperVersion('distributionBase=GRADLE_USER_HOME')).toBeUndefined();
|
|
25
|
+
expect(parseGradleWrapperVersion('')).toBeUndefined();
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
describe('gradleJavaCeiling / gradleJavaFloor', () => {
|
|
29
|
+
test('tracks what each Gradle line can run on', () => {
|
|
30
|
+
expect(gradleJavaCeiling('4.10.2')).toBe(8);
|
|
31
|
+
expect(gradleJavaCeiling('5.2.1')).toBe(11);
|
|
32
|
+
expect(gradleJavaCeiling('6.9')).toBe(15);
|
|
33
|
+
expect(gradleJavaCeiling('7.6.1')).toBe(17);
|
|
34
|
+
expect(gradleJavaCeiling('8.9')).toBe(21);
|
|
35
|
+
expect(gradleJavaCeiling('9.4.0')).toBe(24);
|
|
36
|
+
});
|
|
37
|
+
test('knows Gradle 9 dropped everything below 17', () => {
|
|
38
|
+
expect(gradleJavaFloor('8.9')).toBe(8);
|
|
39
|
+
expect(gradleJavaFloor('9.0')).toBe(17);
|
|
40
|
+
});
|
|
41
|
+
test('says nothing about a version it cannot read', () => {
|
|
42
|
+
expect(gradleJavaCeiling(undefined)).toBeUndefined();
|
|
43
|
+
expect(gradleJavaCeiling('nightly')).toBeUndefined();
|
|
44
|
+
expect(gradleJavaFloor(undefined)).toBeUndefined();
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
describe('runnableJavaVersion', () => {
|
|
48
|
+
test('stays on the default when the default covers the declaration', () => {
|
|
49
|
+
// 11 is installed, but AGP 8.x cannot run on it — a project declaring
|
|
50
|
+
// sourceCompatibility 11 must still be built on 17.
|
|
51
|
+
expect(runnableJavaVersion(11)).toBe(17);
|
|
52
|
+
expect(runnableJavaVersion(17)).toBe(17);
|
|
53
|
+
expect(runnableJavaVersion(21)).toBe(21);
|
|
54
|
+
});
|
|
55
|
+
test('defaults to the preferred JDK when nothing is declared', () => {
|
|
56
|
+
expect(runnableJavaVersion(undefined)).toBe(17);
|
|
57
|
+
});
|
|
58
|
+
test('steps down to 11 only when the wrapper rules the default out', () => {
|
|
59
|
+
expect(runnableJavaVersion(undefined, '5.2.1')).toBe(11);
|
|
60
|
+
expect(runnableJavaVersion(11, '5.2.1')).toBe(11);
|
|
61
|
+
expect(runnableJavaVersion(undefined, '6.9')).toBe(11);
|
|
62
|
+
});
|
|
63
|
+
test('never names a JDK no build machine has', () => {
|
|
64
|
+
expect(AVAILABLE_JAVA_VERSIONS).toContain(runnableJavaVersion(23));
|
|
65
|
+
expect(AVAILABLE_JAVA_VERSIONS).toContain(runnableJavaVersion(25, '8.9'));
|
|
66
|
+
});
|
|
67
|
+
test('lets an old wrapper cap a newer declaration', () => {
|
|
68
|
+
// Gradle 7.x tops out at 17 even though 21 is installed.
|
|
69
|
+
expect(runnableJavaVersion(21, '7.6.1')).toBe(17);
|
|
70
|
+
});
|
|
71
|
+
test('honours the Gradle 9 floor of 17', () => {
|
|
72
|
+
expect(runnableJavaVersion(8, '9.0')).toBe(17);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
describe('javaVersionProblem', () => {
|
|
76
|
+
test('names a Gradle version no installed JDK can run', () => {
|
|
77
|
+
// 4.10.2 tops out at Java 8, and no image carries 8.
|
|
78
|
+
const problem = javaVersionProblem(undefined, '4.10.2');
|
|
79
|
+
expect(problem).toContain('Gradle 4.10.2');
|
|
80
|
+
expect(problem).toContain('Java 8');
|
|
81
|
+
});
|
|
82
|
+
test('names a declaration above every installed JDK', () => {
|
|
83
|
+
const problem = javaVersionProblem(23, '8.9');
|
|
84
|
+
expect(problem).toContain('Java 23');
|
|
85
|
+
expect(problem).toContain('11, 17 and 21');
|
|
86
|
+
});
|
|
87
|
+
test('is silent when every constraint was honoured', () => {
|
|
88
|
+
expect(javaVersionProblem(17, '8.9')).toBeUndefined();
|
|
89
|
+
expect(javaVersionProblem(undefined, '8.9')).toBeUndefined();
|
|
90
|
+
expect(javaVersionProblem(undefined, undefined)).toBeUndefined();
|
|
91
|
+
// 5.2.1 used to be a problem. The images carry 11 now, so it is not.
|
|
92
|
+
expect(javaVersionProblem(undefined, '5.2.1')).toBeUndefined();
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
//# sourceMappingURL=android-java-version.test.js.map
|
|
@@ -11,6 +11,8 @@ export interface ScanResult {
|
|
|
11
11
|
warnings: BuildWarning[];
|
|
12
12
|
/** Highest Java version requirement detected in Gradle files (e.g. 17, 21). */
|
|
13
13
|
detectedJavaVersion?: number;
|
|
14
|
+
/** Gradle version the wrapper pins, e.g. "8.9". Undefined when there is no wrapper. */
|
|
15
|
+
detectedGradleVersion?: string;
|
|
14
16
|
/** Build types, product flavors, and all variant combinations detected in Gradle files. */
|
|
15
17
|
buildVariants: BuildVariants;
|
|
16
18
|
}
|
|
@@ -22,6 +24,88 @@ export interface BuildVariants {
|
|
|
22
24
|
/** All variant combinations. Equals buildTypes when no product flavors are defined. */
|
|
23
25
|
variants: string[];
|
|
24
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Removes `if (file("…").exists()) { … }` blocks from build-file content.
|
|
29
|
+
*
|
|
30
|
+
* A plugin applied inside one of these is *conditional on a file the build
|
|
31
|
+
* may not have*. Projects use the idiom precisely so a checkout without the
|
|
32
|
+
* credential still builds:
|
|
33
|
+
*
|
|
34
|
+
* if (file("google-services.json").exists()) {
|
|
35
|
+
* apply(plugin = libs.plugins.gms.googleServices.get().pluginId)
|
|
36
|
+
* }
|
|
37
|
+
*
|
|
38
|
+
* Reading the declaration and ignoring the guard turns "this project builds
|
|
39
|
+
* fine without a credential" into "this project cannot build without one" —
|
|
40
|
+
* a warning that sends the user looking for a file the build never asks for.
|
|
41
|
+
*
|
|
42
|
+
* Brace matching skips quoted strings so a `{` inside a literal cannot end
|
|
43
|
+
* the block early. Anything it cannot match to a close brace is left alone:
|
|
44
|
+
* losing a real declaration is worse than keeping a guarded one.
|
|
45
|
+
*/
|
|
46
|
+
export declare function stripExistenceGuardedBlocks(content: string): string;
|
|
47
|
+
/**
|
|
48
|
+
* The Gradle version a wrapper pins, read out of its `distributionUrl`.
|
|
49
|
+
* `…/gradle-8.9-bin.zip` → `8.9`.
|
|
50
|
+
*
|
|
51
|
+
* This bounds which JDK the project can build on: Gradle refuses to start on
|
|
52
|
+
* a JDK newer than it knows about, so the wrapper is a hard ceiling that no
|
|
53
|
+
* `sourceCompatibility` declaration can raise.
|
|
54
|
+
*
|
|
55
|
+
* The trailing `-bin` / `-all` belongs to the file name rather than the
|
|
56
|
+
* version, and a release candidate spends two more hyphens on `-rc-1`, so the
|
|
57
|
+
* version group has to be able to give its last segment back.
|
|
58
|
+
*/
|
|
59
|
+
export declare function parseGradleWrapperVersion(content: string): string | undefined;
|
|
60
|
+
/**
|
|
61
|
+
* The newest Java release a given Gradle version can run on, or undefined
|
|
62
|
+
* when the version string says nothing usable.
|
|
63
|
+
*/
|
|
64
|
+
export declare function gradleJavaCeiling(gradleVersion: string | undefined): number | undefined;
|
|
65
|
+
/** The oldest Java release a given Gradle version will start on. */
|
|
66
|
+
export declare function gradleJavaFloor(gradleVersion: string | undefined): number | undefined;
|
|
67
|
+
/**
|
|
68
|
+
* The JDKs a build machine installs, and therefore the only values the
|
|
69
|
+
* generated `set-java-version` step can satisfy.
|
|
70
|
+
*
|
|
71
|
+
* 11 joined the images on 2026-09-05, for Gradle 5.x and 6.x — which cannot
|
|
72
|
+
* *start* on 17, whatever the sources declare. It is a fallback, never a
|
|
73
|
+
* preference; see `PREFERRED_JAVA_VERSION`.
|
|
74
|
+
*/
|
|
75
|
+
export declare const AVAILABLE_JAVA_VERSIONS: number[];
|
|
76
|
+
/**
|
|
77
|
+
* The JDK to write whenever nothing forces otherwise.
|
|
78
|
+
*
|
|
79
|
+
* This is what makes 11 safe to list. The selection below used to answer with
|
|
80
|
+
* the *lowest* usable JDK, which was harmless while the lowest was 17. With 11
|
|
81
|
+
* installed that rule would write `JAVA_VERSION: 11` for every project whose
|
|
82
|
+
* `sourceCompatibility` is 11 — and AGP 8.x will not run on JDK 11, so
|
|
83
|
+
* pipelines that build today would stop building.
|
|
84
|
+
*/
|
|
85
|
+
export declare const PREFERRED_JAVA_VERSION = 17;
|
|
86
|
+
/**
|
|
87
|
+
* The Java version to write into a generated pipeline: `PREFERRED_JAVA_VERSION`
|
|
88
|
+
* whenever it satisfies both what the sources declare and what the Gradle
|
|
89
|
+
* wrapper can run on, and the nearest available JDK that does when it cannot.
|
|
90
|
+
*
|
|
91
|
+
* Source compatibility is a floor, not an exact request — a project
|
|
92
|
+
* declaring 11 compiles fine on 17 — but it is not the only constraint.
|
|
93
|
+
* Gradle starts before it reads a single `sourceCompatibility`, so a wrapper
|
|
94
|
+
* pinning an old Gradle caps the JDK no matter what the sources say, and a
|
|
95
|
+
* declaration above every installed JDK cannot be honoured at all.
|
|
96
|
+
*
|
|
97
|
+
* Falls back to the preferred JDK — not the lowest — when the constraints
|
|
98
|
+
* cannot all be met, because a pipeline has to name something and the
|
|
99
|
+
* unsatisfiable cases are overwhelmingly "declared something newer than we
|
|
100
|
+
* have", where 17 is a far better guess than 11. `javaVersionProblem` says
|
|
101
|
+
* what was given up so the caller can warn.
|
|
102
|
+
*/
|
|
103
|
+
export declare function runnableJavaVersion(detectedJavaVersion: number | undefined, gradleVersion?: string): number;
|
|
104
|
+
/**
|
|
105
|
+
* What `runnableJavaVersion` could not honour, as a sentence, or undefined
|
|
106
|
+
* when it honoured everything.
|
|
107
|
+
*/
|
|
108
|
+
export declare function javaVersionProblem(detectedJavaVersion: number | undefined, gradleVersion?: string): string | undefined;
|
|
25
109
|
/**
|
|
26
110
|
* Detects build types and product flavors from Gradle files by static parsing.
|
|
27
111
|
* Always includes "debug" and "release" as defaults.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"android-scanner.d.ts","sourceRoot":"","sources":["../../../src/commands/android-scanner.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,MAAM,CAAC;AAEjD,MAAM,MAAM,eAAe,GACvB,cAAc,GACd,SAAS,GACT,iBAAiB,GACjB,gBAAgB,GAChB,cAAc,GACd,UAAU,GACV,gBAAgB,CAAC;AAErB,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,eAAe,CAAC;IAC1B,QAAQ,EAAE,eAAe,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,+EAA+E;IAC/E,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,2FAA2F;IAC3F,aAAa,EAAE,aAAa,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B,gGAAgG;IAChG,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,wFAAwF;IACxF,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,uFAAuF;IACvF,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"android-scanner.d.ts","sourceRoot":"","sources":["../../../src/commands/android-scanner.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,MAAM,CAAC;AAEjD,MAAM,MAAM,eAAe,GACvB,cAAc,GACd,SAAS,GACT,iBAAiB,GACjB,gBAAgB,GAChB,cAAc,GACd,UAAU,GACV,gBAAgB,CAAC;AAErB,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,eAAe,CAAC;IAC1B,QAAQ,EAAE,eAAe,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,+EAA+E;IAC/E,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,uFAAuF;IACvF,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,2FAA2F;IAC3F,aAAa,EAAE,aAAa,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B,gGAAgG;IAChG,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,wFAAwF;IACxF,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,uFAAuF;IACvF,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AA+JD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAcnE;AAoKD;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG7E;AAQD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CASvF;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAIrF;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,UAAe,CAAC;AAEpD;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CACjC,mBAAmB,EAAE,MAAM,GAAG,SAAS,EACvC,aAAa,CAAC,EAAE,MAAM,GACrB,MAAM,CAYR;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,mBAAmB,EAAE,MAAM,GAAG,SAAS,EACvC,aAAa,CAAC,EAAE,MAAM,GACrB,MAAM,GAAG,SAAS,CAkBpB;AA6FD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,aAAa,CAmCxE;AAMD,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA4PjF;AAgBD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAyD3D"}
|
|
@@ -135,11 +135,74 @@ function parsePropertyKeys(propertiesContent) {
|
|
|
135
135
|
.map((l) => l.split("=")[0].trim())
|
|
136
136
|
.filter(Boolean);
|
|
137
137
|
}
|
|
138
|
-
/**
|
|
138
|
+
/**
|
|
139
|
+
* Removes `if (file("…").exists()) { … }` blocks from build-file content.
|
|
140
|
+
*
|
|
141
|
+
* A plugin applied inside one of these is *conditional on a file the build
|
|
142
|
+
* may not have*. Projects use the idiom precisely so a checkout without the
|
|
143
|
+
* credential still builds:
|
|
144
|
+
*
|
|
145
|
+
* if (file("google-services.json").exists()) {
|
|
146
|
+
* apply(plugin = libs.plugins.gms.googleServices.get().pluginId)
|
|
147
|
+
* }
|
|
148
|
+
*
|
|
149
|
+
* Reading the declaration and ignoring the guard turns "this project builds
|
|
150
|
+
* fine without a credential" into "this project cannot build without one" —
|
|
151
|
+
* a warning that sends the user looking for a file the build never asks for.
|
|
152
|
+
*
|
|
153
|
+
* Brace matching skips quoted strings so a `{` inside a literal cannot end
|
|
154
|
+
* the block early. Anything it cannot match to a close brace is left alone:
|
|
155
|
+
* losing a real declaration is worse than keeping a guarded one.
|
|
156
|
+
*/
|
|
157
|
+
export function stripExistenceGuardedBlocks(content) {
|
|
158
|
+
const guard = /if\s*\(\s*[A-Za-z0-9_.]*file\s*\(\s*[^)]*\)\s*\.exists\s*\(\s*\)\s*\)\s*\{/g;
|
|
159
|
+
let out = "";
|
|
160
|
+
let cursor = 0;
|
|
161
|
+
let match;
|
|
162
|
+
while ((match = guard.exec(content)) !== null) {
|
|
163
|
+
const bodyStart = match.index + match[0].length;
|
|
164
|
+
const end = matchingBrace(content, bodyStart);
|
|
165
|
+
if (end === -1)
|
|
166
|
+
continue;
|
|
167
|
+
out += content.slice(cursor, match.index);
|
|
168
|
+
cursor = end + 1;
|
|
169
|
+
guard.lastIndex = cursor;
|
|
170
|
+
}
|
|
171
|
+
return out + content.slice(cursor);
|
|
172
|
+
}
|
|
173
|
+
/** Index of the `}` closing a block whose body starts at `start`, or -1. */
|
|
174
|
+
function matchingBrace(content, start) {
|
|
175
|
+
let depth = 1;
|
|
176
|
+
let quote = null;
|
|
177
|
+
for (let i = start; i < content.length; i++) {
|
|
178
|
+
const ch = content[i];
|
|
179
|
+
if (quote) {
|
|
180
|
+
if (ch === "\\")
|
|
181
|
+
i++;
|
|
182
|
+
else if (ch === quote)
|
|
183
|
+
quote = null;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (ch === '"' || ch === "'")
|
|
187
|
+
quote = ch;
|
|
188
|
+
else if (ch === "{")
|
|
189
|
+
depth++;
|
|
190
|
+
else if (ch === "}" && --depth === 0)
|
|
191
|
+
return i;
|
|
192
|
+
}
|
|
193
|
+
return -1;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Returns true if the GMS google-services plugin is applied unconditionally
|
|
197
|
+
* in this content. A declaration guarded by the presence of
|
|
198
|
+
* `google-services.json` is not a credential requirement — see
|
|
199
|
+
* `stripExistenceGuardedBlocks`.
|
|
200
|
+
*/
|
|
139
201
|
function detectGmsPlugin(content) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
/id\s*["']com\.google\.gms\.google-services["']/.test(
|
|
202
|
+
const unguarded = stripExistenceGuardedBlocks(content);
|
|
203
|
+
return (/apply\s+plugin\s*:\s*['"]com\.google\.gms\.google-services['"]/.test(unguarded) ||
|
|
204
|
+
/id\s*\(\s*["']com\.google\.gms\.google-services["']\s*\)/.test(unguarded) ||
|
|
205
|
+
/id\s*["']com\.google\.gms\.google-services["']/.test(unguarded));
|
|
143
206
|
}
|
|
144
207
|
/** Returns true if a signingConfigs block exists. */
|
|
145
208
|
function detectSigningConfigs(content) {
|
|
@@ -260,6 +323,126 @@ function detectRequiredJavaVersion(gradleFiles) {
|
|
|
260
323
|
}
|
|
261
324
|
return versions.length > 0 ? Math.max(...versions) : undefined;
|
|
262
325
|
}
|
|
326
|
+
/**
|
|
327
|
+
* The Gradle version a wrapper pins, read out of its `distributionUrl`.
|
|
328
|
+
* `…/gradle-8.9-bin.zip` → `8.9`.
|
|
329
|
+
*
|
|
330
|
+
* This bounds which JDK the project can build on: Gradle refuses to start on
|
|
331
|
+
* a JDK newer than it knows about, so the wrapper is a hard ceiling that no
|
|
332
|
+
* `sourceCompatibility` declaration can raise.
|
|
333
|
+
*
|
|
334
|
+
* The trailing `-bin` / `-all` belongs to the file name rather than the
|
|
335
|
+
* version, and a release candidate spends two more hyphens on `-rc-1`, so the
|
|
336
|
+
* version group has to be able to give its last segment back.
|
|
337
|
+
*/
|
|
338
|
+
export function parseGradleWrapperVersion(content) {
|
|
339
|
+
const match = /gradle-(\d+(?:\.\d+)*(?:-[A-Za-z0-9.]+)*)-(?:bin|all)\.zip/.exec(content);
|
|
340
|
+
return match ? match[1] : undefined;
|
|
341
|
+
}
|
|
342
|
+
function detectGradleWrapperVersion(projectRoot) {
|
|
343
|
+
const path = resolve(projectRoot, "gradle", "wrapper", "gradle-wrapper.properties");
|
|
344
|
+
if (!existsSync(path))
|
|
345
|
+
return undefined;
|
|
346
|
+
return parseGradleWrapperVersion(safeRead(path));
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* The newest Java release a given Gradle version can run on, or undefined
|
|
350
|
+
* when the version string says nothing usable.
|
|
351
|
+
*/
|
|
352
|
+
export function gradleJavaCeiling(gradleVersion) {
|
|
353
|
+
const major = Number(/^(\d+)\./.exec(gradleVersion ?? "")?.[1]);
|
|
354
|
+
if (!Number.isInteger(major))
|
|
355
|
+
return undefined;
|
|
356
|
+
if (major <= 4)
|
|
357
|
+
return 8;
|
|
358
|
+
if (major === 5)
|
|
359
|
+
return 11;
|
|
360
|
+
if (major === 6)
|
|
361
|
+
return 15;
|
|
362
|
+
if (major === 7)
|
|
363
|
+
return 17;
|
|
364
|
+
if (major === 8)
|
|
365
|
+
return 21;
|
|
366
|
+
return 24;
|
|
367
|
+
}
|
|
368
|
+
/** The oldest Java release a given Gradle version will start on. */
|
|
369
|
+
export function gradleJavaFloor(gradleVersion) {
|
|
370
|
+
const major = Number(/^(\d+)\./.exec(gradleVersion ?? "")?.[1]);
|
|
371
|
+
if (!Number.isInteger(major))
|
|
372
|
+
return undefined;
|
|
373
|
+
return major >= 9 ? 17 : 8;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* The JDKs a build machine installs, and therefore the only values the
|
|
377
|
+
* generated `set-java-version` step can satisfy.
|
|
378
|
+
*
|
|
379
|
+
* 11 joined the images on 2026-09-05, for Gradle 5.x and 6.x — which cannot
|
|
380
|
+
* *start* on 17, whatever the sources declare. It is a fallback, never a
|
|
381
|
+
* preference; see `PREFERRED_JAVA_VERSION`.
|
|
382
|
+
*/
|
|
383
|
+
export const AVAILABLE_JAVA_VERSIONS = [11, 17, 21];
|
|
384
|
+
/**
|
|
385
|
+
* The JDK to write whenever nothing forces otherwise.
|
|
386
|
+
*
|
|
387
|
+
* This is what makes 11 safe to list. The selection below used to answer with
|
|
388
|
+
* the *lowest* usable JDK, which was harmless while the lowest was 17. With 11
|
|
389
|
+
* installed that rule would write `JAVA_VERSION: 11` for every project whose
|
|
390
|
+
* `sourceCompatibility` is 11 — and AGP 8.x will not run on JDK 11, so
|
|
391
|
+
* pipelines that build today would stop building.
|
|
392
|
+
*/
|
|
393
|
+
export const PREFERRED_JAVA_VERSION = 17;
|
|
394
|
+
/**
|
|
395
|
+
* The Java version to write into a generated pipeline: `PREFERRED_JAVA_VERSION`
|
|
396
|
+
* whenever it satisfies both what the sources declare and what the Gradle
|
|
397
|
+
* wrapper can run on, and the nearest available JDK that does when it cannot.
|
|
398
|
+
*
|
|
399
|
+
* Source compatibility is a floor, not an exact request — a project
|
|
400
|
+
* declaring 11 compiles fine on 17 — but it is not the only constraint.
|
|
401
|
+
* Gradle starts before it reads a single `sourceCompatibility`, so a wrapper
|
|
402
|
+
* pinning an old Gradle caps the JDK no matter what the sources say, and a
|
|
403
|
+
* declaration above every installed JDK cannot be honoured at all.
|
|
404
|
+
*
|
|
405
|
+
* Falls back to the preferred JDK — not the lowest — when the constraints
|
|
406
|
+
* cannot all be met, because a pipeline has to name something and the
|
|
407
|
+
* unsatisfiable cases are overwhelmingly "declared something newer than we
|
|
408
|
+
* have", where 17 is a far better guess than 11. `javaVersionProblem` says
|
|
409
|
+
* what was given up so the caller can warn.
|
|
410
|
+
*/
|
|
411
|
+
export function runnableJavaVersion(detectedJavaVersion, gradleVersion) {
|
|
412
|
+
const ceiling = gradleJavaCeiling(gradleVersion) ?? Infinity;
|
|
413
|
+
const floor = Math.max(detectedJavaVersion ?? 0, gradleJavaFloor(gradleVersion) ?? 0);
|
|
414
|
+
const usable = AVAILABLE_JAVA_VERSIONS.filter((v) => v >= floor && v <= ceiling).sort((a, b) => a - b);
|
|
415
|
+
if (usable.length === 0)
|
|
416
|
+
return PREFERRED_JAVA_VERSION;
|
|
417
|
+
if (usable.includes(PREFERRED_JAVA_VERSION))
|
|
418
|
+
return PREFERRED_JAVA_VERSION;
|
|
419
|
+
// Forced off the default: below it take the newest that fits under the
|
|
420
|
+
// ceiling, above it the oldest that clears the floor.
|
|
421
|
+
const below = usable.filter((v) => v < PREFERRED_JAVA_VERSION);
|
|
422
|
+
return below.length > 0 ? below[below.length - 1] : usable[0];
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* What `runnableJavaVersion` could not honour, as a sentence, or undefined
|
|
426
|
+
* when it honoured everything.
|
|
427
|
+
*/
|
|
428
|
+
export function javaVersionProblem(detectedJavaVersion, gradleVersion) {
|
|
429
|
+
// "11, 17 and 21", not "11 and 17 and 21" — a human reads this next to a
|
|
430
|
+
// build that will not start.
|
|
431
|
+
const sorted = [...AVAILABLE_JAVA_VERSIONS].sort((a, b) => a - b);
|
|
432
|
+
const installed = sorted.length > 1
|
|
433
|
+
? `${sorted.slice(0, -1).join(", ")} and ${sorted[sorted.length - 1]}`
|
|
434
|
+
: String(sorted[0]);
|
|
435
|
+
const ceiling = gradleJavaCeiling(gradleVersion);
|
|
436
|
+
const lowest = Math.min(...AVAILABLE_JAVA_VERSIONS);
|
|
437
|
+
if (ceiling !== undefined && ceiling < lowest) {
|
|
438
|
+
return `Gradle ${gradleVersion} runs on Java ${ceiling} at most, and build machines carry only ${installed}. This pipeline will very likely fail before it compiles anything — upgrade the Gradle wrapper.`;
|
|
439
|
+
}
|
|
440
|
+
const highest = Math.max(...AVAILABLE_JAVA_VERSIONS);
|
|
441
|
+
if ((detectedJavaVersion ?? 0) > highest) {
|
|
442
|
+
return `This project declares Java ${detectedJavaVersion}, and build machines carry only ${installed}. Writing Java ${runnableJavaVersion(detectedJavaVersion, gradleVersion)} instead — asking for ${detectedJavaVersion} would fail at "Set the Java version".`;
|
|
443
|
+
}
|
|
444
|
+
return undefined;
|
|
445
|
+
}
|
|
263
446
|
// ---------------------------------------------------------------------------
|
|
264
447
|
// Gitignore helper
|
|
265
448
|
// ---------------------------------------------------------------------------
|
|
@@ -399,6 +582,7 @@ export async function scanAndroidProject(projectRoot) {
|
|
|
399
582
|
// ------------------------------------------------------------------
|
|
400
583
|
const gradleFiles = findGradleFiles(projectRoot);
|
|
401
584
|
const detectedJavaVersion = detectRequiredJavaVersion(gradleFiles);
|
|
585
|
+
const detectedGradleVersion = detectGradleWrapperVersion(projectRoot);
|
|
402
586
|
const buildVariants = detectBuildVariants(gradleFiles);
|
|
403
587
|
// ------------------------------------------------------------------
|
|
404
588
|
// 3. Scan Gradle files
|
|
@@ -605,7 +789,7 @@ export async function scanAndroidProject(projectRoot) {
|
|
|
605
789
|
});
|
|
606
790
|
}
|
|
607
791
|
}
|
|
608
|
-
return { warnings, detectedJavaVersion, buildVariants };
|
|
792
|
+
return { warnings, detectedJavaVersion, detectedGradleVersion, buildVariants };
|
|
609
793
|
}
|
|
610
794
|
// ---------------------------------------------------------------------------
|
|
611
795
|
// Formatter
|
|
@@ -622,9 +806,13 @@ const CATEGORY_LABELS = {
|
|
|
622
806
|
export function formatScanResult(result) {
|
|
623
807
|
const lines = [];
|
|
624
808
|
const sep = "─".repeat(50);
|
|
625
|
-
// Always show the detected Java version
|
|
809
|
+
// Always show the detected Java version, and the one the pipeline will
|
|
810
|
+
// actually name — they differ whenever the declaration is below the oldest
|
|
811
|
+
// installed JDK or above the newest, and saying only the first made the
|
|
812
|
+
// second look like it had been honoured.
|
|
626
813
|
if (result.detectedJavaVersion !== undefined) {
|
|
627
|
-
|
|
814
|
+
const willUse = runnableJavaVersion(result.detectedJavaVersion, result.detectedGradleVersion);
|
|
815
|
+
lines.push(`ℹ Detected Java ${result.detectedJavaVersion} requirement — pipeline will use Java ${willUse}`);
|
|
628
816
|
lines.push("");
|
|
629
817
|
}
|
|
630
818
|
if (result.warnings.length === 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/commands/build.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/commands/build.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,oFAAoF;IACpF,YAAY,EAAE,KAAK,GAAG,KAAK,CAAC;IAC5B,8FAA8F;IAC9F,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,qBAAqB;IACpC,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;IAChB,+FAA+F;IAC/F,SAAS,EAAE,MAAM,CAAC;IAClB,6FAA6F;IAC7F,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,qBAAqB,CAAC;IAC/B,WAAW,EAAE,qBAAqB,CAAC;IACnC,OAAO,EAAE,qBAAqB,CAAC;CAChC;AAiBD,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,uBAAuB,CAAC;IACjC,WAAW,EAAE,uBAAuB,CAAC;IACrC,OAAO,EAAE,uBAAuB,CAAC;CAClC;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAoJD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,aAAa,GAAE,MAAgC,GAAG,MAAM,CAcvF;AAED,wBAAgB,uBAAuB,CACrC,WAAW,GAAE,MAAW,EACxB,KAAK,GAAE,YAAgL,EACvL,QAAQ,GAAE,gBAAmC,EAC7C,eAAe,GAAE,QAAQ,GAAG,KAAgB,EAC5C,aAAa,GAAE,QAAQ,GAAG,YAA2B,EACrD,aAAa,GAAE,MAAgC,GAC9C,MAAM,CA2NR;AAED,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,eAAe,EACtB,QAAQ,EAAE,mBAAmB,EAC7B,aAAa,GAAE,QAAQ,GAAG,YAA2B,EACrD,aAAa,GAAE,MAAgC,GAC9C,MAAM,CA4LR;AAiVD,wBAAsB,kBAAkB,CACtC,uBAAuB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,EAC1E,OAAO,GAAE;IACP,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,QAAQ,GAAG,YAAY,CAAC;CACpC,GACL,OAAO,CAAC,IAAI,CAAC,CA4Bf"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
2
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
3
3
|
import prompts from "prompts";
|
|
4
|
-
import { scanAndroidProject, formatScanResult } from "./android-scanner.js";
|
|
4
|
+
import { scanAndroidProject, formatScanResult, runnableJavaVersion, javaVersionProblem, } from "./android-scanner.js";
|
|
5
5
|
import { scanIosProject, formatIosScanResult } from "./ios-scanner.js";
|
|
6
6
|
import { SecretsManager } from "../yaml/secrets-manager.js";
|
|
7
7
|
import { collectFileSecret } from "./file-secret-collector.js";
|
|
@@ -1064,10 +1064,10 @@ async function handleAndroidBuildCommand(cwd, options, cacheTechnology) {
|
|
|
1064
1064
|
}
|
|
1065
1065
|
}
|
|
1066
1066
|
// 7. Generate and write the pipeline
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1067
|
+
const javaVersion = runnableJavaVersion(scanResult.detectedJavaVersion, scanResult.detectedGradleVersion);
|
|
1068
|
+
const javaProblem = javaVersionProblem(scanResult.detectedJavaVersion, scanResult.detectedGradleVersion);
|
|
1069
|
+
if (javaProblem)
|
|
1070
|
+
console.log(`\n⚠️ ${javaProblem}`);
|
|
1071
1071
|
const yaml = generateAndroidPipeline(javaVersion, setupOptions, variants, cacheTechnology, options.metaNamespace, detectDefaultBranch());
|
|
1072
1072
|
writeFileSync(outputPath, yaml, "utf-8");
|
|
1073
1073
|
console.log("\n✅ Generated .ci/pipelines/cibuild.yml");
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A cache key that cannot be computed costs a cache, not a pipeline.
|
|
3
|
+
*
|
|
4
|
+
* `cache_key: pods-{{checksum "Podfile.lock"}}` in a repository with no
|
|
5
|
+
* Podfile.lock used to abort conversion, so the build died at `cache-pull`
|
|
6
|
+
* before compiling a single file — including in repositories that use Swift
|
|
7
|
+
* Package Manager and have no reason to own a CocoaPods lockfile at all.
|
|
8
|
+
* Every other step keeps the hard failure: a checksum in a real input is a
|
|
9
|
+
* value that step needs.
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=cache-key-missing-file.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-key-missing-file.test.d.ts","sourceRoot":"","sources":["../../../src/yaml/cache-key-missing-file.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|