Bootleg.DSL (bootleg v0.13.0) View Source

Configuration DSL for Bootleg.

Link to this section Summary

Functions

Defines an after hook for a task.

Defines a before hook for a task.

Fetches all key/value pairs currently defined in the Bootleg configuration.

Fetches the value for the supplied key from the Bootleg configuration. If the provided key is a Tuple, the first element is considered the key, the second value is considered the default value (and returned without altering the config) in case the key has not been set. This uses the same semantics as Keyword.get/3.

Sets key in the Bootleg configuration to value.

Downloads files from remote hosts to the local machine.

Invokes the task identified by task.

Executes commands on all remote hosts.

Executes commands on all remote hosts within a role.

Executes commands on a remote host.

Defines a task idefintied by task.

Uploads a local file to remote hosts.

Link to this section Functions

Link to this macro

after_task(task, other_task)

View Source (macro)

Defines an after hook for a task.

Behaves exactly like a before hook, but executes after the task has run. See before_task/2 for more details.

use Bootleg.DSL

after_task :build, :store_artifact
after_task :deploy do
  Notify.team "Deployed!"
end
Link to this macro

before_task(task, other_task)

View Source (macro)

Defines a before hook for a task.

A hook is a piece of code that is executed before/after a task has been run. The hook can either be a standalone code block, or the name of another task. Hooks are executed in an unconditional fashion. Only an uncaught exeception will prevent futher execution. If a task name is provided, it will be invoked via invoke/1.

Just like with invoke/1, a task does not need to be defined to have a hook registered for it, nor does the task need to be defined in order to be triggered via a hook. Tasks may also be defined at a later point, provided execution has not begun.

If multiple hooks are defined for the same task, they are executed in the order they were originally defined.

use Bootleg.DSL

before_task :build, :checksum_code
before_task :deploy do
  Notify.team "Here we go!"
end

Relying on the ordering of hook execution is heavily discouraged. It's better to explicitly define the order using extra tasks and hooks. For example

use Bootleg.DSL

before_task :build, :do_first
before_task :build, :do_second

would be much better written as

use Bootleg.DSL

before_task :build, :do_first
before_task :do_first, :do_second

Fetches all key/value pairs currently defined in the Bootleg configuration.

Fetches the value for the supplied key from the Bootleg configuration. If the provided key is a Tuple, the first element is considered the key, the second value is considered the default value (and returned without altering the config) in case the key has not been set. This uses the same semantics as Keyword.get/3.

use Bootleg.DSL
config :foo, :bar

# local_foo will be :bar
local_foo = config :foo

# local_foo will be :bar still, as :foo already has a value
local_foo = config {:foo, :car}

# local_hello will be :world, as :hello has not been defined yet
local_hello = config {:hello, :world}

config :hello, nil
# local_hello will be nil, as :hello has a value of nil now
local_hello = config {:hello, :world}
Link to this macro

config(key, value)

View Source (macro)

Sets key in the Bootleg configuration to value.

One of the cornerstones of the Bootleg DSL, config/2 is used to pass configuration options to Bootleg. See the documentation for the specific task you are trying to configure for what keys it supports.

use Bootleg.DSL

config :app, :my_cool_app
config :version, "1.0.0"
Link to this macro

download(role, remote_path, local_path)

View Source (macro)

Downloads files from remote hosts to the local machine.

Downloading works much like remote/3, but instead of transferring shell commands over SSH, it transfers files via SCP. The remote host does need to support SCP, which should be provided by most SSH implementations automatically.

role can either be a single role name, a list of roles, or a list of roles and filter attributes. The special :all role is also supported. See remote/3 for details. Note that if multiple hosts match, files will be downloaded from all matching hosts, and any duplicate file names will result in collisions. The exact semantics of how that works are handled by SSHKit.SCP, but in general the file transfered last wins.

local_path is a path to local directory or file where the downloaded files(s) should be placed. Absolute paths will be respected, relative paths will be resolved relative to the current working directory of the invoking shell. If the local_path does not exist in the local file system, an attempt will be made to create the missing directory. This does not handle nested directories, and a File.Error will be raised.

remote_path is the file or directory to be copied from the remote hosts. If a directory is specified, its contents will be recursively copied. Relative paths will be resolved relative to the remote workspace, absolute paths will be respected.

The files on the local host are created using the current user's uid/gid and umask.

use Bootleg.DSL

# copies ./my_file from the remote host to ./new_name locally
download :app, "my_file", "new_name"

# copies ./my_file from the remote host to the file ./a_dir/my_file locally
download :app, "my_file", "a_dir"

# recursively copies ./some_dir on the remote host to ./new_dir locally, ./new_dir
# will be created if missing
download :app, "some_dir", "new_dir"

# copies /foo/my_file on the remote host to /tmp/foo locally
download :app, "/foo/my_file", "/tmp/foo"

Specs

invoke(atom()) :: :ok

Invokes the task identified by task.

This is one of the cornerstones of the Bootleg DSL. Executing a task first calls any registered before_task/2 hooks, then executes the task itself (which was defined via task/2), then any registered after_task/2 hooks.

The execution of the hooks and the task are unconditional. Return values are ignored, though an uncuaght exception will stop further execution. The task does not need to exist. Any hooks for a task with the name of task will still be executed, and no error or warning will be emitted. This can be used to create events which a developer wants to be able to install hooks around without needing to define no-op tasks.

invoke/1 executes immediately, so it should always be called from inside a task. If it's placed directly inside config/deploy.exs, the task will be invoked when the configuration is first read. This is probably not what is desired.

