Change value of shell variables as an argument of npm run command - bash

I am trying to accomplish the following -> Right now I use cypress to run e2e tests. It is being launched by npm command. I have several environments and different user permission. I created a shell script, where I have stored value of environment and user permission rights. What I want to do is to have opportunity to run npm command with parameters to change the value of variable from shell script. Could someone give a clue, is it even possible? The expected behaviour is to write something like:
npm run cy dev3,full
And have the opportunity to change the value of shell script variable to launch necessary environament and change value of user permissions.
package.json command:
"scripts": {
"cy": "./scripts/cypress.sh",
}
cypress.sh file content
#!/usr/bin/env bash
DEV_ENV="${DEV_ENV:-"dev3"}"
USER_TYPE="${USER_TYPE:-"full"}"
COMMAND="cypress open \
--browser chrome \
--config baseUrl=https://environment-$DEV_ENV.com \
--env DEV_ENV=https://environment-$DEV_ENV.com,USER_TYPE=$USER_TYPE
"
eval $COMMAND

Are you trying to change the environment variables seen in cypress.sh? If so, you can just execute npm run like this:
DEV_ENV=dev2 USER_TYPE=empty npm run cy
and it will change the value of DEV_ENV and USER_TYPE.
If you want to strictly run it by using the format you gave (npm run cy dev3,full), the args dev3,full are passed on to cypress.sh, so you can just parse the arguments directly in cypress.sh:
if [ ! -z "$1" ]; then
# do whatever here...
fi

Related

Bash script behaving different than when manually executing commands into remote server

I have a remote server and I can ssh into it and when I execute npm install it works just fine. I can see that it's installed by calling which npm and i see:
/home/ubuntu/.nvm/versions/node/v15.11.0/bin/npm
Great.
However, when I do this via a bash script, it says
bash: line 1: npm: command not found
My script:
#!/bin/bash
ssh he-int 'npm install'
Why the discrepancy between the two ? It's the same commands...
Sounds like maybe npm is added to your PATH in one of the login scripts (.bashrc, .profile, etc). I especially think this is true because the npm path indicates you are using nvm to manage your npm environment. There may be a call to nvm to add npm to the path in one of those login scripts.
When you run an ssh command like your second command, it doesn't run as a login shell, so it doesn't run the login scripts. You can either:
Try and force it to run as a login shell (ssh -t maybe? not sure).
Try to initialize your npm environment inside your script, probably by calling nvm.
npm may not be in the PATH of the user you're sshing in as using the bash script.
Use this to see what's in your PATH variable:
ssh he-int 'echo $PATH'
You can also just try to use the path directly and see if it works.
#!/bin/bash
ssh he-int '/home/ubuntu/.nvm/versions/node/v15.11.0/bin/npm install'

Pass environment variable from command line to yarn

