Comparisons

Tomo is a SSH-based deployment tool written in Ruby, and so it is natural to compare it with the many other popular Ruby tools in that category. Here are some specific design choices that make tomo different.

  • Proven built-in Rails support. Tomo includes all the setup and deployment tasks you need to deploy a basic Rails app. On top of that, every release of tomo is automatically tested to verify that it can successfully deploy the latest versions of Rails, Bundler, and Ruby out of the box.
  • Opinionated defaults. The tasks built-into tomo provide a very opinionated deployment: rbenv and nodenv to install ruby and node, puma via systemd with socket activation for zero-downtime restarts, 12-factor style configuration (environment variables as opposed to configuration files), and so on. Tomo provides a strong set of production-tested conventions without you needing to piece together snippets from blog posts or tutorials.
  • Easy to extend. Unlike other Ruby deployment tools that layer DSL monkey patches on top of rake, tomo is built from the ground up with modern CLI conventions, testability, and simplicity in mind. Tomo takes care of SSH connection management for you, and the ordering of deployment and setup operations is purely configuration based. There are no complex chains of prerequisites or programmatic before/after hooks to deal with. All you have to do is write plain Ruby methods utilizing a concise API.

Code example

To get an idea of how much simpler tomo can be, here is an example of the same task implemented in capistrano vs tomo:

# capistrano
task :precompile do
  on release_roles(fetch(:assets_roles)) do
    within release_path do
      with rails_env: fetch(:rails_env), rails_groups: fetch(:rails_assets_groups) do
        execute :rake, "assets:precompile"
      end
    end
  end
end
# tomo
def assets_precompile
  remote.rake("assets:precompile")
end

Features

Here’s how tomo compares with the most popular Ruby-based deployment tools: Capistrano and Mina.

Tomo Capistrano Mina
First release 2019 2009 2012
Required gem dependencies 0 7 2
Minimum supported ruby version 2.6 2.0 2.0
Configuration files 1 (.tomo/config.rb) 3+ (Capfile, config/deploy.rb, config/deploy/*.rb per stage) 1 (config/deploy.rb)
Deploy in parallel to multiple hosts ✅ Yes ✅ Yes ❌ No
Configure multiple environments/stages ✅ Yes ✅ Yes ✅ Yes, via custom rake tasks
Simulate a deploy (dry run) ✅ Yes ✅ Yes ✅ Yes
Customizable deploy command ✅ Yes, via config ✅ Yes, via rake tasks that attach before/after hooks ✅ Yes, via rake task
Built-in setup or “cold deploy” command ✅ Yes ❌ No ✅ Yes
Automated host setup (ruby, bundler, yarn, etc.) ✅ Yes ❌ No ❌ No
Rollback command ❌ No ✅ Yes ✅ Yes
Manage host environment variables (SECRET_KEY_BASE, DATABASE_URL, etc.) ✅ Yes ❌ No ❌ No
Automated testing of deploying Rails end-to-end ✅ Yes, via CircleCI ❌ No ❌ No
Built-in Rails web server tasks ✅ Yes, puma with systemd ❌ No ❌ No
Built-in ruby version manager tasks ✅ Yes, rbenv ❌ No ✅ Yes, chruby, rbenv, rvm, ry
Built-in node version manager tasks ✅ Yes, nodenv ❌ No ❌ No
SSH command execution One at a time One at a time Batched
SSH implementation Native Ruby (net-ssh) Native
SSH connection management Automatic Explicit Automatic
Task framework Tomo-specific Rake Rake
Tasks can invoke other tasks ❌ No ✅ Yes ✅ Yes
Tasks can modify settings on the fly ❌ No ✅ Yes ✅ Yes
Tasks can have before/after hooks ❌ No ✅ Yes, via DSL ✅ Yes, via rake
DSL availability Inside task definitions only Global mixin (monkey patch) Global mixin (monkey patch)
DSL for running scripts locally (as opposed to on remote host) ❌ No ✅ Yes ✅ Yes
DSL for uploading ERB templates ✅ Yes ❌ No ❌ No