Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ on:
- main

# Set up for Trusted Publishing by NPM
permissions:
permissions:
id-token: write
contents: read
contents: write

jobs:
release:
Expand Down
48 changes: 38 additions & 10 deletions packages/cli/src/commands/generate/implementation/repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,22 @@ async function generateRepo({
printOutput,
});

//const resolvedContext = await resolveEffectiveContext({ instance, workspace, branch }, core);
const { instanceConfig, workspaceConfig, branchConfig } = await resolveConfigs({
cliContext: { instance, workspace, branch },
core,
});
let instanceConfig, workspaceConfig, branchConfig;
if (input && !fetch) {
// Skip context validation, provide dummy configs or minimal required fields
instanceConfig = {
name: instance || 'defaultInstance',
process: { output: output || './output' },
};
workspaceConfig = { name: workspace || 'defaultWorkspace', id: 'dummyId' };
branchConfig = { label: branch || 'main' };
} else {
// Perform normal context resolution and validation
({ instanceConfig, workspaceConfig, branchConfig } = await resolveConfigs({
cliContext: { instance, workspace, branch },
core,
}));
}

// Resolve output dir
const outputDir = output
Expand Down Expand Up @@ -96,25 +107,42 @@ async function generateRepo({
log.step(`Reading and parsing YAML file -> ${inputFile}`);
const fileContents = await core.storage.readFile(inputFile, 'utf8');
const jsonData = load(fileContents);

const plannedWrites: { path: string; content: string }[] = await core.generateRepo({
jsonData,
instance: instanceConfig.name,
workspace: workspaceConfig.name,
branch: branchConfig.label,
});

log.step(`Writing Repository to the output directory -> ${outputDir}`);
await Promise.all(

// Track results for logging
const writeResults = await Promise.all(
plannedWrites.map(async ({ path, content }) => {
const outputPath = joinPath(outputDir, path);
const writeDir = dirname(outputPath);
if (!(await core.storage.exists(writeDir))) {
await core.storage.mkdir(writeDir, { recursive: true });

try {
if (!(await core.storage.exists(writeDir))) {
await core.storage.mkdir(writeDir, { recursive: true });
}
await core.storage.writeFile(outputPath, content);
return { path: outputPath, success: true };
} catch (err) {
return { path: outputPath, success: false, error: err };
}
await core.storage.writeFile(outputPath, content);
})
);

// Summary log
const failedWrites = writeResults.filter((r) => !r.success);
if (failedWrites.length) {
log.warn(`Some files failed to write (${failedWrites.length}):`);
failedWrites.forEach((r) => log.warn(` - ${r.path}: ${r.error}`));
} else {
log.info('All files written successfully.');
}

printOutputDir(printOutput, outputDir);
outro('Directory structure rebuilt successfully!');
}
Expand Down
30 changes: 28 additions & 2 deletions packages/cli/src/commands/test/implementation/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,25 @@ import {
} from '../../../utils/index';

/**
* Print a formatted table of test outcomes and an optional detailed warnings section to the log.
*
* @param cliEnvVars - object of CLI provided env vars (e.g., {DEMO_ADMIN_PWD: 'xyz'})
* @returns flat object with keys as-is, to be used with {{ENVIRONMENT.KEY}} template pattern
*/
function collectInitialRuntimeValues(cliEnvVars = {}) {
// 1. Collect process.env XANO_* vars (Node only)
const envVars = {};
for (const [k, v] of Object.entries(process.env)) {
if (k.startsWith('XANO_')) envVars[k] = v;
}

// 2. Merge CLI over ENV, CLI wins
const merged = { ...envVars, ...cliEnvVars };

return merged;
}

/**
* Prints a formatted summary table of test outcomes to the log.
*
* The table includes columns for status, HTTP method, path, warnings count, and duration (ms),
* followed by an aggregate summary line with total, passed, failed, and total duration.
Expand Down Expand Up @@ -154,6 +172,7 @@ async function runTest({
isAll = false,
printOutput = false,
core,
cliTestEnvVars,
}: {
instance: string;
workspace: string;
Expand All @@ -163,6 +182,7 @@ async function runTest({
isAll: boolean;
printOutput: boolean;
core: any;
cliTestEnvVars: any;
}) {
intro('☣️ Starting up the testing...');

Expand All @@ -188,6 +208,11 @@ async function runTest({
const testConfig = await loadTestConfig(testConfigPath);
const s = spinner();
s.start('Running tests based on the provided spec');

// Collect env vars to set up
const initialRuntimeValues = collectInitialRuntimeValues(cliTestEnvVars);

// Run tests
const testResults = await core.runTests({
context: {
instance: instanceConfig.name,
Expand All @@ -196,6 +221,7 @@ async function runTest({
},
groups: groups,
testConfig,
initialRuntimeValues,
});
s.stop();

Expand Down Expand Up @@ -227,4 +253,4 @@ async function runTest({
}
}

export { runTest };
export { runTest };
21 changes: 20 additions & 1 deletion packages/cli/src/commands/test/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { addApiGroupOptions, addFullContextOptions, addPrintOutputFlag, withErrorHandler } from '../../utils';
import {
addApiGroupOptions,
addFullContextOptions,
addPrintOutputFlag,
withErrorHandler,
} from '../../utils';
import { runTest } from './implementation/test';

function registerTestCommands(program, core) {
Expand All @@ -21,13 +26,27 @@ function registerTestCommands(program, core) {

runTestsCommand
.option('--test-config-path <path>', 'Local path to the test configuration file.')
.option(
'--test-env <keyValue...>',
'Inject environment variables (KEY=VALUE) for tests. Can be repeated to set multiple.'
)
.action(
withErrorHandler(async (options) => {
const cliTestEnvVars = {};
if (options.testEnv) {
for (const arg of options.testEnv) {
const [key, ...rest] = arg.split('=');
if (key && rest.length > 0) {
cliTestEnvVars[key] = rest.join('=');
}
}
}
await runTest({
...options,
isAll: options.all,
printOutput: options.printOutputDir,
core,
cliTestEnvVars,
});
})
);
Expand Down
6 changes: 4 additions & 2 deletions packages/core/src/features/testing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ async function testRunner({
testConfig,
core,
storage,
initialRuntimeValues = {},
}: {
context: CoreContext;
groups: ApiGroupConfig[];
Expand All @@ -81,6 +82,7 @@ async function testRunner({
}[];
core: Caly;
storage: Caly['storage'];
initialRuntimeValues?: Record<string, any>;
}): Promise<
{
group: ApiGroupConfig;
Expand Down Expand Up @@ -109,7 +111,7 @@ async function testRunner({
'X-Data-Source': 'test',
'X-Branch': branchConfig.label,
};
let runtimeValues = {};
let runtimeValues = initialRuntimeValues ?? {};

let finalOutput = [];

Expand Down Expand Up @@ -259,4 +261,4 @@ async function testRunner({
return finalOutput;
}

export { testRunner };
export { testRunner };
4 changes: 3 additions & 1 deletion packages/core/src/implementations/run-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ async function runTestsImplementation({
testConfig,
core,
storage,
initialRuntimeValues,
}: {
context: CoreContext;
groups: ApiGroupConfig[];
Expand All @@ -22,6 +23,7 @@ async function runTestsImplementation({
}[];
core: Caly;
storage: Caly['storage'];
initialRuntimeValues: Record<string, any>;
}): Promise<
{
group: ApiGroupConfig;
Expand All @@ -35,7 +37,7 @@ async function runTestsImplementation({
}[];
}[]
> {
return await testRunner({ context, groups, testConfig, core, storage });
return await testRunner({ context, groups, testConfig, core, storage, initialRuntimeValues });
}

export { runTestsImplementation };
3 changes: 3 additions & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,10 +336,12 @@ export class Caly extends TypedEmitter<EventMap> {
context,
groups,
testConfig,
initialRuntimeValues,
}: {
context: Context;
groups: ApiGroupConfig[];
testConfig: any;
initialRuntimeValues: Record<string, any>;
}): Promise<
{
group: ApiGroupConfig;
Expand All @@ -359,6 +361,7 @@ export class Caly extends TypedEmitter<EventMap> {
testConfig,
core: this,
storage: this.storage,
initialRuntimeValues,
});
}

Expand Down