@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.
- package/dist/cli.cjs +97 -12
- package/dist/src/yaml/steps/android.d.ts.map +1 -1
- package/dist/src/yaml/steps/android.js +11 -3
- package/dist/src/yaml/steps/capture-injection.d.ts +30 -0
- package/dist/src/yaml/steps/capture-injection.d.ts.map +1 -0
- package/dist/src/yaml/steps/capture-injection.js +88 -0
- package/dist/src/yaml/steps/capture-injection.test.d.ts +2 -0
- package/dist/src/yaml/steps/capture-injection.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/capture-injection.test.js +163 -0
- package/dist/src/yaml/steps/cocoapods-deployment-floor.d.ts +42 -0
- package/dist/src/yaml/steps/cocoapods-deployment-floor.d.ts.map +1 -0
- package/dist/src/yaml/steps/cocoapods-deployment-floor.js +140 -0
- package/dist/src/yaml/steps/cocoapods-deployment-floor.test.d.ts +11 -0
- package/dist/src/yaml/steps/cocoapods-deployment-floor.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/cocoapods-deployment-floor.test.js +176 -0
- package/dist/src/yaml/steps/gradle-memory.d.ts +1 -1
- package/dist/src/yaml/steps/gradle-memory.d.ts.map +1 -1
- package/dist/src/yaml/steps/gradle-memory.js +78 -3
- package/dist/src/yaml/steps/gradle-memory.test.js +48 -1
- package/dist/src/yaml/steps/ios-deps.d.ts.map +1 -1
- package/dist/src/yaml/steps/ios-deps.js +2 -0
- package/dist/src/yaml/steps/xcode-derived-data.test.js +47 -4
- package/dist/src/yaml/steps/xcode-simulator-archs.d.ts +53 -0
- package/dist/src/yaml/steps/xcode-simulator-archs.d.ts.map +1 -0
- package/dist/src/yaml/steps/xcode-simulator-archs.js +98 -0
- package/dist/src/yaml/steps/xcode-simulator-archs.test.d.ts +21 -0
- package/dist/src/yaml/steps/xcode-simulator-archs.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/xcode-simulator-archs.test.js +155 -0
- package/dist/src/yaml/steps/xcode.d.ts.map +1 -1
- package/dist/src/yaml/steps/xcode.js +43 -4
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"android.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/android.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH,OAAO,EAAE,gBAAgB,EAAuB,MAAM,WAAW,CAAC;
|
|
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
|
|
473
|
+
let gradleArgs = this.escapeBash(gradleTask);
|
|
473
474
|
if (gradleOptions && gradleOptions.trim() !== '') {
|
|
474
|
-
|
|
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 @@
|
|
|
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"}
|