@invarn/cibuild 2.7.9 → 2.8.1
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 +143 -10
- package/dist/src/commands/a-properties-stand-in-declares-the-keys-the-build-reads.test.d.ts +2 -0
- package/dist/src/commands/a-properties-stand-in-declares-the-keys-the-build-reads.test.d.ts.map +1 -0
- package/dist/src/commands/a-properties-stand-in-declares-the-keys-the-build-reads.test.js +218 -0
- package/dist/src/commands/android-java-version.test.js +93 -10
- package/dist/src/commands/android-scanner.d.ts +109 -8
- package/dist/src/commands/android-scanner.d.ts.map +1 -1
- package/dist/src/commands/android-scanner.js +397 -27
- package/dist/src/commands/build.d.ts +8 -0
- package/dist/src/commands/build.d.ts.map +1 -1
- package/dist/src/commands/build.js +17 -3
- package/dist/src/commands/index.d.ts +1 -0
- package/dist/src/commands/index.d.ts.map +1 -1
- package/dist/src/commands/index.js +3 -0
- package/dist/src/commands/ios-scanner.d.ts.map +1 -1
- package/dist/src/commands/ios-scanner.js +15 -24
- package/dist/src/commands/ios-scheme-ranking.test.js +5 -0
- package/dist/src/shared/detect-project.d.ts +32 -0
- package/dist/src/shared/detect-project.d.ts.map +1 -1
- package/dist/src/shared/detect-project.js +62 -10
- package/dist/src/shared/xcode-container.test.d.ts +2 -0
- package/dist/src/shared/xcode-container.test.d.ts.map +1 -0
- package/dist/src/shared/xcode-container.test.js +123 -0
- package/dist/src/yaml/steps/xcode-app-product.d.ts +90 -0
- package/dist/src/yaml/steps/xcode-app-product.d.ts.map +1 -0
- package/dist/src/yaml/steps/xcode-app-product.js +247 -0
- package/dist/src/yaml/steps/xcode-app-product.test.d.ts +2 -0
- package/dist/src/yaml/steps/xcode-app-product.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/xcode-app-product.test.js +202 -0
- package/dist/src/yaml/steps/xcode-derived-data.test.js +66 -1
- package/dist/src/yaml/steps/xcode.d.ts.map +1 -1
- package/dist/src/yaml/steps/xcode.js +50 -3
- package/package.json +1 -1
|
@@ -138,6 +138,259 @@ function extractSecretsPropertiesFile(content) {
|
|
|
138
138
|
const m = /propertiesFileName\s*=\s*["']([^"']+)["']/.exec(block);
|
|
139
139
|
return m ? m[1] : "local.properties";
|
|
140
140
|
}
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
// Property keys the build reads out of the Secrets plugin's properties file
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
/**
|
|
145
|
+
* True when this build file *applies* the Secrets plugin, as opposed to merely
|
|
146
|
+
* declaring its version for other modules.
|
|
147
|
+
*
|
|
148
|
+
* A root build file almost always carries
|
|
149
|
+
* `alias(libs.plugins.secrets) apply false` — the plugin is named there so a
|
|
150
|
+
* module can apply it without repeating the version, and the root project
|
|
151
|
+
* itself never loads a properties file. Reading that as "the root module
|
|
152
|
+
* applies it" would aim the source walk below at the whole repository on the
|
|
153
|
+
* strength of a line that applies nothing.
|
|
154
|
+
*
|
|
155
|
+
* Separate from `detectSecretsPlugin` on purpose: that one decides which
|
|
156
|
+
* warnings are emitted, and this must not change them.
|
|
157
|
+
*/
|
|
158
|
+
function appliesSecretsPlugin(content) {
|
|
159
|
+
const applied = content
|
|
160
|
+
.split("\n")
|
|
161
|
+
.filter((line) => !/\bapply\s+false\b/.test(line))
|
|
162
|
+
.join("\n");
|
|
163
|
+
return detectSecretsPlugin(applied);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* The `BuildConfig` fields the Android Gradle Plugin generates by itself.
|
|
167
|
+
*
|
|
168
|
+
* `BuildConfig.DEBUG` is the most-referenced constant in Android source, and
|
|
169
|
+
* every one of these is generated whether or not a properties file exists — so
|
|
170
|
+
* naming them costs more than the unused line the rest of this scan tolerates.
|
|
171
|
+
* A property named `DEBUG` would make the Secrets plugin generate a `String
|
|
172
|
+
* DEBUG` beside AGP's `boolean DEBUG`, and the build that was going to compile
|
|
173
|
+
* stops compiling because of the file meant to rescue it.
|
|
174
|
+
*
|
|
175
|
+
* `FLAVOR_<dimension>` is generated once per flavor dimension, so it is matched
|
|
176
|
+
* by prefix rather than listed.
|
|
177
|
+
*/
|
|
178
|
+
const AGP_GENERATED_BUILD_CONFIG_FIELDS = new Set([
|
|
179
|
+
"DEBUG",
|
|
180
|
+
"APPLICATION_ID",
|
|
181
|
+
"BUILD_TYPE",
|
|
182
|
+
"FLAVOR",
|
|
183
|
+
"VERSION_CODE",
|
|
184
|
+
"VERSION_NAME",
|
|
185
|
+
"LIBRARY_PACKAGE_NAME",
|
|
186
|
+
]);
|
|
187
|
+
function isAgpGeneratedField(name) {
|
|
188
|
+
return AGP_GENERATED_BUILD_CONFIG_FIELDS.has(name) || name.startsWith("FLAVOR_");
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* `BuildConfig.SOME_FIELD` references in a source file.
|
|
192
|
+
*
|
|
193
|
+
* Screaming snake case only: that is the convention for a generated constant,
|
|
194
|
+
* and widening it to any identifier would pull in `BuildConfig.javaClass` and
|
|
195
|
+
* every other member access on the class itself.
|
|
196
|
+
*/
|
|
197
|
+
function extractBuildConfigFieldRefs(content) {
|
|
198
|
+
const names = [];
|
|
199
|
+
const re = /\bBuildConfig\.([A-Z][A-Z0-9_]*)\b/g;
|
|
200
|
+
let m;
|
|
201
|
+
while ((m = re.exec(content)) !== null) {
|
|
202
|
+
if (!isAgpGeneratedField(m[1]))
|
|
203
|
+
names.push(m[1]);
|
|
204
|
+
}
|
|
205
|
+
return names;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* The index of the character closing the bracket or parenthesis at `open`,
|
|
209
|
+
* ignoring anything inside a string literal. -1 when it is never closed.
|
|
210
|
+
*/
|
|
211
|
+
function matchingClose(content, open) {
|
|
212
|
+
const closing = content[open] === "[" ? "]" : ")";
|
|
213
|
+
let depth = 0;
|
|
214
|
+
let quote = "";
|
|
215
|
+
for (let i = open; i < content.length; i++) {
|
|
216
|
+
const ch = content[i];
|
|
217
|
+
if (quote) {
|
|
218
|
+
if (ch === "\\")
|
|
219
|
+
i++;
|
|
220
|
+
else if (ch === quote)
|
|
221
|
+
quote = "";
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
if (ch === '"' || ch === "'")
|
|
225
|
+
quote = ch;
|
|
226
|
+
else if (ch === "[" || ch === "(")
|
|
227
|
+
depth++;
|
|
228
|
+
else if (ch === "]" || ch === ")") {
|
|
229
|
+
depth--;
|
|
230
|
+
if (depth === 0)
|
|
231
|
+
return content[i] === closing ? i : -1;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return -1;
|
|
235
|
+
}
|
|
236
|
+
/** Split a map-literal body on its top-level commas — not ones nested or quoted. */
|
|
237
|
+
function splitTopLevel(body) {
|
|
238
|
+
const parts = [];
|
|
239
|
+
let depth = 0;
|
|
240
|
+
let quote = "";
|
|
241
|
+
let start = 0;
|
|
242
|
+
for (let i = 0; i < body.length; i++) {
|
|
243
|
+
const ch = body[i];
|
|
244
|
+
if (quote) {
|
|
245
|
+
if (ch === "\\")
|
|
246
|
+
i++;
|
|
247
|
+
else if (ch === quote)
|
|
248
|
+
quote = "";
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (ch === '"' || ch === "'")
|
|
252
|
+
quote = ch;
|
|
253
|
+
else if (ch === "[" || ch === "(" || ch === "{")
|
|
254
|
+
depth++;
|
|
255
|
+
else if (ch === "]" || ch === ")" || ch === "}")
|
|
256
|
+
depth--;
|
|
257
|
+
else if (ch === "," && depth === 0) {
|
|
258
|
+
parts.push(body.slice(start, i));
|
|
259
|
+
start = i + 1;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
parts.push(body.slice(start));
|
|
263
|
+
return parts;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* The keys of a map literal, in either language's spelling:
|
|
267
|
+
* Groovy `[key: v, "key": v]`, Kotlin `mapOf("key" to v)`.
|
|
268
|
+
*/
|
|
269
|
+
function mapLiteralKeys(body) {
|
|
270
|
+
const names = [];
|
|
271
|
+
for (const entry of splitTopLevel(body)) {
|
|
272
|
+
const kotlin = /^\s*["']([^"']+)["']\s+to\s/.exec(entry);
|
|
273
|
+
if (kotlin) {
|
|
274
|
+
names.push(kotlin[1]);
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
const groovy = /^\s*(?:["']([^"']+)["']|([A-Za-z_]\w*))\s*:/.exec(entry);
|
|
278
|
+
if (groovy)
|
|
279
|
+
names.push(groovy[1] ?? groovy[2]);
|
|
280
|
+
}
|
|
281
|
+
return names;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Keys named in a `manifestPlaceholders` map in a build file.
|
|
285
|
+
*
|
|
286
|
+
* The Secrets plugin fills a placeholder from the property of the same name,
|
|
287
|
+
* so a placeholder the build declares is a property the build reads. Every
|
|
288
|
+
* spelling the two DSLs offer for the same map:
|
|
289
|
+
*
|
|
290
|
+
* manifestPlaceholders["mapsApiKey"] = … // both
|
|
291
|
+
* manifestPlaceholders.put("mapsApiKey", …) // Groovy
|
|
292
|
+
* manifestPlaceholders = [mapsApiKey: …] // Groovy
|
|
293
|
+
* manifestPlaceholders += mapOf("mapsApiKey" to …) // Kotlin
|
|
294
|
+
*/
|
|
295
|
+
function extractManifestPlaceholderKeys(content) {
|
|
296
|
+
const names = [];
|
|
297
|
+
for (const re of [
|
|
298
|
+
/manifestPlaceholders\s*\[\s*["']([^"']+)["']\s*\]/g,
|
|
299
|
+
/manifestPlaceholders\s*\.\s*put\s*\(\s*["']([^"']+)["']/g,
|
|
300
|
+
]) {
|
|
301
|
+
let m;
|
|
302
|
+
while ((m = re.exec(content)) !== null)
|
|
303
|
+
names.push(m[1]);
|
|
304
|
+
}
|
|
305
|
+
// A whole map assigned, added or put at once. The opening bracket the regex
|
|
306
|
+
// ends on is where the literal starts; its match is where it ends.
|
|
307
|
+
const assigned = /manifestPlaceholders\s*(?:\.\s*putAll\s*\(\s*)?(?:\+?=\s*)?(?:mapOf\s*|mutableMapOf\s*)?[[(]/g;
|
|
308
|
+
let m;
|
|
309
|
+
while ((m = assigned.exec(content)) !== null) {
|
|
310
|
+
const open = m.index + m[0].length - 1;
|
|
311
|
+
const close = matchingClose(content, open);
|
|
312
|
+
if (close === -1)
|
|
313
|
+
continue;
|
|
314
|
+
names.push(...mapLiteralKeys(content.slice(open + 1, close)));
|
|
315
|
+
assigned.lastIndex = close;
|
|
316
|
+
}
|
|
317
|
+
return names;
|
|
318
|
+
}
|
|
319
|
+
// Bounds on the source walk, the way `findGradleFiles` bounds itself to the
|
|
320
|
+
// files a build actually declares. A repository is an unbounded tree and this
|
|
321
|
+
// runs on every scan of one.
|
|
322
|
+
const SOURCE_EXTENSIONS = [".kt", ".kts", ".java"];
|
|
323
|
+
const SOURCE_SKIP_DIRS = new Set(["build", "node_modules"]);
|
|
324
|
+
const SOURCE_FILE_CAP = 1500;
|
|
325
|
+
const SOURCE_DEPTH_CAP = 12;
|
|
326
|
+
/** Source files under `dir`, up to the shared file budget. */
|
|
327
|
+
function findSourceFiles(dir, budget, depth = 0) {
|
|
328
|
+
if (depth > SOURCE_DEPTH_CAP || budget.left <= 0)
|
|
329
|
+
return [];
|
|
330
|
+
let entries;
|
|
331
|
+
try {
|
|
332
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
return [];
|
|
336
|
+
}
|
|
337
|
+
const files = [];
|
|
338
|
+
const subdirs = [];
|
|
339
|
+
for (const entry of entries) {
|
|
340
|
+
// Dot directories hold caches and VCS state, never source: `.git`,
|
|
341
|
+
// `.gradle`, `.idea`, `.kotlin`.
|
|
342
|
+
if (entry.name.startsWith("."))
|
|
343
|
+
continue;
|
|
344
|
+
if (entry.isDirectory()) {
|
|
345
|
+
if (!SOURCE_SKIP_DIRS.has(entry.name))
|
|
346
|
+
subdirs.push(join(dir, entry.name));
|
|
347
|
+
}
|
|
348
|
+
else if (SOURCE_EXTENSIONS.some((ext) => entry.name.endsWith(ext))) {
|
|
349
|
+
if (budget.left <= 0)
|
|
350
|
+
break;
|
|
351
|
+
budget.left--;
|
|
352
|
+
files.push(join(dir, entry.name));
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
for (const sub of subdirs)
|
|
356
|
+
files.push(...findSourceFiles(sub, budget, depth + 1));
|
|
357
|
+
return files;
|
|
358
|
+
}
|
|
359
|
+
/** The directories of `dirs` that no other member of `dirs` contains. */
|
|
360
|
+
function outermost(dirs) {
|
|
361
|
+
return dirs.filter((dir) => !dirs.some((other) => other !== dir && dir.startsWith(other + "/")));
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* The property names the build reads out of the Secrets plugin's properties
|
|
365
|
+
* file — see `ScanResult.missingPropertyKeys`.
|
|
366
|
+
*
|
|
367
|
+
* Bounded to the modules that apply the plugin, because that is where its
|
|
368
|
+
* generated fields are visible and where the references to them live.
|
|
369
|
+
*/
|
|
370
|
+
function collectPropertyKeys(gradleFiles) {
|
|
371
|
+
// A module with both a `build.gradle` and a `build.gradle.kts` yields its
|
|
372
|
+
// directory twice, and walking it twice would spend the file budget twice.
|
|
373
|
+
const moduleDirs = new Set();
|
|
374
|
+
const keys = new Set();
|
|
375
|
+
for (const filePath of gradleFiles) {
|
|
376
|
+
const content = safeRead(filePath);
|
|
377
|
+
if (!appliesSecretsPlugin(content))
|
|
378
|
+
continue;
|
|
379
|
+
moduleDirs.add(dirname(filePath));
|
|
380
|
+
for (const key of extractManifestPlaceholderKeys(content))
|
|
381
|
+
keys.add(key);
|
|
382
|
+
}
|
|
383
|
+
if (moduleDirs.size === 0)
|
|
384
|
+
return [];
|
|
385
|
+
const budget = { left: SOURCE_FILE_CAP };
|
|
386
|
+
for (const dir of outermost([...moduleDirs])) {
|
|
387
|
+
for (const file of findSourceFiles(dir, budget)) {
|
|
388
|
+
for (const name of extractBuildConfigFieldRefs(safeRead(file)))
|
|
389
|
+
keys.add(name);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return [...keys].sort();
|
|
393
|
+
}
|
|
141
394
|
/** Parse property keys from a standard .properties file, skipping comments and blank lines. */
|
|
142
395
|
function parsePropertyKeys(propertiesContent) {
|
|
143
396
|
return propertiesContent
|
|
@@ -518,12 +771,87 @@ export function gradleJavaFloor(gradleVersion) {
|
|
|
518
771
|
*/
|
|
519
772
|
export const AVAILABLE_JAVA_VERSIONS = [8, 11, 17, 21, 25];
|
|
520
773
|
/**
|
|
521
|
-
* The newest JDK a build machine carries.
|
|
522
|
-
*
|
|
523
|
-
*
|
|
524
|
-
*
|
|
774
|
+
* The newest JDK a build machine carries.
|
|
775
|
+
*
|
|
776
|
+
* It is no longer what the chooser falls back to. It used to be: with no JDK
|
|
777
|
+
* satisfying both the sources and the wrapper, `runnableJavaVersion` returned
|
|
778
|
+
* this — which on a project pinning a modern Java level under an old Gradle
|
|
779
|
+
* wrapper is a JDK **above** that wrapper's ceiling, and the build dies at
|
|
780
|
+
* `:app:processDebugMainManifest` with "module java.base does not opens
|
|
781
|
+
* java.io to unnamed module". A number above the ceiling is not a fallback;
|
|
782
|
+
* it is the failure, chosen deliberately and reported as success.
|
|
525
783
|
*/
|
|
526
784
|
export const NEWEST_AVAILABLE_JAVA_VERSION = Math.max(...AVAILABLE_JAVA_VERSIONS);
|
|
785
|
+
/**
|
|
786
|
+
* The JDK to build on, with the reason attached — one place where the
|
|
787
|
+
* constraints are resolved, so the answer and the explanation cannot disagree.
|
|
788
|
+
*
|
|
789
|
+
* They used to. The chooser fell back to the newest installed JDK whenever
|
|
790
|
+
* nothing satisfied both constraints, and the sentence beside it had two
|
|
791
|
+
* branches — a ceiling below every installed JDK, and a declaration above
|
|
792
|
+
* every installed JDK — so the commonest shape of all fell through both and
|
|
793
|
+
* said nothing at all. A project pinning Java 12 against a Gradle wrapper that
|
|
794
|
+
* runs on 11 at most got Java 25 and silence.
|
|
795
|
+
*
|
|
796
|
+
* Three facts decide it:
|
|
797
|
+
*
|
|
798
|
+
* - **What the build machine has.** Only `AVAILABLE_JAVA_VERSIONS` exist, so
|
|
799
|
+
* a project declaring 30 cannot simply be given 30.
|
|
800
|
+
* - **What Gradle can run on.** The wrapper sets a ceiling that source
|
|
801
|
+
* compatibility cannot raise: Gradle starts before it reads a single
|
|
802
|
+
* `sourceCompatibility`.
|
|
803
|
+
* - **What the sources ask for.** A declaration is a floor, not an exact
|
|
804
|
+
* request — a project declaring 11 compiles fine on 21.
|
|
805
|
+
*
|
|
806
|
+
* `kind` distinguishes the five outcomes:
|
|
807
|
+
*
|
|
808
|
+
* - `unknown` — nothing declared and no readable wrapper. Nothing to go on
|
|
809
|
+
* and nothing to say.
|
|
810
|
+
* - `satisfies` — an installed JDK meets both the floor and the ceiling.
|
|
811
|
+
* - `capped-by-wrapper` — nothing meets both, and the wrapper is why. The
|
|
812
|
+
* ceiling is hard and the declaration is a preference, so the newest JDK
|
|
813
|
+
* the wrapper *can* run is the answer, and the caller says so.
|
|
814
|
+
* - `above-runners` — the declaration is above every installed JDK, and that
|
|
815
|
+
* rather than the wrapper is what binds. **No answer**: asking for it would
|
|
816
|
+
* fail when the JDK is selected, and quietly picking a lower one would be
|
|
817
|
+
* the guess this exists to avoid.
|
|
818
|
+
* - `wrapper-below-runners` — the ceiling is below every installed JDK. No
|
|
819
|
+
* answer exists.
|
|
820
|
+
*
|
|
821
|
+
* `above-runners` is checked before `capped-by-wrapper` so a project declaring
|
|
822
|
+
* 99 against a modern wrapper is told about the machines rather than about its
|
|
823
|
+
* wrapper: both bind, and the one it can act on is the one worth naming.
|
|
824
|
+
*/
|
|
825
|
+
export function chooseJavaVersion(detectedJavaVersion, gradleVersion) {
|
|
826
|
+
const declared = Number(detectedJavaVersion) || 0;
|
|
827
|
+
const ceiling = gradleJavaCeiling(gradleVersion);
|
|
828
|
+
const floor = gradleJavaFloor(gradleVersion);
|
|
829
|
+
const installed = [...AVAILABLE_JAVA_VERSIONS].sort((a, b) => a - b);
|
|
830
|
+
const base = { declared, ceiling, installed };
|
|
831
|
+
if (!declared && floor === undefined) {
|
|
832
|
+
return { ...base, version: undefined, kind: "unknown" };
|
|
833
|
+
}
|
|
834
|
+
const wanted = Math.max(declared, floor ?? 0);
|
|
835
|
+
const usable = installed.filter((v) => v >= wanted && v <= (ceiling ?? Infinity));
|
|
836
|
+
// The newest that fits. Nothing reaches the oldest installed JDK unless a
|
|
837
|
+
// ceiling leaves nothing else, which is the only reason 8 and 11 are on the
|
|
838
|
+
// images at all.
|
|
839
|
+
if (usable.length > 0) {
|
|
840
|
+
return { ...base, version: usable[usable.length - 1], kind: "satisfies" };
|
|
841
|
+
}
|
|
842
|
+
if (declared > installed[installed.length - 1]) {
|
|
843
|
+
return { ...base, version: undefined, kind: "above-runners" };
|
|
844
|
+
}
|
|
845
|
+
const underCeiling = installed.filter((v) => v <= (ceiling ?? Infinity));
|
|
846
|
+
if (underCeiling.length > 0) {
|
|
847
|
+
return {
|
|
848
|
+
...base,
|
|
849
|
+
version: underCeiling[underCeiling.length - 1],
|
|
850
|
+
kind: "capped-by-wrapper",
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
return { ...base, version: undefined, kind: "wrapper-below-runners" };
|
|
854
|
+
}
|
|
527
855
|
/**
|
|
528
856
|
* The Java version to write into a generated pipeline: the **newest**
|
|
529
857
|
* available JDK that satisfies both what the sources declare and what the
|
|
@@ -542,34 +870,44 @@ export const NEWEST_AVAILABLE_JAVA_VERSION = Math.max(...AVAILABLE_JAVA_VERSIONS
|
|
|
542
870
|
* above had to learn minor versions before this could ship.
|
|
543
871
|
*/
|
|
544
872
|
export function runnableJavaVersion(detectedJavaVersion, gradleVersion) {
|
|
545
|
-
|
|
546
|
-
const floor = Math.max(detectedJavaVersion ?? 0, gradleJavaFloor(gradleVersion) ?? 0);
|
|
547
|
-
const usable = AVAILABLE_JAVA_VERSIONS.filter((v) => v >= floor && v <= ceiling).sort((a, b) => a - b);
|
|
548
|
-
if (usable.length === 0)
|
|
549
|
-
return NEWEST_AVAILABLE_JAVA_VERSION;
|
|
550
|
-
return usable[usable.length - 1];
|
|
873
|
+
return chooseJavaVersion(detectedJavaVersion, gradleVersion).version;
|
|
551
874
|
}
|
|
552
875
|
/**
|
|
553
|
-
* What
|
|
554
|
-
*
|
|
876
|
+
* What the choice could not honour, as a sentence, or undefined when it
|
|
877
|
+
* honoured everything.
|
|
878
|
+
*
|
|
879
|
+
* Silence is the failure this exists to prevent: a pipeline that quietly
|
|
880
|
+
* overruled what a project asked for reads as the project's own problem, and
|
|
881
|
+
* the commonest shape of all — an old wrapper under a modern declaration — was
|
|
882
|
+
* the one that used to fall through every branch.
|
|
883
|
+
*
|
|
884
|
+
* `source` names the file that asked, when the caller knows it. The scan now
|
|
885
|
+
* returns it, so "asks for Java 12" can become "asks for Java 12
|
|
886
|
+
* (.github/workflows/Build.yml)" — a version with no provenance sends a reader
|
|
887
|
+
* looking through every Gradle file for a number that is not in any of them.
|
|
555
888
|
*/
|
|
556
|
-
export function javaVersionProblem(detectedJavaVersion, gradleVersion) {
|
|
889
|
+
export function javaVersionProblem(detectedJavaVersion, gradleVersion, source) {
|
|
890
|
+
const choice = chooseJavaVersion(detectedJavaVersion, gradleVersion);
|
|
891
|
+
if (choice.kind === "satisfies" || choice.kind === "unknown")
|
|
892
|
+
return undefined;
|
|
893
|
+
const { declared, ceiling, installed } = choice;
|
|
557
894
|
// "11, 17 and 21", not "11 and 17 and 21" — a human reads this next to a
|
|
558
895
|
// build that will not start.
|
|
559
|
-
const
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
if (ceiling !== undefined && ceiling < lowest) {
|
|
566
|
-
return `Gradle ${gradleVersion} runs on Java ${ceiling} at most, and build machines carry only ${installed}. This pipeline will very likely fail before it compiles anything — upgrade the Gradle wrapper.`;
|
|
896
|
+
const list = installed.length > 1
|
|
897
|
+
? `${installed.slice(0, -1).join(", ")} and ${installed[installed.length - 1]}`
|
|
898
|
+
: String(installed[0]);
|
|
899
|
+
const asked = source ? `Java ${declared} (${source})` : `Java ${declared}`;
|
|
900
|
+
if (choice.kind === "wrapper-below-runners") {
|
|
901
|
+
return `Gradle ${gradleVersion} runs on Java ${ceiling} at most, and build machines carry only ${list}. This pipeline will very likely fail before it compiles anything — upgrade the Gradle wrapper.`;
|
|
567
902
|
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
return `This project declares Java ${detectedJavaVersion}, and build machines carry only ${installed}. Writing Java ${runnableJavaVersion(detectedJavaVersion, gradleVersion)} instead — asking for ${detectedJavaVersion} would fail at "Set the Java version".`;
|
|
903
|
+
if (choice.kind === "above-runners") {
|
|
904
|
+
return `This project declares Java ${declared}, and build machines carry only ${list}. Leaving JAVA_VERSION at the pipeline default — asking for ${declared} would fail at "Set the Java version", and quietly choosing a lower one would be a guess.`;
|
|
571
905
|
}
|
|
572
|
-
|
|
906
|
+
// capped-by-wrapper
|
|
907
|
+
const preamble = declared
|
|
908
|
+
? `This project asks for ${asked}, and Gradle ${gradleVersion} runs on Java ${ceiling} at most.`
|
|
909
|
+
: `Gradle ${gradleVersion} runs on Java ${ceiling} at most.`;
|
|
910
|
+
return `${preamble} Building on ${choice.version} — the newest the wrapper allows.`;
|
|
573
911
|
}
|
|
574
912
|
// ---------------------------------------------------------------------------
|
|
575
913
|
// Gitignore helper
|
|
@@ -817,6 +1155,12 @@ export async function scanAndroidProject(projectRoot) {
|
|
|
817
1155
|
const detectedJavaVersion = declaredJavaVersion === undefined && pinnedJava === undefined
|
|
818
1156
|
? undefined
|
|
819
1157
|
: Math.max(declaredJavaVersion ?? 0, pinnedJava?.version ?? 0);
|
|
1158
|
+
// Only when the pin is what set the level. A Gradle file asking for as much
|
|
1159
|
+
// or more is the thing a reader would find by looking, so naming the
|
|
1160
|
+
// workflow there would point away from the answer.
|
|
1161
|
+
const detectedJavaVersionSource = pinnedJava !== undefined && pinnedJava.version > (declaredJavaVersion ?? 0)
|
|
1162
|
+
? pinnedJava.source
|
|
1163
|
+
: undefined;
|
|
820
1164
|
const detectedGradleVersion = detectGradleWrapperVersion(projectRoot);
|
|
821
1165
|
const buildVariants = detectBuildVariants(gradleFiles);
|
|
822
1166
|
// ------------------------------------------------------------------
|
|
@@ -979,6 +1323,16 @@ export async function scanAndroidProject(projectRoot) {
|
|
|
979
1323
|
}
|
|
980
1324
|
}
|
|
981
1325
|
// ------------------------------------------------------------------
|
|
1326
|
+
// 4b. Which keys that properties file has to declare
|
|
1327
|
+
// ------------------------------------------------------------------
|
|
1328
|
+
//
|
|
1329
|
+
// Section 4 says the file is absent; this says what is in it. The two are
|
|
1330
|
+
// separate because they answer different questions for different readers —
|
|
1331
|
+
// the warnings above tell a person a file is missing, and this tells a
|
|
1332
|
+
// generator what a stand-in for it has to contain.
|
|
1333
|
+
// ------------------------------------------------------------------
|
|
1334
|
+
const missingPropertyKeys = collectPropertyKeys(gradleFiles);
|
|
1335
|
+
// ------------------------------------------------------------------
|
|
982
1336
|
// 5. Firebase / GMS — check google-services.json after scanning all files
|
|
983
1337
|
// ------------------------------------------------------------------
|
|
984
1338
|
if (gmsDetected) {
|
|
@@ -1024,7 +1378,14 @@ export async function scanAndroidProject(projectRoot) {
|
|
|
1024
1378
|
});
|
|
1025
1379
|
}
|
|
1026
1380
|
}
|
|
1027
|
-
return {
|
|
1381
|
+
return {
|
|
1382
|
+
warnings,
|
|
1383
|
+
detectedJavaVersion,
|
|
1384
|
+
detectedJavaVersionSource,
|
|
1385
|
+
detectedGradleVersion,
|
|
1386
|
+
buildVariants,
|
|
1387
|
+
missingPropertyKeys,
|
|
1388
|
+
};
|
|
1028
1389
|
}
|
|
1029
1390
|
// ---------------------------------------------------------------------------
|
|
1030
1391
|
// Formatter
|
|
@@ -1045,9 +1406,18 @@ export function formatScanResult(result) {
|
|
|
1045
1406
|
// actually name — they differ whenever the declaration is below the oldest
|
|
1046
1407
|
// installed JDK or above the newest, and saying only the first made the
|
|
1047
1408
|
// second look like it had been honoured.
|
|
1409
|
+
//
|
|
1410
|
+
// And when they differ, say why in the same breath. An answer that is not
|
|
1411
|
+
// what was asked for, printed with no reason, reads as a fact about the
|
|
1412
|
+
// project rather than as a decision made on its behalf.
|
|
1048
1413
|
if (result.detectedJavaVersion !== undefined) {
|
|
1049
1414
|
const willUse = runnableJavaVersion(result.detectedJavaVersion, result.detectedGradleVersion);
|
|
1050
|
-
lines.push(
|
|
1415
|
+
lines.push(willUse === undefined
|
|
1416
|
+
? `ℹ Detected Java ${result.detectedJavaVersion} requirement — no installed JDK can satisfy it`
|
|
1417
|
+
: `ℹ Detected Java ${result.detectedJavaVersion} requirement — pipeline will use Java ${willUse}`);
|
|
1418
|
+
const problem = javaVersionProblem(result.detectedJavaVersion, result.detectedGradleVersion, result.detectedJavaVersionSource);
|
|
1419
|
+
if (problem)
|
|
1420
|
+
lines.push(` ${problem}`);
|
|
1051
1421
|
lines.push("");
|
|
1052
1422
|
}
|
|
1053
1423
|
if (result.warnings.length === 0) {
|
|
@@ -197,6 +197,14 @@ export declare function detectSetupNeeds(warnings: BuildWarning[]): Omit<SetupOp
|
|
|
197
197
|
* and a webhook must never reach it.
|
|
198
198
|
*/
|
|
199
199
|
export declare function triggerMapBlock(defaultBranch?: string): string;
|
|
200
|
+
/**
|
|
201
|
+
* The JDK a generated pipeline names when the project's own constraints have
|
|
202
|
+
* no answer — nothing declared and no readable wrapper, or a declaration no
|
|
203
|
+
* installed JDK can meet. A generated pipeline has to write something; what it
|
|
204
|
+
* must not do is write a number the wrapper cannot start on and call that a
|
|
205
|
+
* choice.
|
|
206
|
+
*/
|
|
207
|
+
export declare const DEFAULT_PIPELINE_JAVA_VERSION = 17;
|
|
200
208
|
export declare function generateAndroidPipeline(javaVersion?: number, setup?: SetupOptions, variants?: WorkflowVariants, cacheTechnology?: "gradle" | "kmm", metaNamespace?: 'invarn' | 'cibuild.io', defaultBranch?: string): string;
|
|
201
209
|
export declare function generateIosPipeline(projectPath: string, setup: IosSetupOptions, variants: IosWorkflowVariants, metaNamespace?: 'invarn' | 'cibuild.io', defaultBranch?: string): string;
|
|
202
210
|
export declare function handleBuildCommand(detectMobileProjectRoot: (dir: string) => "android" | "ios" | "kmm" | null, options?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/commands/build.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/commands/build.ts"],"names":[],"mappings":"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"}
|
|
@@ -326,7 +326,15 @@ trigger_map:
|
|
|
326
326
|
workflow: pull-request
|
|
327
327
|
`;
|
|
328
328
|
}
|
|
329
|
-
|
|
329
|
+
/**
|
|
330
|
+
* The JDK a generated pipeline names when the project's own constraints have
|
|
331
|
+
* no answer — nothing declared and no readable wrapper, or a declaration no
|
|
332
|
+
* installed JDK can meet. A generated pipeline has to write something; what it
|
|
333
|
+
* must not do is write a number the wrapper cannot start on and call that a
|
|
334
|
+
* choice.
|
|
335
|
+
*/
|
|
336
|
+
export const DEFAULT_PIPELINE_JAVA_VERSION = 17;
|
|
337
|
+
export function generateAndroidPipeline(javaVersion = DEFAULT_PIPELINE_JAVA_VERSION, setup = { keystore: false, keystoreProperties: false, googleServices: false, googlePlayDeploy: false, googlePlayPackageName: '', artifactType: 'apk', keystorePaths: {}, googleServicesPaths: {}, workflowFlavors: {}, secretsProperties: false, secretsPropertiesPath: 'local.properties' }, variants = DEFAULT_VARIANTS, cacheTechnology = "gradle", metaNamespace = 'cibuild.io', defaultBranch = FALLBACK_DEFAULT_BRANCH) {
|
|
330
338
|
const keystoreStepFor = (wf) => {
|
|
331
339
|
if (!setup.keystore)
|
|
332
340
|
return "";
|
|
@@ -1370,11 +1378,17 @@ async function handleAndroidBuildCommand(cwd, options, cacheTechnology) {
|
|
|
1370
1378
|
}
|
|
1371
1379
|
}
|
|
1372
1380
|
// 7. Generate and write the pipeline
|
|
1381
|
+
//
|
|
1382
|
+
// The chooser abstains rather than falling back, so `undefined` here means
|
|
1383
|
+
// "no installed JDK meets this project's constraints" — not "17 is fine".
|
|
1384
|
+
// The default is what gets written in that case, and the warning below is
|
|
1385
|
+
// what says so; it is never silent when the answer is not what was asked
|
|
1386
|
+
// for, which is the whole reason the two are resolved together.
|
|
1373
1387
|
const javaVersion = runnableJavaVersion(scanResult.detectedJavaVersion, scanResult.detectedGradleVersion);
|
|
1374
|
-
const javaProblem = javaVersionProblem(scanResult.detectedJavaVersion, scanResult.detectedGradleVersion);
|
|
1388
|
+
const javaProblem = javaVersionProblem(scanResult.detectedJavaVersion, scanResult.detectedGradleVersion, scanResult.detectedJavaVersionSource);
|
|
1375
1389
|
if (javaProblem)
|
|
1376
1390
|
console.log(`\n⚠️ ${javaProblem}`);
|
|
1377
|
-
const yaml = generateAndroidPipeline(javaVersion, setupOptions, variants, cacheTechnology, options.metaNamespace, detectDefaultBranch());
|
|
1391
|
+
const yaml = generateAndroidPipeline(javaVersion ?? DEFAULT_PIPELINE_JAVA_VERSION, setupOptions, variants, cacheTechnology, options.metaNamespace, detectDefaultBranch());
|
|
1378
1392
|
writeFileSync(outputPath, yaml, "utf-8");
|
|
1379
1393
|
console.log("\n✅ Generated .ci/pipelines/cibuild.yml");
|
|
1380
1394
|
console.log(` Platform: ${platformLabel}`);
|
|
@@ -23,6 +23,7 @@ export { handleBuildCommand } from "./build.js";
|
|
|
23
23
|
export { handleResetCommand } from "./reset.js";
|
|
24
24
|
export { detectMobileProjectRoot } from "../shared/detect-project.js";
|
|
25
25
|
export type { MobileProjectType } from "../shared/detect-project.js";
|
|
26
|
+
export { isXcodeContainer, xcodeContainersIn } from "../shared/detect-project.js";
|
|
26
27
|
export { scanIosProject, formatIosScanResult } from "./ios-scanner.js";
|
|
27
28
|
export type { IosScanResult, IosWarning, IosWarningCategory, IosWarningSeverity, } from "./ios-scanner.js";
|
|
28
29
|
export { scanAndroidProject, formatScanResult, detectBuildVariants, } from "./android-scanner.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAEjE,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,YAAY,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAElE,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGhD,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,YAAY,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAEjE,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,YAAY,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAElE,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGhD,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,YAAY,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAGrE,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAOlF,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvE,YAAY,EACV,aAAa,EACb,UAAU,EACV,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,UAAU,IAAI,iBAAiB,EAC/B,aAAa,EACb,YAAY,EACZ,eAAe,EACf,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACjF,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,aAAa,GACd,MAAM,4BAA4B,CAAC"}
|
|
@@ -19,6 +19,9 @@ export { handleBuildCommand } from "./build.js";
|
|
|
19
19
|
export { handleResetCommand } from "./reset.js";
|
|
20
20
|
// Helpers useful for callers that implement their own variations.
|
|
21
21
|
export { detectMobileProjectRoot } from "../shared/detect-project.js";
|
|
22
|
+
// The one answer to "is this `.xcodeproj` a project", exported so the Invarn
|
|
23
|
+
// CLI's own scans cannot drift from cibuild's.
|
|
24
|
+
export { isXcodeContainer, xcodeContainersIn } from "../shared/detect-project.js";
|
|
22
25
|
// Project scanners — pure, toolchain-free file-content detectors. Exposed
|
|
23
26
|
// so external callers (the Invarn CLI) can detect build variables and
|
|
24
27
|
// secret-bearing files from a checkout and push them to the backend,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ios-scanner.d.ts","sourceRoot":"","sources":["../../../src/commands/ios-scanner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ios-scanner.d.ts","sourceRoot":"","sources":["../../../src/commands/ios-scanner.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,kBAAkB,GAAG,cAAc,GAAG,SAAS,GAAG,gBAAgB,GAAG,WAAW,CAAC;AAE7F,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB;;;OAGG;IACH,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,uEAAuE;IACvE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oDAAoD;IACpD,YAAY,EAAE,OAAO,CAAC;IACtB,0DAA0D;IAC1D,MAAM,EAAE,OAAO,CAAC;IAChB,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iFAAiF;IACjF,eAAe,EAAE,MAAM,CAAC;CACzB;AAiFD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EAAE,GAChB,MAAM,EAAE,CAEV;AAED,iEAAiE;AACjE,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EAAE,GAChB;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CA8CxC;AAkLD,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAgGhF;AAaD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAkDjE"}
|