mirror of
https://github.com/usebruno/bruno.git
synced 2026-07-08 06:28:33 +00:00
remove activeEnvironmentUid and migration (#7545)
* remove activeEnvironmentUid and migration * fix: no environment handling * fix: standardize workspace path handling
This commit is contained in:
@@ -737,28 +737,6 @@ export const deleteWorkspaceEnvironment = (workspaceUid, environmentUid) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const selectWorkspaceEnvironment = (workspaceUid, environmentUid) => {
|
||||
return async (dispatch, getState) => {
|
||||
try {
|
||||
const workspace = getState().workspaces.workspaces.find((w) => w.uid === workspaceUid);
|
||||
if (!workspace) {
|
||||
throw new Error('Workspace not found');
|
||||
}
|
||||
|
||||
await ipcRenderer.invoke('renderer:select-workspace-environment', workspace.pathname, environmentUid);
|
||||
|
||||
dispatch(updateWorkspace({
|
||||
uid: workspaceUid,
|
||||
activeEnvironmentUid: environmentUid
|
||||
}));
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const importWorkspaceEnvironment = (workspaceUid, environmentData) => {
|
||||
return async (dispatch, getState) => {
|
||||
try {
|
||||
|
||||
@@ -5,6 +5,49 @@ const { ipcMain } = require('electron');
|
||||
const { utils: { jsonToDotenv } } = require('@usebruno/common');
|
||||
const { globalEnvironmentsStore } = require('../store/global-environments');
|
||||
const { generateUniqueName, sanitizeName, writeFile, isValidDotEnvFilename } = require('../utils/filesystem');
|
||||
const { readWorkspaceConfig, writeWorkspaceConfig } = require('../utils/workspace-config');
|
||||
|
||||
/**
|
||||
* Migrates activeEnvironmentUid from workspace.yml to the electron store (per-workspace).
|
||||
* This handles users upgrading from versions that stored the active global env in workspace.yml.
|
||||
*
|
||||
* Fallback chain:
|
||||
* 1. Per-workspace electron store (already migrated) - use it
|
||||
* 2. workspace.yml activeEnvironmentUid - migrate to electron store, remove from file
|
||||
* 3. Legacy electron store activeGlobalEnvironmentUid - migrate to per-workspace store
|
||||
* 4. null (new workspace)
|
||||
*/
|
||||
const migrateActiveGlobalEnvironmentUid = async (workspacePath) => {
|
||||
// Already in per-workspace store (null means explicitly "No Environment", undefined means not set)
|
||||
const perWorkspaceUid = globalEnvironmentsStore.getActiveGlobalEnvironmentUidForWorkspace(workspacePath);
|
||||
if (perWorkspaceUid !== undefined) {
|
||||
return perWorkspaceUid;
|
||||
}
|
||||
|
||||
// Try workspace.yml
|
||||
try {
|
||||
const config = readWorkspaceConfig(workspacePath);
|
||||
if (config.activeEnvironmentUid) {
|
||||
const uid = config.activeEnvironmentUid;
|
||||
// Migrate to electron store
|
||||
globalEnvironmentsStore.setActiveGlobalEnvironmentUidForWorkspace(workspacePath, uid);
|
||||
// Rewrite workspace.yml without activeEnvironmentUid (generateYamlContent drops unknown fields)
|
||||
await writeWorkspaceConfig(workspacePath, config);
|
||||
return uid;
|
||||
}
|
||||
} catch (error) {
|
||||
// workspace.yml may not exist or be unreadable, continue to next fallback
|
||||
}
|
||||
|
||||
// Fallback to legacy single active uid
|
||||
const legacyUid = globalEnvironmentsStore.getActiveGlobalEnvironmentUid();
|
||||
if (legacyUid) {
|
||||
globalEnvironmentsStore.setActiveGlobalEnvironmentUidForWorkspace(workspacePath, legacyUid);
|
||||
return legacyUid;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const registerGlobalEnvironmentsIpc = (mainWindow, workspaceEnvironmentsManager) => {
|
||||
ipcMain.handle('renderer:create-global-environment', async (event, { uid, name, variables, color, workspaceUid, workspacePath }) => {
|
||||
@@ -64,23 +107,28 @@ const registerGlobalEnvironmentsIpc = (mainWindow, workspaceEnvironmentsManager)
|
||||
ipcMain.handle('renderer:delete-global-environment', async (event, { environmentUid, workspaceUid, workspacePath }) => {
|
||||
try {
|
||||
if (workspacePath && workspaceEnvironmentsManager) {
|
||||
return await workspaceEnvironmentsManager.deleteGlobalEnvironmentByPath(workspacePath, { environmentUid });
|
||||
await workspaceEnvironmentsManager.deleteGlobalEnvironmentByPath(workspacePath, { environmentUid });
|
||||
// Clear active environment for this workspace if the deleted one was active
|
||||
const activeUid = globalEnvironmentsStore.getActiveGlobalEnvironmentUidForWorkspace(workspacePath);
|
||||
if (activeUid === environmentUid) {
|
||||
globalEnvironmentsStore.setActiveGlobalEnvironmentUidForWorkspace(workspacePath, null);
|
||||
}
|
||||
} else {
|
||||
globalEnvironmentsStore.deleteGlobalEnvironment({ environmentUid });
|
||||
}
|
||||
|
||||
globalEnvironmentsStore.deleteGlobalEnvironment({ environmentUid });
|
||||
} catch (error) {
|
||||
console.error('Error in renderer:delete-global-environment:', error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('renderer:select-global-environment', async (event, { environmentUid, workspaceUid, workspacePath }) => {
|
||||
ipcMain.handle('renderer:select-global-environment', async (event, { environmentUid, workspacePath }) => {
|
||||
try {
|
||||
if (workspacePath && workspaceEnvironmentsManager) {
|
||||
return await workspaceEnvironmentsManager.selectGlobalEnvironmentByPath(workspacePath, { environmentUid });
|
||||
if (workspacePath) {
|
||||
globalEnvironmentsStore.setActiveGlobalEnvironmentUidForWorkspace(workspacePath, environmentUid || null);
|
||||
} else {
|
||||
globalEnvironmentsStore.setActiveGlobalEnvironmentUid(environmentUid || null);
|
||||
}
|
||||
|
||||
globalEnvironmentsStore.selectGlobalEnvironment({ environmentUid });
|
||||
} catch (error) {
|
||||
console.error('Error in renderer:select-global-environment:', error);
|
||||
return Promise.reject(error);
|
||||
@@ -89,13 +137,22 @@ const registerGlobalEnvironmentsIpc = (mainWindow, workspaceEnvironmentsManager)
|
||||
|
||||
ipcMain.handle('renderer:get-global-environments', async (event, { workspaceUid, workspacePath }) => {
|
||||
try {
|
||||
let globalEnvironments = [];
|
||||
|
||||
if (workspacePath && workspaceEnvironmentsManager) {
|
||||
return await workspaceEnvironmentsManager.getGlobalEnvironmentsByPath(workspacePath);
|
||||
const result = await workspaceEnvironmentsManager.getGlobalEnvironmentsByPath(workspacePath);
|
||||
globalEnvironments = result?.globalEnvironments || [];
|
||||
} else {
|
||||
globalEnvironments = globalEnvironmentsStore.getGlobalEnvironments() || [];
|
||||
}
|
||||
|
||||
const activeGlobalEnvironmentUid = workspacePath
|
||||
? await migrateActiveGlobalEnvironmentUid(workspacePath)
|
||||
: globalEnvironmentsStore.getActiveGlobalEnvironmentUid();
|
||||
|
||||
return {
|
||||
globalEnvironments: globalEnvironmentsStore.getGlobalEnvironments() || [],
|
||||
activeGlobalEnvironmentUid: globalEnvironmentsStore.getActiveGlobalEnvironmentUid()
|
||||
globalEnvironments,
|
||||
activeGlobalEnvironmentUid
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error in renderer:get-global-environments:', error);
|
||||
|
||||
@@ -10,6 +10,7 @@ const yaml = require('js-yaml');
|
||||
const LastOpenedWorkspaces = require('../store/last-opened-workspaces');
|
||||
const { defaultWorkspaceManager } = require('../store/default-workspace');
|
||||
const { globalEnvironmentsManager } = require('../store/workspace-environments');
|
||||
const { globalEnvironmentsStore } = require('../store/global-environments');
|
||||
|
||||
const {
|
||||
createWorkspaceConfig,
|
||||
@@ -280,6 +281,7 @@ const registerWorkspaceIpc = (mainWindow, workspaceWatcher) => {
|
||||
ipcMain.handle('renderer:close-workspace', async (event, workspacePath) => {
|
||||
try {
|
||||
lastOpenedWorkspaces.remove(workspacePath);
|
||||
globalEnvironmentsStore.removeActiveGlobalEnvironmentUidForWorkspace(workspacePath);
|
||||
|
||||
if (workspaceWatcher) {
|
||||
workspaceWatcher.removeWatcher(workspacePath);
|
||||
@@ -468,14 +470,6 @@ const registerWorkspaceIpc = (mainWindow, workspaceWatcher) => {
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('renderer:select-workspace-environment', async (event, workspacePath, environmentUid) => {
|
||||
try {
|
||||
return await globalEnvironmentsManager.selectGlobalEnvironment(workspacePath, { environmentUid });
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('renderer:import-workspace-environment', async (event, workspacePath, environmentData) => {
|
||||
try {
|
||||
return await globalEnvironmentsManager.createGlobalEnvironment(workspacePath, {
|
||||
|
||||
@@ -66,7 +66,7 @@ class DefaultWorkspaceManager {
|
||||
* Recovers collections and environments from an existing workspace directory
|
||||
*/
|
||||
recoverDataFromWorkspace(workspacePath) {
|
||||
const recovered = { collections: [], environments: [], activeEnvironmentUid: null };
|
||||
const recovered = { collections: [], environments: [] };
|
||||
|
||||
try {
|
||||
// Try to read workspace config for collections
|
||||
@@ -78,9 +78,6 @@ class DefaultWorkspaceManager {
|
||||
return isValidCollectionDirectory(collectionPath);
|
||||
});
|
||||
}
|
||||
if (config.activeEnvironmentUid) {
|
||||
recovered.activeEnvironmentUid = config.activeEnvironmentUid;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to read workspace config during recovery:', error);
|
||||
}
|
||||
@@ -273,9 +270,6 @@ class DefaultWorkspaceManager {
|
||||
console.error('Failed to copy environment:', env.name, error);
|
||||
}
|
||||
}
|
||||
if (recoveredData.activeEnvironmentUid) {
|
||||
workspaceConfig.activeEnvironmentUid = recoveredData.activeEnvironmentUid;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply recovered collections first (lower priority)
|
||||
@@ -374,8 +368,12 @@ class DefaultWorkspaceManager {
|
||||
const content = stringifyEnvironment(environment, { format: 'yml' });
|
||||
await writeFile(envFilePath, content);
|
||||
|
||||
if (env.uid === activeGlobalEnvironmentUid && !workspaceConfig.activeEnvironmentUid) {
|
||||
workspaceConfig.activeEnvironmentUid = generateUidBasedOnHash(envFilePath);
|
||||
// Map the legacy active env uid to the new file-based uid in the per-workspace store
|
||||
if (env.uid === activeGlobalEnvironmentUid) {
|
||||
globalEnvironmentsStore.setActiveGlobalEnvironmentUidForWorkspace(
|
||||
workspacePath,
|
||||
generateUidBasedOnHash(envFilePath)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ const _ = require('lodash');
|
||||
const Store = require('electron-store');
|
||||
const { encryptStringSafe, decryptStringSafe } = require('../utils/encryption');
|
||||
const { environmentSchema } = require('@usebruno/schema');
|
||||
const { posixifyPath } = require('../utils/filesystem');
|
||||
|
||||
class GlobalEnvironmentsStore {
|
||||
constructor() {
|
||||
@@ -86,6 +87,36 @@ class GlobalEnvironmentsStore {
|
||||
return this.store.get('activeGlobalEnvironmentUid', null);
|
||||
}
|
||||
|
||||
setActiveGlobalEnvironmentUid(uid) {
|
||||
return this.store.set('activeGlobalEnvironmentUid', uid);
|
||||
}
|
||||
|
||||
getActiveGlobalEnvironmentUidForWorkspace(workspacePath) {
|
||||
if (!workspacePath) return undefined;
|
||||
const key = posixifyPath(workspacePath);
|
||||
const mapping = this.store.get('activeGlobalEnvironmentUidByWorkspace', {});
|
||||
if (key in mapping) {
|
||||
return mapping[key];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
setActiveGlobalEnvironmentUidForWorkspace(workspacePath, uid) {
|
||||
if (!workspacePath) return;
|
||||
const key = posixifyPath(workspacePath);
|
||||
const mapping = this.store.get('activeGlobalEnvironmentUidByWorkspace', {});
|
||||
mapping[key] = uid || null;
|
||||
this.store.set('activeGlobalEnvironmentUidByWorkspace', mapping);
|
||||
}
|
||||
|
||||
removeActiveGlobalEnvironmentUidForWorkspace(workspacePath) {
|
||||
if (!workspacePath) return;
|
||||
const key = posixifyPath(workspacePath);
|
||||
const mapping = this.store.get('activeGlobalEnvironmentUidByWorkspace', {});
|
||||
delete mapping[key];
|
||||
this.store.set('activeGlobalEnvironmentUidByWorkspace', mapping);
|
||||
}
|
||||
|
||||
setGlobalEnvironments(globalEnvironments) {
|
||||
globalEnvironments = this.filterValidEnvironments(globalEnvironments);
|
||||
|
||||
@@ -93,10 +124,6 @@ class GlobalEnvironmentsStore {
|
||||
return this.store.set('environments', globalEnvironments);
|
||||
}
|
||||
|
||||
setActiveGlobalEnvironmentUid(uid) {
|
||||
return this.store.set('activeGlobalEnvironmentUid', uid);
|
||||
}
|
||||
|
||||
addGlobalEnvironment({ uid, name, variables = [], color }) {
|
||||
let globalEnvironments = this.getGlobalEnvironments();
|
||||
const existingEnvironment = globalEnvironments.find((env) => env?.name == name);
|
||||
|
||||
@@ -1,18 +1,11 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const _ = require('lodash');
|
||||
const yaml = require('js-yaml');
|
||||
const { parseEnvironment, stringifyEnvironment } = require('@usebruno/filestore');
|
||||
const { writeFile, createDirectory } = require('../utils/filesystem');
|
||||
const { generateUidBasedOnHash, uuid } = require('../utils/common');
|
||||
const { decryptStringSafe } = require('../utils/encryption');
|
||||
const EnvironmentSecretsStore = require('./env-secrets');
|
||||
const {
|
||||
readWorkspaceConfig,
|
||||
generateYamlContent,
|
||||
writeWorkspaceFileAtomic
|
||||
} = require('../utils/workspace-config');
|
||||
const { withLock, getWorkspaceLockKey } = require('../utils/workspace-lock');
|
||||
|
||||
const environmentSecretsStore = new EnvironmentSecretsStore();
|
||||
|
||||
@@ -98,8 +91,7 @@ class GlobalEnvironmentsManager {
|
||||
|
||||
if (!fs.existsSync(environmentsDir)) {
|
||||
return {
|
||||
globalEnvironments: [],
|
||||
activeGlobalEnvironmentUid: null
|
||||
globalEnvironments: []
|
||||
};
|
||||
}
|
||||
|
||||
@@ -119,58 +111,14 @@ class GlobalEnvironmentsManager {
|
||||
}
|
||||
}
|
||||
|
||||
const activeGlobalEnvironmentUid = await this.getActiveGlobalEnvironmentUid(workspacePath);
|
||||
|
||||
return {
|
||||
globalEnvironments: environments,
|
||||
activeGlobalEnvironmentUid
|
||||
globalEnvironments: environments
|
||||
};
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async getActiveGlobalEnvironmentUid(workspacePath) {
|
||||
try {
|
||||
if (!workspacePath) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const workspaceFilePath = path.join(workspacePath, 'workspace.yml');
|
||||
|
||||
if (!fs.existsSync(workspaceFilePath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const yamlContent = fs.readFileSync(workspaceFilePath, 'utf8');
|
||||
const workspaceConfig = yaml.load(yamlContent);
|
||||
|
||||
return workspaceConfig.activeEnvironmentUid || null;
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async setActiveGlobalEnvironmentUid(workspacePath, environmentUid) {
|
||||
if (!workspacePath) {
|
||||
throw new Error('Workspace path is required');
|
||||
}
|
||||
|
||||
const workspaceFilePath = path.join(workspacePath, 'workspace.yml');
|
||||
|
||||
if (!fs.existsSync(workspaceFilePath)) {
|
||||
throw new Error('Invalid workspace: workspace.yml not found');
|
||||
}
|
||||
|
||||
return withLock(getWorkspaceLockKey(workspacePath), async () => {
|
||||
const workspaceConfig = readWorkspaceConfig(workspacePath);
|
||||
workspaceConfig.activeEnvironmentUid = environmentUid;
|
||||
const yamlOutput = generateYamlContent(workspaceConfig);
|
||||
await writeWorkspaceFileAtomic(workspacePath, yamlOutput);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
async createGlobalEnvironment(workspacePath, { uid, name, variables, color }) {
|
||||
try {
|
||||
if (!workspacePath) {
|
||||
@@ -303,24 +251,6 @@ class GlobalEnvironmentsManager {
|
||||
|
||||
fs.unlinkSync(envFile.filePath);
|
||||
|
||||
const activeGlobalEnvironmentUid = await this.getActiveGlobalEnvironmentUid(workspacePath);
|
||||
if (activeGlobalEnvironmentUid === environmentUid) {
|
||||
await this.setActiveGlobalEnvironmentUid(workspacePath, null);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async selectGlobalEnvironment(workspacePath, { environmentUid }) {
|
||||
try {
|
||||
if (!workspacePath) {
|
||||
throw new Error('Workspace path is required');
|
||||
}
|
||||
|
||||
await this.setActiveGlobalEnvironmentUid(workspacePath, environmentUid);
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
@@ -371,10 +301,6 @@ class GlobalEnvironmentsManager {
|
||||
return this.deleteGlobalEnvironment(workspacePath, params);
|
||||
}
|
||||
|
||||
async selectGlobalEnvironmentByPath(workspacePath, params) {
|
||||
return this.selectGlobalEnvironment(workspacePath, params);
|
||||
}
|
||||
|
||||
async updateGlobalEnvironmentColorByPath(workspacePath, { environmentUid, color }) {
|
||||
return this.updateGlobalEnvironmentColor(workspacePath, environmentUid, color);
|
||||
}
|
||||
|
||||
@@ -272,11 +272,6 @@ const generateYamlContent = (config) => {
|
||||
yamlLines.push('docs: \'\'');
|
||||
}
|
||||
|
||||
if (config.activeEnvironmentUid && typeof config.activeEnvironmentUid === 'string') {
|
||||
yamlLines.push('');
|
||||
yamlLines.push(`activeEnvironmentUid: ${config.activeEnvironmentUid}`);
|
||||
}
|
||||
|
||||
yamlLines.push('');
|
||||
|
||||
return yamlLines.join('\n');
|
||||
|
||||
Reference in New Issue
Block a user