ezrun v1.0.0-alpha.26
ezrun
A platform helps to run everythings base on a yaml script file
Installation
Install via npm
npm install -g ezrun
Install via yarn
yarn global add ezrun
Run a scene
Run a scene file
r $PATH_TO_SCENE_FILE
Run a encrypted scene file with a password
r $PATH_TO_SCENE_FILE $PASSWORD
Override env variables then run
r -e "port=80" -e "log=error" -- $PATH_TO_SCENE_FILE
CLI
Show helps
r -h
Upgrade external tags which are auto installed when lacks in the scene
r up ezrun-telegram@latest
Customize source paths which are registed tags in application
r --tagDirs /myapp1 --tagDirs /myapp2 -- myapp.yaml # "/myapp1", "/myapp2" are includes source code
Example
- Create a scene file at
test.yaml
title: Test scene
runs:
- Hello world
- Run
r test.yaml
Common tags which is used in the program
Tags | Description |
---|---|
md'doc | Generate comment in a file to document |
echo | Print to console screen |
clear | Clear console screen |
exec | Execute a program |
exec'js | Execute a nodejs code |
exec'sh | Execute a shell script |
exit | Stop then quit the program |
file'read | Read a file then load data into a variable |
file'store | Store data to file |
file'write | Write data to file |
group | Group elements |
http'del | Send a http request with DELETE method |
http'get | Send a http request with GET method |
http'head | Send a http request with HEAD method |
http'patch | Send a http request with PATCH method |
http'post | Send a http request with POST method |
http'put | Send a http request with PUT method |
http/jobs | Create a jobs queue to do something step by step |
http/jobs'add | Add a job to the queue |
http/jobs'stop | Stop the jobs queue |
input'confirm | Get user confirm (yes/no) |
input'multiselect | Suggest a list of choices for user then allow pick multiple choices |
input'number | Get user input from keyboard then convert to number |
input'password | Get user input from keyboard but hide them then convert to text |
input'select | Suggest a list of choices for user then allow pick a choice |
input'suggest | Suggest a list of choices for user then allow pick a choice or create a new one |
input'text | Get user input from keyboard then convert to text |
npm'install | Install librarries to use in the scene. |
npm'uninstall | Uninstall librarries to use in the scene. |
pause | Pause the program then wait to user enter to continue |
scene | Load another scene into the running program |
sleep | Sleep the program then wait to user enter to continue |
tag'register | Register custom tags from code or npm module, github.... |
test | Check conditions in the program |
vars | Declare and set value to variables to reused in the scene/global scope |
- If the first character is uppercase, it's auto assigned to global which is used in the program (all of scenes)
- If the first character is NOT uppercase, it will be assigned to scene scope which is only used in the scene | | view | View data in a pretty format | | view'json | View data in a json format | | view'table | View data in a table format | | view'yaml | View data in a yaml format |
Root scene
It's a scene file
Root scene file includes all of steps to run
Example:
title: Scene name # Scene name
description: Scene description # Scene description
log: info # Show log when run. Default is info. [silent, error, warn, info, debug, trace, all]
password: # Encrypted this file with the password. To run this file, need to provides a password in the command line
vars: # Declare global variables which are used in the program.
env: production # |- Only the variables which are declared at here just can be overrided by environment variables
runs: # Defined all of steps which will be run in the scene
- echo: Hello world
- test: test props
->
It's a property in a tag
Expose item properties for others extends
Example:
- echo: # Not run
->: helloTemplate
skip: true
content: Hello
- echo: # => Hi
<-: helloTemplate
content: Hi
<-
It's a property in a tag
Copy properties from others (a item, or list items)
Example:
- http'get:
skip: true
->: baseRequest
baseURL: http://localhost
- http'get:
skip: true
<-: baseRequest
->: user1Request
headers:
authorization: Bearer user1_token
- http'get:
skip: true
->: user2RequestWithoutBaseURL
headers:
authorization: Bearer user2_token
- http'get: # Send a get request with baseURL is "http://localhost" and headers.authorization is "Bearer user1_token"
<-: user1Request
url: /posts
vars: user1Posts
- http'get: # Send a get request with baseURL is "http://localhost" and headers.authorization is "Bearer user2_token"
<-:
- baseRequest
- user2RequestWithoutBaseURL
url: /posts
vars: user2Posts
async
It's a property in a tag
Execute parallel tasks
Example:
- http'get:
async: true
url: /categories
vars: categories
- http'get:
async: true
url: /product/1
vars: product
- echo: The product ${product.name} is in the categories ${categories.map(c => c.name)}
force
It's a property in a tag
Try to execute and ignore error in the running
Example:
- echo: # Not run
force: true
content: Got error "abc is not defined" but it should not stop here ${abc}
- echo: Keep playing
if
It's a property in a tag
Check condition before run the item
Example:
- vars:
number: 11
- echo: # => Value is greater than 10
if: ${vars.number > 10}
content: Value is greater than 10
- echo: # No print
if: ${vars.number < 10}
content: Value is lessthan than 10
log
It's a property in a tag
How to print log details for each of item.
Default is info
Value must be:
all
: Print all of log messagetrace
: Print all of log messagedebug
: Print short of loginfo
: Print title, not show log detailswarn
: Only show warning logerror
: Only show error log
Example:
- http'get:
title: Get data from a API
log: debug
url: http://...../data.json
loop
It's a property in a tag
Loop to run items with a condition
Example:
Loop in array
- vars:
arrs: [1,2,3,4]
- echo:
loop: ${vars.arrs}
content: Index is ${this.loopKey}, value is ${this.loopValue}
# =>
# Index is 0, value is 1
# Index is 1, value is 2
# Index is 2, value is 3
# Index is 3, value is 4
Loop in object
- vars:
obj: {
"name": "thanh",
"sex": "male"
}
- echo:
loop: ${vars.obj}
content: Key is ${this.loopKey}, value is ${this.loopValue}
# =>
# Key is name, value is thanh
# Key is sex, value is male
Dynamic loop in a condition
- vars:
i: 0
- echo:
loop: ${vars.i < 3}
content: value is ${vars.i++}
# =>
# value is 0
# value is 1
# value is 2
Loop in nested items
- vars:
arrs: [1,2,3]
- group:
loop: ${vars.arrs}
title: group ${this.loopValue}
items:
- echo: item value is ${this.parent.loopValue}
# =>
# group 1
# item value is 1
skip
It's a property in a tag
Only init but not execute
Example:
- echo: # Not run
->: helloTemplate
skip: true
content: Hello
- echo: # => Hi
<-: helloTemplate
content: Hi
title
It's a property in a tag
Title
Example:
- sleep:
title: Sleep in 1s
duration: 1000
vars
It's a property in a tag
Set value in the item to global vars to reused later
Example:
- echo:
content: Hello world
vars: helloText
- echo: ${vars.helloTexxt}
# =>
# Hello world
md'doc
doc
Generate comment in a file to document
Example:
- doc'md:
includeDirs:
- /workspaces/ezrun/src/components/doc/md.ts
includePattern: "^(?!.*\\.spec\\.ts$)"
excludeDirs:
- node_modules
prependMDs: # Prepend content in the document (Optional)
- path: ${utils.curDir}/../INSTALLATION.md # |- {path}: Read file content then copy it into document
- --- # |- string: Markdown content
appendMDs: # Append content in the document
- ---
- "### Have fun :)"
saveTo: /workspaces/ezrun/test/thanh.doc.md
Declare doc in file Example
echo
Print to console screen
Example:
Print a message
- echo: Hello world
- echo:
if: ${true}
content: Hello
Print a variable
- vars:
name: thanh
- echo: ${vars.name}
Quick print
- Hello world
- vars:
name: thanh
- ${vars.name}
Print text with custom type. (Follow "chalk")
- echo'red: Color is red
- echo'yellow: Color is yellow
- echo'gray: Color is gray
- echo'blue: Color is blue
- echo'cyan: Color is cyan
- echo'green: Color is green
- echo'magenta: Color is magenta
- echo: Color is white
- echo:
style: red
content: Color is red
- echo:
style: red.bold
content: Content is red and bold
clear
Clear console screen
Example:
- clear:
exec
Execute a program
Example:
Execute a bash script
- exec:
title: Run a bash script
commands:
- /bin/sh
- /startup.sh
Execute a python app
- exec:
title: Run a python app
commands:
- python
- app.py
exec'js
Execute a nodejs code
Example:
Set value to a variable
- exec'js:
title: Set value to a variable
script: |
vars.name = 'thanh'
logger.info(vars.name)
Write a file
- exec'js:
title: Write a file
path: /sayHello.sh # Path of js file (Use only "path" OR "script")
script: | # NodeJS content
const { writeFileSync } = require('fs')
writeFileSync('/tmp/hello.txt', 'Hello world')
return "OK"
vars: result # !optional
exec'sh
Execute a shell script
Example:
- exec'sh:
title: Write a hello file
path: /sayHello.sh # Path of sh file (Use only "path" OR "script")
script: | # Shell script content
touch hello.txt
echo "Hello world" > /tmp/hello.txt
bin: /bin/sh # !optional. Default use /bin/sh to run sh script
vars: log # !optional
exit
Stop then quit the program
Example:
- exit:
file'read
Read a file then load data into a variable
Example:
Read a json file
- file'read:
path: /tmp/data.json
vars: fileData
format: json # !optional
Read a yaml file
- file'read:
path: /tmp/data.yaml
vars: fileData
format: yaml # !optional
Read a text file
- file'read:
path: /tmp/data.txt
vars: fileContent
file'store
Store data to file
Example:
- file'store:
path: /tmp/data.json # Path to store data
password: # Password to encrypt/decrypt data content
initData: [] # Default data will be stored when file not found
Use in global by reference
- file'store:
path: /tmp/data.yaml
initData: []
vars:
fileDB: ${this} # Store this element to "fileDB" in vars
- exec'js: |
const { fileDB } = vars
fileDB.data.push('item 1')
fileDB.data.push('item 2')
// Save data to file
fileDB.save()
- echo: ${vars.fileDB.data} # => ['item 1', 'item 2']
file'write
Write data to file
Example:
Write a json file
- file'write:
path: /tmp/data.json
content: {
"say": "hello"
}
format: json # !optional
pretty: true # !optional
Write a yaml file
- file'write:
path: /tmp/data.yaml
content: ${vars.fileData}
format: yaml # !optional
Write a text file
- file'write:
path: /tmp/data.txt
content: Hello world
group
Group elements
Example:
- group:
title: Print all of message
runs:
- echo: hello
- echo: world
- group:
title: Stop
runs:
- exit:
http'del
Send a http request with DELETE method
Example:
# DELETE http://localhost:3000/posts/1?method=check_existed
- http'del:
title: Delete a post
url: /posts/1
baseURL: http://localhost:3000 # !optional - Request base url
query: # !optional - Request query string
method: check_existed
headers: # !optional - Request headers
authorization: Bearer TOKEN
timeout: 5000 # !optional - Request timeout. Default is no timeout
vars: # !optional - Global variable which store value after executed
status: ${this.response.status}
http'get
Send a http request with GET method
Example:
Get data from API then store value in vars.posts
# GET http://localhost:3000/posts?category=users
- http'get:
title: Get list posts
url: /posts
timeout: 5000 # !optional - Request timeout. Default is no timeout
baseURL: http://localhost:3000 # !optional - Request base url
query: # !optional - Request query string
category: users
headers: # !optional - Request headers
authorization: Bearer TOKEN
responseType: json # !optional - Default is json ['json' | 'blob' | 'text' | 'buffer' | 'none']
vars: posts # !optional - Global variable which store value after executed
Download file from a API
# GET http://localhost:3000/posts?category=users
- http'get:
title: Download a file
baseURL: http://localhost:3000
url: /posts
query:
category: users
headers:
authorization: Bearer TOKEN
saveTo: /tmp/post.json
http'head
Send a http request with HEAD method
Example:
# HEAD http://localhost:3000/posts/1?method=check_existed
- http'head:
title: Check post is existed or not
baseURL: http://localhost:
timeout: 5000 # !optional - Request timeout. Default is no timeout
url: /posts/1
query:
method: check_existed
headers:
authorization: Bearer TOKEN
vars:
status: ${this.response?.status}
http'patch
Send a http request with PATCH method
Example:
Update apart of data to API then store value in vars.posts
# PATCH http://localhost:3000/posts/ID?category=users
- http'patch:
title: Update a post
baseURL: http://localhost:3000
url: /posts/ID
query:
category: users
headers:
authorization: Bearer TOKEN
type: json # 'json' | 'form' | 'raw' | 'multipart' | 'text'
timeout: 5000 # !optional - Request timeout. Default is no timeout
body: {
"title": "My title",
"description": "My description"
}
responseType: json # 'json' | 'blob' | 'text' | 'buffer' | 'none'
vars: newPost
Upload file to server
# PATCH http://localhost:3000/upload/ID_UPLOADER_TO_REPLACE
- http'patch:
title: Upload and update data
baseURL: http://localhost:3000
url: /upload/ID_UPLOADER_TO_REPLACE
headers:
authorization: Bearer TOKEN
type: multipart
body: {
"file": { # File upload must includes path of file, name is optional
"path": "/tmp/new_my_avatar.jpg",
"name": "thanh_avatar"
}
}
vars:
status: ${this.response.status}
http'post
Send a http request with POST method
Example:
Post data to API then store value in vars.posts
# POST http://localhost:3000/posts?category=users
- http'post:
title: Create a new post
baseURL: http://localhost:3000
url: /posts
query:
category: users
headers:
authorization: Bearer TOKEN
type: json # 'json' | 'form' | 'raw' | 'multipart' | 'text'
timeout: 5000 # !optional - Request timeout. Default is no timeout
body: {
"title": "My title",
"description": "My description"
}
responseType: json # 'json' | 'blob' | 'text' | 'buffer' | 'none'
vars: newPost
Upload file to server
# POST http://localhost:3000/upload
- http'post:
title: Upload a new avatar
baseURL: http://localhost:3000
url: /upload
headers:
authorization: Bearer TOKEN
type: multipart
body: {
"category": "avatar",
"file": { # File upload must includes path of file, name is optional
"path": "/tmp/my_avatar.jpg",
"name": "thanh_avatar"
}
}
vars:
status: ${this.response.status}
http'put
Send a http request with PUT method
Example:
Update data to API then store value in vars.posts
# PUT http://localhost:3000/posts/ID?category=users
- http'put:
title: Update a post
baseURL: http://localhost:3000
url: /posts/ID
query:
category: users
headers:
authorization: Bearer TOKEN
type: json # 'json' | 'form' | 'raw' | 'multipart' | 'text'
timeout: 5000 # !optional - Request timeout. Default is no timeout
body: {
"title": "My title",
"description": "My description"
}
responseType: json # 'json' | 'blob' | 'text' | 'buffer' | 'none'
vars: newPost
Upload file to server
# PUT http://localhost:3000/upload/ID_UPLOADER_TO_REPLACE
- http'put:
title: Upload and update data
baseURL: http://localhost:3000
url: /upload/ID_UPLOADER_TO_REPLACE
headers:
authorization: Bearer TOKEN
type: multipart
body: {
"category": "avatar updated",
"file": { # File upload must includes path of file, name is optional
"path": "/tmp/new_my_avatar.jpg",
"name": "thanh_avatar"
}
}
vars:
status: ${this.response.status}
http/jobs
Create a jobs queue to do something step by step
Example:
- file'store: # Defined a file store to save data to file
path: /tmp/test.queue,
initData: [],
vars:
fileStorage: '${this}'
- http/jobs:
address: 0.0.0.0:8811 # Address to listen to add a new job to
queue: # Wait to finish a job before keep doing the next
concurrent: 1 # Num of jobs can be run parallel
storage: ${vars.fileStorage} # Set a storage to queue
runs: # Steps to do a job
- ${parentState.jobData} # {parentState.jobData} is job data in the queue which is included both querystring and request body
- ${parentState.jobInfo} # {parentState.jobInfo} is job information
# {parentState.jobInfo.path} request path
# {parentState.jobInfo.method} request method
# {parentState.jobInfo.query} request query string
# {parentState.jobInfo.headers} request headers
http/jobs'add
Add a job to the queue
Example:
Add a job by default
- http/jobs'add:
address: 0.0.0.0:3007 # Address to listen to add a new job to queue
data: # Steps to do a job
name: name1
age: 2
Use a "GET" http request to add a job
- http'get:
url: http://0.0.0.0:3007?name=name1&age=2
Use a "POST" http request to add a job
- http'post:
url: http://0.0.0.0:3007?name=name1
body:
age: 2
http/jobs'stop
Stop the jobs queue
Example:
- http/jobs:
address: 0.0.0.0:3007 # Address to listen to add a new job to
runs: # Steps to do a job
- echo: Display then stop
- http/jobs'stop: # Stop job here
input'confirm
Get user confirm (yes/no)
Example:
# - input'conf:
- input'confirm:
title: Are you sure to delete it ?
vars: userWantToDelete
default: false # !optional
required: true # !optional
input'multiselect
Suggest a list of choices for user then allow pick multiple choices
Example:
# - input'msel:
- input'multiselect:
title: Please select your hobbies ?
vars: hobbies
choices:
- title: Tennis
value: tn
- title: Football
value: fb
- title: Basket ball
value: bb
default: [tn, fb] # !optional
required: true # !optional
input'number
Get user input from keyboard then convert to number
Example:
# - input'num:
- input'number:
title: Enter your age ?
vars: age
default: 18 # !optional
required: true # !optional
input'password
Get user input from keyboard but hide them then convert to text
Example:
# - input'pwd:
- input'password:
title: Enter your password ?
vars: password
required: true # !optional
input'select
Suggest a list of choices for user then allow pick a choice
Example:
# - input'sel:
- input'select:
title: Your sex ?
vars: sex
choices:
- title: male
value: m
- title: female
value: f
default: m # !optional
required: true # !optional
input'suggest
Suggest a list of choices for user then allow pick a choice or create a new one
Example:
# - input'sug:
- input'suggest:
title: Your hobby
vars: hobby
choices:
- title: Football
value: football
- title: Basket Ball
value: backetball
default: football # !optional
required: true # !optional
suggestType: INCLUDE_AND_ALLOW_NEW # Must be in [STARTSWITH_AND_ALLOW_NEW, INCLUDE_AND_ALLOW_NEW, STARTSWITH, INCLUDE]
# - "INCLUDE": Only find in the text in the list suggestions
# - "INCLUDE_AND_ALLOW_NEW": Same "INCLUDE" and allow to create a new one if not in the list suggestions
# - "STARTSWITH": Only find in the start of text
# - "STARTSWITH_AND_ALLOW_NEW": Same "STARTSWITH" and allow to create a new one if not in the list suggestions
input'text
Get user input from keyboard then convert to text
Example:
# - input:
- input'text:
title: Enter your name
vars: name
default: Noname # !optional
required: true # !optional
npm'install
Install librarries to use in the scene.
Example:
- npm'install: module1, module2
- npm'install:
- module1
- myapp: git+ssh:git@github.com:...
- npm'install:
packages:
- lodash
- ezrun-telegram@latest // Always get latest ezrun-telegram librarry
# How to used
- exec'js: |
vars.newObject = require('lodash').merge({a: 2, b: 2}, {a: 1})
require('myapp')
- echo'pretty: ${vars.newObject}
Install from github
- npm'install:
title: Install from github
if: ${vars.useExternalPackage}
packages:
- myapp: git+ssh:git@github.com:...
- ezrun...
# How to used
- myapp:
title: This is my first application
npm'uninstall
Uninstall librarries to use in the scene.
Example:
- npm'uninstall: module1, module2
- npm'uninstall:
- module1
- myapp
- npm'uninstall:
title: Uninstall librarry
packages:
- ezrun-telegram
- ezrun...
pause
Pause the program then wait to user enter to continue
Example:
- pause:
- pause:
title: Pause here
scene
Load another scene into the running program
Example:
- scene:
title: A scene from remote server
path: https://.../another.yaml # path can be URL or local path
password: # password to decode when the file is encrypted
vars: # Set value to global environment
foo: bar
sleep
Sleep the program then wait to user enter to continue
Example:
Sleep for a time
- sleep: 10000 # Sleep 10s then keep continue
Full props
- sleep:
title: Sleep 10s
duration 10000 # Sleep 10s then keep continue
tag'register
Register custom tags from code or npm module, github....
Example:
Register custom tags from a file
- tag'register:
test1: /workspaces/ezrun/test/resources/test.js # { tagName: pathOfModule }
- test1:
foo: bar
Register custom tags from an object
- tag'register:
newOne: |
{
constructor(props) {
Object.assign(this, props)
},
async asyncConstructor(props) {
// Do async job to init data
},
exec() {
this.logger.info('ok ' + this.name, this.tag)
},
dispose() {
// Dispose after finished this
},
disposeApp() {
// Dispose when exit app
}
}
- newOne:
name: foo
Register custom tags from a class
- tag'register:
newOne: |
class {
constructor(props) {
Object.assign(this, props)
}
async asyncConstructor(props) {
// Do async job to init data
}
exec() {
this.logger.info('ok ' + this.name, this.tag)
}
dispose() {
// Dispose after finished this
}
disposeApp() {
// Dispose when exit app
}
}
- newOne:
name: foo
test
Check conditions in the program
Example:
Quick test
- test:
title: Number must be greater than 10
check: ${vars.age > 10}
- test: ${vars.age < 10}
Test with nodejs script
- test:
title: Number must be greater than 10
script: |
if (vars.age > 10) this.failed('Age is not valid')
vars
Declare and set value to variables to reused in the scene/global scope
- If the first character is uppercase, it's auto assigned to global which is used in the program (all of scenes)
- If the first character is NOT uppercase, it will be assigned to scene scope which is only used in the scene
Example:
A main scene file
- vars:
MainName: global var # Is used in all of scenes
mainName: local var # Only used in this scene
- scene:
path: ./child.scene.yaml
- echo: ${vars.MainName} # => global var
- echo: ${vars.mainName} # => local var
- echo: ${vars.name} # => undefined
- echo: ${vars.Name} # => global name here
A scene file child.scene.yaml
is:
- vars:
Name: global name here
name: scene name here # Only used in this scene
- echo: ${vars.MainName} # => global var
- echo: ${vars.mainName} # => undefined
- echo: ${vars.name} # => scene name here
- echo: ${vars.Name} # => global name here
view
View data in a pretty format
Example:
- view:
title: Pretty Viewer
data: [{ name: "name 2", age: 2 }, { name: "name 2", age: 3 }]
- view: ${vars.TEST_DATA}
view'json
View data in a json format
Example:
- view'json:
title: JSON Viewer
data: [{ name: "name 2", age: 2 }, { name: "name 2", age: 3 }]
- view'json: ${vars.TEST_DATA}
view'table
View data in a table format
Example:
- view'table:
title: Table viewer
headers: # Pick some headers to show. Default is all
- name
- age
data: [{ name: "name 2", age: 2 }, { name: "name 2", age: 3 }]
- view'table: ${vars.TEST_DATA}
view'yaml
View data in a yaml format
Example:
- view'yaml:
title: Yaml Viewer
data: [{ name: "name 2", age: 2 }, { name: "name 2", age: 3 }]
- view'yaml: ${vars.TEST_DATA}
Have fun :)
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago