Syntax

This article covers all information about gilbert.yaml syntax and step-by-step task definition guide.

Manifest file

gilbert.yaml it’s a yaml file that contains all information about your tasks and tells Gilbert what to do when you try to run specific task.

This file should be located at the root folder of your codebase, or at least at the same location where you call gilbert command.

Run gilbert init command to create a sample gilbert.yaml file.

Structure

gilbert.yaml consists of tasks, and tasks include a list of jobs to be done and rules.

Here is an annotated example of gilbert.yaml file.

version: 1.0
tasks:
  build:
  - description: Build project
    action: build
  clean:
  - if: file ./vendor
    description: Remove vendor files
    action: shell
    params:
      command: rm -rf ./vendor

Sections:

  • version - file schema version
  • imports - list of files to import. Imported files should share the same syntax as gilbert.yaml file.
  • vars - list of global variables that available for all tasks and jobs
  • mixins - mixins. See mixins for more info
  • tasks - contains a list of tasks. Task can be called by gilbert run task_name

Variables

Gilbert allows to keep variables in the manifest file and use them in tasks and jobs.

There are 2 type of variables:

  • Global - defined in vars section in root. Available everythere.
  • Local - defined in specific job and visible only in scope of job.

Tip: variable values could be set or changed using command flags.

Predefined variables

By default, there are a few predefined variables in global scope:

  • PROJECT - Path to the folder where gilbert.yaml is located.
  • BUILD - Alias to ${PROJECT}/build, can be useful as default build output directory.
  • GOPATH - Go path environment variable

String expressions

All variable values and some other params can contain not only static value, but also string expression.

String expression can contain a value of any variable ({{ var_name }}) or a value of some shell command ({% whoami %}) or both.

Example:

version: 1.0
vars:
    foo: "{% go version %} is installed on {{ GOROOT }}"

The value of variable foo will be:
go version go1.10.1 linux/amd64 is installed on /usr/local/go

Go templates

gilbert.yaml supports Go template expressions. Expressions should be wrapped with {{{ ... }}}.

Also manifest template includes some useful functions:

  • slice - creates a new slice
  • shell - runs shell command and returns command output
  • split - splits string by char
  • yaml - serializes slice to YAML/JSON string
version: 1.0

# Run shell command and split output string by "\n" char
{{{ $libs := shell "ls -1 ./libs | tr '\n' '\0' | xargs -0 -n 1 basename" | split "\n" }}}

# Define a slice template variable
{{{ $packages := slice "./foo" "./bar" }}}

tasks:
  build-libs:
    {{{ range $libs }}}
    - mixin: build-lib
      vars:
        name: {{{.}}}
    {{{ end }}}

    cover:
    - action: cover
      params:
        threshold: 40
        reportCoverage: true
        packages: 
          {{{ $packages | yaml }}}  # Serialize and insert slice

The difference between Go template expressions and String expressions is that values in template cannot be changed, because first Gilbert compiles Go template in gilbert.yaml and then process the result as YAML file.

Tasks

Each task is located in tasks section and contains from a sequence of jobs that should be ran when task was called.

Job definiton

Each job should contain a subject to call - action, task or mixin. Most of parameters are optional.

tasks:
  build_project:
  - action: build                     # name of action to perform, required!
    description: "build the project"  # step description, optional
    delay: 500                        # delay before step start in milliseconds, optional
    vars:
      commit: "{% git log --format=%H -n 1 %}"     # Variables for current step, optional
      foo: "bar"
    params:                                           # Arguments for action.
      variables:                                      # Those values are specific
          'main.version': "{{ commit }}"              # to each action.
          'main.stable': 'true'
  
  # Call sub-task
  - if: '[ $(uname -s) == "Darwin" ]'    # Condition for step run, contains a shell command, optional
    task: build-for-mac
    vars:
      dist_dir: '/tmp'  # variable `dist_dir` will be passed to 'build-for-mac' task

Job fields

Param name Type Description
if boolean Contains conditional shell command. If command returns non-zero exit code, step will be skipped
description string Contains step description and makes your job run status more informative
action string Name of action to execute. See built-in actions for more info
task string Name of task to be called. Cannot be together with action not mixin in the same job.
mixin string Name of the mixin to be called. Cannot be together with action nor task in the same job.
async boolean Run job asynchronously. Useful for executing programs like web-servers, etc.
delay int Delay before step start in milliseconds
deadline int Job execution deadline in milliseconds
vars dict List of local variables for the step, work the same as global vars section.
params dict Contains arguments for the action. See action docs for more info

- Required parameter
- Optional parameter but depends on action

Subtasks

Task can call another tasks and pass or replace variables with own values.

tasks:
  start-qa:
    - task: start-server            # call 'start-server' task
      vars:                         # with overrided 'config' variable
        config: ./config-qa.json
  
  start-server:
    - action: shell
      vars:
        config: ./config.json
      params:
        command: './build/server -c {{config}}'

Mixins

Mixin is a set of jobs that can be included into task.
Mixin serves as a template for common actions and used to reduce boilerplate code and do not clutter up tasks list.

Also, one of the biggest differences that most of values can contain template expressions.

Declaration

Each mixin should be declared in mixins section and have the same syntax as regular jobs in tasks section:

  version: 1.0
  mixins:
    hello-world:
      - action: shell
        params:
          command: 'echo "hello world"'
      - action: build

Calling a mixin

Mixins are called by tasks and use job variables as parameters. The same mixin can be called several times with different parameters in the same job.

Example:

version: 1.0
mixins:
  platform-build:
  - action: build
    description: 'build for {{os}} {{arch}}'
      vars:
        extension: '' # variable default value
      params:
        outputPath: '{{buildDir}}/myproject_{{os}}-{{arch}}{{extension}}'
        target:
          os: '{{os}}'
          arch: '{{arch}}'
  - if: 'type md5sum'
    description: 'generate checksum for {{buildDir}}/myproject_{{os}}-{{arch}}{{extension}}'
    action: shell
    vars:
      fileName: 'myproject_{{os}}-{{arch}}{{extension}}'
    params:
      workDir: '{{buildDir}}'
      command: 'md5sum {{fileName}} > {{fileName}}.md5'

tasks:
  release:
  - mixin: platform-build
    vars:
      os: windows
      arch: amd64
      ext: .exe
  - mixin: platform-build
    if: '[ $(uname -s) == "Darwin" ]'
    vars:
      os: darwin
      arch: amd64

In example above, task release calls mixin platform-release and passes variables os, arch and ext to the mixin.

Advanced examples

You can find a good use-case example in this demo project.
That repo demonstrates usage of mixins and a few built-in actions for a real-world web-server example.