feat(#334): bru cli support for collection headers, auth, scripts and tests

This commit is contained in:
Anoop M D 2023-10-09 08:26:10 +05:30
parent f9f1ca0640
commit 362289b7cd
8 changed files with 96 additions and 19 deletions

12
package-lock.json generated
View File

@ -16691,7 +16691,7 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@usebruno/js": "0.8.0", "@usebruno/js": "0.8.0",
"@usebruno/lang": "0.5.0", "@usebruno/lang": "0.6.0",
"axios": "^1.5.1", "axios": "^1.5.1",
"chai": "^4.3.7", "chai": "^4.3.7",
"chalk": "^3.0.0", "chalk": "^3.0.0",
@ -16771,10 +16771,10 @@
}, },
"packages/bruno-electron": { "packages/bruno-electron": {
"name": "bruno", "name": "bruno",
"version": "v0.21.1", "version": "v0.22.0",
"dependencies": { "dependencies": {
"@usebruno/js": "0.8.0", "@usebruno/js": "0.8.0",
"@usebruno/lang": "0.5.0", "@usebruno/lang": "0.6.0",
"@usebruno/schema": "0.5.0", "@usebruno/schema": "0.5.0",
"about-window": "^1.15.2", "about-window": "^1.15.2",
"axios": "^1.5.1", "axios": "^1.5.1",
@ -17021,7 +17021,7 @@
}, },
"packages/bruno-lang": { "packages/bruno-lang": {
"name": "@usebruno/lang", "name": "@usebruno/lang",
"version": "0.5.0", "version": "0.6.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"arcsecond": "^5.0.0", "arcsecond": "^5.0.0",
@ -20011,7 +20011,7 @@
"version": "file:packages/bruno-cli", "version": "file:packages/bruno-cli",
"requires": { "requires": {
"@usebruno/js": "0.8.0", "@usebruno/js": "0.8.0",
"@usebruno/lang": "0.5.0", "@usebruno/lang": "0.6.0",
"axios": "^1.5.1", "axios": "^1.5.1",
"chai": "^4.3.7", "chai": "^4.3.7",
"chalk": "^3.0.0", "chalk": "^3.0.0",
@ -21135,7 +21135,7 @@
"version": "file:packages/bruno-electron", "version": "file:packages/bruno-electron",
"requires": { "requires": {
"@usebruno/js": "0.8.0", "@usebruno/js": "0.8.0",
"@usebruno/lang": "0.5.0", "@usebruno/lang": "0.6.0",
"@usebruno/schema": "0.5.0", "@usebruno/schema": "0.5.0",
"about-window": "^1.15.2", "about-window": "^1.15.2",
"axios": "^1.5.1", "axios": "^1.5.1",

View File

@ -25,7 +25,7 @@
], ],
"dependencies": { "dependencies": {
"@usebruno/js": "0.8.0", "@usebruno/js": "0.8.0",
"@usebruno/lang": "0.5.0", "@usebruno/lang": "0.6.0",
"axios": "^1.5.1", "axios": "^1.5.1",
"chai": "^4.3.7", "chai": "^4.3.7",
"chalk": "^3.0.0", "chalk": "^3.0.0",

View File

@ -6,7 +6,7 @@ const { exists, isFile, isDirectory } = require('../utils/filesystem');
const { runSingleRequest } = require('../runner/run-single-request'); const { runSingleRequest } = require('../runner/run-single-request');
const { bruToEnvJson, getEnvVars } = require('../utils/bru'); const { bruToEnvJson, getEnvVars } = require('../utils/bru');
const { rpad } = require('../utils/common'); const { rpad } = require('../utils/common');
const { bruToJson, getOptions } = require('../utils/bru'); const { bruToJson, getOptions, collectionBruToJson } = require('../utils/bru');
const { dotenvToJson } = require('@usebruno/lang'); const { dotenvToJson } = require('@usebruno/lang');
const command = 'run [filename]'; const command = 'run [filename]';
@ -121,6 +121,9 @@ const getBruFilesRecursively = (dir) => {
const currentDirBruJsons = []; const currentDirBruJsons = [];
for (const file of filesInCurrentDir) { for (const file of filesInCurrentDir) {
if (['collection.bru', 'folder.bru'].includes(file)) {
continue;
}
const filePath = path.join(currentPath, file); const filePath = path.join(currentPath, file);
const stats = fs.lstatSync(filePath); const stats = fs.lstatSync(filePath);
@ -151,6 +154,19 @@ const getBruFilesRecursively = (dir) => {
return getFilesInOrder(dir); return getFilesInOrder(dir);
}; };
const getCollectionRoot = (dir) => {
const collectionRootPath = path.join(dir, 'collection.bru');
const exists = fs.existsSync(collectionRootPath);
if (!exists) {
return {};
}
const content = fs.readFileSync(collectionRootPath, 'utf8');
const json = collectionBruToJson(content);
return json;
};
const builder = async (yargs) => { const builder = async (yargs) => {
yargs yargs
.option('r', { .option('r', {
@ -210,6 +226,7 @@ const handler = async function (argv) {
const brunoConfigFile = fs.readFileSync(brunoJsonPath, 'utf8'); const brunoConfigFile = fs.readFileSync(brunoJsonPath, 'utf8');
const brunoConfig = JSON.parse(brunoConfigFile); const brunoConfig = JSON.parse(brunoConfigFile);
const collectionRoot = getCollectionRoot(collectionPath);
if (filename && filename.length) { if (filename && filename.length) {
const pathExists = await exists(filename); const pathExists = await exists(filename);
@ -349,7 +366,8 @@ const handler = async function (argv) {
collectionVariables, collectionVariables,
envVars, envVars,
processEnvVars, processEnvVars,
brunoConfig brunoConfig,
collectionRoot
); );
results.push(result); results.push(result);

View File

@ -1,9 +1,20 @@
const { get, each, filter } = require('lodash'); const { get, each, filter } = require('lodash');
const decomment = require('decomment'); const decomment = require('decomment');
const prepareRequest = (request) => { const prepareRequest = (request, collectionRoot) => {
const headers = {}; const headers = {};
let contentTypeDefined = false; let contentTypeDefined = false;
// collection headers
each(get(collectionRoot, 'request.headers', []), (h) => {
if (h.enabled) {
headers[h.name] = h.value;
if (h.name.toLowerCase() === 'content-type') {
contentTypeDefined = true;
}
}
});
each(request.headers, (h) => { each(request.headers, (h) => {
if (h.enabled) { if (h.enabled) {
headers[h.name] = h.value; headers[h.name] = h.value;
@ -20,6 +31,23 @@ const prepareRequest = (request) => {
}; };
// Authentication // Authentication
// A request can override the collection auth with another auth
// But it cannot override the collection auth with no auth
// We will provide support for disabling the auth via scripting in the future
const collectionAuth = get(collectionRoot, 'request.auth');
if (collectionAuth) {
if (collectionAuth.mode === 'basic') {
axiosRequest.auth = {
username: get(collectionAuth, 'basic.username'),
password: get(collectionAuth, 'basic.password')
};
}
if (collectionAuth.mode === 'bearer') {
axiosRequest.headers['authorization'] = `Bearer ${get(collectionAuth, 'bearer.token')}`;
}
}
if (request.auth) { if (request.auth) {
if (request.auth.mode === 'basic') { if (request.auth.mode === 'basic') {
axiosRequest.auth = { axiosRequest.auth = {

View File

@ -1,8 +1,9 @@
const os = require('os');
const qs = require('qs'); const qs = require('qs');
const chalk = require('chalk'); const chalk = require('chalk');
const decomment = require('decomment'); const decomment = require('decomment');
const fs = require('fs'); const fs = require('fs');
const { forOwn, each, extend, get } = require('lodash'); const { forOwn, each, extend, get, compact } = require('lodash');
const FormData = require('form-data'); const FormData = require('form-data');
const prepareRequest = require('./prepare-request'); const prepareRequest = require('./prepare-request');
const interpolateVars = require('./interpolate-vars'); const interpolateVars = require('./interpolate-vars');
@ -23,7 +24,8 @@ const runSingleRequest = async function (
collectionVariables, collectionVariables,
envVariables, envVariables,
processEnvVars, processEnvVars,
brunoConfig brunoConfig,
collectionRoot
) { ) {
try { try {
let request; let request;
@ -58,7 +60,10 @@ const runSingleRequest = async function (
} }
// run pre request script // run pre request script
const requestScriptFile = get(bruJson, 'request.script.req'); const requestScriptFile = compact([
get(collectionRoot, 'request.script.req'),
get(bruJson, 'request.script.req')
]).join(os.EOL);
if (requestScriptFile && requestScriptFile.length) { if (requestScriptFile && requestScriptFile.length) {
const scriptRuntime = new ScriptRuntime(); const scriptRuntime = new ScriptRuntime();
await scriptRuntime.runRequestScript( await scriptRuntime.runRequestScript(
@ -208,7 +213,10 @@ const runSingleRequest = async function (
} }
// run post response script // run post response script
const responseScriptFile = get(bruJson, 'request.script.res'); const responseScriptFile = compact([
get(collectionRoot, 'request.script.res'),
get(bruJson, 'request.script.res')
]).join(os.EOL);
if (responseScriptFile && responseScriptFile.length) { if (responseScriptFile && responseScriptFile.length) {
const scriptRuntime = new ScriptRuntime(); const scriptRuntime = new ScriptRuntime();
await scriptRuntime.runResponseScript( await scriptRuntime.runResponseScript(
@ -250,7 +258,7 @@ const runSingleRequest = async function (
// run tests // run tests
let testResults = []; let testResults = [];
const testFile = get(bruJson, 'request.tests'); const testFile = compact([get(collectionRoot, 'request.tests'), get(bruJson, 'request.tests')]).join(os.EOL);
if (typeof testFile === 'string') { if (typeof testFile === 'string') {
const testRuntime = new TestRuntime(); const testRuntime = new TestRuntime();
const result = await testRuntime.runTests( const result = await testRuntime.runTests(
@ -296,6 +304,7 @@ const runSingleRequest = async function (
testResults testResults
}; };
} catch (err) { } catch (err) {
console.log(chalk.red(stripExtension(filename)) + chalk.dim(` (${err.message})`));
return { return {
request: { request: {
method: null, method: null,

View File

@ -1,12 +1,33 @@
const _ = require('lodash'); const _ = require('lodash');
const Mustache = require('mustache'); const Mustache = require('mustache');
const { bruToEnvJsonV2, bruToJsonV2 } = require('@usebruno/lang'); const { bruToEnvJsonV2, bruToJsonV2, collectionBruToJson: _collectionBruToJson } = require('@usebruno/lang');
// override the default escape function to prevent escaping // override the default escape function to prevent escaping
Mustache.escape = function (value) { Mustache.escape = function (value) {
return value; return value;
}; };
const collectionBruToJson = (bru) => {
try {
const json = _collectionBruToJson(bru);
const transformedJson = {
request: {
params: _.get(json, 'query', []),
headers: _.get(json, 'headers', []),
auth: _.get(json, 'auth', {}),
script: _.get(json, 'script', {}),
vars: _.get(json, 'vars', {}),
tests: _.get(json, 'tests', '')
}
};
return transformedJson;
} catch (error) {
return Promise.reject(error);
}
};
/** /**
* The transformer function for converting a BRU file to JSON. * The transformer function for converting a BRU file to JSON.
* *
@ -91,5 +112,6 @@ module.exports = {
bruToJson, bruToJson,
bruToEnvJson, bruToEnvJson,
getEnvVars, getEnvVars,
getOptions getOptions,
collectionBruToJson
}; };

View File

@ -15,7 +15,7 @@
}, },
"dependencies": { "dependencies": {
"@usebruno/js": "0.8.0", "@usebruno/js": "0.8.0",
"@usebruno/lang": "0.5.0", "@usebruno/lang": "0.6.0",
"@usebruno/schema": "0.5.0", "@usebruno/schema": "0.5.0",
"about-window": "^1.15.2", "about-window": "^1.15.2",
"axios": "^1.5.1", "axios": "^1.5.1",

View File

@ -1,6 +1,6 @@
{ {
"name": "@usebruno/lang", "name": "@usebruno/lang",
"version": "0.5.0", "version": "0.6.0",
"license": "MIT", "license": "MIT",
"main": "src/index.js", "main": "src/index.js",
"files": [ "files": [