use Bootleg.DSL

task :hello do
  IO.puts "Hello?"
  invoke :world
end

task :world do
  IO.puts "World!"
end

Executes commands on all remote hosts.

This is equivalent to calling remote/2 with a role of :all.

Link to this macro

remote(role, lines)

View Source (macro)

Executes commands on all remote hosts within a role.

This is equivalent to calling remote/3 with an options of [].

Link to this macro

remote(role, options, lines)

View Source (macro)

Executes commands on a remote host.

This is the workhorse of the DSL. It executes shell commands on all hosts associated with the role. If any of the shell commands exits with a non-zero status, execution will be stopped and an SSHError will be raised.

lines can be a List of commands to execute, or a code block where each line's return value is used as a command. Each command will be simulataneously executed on all hosts in the role. Once all hosts have finished executing the command, the next command in the list will be sent.

options is an optional Keyword list of options to customize the remote invocation. Currently two keys are supported:

  • filter takes a Keyword list of host options to filter with. Any host whose options match the filter will be included in the remote execution. A host matches if it has all of the filtering options defined and the values match (via ==/2) the filter.
  • cd changes the working directory of the remote shell prior to executing the remote commands. The options takes either an absolute or relative path, with relative paths being defined relative to the workspace configured for the role, or the default working directory of the shell if no workspace is defined.

role can be a single role, a list of roles, or the special role :all (all roles). If the same host exists in multiple roles, the commands will be run once for each role where the host shows up. In the case of multiple roles, each role is processed sequentially.

Returns the results to the caller, per command and per host. See Bootleg.SSH.run! for more details.

use Bootleg.DSL

remote :build, ["uname -a", "date"]
remote :build do
  "ls -la"
  "echo " <> Time.to_string(Time.utc_now) <> " > local_now"
end

# will raise an error since `false` exits with a non-zero status
remote :build, ["false", "touch never_gonna_happen"]

# runs for hosts found in all roles
remote do: "hostname"
remote :all, do: "hostname"

# runs for hosts found in :build first, then for hosts in :app
remote [:build, :app], do: "hostname"

role :build, "host2.example.com"
role :build, "host1.example.com", primary: true, another_attr: :cat

# only runs on `host1.example.com`
remote :build, filter: [primary: true] do
  "hostname"
end

# runs on `host1.example.com` inside the `tmp` directory found in the workspace
remote :build, filter: [primary: true], cd: "tmp/" do
  "hostname"
end
Link to this macro

role(name, hosts, options \\ [])

View Source (macro)

Defines a role.

Roles are a collection of hosts and their options that are responsible for the same function, for example building a release, archiving a release, or executing commands against a running application.

name is the name of the role, and is globally unique. Calling role/3 multiple times with the same name will result in the host lists being merged. If the same host shows up mutliple times, it will have its options merged. The name :all is reserved and cannot be used here.

hosts can be a single hostname, or a List of hostnames.

options is an optional Keyword used to provide configuration details about a specific host (or collection of hosts). Certain options are passed to SSH directly (see Bootleg.SSH.ssh_options/0), others are used internally (user for example, is used by both SSH and Git), and unknown options are simply stored. In the future remote/1,2 will allow for host filtering based on role options. Some Bootleg extensions may also add support for additional options.

use Bootleg.DSL

role :build, ["build1.example.com", "build2.example.com"], user: "foo", identity: "~/.ssh/id_rsa"
Link to this macro

task(task, options \\ [], list)

View Source (macro)

Defines a task idefintied by task.

This is one of the cornerstones of the Bootleg DSL. It takes a task name (task) a block of code and registers the code to be executed when task is invoked. Inside the block, the full Bootleg DSL is available.

A warning will be emitted if a task is redefined, unless the override option is specified with a value of true.

use Bootleg.DSL

task :hello do
  IO.puts "Hello World!"
end

Tasks can override existing tasks:

use Bootleg.DSL

task :update, override: true do
  alias Bootleg.UI
  UI.info("No longer using stock update task")
end
Link to this macro

upload(role, local_path, remote_path)

View Source (macro)

Uploads a local file to remote hosts.

Uploading works much like remote/3, but instead of transferring shell commands over SSH, it transfers files via SCP. The remote host does need to support SCP, which should be provided by most SSH implementations automatically.

role can either be a single role name, a list of roles, or a list of roles and filter attributes. The special :all role is also supported. See remote/3 for details.

local_path can either be a file or directory found on the local machine. If its a directory, the entire directory will be recursively copied to the remote hosts. Relative paths are resolved relative to the root of the local project.

remote_path is the file or directory where the transfered files should be placed. The semantics of how remote_path is treated vary depending on what local_path refers to. If local_path points to a file, remote_path is treated as a file unless it's . or ends in /, in which case it's treated as a directory and the filename of the local file will be used. If local_path is a directory, remote_path is treated as a directory as well. Relative paths are resolved relative to the projects remote workspace. Missing directories are not implicilty created.

The files on the remote server are created using the authenticating user's uid/gid and umask.

use Bootleg.DSL

# copies ./my_file to ./new_name on the remote host
upload :app, "my_file", "new_name"

# copies ./my_file to ./a_dir/my_file on the remote host. ./a_dir must already exist
upload :app, "my_file", "a_dir/"

# recursively copies ./some_dir to ./new_dir on the remote host. ./new_dir will be created if missing
upload :app, "some_dir", "new_dir"

# copies ./my_file to /tmp/foo on the remote host
upload :app, "my_file", "/tmp/foo"