How to set up a conditional npm script based on the output of another?

6.7k views Asked by At

This is an issue I have run into before when trying to set something up with npm scripts, yet I have not been able to solve it. Not even sure this is possible, preferably I would like the solution to work in both Mac and Windows environments.

I'm trying to split up some of the logic of my npm scripts into several short scripts that can call each other. This in combination with variables would make the scripts better maintainable and readable for other developers.

I can not figure out however how to use the result of one npm script in another. I'm hardly a bash expert so that why I'm looking for some help here (:

In this example I'm trying to set up a script which allows the developer to easily launch a docker (virtual) environment.

in the package.json:

...
"config": {
    "docker": {
        "container": "docker-test"
    }
},
"scripts": {
    "container_run": "docker run -d -p 80:80 $npm_package_config_docker_container"
    "container_running": "docker inspect -f {{.State.Running}} $npm_package_config_docker_container || echo 'false'",
    "container_stop": "docker stop $npm_package_config_docker_container && docker rm $npm_package_config_docker_container",
    "start": "???"
}

So here I have a variable containing the name of a docker container to be run: $npm_package_config_docker_container.

When I do npm run container_running, this will return true, if the container is running or throw an error if the container is not there in which case it will echo 'false'. So far so good.

Now I would like the start script to check if the container if running, if so stop the container and start a new run and of it is not running just start a new run. So something like this:

"start": "if [ container_running == "true" ]; then container_stop && container_run; else container_run; fi"

So the question is how to achieve this? And as a bonus question, can this be done in a way that is compatible in both Mac and Windows environments?

Any help would be much appreciated!!

2

There are 2 answers

1
SnailCrusher On

After some more digging I found a solution to his although I'm sure this could be improved.

You can use command substitution to run $(npm run container_running), this will return all the output from running that command (in a subshell). Then you can test the output to check if the last word was 'true'.

"start": "if [[ $(npm run container_running) == *true ]]; then npm run container_stop && npm run container_run; else npm run container_run; fi"

Have not tested this on Windows yet.

If anyone has a better idea / solution please let me know!

1
Paul On

Honestly, for anything more complex than a single command with options, I create a bin folder and add a custom script file for it, then have one of the non scripts call that instead. E.g.:

"container_run": "./bin/container-run"

The thing is, you don't have to be a bash expert then because you can create that file with a #! /usr/env node at the top and then write the rest in JavaScript.