@invarn/cibuild 2.8.6 → 2.8.8

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.
@@ -38,7 +38,9 @@ export declare function xcodeContainersIn(dir: string): string[];
38
38
  *
39
39
  * KMM is checked before Android because both have Gradle files, and it is
40
40
  * decided by what the repository *is*: a module that applies the Kotlin
41
- * Multiplatform plugin, and an Apple consumer within one directory of the
41
+ * Multiplatform plugin or declares a Kotlin/Native Apple target in its own
42
+ * build file (garfiec/Librechat-Mobile applies the plugin only through a
43
+ * convention plugin), and an Apple consumer within one directory of the
42
44
  * root. The three conventional directory names (`shared`, `composeApp`,
43
45
  * `iosApp`) used to be the whole rule, and were wrong in both directions —
44
46
  * `joreilly/PeopleInSpace` (`common` + `PeopleInSpaceSwiftUI/`) and
@@ -1 +1 @@
1
- {"version":3,"file":"detect-project.d.ts","sourceRoot":"","sources":["../../../src/shared/detect-project.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK,CAAC;AAoB1D,iBAAS,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAM1C;AAUD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAYtD;AAED,+EAA+E;AAC/E,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAYvD;AAuED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CA4B7E;AAED,oEAAoE;AACpE,OAAO,EAAE,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"detect-project.d.ts","sourceRoot":"","sources":["../../../src/shared/detect-project.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK,CAAC;AAoB1D,iBAAS,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAM1C;AAUD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAYtD;AAED,+EAA+E;AAC/E,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAYvD;AAwED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CA4B7E;AAED,oEAAoE;AACpE,OAAO,EAAE,WAAW,EAAE,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
- import { declaresKotlinMultiplatformPlugin, parseSettingsModules, } from "./gradle-settings.js";
3
+ import { declaresKotlinMultiplatform, parseSettingsModules, } from "./gradle-settings.js";
4
4
  /** Directories that hold a copy of a project rather than the source of it. */
5
5
  const NON_SOURCE_DIRS = new Set([
6
6
  ".git",
@@ -141,18 +141,19 @@ function hasAppleConsumerWithinOneLevel(root) {
141
141
  }
142
142
  return false;
143
143
  }
144
- function moduleAppliesMultiplatformPlugin(root, module) {
144
+ /** The plugin, or a Kotlin/Native Apple target, in the module's own build file. */
145
+ function moduleIsMultiplatform(root, module) {
145
146
  for (const name of ["build.gradle.kts", "build.gradle"]) {
146
147
  const content = readOrNull(resolve(root, module, name));
147
- if (content !== null && declaresKotlinMultiplatformPlugin(content))
148
+ if (content !== null && declaresKotlinMultiplatform(content))
148
149
  return true;
149
150
  }
150
151
  return false;
151
152
  }
152
- /** True when any module this build includes applies the Kotlin MP plugin. */
153
+ /** True when any module this build includes is Kotlin Multiplatform. */
153
154
  function hasMultiplatformModule(root) {
154
155
  for (const module of CONVENTIONAL_MULTIPLATFORM_MODULES) {
155
- if (moduleAppliesMultiplatformPlugin(root, module))
156
+ if (moduleIsMultiplatform(root, module))
156
157
  return true;
157
158
  }
158
159
  for (const name of ["settings.gradle", "settings.gradle.kts"]) {
@@ -160,7 +161,7 @@ function hasMultiplatformModule(root) {
160
161
  if (content === null)
161
162
  continue;
162
163
  for (const module of parseSettingsModules(content)) {
163
- if (moduleAppliesMultiplatformPlugin(root, module))
164
+ if (moduleIsMultiplatform(root, module))
164
165
  return true;
165
166
  }
166
167
  }
@@ -172,7 +173,9 @@ function hasMultiplatformModule(root) {
172
173
  *
173
174
  * KMM is checked before Android because both have Gradle files, and it is
174
175
  * decided by what the repository *is*: a module that applies the Kotlin
175
- * Multiplatform plugin, and an Apple consumer within one directory of the
176
+ * Multiplatform plugin or declares a Kotlin/Native Apple target in its own
177
+ * build file (garfiec/Librechat-Mobile applies the plugin only through a
178
+ * convention plugin), and an Apple consumer within one directory of the
176
179
  * root. The three conventional directory names (`shared`, `composeApp`,
177
180
  * `iosApp`) used to be the whole rule, and were wrong in both directions —
178
181
  * `joreilly/PeopleInSpace` (`common` + `PeopleInSpaceSwiftUI/`) and
@@ -10,9 +10,10 @@
10
10
  * `shared` module was called KMM and handed a pipeline that builds an iOS app
11
11
  * it does not have.
12
12
  */
13
- import { mkdtempSync, rmSync, mkdirSync, writeFileSync } from "node:fs";
14
- import { join } from "node:path";
13
+ import { mkdtempSync, rmSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
14
+ import { dirname, join } from "node:path";
15
15
  import { tmpdir } from "node:os";
16
+ import { fileURLToPath } from "node:url";
16
17
  import { detectMobileProjectRoot } from "./detect-project.js";
17
18
  let root;
18
19
  beforeEach(() => {
@@ -67,6 +68,27 @@ describe("detectMobileProjectRoot", () => {
67
68
  xcodeProject("iosApp", "iosApp");
68
69
  expect(detectMobileProjectRoot(root)).toBe("kmm");
69
70
  });
71
+ // The build files of garfiec/Librechat-Mobile's `:shared` and
72
+ // openMF/mifos-mobile's `:cmp-shared` at their pins. Each applies Kotlin
73
+ // Multiplatform only through a convention plugin, and declares Apple
74
+ // targets in its own file.
75
+ const APPLE_TARGETS = join(dirname(fileURLToPath(import.meta.url)), "../../test/fixtures/kotlin-native-apple-targets");
76
+ const appleTargets = (name) => readFileSync(join(APPLE_TARGETS, name), "utf-8");
77
+ test("Kotlin/Native Apple targets behind a convention plugin are KMM (Librechat-Mobile)", () => {
78
+ settings("app", "core:common", "shared");
79
+ write("shared/build.gradle.kts", appleTargets("librechat-mobile.shared.build.gradle.kts"));
80
+ write("app/build.gradle.kts", ANDROID_APP);
81
+ write("core/common/build.gradle.kts", 'plugins { id("librechat.kmp.library") }\n');
82
+ xcodeProject("iosApp", "iosApp");
83
+ expect(detectMobileProjectRoot(root)).toBe("kmm");
84
+ });
85
+ test("Kotlin/Native Apple targets behind a convention plugin are KMM (mifos-mobile)", () => {
86
+ settings("cmp-android", "cmp-shared");
87
+ write("cmp-shared/build.gradle.kts", appleTargets("mifos-mobile.cmp-shared.build.gradle.kts"));
88
+ write("cmp-android/build.gradle.kts", ANDROID_APP);
89
+ xcodeProject("cmp-ios", "iosApp");
90
+ expect(detectMobileProjectRoot(root)).toBe("kmm");
91
+ });
70
92
  test("a nested multiplatform module counts", () => {
71
93
  settings("core:domain", "app");
72
94
  write("core/domain/build.gradle.kts", KMP);
@@ -86,6 +108,19 @@ describe("detectMobileProjectRoot", () => {
86
108
  expect(detectMobileProjectRoot(root)).toBe("android");
87
109
  });
88
110
  // The false positive the three directory names caused.
111
+ test("an iosApp folder beside modules with no Apple target and no KMP plugin is Android", () => {
112
+ settings("app", "shared");
113
+ write("app/build.gradle.kts", ANDROID_APP);
114
+ write("shared/build.gradle.kts", 'plugins { id("com.android.library") }\n// iosArm64() once lived here\nval note = "iosX64()"\n');
115
+ xcodeProject("iosApp", "iosApp");
116
+ expect(detectMobileProjectRoot(root)).toBe("android");
117
+ });
118
+ test("an Apple target with no Apple consumer is still Android", () => {
119
+ settings("shared", "app");
120
+ write("shared/build.gradle.kts", "kotlin { iosArm64() }\n");
121
+ write("app/build.gradle.kts", ANDROID_APP);
122
+ expect(detectMobileProjectRoot(root)).toBe("android");
123
+ });
89
124
  test("a module merely named shared is not multiplatform", () => {
90
125
  settings("shared", "app");
91
126
  write("shared/build.gradle.kts", ANDROID_LIB);
@@ -23,6 +23,23 @@ export declare function parseSettingsModules(content: string): string[];
23
23
  * convention plugin whose own id ends in `multiplatform`.
24
24
  */
25
25
  export declare function declaresKotlinMultiplatformPlugin(content: string): boolean;
26
+ /**
27
+ * True when a build file itself declares a Kotlin/Native Apple target.
28
+ *
29
+ * A convention plugin can hide the Kotlin Multiplatform plugin itself —
30
+ * garfiec/Librechat-Mobile's `:shared` applies `id("librechat.kmp.library")`
31
+ * and openMF/mifos-mobile's `:cmp-shared` a catalog alias — but the Apple
32
+ * targets are still declared in the module's own file. Only a call counts:
33
+ * the word in a comment or a string, or a source set named after a target
34
+ * (`iosArm64Main`), does not.
35
+ */
36
+ export declare function declaresKotlinNativeAppleTarget(content: string): boolean;
37
+ /**
38
+ * True when a build file makes its module Kotlin Multiplatform: it applies the
39
+ * plugin, or declares a Kotlin/Native Apple target. The KMM decision in
40
+ * `detect-project.ts` asks this, never the plugin test alone.
41
+ */
42
+ export declare function declaresKotlinMultiplatform(content: string): boolean;
26
43
  /**
27
44
  * Every plugin identifier a build file declares: `id("x")`, `id 'x'`,
28
45
  * `apply plugin: 'x'` / `apply(plugin = "x")`, and the version-catalog alias
@@ -1 +1 @@
1
- {"version":3,"file":"gradle-settings.d.ts","sourceRoot":"","sources":["../../../src/shared/gradle-settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAY9D;AAED;;;;GAIG;AACH,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAO1E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAW3D"}
1
+ {"version":3,"file":"gradle-settings.d.ts","sourceRoot":"","sources":["../../../src/shared/gradle-settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAY9D;AAED;;;;GAIG;AACH,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAO1E;AAUD;;;;;;;;;GASG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAGxE;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEpE;AA4CD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAW3D"}
@@ -45,6 +45,78 @@ export function declaresKotlinMultiplatformPlugin(content) {
45
45
  return true;
46
46
  return declaredPluginIds(content).some((id) => /kotlin[._-]?multiplatform$/i.test(id));
47
47
  }
48
+ /**
49
+ * The Kotlin/Native Apple target functions of the Kotlin Multiplatform DSL.
50
+ * A call to one (`iosArm64()`, `iosX64 { … }`, `listOf(iosArm64(), …)`) exists
51
+ * only inside a multiplatform module.
52
+ */
53
+ const KOTLIN_NATIVE_APPLE_TARGET_CALL = /(?<![A-Za-z0-9_$])(?:ios(?:Arm32|Arm64|X64|SimulatorArm64)|macos(?:Arm64|X64)|watchos(?:Arm32|Arm64|X64|SimulatorArm64|DeviceArm64)|tvos(?:Arm64|X64|SimulatorArm64))\s*[({]/;
54
+ /**
55
+ * True when a build file itself declares a Kotlin/Native Apple target.
56
+ *
57
+ * A convention plugin can hide the Kotlin Multiplatform plugin itself —
58
+ * garfiec/Librechat-Mobile's `:shared` applies `id("librechat.kmp.library")`
59
+ * and openMF/mifos-mobile's `:cmp-shared` a catalog alias — but the Apple
60
+ * targets are still declared in the module's own file. Only a call counts:
61
+ * the word in a comment or a string, or a source set named after a target
62
+ * (`iosArm64Main`), does not.
63
+ */
64
+ export function declaresKotlinNativeAppleTarget(content) {
65
+ if (!content || typeof content !== "string")
66
+ return false;
67
+ return KOTLIN_NATIVE_APPLE_TARGET_CALL.test(codeOnly(content));
68
+ }
69
+ /**
70
+ * True when a build file makes its module Kotlin Multiplatform: it applies the
71
+ * plugin, or declares a Kotlin/Native Apple target. The KMM decision in
72
+ * `detect-project.ts` asks this, never the plugin test alone.
73
+ */
74
+ export function declaresKotlinMultiplatform(content) {
75
+ return declaresKotlinMultiplatformPlugin(content) || declaresKotlinNativeAppleTarget(content);
76
+ }
77
+ /**
78
+ * A Kotlin or Groovy build file with its comments and string literals
79
+ * blanked, so what is left is code. Strings keep their quotes and lose their
80
+ * contents; a comment becomes a space.
81
+ */
82
+ function codeOnly(content) {
83
+ let out = "";
84
+ let i = 0;
85
+ const n = content.length;
86
+ while (i < n) {
87
+ const c = content[i];
88
+ const next = content[i + 1];
89
+ if (c === "/" && next === "/") {
90
+ while (i < n && content[i] !== "\n")
91
+ i++;
92
+ continue;
93
+ }
94
+ if (c === "/" && next === "*") {
95
+ const end = content.indexOf("*/", i + 2);
96
+ i = end === -1 ? n : end + 2;
97
+ out += " ";
98
+ continue;
99
+ }
100
+ if (content.startsWith('"""', i) || content.startsWith("'''", i)) {
101
+ const quote = content.slice(i, i + 3);
102
+ const end = content.indexOf(quote, i + 3);
103
+ i = end === -1 ? n : end + 3;
104
+ out += quote + quote;
105
+ continue;
106
+ }
107
+ if (c === '"' || c === "'") {
108
+ let j = i + 1;
109
+ while (j < n && content[j] !== c && content[j] !== "\n")
110
+ j += content[j] === "\\" ? 2 : 1;
111
+ i = j + 1;
112
+ out += c + c;
113
+ continue;
114
+ }
115
+ out += c;
116
+ i++;
117
+ }
118
+ return out;
119
+ }
48
120
  /**
49
121
  * Every plugin identifier a build file declares: `id("x")`, `id 'x'`,
50
122
  * `apply plugin: 'x'` / `apply(plugin = "x")`, and the version-catalog alias
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=gradle-settings.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gradle-settings.test.d.ts","sourceRoot":"","sources":["../../../src/shared/gradle-settings.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * What in a module's own build file makes it Kotlin Multiplatform.
3
+ *
4
+ * The plugin is the first answer, but a convention plugin can hide it:
5
+ * garfiec/Librechat-Mobile's `:shared` applies `id("librechat.kmp.library")`
6
+ * and openMF/mifos-mobile's `:cmp-shared` applies
7
+ * `alias(libs.plugins.cmp.feature.convention)`. Both declare Kotlin/Native
8
+ * Apple targets in the module's own file, which only a multiplatform module
9
+ * can do, so that counts too. It has to be a call: the word in a comment or a
10
+ * string, or a source set named after a target, does not count.
11
+ */
12
+ import { readFileSync } from "node:fs";
13
+ import { dirname, join } from "node:path";
14
+ import { fileURLToPath } from "node:url";
15
+ import { declaresKotlinMultiplatform, declaresKotlinMultiplatformPlugin, declaresKotlinNativeAppleTarget, } from "./gradle-settings.js";
16
+ const FIXTURES = join(dirname(fileURLToPath(import.meta.url)), "../../test/fixtures/kotlin-native-apple-targets");
17
+ const fixture = (name) => readFileSync(join(FIXTURES, name), "utf-8");
18
+ describe("declaresKotlinNativeAppleTarget", () => {
19
+ test("Librechat-Mobile: listOf(iosArm64(), iosSimulatorArm64()) behind a convention plugin", () => {
20
+ const content = fixture("librechat-mobile.shared.build.gradle.kts");
21
+ expect(declaresKotlinMultiplatformPlugin(content)).toBe(false);
22
+ expect(declaresKotlinNativeAppleTarget(content)).toBe(true);
23
+ expect(declaresKotlinMultiplatform(content)).toBe(true);
24
+ });
25
+ test("mifos-mobile: iosX64(), iosArm64(), iosSimulatorArm64() behind a convention plugin", () => {
26
+ const content = fixture("mifos-mobile.cmp-shared.build.gradle.kts");
27
+ expect(declaresKotlinMultiplatformPlugin(content)).toBe(false);
28
+ expect(declaresKotlinNativeAppleTarget(content)).toBe(true);
29
+ });
30
+ test.each([
31
+ "kotlin { iosArm64() }",
32
+ "kotlin {\n iosX64 {\n binaries.framework()\n }\n}",
33
+ 'kotlin { iosSimulatorArm64("sim") }',
34
+ "kotlin { macosArm64() }",
35
+ "kotlin { macosX64() }",
36
+ "kotlin { watchosArm64(); watchosSimulatorArm64() }",
37
+ "kotlin { watchosDeviceArm64() }",
38
+ "kotlin { tvosArm64() }",
39
+ "kotlin { tvosSimulatorArm64 () }",
40
+ "kotlin {\n [iosArm64(), iosX64()].each { it.binaries.framework() }\n}",
41
+ ])("a target call counts: %s", (content) => {
42
+ expect(declaresKotlinNativeAppleTarget(content)).toBe(true);
43
+ });
44
+ test.each([
45
+ "// iosArm64()\nplugins { id(\"com.android.application\") }",
46
+ "/* kotlin { iosArm64() } */\nandroid { }",
47
+ "/*\n * iosX64()\n */",
48
+ 'val note = "call iosArm64() for iOS"',
49
+ "def note = 'iosArm64()'",
50
+ 'val s = """\n iosArm64()\n"""',
51
+ "val iosArm64Main by getting { }",
52
+ "sourceSets { iosArm64Main.dependencies { } }",
53
+ "sourceSets { iosMain.dependencies { } }",
54
+ "val iosArm64 = 1",
55
+ "myiosArm64()",
56
+ "linuxX64()\nandroidTarget()\njvm()",
57
+ "",
58
+ ])("not a target call: %j", (content) => {
59
+ expect(declaresKotlinNativeAppleTarget(content)).toBe(false);
60
+ });
61
+ test("a comment marker inside a string does not hide the call after it", () => {
62
+ expect(declaresKotlinNativeAppleTarget('val url = "https://example.com"\nkotlin { iosArm64() }')).toBe(true);
63
+ });
64
+ });
65
+ //# sourceMappingURL=gradle-settings.test.js.map
@@ -22,6 +22,8 @@ export interface GradleBuildInputs {
22
22
  module?: string;
23
23
  /** JVM arguments to run the Gradle daemon with instead of the project's org.gradle.jvmargs; capped to the machine like the project's own. */
24
24
  jvmargs?: string;
25
+ /** Gradle workers to run with (`--max-workers`), over any org.gradle.workers.max; a positive whole number. */
26
+ max_workers?: string | number;
25
27
  }
26
28
  /**
27
29
  * Inputs for android-lint step
@@ -32,6 +34,8 @@ export interface AndroidLintInputs {
32
34
  variant?: string;
33
35
  /** JVM arguments to run the Gradle daemon with instead of the project's org.gradle.jvmargs; capped to the machine like the project's own. */
34
36
  jvmargs?: string;
37
+ /** Gradle workers to run with (`--max-workers`), over any org.gradle.workers.max; a positive whole number. */
38
+ max_workers?: string | number;
35
39
  }
36
40
  /**
37
41
  * Inputs for android-unit-test step
@@ -43,6 +47,8 @@ export interface AndroidUnitTestInputs {
43
47
  test_filter?: string;
44
48
  /** JVM arguments to run the Gradle daemon with instead of the project's org.gradle.jvmargs; capped to the machine like the project's own. */
45
49
  jvmargs?: string;
50
+ /** Gradle workers to run with (`--max-workers`), over any org.gradle.workers.max; a positive whole number. */
51
+ max_workers?: string | number;
46
52
  }
47
53
  /**
48
54
  * Set Java version step executor
@@ -135,6 +141,8 @@ export interface AndroidBuildForUITestingInputs {
135
141
  arguments?: string;
136
142
  /** JVM arguments to run the Gradle daemon with instead of the project's org.gradle.jvmargs; capped to the machine like the project's own. */
137
143
  jvmargs?: string;
144
+ /** Gradle workers to run with (`--max-workers`), over any org.gradle.workers.max; a positive whole number. */
145
+ max_workers?: string | number;
138
146
  }
139
147
  /**
140
148
  * Builds app APK and test APK for Android instrumented (UI) tests.
@@ -1 +1 @@
1
- {"version":3,"file":"android.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/android.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"android.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/android.ts"],"names":[],"mappings":"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"}
@@ -460,7 +460,7 @@ export class GradleBuildStepExecutor extends BaseStepExecutor {
460
460
  commands.push(' echo "Error: Neither ./gradlew nor gradle command found"');
461
461
  commands.push(' exit 1');
462
462
  commands.push('fi');
463
- commands.push(...gradleMemoryCommands(this.getInput(inputs, 'jvmargs', ''), (v) => this.escapeBash(v)));
463
+ commands.push(...gradleMemoryCommands(this.getInput(inputs, 'jvmargs', ''), (v) => this.escapeBash(v), String(this.getInput(inputs, 'max_workers', '')).trim()));
464
464
  // Build gradle command
465
465
  commands.push('');
466
466
  commands.push('# Timestamp marker — used to collect only artifacts from this build');
@@ -782,7 +782,7 @@ export class AndroidLintStepExecutor extends BaseStepExecutor {
782
782
  commands.push(' echo "Error: Neither ./gradlew nor gradle command found"');
783
783
  commands.push(' exit 1');
784
784
  commands.push('fi');
785
- commands.push(...gradleMemoryCommands(this.getInput(inputs, 'jvmargs', ''), (v) => this.escapeBash(v)));
785
+ commands.push(...gradleMemoryCommands(this.getInput(inputs, 'jvmargs', ''), (v) => this.escapeBash(v), String(this.getInput(inputs, 'max_workers', '')).trim()));
786
786
  // Build lint task name
787
787
  commands.push('');
788
788
  commands.push('# Run lint');
@@ -972,7 +972,7 @@ export class AndroidUnitTestStepExecutor extends BaseStepExecutor {
972
972
  commands.push(' echo "Error: Neither ./gradlew nor gradle command found"');
973
973
  commands.push(' exit 1');
974
974
  commands.push('fi');
975
- commands.push(...gradleMemoryCommands(this.getInput(inputs, 'jvmargs', ''), (v) => this.escapeBash(v)));
975
+ commands.push(...gradleMemoryCommands(this.getInput(inputs, 'jvmargs', ''), (v) => this.escapeBash(v), String(this.getInput(inputs, 'max_workers', '')).trim()));
976
976
  // Build test task name
977
977
  commands.push('');
978
978
  commands.push('# Run unit tests');
@@ -1040,7 +1040,7 @@ export class AndroidBuildForUITestingStepExecutor extends BaseStepExecutor {
1040
1040
  commands.push('else');
1041
1041
  commands.push(' GRADLE_CMD="gradle"');
1042
1042
  commands.push('fi');
1043
- commands.push(...gradleMemoryCommands(this.getInput(inputs, 'jvmargs', ''), (v) => this.escapeBash(v)));
1043
+ commands.push(...gradleMemoryCommands(this.getInput(inputs, 'jvmargs', ''), (v) => this.escapeBash(v), String(this.getInput(inputs, 'max_workers', '')).trim()));
1044
1044
  commands.push('');
1045
1045
  // Build both app and test APKs
1046
1046
  const appTask = gradleTaskPath(this.escapeBash(module), `assemble${variantCap}`);
@@ -55,6 +55,9 @@ const run = async (opts) => {
55
55
  if (opts.lock !== undefined)
56
56
  writeFileSync(join(project, 'Gemfile.lock'), opts.lock);
57
57
  writeFileSync(join(project, 'Gemfile'), opts.gemfile ?? "gem 'cocoapods'\n");
58
+ if (opts.rubyVersionFile !== undefined) {
59
+ writeFileSync(join(project, '.ruby-version'), opts.rubyVersionFile);
60
+ }
58
61
  const installed = (opts.installed ?? []).join(' ');
59
62
  executable(join(bin, 'gem'), `echo "gem $*" >> '${log}'
60
63
  if [ "$1" = "list" ]; then
@@ -134,12 +137,71 @@ describe('cocoapods-install runs the bundler Gemfile.lock names', () => {
134
137
  expect(output).toContain('BUNDLED WITH');
135
138
  expect(output).toMatch(/EXIT [1-9]/);
136
139
  });
137
- // Homebrew's ruby is keg-only, so a guest whose CocoaPods and fastlane came
138
- // from Homebrew has it installed and still resolves `ruby` to the system 2.6.
139
- test('prefers an installed Homebrew Ruby over system Ruby', async () => {
140
- const { calls } = await run({ lock: LOCK_WITH_BUNDLER, brewRuby: true });
141
- expect(calls.some((c) => c.startsWith('brew-ruby'))).toBe(true);
142
- expect(calls.some((c) => c.startsWith('ruby '))).toBe(false);
140
+ });
141
+ // Issue 08 preferred Homebrew's Ruby whenever it was installed. On the mac
142
+ // image that is Ruby 4, and an old lockfile's gems do not load there: rake
143
+ // 13.0.6 requires `ostruct`, which stopped being a default gem in Ruby 4.0,
144
+ // so a native-extension build died inside rake. The lockfile decides instead:
145
+ // its `RUBY VERSION`, then `.ruby-version`, and system Ruby when neither names
146
+ // one. Homebrew's Ruby only when the named Ruby is 3 or newer.
147
+ describe('cocoapods-install runs the Ruby the project names', () => {
148
+ const usedBrew = (calls) => calls.some((c) => c.startsWith('brew-ruby'));
149
+ const usedSystem = (calls) => calls.some((c) => c.startsWith('ruby '));
150
+ const lockWithRuby = (v) => LOCK_WITH_BUNDLER.replace('BUNDLED WITH', `RUBY VERSION\n ruby ${v}\n\nBUNDLED WITH`);
151
+ test('a lock that names no Ruby runs system Ruby, with the locked bundler', async () => {
152
+ const { calls, output, gemHome } = await run({ lock: LOCK_WITH_BUNDLER, brewRuby: true });
153
+ expect(usedSystem(calls)).toBe(true);
154
+ expect(usedBrew(calls)).toBe(false);
155
+ expect(calls).toContain('gem install bundler -v 2.3.21 --no-document');
156
+ expect(calls.find((c) => c.startsWith('bundle _2.3.21_ install'))).toContain(`GEM_HOME=${gemHome}`);
157
+ expect(output).toMatch(/^Ruby: .*\(2\.6\.10\), GEM_HOME: .* — system: lockfile names no Ruby$/m);
158
+ });
159
+ test('a lock whose RUBY VERSION is 3 or newer runs Homebrew Ruby', async () => {
160
+ const { calls, output } = await run({ lock: lockWithRuby('3.3.4p94'), brewRuby: true });
161
+ expect(usedBrew(calls)).toBe(true);
162
+ expect(usedSystem(calls)).toBe(false);
163
+ expect(output).toMatch(/^Ruby: .*homebrew-ruby\/bin\/ruby \(3\.4\.1\), .* — from Gemfile\.lock RUBY VERSION 3\.3\.4$/m);
164
+ });
165
+ test('a lock whose RUBY VERSION is 2.x runs system Ruby', async () => {
166
+ const { calls, output } = await run({ lock: lockWithRuby('2.7.2p137'), brewRuby: true });
167
+ expect(usedBrew(calls)).toBe(false);
168
+ expect(output).toContain('— from Gemfile.lock RUBY VERSION 2.7.2');
169
+ });
170
+ test('the lock outranks .ruby-version', async () => {
171
+ const { calls, output } = await run({
172
+ lock: lockWithRuby('3.3.4p94'),
173
+ rubyVersionFile: '2.7.6\n',
174
+ brewRuby: true,
175
+ });
176
+ expect(usedBrew(calls)).toBe(true);
177
+ expect(output).toContain('— from Gemfile.lock RUBY VERSION 3.3.4');
178
+ });
179
+ test('.ruby-version of 3 or newer runs Homebrew Ruby when the lock names none', async () => {
180
+ const { calls, output } = await run({ lock: LOCK_WITH_BUNDLER, rubyVersionFile: 'ruby-3.2.2\n', brewRuby: true });
181
+ expect(usedBrew(calls)).toBe(true);
182
+ expect(output).toContain('— from .ruby-version 3.2.2');
183
+ });
184
+ test('.ruby-version of 2.7 runs system Ruby, and says so', async () => {
185
+ const { calls, output } = await run({ lock: LOCK_WITH_BUNDLER, rubyVersionFile: '2.7.6\n', brewRuby: true });
186
+ expect(usedBrew(calls)).toBe(false);
187
+ expect(usedSystem(calls)).toBe(true);
188
+ expect(output).toContain('— from .ruby-version 2.7.6');
189
+ });
190
+ test('a .ruby-version that names no version is ignored', async () => {
191
+ const { calls, output } = await run({ lock: LOCK_WITH_BUNDLER, rubyVersionFile: 'system\n', brewRuby: true });
192
+ expect(usedBrew(calls)).toBe(false);
193
+ expect(output).toContain('— system: lockfile names no Ruby');
194
+ });
195
+ test('Ruby 3 named, no Homebrew Ruby installed: system Ruby, and says so', async () => {
196
+ const { calls, output } = await run({ lock: lockWithRuby('3.3.4p94') });
197
+ expect(usedSystem(calls)).toBe(true);
198
+ expect(output).toContain('— from Gemfile.lock RUBY VERSION 3.3.4, but no Homebrew Ruby is installed');
199
+ });
200
+ test('a project without cocoapods in its Gemfile never picks a Ruby', async () => {
201
+ const { calls } = await run({ gemfile: "gem 'fastlane'\n", rubyVersionFile: '3.3.0\n', brewRuby: true });
202
+ expect(calls).toContain('pod install');
203
+ expect(usedBrew(calls)).toBe(false);
204
+ expect(usedSystem(calls)).toBe(false);
143
205
  });
144
206
  });
145
207
  //# sourceMappingURL=cocoapods-locked-bundler.test.js.map
@@ -19,20 +19,26 @@
19
19
  * 2. **Say so.** When a Gradle run exits 137 or its output says the daemon
20
20
  * disappeared, print the kernel's out-of-memory lines and one sentence
21
21
  * with the machine's memory and what the build asked for.
22
+ * 3. **Workers.** A heap cap does not bound what runs beside the heaps:
23
+ * off-heap memory, and native compilers run in parallel. IacobIonut01/ReFra
24
+ * was killed again at a capped -Xmx3712m, one JVM holding ~5.1 GiB
25
+ * resident; its own CI also sets `org.gradle.workers.max=2`. A pipeline
26
+ * may ask for a worker count, passed as `--max-workers=<n>`.
22
27
  *
23
28
  * Precedence, measured with Gradle 8.14.3 and 9.5.0 (daemon and --no-daemon):
24
29
  * `-Dorg.gradle.jvmargs` on the command line beats both the Gradle user
25
30
  * home's and the project's `gradle.properties` for the daemon's heap, and
26
31
  * `-P` beats `gradle.properties` for a Gradle property, which is how the
27
- * Kotlin Gradle plugin reads `kotlin.daemon.jvmargs`. `GRADLE_OPTS` is not
28
- * used: it sizes the client JVM, not the daemon.
32
+ * Kotlin Gradle plugin reads `kotlin.daemon.jvmargs`. `--max-workers` beats
33
+ * `org.gradle.workers.max` in both files (`gradle.startParameter.maxWorkerCount`).
34
+ * `GRADLE_OPTS` is not used: it sizes the client JVM, not the daemon.
29
35
  *
30
36
  * Written as shell functions so what ships is what the tests run. Its lines
31
37
  * start with "Gradle memory:", never with a step-progress marker.
32
38
  */
33
39
  /** The share of the machine's memory the two daemon heaps may take together. */
34
40
  export declare const GRADLE_HEAP_SHARE_PERCENT = 75;
35
- export declare const GRADLE_MEMORY_FUNCTIONS = "# This machine's memory in MiB, or nothing when it cannot be read.\ncibuild_mem_mib() {\n if [ -r /proc/meminfo ]; then\n awk '/^MemTotal:/ { print int($2 / 1024); exit }' /proc/meminfo\n else\n local bytes\n bytes=$(sysctl -n hw.memsize 2>/dev/null || true)\n if [ -n \"$bytes\" ]; then echo $(( bytes / 1048576 )); fi\n fi\n}\n\n# $1 a .properties file, $2 a key. Prints \"<line number><TAB><value>\" for the\n# last assignment of the key, or nothing.\ncibuild_prop_line() {\n [ -f \"$1\" ] || return 0\n awk -v key=\"$2\" '\n { line = $0; sub(/^[ \\t]+/, \"\", line) }\n line ~ /^[#!]/ { next }\n {\n k = line; sub(/[ \\t]*[=:].*$/, \"\", k)\n if (k == key) { v = line; sub(/^[^=:]*[=:][ \\t]*/, \"\", v); sub(/[ \\t\\r]+$/, \"\", v); found = NR \"\\t\" v }\n }\n END { if (found != \"\") print found }\n ' \"$1\"\n}\n\n# The -Xmx of a JVM argument string in MiB (the last one wins, as in the JVM),\n# or nothing when it has none.\ncibuild_xmx_mib() {\n printf '%s\\n' \"$1\" | tr ' \\t' '\\n\\n' | awk '\n /^-Xmx[0-9]+[kKmMgGtT]?$/ {\n n = substr($0, 5); u = substr(n, length(n))\n if (u ~ /[0-9]/) { v = n / 1048576 }\n else {\n n = substr(n, 1, length(n) - 1)\n if (u ~ /[kK]/) v = n / 1024\n else if (u ~ /[mM]/) v = n\n else if (u ~ /[gG]/) v = n * 1024\n else v = n * 1048576\n }\n r = int(v)\n }\n END { if (r != \"\") print r }'\n}\n\n# $1 a JVM argument string, $2 a heap in MiB: the same arguments with every\n# -Xmx replaced by that one (added in front when there was none).\ncibuild_with_xmx() (\n set -f\n out=\"\"\n replaced=0\n for arg in $1; do\n case \"$arg\" in\n -Xmx*) if [ \"$replaced\" -eq 0 ]; then out=\"$out -Xmx${2}m\"; replaced=1; fi ;;\n *) out=\"$out $arg\" ;;\n esac\n done\n [ \"$replaced\" -eq 1 ] || out=\" -Xmx${2}m$out\"\n printf '%s' \"${out# }\"\n)\n\n# MiB as GiB with one decimal.\ncibuild_gib() {\n awk -v m=\"$1\" 'BEGIN { printf \"%.1f\", m / 1024 }'\n}\n\n# A heap scaled by budget/total, rounded down to 64 MiB, never below 512 MiB.\ncibuild_scaled_heap() {\n local v=$(( $1 * $2 / $3 / 64 * 64 ))\n [ \"$v\" -ge 512 ] || v=512\n echo \"$v\"\n}\n\n# The plan, from its inputs only, so a test can run it:\n# $1 this machine's memory in MiB (empty when unknown)\n# $2 the project's gradle.properties $3 the Gradle user home's\n# $4 JVM arguments the pipeline asks for instead (may be empty)\n# Sets CIBUILD_GRADLE_MEMORY_ARGS (extra Gradle arguments),\n# CIBUILD_GRADLE_MEMORY_LINE (what to print before Gradle runs; empty when\n# nothing changes) and CIBUILD_GRADLE_MEMORY_SENTENCE (what to print if a\n# daemon is killed).\n#\n# Precedence is Gradle's own: the command line beats GRADLE_USER_HOME's\n# gradle.properties, which beats the project's. A Kotlin daemon with no -Xmx of\n# its own inherits the Gradle daemon's, and in-process compilation has no\n# Kotlin daemon at all.\ncibuild_gradle_memory_plan() {\n local mem=\"$1\" project=\"$2\" user=\"$3\" preferred=\"$4\" l\n local jvm=\"\" jvm_at=\"\" kd=\"\" kd_at=\"\" strategy=\"\"\n CIBUILD_GRADLE_MEMORY_ARGS=()\n CIBUILD_GRADLE_MEMORY_LINE=\"\"\n CIBUILD_GRADLE_MEMORY_SENTENCE=\"\"\n\n if [ -n \"$preferred\" ]; then jvm=\"$preferred\"; jvm_at=\"the pipeline\"; fi\n for f in \"$user\" \"$project\"; do\n if [ -z \"$jvm_at\" ]; then\n l=$(cibuild_prop_line \"$f\" org.gradle.jvmargs)\n if [ -n \"$l\" ]; then jvm=\"${l#*\t}\"; jvm_at=\"$f:${l%%\t*}\"; fi\n fi\n if [ -z \"$kd_at\" ]; then\n l=$(cibuild_prop_line \"$f\" kotlin.daemon.jvmargs)\n if [ -n \"$l\" ]; then kd=\"${l#*\t}\"; kd_at=\"$f:${l%%\t*}\"; fi\n fi\n if [ -z \"$strategy\" ]; then\n l=$(cibuild_prop_line \"$f\" kotlin.compiler.execution.strategy)\n strategy=\"${l#*\t}\"\n fi\n done\n\n local g k kd_own=\"\"\n g=$(cibuild_xmx_mib \"$jvm\")\n [ -n \"$g\" ] || g=512\n if [ \"$strategy\" = \"in-process\" ]; then\n k=0\n else\n kd_own=$(cibuild_xmx_mib \"$kd\")\n k=\"${kd_own:-$g}\"\n fi\n local total=$(( g + k ))\n\n local asked\n if [ -n \"$jvm_at\" ]; then asked=\"org.gradle.jvmargs=$jvm at ${jvm_at}\"; else asked=\"Gradle's default -Xmx512m\"; fi\n if [ \"$k\" -eq 0 ]; then\n asked=\"$asked; Kotlin compiles in-process\"\n elif [ -n \"$kd_own\" ]; then\n asked=\"$asked, kotlin.daemon.jvmargs=$kd at ${kd_at}\"\n else\n asked=\"$asked; the Kotlin daemon inherits its -Xmx\"\n fi\n\n if [ -z \"$mem\" ]; then\n CIBUILD_GRADLE_MEMORY_SENTENCE=\"This build's Gradle and Kotlin daemons asked for $(cibuild_gib \"$total\") GiB ($asked); this machine's memory could not be read.\"\n if [ -n \"$preferred\" ]; then CIBUILD_GRADLE_MEMORY_ARGS=(\"-Dorg.gradle.jvmargs=$preferred\"); fi\n return 0\n fi\n\n local budget=$(( mem * 75 / 100 ))\n CIBUILD_GRADLE_MEMORY_SENTENCE=\"The build machine has $(cibuild_gib \"$mem\") GiB; this build's Gradle and Kotlin daemons asked for $(cibuild_gib \"$total\") GiB ($asked).\"\n\n if [ \"$total\" -le \"$budget\" ]; then\n if [ -n \"$preferred\" ]; then\n CIBUILD_GRADLE_MEMORY_ARGS=(\"-Dorg.gradle.jvmargs=$preferred\")\n CIBUILD_GRADLE_MEMORY_LINE=\"Gradle memory: org.gradle.jvmargs=$preferred, as the pipeline asks (-Dorg.gradle.jvmargs on the command line).\"\n fi\n return 0\n fi\n\n case \"$jvm\" in\n *\\\\)\n CIBUILD_GRADLE_MEMORY_LINE=\"Gradle memory: the declared heaps ask for $(cibuild_gib \"$total\") GiB of this machine's $(cibuild_gib \"$mem\") GiB, but org.gradle.jvmargs at ${jvm_at} continues onto another line, so it is left as it is.\"\n return 0\n ;;\n esac\n\n local ng nk new_jvm\n ng=$(cibuild_scaled_heap \"$g\" \"$budget\" \"$total\")\n new_jvm=$(cibuild_with_xmx \"$jvm\" \"$ng\")\n CIBUILD_GRADLE_MEMORY_ARGS=(\"-Dorg.gradle.jvmargs=$new_jvm\")\n local now=\"Gradle -Xmx${ng}m\"\n if [ \"$k\" -eq 0 ]; then\n :\n elif [ -n \"$kd_own\" ]; then\n nk=$(cibuild_scaled_heap \"$k\" \"$budget\" \"$total\")\n CIBUILD_GRADLE_MEMORY_ARGS+=(\"-Pkotlin.daemon.jvmargs=$(cibuild_with_xmx \"$kd\" \"$nk\")\")\n now=\"$now and the Kotlin daemon -Xmx${nk}m\"\n else\n now=\"$now, which the Kotlin daemon inherits\"\n fi\n CIBUILD_GRADLE_MEMORY_LINE=\"Gradle memory: this machine has $(cibuild_gib \"$mem\") GiB and the declared heaps ask for $(cibuild_gib \"$total\") GiB ($asked), past the $(cibuild_gib \"$budget\") GiB this build allows them. Running with $now, set on the command line.\"\n CIBUILD_GRADLE_MEMORY_SENTENCE=\"$CIBUILD_GRADLE_MEMORY_SENTENCE This build ran them capped: $now.\"\n}\n\n# The kernel's out-of-memory lines, if this user may read the kernel log.\n# Linux guests restrict dmesg to root by default; their build user has\n# non-interactive sudo, so that is the second try.\ncibuild_kernel_oom_lines() {\n { dmesg 2>/dev/null || sudo -n dmesg 2>/dev/null || true; } |\n grep -i -E 'out of memory|oom-kill|oom_reaper|killed process' | tail -n 20 || true\n}\n\n# $1 Gradle's exit status, $2 a file holding its output. Says so when the\n# failure is a killed daemon rather than a failed build.\ncibuild_gradle_memory_report() {\n if [ \"$1\" -ne 137 ] && ! grep -q \"daemon disappeared unexpectedly\" \"$2\" 2>/dev/null; then\n return 0\n fi\n local oom\n oom=$(cibuild_kernel_oom_lines)\n echo \"\"\n echo \"Gradle memory: a Gradle daemon was killed rather than failing the build (exit $1).\"\n if [ -n \"$oom\" ]; then\n echo \"The kernel's out-of-memory lines:\"\n printf '%s\\n' \"$oom\" | sed 's/^/ /'\n else\n echo \"The kernel log shows no out-of-memory kill, or this machine does not let the build read it.\"\n fi\n if [ -n \"$CIBUILD_GRADLE_MEMORY_SENTENCE\" ]; then echo \"$CIBUILD_GRADLE_MEMORY_SENTENCE\"; fi\n}\n\n# Runs Gradle with the plan's arguments, and reports a killed daemon.\ncibuild_gradle() {\n local log rc\n log=$(mktemp)\n set +e\n \"$CIBUILD_GRADLE_BIN\" \"${CIBUILD_GRADLE_MEMORY_ARGS[@]}\" \"$@\" 2>&1 | tee \"$log\"\n rc=${PIPESTATUS[0]}\n set -e\n if [ \"$rc\" -ne 0 ]; then cibuild_gradle_memory_report \"$rc\" \"$log\" || true; fi\n rm -f \"$log\"\n return \"$rc\"\n}\n\n# $1 JVM arguments the pipeline asks for (may be empty). Run in the Gradle\n# project directory, after GRADLE_CMD is chosen.\ncibuild_gradle_memory_cap() {\n cibuild_gradle_memory_plan \"$(cibuild_mem_mib || true)\" \"gradle.properties\" \\\n \"${GRADLE_USER_HOME:-$HOME/.gradle}/gradle.properties\" \"$1\"\n if [ -n \"$CIBUILD_GRADLE_MEMORY_LINE\" ]; then echo \"$CIBUILD_GRADLE_MEMORY_LINE\"; fi\n CIBUILD_GRADLE_BIN=\"$GRADLE_CMD\"\n GRADLE_CMD=cibuild_gradle\n}";
41
+ export declare const GRADLE_MEMORY_FUNCTIONS = "# This machine's memory in MiB, or nothing when it cannot be read.\ncibuild_mem_mib() {\n if [ -r /proc/meminfo ]; then\n awk '/^MemTotal:/ { print int($2 / 1024); exit }' /proc/meminfo\n else\n local bytes\n bytes=$(sysctl -n hw.memsize 2>/dev/null || true)\n if [ -n \"$bytes\" ]; then echo $(( bytes / 1048576 )); fi\n fi\n}\n\n# $1 a .properties file, $2 a key. Prints \"<line number><TAB><value>\" for the\n# last assignment of the key, or nothing.\ncibuild_prop_line() {\n [ -f \"$1\" ] || return 0\n awk -v key=\"$2\" '\n { line = $0; sub(/^[ \\t]+/, \"\", line) }\n line ~ /^[#!]/ { next }\n {\n k = line; sub(/[ \\t]*[=:].*$/, \"\", k)\n if (k == key) { v = line; sub(/^[^=:]*[=:][ \\t]*/, \"\", v); sub(/[ \\t\\r]+$/, \"\", v); found = NR \"\\t\" v }\n }\n END { if (found != \"\") print found }\n ' \"$1\"\n}\n\n# The -Xmx of a JVM argument string in MiB (the last one wins, as in the JVM),\n# or nothing when it has none.\ncibuild_xmx_mib() {\n printf '%s\\n' \"$1\" | tr ' \\t' '\\n\\n' | awk '\n /^-Xmx[0-9]+[kKmMgGtT]?$/ {\n n = substr($0, 5); u = substr(n, length(n))\n if (u ~ /[0-9]/) { v = n / 1048576 }\n else {\n n = substr(n, 1, length(n) - 1)\n if (u ~ /[kK]/) v = n / 1024\n else if (u ~ /[mM]/) v = n\n else if (u ~ /[gG]/) v = n * 1024\n else v = n * 1048576\n }\n r = int(v)\n }\n END { if (r != \"\") print r }'\n}\n\n# $1 a JVM argument string, $2 a heap in MiB: the same arguments with every\n# -Xmx replaced by that one (added in front when there was none).\ncibuild_with_xmx() (\n set -f\n out=\"\"\n replaced=0\n for arg in $1; do\n case \"$arg\" in\n -Xmx*) if [ \"$replaced\" -eq 0 ]; then out=\"$out -Xmx${2}m\"; replaced=1; fi ;;\n *) out=\"$out $arg\" ;;\n esac\n done\n [ \"$replaced\" -eq 1 ] || out=\" -Xmx${2}m$out\"\n printf '%s' \"${out# }\"\n)\n\n# MiB as GiB with one decimal.\ncibuild_gib() {\n awk -v m=\"$1\" 'BEGIN { printf \"%.1f\", m / 1024 }'\n}\n\n# A heap scaled by budget/total, rounded down to 64 MiB, never below 512 MiB.\ncibuild_scaled_heap() {\n local v=$(( $1 * $2 / $3 / 64 * 64 ))\n [ \"$v\" -ge 512 ] || v=512\n echo \"$v\"\n}\n\n# The plan, from its inputs only, so a test can run it:\n# $1 this machine's memory in MiB (empty when unknown)\n# $2 the project's gradle.properties $3 the Gradle user home's\n# $4 JVM arguments the pipeline asks for instead (may be empty)\n# Sets CIBUILD_GRADLE_MEMORY_ARGS (extra Gradle arguments),\n# CIBUILD_GRADLE_MEMORY_LINE (what to print before Gradle runs; empty when\n# nothing changes) and CIBUILD_GRADLE_MEMORY_SENTENCE (what to print if a\n# daemon is killed).\n#\n# Precedence is Gradle's own: the command line beats GRADLE_USER_HOME's\n# gradle.properties, which beats the project's. A Kotlin daemon with no -Xmx of\n# its own inherits the Gradle daemon's, and in-process compilation has no\n# Kotlin daemon at all.\ncibuild_gradle_memory_plan() {\n local mem=\"$1\" project=\"$2\" user=\"$3\" preferred=\"$4\" l\n local jvm=\"\" jvm_at=\"\" kd=\"\" kd_at=\"\" strategy=\"\"\n CIBUILD_GRADLE_MEMORY_ARGS=()\n CIBUILD_GRADLE_MEMORY_LINE=\"\"\n CIBUILD_GRADLE_MEMORY_SENTENCE=\"\"\n\n if [ -n \"$preferred\" ]; then jvm=\"$preferred\"; jvm_at=\"the pipeline\"; fi\n for f in \"$user\" \"$project\"; do\n if [ -z \"$jvm_at\" ]; then\n l=$(cibuild_prop_line \"$f\" org.gradle.jvmargs)\n if [ -n \"$l\" ]; then jvm=\"${l#*\t}\"; jvm_at=\"$f:${l%%\t*}\"; fi\n fi\n if [ -z \"$kd_at\" ]; then\n l=$(cibuild_prop_line \"$f\" kotlin.daemon.jvmargs)\n if [ -n \"$l\" ]; then kd=\"${l#*\t}\"; kd_at=\"$f:${l%%\t*}\"; fi\n fi\n if [ -z \"$strategy\" ]; then\n l=$(cibuild_prop_line \"$f\" kotlin.compiler.execution.strategy)\n strategy=\"${l#*\t}\"\n fi\n done\n\n local g k kd_own=\"\"\n g=$(cibuild_xmx_mib \"$jvm\")\n [ -n \"$g\" ] || g=512\n if [ \"$strategy\" = \"in-process\" ]; then\n k=0\n else\n kd_own=$(cibuild_xmx_mib \"$kd\")\n k=\"${kd_own:-$g}\"\n fi\n local total=$(( g + k ))\n\n local asked\n if [ -n \"$jvm_at\" ]; then asked=\"org.gradle.jvmargs=$jvm at ${jvm_at}\"; else asked=\"Gradle's default -Xmx512m\"; fi\n if [ \"$k\" -eq 0 ]; then\n asked=\"$asked; Kotlin compiles in-process\"\n elif [ -n \"$kd_own\" ]; then\n asked=\"$asked, kotlin.daemon.jvmargs=$kd at ${kd_at}\"\n else\n asked=\"$asked; the Kotlin daemon inherits its -Xmx\"\n fi\n\n if [ -z \"$mem\" ]; then\n CIBUILD_GRADLE_MEMORY_SENTENCE=\"This build's Gradle and Kotlin daemons asked for $(cibuild_gib \"$total\") GiB ($asked); this machine's memory could not be read.\"\n if [ -n \"$preferred\" ]; then CIBUILD_GRADLE_MEMORY_ARGS=(\"-Dorg.gradle.jvmargs=$preferred\"); fi\n return 0\n fi\n\n local budget=$(( mem * 75 / 100 ))\n CIBUILD_GRADLE_MEMORY_SENTENCE=\"The build machine has $(cibuild_gib \"$mem\") GiB; this build's Gradle and Kotlin daemons asked for $(cibuild_gib \"$total\") GiB ($asked).\"\n\n if [ \"$total\" -le \"$budget\" ]; then\n if [ -n \"$preferred\" ]; then\n CIBUILD_GRADLE_MEMORY_ARGS=(\"-Dorg.gradle.jvmargs=$preferred\")\n CIBUILD_GRADLE_MEMORY_LINE=\"Gradle memory: org.gradle.jvmargs=$preferred, as the pipeline asks (-Dorg.gradle.jvmargs on the command line).\"\n fi\n return 0\n fi\n\n case \"$jvm\" in\n *\\\\)\n CIBUILD_GRADLE_MEMORY_LINE=\"Gradle memory: the declared heaps ask for $(cibuild_gib \"$total\") GiB of this machine's $(cibuild_gib \"$mem\") GiB, but org.gradle.jvmargs at ${jvm_at} continues onto another line, so it is left as it is.\"\n return 0\n ;;\n esac\n\n local ng nk new_jvm\n ng=$(cibuild_scaled_heap \"$g\" \"$budget\" \"$total\")\n new_jvm=$(cibuild_with_xmx \"$jvm\" \"$ng\")\n CIBUILD_GRADLE_MEMORY_ARGS=(\"-Dorg.gradle.jvmargs=$new_jvm\")\n local now=\"Gradle -Xmx${ng}m\"\n if [ \"$k\" -eq 0 ]; then\n :\n elif [ -n \"$kd_own\" ]; then\n nk=$(cibuild_scaled_heap \"$k\" \"$budget\" \"$total\")\n CIBUILD_GRADLE_MEMORY_ARGS+=(\"-Pkotlin.daemon.jvmargs=$(cibuild_with_xmx \"$kd\" \"$nk\")\")\n now=\"$now and the Kotlin daemon -Xmx${nk}m\"\n else\n now=\"$now, which the Kotlin daemon inherits\"\n fi\n CIBUILD_GRADLE_MEMORY_LINE=\"Gradle memory: this machine has $(cibuild_gib \"$mem\") GiB and the declared heaps ask for $(cibuild_gib \"$total\") GiB ($asked), past the $(cibuild_gib \"$budget\") GiB this build allows them. Running with $now, set on the command line.\"\n CIBUILD_GRADLE_MEMORY_SENTENCE=\"$CIBUILD_GRADLE_MEMORY_SENTENCE This build ran them capped: $now.\"\n}\n\n# $1 the number of Gradle workers the pipeline asks for (may be empty). Adds\n# --max-workers to the plan's arguments; run after cibuild_gradle_memory_plan.\n# Sets CIBUILD_GRADLE_WORKERS_LINE (what to print; empty when nothing asked).\ncibuild_gradle_workers_plan() {\n CIBUILD_GRADLE_WORKERS_LINE=\"\"\n [ -n \"$1\" ] || return 0\n case \"$1\" in\n *[!0-9]*|0*)\n CIBUILD_GRADLE_WORKERS_LINE=\"Gradle memory: max_workers=$1 is not a positive whole number, so it is not passed and Gradle picks its own worker count.\"\n return 0\n ;;\n esac\n CIBUILD_GRADLE_MEMORY_ARGS+=(\"--max-workers=$1\")\n CIBUILD_GRADLE_WORKERS_LINE=\"Gradle memory: running with --max-workers=$1, as the pipeline asks (set on the command line, over any org.gradle.workers.max).\"\n CIBUILD_GRADLE_MEMORY_SENTENCE=\"$CIBUILD_GRADLE_MEMORY_SENTENCE Gradle ran with --max-workers=$1.\"\n}\n\n# The kernel's out-of-memory lines, if this user may read the kernel log.\n# Linux guests restrict dmesg to root by default; their build user has\n# non-interactive sudo, so that is the second try.\ncibuild_kernel_oom_lines() {\n { dmesg 2>/dev/null || sudo -n dmesg 2>/dev/null || true; } |\n grep -i -E 'out of memory|oom-kill|oom_reaper|killed process' | tail -n 20 || true\n}\n\n# $1 Gradle's exit status, $2 a file holding its output. Says so when the\n# failure is a killed daemon rather than a failed build.\ncibuild_gradle_memory_report() {\n if [ \"$1\" -ne 137 ] && ! grep -q \"daemon disappeared unexpectedly\" \"$2\" 2>/dev/null; then\n return 0\n fi\n local oom\n oom=$(cibuild_kernel_oom_lines)\n echo \"\"\n echo \"Gradle memory: a Gradle daemon was killed rather than failing the build (exit $1).\"\n if [ -n \"$oom\" ]; then\n echo \"The kernel's out-of-memory lines:\"\n printf '%s\\n' \"$oom\" | sed 's/^/ /'\n else\n echo \"The kernel log shows no out-of-memory kill, or this machine does not let the build read it.\"\n fi\n if [ -n \"$CIBUILD_GRADLE_MEMORY_SENTENCE\" ]; then echo \"$CIBUILD_GRADLE_MEMORY_SENTENCE\"; fi\n}\n\n# Runs Gradle with the plan's arguments, and reports a killed daemon.\ncibuild_gradle() {\n local log rc\n log=$(mktemp)\n set +e\n \"$CIBUILD_GRADLE_BIN\" \"${CIBUILD_GRADLE_MEMORY_ARGS[@]}\" \"$@\" 2>&1 | tee \"$log\"\n rc=${PIPESTATUS[0]}\n set -e\n if [ \"$rc\" -ne 0 ]; then cibuild_gradle_memory_report \"$rc\" \"$log\" || true; fi\n rm -f \"$log\"\n return \"$rc\"\n}\n\n# $1 JVM arguments the pipeline asks for, $2 the Gradle workers it asks for\n# (either may be empty). Run in the Gradle project directory, after GRADLE_CMD\n# is chosen.\ncibuild_gradle_memory_cap() {\n cibuild_gradle_memory_plan \"$(cibuild_mem_mib || true)\" \"gradle.properties\" \\\n \"${GRADLE_USER_HOME:-$HOME/.gradle}/gradle.properties\" \"$1\"\n cibuild_gradle_workers_plan \"$2\"\n if [ -n \"$CIBUILD_GRADLE_MEMORY_LINE\" ]; then echo \"$CIBUILD_GRADLE_MEMORY_LINE\"; fi\n if [ -n \"$CIBUILD_GRADLE_WORKERS_LINE\" ]; then echo \"$CIBUILD_GRADLE_WORKERS_LINE\"; fi\n CIBUILD_GRADLE_BIN=\"$GRADLE_CMD\"\n GRADLE_CMD=cibuild_gradle\n}";
36
42
  /**
37
43
  * The commands a Gradle step runs once it has chosen `GRADLE_CMD` and is in
38
44
  * the project directory. Afterwards `$GRADLE_CMD` runs Gradle with the plan's
@@ -40,7 +46,8 @@ export declare const GRADLE_MEMORY_FUNCTIONS = "# This machine's memory in MiB,
40
46
  *
41
47
  * `jvmargs` is what the pipeline asks for instead of the project's
42
48
  * `org.gradle.jvmargs` (a value the repository's own CI sets, say); the cap
43
- * still applies to it.
49
+ * still applies to it. `maxWorkers` is the worker count it asks for (the
50
+ * repository CI's `org.gradle.workers.max`), passed as `--max-workers`.
44
51
  */
45
- export declare function gradleMemoryCommands(jvmargs: string, escape: (value: string) => string): string[];
52
+ export declare function gradleMemoryCommands(jvmargs: string, escape: (value: string) => string, maxWorkers?: string): string[];
46
53
  //# sourceMappingURL=gradle-memory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gradle-memory.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/gradle-memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,gFAAgF;AAChF,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAE5C,eAAO,MAAM,uBAAuB,i/QA4NlC,CAAC;AAEH;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,MAAM,EAAE,CAEjG"}
1
+ {"version":3,"file":"gradle-memory.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/gradle-memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,gFAAgF;AAChF,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAE5C,eAAO,MAAM,uBAAuB,4hTAgPlC,CAAC;AAEH;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EACjC,UAAU,SAAK,GACd,MAAM,EAAE,CAOV"}