@invarn/cibuild 2.9.2 → 2.9.5

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.
Files changed (31) hide show
  1. package/dist/cli.cjs +97 -12
  2. package/dist/src/yaml/steps/android.d.ts.map +1 -1
  3. package/dist/src/yaml/steps/android.js +11 -3
  4. package/dist/src/yaml/steps/capture-injection.d.ts +30 -0
  5. package/dist/src/yaml/steps/capture-injection.d.ts.map +1 -0
  6. package/dist/src/yaml/steps/capture-injection.js +88 -0
  7. package/dist/src/yaml/steps/capture-injection.test.d.ts +2 -0
  8. package/dist/src/yaml/steps/capture-injection.test.d.ts.map +1 -0
  9. package/dist/src/yaml/steps/capture-injection.test.js +163 -0
  10. package/dist/src/yaml/steps/cocoapods-deployment-floor.d.ts +42 -0
  11. package/dist/src/yaml/steps/cocoapods-deployment-floor.d.ts.map +1 -0
  12. package/dist/src/yaml/steps/cocoapods-deployment-floor.js +140 -0
  13. package/dist/src/yaml/steps/cocoapods-deployment-floor.test.d.ts +11 -0
  14. package/dist/src/yaml/steps/cocoapods-deployment-floor.test.d.ts.map +1 -0
  15. package/dist/src/yaml/steps/cocoapods-deployment-floor.test.js +176 -0
  16. package/dist/src/yaml/steps/gradle-memory.d.ts +1 -1
  17. package/dist/src/yaml/steps/gradle-memory.d.ts.map +1 -1
  18. package/dist/src/yaml/steps/gradle-memory.js +78 -3
  19. package/dist/src/yaml/steps/gradle-memory.test.js +48 -1
  20. package/dist/src/yaml/steps/ios-deps.d.ts.map +1 -1
  21. package/dist/src/yaml/steps/ios-deps.js +2 -0
  22. package/dist/src/yaml/steps/xcode-derived-data.test.js +47 -4
  23. package/dist/src/yaml/steps/xcode-simulator-archs.d.ts +53 -0
  24. package/dist/src/yaml/steps/xcode-simulator-archs.d.ts.map +1 -0
  25. package/dist/src/yaml/steps/xcode-simulator-archs.js +98 -0
  26. package/dist/src/yaml/steps/xcode-simulator-archs.test.d.ts +21 -0
  27. package/dist/src/yaml/steps/xcode-simulator-archs.test.d.ts.map +1 -0
  28. package/dist/src/yaml/steps/xcode-simulator-archs.test.js +155 -0
  29. package/dist/src/yaml/steps/xcode.d.ts.map +1 -1
  30. package/dist/src/yaml/steps/xcode.js +43 -4
  31. package/package.json +1 -1
@@ -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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"}
@@ -11,6 +11,7 @@ import { execSync } from 'node:child_process';
11
11
  import { BaseStepExecutor, javaHomeVersionSpec } from './base.js';
12
12
  import { gradleMemoryCommands } from './gradle-memory.js';
13
13
  import { gradleSdkCmakeCommands } from './gradle-sdk-cmake.js';
