From 5bca0cdd848dc2f876d1d427f907184f90f39f47 Mon Sep 17 00:00:00 2001 From: Pooja Date: Mon, 23 Feb 2026 18:53:03 +0530 Subject: [PATCH] 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 --- packages/bruno-cli/src/commands/import.js | 14 +++- packages/bruno-cli/src/utils/collection.js | 72 ++++++++++++------- ...reate-collection-from-bruno-object.spec.js | 9 ++- 3 files changed, 65 insertions(+), 30 deletions(-) diff --git a/packages/bruno-cli/src/commands/import.js b/packages/bruno-cli/src/commands/import.js index 2ee8d838b..cb3864def 100644 --- a/packages/bruno-cli/src/commands/import.js +++ b/packages/bruno-cli/src/commands/import.js @@ -10,6 +10,8 @@ const { createCollectionFromBrunoObject } = require('../utils/collection'); const command = 'import '; 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) { diff --git a/packages/bruno-cli/src/utils/collection.js b/packages/bruno-cli/src/utils/collection.js index baebbe957..8fcf1e167 100644 --- a/packages/bruno-cli/src/utils/collection.js +++ b/packages/bruno-cli/src/utils/collection.js @@ -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}`); diff --git a/packages/bruno-cli/tests/utils/collection/create-collection-from-bruno-object.spec.js b/packages/bruno-cli/tests/utils/collection/create-collection-from-bruno-object.spec.js index 5135152d5..332a87b42 100644 --- a/packages/bruno-cli/tests/utils/collection/create-collection-from-bruno-object.spec.js +++ b/packages/bruno-cli/tests/utils/collection/create-collection-from-bruno-object.spec.js @@ -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'); });