mirror of
https://github.com/usebruno/bruno.git
synced 2026-07-09 06:55:03 +00:00
@@ -22,7 +22,7 @@ async function findUniqueFolderName(baseName, collectionLocation, counter = 0) {
|
||||
/**
|
||||
* Import a collection - shared logic used by both IPC handler and onboarding service
|
||||
*/
|
||||
async function importCollection(collection, collectionLocation, mainWindow, lastOpenedCollections, uniqueFolderName = null, format = 'bru') {
|
||||
async function importCollection(collection, collectionLocation, mainWindow, uniqueFolderName = null, format = 'bru') {
|
||||
// Use provided unique folder name or use collection name
|
||||
let folderName = uniqueFolderName ? sanitizeName(uniqueFolderName) : sanitizeName(collection.name);
|
||||
let collectionPath = path.join(collectionLocation, folderName);
|
||||
@@ -100,13 +100,13 @@ async function importCollection(collection, collectionLocation, mainWindow, last
|
||||
let brunoConfig = getBrunoJsonConfig(collection);
|
||||
|
||||
if (format === 'yml') {
|
||||
const collectionContent = await stringifyCollection(collection.root, brunoConfig, { format });
|
||||
const collectionContent = await stringifyCollection(collection.root, { format });
|
||||
await writeFile(path.join(collectionPath, 'opencollection.yml'), collectionContent);
|
||||
} else if (format === 'bru') {
|
||||
const stringifiedBrunoConfig = await stringifyJson(brunoConfig);
|
||||
await writeFile(path.join(collectionPath, 'bruno.json'), stringifiedBrunoConfig);
|
||||
|
||||
const collectionContent = await stringifyCollection(collection.root, brunoConfig, { format });
|
||||
const collectionContent = await stringifyCollection(collection.root, { format });
|
||||
await writeFile(path.join(collectionPath, 'collection.bru'), collectionContent);
|
||||
} else {
|
||||
throw new Error(`Invalid format: ${format}`);
|
||||
@@ -119,8 +119,6 @@ async function importCollection(collection, collectionLocation, mainWindow, last
|
||||
mainWindow.webContents.send('main:collection-opened', collectionPath, uid, brunoConfig);
|
||||
ipcMain.emit('main:collection-opened', mainWindow, collectionPath, uid, brunoConfig);
|
||||
|
||||
lastOpenedCollections.add(collectionPath);
|
||||
|
||||
// create folder and files based on collection
|
||||
await parseCollectionItems(collection.items, collectionPath);
|
||||
await parseEnvironments(collection.environments, collectionPath);
|
||||
|
||||
225
packages/bruno-electron/src/utils/workspace-config.js
Normal file
225
packages/bruno-electron/src/utils/workspace-config.js
Normal file
@@ -0,0 +1,225 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const yaml = require('js-yaml');
|
||||
const { writeFile, validateName } = require('./filesystem');
|
||||
|
||||
const WORKSPACE_TYPE = 'workspace';
|
||||
|
||||
const makeRelativePath = (workspacePath, absolutePath) => {
|
||||
if (!path.isAbsolute(absolutePath)) {
|
||||
return absolutePath;
|
||||
}
|
||||
|
||||
try {
|
||||
return path.relative(workspacePath, absolutePath);
|
||||
} catch (error) {
|
||||
return absolutePath;
|
||||
}
|
||||
};
|
||||
|
||||
const normalizeCollectionEntry = (workspacePath, collection) => {
|
||||
const relativePath = makeRelativePath(workspacePath, collection.path);
|
||||
|
||||
const normalizedCollection = {
|
||||
name: collection.name,
|
||||
path: relativePath
|
||||
};
|
||||
|
||||
if (collection.remote) {
|
||||
normalizedCollection.remote = collection.remote;
|
||||
}
|
||||
|
||||
return normalizedCollection;
|
||||
};
|
||||
|
||||
const validateWorkspacePath = (workspacePath) => {
|
||||
if (!workspacePath) {
|
||||
throw new Error('Workspace path is required');
|
||||
}
|
||||
|
||||
if (!fs.existsSync(workspacePath)) {
|
||||
throw new Error(`Workspace path does not exist: ${workspacePath}`);
|
||||
}
|
||||
|
||||
const workspaceFilePath = path.join(workspacePath, 'workspace.yml');
|
||||
if (!fs.existsSync(workspaceFilePath)) {
|
||||
throw new Error('Invalid workspace: workspace.yml not found');
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const validateWorkspaceDirectory = (dirPath) => {
|
||||
if (!validateName(path.basename(dirPath))) {
|
||||
throw new Error(`Invalid workspace directory name: ${dirPath}`);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const createWorkspaceConfig = (workspaceName) => ({
|
||||
name: workspaceName,
|
||||
type: WORKSPACE_TYPE,
|
||||
version: '1.0.0',
|
||||
docs: '',
|
||||
collections: []
|
||||
});
|
||||
|
||||
const readWorkspaceConfig = (workspacePath) => {
|
||||
const workspaceFilePath = path.join(workspacePath, 'workspace.yml');
|
||||
|
||||
if (!fs.existsSync(workspaceFilePath)) {
|
||||
throw new Error('Invalid workspace: workspace.yml not found');
|
||||
}
|
||||
|
||||
const yamlContent = fs.readFileSync(workspaceFilePath, 'utf8');
|
||||
const workspaceConfig = yaml.load(yamlContent);
|
||||
|
||||
if (!workspaceConfig || typeof workspaceConfig !== 'object') {
|
||||
throw new Error('Invalid workspace: workspace.yml is malformed');
|
||||
}
|
||||
|
||||
return workspaceConfig;
|
||||
};
|
||||
|
||||
const writeWorkspaceConfig = async (workspacePath, config) => {
|
||||
const yamlContent = yaml.dump(config, {
|
||||
indent: 2,
|
||||
lineWidth: -1,
|
||||
noRefs: true
|
||||
});
|
||||
await writeFile(path.join(workspacePath, 'workspace.yml'), yamlContent);
|
||||
};
|
||||
|
||||
const validateWorkspaceConfig = (config) => {
|
||||
if (!config || typeof config !== 'object') {
|
||||
throw new Error('Workspace configuration must be an object');
|
||||
}
|
||||
|
||||
if (config.type !== WORKSPACE_TYPE) {
|
||||
throw new Error('Invalid workspace: not a bruno workspace');
|
||||
}
|
||||
|
||||
if (!config.name || typeof config.name !== 'string') {
|
||||
throw new Error('Workspace must have a valid name');
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const updateWorkspaceName = async (workspacePath, newName) => {
|
||||
const config = readWorkspaceConfig(workspacePath);
|
||||
config.name = newName;
|
||||
await writeWorkspaceConfig(workspacePath, config);
|
||||
return config;
|
||||
};
|
||||
|
||||
const updateWorkspaceDocs = async (workspacePath, docs) => {
|
||||
const config = readWorkspaceConfig(workspacePath);
|
||||
config.docs = docs;
|
||||
await writeWorkspaceConfig(workspacePath, config);
|
||||
return docs;
|
||||
};
|
||||
|
||||
const addCollectionToWorkspace = async (workspacePath, collection) => {
|
||||
const config = readWorkspaceConfig(workspacePath);
|
||||
|
||||
if (!config.collections) {
|
||||
config.collections = [];
|
||||
}
|
||||
|
||||
// Normalize collection entry
|
||||
const normalizedCollection = {
|
||||
name: collection.name,
|
||||
path: collection.path
|
||||
};
|
||||
|
||||
if (collection.remote) {
|
||||
normalizedCollection.remote = collection.remote;
|
||||
}
|
||||
|
||||
// Check if collection already exists
|
||||
const existingIndex = config.collections.findIndex((c) => c.name === normalizedCollection.name || c.path === normalizedCollection.path);
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
config.collections[existingIndex] = normalizedCollection;
|
||||
} else {
|
||||
config.collections.push(normalizedCollection);
|
||||
}
|
||||
|
||||
await writeWorkspaceConfig(workspacePath, config);
|
||||
return config.collections;
|
||||
};
|
||||
|
||||
const removeCollectionFromWorkspace = async (workspacePath, collectionPath) => {
|
||||
const config = readWorkspaceConfig(workspacePath);
|
||||
|
||||
let removedCollection = null;
|
||||
let shouldDeleteFiles = false;
|
||||
|
||||
config.collections = (config.collections || []).filter((c) => {
|
||||
const collectionPathFromYml = c.path;
|
||||
|
||||
if (!collectionPathFromYml) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Convert to absolute path for comparison
|
||||
const absoluteCollectionPath = path.isAbsolute(collectionPathFromYml)
|
||||
? collectionPathFromYml
|
||||
: path.resolve(workspacePath, collectionPathFromYml);
|
||||
|
||||
if (path.normalize(absoluteCollectionPath) === path.normalize(collectionPath)) {
|
||||
removedCollection = c;
|
||||
|
||||
// Delete files only for workspace collections (not remote, not external absolute paths)
|
||||
const hasRemote = c.remote;
|
||||
const isExternalPath = path.isAbsolute(collectionPathFromYml);
|
||||
|
||||
shouldDeleteFiles = !hasRemote && !isExternalPath;
|
||||
|
||||
return false; // Remove from array
|
||||
}
|
||||
|
||||
return true; // Keep in array
|
||||
});
|
||||
|
||||
await writeWorkspaceConfig(workspacePath, config);
|
||||
|
||||
return {
|
||||
removedCollection,
|
||||
shouldDeleteFiles,
|
||||
updatedConfig: config
|
||||
};
|
||||
};
|
||||
|
||||
const getWorkspaceCollections = (workspacePath) => {
|
||||
const config = readWorkspaceConfig(workspacePath);
|
||||
const collections = config.collections || [];
|
||||
|
||||
// Resolve relative paths to absolute
|
||||
return collections.map((collection) => {
|
||||
if (collection.path && !path.isAbsolute(collection.path)) {
|
||||
return {
|
||||
...collection,
|
||||
path: path.join(workspacePath, collection.path)
|
||||
};
|
||||
}
|
||||
return collection;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
makeRelativePath,
|
||||
normalizeCollectionEntry,
|
||||
validateWorkspacePath,
|
||||
validateWorkspaceDirectory,
|
||||
createWorkspaceConfig,
|
||||
readWorkspaceConfig,
|
||||
writeWorkspaceConfig,
|
||||
validateWorkspaceConfig,
|
||||
updateWorkspaceName,
|
||||
updateWorkspaceDocs,
|
||||
addCollectionToWorkspace,
|
||||
removeCollectionFromWorkspace,
|
||||
getWorkspaceCollections
|
||||
};
|
||||
Reference in New Issue
Block a user