From 735c46111640c60da7ea3399b2d71dc14761b62b Mon Sep 17 00:00:00 2001 From: Jitendra Adhikari Date: Thu, 30 Nov 2017 15:28:30 +0700 Subject: [PATCH 01/11] test: collect() --- src/internals.spec.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/internals.spec.js b/src/internals.spec.js index 66513d6..7daa797 100644 --- a/src/internals.spec.js +++ b/src/internals.spec.js @@ -1,6 +1,6 @@ import test from 'ava'; -import {preprocessArgs, parseConfigActions, parseConfig} from './internals'; +import {preprocessArgs, parseConfigActions, parseConfig, collect} from './internals'; test('preprocessArgs() with empty array', t => { t.deepEqual(preprocessArgs(['node.exe', 'cli.js']), { @@ -145,3 +145,10 @@ test('parseConfig()', t => { t.deepEqual(parseConfig(config), expected); }); + +test('collect()', t => { + const memo = []; + + t.deepEqual(collect(1, memo), [1]); + t.deepEqual(collect('a', memo), [1, 'a']); +}); From a5a4ccf3bf4971605213adfa0da66d3e43448550 Mon Sep 17 00:00:00 2001 From: Jitendra Adhikari Date: Thu, 30 Nov 2017 15:45:24 +0700 Subject: [PATCH 02/11] refactor: extract cliOptions exitHandler() [wip][skip ci] --- src/cli.js | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/cli.js b/src/cli.js index 7104933..581f80c 100644 --- a/src/cli.js +++ b/src/cli.js @@ -68,7 +68,7 @@ if (!packageConfig && !doprConfig) { if (typeof packageConfig.file === 'string') { packageConfig.file = [packageConfig.file]; } -if (typeof doprConfig.file === 'string') { +if (doprConfig && typeof doprConfig.file === 'string') { doprConfig.file = [doprConfig.file]; } @@ -130,6 +130,28 @@ cliAction.file.forEach((file, pos) => { dockerComposeFiles.push('--file', file); }); +// Supporting array command so treat anything else as array as well. +if (typeof cliAction.command === 'string') { + cliAction.command = [cliAction.command]; +} + +const cliOptions = { + cwd: basePath, + stdio: 'inherit', + shell: true +}; + +const exitHandler = code => { + if (program.verbose) { + console.log((code > 0 ? chalk.red : chalk.gray)(`command exited with code ${code}`)); + } + + // Pass through exit code + if (code !== 0) { + process.exit(code); + } +}; + // Parse command const cliCommand = cliAction.command .replace('%action%', action || '') @@ -153,18 +175,6 @@ if (program.verbose) { } // Fire! -const childProcess = spawn('docker-compose', cliArgs, { - cwd: basePath, - env, - stdio: 'inherit', - shell: true -}); +const childProcess = spawn('docker-compose', cliArgs, cliOptions); -childProcess.on('close', code => { - if (program.verbose) { - console.log((code > 0 ? chalk.red : chalk.gray)(`command exited with code ${code}`)); - } - - // Pass through exit code - process.exit(code); -}); +childProcess.on('close', exitHandler); From ab52409cf189a5ec82547fea393d4e32fcf36ab7 Mon Sep 17 00:00:00 2001 From: Jitendra Adhikari Date: Thu, 30 Nov 2017 16:02:09 +0700 Subject: [PATCH 03/11] feat: support multiple command(s) as array, enable reusing command with @ prefix --- src/cli.js | 65 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/src/cli.js b/src/cli.js index 581f80c..fe5cf4c 100644 --- a/src/cli.js +++ b/src/cli.js @@ -1,7 +1,7 @@ #!/usr/bin/env node const path = require('path'); -const {spawn} = require('child_process'); +const {spawnSync} = require('child_process'); const program = require('commander'); const chalk = require('chalk'); const deepAssign = require('deep-assign'); @@ -152,29 +152,44 @@ const exitHandler = code => { } }; -// Parse command -const cliCommand = cliAction.command - .replace('%action%', action || '') - .replace('%args%', args.join(' ')) - .split(' '); - -// Args -const user = cliAction.user ? ['--user', cliAction.user] : []; - -const cliArgs = dockerComposeFiles - .concat(cliAction.exec ? ['exec', ...user, cliAction.service] : []) - .concat(cliAction.detached ? ['-d'] : []) - .concat(cliAction.privileged ? ['--privileged'] : []) - .concat(cliAction.index ? ['--index', cliAction.index] : []) - .concat(cliCommand); - -if (program.verbose) { - console.log(chalk.gray('ENV: ' + env)); - console.log(chalk.gray('CWD: ' + basePath)); - console.log(chalk.gray('CMD: docker-compose ' + cliArgs.join(' '))); -} +cliAction.command.forEach(command => { + if (program.verbose) { + console.log(chalk.gray('ENV: ' + env)); + console.log(chalk.gray('CWD: ' + basePath)); + } + + // Is it a reference to another action? + if (command[0] === '@') { + const refArgs = dockerProjectArgs.slice(2).concat(command.substr(1)); + + if (program.verbose) { + console.log(chalk.gray('CMD: dopr ' + refArgs.join(' '))); + } + + // Fire! + return exitHandler(spawnSync('dopr ', refArgs, cliOptions).status); + } -// Fire! -const childProcess = spawn('docker-compose', cliArgs, cliOptions); + // Parse command + const cliCommand = command + .replace('%action%', action || '') + .replace('%args%', args.join(' ')) + .split(' '); -childProcess.on('close', exitHandler); + // Args + const user = cliAction.user ? ['--user', cliAction.user] : []; + + const cliArgs = dockerComposeFiles + .concat(cliAction.exec ? ['exec', ...user, cliAction.service] : []) + .concat(cliAction.detached ? ['-d'] : []) + .concat(cliAction.privileged ? ['--privileged'] : []) + .concat(cliAction.index ? ['--index', cliAction.index] : []) + .concat(cliCommand); + + if (program.verbose) { + console.log(chalk.gray('CMD: docker-compose ' + cliArgs.join(' '))); + } + + // Fire! + exitHandler(spawnSync('docker-compose', cliArgs, cliOptions).status); +}); From 2199cb115427cd6bca38fa9619b062f793fba431 Mon Sep 17 00:00:00 2001 From: Jitendra Adhikari Date: Thu, 30 Nov 2017 16:03:02 +0700 Subject: [PATCH 04/11] docs(readme): add info on running and reusing multiple commands --- readme.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/readme.md b/readme.md index 6df952d..f03c115 100644 --- a/readme.md +++ b/readme.md @@ -17,7 +17,7 @@ Install it globally for quick access Optionally install it locally, to pin down versions if required. - $ npm i --save @crazyfactory/docker-project-cli + $ npm i --save @crazyfactory/docker-project-cli ## Configuration @@ -55,7 +55,16 @@ Default configuration }, "npm": "%action% %args%", "git": "%action% %args%", - "yarn": "%action% %args%" + "yarn": "%action% %args%", + "multiple-cmd": { + "command": ["echo multiple command as array", "@nested-cmd arg1 arg2"] + }, + "nested-cmd": { + "command": ["echo nested command %args%", "@deepnested-cmd --opt1 val1 --opt2 val2"] + }, + "deepnested-cmd": { + "command": ["echo deep nested command %args%"] + } } } ``` @@ -66,6 +75,8 @@ Notes: - The `node` will be launched with the user `node` by default. - This will use a different config if NODE_ENV is set to *production* or if dopr is with `--env production`. - The `"file"` value can be array or string. +- The `"actions"[\d]."command"` can be either array or string. +- The command can be reused or recalled by prefixing it with `@` (see sample above). ## Usage @@ -76,8 +87,8 @@ To start you project in deamon mode run $ dopr up -d -You can similarly use `down` and `stop`, just like you would with `docker-compose` directly. - +You can similarly use `down` and `stop`, just like you would with `docker-compose` directly. + ### custom commands You can add simple custom commands, but we add some by default. They are passed through to the service specified in your dopr configuration. @@ -86,7 +97,7 @@ For instance to open a bash session just run $ dopr bash -You can similarly access `node`, `npm`, `git` and `composer` like so +You can similarly access `node`, `npm`, `git` and `composer` like so $ dopr npm run my-script From 8769820cff021ccb5eb4a410e89e77b339b5a1db Mon Sep 17 00:00:00 2001 From: Jitendra Adhikari Date: Thu, 30 Nov 2017 16:06:22 +0700 Subject: [PATCH 05/11] docs(readme): fix the sample commands --- readme.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/readme.md b/readme.md index f03c115..aff9be3 100644 --- a/readme.md +++ b/readme.md @@ -48,14 +48,14 @@ Default configuration "exec": false }, "bash": "%action% %args%", - "composer": "%action% %args%", + "composer": "composer %action% %args%", "node": { - "command": "%action% %args%", + "command": "node %action% %args%", "user": "node" }, - "npm": "%action% %args%", - "git": "%action% %args%", - "yarn": "%action% %args%", + "npm": "npm %action% %args%", + "git": "git %action% %args%", + "yarn": "yarn %action% %args%", "multiple-cmd": { "command": ["echo multiple command as array", "@nested-cmd arg1 arg2"] }, From d13570d48e910d47b2a3bfb836741de7aee4bf79 Mon Sep 17 00:00:00 2001 From: Jitendra Adhikari Date: Thu, 30 Nov 2017 16:15:39 +0700 Subject: [PATCH 06/11] docs: comment --- src/cli.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cli.js b/src/cli.js index fe5cf4c..891088e 100644 --- a/src/cli.js +++ b/src/cli.js @@ -114,6 +114,7 @@ if (cliAction.exec && !cliAction.service) { const dockerComposeFiles = []; +// Run commands synchronously one after another! cliAction.file.forEach((file, pos) => { file = path.resolve(file); From 114f99ef088e14ef51c78ab9018c21a3c2d45bcf Mon Sep 17 00:00:00 2001 From: Jitendra Adhikari Date: Thu, 30 Nov 2017 17:06:13 +0700 Subject: [PATCH 07/11] feat: host context command --- src/cli.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cli.js b/src/cli.js index 891088e..c23e752 100644 --- a/src/cli.js +++ b/src/cli.js @@ -1,7 +1,7 @@ #!/usr/bin/env node const path = require('path'); -const {spawnSync} = require('child_process'); +const {execSync, spawnSync} = require('child_process'); const program = require('commander'); const chalk = require('chalk'); const deepAssign = require('deep-assign'); @@ -171,6 +171,11 @@ cliAction.command.forEach(command => { return exitHandler(spawnSync('dopr ', refArgs, cliOptions).status); } + // Command is expected to run in host context! + if (cliAction.service === '@host') { + return execSync(command, cliOptions); + } + // Parse command const cliCommand = command .replace('%action%', action || '') From 85bbe51e06f56f9012aa5e6b09e4a3eeaed670d3 Mon Sep 17 00:00:00 2001 From: Jitendra Adhikari Date: Thu, 30 Nov 2017 17:06:31 +0700 Subject: [PATCH 08/11] docs: add info for host context cmd --- readme.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/readme.md b/readme.md index aff9be3..5f6d143 100644 --- a/readme.md +++ b/readme.md @@ -64,6 +64,10 @@ Default configuration }, "deepnested-cmd": { "command": ["echo deep nested command %args%"] + }, + "host-cmd": { + "service": "@host", + "command": "docker-compose version" } } } @@ -77,6 +81,7 @@ Notes: - The `"file"` value can be array or string. - The `"actions"[\d]."command"` can be either array or string. - The command can be reused or recalled by prefixing it with `@` (see sample above). +- The command that should run in host context will need `"service"` value of `"@host"` (see sample above). ## Usage From 1db058b8ba502609e53e029e3dcd11c919ffe7d4 Mon Sep 17 00:00:00 2001 From: Jitendra Adhikari Date: Fri, 1 Dec 2017 09:44:30 +0700 Subject: [PATCH 09/11] docs: fix comments --- src/cli.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cli.js b/src/cli.js index c23e752..39a13fe 100644 --- a/src/cli.js +++ b/src/cli.js @@ -114,7 +114,7 @@ if (cliAction.exec && !cliAction.service) { const dockerComposeFiles = []; -// Run commands synchronously one after another! +// Validate/sanitize all docker-compose files! cliAction.file.forEach((file, pos) => { file = path.resolve(file); @@ -153,6 +153,7 @@ const exitHandler = code => { } }; +// Run commands synchronously one after another! cliAction.command.forEach(command => { if (program.verbose) { console.log(chalk.gray('ENV: ' + env)); From fc9feaa6a8ba5d0f419778886ac145657d608572 Mon Sep 17 00:00:00 2001 From: Jitendra Adhikari Date: Fri, 1 Dec 2017 13:46:56 +0700 Subject: [PATCH 10/11] docs: fix configuration sample --- readme.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/readme.md b/readme.md index 5f6d143..2004d22 100644 --- a/readme.md +++ b/readme.md @@ -21,10 +21,11 @@ Optionally install it locally, to pin down versions if required. ## Configuration - + Configuration of DOPR can be done either via `package.json` under the `dopr` key or with a provided file defaulting to `docker-project.json`. -Default configuration +Sample configuration (based on [default configuration](./src/defaulConfig.json)): + ```json { "file": ["./docker/docker-compose.yml"], @@ -48,14 +49,14 @@ Default configuration "exec": false }, "bash": "%action% %args%", - "composer": "composer %action% %args%", + "composer": "%action% %args%", "node": { - "command": "node %action% %args%", + "command": "%action% %args%", "user": "node" }, - "npm": "npm %action% %args%", - "git": "git %action% %args%", - "yarn": "yarn %action% %args%", + "npm": "%action% %args%", + "git": "%action% %args%", + "yarn": "%action% %args%", "multiple-cmd": { "command": ["echo multiple command as array", "@nested-cmd arg1 arg2"] }, From df2f8e789e274ff416a01d133561d66b860926e7 Mon Sep 17 00:00:00 2001 From: Jitendra Adhikari Date: Fri, 1 Dec 2017 14:49:10 +0700 Subject: [PATCH 11/11] docs: separate default and sample configuration --- readme.md | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/readme.md b/readme.md index 2004d22..97047a5 100644 --- a/readme.md +++ b/readme.md @@ -24,8 +24,7 @@ Optionally install it locally, to pin down versions if required. Configuration of DOPR can be done either via `package.json` under the `dopr` key or with a provided file defaulting to `docker-project.json`. -Sample configuration (based on [default configuration](./src/defaulConfig.json)): - +**Default configuration:** ```json { "file": ["./docker/docker-compose.yml"], @@ -40,6 +39,10 @@ Sample configuration (based on [default configuration](./src/defaulConfig.json)) "command": "%action% %args%", "exec": false }, + "pull": { + "command": "%action% %args%", + "exec": false + }, "start": { "command": "%action% %args%", "exec": false @@ -54,9 +57,28 @@ Sample configuration (based on [default configuration](./src/defaulConfig.json)) "command": "%action% %args%", "user": "node" }, - "npm": "%action% %args%", + "npm": { + "command": "%action% %args%", + "user": "node" + }, "git": "%action% %args%", - "yarn": "%action% %args%", + "yarn": "%action% %args%" + } +} +``` + +*Notes:* +- This will relay `up`, `down`, `start` and `stop` to `docker-compose -f $params$` +- This will add custom commands like `dopr bash ...`, `dopr composer ...` and `dopr optimize` +- The `node` will be launched with the user `node` by default. +- This will use a different config if NODE_ENV is set to *production* or if dopr is with `--env production`. +- The `"file"` value can be array or string. + +**Sample configuration with all usecases:** + +```json +{ + "actions": { "multiple-cmd": { "command": ["echo multiple command as array", "@nested-cmd arg1 arg2"] }, @@ -74,13 +96,8 @@ Sample configuration (based on [default configuration](./src/defaulConfig.json)) } ``` -Notes: -- This will relay `up`, `down`, `start` and `stop` to `docker-compose -f $params$` -- This will add custom commands like `dopr bash ...`, `dopr composer ...` and `dopr optimize` -- The `node` will be launched with the user `node` by default. -- This will use a different config if NODE_ENV is set to *production* or if dopr is with `--env production`. -- The `"file"` value can be array or string. -- The `"actions"[\d]."command"` can be either array or string. +*Notes:* +- The `"actions".[$key]."command"` can be either array or string. - The command can be reused or recalled by prefixing it with `@` (see sample above). - The command that should run in host context will need `"service"` value of `"@host"` (see sample above).