@invarn/cibuild 1.4.1 → 1.4.3
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 +1 -1
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +56 -678
- package/dist/src/commands/detect-platform.d.ts +13 -0
- package/dist/src/commands/detect-platform.d.ts.map +1 -0
- package/dist/src/commands/detect-platform.js +51 -0
- package/dist/src/commands/detect-project.d.ts +7 -0
- package/dist/src/commands/detect-project.d.ts.map +1 -0
- package/dist/src/commands/detect-project.js +12 -0
- package/dist/src/commands/index.d.ts +26 -0
- package/dist/src/commands/index.d.ts.map +1 -0
- package/dist/src/commands/index.js +22 -0
- package/dist/src/commands/init.d.ts +13 -0
- package/dist/src/commands/init.d.ts.map +1 -0
- package/dist/src/commands/init.js +262 -0
- package/dist/src/commands/run.d.ts +22 -0
- package/dist/src/commands/run.d.ts.map +1 -0
- package/dist/src/commands/run.js +131 -0
- package/dist/src/commands/validate.d.ts +10 -0
- package/dist/src/commands/validate.d.ts.map +1 -0
- package/dist/src/commands/validate.js +46 -0
- package/dist/src/shared/detect-project.d.ts +11 -0
- package/dist/src/shared/detect-project.d.ts.map +1 -0
- package/dist/src/shared/detect-project.js +53 -0
- package/dist/src/shared/gitignore.d.ts +6 -0
- package/dist/src/shared/gitignore.d.ts.map +1 -0
- package/dist/src/shared/gitignore.js +26 -0
- package/dist/src/shared/prompts.d.ts +18 -0
- package/dist/src/shared/prompts.d.ts.map +1 -0
- package/dist/src/shared/prompts.js +96 -0
- package/dist/src/yaml/steps/cache.d.ts.map +1 -1
- package/dist/src/yaml/steps/cache.js +24 -10
- package/package.json +7 -3
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Detects whether the given directory is the root of an Android, iOS, or
|
|
5
|
+
* KMM project. Returns the detected project type, or null if none match.
|
|
6
|
+
*
|
|
7
|
+
* KMM is checked before Android because both have Gradle files; KMM is
|
|
8
|
+
* distinguished by the presence of an `iosApp/`, `shared/`, or
|
|
9
|
+
* `composeApp/` directory alongside the Gradle files.
|
|
10
|
+
*/
|
|
11
|
+
export function detectMobileProjectRoot(dir) {
|
|
12
|
+
const androidIndicators = [
|
|
13
|
+
"build.gradle",
|
|
14
|
+
"build.gradle.kts",
|
|
15
|
+
"settings.gradle",
|
|
16
|
+
"settings.gradle.kts",
|
|
17
|
+
"gradlew",
|
|
18
|
+
];
|
|
19
|
+
const hasAndroidIndicator = androidIndicators.some((f) => existsSync(resolve(dir, f)));
|
|
20
|
+
if (hasAndroidIndicator) {
|
|
21
|
+
const kmmIndicators = ["iosApp", "shared", "composeApp"];
|
|
22
|
+
const hasKmmIndicator = kmmIndicators.some((d) => {
|
|
23
|
+
const fullPath = resolve(dir, d);
|
|
24
|
+
try {
|
|
25
|
+
return existsSync(fullPath) && statSync(fullPath).isDirectory();
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
if (hasKmmIndicator)
|
|
32
|
+
return "kmm";
|
|
33
|
+
return "android";
|
|
34
|
+
}
|
|
35
|
+
const iosFileIndicators = ["Podfile"];
|
|
36
|
+
const hasIosFile = iosFileIndicators.some((f) => existsSync(resolve(dir, f)));
|
|
37
|
+
if (!hasIosFile) {
|
|
38
|
+
try {
|
|
39
|
+
const entries = readdirSync(dir);
|
|
40
|
+
const hasXcodeDir = entries.some((e) => e.endsWith(".xcodeproj") || e.endsWith(".xcworkspace"));
|
|
41
|
+
if (hasXcodeDir)
|
|
42
|
+
return "ios";
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// Unreadable directory — fall through.
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
return "ios";
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=detect-project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitignore.d.ts","sourceRoot":"","sources":["../../../src/shared/gitignore.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAiB/D"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { appendFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Ensures CI Build runtime files are listed in .gitignore. Safe to call
|
|
5
|
+
* repeatedly — only appends entries that are missing.
|
|
6
|
+
*/
|
|
7
|
+
export function ensureCiBuildGitignoreEntries(cwd) {
|
|
8
|
+
const gitignorePath = resolve(cwd, ".gitignore");
|
|
9
|
+
const gitignoreEntries = [".cibuild-secrets.json", ".ci/.envstore.json", ".ci/keys/", "build/"];
|
|
10
|
+
if (existsSync(gitignorePath)) {
|
|
11
|
+
const contents = readFileSync(gitignorePath, "utf-8");
|
|
12
|
+
const lines = contents.split("\n").map((l) => l.trim());
|
|
13
|
+
const toAdd = gitignoreEntries.filter((e) => !lines.includes(e));
|
|
14
|
+
if (toAdd.length > 0) {
|
|
15
|
+
appendFileSync(gitignorePath, `\n${toAdd.join("\n")}\n`);
|
|
16
|
+
for (const entry of toAdd) {
|
|
17
|
+
console.log(`✅ Added ${entry} to .gitignore`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
writeFileSync(gitignorePath, `${gitignoreEntries.join("\n")}\n`);
|
|
23
|
+
console.log(`✅ Created .gitignore with CI Build entries`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=gitignore.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { YAMLPipeline } from "../yaml/types.js";
|
|
2
|
+
import type { CIConfig } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Shows an interactive workflow picker. If exactly one workflow exists,
|
|
5
|
+
* returns it without prompting. Returns `undefined` when the user cancels
|
|
6
|
+
* or no workflows are defined.
|
|
7
|
+
*/
|
|
8
|
+
export declare function promptForWorkflow(workflows: string[]): Promise<string | undefined>;
|
|
9
|
+
/**
|
|
10
|
+
* Runs pre-execution validation, separates issues into user-fillable
|
|
11
|
+
* (missing env vars) vs hard-blocking, and collects all missing values
|
|
12
|
+
* upfront in a single form-like pass before execution begins.
|
|
13
|
+
*
|
|
14
|
+
* @returns true if it's safe to proceed, false if the user cancelled or
|
|
15
|
+
* hard errors exist.
|
|
16
|
+
*/
|
|
17
|
+
export declare function promptForMissingVariables(yamlPipeline: YAMLPipeline, workflowName: string, config: CIConfig, yamlFilePath: string): Promise<boolean>;
|
|
18
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/shared/prompts.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA0BxF;AAED;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,YAAY,EAC1B,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,QAAQ,EAChB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,OAAO,CAAC,CAgFlB"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import prompts from "prompts";
|
|
2
|
+
import { StepValidator, formatValidationResult } from "../yaml/step-validator.js";
|
|
3
|
+
import { MissingEnvHandler } from "../yaml/missing-env-handler.js";
|
|
4
|
+
import { MissingEnvironmentVariableError } from "../yaml/env-resolver.js";
|
|
5
|
+
/**
|
|
6
|
+
* Shows an interactive workflow picker. If exactly one workflow exists,
|
|
7
|
+
* returns it without prompting. Returns `undefined` when the user cancels
|
|
8
|
+
* or no workflows are defined.
|
|
9
|
+
*/
|
|
10
|
+
export async function promptForWorkflow(workflows) {
|
|
11
|
+
if (workflows.length === 0) {
|
|
12
|
+
console.error("Error: No workflows found in pipeline file");
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
if (workflows.length === 1) {
|
|
16
|
+
console.log(`Using workflow: ${workflows[0]}\n`);
|
|
17
|
+
return workflows[0];
|
|
18
|
+
}
|
|
19
|
+
const response = await prompts({
|
|
20
|
+
type: "select",
|
|
21
|
+
name: "workflow",
|
|
22
|
+
message: "Select a workflow to run:",
|
|
23
|
+
choices: workflows.map((name) => ({ title: name, value: name })),
|
|
24
|
+
initial: 0,
|
|
25
|
+
});
|
|
26
|
+
if (!response.workflow) {
|
|
27
|
+
console.log("\nWorkflow selection cancelled");
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
console.log();
|
|
31
|
+
return response.workflow;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Runs pre-execution validation, separates issues into user-fillable
|
|
35
|
+
* (missing env vars) vs hard-blocking, and collects all missing values
|
|
36
|
+
* upfront in a single form-like pass before execution begins.
|
|
37
|
+
*
|
|
38
|
+
* @returns true if it's safe to proceed, false if the user cancelled or
|
|
39
|
+
* hard errors exist.
|
|
40
|
+
*/
|
|
41
|
+
export async function promptForMissingVariables(yamlPipeline, workflowName, config, yamlFilePath) {
|
|
42
|
+
console.log(`\n🔍 Running pre-execution validation...`);
|
|
43
|
+
const validator = new StepValidator(yamlPipeline, workflowName, config, yamlFilePath);
|
|
44
|
+
const result = await validator.validateWorkflow();
|
|
45
|
+
const errorIssues = result.issues.filter((i) => i.requirement.severity === "error" && i.result && !i.result.passed);
|
|
46
|
+
const fillable = errorIssues.filter((i) => i.requirement.timing === "pre-execution" &&
|
|
47
|
+
(i.requirement.category === "environment" || i.requirement.category === "input"));
|
|
48
|
+
const blocking = errorIssues.filter((i) => !(i.requirement.timing === "pre-execution" &&
|
|
49
|
+
(i.requirement.category === "environment" || i.requirement.category === "input")));
|
|
50
|
+
if (blocking.length > 0) {
|
|
51
|
+
console.log(formatValidationResult(result));
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
if (fillable.length === 0) {
|
|
55
|
+
if (result.counts.warnings > 0 || result.counts.info > 0) {
|
|
56
|
+
console.log(formatValidationResult(result));
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
console.log("✅ Pre-execution validation passed\n");
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
console.log(`\n${fillable.length} required value(s) missing — provide them to continue:\n`);
|
|
64
|
+
for (const issue of fillable) {
|
|
65
|
+
const stepInfo = issue.stepName ? ` needed by: ${issue.stepName}` : "";
|
|
66
|
+
console.log(` • ${issue.requirement.name.padEnd(30)}${stepInfo}`);
|
|
67
|
+
}
|
|
68
|
+
console.log();
|
|
69
|
+
const handler = new MissingEnvHandler({
|
|
70
|
+
interactive: true,
|
|
71
|
+
workflow: workflowName,
|
|
72
|
+
});
|
|
73
|
+
for (let i = 0; i < fillable.length; i++) {
|
|
74
|
+
const issue = fillable[i];
|
|
75
|
+
const error = new MissingEnvironmentVariableError(issue.requirement.name, issue.stepName, issue.requirement.hint);
|
|
76
|
+
const original = console.log;
|
|
77
|
+
const label = `(${i + 1} of ${fillable.length})`;
|
|
78
|
+
let patched = false;
|
|
79
|
+
console.log = (...args) => {
|
|
80
|
+
if (!patched && typeof args[0] === "string" && args[0].includes("MISSING REQUIRED")) {
|
|
81
|
+
original(`║ MISSING REQUIRED ENVIRONMENT VARIABLE ${label.padEnd(28)}║`);
|
|
82
|
+
patched = true;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
original(...args);
|
|
86
|
+
};
|
|
87
|
+
const handleResult = await handler.handleMissingVariable(error);
|
|
88
|
+
console.log = original;
|
|
89
|
+
if (handleResult.cancelled) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
handler.close();
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAExD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yGAAyG;IACzG,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAUrD,CAAC;AAoBF;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,gBAAgB;IACnD,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;YAoGzF,iBAAiB;
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAExD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yGAAyG;IACzG,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAUrD,CAAC;AAoBF;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,gBAAgB;IACnD,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;YAoGzF,iBAAiB;CAoGhC;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,gBAAgB;IACnD,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;YAwJzF,iBAAiB;CAoGhC"}
|
|
@@ -131,14 +131,21 @@ export class CachePullStepExecutor extends BaseStepExecutor {
|
|
|
131
131
|
commands.push(`CACHE_DIR="${this.escapeBash(config.paths.cacheDir)}"`);
|
|
132
132
|
commands.push('mkdir -p "$CACHE_DIR"');
|
|
133
133
|
commands.push('');
|
|
134
|
+
// Helper: resolve lockfile path — checks exact path first, then searches
|
|
135
|
+
// recursively (handles SPM Package.resolved inside .xcodeproj/.xcworkspace)
|
|
136
|
+
commands.push('__ci_find_lockfile() {');
|
|
137
|
+
commands.push(' if [ -f "$1" ]; then echo "$1"; return; fi');
|
|
138
|
+
commands.push(' find . -name "$(basename "$1")" -not -path "*/DerivedData/*" -not -path "*/.build/*" 2>/dev/null | head -1');
|
|
139
|
+
commands.push('}');
|
|
140
|
+
commands.push('');
|
|
134
141
|
if (chain.length === 1) {
|
|
135
142
|
const preset = chain[0];
|
|
136
|
-
commands.push(`LOCKFILE
|
|
137
|
-
commands.push('if [ -f "$LOCKFILE" ]; then');
|
|
143
|
+
commands.push(`LOCKFILE=$(__ci_find_lockfile "${this.escapeBash(preset.lockfile)}")`);
|
|
144
|
+
commands.push('if [ -n "$LOCKFILE" ] && [ -f "$LOCKFILE" ]; then');
|
|
138
145
|
commands.push(` CHECKSUM=$(shasum -a 256 "$LOCKFILE" | cut -d ' ' -f1 | head -c 16)`);
|
|
139
146
|
commands.push(` CACHE_KEY="${this.escapeBash(preset.keyPrefix)}-\${CHECKSUM}"`);
|
|
140
147
|
commands.push('else');
|
|
141
|
-
commands.push(` echo "Warning: $
|
|
148
|
+
commands.push(` echo "Warning: ${this.escapeBash(preset.lockfile)} not found, using fallback cache key"`);
|
|
142
149
|
commands.push(` CACHE_KEY="${this.escapeBash(preset.keyPrefix)}-no-lockfile"`);
|
|
143
150
|
commands.push('fi');
|
|
144
151
|
}
|
|
@@ -147,8 +154,9 @@ export class CachePullStepExecutor extends BaseStepExecutor {
|
|
|
147
154
|
for (let i = 0; i < chain.length; i++) {
|
|
148
155
|
const preset = chain[i];
|
|
149
156
|
const cond = i === 0 ? 'if' : 'elif';
|
|
150
|
-
commands.push(
|
|
151
|
-
commands.push(
|
|
157
|
+
commands.push(`__ci_lockfile_candidate=$(__ci_find_lockfile "${this.escapeBash(preset.lockfile)}")`);
|
|
158
|
+
commands.push(`${cond} [ -n "$__ci_lockfile_candidate" ] && [ -f "$__ci_lockfile_candidate" ]; then`);
|
|
159
|
+
commands.push(' LOCKFILE="$__ci_lockfile_candidate"');
|
|
152
160
|
commands.push(` CHECKSUM=$(shasum -a 256 "$LOCKFILE" | cut -d ' ' -f1 | head -c 16)`);
|
|
153
161
|
commands.push(` CACHE_KEY="${this.escapeBash(preset.keyPrefix)}-\${CHECKSUM}"`);
|
|
154
162
|
if (isDebugMode) {
|
|
@@ -341,14 +349,19 @@ export class CachePushStepExecutor extends BaseStepExecutor {
|
|
|
341
349
|
commands.push(`CACHE_DIR="${this.escapeBash(config.paths.cacheDir)}"`);
|
|
342
350
|
commands.push('mkdir -p "$CACHE_DIR"');
|
|
343
351
|
commands.push('');
|
|
352
|
+
commands.push('__ci_find_lockfile() {');
|
|
353
|
+
commands.push(' if [ -f "$1" ]; then echo "$1"; return; fi');
|
|
354
|
+
commands.push(' find . -name "$(basename "$1")" -not -path "*/DerivedData/*" -not -path "*/.build/*" 2>/dev/null | head -1');
|
|
355
|
+
commands.push('}');
|
|
356
|
+
commands.push('');
|
|
344
357
|
if (chain.length === 1) {
|
|
345
358
|
const preset = chain[0];
|
|
346
|
-
commands.push(`LOCKFILE
|
|
347
|
-
commands.push('if [ -f "$LOCKFILE" ]; then');
|
|
359
|
+
commands.push(`LOCKFILE=$(__ci_find_lockfile "${this.escapeBash(preset.lockfile)}")`);
|
|
360
|
+
commands.push('if [ -n "$LOCKFILE" ] && [ -f "$LOCKFILE" ]; then');
|
|
348
361
|
commands.push(` CHECKSUM=$(shasum -a 256 "$LOCKFILE" | cut -d ' ' -f1 | head -c 16)`);
|
|
349
362
|
commands.push(` CACHE_KEY="${this.escapeBash(preset.keyPrefix)}-\${CHECKSUM}"`);
|
|
350
363
|
commands.push('else');
|
|
351
|
-
commands.push(` echo "Warning: $
|
|
364
|
+
commands.push(` echo "Warning: ${this.escapeBash(preset.lockfile)} not found, using fallback cache key"`);
|
|
352
365
|
commands.push(` CACHE_KEY="${this.escapeBash(preset.keyPrefix)}-no-lockfile"`);
|
|
353
366
|
commands.push('fi');
|
|
354
367
|
}
|
|
@@ -356,8 +369,9 @@ export class CachePushStepExecutor extends BaseStepExecutor {
|
|
|
356
369
|
for (let i = 0; i < chain.length; i++) {
|
|
357
370
|
const preset = chain[i];
|
|
358
371
|
const cond = i === 0 ? 'if' : 'elif';
|
|
359
|
-
commands.push(
|
|
360
|
-
commands.push(
|
|
372
|
+
commands.push(`__ci_lockfile_candidate=$(__ci_find_lockfile "${this.escapeBash(preset.lockfile)}")`);
|
|
373
|
+
commands.push(`${cond} [ -n "$__ci_lockfile_candidate" ] && [ -f "$__ci_lockfile_candidate" ]; then`);
|
|
374
|
+
commands.push(' LOCKFILE="$__ci_lockfile_candidate"');
|
|
361
375
|
commands.push(` CHECKSUM=$(shasum -a 256 "$LOCKFILE" | cut -d ' ' -f1 | head -c 16)`);
|
|
362
376
|
commands.push(` CACHE_KEY="${this.escapeBash(preset.keyPrefix)}-\${CHECKSUM}"`);
|
|
363
377
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@invarn/cibuild",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.3",
|
|
4
4
|
"description": "CI Build CLI — local pipeline orchestration and validation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/cli.cjs",
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
"./lib": {
|
|
10
10
|
"import": "./dist/src/lib.js",
|
|
11
11
|
"types": "./dist/src/lib.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./commands": {
|
|
14
|
+
"import": "./dist/src/commands/index.js",
|
|
15
|
+
"types": "./dist/src/commands/index.d.ts"
|
|
12
16
|
}
|
|
13
17
|
},
|
|
14
18
|
"bin": {
|
|
@@ -48,7 +52,8 @@
|
|
|
48
52
|
},
|
|
49
53
|
"homepage": "https://github.com/invarnhq/cibuild",
|
|
50
54
|
"dependencies": {
|
|
51
|
-
"js-yaml": "^4.1.0"
|
|
55
|
+
"js-yaml": "^4.1.0",
|
|
56
|
+
"prompts": "^2.4.2"
|
|
52
57
|
},
|
|
53
58
|
"devDependencies": {
|
|
54
59
|
"@types/jest": "^29.5.14",
|
|
@@ -59,7 +64,6 @@
|
|
|
59
64
|
"esbuild": "^0.27.3",
|
|
60
65
|
"javascript-obfuscator": "^5.3.0",
|
|
61
66
|
"jest": "^29.7.0",
|
|
62
|
-
"prompts": "^2.4.2",
|
|
63
67
|
"ts-jest": "^29.4.6",
|
|
64
68
|
"typescript": "^5.7.2"
|
|
65
69
|
}
|