I have a code that reads port number from environment variable or from config. Code looks like this
const port = process.env.PORT || serverConfig.port;
await app.listen(port);
To run app without defining environment variable, I run following yarn command.
yarn start:dev
This command works successfully in Linux shell and Windows command line.
Now, I want to pass environment variable. I tried following,
PORT=2344 yarn start:dev
This commands works successfully in Linux shell but failing in Windows command line. I tried following ways but couldn't get it to work.
Tried: PORT=2344 yarn start:dev
I got error: 'PORT' is not recognized as an internal or external command,
operable program or batch file.
Tried: yarn PORT=2344 start:dev
I got error: yarn run v1.17.3
error Command "PORT=2344" not found.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Any idea please? I know, I can define environment variables from System Properties in Windows. But any way if I can do it from command line?
i'd suggest you use the NPM module called cross-env. it allows adding particular env variables on the command line regardless of platform. with that said, you may try:
$ cross-env PORT=2344 yarn start:dev
You can chain commands on the Windows command prompt with &(or &&). To set an environment variable you need to use the set command.
The result should look like this: set PORT=1234 && yarn start:dev.
Found a solution for this problem in Windows command prompt.
Create a .env file in project root folder (outside src folder).
Define PORT in it. In my case, contents of .env file will be,
PORT=2344
Run yarn start:dev
Application will use port number that you have specified in .env file.
Put .env file at root. Then following command will expose content of .env file and then run yarn start command
$ source .env && yarn start
or this command
$ export $(cat .env) && yarn start
If update any variable in .env then close the terminal and open new terminal window and can again run above command. Or else can also run unset command to remove existing var.
unset VAR_NAME
You can use popular package dotenv:
create a file .env in root directory
put all your env vars
e.g.:
ENV=DEVELOPMENT
run your code like this
$ node -r dotenv/config your_script.js
here the explanation:
[https://github.com/motdotla/dotenv#preload]
To define environment variables in the Windows command prompt we can use the set command, you can then split your call into two lines.
set PORT=2344
yarn start:dev
The set command persists within the current command prompt, so you only need to run it once.
The equivalent command in bash is 'export'.
FYI (not a direct answer). I was attempting this in VS Code - passing .env variables through yarn to a JavaScript app. Google had very few examples so I'm sharing this for posterity as it's somewhat related.
The following simply substitutes text normally placed directly into the package.json or script file. Use this to quickly obfuscate or externalize your delivery configurations.
In Environment Variable File (.env)
PORT=2344
In Yarn File (package.json)
source .env; yarn ./start.sh --port $PORT
In Yarn Script (start.sh)
#!/bin/bash
while [ $? != 0 ]; do
node dist/src/index.js $1; #replace with your app call#
done
The app then accepts port as a variable. Great for multi-tenant deployments.

How to define an environment variable that can be automatically used in multiple npm scripts?

Consider the following npm scripts.
$ npm run
available via `npm run-script`:
make
OUTPUT=dist/main.js bash -c 'elm make src/Main.js --output=$0 $1'
make:dev
npm run make -- '$OUTPUT' --debug
make:prod
npm run make -- '>(npm run uglify -- $OUTPUT)' --optimize
uglify
uglifyjs --compress 'pure_funcs="F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9",pure_getters,keep_fargs=false,unsafe_comps,unsafe' | uglifyjs --mangle --output=
I'd like to use it as follows:
$ npm run make -- '$OUTPUT' '--debug'
> experiment#0.1.0 experiment /Users/Adit/experiment
> OUTPUT=dist/main.js bash -c 'elm make src/Main.js --output=$0 $1' '$OUTPUT' '--debug'
This would correctly create the debug build of the Elm application. However, this is not what happens. Instead of using single quotes, npm run uses double quotes:
$ npm run make -- '$OUTPUT' '--debug'
> experiment#0.1.0 experiment /Users/Adit/experiment
> OUTPUT=dist/main.js bash -c 'elm make src/Main.js --output=$0 $1' "$OUTPUT" "--debug"
Due to this the output is not what I expect it to be. What's the best way to resolve this issue without writing a custom shell script? I want to use the OUTPUT variable in two different commands. However, I only want to define it in one place.
I solved the problem as follows.
{
"config": {
"input": "src/Main.elm",
"output": "dist/main.js"
},
"scripts": {
"make": "elm make $npm_package_config_input --output $npm_package_config_output",
"make:dev": "npm run make -- --debug",
"make:prod": "npm run make -- --optimize",
"postmake:prod": "uglifyjs $npm_package_config_output --compress 'pure_funcs=\"F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9\",pure_getters,keep_fargs=false,unsafe_comps,unsafe' | uglifyjs --mangle --output=$npm_package_config_output"
}
}
Hence, if you have a configuration variables that you'd like to use in multiple npm scripts, you can add them to the config dictionary of package.json. After that, you can access them as environment variables in the npm scripts via the name $npm_package_config_<name> where <name> is the name of your config variable.
I also used a post script instead of process substitution to uglify the output of the Elm compiler. Doing so was overall less of a hassle than using process substitution via bash -c.
Finally, you can run make, make:dev, or make:prod for different builds. The first one is a regular build. The second one is a development build with the Elm debugging tools. The third one is a regular build which is optimized and minified for production use.

Why Can't I Set Env Variables By Running A BASH Script From An Npm Script?

I have a nodejs javascript project, but I would like to set a bunch of environment variables locally. created a bash file that just exports some variables:
#!/usr/bin/env bash
export waka=flaka
export fat=booty
When I use the dot to source and run the file from the command line it works fine:
. ./env.sh
And I can see the variable has been set
echo $waka # prints "flaka"
But then I try to take this command and make it an npm script by adding it to my package.json
scripts: {
"set-env": ". ./env.sh",
...
}
and then run it:
npm run set-env
The script is run but the environment variables are not saved:
echo $waka # prints undefined (assuming you didn't already run it from command line)
So, I'm wondering why it doesn't save the envrionment variables as an npm script and if it's possible to run the bash script from an npm script in a way such that the environment variables will be saved for the rest of the command prompt session. Thanks!
npm is not a shell command; it runs in a separate process that forks another shell in order to run the command specified by set-env. env.sh is executed, but then that shell immediately exits, at which point the changes are gone (and then npm itself exits).

How to declare a shell constant for Jenkins execute shell build configuration?

I'm running the following command in the "execute shell" entry in my Jenkins job configuration.
AWS_ACCESS_KEY_ID=XXX AWS_SECRET_ACCESS_KEY=XXX CASS_HOSTNAME=XXX DB_HOSTNAME=XXX DB_PASSWORD=XXX DB_USERNAME=XXX EMAIL_REGION=XXX RED_HOSTNAME=XXXX RED_PORT=XXX npm run
How could I create a single variable for those parameters? I tried declaring a regular shell constant like:
readonly parameters="AWS_ACCESS_KEY_ID=XXX AWS_SECRET_ACCESS_KEY=XXX .."
$parameters npm run init_test_tenant
But I get the following error
/tmp/hudson6912171417213995775.sh: 4: /tmp/hudson6912171417213995775.sh: AWS_ACCESS_KEY_ID=XXX: not found
In order to avoid place eval in front of everything and open a hole in your code, you can use a trick:
export $parameters
npm run init_test_tenant
The difference from the attempt in your question: all variables will be visible to npm and all other commands you would execute after that, while VAR=value command syntax let VAR visible only to command.
Prefix with env
readonly parameters="AWS_ACCESS_KEY_ID=XXX AWS_SECRET_ACCESS_KEY=XXX .."
env $parameters npm run init_test_tenant
Also if you do not need any other environment variables in your nodejs program you can add the -i option to env so that you get a clean environment for npm, but then you would have to address npm via full path ( eg: /usr/bin/npm ) and all other programs that might run within you nodejs program:
readonly parameters="AWS_ACCESS_KEY_ID=XXX AWS_SECRET_ACCESS_KEY=XXX .."
env -i $parameters /usr/bin/npm run init_test_tenant
Or add the PATH=/usr/bin/ to the $parameters constant like so:
readonly parameters="PATH=/usr/bin AWS_ACCESS_KEY_ID=XXX AWS_SECRET_ACCESS_KEY=XXX .."
env -i $parameters npm run init_test_tenant

Resources