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) or the task level:

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

const hello = project.addTask('hello');
hello.env('BAR', 'world');
hello.exec('echo $FOO, $BAR!');

Then:

$ projen hello
πŸ€– hello | echo $FOO, $BAR!
hello, 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

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.