@usebruno/cli
Version:
With Bruno CLI, you can now run your API collections with ease using simple command line commands.
95 lines (82 loc) • 3.7 kB
JavaScript
const chalk = require('chalk');
const constants = require('../constants');
const { GITHUB_DISCUSSION_URL, scriptWritesEnvVar } = require('@usebruno/common/utils');
const collectScriptsFromRequest = (request) => {
if (!request) return [];
return [request.script?.req, request.script?.res, request.tests];
};
/**
* Walks the folder tree and collects scripts only from folders that contain at least one
* request in `runningPaths` — i.e. folders whose scripts will actually execute this run.
* Returns whether the visited subtree contains a running request so parents can include
* their own scripts. A single post-order pass, so each node is visited once.
*/
const collectRunningFolderScripts = (items = [], runningPaths, out) => {
let subtreeHasRunningRequest = false;
for (const item of items) {
if (item?.type === 'folder') {
const childScripts = [];
const folderHasRunningRequest = collectRunningFolderScripts(item.items || [], runningPaths, childScripts);
if (folderHasRunningRequest) {
const folderRoot = item?.draft || item?.root;
out.push(...collectScriptsFromRequest(folderRoot?.request));
out.push(...childScripts);
subtreeHasRunningRequest = true;
}
} else if (runningPaths.has(item?.pathname)) {
subtreeHasRunningRequest = true;
}
}
return subtreeHasRunningRequest;
};
/**
* Detects whether any script that will actually run this invocation calls an env-var write
* API without the `{ persist: false }` opt-out. Only scripts that execute are considered:
* request-level scripts for the requests in the run set, the collection-level script (which
* runs for every executed request), and folder-level scripts for folders that contain a
* request in the run set. Scripts that never run (filtered-out requests/folders, or an empty
* run set) are not scanned.
*/
const detectEnvVarWriteUsage = (requestItems = [], collectionRoot = {}, collection = null) => {
if (!requestItems.length) return false;
const scripts = [];
// Collection-level scripts run for every executed request, and at least one request runs.
scripts.push(...collectScriptsFromRequest(collectionRoot?.request));
// Request-level scripts for the requests in the run set.
for (const item of requestItems) {
scripts.push(...collectScriptsFromRequest(item?.request));
}
// Folder-level scripts, but only for folders an executed request lives under.
if (collection?.items) {
const runningPaths = new Set(requestItems.map((item) => item?.pathname).filter(Boolean));
collectRunningFolderScripts(collection.items, runningPaths, scripts);
}
return scripts.some((code) => scriptWritesEnvVar(code));
};
const printEnvVarWriteWarning = () => {
const yellow = chalk.hex(constants.COLORS.ORANGE);
console.log();
console.log(yellow.bold('⚠️ Heads up: Bruno v4 migration'));
console.log(
chalk.white(
'In v4 (to be released in 3rd week of July), script APIs: bru.setEnvVar(), bru.setGlobalEnvVar(), that set environment variables will write to the disk. If you are using it to set secrets, it could be committed to Git.'
)
);
console.log(
chalk.white('Migrate to bru.setVar() before v4 to keep values runtime-only. Please ignore if already done.')
+ ' '
+ chalk.white('Read more: ' + GITHUB_DISCUSSION_URL)
);
console.log();
};
const maybePrintEnvVarWriteWarning = (requestItems, collectionRoot, collection) => {
if (detectEnvVarWriteUsage(requestItems, collectionRoot, collection)) {
printEnvVarWriteWarning();
}
};
module.exports = {
scriptWritesEnvVar,
detectEnvVarWriteUsage,
printEnvVarWriteWarning,
maybePrintEnvVarWriteWarning
};