lets-cli / lets Goto Github PK
View Code? Open in Web Editor NEWCLI task runner for developers - a better alternative to make
Home Page: https://lets-cli.org
License: MIT License
CLI task runner for developers - a better alternative to make
Home Page: https://lets-cli.org
License: MIT License
In version <=0.0.14 we have only commands
-h, --help help for lets
--version version for lets
As you can see, flag version
is does not support short abbreviation -v
.
I consider, lets
should support both variants of all common used flags
test how to use positional args appending
commands:
build-js:
cmd:
- npm
- run
- webpack
lets build-js --watch
It is a bad default since many commands can have own --help and it will be always intercepted by lets --help
It is more consistent to use builtin lets help .
To be able to use shared lets configs we could introduce remote mixins
PoC would look like this
mixins:
- lets.test.yaml
- url: https://some.path.com/lets.lint.yaml
version: v1
This will download this mixin in .lets
dir and cache it
Thing to consider:
For example:
lets
[ERROR] failed to load config file lets.yaml: open lets.yaml: no such file or directory
<----link on how to create your first lets.yaml --->
Basic built-in command which will generate default lets.yaml with hello world command inside, so it is very easy to introduce lets into a project. We can imagine a wizard asking basic defaults like shell type before generating the file.
This is probably not an issue with lets-cli, just something I've looked up on stack overflow and cannot get it to work.
I want to export variables in a docker swarm project:
load-env:
description: Loads environment variables specified in stacks/swarm.env into the current shell.
cmd: set -a; . stacks/swarm.env; set +a
Running set -a; . stacks/swarm.env; set +a
exports the variables in the env file, but running lets load-env
does not. I haven't been able to figure out why.
I also tried export $(cat stacks/swarm.env) > /dev/null 2>&1;
and it works the same way.
It may be useful to declare cleanup command.
Example:
commands:
run:
cmd: |
docker-compose up some-service -d
npm run app
on_stop:
docker-compose down
I will allow to explicitly declare what to do when a command stopped either by error or Ctrl+c
commands:
js-dev:
description: Build js dev version
eval_env:
CHECKSUM: echo `lets checksum`
cmd: |
docker build . -f Dockerfile --build-arg CHECKSUM=${CHECKSUM}
commands:
run:
env:
DEBUG: 1
cmd: echo ${DEBUG}
Got [ERROR] failed to load config file lets.yaml: failed to parse 'run' command: field env.DEBUG: must be a string
We need to store checksum persistent, if we want to be able to start working on #32
Sometimes I want to skip execution of some tasks, if command's checksum from last run is not changed.
Example: before each npm run smth
I want to run npm i
. But if package.json
and package.lock
is not changed, I do not need to run npm i
So, in lets.yaml
I want to past smth like this and as a result, omit running task
New lets.yaml
install_deps:
checksum:
deps: &deps
- package.json
- package-lock.json
only:
checksum:
<<: *deps
cmd: npm i
run-smth:
depends: [install_deps]
cmd: npm run smth
As you can see, in lets.yaml
I added in cmd install_deps
property only
. It will allow to execute install_deps.cmd
only if checksum for this cmd changed.
So, what we need to implement:
Update go runtime and update source code using new go standard library functions
In some cases I need to run two or more jobs in parallel. For ex. compile TS code and serve it over HTTP. Now I need to open two or more terminal sessions and run cmds. It will be great if I will be able to write in lets.yaml
like:
commands:
compile-ts:
cmd: npm run build
serve:
cmd: npm run serve
serve-compiled:
cmds:
- compile-ts
- serve-compiled
Also It will be great, if lets will decorate each stdout of subproceses like docker-compose:
[compile-ts]: foo
[serve]: bar
For now if I want to pass options to command I must describe them in options
property of command block. If I want to pass non documented options to Lets command, I need to write cmd
property as array of strings, then Lets will allow me to add any option to cmd.
If my command script is complex and uses if-else
bash blocks, it cannot be described using array syntax with the same level of understanding and laconicism as when I use multiline command.
I need to allow to pass non documented options to my command, even if it was written using multiline/singleline style the same as using list-of-strings style
Idea to add settings
to config.
It then used as LETS_SETTING_<NAME_OF_SETTING>
Settings can be stored in .lets/settings.json
Add new --set
and --reset
flags.
Example:
settings:
skip-pull: false
So LETS_SETTING_SKIP_PULL=false
will be available in env.
lets --set skip-pull=true
will override and persist setting to .lets/settings.json
Example
commands:
build-image:
persist_checksum: true
checksum:
- requirements.txt
cmd: docker build -t img:${LETS_CHECKSUM} -f Dockerfile .
unpack-container:
depends: [build-image]
cmd: |
if [[ ${LETS_BUILD_IMAGE_CHECKSUM_CHANGED} = true ]]; then
cid=`docker create img:${LETS_BUILD_IMAGE_CHECKSUM}`;
docker cp ${cid}:/usr/ ./local/usr
docker rm ${cid}
fi
In this example, we have build-image
command with persist_checksum: true. If this command runs, it will generate env LETS_CHECKSUM_CHANGED and LETS_CHECKSUM.
It would be very convenient to pass this env vars to unpack-container
as build-image
is in it's depends so we could use those envs in root cmd.
env vars can be named by pattern LETS_<UPPERCASED_AND_UNDERSCORED_CMD_NAME>_CHECKSUM
and so on.
Something like this. Syntax is discussable
commands:
foo:
env:
MYENV: "1"
depends: [bar]
bar:
cmd: echo ${MYENV}
Often we have several almost-identical commands which share most of the body.
But due to constraints to https://github.com/docopt/docopt.go we have to declare Usage
with particular command name. Let me show an example:
commands:
run:
options: |
Usage: lets run [--config=<config>]
env:
SOME_SECRET: "123"
depends: [build-app]
cmd: docker-compose up app postgres
run-app:
options: |
Usage: lets run-app [--config=<config>]
env:
SOME_SECRET: "123"
cmd: docker-compose up app
run-debug:
options: |
Usage: lets run-debug [--config=<config>]
env:
SOME_SECRET: "123"
cmd: docker-compose up app-debug
We can get rid of some repetition using yaml features:
commands:
run: &run
options: |
Usage:
lets run [--config=<config>]
lets run-app [--config=<config>]
lets run-debug [--config=<config>]
env:
SOME_SECRET: "123"
depends: [build-app]
cmd: docker-compose up app postgres
run-app:
<<: *run
cmd: docker-compose up app
run-debug:
<<: *run
cmd: docker-compose up app-debug
But its still required to enumerate all run run command options in options
in run
command. Its bad.
What I suggest is:
LETS_COMMAND_NAME
which is a command name itself.options
and interpolate options string.commands:
run: &run
options: |
Usage: lets ${LETS_COMMAND_NAME} [--config=<config>]
env:
SOME_SECRET: "123"
depends: [build-app]
cmd: docker-compose up app postgres
run-app:
<<: *run
cmd: docker-compose up app
run-debug:
<<: *run
cmd: docker-compose up app-debug
Thus we do not breaking docopt contract and providing absolutely correct docopt string and its cleaner as well.
Example:
commands:
show-users:
cmd: cat users.txt
grant-access-all:
ADMINS:
ref: show-users
We can mimic this behavior like this:
commands:
show-users:
cmd: cat users.txt
grant-access-all:
ADMINS:
sh: lets show-users
and while this does not require complex validations, it is a bit slower since requires to start new instance of lets
Validate that:
a
and b
declares envs that a:env:B
depends on b
and b:env:A
depends on a
mode: ref
for global env in first iteration because it can be hard to deal with circular callsFor commands like these:
commands:
build-app:
...
run-app:
depends: [build-app]
...
if build-app fails we show:
failed to run command 'build-app': exit status 130
failed to run command 'run-app': exit status 130
But we can make it something like
'run-app' ->
'build-app' failed: exit status 130
^^^^^^^^^
or with more verbosity
'build-app' failed: exit status 130
'run-app' ->
'build-app'
^^^^^^^^^
Consider this
commands:
run:
depends: [build-img-1, build-img-2]
cmd: echo Run
build-img-1:
cmd: lets _build-image first.Dockerfile
build-img-2:
cmd: lets _build-image second.Dockerfile
_build-image:
options: |
Usage: lets _build-image <image>
cmd: docker build . -f ${LETSOPT_IMAGE}
It would be more cool to not run lets-in-lets. Something like this
commands:
run:
depends: [build-img-1, build-img-2]
cmd: echo Run
build-img-1:
ref: _build_image
args: first.Dockerfile
build-img-2:
ref: _build_image
args: second.Dockerfile
_build-image:
options: |
Usage: lets _build-image <image>
cmd: docker build . -f ${LETSOPT_IMAGE}
This way we do not run lets in lets, we just say - reference _build_image and pass args first.Dockerfile
Maybe it makes sense to separate this new ref commands into aliases
top level directive or smth like this
having example command:
shell: bash
commands:
push:
cmd: git push origin master
will give us an error on macOS
Shell "bash" is not executable: No such file or directory
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
failed to run command 'publish': exit status 128
It's quite a nice feature to have an opportunity to make command aliases/command prefix shortcuts. Sometimes lets.yaml
may look like this:
shell: bash
commands:
compile:
description: Compilation
cmd: docker run --rm -v ${PWD}:/go/src/app helloworld sh -c "go build -o helloworld main.go"
format:
description: Formatting
cmd: docker run --rm -v ${PWD}:/go/src/app helloworld sh -c "gofmt -w -s ."
test:
description: Testing
cmd: docker run --rm -v ${PWD}:/go/src/app helloworld sh -c "go test"
lint:
description: Linting
cmd: docker run --rm -v ${PWD}:/go/src/app helloworld sh -c "golangci-lint run"
run:
description: Execution
cmd: ./helloworld
In this case command shortcuts would shorten general commands' length, like this:
shell: bash
aliases:
docker: docker run --rm -v ${PWD}:/go/src/app helloworld
commands:
compile:
description: Compilation
cmd: @docker go build -o helloworld main.go
format:
description: Formatting
cmd: @docker gofmt -w -s .
test:
description: Testing
cmd: @docker go test
lint:
description: Linting
cmd: @docker golangci-lint run
run:
description: Execution
cmd: ./helloworld
Character @
or %
or some other one can be used as a placeholder identifier.
commands:
lint:
group: codequality
cmd: eslint
test:
group: tests
cmd: jest
and the output will be grouped and indented
Available commands:
codequality
lint
tests
test
When type lets a
- it has to suggest only commands which start with a
but suggested shows all available commands
Allow passing a map to options instead of docopts
Problems need solving:
commands:
foo:
options:
debug:
required: true
Sometimes I need to reuse env vars. Now I need to copy/paste envs from cmd to cmd. I want to be able to define env vars once and than access them in my commands
By doing this we can have own lets.my.yaml
which will not be pushed to repo.
Example:
touch lets.my.yaml
lets.my.yaml
to .gitignore
lets.my.yaml
in mixins
.Now user can add/override commands/env, etc. in his own lets.my.yaml
.
P.s. This can be also achieved by adding new flag to lets - something like -f
(similar to docker-compose approach)
Also, we can add built-in command help (like in kubectl) which will describe command as argument
lets foo --help
lets help foo
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.