Inline Node Scripts

Run inline node scripts in Azure DevOps pipelines.

· #cicd, #azure

Under normal circumstances, I'd recommend that any nodejs scripts used in your CI/CD pipelines be checked into the repository and run from your YAML pipeline using a normal node command, for example:

steps:
- script: |
node scripts/build.js

env:
NODE_ENV: production

Keeping your scripts out of your YAML pipeline has some clear advantages:

Despite these advantages, there are situations where checking the script into the repository doesn't work.

In these situations, it's helpful to have an inline node script.

Bash

In bash, we can run an inline node script by piping a heredoc:

steps:
- script: |
echo "Running an inline node script..."
node <<-'EOF'
const package = require('./package.json');
console.log(`Now I'm running in a nodejs script!`);
console.log(`Node env is: ${process.env.NODE_ENV}`);
console.log(`Building version ${package.version}...`);
'EOF'

env:
NODE_ENV: production

Note how the heredoc pair -- <<-'EOF' and closing 'EOF' -- is wrapped in quotes. This is important, because otherwise, syntax inside your nodejs script (like backticks and ${...} blocks) would be interpreted by bash, totally breaking the syntax of your script. The quotes instruct bash to avoid any evaluation of the string until the closing the 'EOF' tag.

PowerShell

We can also use a heredoc in PowerShell, using a slightly different format:

steps:
- powershell: |
echo "Running an inline node script..."
@'
const package = require('./package.json');
console.log(`Now I'm running in a nodejs script!`);
console.log(`Node env is: ${process.env.NODE_ENV}`);
console.log(`Building version ${package.version}...`);
'@ | node


exit $LASTEXITCODE
env:
NODE_ENV: production

Again, make sure you use @' ... '@ (single quotes) and not @" ... "@, to avoid evaluation of your node script by the shell.

The line after the node script -- exit $LASTEXITCODE -- really shouldn't be required. I was forced to add this because piping into nodejs this way as the last command in a powershell script seemed to break some expectations of the Azure DevOps pipeline runner, and it would fail with an exception after my script was finished. Your mileage may vary!

Passing command-line parameters

The easiest way to access values from your pipeline inside your nodejs script is to make them all environment variables (passed in via the env: property), and then grab them from process.env inside your script.

If you'd prefer to use parameters, just remember to add - as the first argument to node (the standard notation for "read from stdin").

Here's an example:

steps:
- powershell: |
@'
console.log(`My build directory is ${process.argv[2]}`);
console.log(`My project name is ${process.argv[3]}`);
'@ | node - "$(Agent.BuildDirectory)" $env:PROJECT_NAME

env:
PROJECT_NAME: Acme