Filter requests by tags in bruno-cli

A request is only included in the test run if its tags include at least
one of the include tags and none of the exclude tags specified in the
CLI options.
This commit is contained in:
Antti Sonkeri
2024-07-24 00:10:22 +03:00
parent 259eee184b
commit 540cc234d7
5 changed files with 79 additions and 3 deletions

View File

@@ -6,6 +6,7 @@ const { getRunnerSummary } = require('@usebruno/common/runner');
const { exists, isFile, isDirectory } = require('../utils/filesystem');
const { runSingleRequest } = require('../runner/run-single-request');
const { bruToEnvJson, getEnvVars } = require('../utils/bru');
const { isRequestTagsIncluded } = require("@usebruno/common")
const makeJUnitOutput = require('../reporters/junit');
const makeHtmlOutput = require('../reporters/html');
const { rpad } = require('../utils/common');
@@ -199,6 +200,14 @@ const builder = async (yargs) => {
type:"number",
description: "Delay between each requests (in miliseconds)"
})
.option('tags', {
type: 'string',
description: 'Tags to include in the run'
})
.option('exclude-tags', {
type: 'string',
description: 'Tags to exclude from the run'
})
.example('$0 run request.bru', 'Run a request')
.example('$0 run request.bru --env local', 'Run a request with the environment set to local')
.example('$0 run request.bru --env-file env.bru', 'Run a request with the environment from env.bru file')
@@ -268,7 +277,9 @@ const handler = async function (argv) {
reporterSkipHeaders,
clientCertConfig,
noproxy,
delay
delay,
tags: includeTags,
excludeTags
} = argv;
const collectionPath = process.cwd();
@@ -353,7 +364,7 @@ const handler = async function (argv) {
if (!match) {
console.error(
chalk.red(`Overridable environment variable not correct: use name=value - presented: `) +
chalk.dim(`${value}`)
chalk.dim(`${value}`)
);
process.exit(constants.EXIT_STATUS.ERROR_INCORRECT_ENV_OVERRIDE);
}
@@ -389,6 +400,9 @@ const handler = async function (argv) {
}
options['ignoreTruststore'] = ignoreTruststore;
includeTags = includeTags ? includeTags.split(',') : [];
excludeTags = excludeTags ? excludeTags.split(',') : [];
if (['json', 'junit', 'html'].indexOf(format) === -1) {
console.error(chalk.red(`Format must be one of "json", "junit or "html"`));
process.exit(constants.EXIT_STATUS.ERROR_INCORRECT_OUTPUT_FORMAT);
@@ -444,6 +458,10 @@ const handler = async function (argv) {
console.error(chalk.red(`Path not found: ${resolvedPath}`));
process.exit(constants.EXIT_STATUS.ERROR_FILE_NOT_FOUND);
}
requestItems = requestItems.filter((item) => {
return isRequestTagsIncluded(item.tags, includeTags, excludeTags);
});
}
requestItems = getCallStack(resolvedPaths, collection, { recursive });

View File

@@ -60,6 +60,7 @@ const bruToJson = (bru) => {
type: requestType,
name: _.get(json, 'meta.name'),
seq: !isNaN(sequence) ? Number(sequence) : 1,
tags: _.get(json, 'tags', []),
request: {
method: _.upperCase(_.get(json, 'http.method')),
url: _.get(json, 'http.url'),

View File

@@ -1,2 +1,3 @@
export { mockDataFunctions } from './utils/faker-functions';
export { default as interpolate } from './interpolate';
export {default as interpolate} from './interpolate';
export {default as isRequestTagsIncluded} from './tags';

View File

@@ -0,0 +1,43 @@
import isRequestTagsIncluded from './index';
describe('isRequestTagsIncluded', () => {
it('should include request when it has an included tag', () => {
const requestTags = ['tag1', 'tag2'];
const includeTags = ['tag1'];
const excludeTags: string[] = [];
const result = isRequestTagsIncluded(requestTags, includeTags, excludeTags);
expect(result).toBe(true);
});
it('should include request when included tags is empty', () => {
const requestTags = ['tag1', 'tag2'];
const includeTags: string[] = [];
const excludeTags: string[] = [];
const result = isRequestTagsIncluded(requestTags, includeTags, excludeTags);
expect(result).toBe(true);
});
it('should exclude request when it does not have an included tag', () => {
const requestTags = ['tag1'];
const includeTags = ['tag2'];
const excludeTags: string[] = [];
const result = isRequestTagsIncluded(requestTags, includeTags, excludeTags);
expect(result).toBe(false);
});
it('should exclude request when it has an excluded tag', () => {
const requestTags = ['tag1'];
const includeTags: string[] = [];
const excludeTags = ['tag1'];
const result = isRequestTagsIncluded(requestTags, includeTags, excludeTags);
expect(result).toBe(false);
});
it('should exclude request when it has both included and excluded tag', () => {
const requestTags = ['tag1', 'tag2'];
const includeTags: string[] = ['tag2'];
const excludeTags = ['tag1'];
const result = isRequestTagsIncluded(requestTags, includeTags, excludeTags);
expect(result).toBe(false);
});
});

View File

@@ -0,0 +1,13 @@
/**
* A request should be included if it has at least one tag that is included and no tags that are excluded
* @param requestTags Tags of the request
* @param includeTags Tags to include
* @param excludeTags Tags to exclude
*/
export const isRequestTagsIncluded = (requestTags: string[], includeTags: string[], excludeTags: string[]) => {
const shouldInclude = includeTags.length === 0 || requestTags.some((tag) => includeTags.includes(tag));
const shouldExclude = excludeTags.length > 0 && requestTags.some((tag) => excludeTags.includes(tag));
return shouldInclude && !shouldExclude;
};
export default isRequestTagsIncluded;