From f759f85fa4da4a5791c18efb9a691e0cbfd0ad7d Mon Sep 17 00:00:00 2001 From: 0xIslamTaha Date: Fri, 8 Apr 2022 13:19:37 +0200 Subject: [PATCH] feat(options): user can set the dockerComposeOptions into the orechestrato.json config file (#21) feat(options): user can set the dockerComposeOptions into the orechestrato.json config file (#21) --- package.json | 2 +- readme.md | 18 ++++--- src/logger.js | 2 +- src/orchestrator.js | 71 ++++++++++++++++---------- src/{config.json => orchestrator.json} | 11 ++-- 5 files changed, 66 insertions(+), 38 deletions(-) rename src/{config.json => orchestrator.json} (71%) diff --git a/package.json b/package.json index 5186c3a..91ac138 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@0xislamtaha/orchestrator", - "version": "2.0.3", + "version": "2.1.0", "description": "Execute cypress specs in parallel across multiple docker containers", "main": "src/orchestrator.js", "scripts": { diff --git a/readme.md b/readme.md index 62ba1d8..714bd64 100644 --- a/readme.md +++ b/readme.md @@ -23,11 +23,11 @@ Check the following repo as a public use case. * Generate one HTML report that has all specs execution results. * Analyse the execution time for each spec. * Generate the execution time reports per browser under ExecutionTimeReport dir. -* In the next run, The orchestrator It will split the test cases based on this execution time report to reduce the exeuction time. +* In the next run, The orchestrator will split the test cases based on this execution time report to reduce the execution time. ## 🏹 The Splitting mechanism: -The orchestrator can measure and report the execution time for each spec per browser. It will report it as `mochawesome-report/specsExecutionTime-chrome.json` file. If you provided this path as `specsExecutionTimePath` in the next run, The orchestrator will split the specs based on its execution time to minimize the total execution time 🚀. +The orchestrator can measure and report the execution time for each spec per browser. It will report it as `mochawesome-report/specsExecutionTime-chrome.json` file. If you provided this path as `specsExecutionTimePath` in the next run, The orchestrator will split the specs-based on its execution time to minimize the total execution time 🚀. ## ⌨️ Operating Systems: - Linux: working out of the box. @@ -75,7 +75,7 @@ services: } ``` -3- Edit the orchestrator [configuration file](/src/config.json) with your configuration. Here is the description of each configuration option. +3- Edit the orchestrator [configuration file](/src/orchestrator.json) with your configuration. Here is the description of each configuration option. ``` - parallelizm: @@ -103,6 +103,11 @@ services: type: list example: ["ls -al", "mkdir -p test"], +- dockerComposeOptions: + description: docker-compose options to be passed to the docker-compose commands + type: dict + example: {"-p": "project_name"} + - dockerComposePath: description: path to the docker compose file. type: string @@ -149,12 +154,12 @@ services: * With your configuration file ```bash -npx orchestrator --config "/path/to/config.json" +npx orchestrator --config "/path/to/orchestrator.json" ``` -* You can **overwrite** any configuration param on the fly, simplly path the new configuration as a prameter. +* You can **overwrite** any configuration param on the fly, simply pass the new configuration as a parameter. ```bash -npx orchestrator --config ./src/config.json --parallelizm 2 --environment '{"DOCKER_TAG":"master_283"}' --browsers "[chrome, firefox]" --specs "[alerts.js, avatar.js]" +npx orchestrator --config ./src/orchestrator.json --parallelizm 2 --environment '{"DOCKER_TAG":"master_283"}' --browsers "[chrome, firefox]" --specs "[alerts.js, avatar.js]" ``` ## 📖 Reports: @@ -165,6 +170,5 @@ The orchestrator generates two reports by default: ## 🎬 To-Do: -* Export COMPOSE_PROJECT_NAME with random value if it doesn't exist. * list configuration rather than multiple files for multiple test suites. * Provide --help option. diff --git a/src/logger.js b/src/logger.js index b84adc9..1e7742c 100644 --- a/src/logger.js +++ b/src/logger.js @@ -5,7 +5,7 @@ function banner() { ██ ██ ██████ ██ ███████ █████ ███████ ██ ██████ ███████ ██ ██ ██ ██████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██████ ██ ██ ██████ ██ ██ ███████ ███████ ██ ██ ██ ██ ██ ██ ██████ ██ ██ - v 2.0.3 @0xIslamTaha + v 2.1.0 @0xIslamTaha `; console.log(banner); diff --git a/src/orchestrator.js b/src/orchestrator.js index 52b9f94..d44d424 100644 --- a/src/orchestrator.js +++ b/src/orchestrator.js @@ -12,13 +12,18 @@ import { orderBasedOnBrowserDuration, } from "./helper.js"; import * as lg from "./logger"; -import { checkRequirements } from "./checker"; - +import { checkRequirements } from "./checker"; const executionTimeReportDir = "executionTimeReport"; -const executionTimeReportDirPath = path.resolve(process.cwd(), executionTimeReportDir) -const executiontimeReportJson = "specsExecutionTime.json" -const executiontimeReportJsonPath = path.join(executionTimeReportDirPath, executiontimeReportJson) +const executionTimeReportDirPath = path.resolve( + process.cwd(), + executionTimeReportDir +); +const executiontimeReportJson = "specsExecutionTime.json"; +const executiontimeReportJsonPath = path.join( + executionTimeReportDirPath, + executiontimeReportJson +); function execa(command, flag = true) { return new Promise((resolve, reject) => @@ -78,8 +83,8 @@ function parseArgumentsIntoConfig(rawArgs) { } function overWriteConfig(args) { - lg.step('Overwrite the config file with the arguments if there is any', true); - const configFile = args["--config"] || path.resolve(__dirname, "config.json"); + lg.step("Overwrite the config file with the arguments if there is any", true); + const configFile = args["--config"] || path.resolve(__dirname, "orchestrator.json"); const defaultConfig = JSON.parse(fs.readFileSync(configFile, "utf-8")); const config = { ...defaultConfig, ...args }; return config; @@ -102,13 +107,23 @@ function execPreCommands(config) { }); } +function extractDockerComposeOptions(config) { + let dockerComposeOptions = ""; + Object.keys(config.dockerComposeOptions).forEach((option) => { + dockerComposeOptions = `${dockerComposeOptions} ${option} ${config.dockerComposeOptions[option]}`; + }); + return dockerComposeOptions; +} + function getListOfSpecs(config, browser) { let existingSpecs = []; if (config.specs.length > 0) { existingSpecs = [...config.specs]; } else { - existingSpecs = sh.ls('-R', config.specsHomePath).filter((val) => val.match(/.*ts|js/)); + existingSpecs = sh + .ls("-R", config.specsHomePath) + .filter((val) => val.match(/.*ts|js/)); } if (checkFileIsExisting(executiontimeReportJsonPath)) { @@ -216,13 +231,14 @@ function upConrainters(config) { let commands = []; let [container_name, command] = ["", ""]; let bashCommands = _constructCypressCommands(config); + let dockerComposeOptions = extractDockerComposeOptions(config); bashCommands.forEach((cmd) => { container_name = `container_${Math.floor( Math.random() * 100000 )}__${bashCommands.indexOf(cmd)}`; - command = `timeout --preserve-status ${config.timeout} docker-compose -f ${config.dockerComposePath} run --name ${container_name} ${config.cypressContainerName} bash -c '${cmd}'`; + command = `timeout --preserve-status ${config.timeout} docker-compose ${dockerComposeOptions} -f ${config.dockerComposePath} run --name ${container_name} ${config.cypressContainerName} bash -c '${cmd}'`; commands.push(command); lg.subStep(`~$ ${command}`); promises.push(execa(command)); @@ -232,29 +248,31 @@ function upConrainters(config) { } function downContainers(config) { + let dockerComposeOptions = extractDockerComposeOptions(config); lg.step("Stop the cypress containers", true); - let dockerComposeDown = `docker-compose -f ${config.dockerComposePath} down`; + let dockerComposeDown = `docker-compose ${dockerComposeOptions} -f ${config.dockerComposePath} down`; sh.exec(dockerComposeDown); } function generateReport(config) { lg.step("Generate the reports", true); return merge({ files: [config.mochawesomeJSONPath] }) - .then((report) =>{ + .then((report) => { lg.subStep(`HTML report: ${config.reportPath}/mochawesome.html`); marge.create(report, { reportDir: config.reportPath, charts: true, saveJson: true, - }) - + }); }) .then(() => { if (config.analyseReport) { - if (!fs.existsSync(executionTimeReportDirPath)){ + if (!fs.existsSync(executionTimeReportDirPath)) { sh.mkdir(executionTimeReportDirPath); } - lg.subStep(`Execution time report: ${executionTimeReportDir}/${executiontimeReportJson}`); + lg.subStep( + `Execution time report: ${executionTimeReportDir}/${executiontimeReportJson}` + ); _analyseReport(config); } }); @@ -296,15 +314,16 @@ export async function orchestrator(rawArgs) { setEnvVars(config); execPreCommands(config); - Promise.allSettled(upConrainters(config)) - .then(promises => { - afterPromises(config, orchestratorTime); - const failedPromises = promises.filter(promise => promise.status === 'rejected'); - if(failedPromises.length){ - setTimeout(() => { - lg.step('Exit code: 1'); - sh.exit(1); - }, 5000); - } - }); + Promise.allSettled(upConrainters(config)).then((promises) => { + afterPromises(config, orchestratorTime); + const failedPromises = promises.filter( + (promise) => promise.status === "rejected" + ); + if (failedPromises.length) { + setTimeout(() => { + lg.step("Exit code: 1"); + sh.exit(1); + }, 5000); + } + }); } diff --git a/src/config.json b/src/orchestrator.json similarity index 71% rename from src/config.json rename to src/orchestrator.json index 7601328..8e7a798 100644 --- a/src/config.json +++ b/src/orchestrator.json @@ -1,13 +1,18 @@ { - "parallelizm": 1, + "parallelizm": 2, "browsers": ["chrome", "firefox"], "timeout": "20m", "environment": { "DOCKER_TAG": "master_283" }, "preCommands": [ - "docker-compose -f /opt/code/github/design-system/cypress.docker-compose.yml up -d cloud_fe_components" + "echo 'START ORCHESTRATOR'", + "rm -rf cypress/report/* #Remove the old reports", + "mkdir -p mochawesome-report" ], + "dockerComposeOptions": { + "-p": "orchestator_public_use_case_project_name" + }, "dockerComposePath": "/opt/code/github/design-system/cypress.docker-compose.yml", "specsHomePath": "/opt/code/github/design-system/tests/cypress/storybook/", "specsDockerPath": "tests/cypress/storybook/", @@ -15,6 +20,6 @@ "mochawesomeJSONPath": "/opt/code/github/design-system/tests/report/mochawesome-report/*.json", "reportPath": "mochawesome-report", "specs": [], - "analyseReport": false, + "analyseReport": true, "specsExecutionTimePath": "mochawesome-report/specsExecutionTime-chrome.json" }