Custom tasks
Simple examples
Let’s write a simple custom task:
task :add_to_priv do
on build_host do |host|
within build_path do
execute :mkdir, "-p", "priv"
execute :cp, "/etc/hostname", "priv/"
end
end
end
While not being terribly useful, this gives you an idea of what we can do:
At some point in time, on the build host within the build path,
we create the priv
directory and copy /etc/hostname
into it.
If we make this happen before distillery’s release
mix task runs, the file
will be part of the application in the release (that’s what priv
is for). So let’s do just that,
using a hook:
before "buildhost:mix:release", :add_to_priv
Custom tasks can be useful even when they are not part of the normal deploy process. Administrative tasks being executed on the target nodes can be executed through capistrano. Let’s write an example:
desc "Does hosekeeping on the node yadda yadda"
task "node:janitor" do
on app_hosts do |host|
within app_path do
# do some janitorial task here
end
end
end
Now you can enter bundle exec cap staging node:janitor
to have the task executed on all
staging nodes.
The desc
line adds documentation to your task that will appear when you run bundle exec cap -T
.
Running mix tasks and other code on a node
On the build host, mix tasks can be run as usual. You can find an example snippet below.
On a node, mix tasks are usually not available. Instead, you can execute arbitrary
elixir code by using the execute_elixir
method in your node task. An example can be found below.
Available API
For the general mechanics of executing commands (with environment, in a path, in parallel) or up/downloading files please see the SSHKit documentation. Capistrano includes the DSL from SSHKit to make all of this available for us.
Carafe defines a handfull of methods to be used by tasks. See the documentation of the DSL module.
Where to put custom tasks and where to trigger them
If your tasks are only a few, short snippets, you can keep them in config/deploy.rb
.
Otherwise, put them into a file matching the pattern lib/capistrano/tasks/*.rake
, and they will automatically be available.
Ecto and Phoenix task snippets
Building assets into the release (with brunch)
task "build:assets" do
on roles(:build) do |host|
within build_path.join("assets") do
execute :npm, "install"
execute "node_modules/.bin/brunch", "build --production"
end
within build_path do
with mix_env: mix_env do
execute :mix, "phx.digest"
end
end
end
end
Migrating up
task "node:migrate:up" do
on roles(:db) do |host|
within app_path do
elixir = %{
path = Application.app_dir(:my_app, "priv/repo/migrations")
Ecto.Migrator.run(MyApp.Repo, path, :up, all: true)
}
execute_elixir elixir
end
end
end
Note that the ruby variable elixir
here contains a string of Elixir code that
is run on the node.