diff --git a/packages/bruno-cli/readme.md b/packages/bruno-cli/readme.md index db41a4d7c..1eedb839d 100644 --- a/packages/bruno-cli/readme.md +++ b/packages/bruno-cli/readme.md @@ -44,6 +44,22 @@ If you need to collect the results of your API tests, you can specify the --outp bru run folder --output results.json ``` +## Scripting + +Bruno cli returns the following exit status codes: + +- `0` -- execution successful +- `1` -- an assertion, test, or request in the executed collection failed +- `2` -- the specified output directory does not exist +- `3` -- the request chain seems to loop endlessly +- `4` -- bru was called outside of a colection root directory +- `5` -- the specified input file does not exist +- `6` -- the specified environment does not exist +- `7` -- the environment override was not a string or object +- `8` -- an environment override is malformed +- `9` -- an invalid output format was requested +- `255` -- another error occured + ## Demo ![demo](assets/images/cli-demo.png) @@ -57,6 +73,7 @@ Thank you for using Bruno CLI! ## Changelog + See [https://github.com/usebruno/bruno/releases](https://github.com/usebruno/bruno/releases) ## License diff --git a/packages/bruno-cli/src/commands/run.js b/packages/bruno-cli/src/commands/run.js index 1d95afc75..00f592bd2 100644 --- a/packages/bruno-cli/src/commands/run.js +++ b/packages/bruno-cli/src/commands/run.js @@ -10,6 +10,7 @@ const makeHtmlOutput = require('../reporters/html'); const { rpad } = require('../utils/common'); const { bruToJson, getOptions, collectionBruToJson } = require('../utils/bru'); const { dotenvToJson } = require('@usebruno/lang'); +const constants = require('../constants'); const command = 'run [filename]'; const desc = 'Run a request'; @@ -255,7 +256,7 @@ const handler = async function (argv) { const brunoJsonExists = await exists(brunoJsonPath); if (!brunoJsonExists) { console.error(chalk.red(`You can run only at the root of a collection`)); - return; + process.exit(constants.EXIT_STATUS.ERROR_NOT_IN_COLLECTION); } const brunoConfigFile = fs.readFileSync(brunoJsonPath, 'utf8'); @@ -266,7 +267,7 @@ const handler = async function (argv) { const pathExists = await exists(filename); if (!pathExists) { console.error(chalk.red(`File or directory ${filename} does not exist`)); - return; + process.exit(constants.EXIT_STATUS.ERROR_FILE_NOT_FOUND); } } else { filename = './'; @@ -282,7 +283,7 @@ const handler = async function (argv) { if (!envPathExists) { console.error(chalk.red(`Environment file not found: `) + chalk.dim(`environments/${env}.bru`)); - return; + process.exit(constants.EXIT_STATUS.ERROR_ENV_NOT_FOUND); } const envBruContent = fs.readFileSync(envFile, 'utf8'); @@ -299,7 +300,7 @@ const handler = async function (argv) { processVars = envVar; } else { console.error(chalk.red(`overridable environment variables not parsable: use name=value`)); - return; + process.exit(constants.EXIT_STATUS.ERROR_MALFORMED_ENV_OVERRIDE); } if (processVars && Array.isArray(processVars)) { for (const value of processVars.values()) { @@ -310,7 +311,7 @@ const handler = async function (argv) { chalk.red(`Overridable environment variable not correct: use name=value - presented: `) + chalk.dim(`${value}`) ); - return; + process.exit(constants.EXIT_STATUS.ERROR_INCORRECT_ENV_OVERRIDE); } envVars[match[1]] = match[2]; } @@ -339,7 +340,7 @@ const handler = async function (argv) { if (['json', 'junit', 'html'].indexOf(format) === -1) { console.error(chalk.red(`Format must be one of "json", "junit or "html"`)); - return; + process.exit(constants.EXIT_STATUS.ERROR_INCORRECT_OUTPUT_FORMAT); } // load .env file at root of collection if it exists @@ -451,7 +452,7 @@ const handler = async function (argv) { nJumps++; if (nJumps > 10000) { console.error(chalk.red(`Too many jumps, possible infinite loop`)); - process.exit(1); + process.exit(constants.EXIT_STATUS.ERROR_INFINTE_LOOP); } if (nextRequestName === null) { break; @@ -477,7 +478,7 @@ const handler = async function (argv) { const outputDirExists = await exists(outputDir); if (!outputDirExists) { console.error(chalk.red(`Output directory ${outputDir} does not exist`)); - process.exit(1); + process.exit(constants.EXIT_STATUS.ERROR_MISSING_OUTPUT_DIR); } const outputJson = { @@ -497,12 +498,12 @@ const handler = async function (argv) { } if (summary.failedAssertions + summary.failedTests + summary.failedRequests > 0) { - process.exit(1); + process.exit(constants.EXIT_STATUS.ERROR_FAILED_COLLECTION); } } catch (err) { console.log('Something went wrong'); console.error(chalk.red(err.message)); - process.exit(1); + process.exit(constants.EXIT_STATUS.ERROR_GENERIC); } }; diff --git a/packages/bruno-cli/src/constants.js b/packages/bruno-cli/src/constants.js index a952f893b..6d0f877d7 100644 --- a/packages/bruno-cli/src/constants.js +++ b/packages/bruno-cli/src/constants.js @@ -3,7 +3,32 @@ const { version } = require('../package.json'); const CLI_EPILOGUE = `Documentation: https://docs.usebruno.com (v${version})`; const CLI_VERSION = version; +// Exit codes +const EXIT_STATUS = { + // One or more assertions, tests, or requests failed + ERROR_FAILED_COLLECTION: 1, + // The specified output dir does not exist + ERROR_MISSING_OUTPUT_DIR: 2, + // request chain caused an endless loop + ERROR_INFINTE_LOOP: 3, + // bru was called outside of a collection root + ERROR_NOT_IN_COLLECTION: 4, + // The specified file was not found + ERROR_FILE_NOT_FOUND: 5, + // The specified environment was not found + ERROR_ENV_NOT_FOUND: 6, + // Environment override not presented as string or object + ERROR_MALFORMED_ENV_OVERRIDE: 7, + // Environment overrides format incorrect + ERROR_INCORRECT_ENV_OVERRIDE: 8, + // Invalid output format requested + ERROR_INCORRECT_OUTPUT_FORMAT: 9, + // Everything else + ERROR_GENERIC: 255, +}; + module.exports = { CLI_EPILOGUE, - CLI_VERSION + CLI_VERSION, + EXIT_STATUS };