projen

Tasks

Tasks are a project-level feature to define a project command system backed by shell scripts. Tasks are used to implement development workflows and are accessible through the projen CLI as subcommands.

The following example defines a task named β€œhello” which executes the shell command echo hello, world!:

const hello = project.addTask('hello');
hello.exec('echo hello, world!');

Run pj and the task will be available in the CLI:

$ projen hello
πŸ€– hello | echo hello, world!
hello, world!

You can also define some metadata and the first exec step declaratively:

const projen = require('projen');

const hello = project.addTask('hello', {
  description: 'say hello',
  category: projen.tasks.TaskCategory.TEST,
  exec: 'echo hello, world!'
});

Steps

Tasks can include any number of steps:

hello.exec('echo step number 2');

// a name can be added to a step if desired
hello.exec('echo foo bar', { name: 'print the text "foo bar"' });

The --inspect option can be used to display the contents of a task:

$ projen hello --inspect
echo hello, world!
echo step number 2
echo foo bar

If a step fails, the task will fail and all subsequent steps will not be executed.

You can also add steps to the beginning of a task:

const hello = project.addTask('hello');
hello.exec('echo hello');
hello.prepend('echo world');

Then:

$ projen hello 2> /dev/null
world
hello

Subtasks

Tasks can also spawn sub-tasks as a step:

const world = project.addTask('world');
world.exec('echo world!');

const hello = project.addTask('hello');
hello.exec('echo hello');
hello.spawn(world);

The output will be:

$ projen hello
πŸ€– hello | echo hello
hello
πŸ€– hello Β» world | echo world!
world!

$ projen hello --inspect
echo hello
world:
   echo world!

Environment

Environment variables can be defined at the project level (for all tasks), the task level, or the task step level:

project.tasks.addEnvironment('FOO', 'hello');

const hello = project.addTask('hello');
hello.env('BAR', 'beautiful');
hello.exec('echo $FOO, $BAR $BAZ!', { env: { BAZ: 'world' } });

Then:

$ projen hello
πŸ€– hello | echo $FOO, $BAR $BAZ!
hello, beautiful world!

You can also evaluate environment variable values from a shell command:

const hello = project.addTask('hello');
hello.env('TIME', '$(date)');
hello.exec('echo current time is $TIME');

Then:

$ projen hello
πŸ€– hello | echo current time is $TIME
current time is Tue Dec 1 09:32:33 IST 2020

Conditions

The condition option includes a command that determines if the task is executed. If the command exits successfully (with a zero exit code), steps will be executed. Otherwise, the task will be skipped (successfully).

const hello = project.addTask('hello', {
  condition: '[ -n "$CI" ]', // only execute if the CI environment variable is defined
  exec: 'echo running in a CI environment'
});

Then:

$ projen hello
πŸ€– hello | condition: [ -n "$CI" ]
πŸ€– hello | condition exited with non-zero - skipping

$ CI=1 projen hello
πŸ€– hello | condition: [ -n "$CI" ]
πŸ€– hello | echo running in a CI environment
running in a CI environment

The condition option can also be specified on individual task steps, for more granular control over task execution behavior:

const hello = project.addTask('hello', {
  steps: [
    { exec: 'running in a CI environment', condition: '[ -n "$CI" ]' },
    { exec: 'not running in a CI environment', condition: '[ ! -n "$CI" ]' }
  ]
});

Then:

$ projen hello
πŸ€– hello | condition: [ -n "$CI" ]
πŸ€– hello | condition exited with non-zero - skipping
πŸ€– hello | condition: [ ! -n "$CI" ]
πŸ€– hello | echo not running in a CI environment
not running in a CI environment

$ CI=1 projen hello
πŸ€– hello | condition: [ -n "$CI" ]
πŸ€– hello | echo running in a CI environment
running in a CI environment
πŸ€– hello | condition: [ ! -n "$CI" ]
πŸ€– hello | condition exited with non-zero - skipping

Tasks as npm scripts

By default, npm scripts in NodeProjects (or derivatives) are implemented by delegating the command to the projen CLI:

{
  "scripts": {
    "compile": "npx projen compile"
  }
}

This means that when yarn compile or npm run compile are executed, the projen CLI will be invoked and the task will be executed.

You can see a list of all steps in a task from the command line by passing the --inspect flag, e.g. yarn compile --inspect.