@celilo/cli 5.2.0 → 5.2.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/package.json
CHANGED
|
@@ -345,12 +345,6 @@ export const CAPABILITY_NAME_BASELINE: readonly CapabilityNameRow[] = [
|
|
|
345
345
|
count: 1,
|
|
346
346
|
why: 'S13 — ZONE_REQUIREMENTS, a second hand-maintained copy of well-known.ts; Phase 2 (#937)',
|
|
347
347
|
},
|
|
348
|
-
{
|
|
349
|
-
file: 'apps/celilo/src/templates/generator.ts',
|
|
350
|
-
capability: 'dns_internal',
|
|
351
|
-
count: 1,
|
|
352
|
-
why: 'X4 — declaration-driven and the model for the rest; only the error string names the capability (#945)',
|
|
353
|
-
},
|
|
354
348
|
{
|
|
355
349
|
file: 'apps/celilo/src/variables/context.ts',
|
|
356
350
|
capability: 'dns_internal',
|
|
@@ -21,9 +21,9 @@ import { tmpdir } from 'node:os';
|
|
|
21
21
|
import { join } from 'node:path';
|
|
22
22
|
import { copyAnsibleRoleFilesDirs } from './generator';
|
|
23
23
|
|
|
24
|
-
function moduleWithRoleFile(binary: string): string {
|
|
24
|
+
function moduleWithRoleFile(binary: string, layout = 'ansible'): string {
|
|
25
25
|
const root = mkdtempSync(join(tmpdir(), 'celilo-rolefiles-'));
|
|
26
|
-
const filesDir = join(root,
|
|
26
|
+
const filesDir = join(root, layout, 'roles', 'demo', 'files');
|
|
27
27
|
mkdirSync(filesDir, { recursive: true });
|
|
28
28
|
writeFileSync(join(filesDir, 'demo-linux-x86_64'), binary);
|
|
29
29
|
return root;
|
|
@@ -59,6 +59,24 @@ describe('copyAnsibleRoleFilesDirs', () => {
|
|
|
59
59
|
expect(generatedBinary(outputPath)).toBe('v2');
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* celilo#1461. The template pipeline accepts BOTH `ansible/` and
|
|
64
|
+
* `celilo/ansible/`; this copy accepted one, so a celilo/-layout module got
|
|
65
|
+
* its role's tasks/ and templates/ and never its files/. `existsSync` was
|
|
66
|
+
* false, the function returned, and nothing anywhere said so.
|
|
67
|
+
*
|
|
68
|
+
* Generated output is the standard layout either way — the source layout is
|
|
69
|
+
* what varies.
|
|
70
|
+
*/
|
|
71
|
+
test('finds role files/ under the celilo/ layout too', async () => {
|
|
72
|
+
const modulePath = moduleWithRoleFile('v1', 'celilo/ansible');
|
|
73
|
+
const outputPath = mkdtempSync(join(tmpdir(), 'celilo-out-'));
|
|
74
|
+
|
|
75
|
+
await copyAnsibleRoleFilesDirs(modulePath, outputPath);
|
|
76
|
+
|
|
77
|
+
expect(generatedBinary(outputPath)).toBe('v1');
|
|
78
|
+
});
|
|
79
|
+
|
|
62
80
|
test('a module with no role files/ directory is not an error', async () => {
|
|
63
81
|
const root = mkdtempSync(join(tmpdir(), 'celilo-norole-'));
|
|
64
82
|
mkdirSync(join(root, 'ansible', 'roles', 'demo', 'tasks'), { recursive: true });
|
|
@@ -60,9 +60,18 @@ const COPY_AS_IS_EXTENSIONS = ['.yml', '.yaml', '.tf'];
|
|
|
60
60
|
/**
|
|
61
61
|
* Template directories to process
|
|
62
62
|
*/
|
|
63
|
+
// A module may keep its deployment tree at the root or under `celilo/`.
|
|
64
|
+
// This is THE list of supported layouts — everything that has to find a
|
|
65
|
+
// module's ansible/ or terraform/ derives it from here. celilo#1461 was two
|
|
66
|
+
// functions deciding that independently and disagreeing.
|
|
67
|
+
const LAYOUT_ROOTS = ['', 'celilo'];
|
|
68
|
+
|
|
69
|
+
const layoutDirs = (name: string): string[] =>
|
|
70
|
+
LAYOUT_ROOTS.map((root) => (root ? `${root}/${name}` : name));
|
|
71
|
+
|
|
63
72
|
// Directories to scan for template files. Supports both root-level and
|
|
64
73
|
// celilo/ subdirectory layouts (e.g., ansible/ or celilo/ansible/).
|
|
65
|
-
const TEMPLATE_DIRS = ['terraform', 'ansible'
|
|
74
|
+
const TEMPLATE_DIRS = [...layoutDirs('terraform'), ...layoutDirs('ansible')];
|
|
66
75
|
|
|
67
76
|
/**
|
|
68
77
|
* Check if file is a template that needs variable resolution
|
|
@@ -513,8 +522,9 @@ export async function readTemplateFiles(
|
|
|
513
522
|
* @param files - Generated files to write
|
|
514
523
|
*/
|
|
515
524
|
/**
|
|
516
|
-
* Copy each
|
|
517
|
-
* to the generated output, verbatim (preserving binary content + mode
|
|
525
|
+
* Copy each `<layout>/ansible/roles/<role>/files/` directory from the module
|
|
526
|
+
* source to the generated output, verbatim (preserving binary content + mode
|
|
527
|
+
* bits). Both supported layouts are scanned — see LAYOUT_ROOTS.
|
|
518
528
|
*
|
|
519
529
|
* These hold Ansible role-local static assets — they may be binaries and
|
|
520
530
|
* don't need template variable resolution, so the standard template
|
|
@@ -524,38 +534,49 @@ export async function copyAnsibleRoleFilesDirs(
|
|
|
524
534
|
modulePath: string,
|
|
525
535
|
outputPath: string,
|
|
526
536
|
): Promise<void> {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
537
|
+
let copied = 0;
|
|
538
|
+
for (const ansibleDir of layoutDirs('ansible')) {
|
|
539
|
+
const rolesDir = join(modulePath, ansibleDir, 'roles');
|
|
540
|
+
if (!existsSync(rolesDir)) continue;
|
|
541
|
+
const roles = await readdir(rolesDir, { withFileTypes: true });
|
|
542
|
+
for (const role of roles) {
|
|
543
|
+
if (!role.isDirectory()) continue;
|
|
544
|
+
const srcFilesDir = join(rolesDir, role.name, 'files');
|
|
545
|
+
if (!existsSync(srcFilesDir)) continue;
|
|
546
|
+
const destFilesDir = join(outputPath, 'ansible', 'roles', role.name, 'files');
|
|
547
|
+
await mkdir(dirname(destFilesDir), { recursive: true });
|
|
548
|
+
// `force: true` is LOAD-BEARING on bun, and its absence was celilo#925.
|
|
549
|
+
//
|
|
550
|
+
// Node defaults `force` to true, so this looked correct and is correct
|
|
551
|
+
// under Node. Bun 1.3.3 does not, on this path specifically — measured,
|
|
552
|
+
// copying "NEW" over an existing "OLD":
|
|
553
|
+
//
|
|
554
|
+
// recursive only -> NEW
|
|
555
|
+
// recursive + force -> NEW
|
|
556
|
+
// recursive + preserveTimestamps -> OLD <- what this was
|
|
557
|
+
// recursive + force + preserveTimestamps -> NEW
|
|
558
|
+
//
|
|
559
|
+
// celilo runs on bun. So a module's built binary landed in `generated/`
|
|
560
|
+
// exactly once, at first generate, and no later version ever replaced it —
|
|
561
|
+
// silently, because `cp` reports no error, so the caller's try/catch has
|
|
562
|
+
// nothing to catch. Ansible then copies that first binary forever and
|
|
563
|
+
// reports `ok`, unchanged, while the module's version field advances.
|
|
564
|
+
//
|
|
565
|
+
// The sibling call in `storage-set-path.ts:153` already passes `force`.
|
|
566
|
+
await cp(srcFilesDir, destFilesDir, {
|
|
567
|
+
recursive: true,
|
|
568
|
+
force: true,
|
|
569
|
+
preserveTimestamps: true,
|
|
570
|
+
});
|
|
571
|
+
copied++;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// "I looked and found nothing" must not read the same as "I copied
|
|
576
|
+
// everything". A module with no role files/ is legitimate; a module that has
|
|
577
|
+
// one somewhere this function cannot see is celilo#1461, and it was silent.
|
|
578
|
+
if (copied === 0) {
|
|
579
|
+
log.info(`No Ansible role files/ directories found under ${modulePath}`);
|
|
559
580
|
}
|
|
560
581
|
}
|
|
561
582
|
|