๐ฅ No BASH-fu is required anymore!
Everyone โค๏ธ npm scripts. However, when you need to use conditionals, loops, regexp and parsers in your scripts, you end up writing JavaScript.
runok gives you a tool to transform your JavaScript scripts into CLI commands.
Each exported function will be a command which can be executed from CLI. You can use full power of JavaScript & bundled tasks like:
- exec
- git
- npmRun
- npx
- ...and others
Write a CommonJS module that exports commands per function.
- Each argument of function will be an argument of a command
- If you provide
options
argument, with default value of an object, this will declate options.
#!/usr/bin/env node
const {
tasks: { git, exec, npx },
runok
} = require('runok');
module.exports = {
async deploy(env = 'prod') {
await this.test();
await git(cmd => {
cmd.add('-A');
cmd.commit('releasing');
cmd.pull();
cmd.push();
});
await exec(`ansible-playbook deploy.yml -i hosts ${env}`);
}
async test() {
await npx('mocha');
},
}
if (require.main === module) runok(module.exports);
- Run
./runok
to list all available commands - Run
./runok deploy
to run a deploy script - Run
./runok deploy staging
to run a deploy script to staging
npm i runok --save
Create a new runok
scripts file:
npx runok init
Each exported function of this file will be command.
When file is created execute runok script to see all available commands:
./runok.js
Edit runok.js
file.
-
Add async function to
module.exports
-
Name a function, function name will be transformed for CLI format:
myFunctionName => my:function-name
-
Define function parameters:
- function arguments will be used as command arguments
- the last argument with object type will is set of options:
// function definition:
async runMe(arg1, arg1, { print: false, retries: 3 })
๐
./runok.js run:me value1 value2 --print --retries 1
- Add a description of a command as the first comment in a function
async runMe() {
// executes very important command
}
๐
โ ./runok.js
Usage: <command> [options]
Options:
-V, --version output the version number
-h, --help output usage information
Commands:
run:me executes very important command
- Import required tasks from
runok
package. - Implement your script!
Export your runok scripts into your current package.json:
./runok export:npm
Runok has a set of built-in tasks.
They can be imported in runio script via tasks
property of runok
:
const {
tasks: {
exec, writeToFile, npm
}
} = require('runok');
Executes npm script
await npmRun('deploy');
command
config
ExecConfig
Returns Promise<Result>
Executes npx script
await npx('create-codeceptjs .');
command
config
ExecConfig
Returns Promise<Result>
Copies file or directory. copySync from 'fs-extra' is used.
copy('src/', 'dst/');
Provides flexible interface to running multiple git commands:
await git(cmd => {
cmd.pull();
cmd.commit('-m updated');
cmd.push();
})
cmd.init
cmd.tag
cmd.branch
cmd.commit
cmd.pull
cmd.push
cmd.add
cmd.clone
cmd.cloneShallow
configFn
gitConfigType
Returns Promise<Result>
Executes shell command and returns a promise.
await exec('ls -ll');
A second parameter can be used to pass in ExecOptions from "child_process" module:
await exec('rails s', { env: { RAILS_ENV: 'production' } })
To hide output pass in output: false
:
await exec('docker build', { output: false });
command
stringconfig
execConfigType?
Returns Promise<Result>
Writes a data to file.
Takes file name as first argument and config function as second.
writeToFile('blog-post.md', cfg => {
cfg.line('---');
cfg.line('title: My blogpost');
cfg.line('---');
cfg.line();
cfg.textFromFile('blog-post.txt');
cfg.text += '// copyright by me';
});
A second argument is a config function that passes in an object for text manipulation.
cfg.text
- string to be written to filecfg.textFromFile(file)
- loads a file and append its context to textcfg.line(text)
- appends a string to a text with "\n" aftercfg.append(text)
- appends a string to a text
file
stringconfigFn
writeToFileCallback
Returns Result
Extends TaskConfig
Git Config Class
tag
Commit params
message
(optional, default''
)
branch
(optional, default''
)
Initialize git repository
params
(optional, default''
)
url
path
command
params
Executes npm script
await npmRun('deploy');
command
config
ExecConfig
Returns Promise<Result>
Executes npx script
await npx('create-codeceptjs .');
command
config
ExecConfig
Returns Promise<Result>
Copies file or directory. copySync from 'fs-extra' is used.
copy('src/', 'dst/');
Writes a data to file.
Takes file name as first argument and config function as second.
writeToFile('blog-post.md', cfg => {
cfg.line('---');
cfg.line('title: My blogpost');
cfg.line('---');
cfg.line();
cfg.textFromFile('blog-post.txt');
cfg.text += '// copyright by me';
});
A second argument is a config function that passes in an object for text manipulation.
cfg.text
- string to be written to filecfg.textFromFile(file)
- loads a file and append its context to textcfg.line(text)
- appends a string to a text with "\n" aftercfg.append(text)
- appends a string to a text
file
stringconfigFn
writeToFileCallback
Returns Result
Tasks in runok use similar API and must follow conventions to match the output:
- task must be a function
- task must return Result instance (or Promise)
Result.start
must be called in the beginning of a function, to create result objectresult.success
must be called on finishresult.error(err)
must be called on failure
const { Result } = require('runok');
module.exports = myTask(arg1, options) {
const result = Result.start("Task Name", `argument: ${arg1}`);
try {
// do something
} catch (err) {
return result.error(err);
}
return result.success();
}
If you want to extend current task, for instamce add custom wrapper to exec
command you can check npx command as an example.
Similar way you can create a task for running Docker scripts:
const { tasks: { exec } } = require('runok');
module.exports = (command, config) => {
return exec(command, baseCfg => {
baseCfg.TASK = 'docker'; // name of task
baseCfg.prefix('docker'); // prefix to an executed command
baseCfg.apply(config);
});
}
Changes directory for commands executed in callback function.
// copy file in "base" directory
chdir('./base', () => copy('a.txt', 'b.txt')));
workDir
stringcallback
CallableFunction
Returns Promise<any>
Prevents execution of next tasks on fail:
stopOnFail();
Ignore failures and continue:
stopOnFail(false);
stop
boolean (optional, defaulttrue
)
Created by Michael Bodnarchuk @davertmik.
Inspired by Robo PHP Task Runner