Skip to content

Commit dc55056

Browse files
authored
feat: test config initial runtime values setup (#177)
2 parents 4b8da6e + 049cdb8 commit dc55056

File tree

7 files changed

+98
-18
lines changed

7 files changed

+98
-18
lines changed

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ on:
77
- main
88

99
# Set up for Trusted Publishing by NPM
10-
permissions:
10+
permissions:
1111
id-token: write
12-
contents: read
12+
contents: write
1313

1414
jobs:
1515
release:

packages/cli/src/commands/generate/implementation/repo.ts

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,22 @@ async function generateRepo({
5656
printOutput,
5757
});
5858

59-
//const resolvedContext = await resolveEffectiveContext({ instance, workspace, branch }, core);
60-
const { instanceConfig, workspaceConfig, branchConfig } = await resolveConfigs({
61-
cliContext: { instance, workspace, branch },
62-
core,
63-
});
59+
let instanceConfig, workspaceConfig, branchConfig;
60+
if (input && !fetch) {
61+
// Skip context validation, provide dummy configs or minimal required fields
62+
instanceConfig = {
63+
name: instance || 'defaultInstance',
64+
process: { output: output || './output' },
65+
};
66+
workspaceConfig = { name: workspace || 'defaultWorkspace', id: 'dummyId' };
67+
branchConfig = { label: branch || 'main' };
68+
} else {
69+
// Perform normal context resolution and validation
70+
({ instanceConfig, workspaceConfig, branchConfig } = await resolveConfigs({
71+
cliContext: { instance, workspace, branch },
72+
core,
73+
}));
74+
}
6475

6576
// Resolve output dir
6677
const outputDir = output
@@ -96,25 +107,42 @@ async function generateRepo({
96107
log.step(`Reading and parsing YAML file -> ${inputFile}`);
97108
const fileContents = await core.storage.readFile(inputFile, 'utf8');
98109
const jsonData = load(fileContents);
99-
100110
const plannedWrites: { path: string; content: string }[] = await core.generateRepo({
101111
jsonData,
102112
instance: instanceConfig.name,
103113
workspace: workspaceConfig.name,
104114
branch: branchConfig.label,
105115
});
116+
106117
log.step(`Writing Repository to the output directory -> ${outputDir}`);
107-
await Promise.all(
118+
119+
// Track results for logging
120+
const writeResults = await Promise.all(
108121
plannedWrites.map(async ({ path, content }) => {
109122
const outputPath = joinPath(outputDir, path);
110123
const writeDir = dirname(outputPath);
111-
if (!(await core.storage.exists(writeDir))) {
112-
await core.storage.mkdir(writeDir, { recursive: true });
124+
125+
try {
126+
if (!(await core.storage.exists(writeDir))) {
127+
await core.storage.mkdir(writeDir, { recursive: true });
128+
}
129+
await core.storage.writeFile(outputPath, content);
130+
return { path: outputPath, success: true };
131+
} catch (err) {
132+
return { path: outputPath, success: false, error: err };
113133
}
114-
await core.storage.writeFile(outputPath, content);
115134
})
116135
);
117136

137+
// Summary log
138+
const failedWrites = writeResults.filter((r) => !r.success);
139+
if (failedWrites.length) {
140+
log.warn(`Some files failed to write (${failedWrites.length}):`);
141+
failedWrites.forEach((r) => log.warn(` - ${r.path}: ${r.error}`));
142+
} else {
143+
log.info('All files written successfully.');
144+
}
145+
118146
printOutputDir(printOutput, outputDir);
119147
outro('Directory structure rebuilt successfully!');
120148
}

packages/cli/src/commands/test/implementation/test.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,25 @@ import {
1010
} from '../../../utils/index';
1111

1212
/**
13-
* Print a formatted table of test outcomes and an optional detailed warnings section to the log.
13+
*
14+
* @param cliEnvVars - object of CLI provided env vars (e.g., {DEMO_ADMIN_PWD: 'xyz'})
15+
* @returns flat object with keys as-is, to be used with {{ENVIRONMENT.KEY}} template pattern
16+
*/
17+
function collectInitialRuntimeValues(cliEnvVars = {}) {
18+
// 1. Collect process.env XANO_* vars (Node only)
19+
const envVars = {};
20+
for (const [k, v] of Object.entries(process.env)) {
21+
if (k.startsWith('XANO_')) envVars[k] = v;
22+
}
23+
24+
// 2. Merge CLI over ENV, CLI wins
25+
const merged = { ...envVars, ...cliEnvVars };
26+
27+
return merged;
28+
}
29+
30+
/**
31+
* Prints a formatted summary table of test outcomes to the log.
1432
*
1533
* The table includes columns for status, HTTP method, path, warnings count, and duration (ms),
1634
* followed by an aggregate summary line with total, passed, failed, and total duration.
@@ -154,6 +172,7 @@ async function runTest({
154172
isAll = false,
155173
printOutput = false,
156174
core,
175+
cliTestEnvVars,
157176
}: {
158177
instance: string;
159178
workspace: string;
@@ -163,6 +182,7 @@ async function runTest({
163182
isAll: boolean;
164183
printOutput: boolean;
165184
core: any;
185+
cliTestEnvVars: any;
166186
}) {
167187
intro('☣️ Starting up the testing...');
168188

@@ -188,6 +208,11 @@ async function runTest({
188208
const testConfig = await loadTestConfig(testConfigPath);
189209
const s = spinner();
190210
s.start('Running tests based on the provided spec');
211+
212+
// Collect env vars to set up
213+
const initialRuntimeValues = collectInitialRuntimeValues(cliTestEnvVars);
214+
215+
// Run tests
191216
const testResults = await core.runTests({
192217
context: {
193218
instance: instanceConfig.name,
@@ -196,6 +221,7 @@ async function runTest({
196221
},
197222
groups: groups,
198223
testConfig,
224+
initialRuntimeValues,
199225
});
200226
s.stop();
201227

@@ -227,4 +253,4 @@ async function runTest({
227253
}
228254
}
229255

230-
export { runTest };
256+
export { runTest };

packages/cli/src/commands/test/index.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { addApiGroupOptions, addFullContextOptions, addPrintOutputFlag, withErrorHandler } from '../../utils';
1+
import {
2+
addApiGroupOptions,
3+
addFullContextOptions,
4+
addPrintOutputFlag,
5+
withErrorHandler,
6+
} from '../../utils';
27
import { runTest } from './implementation/test';
38

49
function registerTestCommands(program, core) {
@@ -21,13 +26,27 @@ function registerTestCommands(program, core) {
2126

2227
runTestsCommand
2328
.option('--test-config-path <path>', 'Local path to the test configuration file.')
29+
.option(
30+
'--test-env <keyValue...>',
31+
'Inject environment variables (KEY=VALUE) for tests. Can be repeated to set multiple.'
32+
)
2433
.action(
2534
withErrorHandler(async (options) => {
35+
const cliTestEnvVars = {};
36+
if (options.testEnv) {
37+
for (const arg of options.testEnv) {
38+
const [key, ...rest] = arg.split('=');
39+
if (key && rest.length > 0) {
40+
cliTestEnvVars[key] = rest.join('=');
41+
}
42+
}
43+
}
2644
await runTest({
2745
...options,
2846
isAll: options.all,
2947
printOutput: options.printOutputDir,
3048
core,
49+
cliTestEnvVars,
3150
});
3251
})
3352
);

packages/core/src/features/testing/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ async function testRunner({
6767
testConfig,
6868
core,
6969
storage,
70+
initialRuntimeValues = {},
7071
}: {
7172
context: CoreContext;
7273
groups: ApiGroupConfig[];
@@ -81,6 +82,7 @@ async function testRunner({
8182
}[];
8283
core: Caly;
8384
storage: Caly['storage'];
85+
initialRuntimeValues?: Record<string, any>;
8486
}): Promise<
8587
{
8688
group: ApiGroupConfig;
@@ -109,7 +111,7 @@ async function testRunner({
109111
'X-Data-Source': 'test',
110112
'X-Branch': branchConfig.label,
111113
};
112-
let runtimeValues = {};
114+
let runtimeValues = initialRuntimeValues ?? {};
113115

114116
let finalOutput = [];
115117

@@ -259,4 +261,4 @@ async function testRunner({
259261
return finalOutput;
260262
}
261263

262-
export { testRunner };
264+
export { testRunner };

packages/core/src/implementations/run-tests.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ async function runTestsImplementation({
88
testConfig,
99
core,
1010
storage,
11+
initialRuntimeValues,
1112
}: {
1213
context: CoreContext;
1314
groups: ApiGroupConfig[];
@@ -22,6 +23,7 @@ async function runTestsImplementation({
2223
}[];
2324
core: Caly;
2425
storage: Caly['storage'];
26+
initialRuntimeValues: Record<string, any>;
2527
}): Promise<
2628
{
2729
group: ApiGroupConfig;
@@ -35,7 +37,7 @@ async function runTestsImplementation({
3537
}[];
3638
}[]
3739
> {
38-
return await testRunner({ context, groups, testConfig, core, storage });
40+
return await testRunner({ context, groups, testConfig, core, storage, initialRuntimeValues });
3941
}
4042

4143
export { runTestsImplementation };

packages/core/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,10 +336,12 @@ export class Caly extends TypedEmitter<EventMap> {
336336
context,
337337
groups,
338338
testConfig,
339+
initialRuntimeValues,
339340
}: {
340341
context: Context;
341342
groups: ApiGroupConfig[];
342343
testConfig: any;
344+
initialRuntimeValues: Record<string, any>;
343345
}): Promise<
344346
{
345347
group: ApiGroupConfig;
@@ -359,6 +361,7 @@ export class Caly extends TypedEmitter<EventMap> {
359361
testConfig,
360362
core: this,
361363
storage: this.storage,
364+
initialRuntimeValues,
362365
});
363366
}
364367

0 commit comments

Comments
 (0)