14
+ import { appProjectOfTask, captureAssembleCommands, captureSetupCommands, isDebugAssembleTask } from './capture-injection.js';
14
15
  /**
15
16
  * Set Java version step executor
16
17
  * Sets the Java version to use for Android builds
@@ -469,11 +470,18 @@ export class GradleBuildStepExecutor extends BaseStepExecutor {
469
470
  commands.push('touch /tmp/.cibuild-build-marker');
470
471
  commands.push('');
471
472
  commands.push('# Run Gradle build');
472
- let gradleCmd = `$GRADLE_CMD ${this.escapeBash(gradleTask)}`;
473
+ let gradleArgs = this.escapeBash(gradleTask);
473
474
  if (gradleOptions && gradleOptions.trim() !== '') {
474
- gradleCmd += ` ${gradleOptions}`;
475
+ gradleArgs += ` ${gradleOptions}`;
476
+ }
477
+ if (isDebugAssembleTask(gradleTask)) {
478
+ // A debug assemble may carry the Invarn capture agent; see capture-injection.ts.
479
+ commands.push(...captureSetupCommands(appProjectOfTask(gradleTask), (v) => `'${this.escapeBash(v)}'`));
480
+ commands.push(...captureAssembleCommands(gradleArgs));
481
+ }
482
+ else {
483
+ commands.push(`$GRADLE_CMD ${gradleArgs}`);
475
484
  }
476
- commands.push(gradleCmd);
477
485
  commands.push('');
478
486
  commands.push('# Build completed');
479
487
  commands.push('echo "Gradle build completed successfully"');
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The Invarn capture agent in a debug build.
3
+ *
4
+ * When the dispatch sets INVARN_CAPTURE_VERSION, INVARN_CAPTURE_TOOLKIT_URL and
5
+ * INVARN_CAPTURE_SHA256 in the build's environment, a debug `assemble` runs with
6
+ * the toolkit's Gradle init script, which adds the capture agent to the app. The
7
+ * three files are downloaded outside the checkout and each is checked against the
8
+ * sha256 the dispatch named; nothing is written into the repository.
9
+ *
10
+ * The build never fails because of the agent: a download that fails, a checksum
11
+ * that does not match, or an instrumented assemble that fails all lead to the same
12
+ * assemble without the agent, and a `▸ INVARN_CAPTURE:` line says which happened.
13
+ * Without those variables the step runs exactly as it always did.
14
+ */
15
+ /** A single Gradle task that assembles a debug variant: `assembleDebug`, `:app:assembleCiDynamicDebug`. */
16
+ export declare function isDebugAssembleTask(task: string): boolean;
17
+ /** The Gradle project the task assembles (`:app` for `:app:assembleDebug`), or null for a bare task. */
18
+ export declare function appProjectOfTask(task: string): string | null;
19
+ /**
20
+ * The shell that downloads and checks the three files, run before the assemble.
21
+ * Leaves CIBUILD_CAPTURE_INIT set to the init script's path when everything checked
22
+ * out, empty otherwise. Plain variables, no arrays: macOS ships bash 3.2.
23
+ */
24
+ export declare function captureSetupCommands(appProject: string | null, quote: (v: string) => string): string[];
25
+ /**
26
+ * The assemble itself: with the init script when the setup left one, and once more
27
+ * without it if that fails. Without an init script it is the plain command.
28
+ */
29
+ export declare function captureAssembleCommands(gradleArgs: string): string[];
30
+ //# sourceMappingURL=capture-injection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture-injection.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/capture-injection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,2GAA2G;AAC3G,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wGAAwG;AACxG,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG5D;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,MAAM,EAAE,CAmCtG;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAkBpE"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * The Invarn capture agent in a debug build.
3
+ *
4
+ * When the dispatch sets INVARN_CAPTURE_VERSION, INVARN_CAPTURE_TOOLKIT_URL and
5
+ * INVARN_CAPTURE_SHA256 in the build's environment, a debug `assemble` runs with
6
+ * the toolkit's Gradle init script, which adds the capture agent to the app. The
7
+ * three files are downloaded outside the checkout and each is checked against the
8
+ * sha256 the dispatch named; nothing is written into the repository.
9
+ *
10
+ * The build never fails because of the agent: a download that fails, a checksum
11
+ * that does not match, or an instrumented assemble that fails all lead to the same
12
+ * assemble without the agent, and a `▸ INVARN_CAPTURE:` line says which happened.
13
+ * Without those variables the step runs exactly as it always did.
14
+ */
15
+ /** A single Gradle task that assembles a debug variant: `assembleDebug`, `:app:assembleCiDynamicDebug`. */
16
+ export function isDebugAssembleTask(task) {
17
+ return /^(:[A-Za-z0-9_.-]+)*:?assemble[A-Za-z0-9]*Debug$/.test(task.trim());
18
+ }
19
+ /** The Gradle project the task assembles (`:app` for `:app:assembleDebug`), or null for a bare task. */
20
+ export function appProjectOfTask(task) {
21
+ const match = /^((?::[A-Za-z0-9_.-]+)+):assemble/.exec(task.trim());
22
+ return match ? match[1] : null;
23
+ }
24
+ /**
25
+ * The shell that downloads and checks the three files, run before the assemble.
26
+ * Leaves CIBUILD_CAPTURE_INIT set to the init script's path when everything checked
27
+ * out, empty otherwise. Plain variables, no arrays: macOS ships bash 3.2.
28
+ */
29
+ export function captureSetupCommands(appProject, quote) {
30
+ return [
31
+ '',
32
+ '# Invarn capture agent: only when the dispatch sent the toolkit',
33
+ 'CIBUILD_CAPTURE_INIT=""',
34
+ 'if [ -n "${INVARN_CAPTURE_VERSION:-}" ] && [ -n "${INVARN_CAPTURE_TOOLKIT_URL:-}" ] && [ -n "${INVARN_CAPTURE_SHA256:-}" ]; then',
35
+ ' CIBUILD_CAPTURE_DIR="$(mktemp -d "${TMPDIR:-/tmp}/cibuild-capture.XXXXXX")"',
36
+ ' CIBUILD_CAPTURE_SKIP=""',
37
+ ' for CIBUILD_CAPTURE_ROLE in init instrument agent; do',
38
+ ' case "$CIBUILD_CAPTURE_ROLE" in',
39
+ ' init) CIBUILD_CAPTURE_FILE="invarn-init-${INVARN_CAPTURE_VERSION}.gradle" ;;',
40
+ ' instrument) CIBUILD_CAPTURE_FILE="invarn-instrument-${INVARN_CAPTURE_VERSION}.jar" ;;',
41
+ ' agent) CIBUILD_CAPTURE_FILE="invarn-agent-${INVARN_CAPTURE_VERSION}.aar" ;;',
42
+ ' esac',
43
+ ' CIBUILD_CAPTURE_WANT="$(printf \'%s\' "$INVARN_CAPTURE_SHA256" | tr \',\' \'\\n\' | sed -n "s/^${CIBUILD_CAPTURE_ROLE}=//p")"',
44
+ ' if ! curl -fsSL --retry 2 --max-time 120 -o "$CIBUILD_CAPTURE_DIR/$CIBUILD_CAPTURE_FILE" "${INVARN_CAPTURE_TOOLKIT_URL%/}/$CIBUILD_CAPTURE_FILE"; then',
45
+ ' CIBUILD_CAPTURE_SKIP="download"',
46
+ ' break',
47
+ ' fi',
48
+ ' CIBUILD_CAPTURE_GOT="$( (sha256sum "$CIBUILD_CAPTURE_DIR/$CIBUILD_CAPTURE_FILE" 2>/dev/null || shasum -a 256 "$CIBUILD_CAPTURE_DIR/$CIBUILD_CAPTURE_FILE") | cut -d\' \' -f1)"',
49
+ ' if [ -z "$CIBUILD_CAPTURE_WANT" ] || [ "$CIBUILD_CAPTURE_GOT" != "$CIBUILD_CAPTURE_WANT" ]; then',
50
+ ' CIBUILD_CAPTURE_SKIP="sha256"',
51
+ ' break',
52
+ ' fi',
53
+ ' done',
54
+ ' if [ -z "$CIBUILD_CAPTURE_SKIP" ]; then',
55
+ ' export INVARN_INSTRUMENT_JAR="$CIBUILD_CAPTURE_DIR/invarn-instrument-${INVARN_CAPTURE_VERSION}.jar"',
56
+ ' export INVARN_AGENT_AAR="$CIBUILD_CAPTURE_DIR/invarn-agent-${INVARN_CAPTURE_VERSION}.aar"',
57
+ ...(appProject ? [` export INVARN_APP_PROJECTS=${quote(appProject)}`] : []),
58
+ ' CIBUILD_CAPTURE_INIT="$CIBUILD_CAPTURE_DIR/invarn-init-${INVARN_CAPTURE_VERSION}.gradle"',
59
+ ' else',
60
+ ' echo "▸ INVARN_CAPTURE:skipped:$CIBUILD_CAPTURE_SKIP"',
61
+ ' fi',
62
+ 'fi',
63
+ ];
64
+ }
65
+ /**
66
+ * The assemble itself: with the init script when the setup left one, and once more
67
+ * without it if that fails. Without an init script it is the plain command.
68
+ */
69
+ export function captureAssembleCommands(gradleArgs) {
70
+ return [
71
+ // In an `if` condition, not between `set +e` and `set -e`: the memory wrapper turns `set -e` back on before it
72
+ // returns Gradle's status, and bash ignores `-e` for a whole function called as a condition.
73
+ 'if [ -n "$CIBUILD_CAPTURE_INIT" ]; then',
74
+ ` if $GRADLE_CMD --init-script "$CIBUILD_CAPTURE_INIT" ${gradleArgs}; then CIBUILD_CAPTURE_RC=0; else CIBUILD_CAPTURE_RC=$?; fi`,
75
+ ' if [ "$CIBUILD_CAPTURE_RC" -eq 0 ]; then',
76
+ ' echo "▸ INVARN_CAPTURE:injected:${INVARN_CAPTURE_VERSION}"',
77
+ ' else',
78
+ ' echo "▸ INVARN_CAPTURE:skipped:build_failed"',
79
+ ' echo "The build failed with the capture agent (exit $CIBUILD_CAPTURE_RC); building again without it."',
80
+ ' touch /tmp/.cibuild-build-marker',
81
+ ` $GRADLE_CMD ${gradleArgs}`,
82
+ ' fi',
83
+ 'else',
84
+ ` $GRADLE_CMD ${gradleArgs}`,
85
+ 'fi',
86
+ ];
87
+ }
88
+ //# sourceMappingURL=capture-injection.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=capture-injection.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture-injection.test.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/capture-injection.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,163 @@
1
+ /**
2
+ * The Invarn capture agent in a debug build: the shell that ships, executed here
3
+ * against a fake `./gradlew`, with the toolkit served from `file://` URLs.
4
+ *
5
+ * Three properties. Without the dispatch's variables the step is the step it was.
6
+ * With them, a debug assemble runs with the init script, and every way that can go
7
+ * wrong (a download, a checksum, the instrumented build itself) ends in the plain
8
+ * assemble, never in a failed build. Only a debug assemble is ever touched.
9
+ */
10
+ import { spawnSync } from "node:child_process";
11
+ import { createHash } from "node:crypto";
12
+ import { chmodSync, existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
13
+ import { tmpdir } from "node:os";
14
+ import { join } from "node:path";
15
+ import { pathToFileURL } from "node:url";
16
+ import { GradleBuildStepExecutor } from "./android.js";
17
+ import { appProjectOfTask, isDebugAssembleTask } from "./capture-injection.js";
18
+ import { testConfig } from "./test-config.js";
19
+ let dir;
20
+ let toolkit;
21
+ const VERSION = "0.14.2";
22
+ const FILES = {
23
+ init: `invarn-init-${VERSION}.gradle`,
24
+ instrument: `invarn-instrument-${VERSION}.jar`,
25
+ agent: `invarn-agent-${VERSION}.aar`,
26
+ };
27
+ function sha(path) {
28
+ return createHash("sha256").update(readFileSync(path)).digest("hex");
29
+ }
30
+ beforeEach(() => {
31
+ dir = mkdtempSync(join(tmpdir(), "capture-step-"));
32
+ toolkit = mkdtempSync(join(tmpdir(), "capture-toolkit-"));
33
+ for (const [role, name] of Object.entries(FILES))
34
+ writeFileSync(join(toolkit, name), `${role} bytes`);
35
+ });
36
+ afterEach(() => {
37
+ rmSync(dir, { recursive: true, force: true });
38
+ rmSync(toolkit, { recursive: true, force: true });
39
+ });
40
+ /** The dispatch's three values, right unless a case says otherwise. */
41
+ function captureEnv(over = {}) {
42
+ const sums = Object.entries(FILES)
43
+ .map(([role, name]) => `${role}=${sha(join(toolkit, name))}`)
44
+ .join(",");
45
+ return {
46
+ INVARN_CAPTURE_VERSION: VERSION,
47
+ INVARN_CAPTURE_TOOLKIT_URL: pathToFileURL(toolkit).href,
48
+ INVARN_CAPTURE_SHA256: sums,
49
+ ...over,
50
+ };
51
+ }
52
+ /**
53
+ * A `./gradlew` that appends each run's arguments and the agent paths it was handed
54
+ * to a file, and fails when it is given an init script and FAIL_WITH_INIT=1.
55
+ */
56
+ function fakeGradlew() {
57
+ writeFileSync(join(dir, "gradlew"), [
58
+ "#!/bin/bash",
59
+ 'echo "RUN $* | jar=${INVARN_INSTRUMENT_JAR:-} aar=${INVARN_AGENT_AAR:-} app=${INVARN_APP_PROJECTS:-}" >> "$(dirname "$0")/runs"',
60
+ 'case " $* " in *" --init-script "*) [ "${FAIL_WITH_INIT:-}" = 1 ] && exit 1 ;; esac',
61
+ "exit 0",
62
+ ].join("\n"));
63
+ chmodSync(join(dir, "gradlew"), 0o755);
64
+ }
65
+ async function run(inputs, env) {
66
+ fakeGradlew();
67
+ const step = await new GradleBuildStepExecutor().execute(inputs, {}, testConfig);
68
+ writeFileSync(join(dir, "step.sh"), step.script);
69
+ const out = spawnSync("bash", [join(dir, "step.sh")], {
70
+ cwd: dir,
71
+ encoding: "utf-8",
72
+ env: { PATH: process.env.PATH, HOME: dir, TMPDIR: dir, JAVA_HOME: "", CIBUILD_SOURCE_DIR: "", ...env },
73
+ });
74
+ const runs = existsSync(join(dir, "runs")) ? readFileSync(join(dir, "runs"), "utf-8").trim().split("\n") : [];
75
+ return { status: out.status, stdout: out.stdout, runs };
76
+ }
77
+ describe("which tasks may carry the agent", () => {
78
+ test.each(["assembleDebug", ":app:assembleDebug", ":app:assembleCiDynamicDebug", "assembleStagingDebug"])("%s does", (task) => {
79
+ expect(isDebugAssembleTask(task)).toBe(true);
80
+ });
81
+ test.each(["assembleRelease", "bundleDebug", "assembleDebug lint", ":app:testDebugUnitTest", "assembleDebugAndroidTest"])("%s does not", (task) => {
82
+ expect(isDebugAssembleTask(task)).toBe(false);
83
+ });
84
+ test("the app project is the task's own", () => {
85
+ expect(appProjectOfTask(":app:assembleDebug")).toBe(":app");
86
+ expect(appProjectOfTask(":apps:phone:assembleDebug")).toBe(":apps:phone");
87
+ expect(appProjectOfTask("assembleDebug")).toBeNull();
88
+ });
89
+ });
90
+ describe("a debug build without the dispatch's variables", () => {
91
+ test("runs the plain assemble once and says nothing of capture", async () => {
92
+ const r = await run({ gradle_task: "assembleDebug" }, {});
93
+ expect(r.status).toBe(0);
94
+ expect(r.runs).toHaveLength(1);
95
+ expect(r.runs[0]).not.toContain("--init-script");
96
+ expect(r.stdout).not.toContain("INVARN_CAPTURE");
97
+ });
98
+ });
99
+ describe("a debug build with them", () => {
100
+ test("assembles once with the init script and the checked files, and says so", async () => {
101
+ const r = await run({ gradle_task: ":app:assembleCiDynamicDebug" }, captureEnv());
102
+ expect(r.status).toBe(0);
103
+ expect(r.runs).toHaveLength(1);
104
+ expect(r.runs[0]).toMatch(new RegExp(`--init-script \\S+/${FILES.init} :app:assembleCiDynamicDebug`));
105
+ expect(r.runs[0]).toMatch(new RegExp(`jar=\\S+/${FILES.instrument} aar=\\S+/${FILES.agent} app=:app`));
106
+ expect(r.stdout).toContain(`▸ INVARN_CAPTURE:injected:${VERSION}`);
107
+ });
108
+ test("writes nothing into the checkout", async () => {
109
+ await run({ gradle_task: "assembleDebug" }, captureEnv());
110
+ for (const name of Object.values(FILES))
111
+ expect(existsSync(join(dir, name))).toBe(false);
112
+ });
113
+ test("a failed instrumented assemble is run again without the agent, and the build passes", async () => {
114
+ const r = await run({ gradle_task: "assembleDebug" }, captureEnv({ FAIL_WITH_INIT: "1" }));
115
+ expect(r.status).toBe(0);
116
+ expect(r.runs).toHaveLength(2);
117
+ expect(r.runs[0]).toContain("--init-script");
118
+ expect(r.runs[1]).not.toContain("--init-script");
119
+ expect(r.stdout).toContain("▸ INVARN_CAPTURE:skipped:build_failed");
120
+ });
121
+ test("a checksum that does not match runs the plain assemble", async () => {
122
+ const r = await run({ gradle_task: "assembleDebug" }, captureEnv({ INVARN_CAPTURE_SHA256: "init=00,instrument=00,agent=00" }));
123
+ expect(r.status).toBe(0);
124
+ expect(r.runs).toHaveLength(1);
125
+ expect(r.runs[0]).not.toContain("--init-script");
126
+ expect(r.stdout).toContain("▸ INVARN_CAPTURE:skipped:sha256");
127
+ });
128
+ test("a file that cannot be downloaded runs the plain assemble", async () => {
129
+ const env = captureEnv();
130
+ rmSync(join(toolkit, FILES.agent));
131
+ const r = await run({ gradle_task: "assembleDebug" }, env);
132
+ expect(r.status).toBe(0);
133
+ expect(r.runs).toHaveLength(1);
134
+ expect(r.runs[0]).not.toContain("--init-script");
135
+ expect(r.stdout).toContain("▸ INVARN_CAPTURE:skipped:download");
136
+ });
137
+ test("a release is never touched", async () => {
138
+ const r = await run({ gradle_task: "assembleRelease" }, captureEnv());
139
+ expect(r.runs).toEqual([expect.not.stringContaining("--init-script")]);
140
+ expect(r.stdout).not.toContain("INVARN_CAPTURE");
141
+ });
142
+ });
143
+ describe("a debug build that fails on its own", () => {
144
+ test("still fails, after trying once without the agent", async () => {
145
+ fakeGradlew();
146
+ writeFileSync(join(dir, "gradlew"), "#!/bin/bash\necho \"RUN $*\" >> \"$(dirname \"$0\")/runs\"\nexit 1\n");
147
+ chmodSync(join(dir, "gradlew"), 0o755);
148
+ const step = await new GradleBuildStepExecutor().execute({ gradle_task: "assembleDebug" }, {}, testConfig);
149
+ writeFileSync(join(dir, "step.sh"), step.script);
150
+ const out = spawnSync("bash", [join(dir, "step.sh")], {
151
+ cwd: dir,
152
+ encoding: "utf-8",
153
+ env: { PATH: process.env.PATH, HOME: dir, TMPDIR: dir, JAVA_HOME: "", CIBUILD_SOURCE_DIR: "", ...captureEnv() },
154
+ });
155
+ expect(out.status).not.toBe(0);
156
+ expect(readFileSync(join(dir, "runs"), "utf-8").trim().split("\n")).toHaveLength(2);
157
+ });
158
+ });
159
+ test("the step is valid bash", async () => {
160
+ const step = await new GradleBuildStepExecutor().execute({ gradle_task: ":app:assembleDebug" }, {}, testConfig);
161
+ expect(spawnSync("bash", ["-n"], { input: step.script }).status).toBe(0);
162
+ });
163
+ //# sourceMappingURL=capture-injection.test.js.map
@@ -0,0 +1,42 @@
1
+ /**
2
+ * After `pod install`: raise every pod target whose deployment target is below
3
+ * the app's own to the app's.
4
+ *
5
+ * A pod target below iOS 9 links ARC Lite, and Xcode 14.3 removed
6
+ * `libarclite`: `clang: error: SDK does not contain 'libarclite' at …
7
+ * libarclite_iphonesimulator.a; try increasing the minimum deployment
8
+ * target`. CocoaPods gives each pod target the deployment target its podspec
9
+ * declares, so an old pod (SwiftLinkPreview 3.1.0, `ios: '8.0'`) stops an app
10
+ * that itself targets iOS 12 (YuigaWada/MissCat, nightly-baseline issue 53).
11
+ * The usual fix lives in the app's own Podfile, a `post_install` that raises
12
+ * the pods; a repository whose Podfile has none cannot build under any
13
+ * current Xcode.
14
+ *
15
+ * RULED 2026-10-01 (Alex): raise every pod target below the app target's own
16
+ * deployment target to it, in the step, always. Never the app target, never
17
+ * past what the app promises: the floor is the lowest deployment target among
18
+ * the user targets CocoaPods integrated (each found by its `Pods-*.xcconfig`
19
+ * base configuration), so an extension that targets lower than the app keeps
20
+ * its pods buildable for it. A pod cannot run below the app that embeds it, so
21
+ * the raise changes nothing a user of the app could observe. Only the
22
+ * generated `Pods/*.xcodeproj` is edited; it is the checkout's, never
23
+ * committed back.
24
+ *
25
+ * Measured on a clone, Xcode 26.4, 2026-10-01: MissCat @ 574355469ebb, app
26
+ * targets MissCat and MissCatShare at 12.0, 74 pod build configurations raised
27
+ * from 8.0–9.3; SwiftLinkPreview then compiled at ios12.0-simulator and the
28
+ * build log never mentioned libarclite.
29
+ *
30
+ * Never a reason the step fails: a Ruby that cannot load `xcodeproj`, a Pods
31
+ * project it cannot read, a workspace it cannot find — each is a line in the
32
+ * log and the pods as CocoaPods left them.
33
+ */
34
+ /** Ruby; argv[0] is the Pods directory. Prints what it read and what it raised. */
35
+ export declare const POD_DEPLOYMENT_FLOOR_SOURCE: string;
36
+ /**
37
+ * Bash lines that run the raise in the step's directory, after `pod install`.
38
+ * They expect `$USE_BUNDLE_EXEC` and `$BUNDLE_CMD` from the step, and never
39
+ * fail it.
40
+ */
41
+ export declare function podDeploymentFloorLines(): string[];
42
+ //# sourceMappingURL=cocoapods-deployment-floor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cocoapods-deployment-floor.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/cocoapods-deployment-floor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,mFAAmF;AACnF,eAAO,MAAM,2BAA2B,EAAE,MAgEzC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,EAAE,CAkClD"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * After `pod install`: raise every pod target whose deployment target is below
3
+ * the app's own to the app's.
4
+ *
5
+ * A pod target below iOS 9 links ARC Lite, and Xcode 14.3 removed
6
+ * `libarclite`: `clang: error: SDK does not contain 'libarclite' at …
7
+ * libarclite_iphonesimulator.a; try increasing the minimum deployment
8
+ * target`. CocoaPods gives each pod target the deployment target its podspec
9
+ * declares, so an old pod (SwiftLinkPreview 3.1.0, `ios: '8.0'`) stops an app
10
+ * that itself targets iOS 12 (YuigaWada/MissCat, nightly-baseline issue 53).
11
+ * The usual fix lives in the app's own Podfile, a `post_install` that raises
12
+ * the pods; a repository whose Podfile has none cannot build under any
13
+ * current Xcode.
14
+ *
15
+ * RULED 2026-10-01 (Alex): raise every pod target below the app target's own
16
+ * deployment target to it, in the step, always. Never the app target, never
17
+ * past what the app promises: the floor is the lowest deployment target among
18
+ * the user targets CocoaPods integrated (each found by its `Pods-*.xcconfig`
19
+ * base configuration), so an extension that targets lower than the app keeps
20
+ * its pods buildable for it. A pod cannot run below the app that embeds it, so
21
+ * the raise changes nothing a user of the app could observe. Only the
22
+ * generated `Pods/*.xcodeproj` is edited; it is the checkout's, never
23
+ * committed back.
24
+ *
25
+ * Measured on a clone, Xcode 26.4, 2026-10-01: MissCat @ 574355469ebb, app
26
+ * targets MissCat and MissCatShare at 12.0, 74 pod build configurations raised
27
+ * from 8.0–9.3; SwiftLinkPreview then compiled at ios12.0-simulator and the
28
+ * build log never mentioned libarclite.
29
+ *
30
+ * Never a reason the step fails: a Ruby that cannot load `xcodeproj`, a Pods
31
+ * project it cannot read, a workspace it cannot find — each is a line in the
32
+ * log and the pods as CocoaPods left them.
33
+ */
34
+ /** Ruby; argv[0] is the Pods directory. Prints what it read and what it raised. */
35
+ export const POD_DEPLOYMENT_FLOOR_SOURCE = String.raw `
36
+ require 'xcodeproj'
37
+ pods_dir = File.expand_path(ARGV[0] || 'Pods')
38
+ pod_projects = Dir.glob(File.join(pods_dir, '*.xcodeproj'))
39
+ if pod_projects.empty?
40
+ puts "No Pods project under #{pods_dir}; pods' deployment targets left as they are"
41
+ exit 0
42
+ end
43
+ root = File.expand_path('..', pods_dir)
44
+ KEYS = %w[IPHONEOS_DEPLOYMENT_TARGET MACOSX_DEPLOYMENT_TARGET TVOS_DEPLOYMENT_TARGET WATCHOS_DEPLOYMENT_TARGET XROS_DEPLOYMENT_TARGET]
45
+ def version_of(value)
46
+ value.to_s.strip =~ /\A\d+(\.\d+){0,2}\z/ ? Gem::Version.new(value.to_s.strip) : nil
47
+ end
48
+
49
+ floors = {}
50
+ Dir.glob(File.join(root, '*.xcworkspace')).each do |ws|
51
+ Xcodeproj::Workspace.new_from_xcworkspace(ws).file_references.each do |ref|
52
+ path = File.expand_path(ref.absolute_path(File.expand_path('..', ws)))
53
+ next if path.start_with?(pods_dir + File::SEPARATOR) || !File.directory?(path)
54
+ project = Xcodeproj::Project.open(path)
55
+ project.native_targets.each do |target|
56
+ target.build_configurations.each do |config|
57
+ base = config.base_configuration_reference
58
+ next unless base && File.basename(base.path.to_s) =~ /\APods-.*\.xcconfig\z/
59
+ project_settings = project.build_configuration_list.build_settings(config.name) || {}
60
+ KEYS.each do |key|
61
+ v = version_of(config.build_settings[key]) || version_of(project_settings[key])
62
+ next unless v
63
+ floors[key] = v if floors[key].nil? || v < floors[key]
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ if floors.empty?
70
+ puts "No app target CocoaPods integrated declares a deployment target; pods' deployment targets left as they are"
71
+ exit 0
72
+ end
73
+ puts "The app's own deployment target: #{floors.map { |k, v| "#{k} #{v}" }.join(', ')}"
74
+
75
+ raised = []
76
+ pod_projects.each do |path|
77
+ project = Xcodeproj::Project.open(path)
78
+ changed = false
79
+ project.targets.each do |target|
80
+ next if target.name.start_with?('Pods-')
81
+ target.build_configurations.each do |config|
82
+ floors.each do |key, floor|
83
+ v = version_of(config.build_settings[key])
84
+ next unless v && v < floor
85
+ config.build_settings[key] = floor.to_s
86
+ raised << "#{target.name} #{v}"
87
+ changed = true
88
+ end
89
+ end
90
+ end
91
+ project.save if changed
92
+ end
93
+ if raised.empty?
94
+ puts "No pod target is below it"
95
+ else
96
+ names = raised.uniq
97
+ puts "Raised #{names.size} pod target(s) below the app's deployment target to it: #{names.join(', ')}"
98
+ end
99
+ `;
100
+ /**
101
+ * Bash lines that run the raise in the step's directory, after `pod install`.
102
+ * They expect `$USE_BUNDLE_EXEC` and `$BUNDLE_CMD` from the step, and never
103
+ * fail it.
104
+ */
105
+ export function podDeploymentFloorLines() {
106
+ return [
107
+ "# Raise pods below the app's own deployment target to it — see",
108
+ '# cocoapods-deployment-floor.ts. Never fails the step.',
109
+ 'if [ -d Pods ]; then',
110
+ ' POD_FLOOR_SCRIPT="$(mktemp -t cibuild-pod-floor).rb"',
111
+ ` cat > "$POD_FLOOR_SCRIPT" << 'CIBUILD_POD_FLOOR_EOF'`,
112
+ POD_DEPLOYMENT_FLOOR_SOURCE.trim(),
113
+ 'CIBUILD_POD_FLOOR_EOF',
114
+ ' # A Ruby that can load xcodeproj: the bundle CocoaPods ran from, the',
115
+ " # ruby on PATH, or a Homebrew pod wrapper's own interpreter and gems.",
116
+ ' POD_FLOOR_RUN=""',
117
+ ' if [ "$USE_BUNDLE_EXEC" = "true" ] && $BUNDLE_CMD exec ruby -e "require %q(xcodeproj)" >/dev/null 2>&1; then',
118
+ ' POD_FLOOR_RUN="$BUNDLE_CMD exec ruby"',
119
+ ' elif ruby -e "require %q(xcodeproj)" >/dev/null 2>&1; then',
120
+ ' POD_FLOOR_RUN="ruby"',
121
+ ' else',
122
+ ' POD_WRAPPER="$(command -v pod 2>/dev/null || true)"',
123
+ ' POD_GEM_HOME="$( [ -n "$POD_WRAPPER" ] && sed -n \'s/^GEM_HOME="\\([^"]*\\)".*/\\1/p\' "$POD_WRAPPER" | head -n 1)"',
124
+ ' POD_REAL="$( [ -n "$POD_WRAPPER" ] && sed -n \'s/.*exec "\\([^"]*\\)".*/\\1/p\' "$POD_WRAPPER" | head -n 1)"',
125
+ ' POD_RUBY="$( [ -n "$POD_REAL" ] && [ -f "$POD_REAL" ] && head -n 1 "$POD_REAL" | sed -n \'s/^#!//p\')"',
126
+ ' if [ -n "$POD_GEM_HOME" ] && [ -n "$POD_RUBY" ] && GEM_HOME="$POD_GEM_HOME" $POD_RUBY -e "require %q(xcodeproj)" >/dev/null 2>&1; then',
127
+ ' POD_FLOOR_RUN="env GEM_HOME=$POD_GEM_HOME $POD_RUBY"',
128
+ ' fi',
129
+ ' fi',
130
+ ' if [ -n "$POD_FLOOR_RUN" ]; then',
131
+ ' $POD_FLOOR_RUN "$POD_FLOOR_SCRIPT" Pods || echo "⚠️ Could not raise pods to the app\'s deployment target; left as CocoaPods wrote them"',
132
+ ' else',
133
+ ' echo "⚠️ No Ruby here loads xcodeproj; pods\' deployment targets left as CocoaPods wrote them"',
134
+ ' fi',
135
+ ' rm -f "$POD_FLOOR_SCRIPT"',
136
+ 'fi',
137
+ '',
138
+ ];
139
+ }
140
+ //# sourceMappingURL=cocoapods-deployment-floor.js.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Pods below the app's own deployment target are raised to it, after pod
3
+ * install, and nothing else moves. Witness: YuigaWada/MissCat (nightly-baseline
4
+ * issue 53) — SwiftLinkPreview 3.1.0 at iOS 8.0 linked libarclite, which
5
+ * Xcode 14.3 removed, in an app that targets iOS 12.0.
6
+ *
7
+ * The Ruby runs for real against projects the xcodeproj gem writes, when this
8
+ * machine's ruby can load it; otherwise those tests are skipped and say so.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=cocoapods-deployment-floor.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cocoapods-deployment-floor.test.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/cocoapods-deployment-floor.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}