Custom Workflows
Bootleg Tasks
Bootleg defines a number of tasks that are used during the default workflow.
Build Tasks
build
- build process for creating a release packageinit
- sets up a bare repository for pushing code toclean
- cleans the remote workspacepush_remote
- pushes code to build serverreset_remote
- checks out the branch specified byrefspec
option (defaults tomaster
)compile
- compilation of your projectgenerate_release
- generation of the release packagedownload_release
- pulls down the release archive
Deployment Tasks
deploy
- deploy of a release packageupload_release
unpack_release
Build and Deploy
update
build
deploy
stop_silent
start
Management tasks
start
- starting of a releasestop
- stopping of a releaserestart
- restarting of a releaseping
- check connectivity to a deployed app
Hooks
Hooks may be defined by the user in order to perform additional (or exceptional) operations before or after certain actions performed by Bootleg.
Hooks can be defined for any task (built-in or user defined), even those that do not exist. This can be used to create an “event” that you want to respond to, but has no real “implementation”.
To register a hook, use:
before_task <:task> do ... end
- Beforetask
executes, execute the provided code block.after_task <:task> do ... end
- Aftertask
executes, execute the provided code block.
For example:
use Bootleg.DSL
before_task :build do
IO.puts "Starting build..."
end
after_task :deploy do
MyAPM.notify_deploy()
end
You can define multiple hooks for a task, and they will be executed in the order they are defined. For example:
use Bootleg.DSL
before_task :start do
IO.puts "This may take a bit"
end
after_task :start do
IO.puts "Started app!"
end
before_task :start do
IO.puts "Starting app!"
end
would result in:
$ mix bootleg.build
This may take a bit
Starting app!
...
Started app!
$
invoke
and task
There are a few ways for custom code to be executed during the Bootleg life cycle. Before showing some examples, here’s a quick glossary of the related pieces.
task <:identifier> do ... end
- Assign a block of code to the atom provided as:identifier
. This can then be executed by using theinvoke
macro.invoke <:identifier>
- Execute thetask
code blocked identified by:identifier
, as well as any before/after hooks.
NOTE: Invoking an undefined task is not an error and any registered hooks will still be executed.
use Bootleg.DSL
before_task :build do
IO.puts "Hello"
invoke :custom_event
end
task :custom_task do
IO.puts "World"
end
after_task :custom_event do
IO.puts "Elixir"
invoke :custom_task
end
A shortened before
/after
syntax can be used to simply invoke a task directly from an event.
task :clear_cache do
{:ok, _} = remote do
"rm -rf /tmp/cache"
end
end
before_task :restart, do: :clear_cache
Alternatively:
before_task :restart do
{:ok, _output} = remote do
"rm -rf /tmp/cache"
end
end
remote
The workhorse of the Bootleg DSL is remote
: it executes shell commands on remote servers and returns
the results. It takes a role and a block of commands to execute. The commands are executed on all servers
belonging to the role, and raises an SSHError
if an error is encountered. Optionally, a list of options
can be provided to filter the hosts where the commands are run.
use Bootleg.DSL
# basic
remote :app do
"echo hello"
end
# multi line
remote :app do
"touch ~/file.txt"
"rm file.txt"
end
# getting the result
[{:ok, [stdout: output], _, _}] = remote :app do
"ls -la"
end
# raises an SSHError
remote :app do
"false"
end
# filtering - only runs on app hosts with an option of primary set to true
remote :app, filter: [primary: true] do
"mix ecto.migrate"
end
# change working directory - creates a file `/tmp/foo`, regardless of the role
# workspace configuration
remote :app, cd: "/tmp" do
"touch ./foo"
end
Custom configuration and hooks
Similar to how bootleg_phoenix
is implemented, you can make use of the hooks system to run some commands on the build server around compile time.
task :phx_digest do
remote :build, cd: "assets" do
"npm install"
"./node_modules/brunch/bin/brunch b -p"
end
remote :build do
"MIX_ENV=prod mix phx.digest"
end
end
after_task :compile, :phx_digest
Task Providers
Sharing is a good thing. Bootleg supports loading
tasks from packages in a manner very similar to Mix.Task
.
You can create and share custom tasks by namespacing a module under Bootleg.Tasks
and passing a block of Bootleg DSL:
defmodule Bootleg.Tasks.Foo do
use Bootleg.Task do
task :foo do
IO.puts "Foo!!"
end
before_task :build, :foo
end
end
In order to be found and loaded by Bootleg, external tasks need to be loaded via a Mix.Project
dependency.
See also: Bootleg.Task for additional examples.