fix: openapi cli import (#7028)

* fix: openapi cli import

* chore: seperate bru and opencollection by a flag

* fix: pass down format correctly

* fix: pass format option correctly in collection tests

* Add opencollection version for YAML format

Set opencollection version for YAML format.

---------

Co-authored-by: Sid <siddharth@usebruno.com>
This commit is contained in:
Pooja
2026-02-23 18:53:03 +05:30
committed by GitHub
parent 89bf2fbf44
commit 5bca0cdd84
3 changed files with 65 additions and 30 deletions

View File

@@ -10,6 +10,8 @@ const { createCollectionFromBrunoObject } = require('../utils/collection');
const command = 'import <type>';
const desc = 'Import a collection from other formats';
const COLLECTION_FORMATS = ['bru', 'opencollection'];
const builder = (yargs) => {
yargs
.positional('type', {
@@ -40,6 +42,12 @@ const builder = (yargs) => {
describe: 'Name for the imported collection',
type: 'string'
})
.option('collection-format', {
describe: 'Format of the imported collection (bru or opencollection). If not specified, the default is `opencollection`',
type: 'string',
choices: COLLECTION_FORMATS,
default: 'opencollection'
})
.option('insecure', {
type: 'boolean',
describe: 'Skip SSL certificate verification when fetching from URLs',
@@ -199,7 +207,7 @@ const readWSDLFile = async (source, options = {}) => {
const handler = async (argv) => {
try {
const { type, source, output, outputFile, collectionName, insecure, groupBy } = argv;
const { type, source, output, collectionFormat, outputFile, collectionName, insecure, groupBy } = argv;
if (!type || !['openapi', 'wsdl'].includes(type)) {
console.error(chalk.red('Only OpenAPI and WSDL imports are supported currently'));
@@ -296,7 +304,9 @@ const handler = async (argv) => {
fs.mkdirSync(outputDir, { recursive: true });
}
await createCollectionFromBrunoObject(brunoCollection, outputDir);
await createCollectionFromBrunoObject(brunoCollection, outputDir, {
format: collectionFormat === 'opencollection' ? 'yml' : 'bru'
});
console.log(chalk.green(`Bruno collection created at ${outputDir}`));
}
} catch (error) {

View File

@@ -442,8 +442,9 @@ const safeWriteFileSync = (filePath, content) => {
* @param {Object} collection - The Bruno collection object
* @param {string} dirPath - The output directory path
*/
const createCollectionFromBrunoObject = async (collection, dirPath) => {
// Create bruno.json
const createCollectionFromBrunoObject = async (collection, dirPath, options = {}) => {
const { format = 'bru' } = options;
// Create brunoConfig for yml format
const brunoConfig = {
version: '1',
name: collection.name,
@@ -451,15 +452,24 @@ const createCollectionFromBrunoObject = async (collection, dirPath) => {
ignore: ['node_modules', '.git']
};
fs.writeFileSync(
path.join(dirPath, 'bruno.json'),
JSON.stringify(brunoConfig, null, 2)
);
if (format === 'yml') {
brunoConfig.opencollection = '1.0.0';
}
const collectionContent = await stringifyCollection(collection.root || {}, brunoConfig, {
format
});
const collectionRootFilePath = format == 'bru' ? path.join(dirPath, 'collection.bru') : path.join(dirPath, 'opencollection.yml');
if (format === 'bru') {
fs.writeFileSync(
path.join(dirPath, 'bruno.json'),
JSON.stringify(brunoConfig, null, 2)
);
}
// Create collection.bru if root exists
if (collection.root) {
const collectionContent = await stringifyCollection(collection.root, {}, { format: 'bru' });
fs.writeFileSync(path.join(dirPath, 'collection.bru'), collectionContent);
fs.writeFileSync(collectionRootFilePath, collectionContent);
}
// Process environments
@@ -468,14 +478,14 @@ const createCollectionFromBrunoObject = async (collection, dirPath) => {
fs.mkdirSync(envDirPath, { recursive: true });
for (const env of collection.environments) {
const content = await stringifyEnvironment(env, { format: 'bru' });
const filename = sanitizeName(`${env.name}.bru`);
const content = stringifyEnvironment(env, { format });
const filename = format === 'bru' ? sanitizeName(`${env.name}.bru`) : sanitizeName(`${env.name}.yml`);
fs.writeFileSync(path.join(envDirPath, filename), content);
}
}
// Process collection items
await processCollectionItems(collection.items, dirPath);
await processCollectionItems(collection.items, dirPath, { format });
return dirPath;
};
@@ -485,8 +495,11 @@ const createCollectionFromBrunoObject = async (collection, dirPath) => {
*
* @param {Array} items - Collection items
* @param {string} currentPath - Current directory path
* @param {object} [options] - Current directory path
* @param {"bru"|"yml"} options.format - Current directory path
*/
const processCollectionItems = async (items = [], currentPath) => {
const processCollectionItems = async (items = [], currentPath, options = {}) => {
const { format = 'bru' } = options;
for (const item of items) {
if (item.type === 'folder') {
// Create folder
@@ -494,29 +507,38 @@ const processCollectionItems = async (items = [], currentPath) => {
const folderPath = path.join(currentPath, sanitizedFolderName);
fs.mkdirSync(folderPath, { recursive: true });
// Create folder.bru file if root exists
// Create folder.yml file if root exists
if (item?.root?.meta?.name) {
const folderBruFilePath = path.join(folderPath, 'folder.bru');
const folderFileName = format === 'bru' ? 'folder.bru' : 'folder.yml';
const folderFilePath = path.join(folderPath, folderFileName);
if (item.seq) {
item.root.meta.seq = item.seq;
}
const folderContent = stringifyFolder(item.root, { format: 'bru' });
safeWriteFileSync(folderBruFilePath, folderContent);
const folderContent = stringifyFolder(item.root, { format });
safeWriteFileSync(folderFilePath, folderContent);
}
// Process folder items recursively
if (item.items && item.items.length) {
await processCollectionItems(item.items, folderPath);
await processCollectionItems(item.items, folderPath, options);
}
} else if (REQUEST_ITEM_TYPES.includes(item.type)) {
// Create request file
let sanitizedFilename = sanitizeName(item?.filename || `${item.name}.bru`);
if (!sanitizedFilename.endsWith('.bru')) {
sanitizedFilename += '.bru';
let sanitizedFilename;
if (format == 'yml') {
sanitizedFilename = sanitizeName(item?.filename || `${item.name}.yml`);
if (!sanitizedFilename.endsWith('.yml')) {
sanitizedFilename += '.yml';
}
} else {
sanitizedFilename = sanitizeName(item?.filename || `${item.name}.bru`);
if (!sanitizedFilename.endsWith('.bru')) {
sanitizedFilename += '.bru';
}
}
const bruJson = {
// Keep schema item type so filestore can stringify request correctly
// Convert to YML format
const itemJson = {
type: item.type,
name: item.name,
seq: typeof item.seq === 'number' ? item.seq : 1,
@@ -537,8 +559,8 @@ const processCollectionItems = async (items = [], currentPath) => {
}
};
// Convert to BRU format and write to file
const content = stringifyRequest(bruJson, { format: 'bru' });
// Convert to YML format and write to file
const content = stringifyRequest(itemJson, { format });
safeWriteFileSync(path.join(currentPath, sanitizedFilename), content);
} else {
throw new Error(`Unsupported item type: ${item.type}`);

View File

@@ -56,7 +56,8 @@ describe('createCollectionFromBrunoObject', () => {
}
]
},
outputDir
outputDir,
{ format: 'bru' }
);
const httpPath = path.join(outputDir, 'get-users.bru');
@@ -103,7 +104,8 @@ describe('createCollectionFromBrunoObject', () => {
}
]
},
outputDir
outputDir,
{ format: 'bru' }
);
const folderPath = path.join(outputDir, 'Users');
@@ -136,7 +138,8 @@ describe('createCollectionFromBrunoObject', () => {
}
]
},
outputDir
outputDir,
{ format: 'bru' }
)
).rejects.toThrow('Unsupported item type: unsupported-type');
});