@invarn/cibuild 1.3.18 → 1.3.19
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/src/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { resolve, extname } from "node:path";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
|
-
import { existsSync, readdirSync, mkdirSync, copyFileSync, readFileSync, writeFileSync, appendFileSync } from "node:fs";
|
|
4
|
+
import { existsSync, readdirSync, mkdirSync, copyFileSync, readFileSync, writeFileSync, appendFileSync, statSync } from "node:fs";
|
|
5
5
|
import { homedir } from "node:os";
|
|
6
6
|
import { execSync } from "node:child_process";
|
|
7
7
|
import prompts from "prompts";
|
|
@@ -26,7 +26,7 @@ import { generateGitHubActionsWorkflow } from "./commands/github-workflow.js";
|
|
|
26
26
|
* Returns the detected project type, or null if neither is found.
|
|
27
27
|
*/
|
|
28
28
|
function detectMobileProjectRoot(dir) {
|
|
29
|
-
// Android: must have build.gradle or build.gradle.kts at root
|
|
29
|
+
// Android/KMM: must have build.gradle or build.gradle.kts at root
|
|
30
30
|
const androidIndicators = [
|
|
31
31
|
"build.gradle",
|
|
32
32
|
"build.gradle.kts",
|
|
@@ -35,7 +35,22 @@ function detectMobileProjectRoot(dir) {
|
|
|
35
35
|
"gradlew",
|
|
36
36
|
];
|
|
37
37
|
const hasAndroidIndicator = androidIndicators.some((f) => existsSync(resolve(dir, f)));
|
|
38
|
+
// KMM: Gradle project with an iosApp/ directory or shared/ multiplatform module
|
|
39
|
+
// Must check before plain Android since KMM also has Gradle files
|
|
38
40
|
if (hasAndroidIndicator) {
|
|
41
|
+
const kmmIndicators = ["iosApp", "shared", "composeApp"];
|
|
42
|
+
const hasKmmIndicator = kmmIndicators.some((d) => {
|
|
43
|
+
const fullPath = resolve(dir, d);
|
|
44
|
+
try {
|
|
45
|
+
return existsSync(fullPath) && statSync(fullPath).isDirectory();
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
if (hasKmmIndicator) {
|
|
52
|
+
return "kmm";
|
|
53
|
+
}
|
|
39
54
|
return "android";
|
|
40
55
|
}
|
|
41
56
|
// iOS: must have a .xcodeproj or .xcworkspace directory, or a Podfile
|
|
@@ -88,9 +103,10 @@ async function handleInitCommand(opts = {}) {
|
|
|
88
103
|
const projectType = detectMobileProjectRoot(cwd);
|
|
89
104
|
if (!projectType) {
|
|
90
105
|
console.error("Error: Not a mobile project root.");
|
|
91
|
-
console.error("ci init must be run from the root folder of an Android or
|
|
92
|
-
console.error("\nAndroid projects must contain one of:");
|
|
106
|
+
console.error("ci init must be run from the root folder of an Android, iOS, or KMM project.");
|
|
107
|
+
console.error("\nAndroid/KMM projects must contain one of:");
|
|
93
108
|
console.error(" build.gradle, build.gradle.kts, settings.gradle, settings.gradle.kts, gradlew");
|
|
109
|
+
console.error("\nKMM projects additionally need: iosApp/, shared/, or composeApp/ directory");
|
|
94
110
|
console.error("\niOS projects must contain one of:");
|
|
95
111
|
console.error(" *.xcodeproj, *.xcworkspace, Podfile");
|
|
96
112
|
process.exit(1);
|
|
@@ -104,7 +120,8 @@ async function handleInitCommand(opts = {}) {
|
|
|
104
120
|
process.exit(1);
|
|
105
121
|
}
|
|
106
122
|
}
|
|
107
|
-
|
|
123
|
+
const projectTypeLabel = projectType === "kmm" ? "KMM (Kotlin Multiplatform)" : projectType === "android" ? "Android" : "iOS";
|
|
124
|
+
console.log(`\nDetected project type: ${projectTypeLabel}`);
|
|
108
125
|
console.log(`
|
|
109
126
|
╔══════════════════════════════════════════════════════════════╗
|
|
110
127
|
║ CI Build - Dependency Check ║
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare function handleBuildCommand(detectMobileProjectRoot: (dir: string) => "android" | "ios" | null, options?: {
|
|
1
|
+
export declare function handleBuildCommand(detectMobileProjectRoot: (dir: string) => "android" | "ios" | "kmm" | null, options?: {
|
|
2
2
|
createPipelinesDir?: boolean;
|
|
3
3
|
nonInteractive?: boolean;
|
|
4
4
|
}): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/commands/build.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/commands/build.ts"],"names":[],"mappings":"AA+7BA,wBAAsB,kBAAkB,CACtC,uBAAuB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,EAC1E,OAAO,GAAE;IAAE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAAC,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GACvE,OAAO,CAAC,IAAI,CAAC,CA4Bf"}
|
|
@@ -122,7 +122,7 @@ function detectSetupNeeds(warnings) {
|
|
|
122
122
|
artifactType: 'apk',
|
|
123
123
|
};
|
|
124
124
|
}
|
|
125
|
-
function generateAndroidPipeline(javaVersion = 17, setup = { keystore: false, keystoreProperties: false, googleServices: false, googlePlayDeploy: false, googlePlayPackageName: '', artifactType: 'apk', keystorePaths: {} }, variants = DEFAULT_VARIANTS) {
|
|
125
|
+
function generateAndroidPipeline(javaVersion = 17, setup = { keystore: false, keystoreProperties: false, googleServices: false, googlePlayDeploy: false, googlePlayPackageName: '', artifactType: 'apk', keystorePaths: {} }, variants = DEFAULT_VARIANTS, cacheTechnology = "gradle") {
|
|
126
126
|
const keystoreStepFor = (wf) => {
|
|
127
127
|
if (!setup.keystore)
|
|
128
128
|
return "";
|
|
@@ -227,11 +227,7 @@ ${keystoreStepFor("primary")}${googleServicesStep}
|
|
|
227
227
|
|
|
228
228
|
- cache-pull@1.0.0:
|
|
229
229
|
inputs:
|
|
230
|
-
|
|
231
|
-
cache_paths:
|
|
232
|
-
- ~/.gradle/caches
|
|
233
|
-
- ~/.gradle/wrapper
|
|
234
|
-
- .gradle
|
|
230
|
+
technology: ${cacheTechnology}
|
|
235
231
|
|
|
236
232
|
- android-lint@1.0.0:
|
|
237
233
|
is_skippable: true
|
|
@@ -257,11 +253,7 @@ ${keystoreStepFor("primary")}${googleServicesStep}
|
|
|
257
253
|
|
|
258
254
|
- cache-push@1.0.0:
|
|
259
255
|
inputs:
|
|
260
|
-
|
|
261
|
-
cache_paths:
|
|
262
|
-
- ~/.gradle/caches
|
|
263
|
-
- ~/.gradle/wrapper
|
|
264
|
-
- .gradle
|
|
256
|
+
technology: ${cacheTechnology}
|
|
265
257
|
|
|
266
258
|
pull-request:
|
|
267
259
|
envs:
|
|
@@ -275,10 +267,7 @@ ${keystoreStepFor("pull-request")}${googleServicesStep}
|
|
|
275
267
|
|
|
276
268
|
- cache-pull@1.0.0:
|
|
277
269
|
inputs:
|
|
278
|
-
|
|
279
|
-
cache_paths:
|
|
280
|
-
- ~/.gradle/caches
|
|
281
|
-
- ~/.gradle/wrapper
|
|
270
|
+
technology: ${cacheTechnology}
|
|
282
271
|
|
|
283
272
|
- android-lint@1.0.0:
|
|
284
273
|
is_skippable: true
|
|
@@ -303,10 +292,7 @@ ${keystoreStepFor("pull-request")}${googleServicesStep}
|
|
|
303
292
|
|
|
304
293
|
- cache-push@1.0.0:
|
|
305
294
|
inputs:
|
|
306
|
-
|
|
307
|
-
cache_paths:
|
|
308
|
-
- ~/.gradle/caches
|
|
309
|
-
- ~/.gradle/wrapper
|
|
295
|
+
technology: ${cacheTechnology}
|
|
310
296
|
|
|
311
297
|
release:
|
|
312
298
|
envs:
|
|
@@ -416,10 +402,8 @@ function generateIosPipeline(projectPath, setup, variants) {
|
|
|
416
402
|
submit_for_review: 'no'
|
|
417
403
|
`
|
|
418
404
|
: "";
|
|
419
|
-
// Cache
|
|
420
|
-
const
|
|
421
|
-
? ` - Pods\n - Podfile.lock`
|
|
422
|
-
: ` - .build`;
|
|
405
|
+
// Cache technology depends on whether CocoaPods is used
|
|
406
|
+
const iosCacheTechnology = setup.cocoaPods ? "cocoapods" : "spm";
|
|
423
407
|
return `format_version: '1'
|
|
424
408
|
|
|
425
409
|
meta:
|
|
@@ -441,9 +425,7 @@ ${schemeEnvFor(pv.scheme)}${configEnvFor(pv.configuration)}
|
|
|
441
425
|
steps:
|
|
442
426
|
- cache-pull@1.0.0:
|
|
443
427
|
inputs:
|
|
444
|
-
|
|
445
|
-
cache_paths:
|
|
446
|
-
${cachePaths}
|
|
428
|
+
technology: ${iosCacheTechnology}
|
|
447
429
|
${podInstallStep}
|
|
448
430
|
- xcode-archive@1.0.0:
|
|
449
431
|
inputs:
|
|
@@ -463,9 +445,7 @@ ${podInstallStep}
|
|
|
463
445
|
|
|
464
446
|
- cache-push@1.0.0:
|
|
465
447
|
inputs:
|
|
466
|
-
|
|
467
|
-
cache_paths:
|
|
468
|
-
${cachePaths}
|
|
448
|
+
technology: ${iosCacheTechnology}
|
|
469
449
|
|
|
470
450
|
pull-request:
|
|
471
451
|
envs:
|
|
@@ -473,9 +453,7 @@ ${schemeEnvFor(prv.scheme)}${configEnvFor(prv.configuration)}
|
|
|
473
453
|
steps:
|
|
474
454
|
- cache-pull@1.0.0:
|
|
475
455
|
inputs:
|
|
476
|
-
|
|
477
|
-
cache_paths:
|
|
478
|
-
${cachePaths}
|
|
456
|
+
technology: ${iosCacheTechnology}
|
|
479
457
|
${podInstallStepPR}
|
|
480
458
|
- xcode-test@1.0.0:
|
|
481
459
|
is_skippable: true
|
|
@@ -493,9 +471,7 @@ ${podInstallStepPR}
|
|
|
493
471
|
|
|
494
472
|
- cache-push@1.0.0:
|
|
495
473
|
inputs:
|
|
496
|
-
|
|
497
|
-
cache_paths:
|
|
498
|
-
${cachePaths}
|
|
474
|
+
technology: ${iosCacheTechnology}
|
|
499
475
|
|
|
500
476
|
release:
|
|
501
477
|
envs:
|
|
@@ -505,9 +481,7 @@ ${schemeEnvFor(rv.scheme)}
|
|
|
505
481
|
${codeSigningStep}
|
|
506
482
|
- cache-pull@1.0.0:
|
|
507
483
|
inputs:
|
|
508
|
-
|
|
509
|
-
cache_paths:
|
|
510
|
-
${cachePaths}
|
|
484
|
+
technology: ${iosCacheTechnology}
|
|
511
485
|
${podInstallStep}
|
|
512
486
|
- xcode-archive@1.0.0:
|
|
513
487
|
inputs:
|
|
@@ -848,17 +822,23 @@ export async function handleBuildCommand(detectMobileProjectRoot, options = {})
|
|
|
848
822
|
await handleIosBuildCommand(cwd, options);
|
|
849
823
|
return;
|
|
850
824
|
}
|
|
851
|
-
if (projectType
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
console.error("\nAndroid projects must contain one of:");
|
|
855
|
-
console.error(" build.gradle, build.gradle.kts, settings.gradle, settings.gradle.kts, gradlew");
|
|
856
|
-
console.error("\niOS projects must contain one of:");
|
|
857
|
-
console.error(" *.xcodeproj, *.xcworkspace, Podfile");
|
|
858
|
-
process.exit(1);
|
|
825
|
+
if (projectType === "kmm" || projectType === "android") {
|
|
826
|
+
await handleAndroidBuildCommand(cwd, options, projectType === "kmm" ? "kmm" : "gradle");
|
|
827
|
+
return;
|
|
859
828
|
}
|
|
829
|
+
console.error("Error: Not a mobile project root.");
|
|
830
|
+
console.error("'ci build' must be run from the root folder of an Android, iOS, or KMM project.");
|
|
831
|
+
console.error("\nAndroid/KMM projects must contain one of:");
|
|
832
|
+
console.error(" build.gradle, build.gradle.kts, settings.gradle, settings.gradle.kts, gradlew");
|
|
833
|
+
console.error("\nKMM projects additionally need: iosApp/, shared/, or composeApp/ directory");
|
|
834
|
+
console.error("\niOS projects must contain one of:");
|
|
835
|
+
console.error(" *.xcodeproj, *.xcworkspace, Podfile");
|
|
836
|
+
process.exit(1);
|
|
837
|
+
}
|
|
838
|
+
async function handleAndroidBuildCommand(cwd, options, cacheTechnology) {
|
|
839
|
+
const platformLabel = cacheTechnology === "kmm" ? "KMM (Kotlin Multiplatform)" : "Android";
|
|
860
840
|
// 2. Scan the project for potential unknowns
|
|
861
|
-
console.log(
|
|
841
|
+
console.log(`\n🔍 Scanning ${platformLabel} project for potential unknowns...\n`);
|
|
862
842
|
const scanResult = await scanAndroidProject(cwd);
|
|
863
843
|
console.log(formatScanResult(scanResult));
|
|
864
844
|
// 3. Prompt for build variants per workflow
|
|
@@ -1059,10 +1039,10 @@ export async function handleBuildCommand(detectMobileProjectRoot, options = {})
|
|
|
1059
1039
|
// that exact JDK — a newer JDK can cross-compile. Enforce a minimum of 17
|
|
1060
1040
|
// since ubuntu-latest runners ship with JDK 17+ and JDK <17 is unavailable.
|
|
1061
1041
|
const javaVersion = Math.max(scanResult.detectedJavaVersion ?? 17, 17);
|
|
1062
|
-
const yaml = generateAndroidPipeline(javaVersion, setupOptions, variants);
|
|
1042
|
+
const yaml = generateAndroidPipeline(javaVersion, setupOptions, variants, cacheTechnology);
|
|
1063
1043
|
writeFileSync(outputPath, yaml, "utf-8");
|
|
1064
1044
|
console.log("\n✅ Generated .ci/pipelines/cibuild.yml");
|
|
1065
|
-
console.log(
|
|
1045
|
+
console.log(` Platform: ${platformLabel}`);
|
|
1066
1046
|
console.log(` Workflows: primary (${variants.primary.variant}), pull-request (${variants.pullRequest.variant}), release (${variants.release.variant})`);
|
|
1067
1047
|
if (setupOptions.keystore || setupOptions.keystoreProperties || setupOptions.googleServices || setupOptions.googlePlayDeploy) {
|
|
1068
1048
|
console.log(" Setup steps included:");
|
|
@@ -80,7 +80,7 @@ export class CachePullStepExecutor extends BaseStepExecutor {
|
|
|
80
80
|
commands.push(' echo "Restored paths:"');
|
|
81
81
|
for (const path of cachePaths) {
|
|
82
82
|
commands.push(` EXPANDED_PATH="${this.escapeBash(path)}"`);
|
|
83
|
-
commands.push(' EXPANDED_PATH="${EXPANDED_PATH/#~/$HOME}"');
|
|
83
|
+
commands.push(' EXPANDED_PATH="${EXPANDED_PATH/#~/${CIBUILD_USER_HOME:-$HOME}}"');
|
|
84
84
|
commands.push(' if [ -e "$EXPANDED_PATH" ]; then');
|
|
85
85
|
commands.push(' echo " ✓ $EXPANDED_PATH"');
|
|
86
86
|
commands.push(' else');
|
|
@@ -137,7 +137,7 @@ export class CachePullStepExecutor extends BaseStepExecutor {
|
|
|
137
137
|
commands.push(' echo "Restored paths:"');
|
|
138
138
|
for (const p of preset.paths) {
|
|
139
139
|
commands.push(` EXPANDED="${this.escapeBash(p)}"`);
|
|
140
|
-
commands.push(' EXPANDED="${EXPANDED/#~/$HOME}"');
|
|
140
|
+
commands.push(' EXPANDED="${EXPANDED/#~/${CIBUILD_USER_HOME:-$HOME}}"');
|
|
141
141
|
commands.push(' if [ -e "$EXPANDED" ]; then');
|
|
142
142
|
commands.push(' echo " ✓ $EXPANDED"');
|
|
143
143
|
commands.push(' else');
|
|
@@ -234,7 +234,7 @@ export class CachePushStepExecutor extends BaseStepExecutor {
|
|
|
234
234
|
}
|
|
235
235
|
// Expand tilde by using parameter expansion
|
|
236
236
|
commands.push(`EXPANDED_PATH="${this.escapeBash(resolvedPath)}"`);
|
|
237
|
-
commands.push('EXPANDED_PATH="${EXPANDED_PATH/#~/$HOME}"');
|
|
237
|
+
commands.push('EXPANDED_PATH="${EXPANDED_PATH/#~/${CIBUILD_USER_HOME:-$HOME}}"');
|
|
238
238
|
commands.push('');
|
|
239
239
|
commands.push('# Expand glob patterns and check each match');
|
|
240
240
|
commands.push('FOUND_MATCH=false');
|
|
@@ -319,7 +319,7 @@ export class CachePushStepExecutor extends BaseStepExecutor {
|
|
|
319
319
|
commands.push('PATHS_TO_CACHE=()');
|
|
320
320
|
for (const p of preset.paths) {
|
|
321
321
|
commands.push(`EXPANDED="${this.escapeBash(p)}"`);
|
|
322
|
-
commands.push('EXPANDED="${EXPANDED/#~/$HOME}"');
|
|
322
|
+
commands.push('EXPANDED="${EXPANDED/#~/${CIBUILD_USER_HOME:-$HOME}}"');
|
|
323
323
|
commands.push('if [ -e "$EXPANDED" ]; then');
|
|
324
324
|
commands.push(' PATHS_TO_CACHE+=("$EXPANDED")');
|
|
325
325
|
if (isDebugMode) {
|