Don't allow a capistrano deploy if code contains ruby debug statements
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
lib
.gitignore
Gemfile
LICENSE.txt
README.md
Rakefile
dont_deploy_debug.gemspec

README.md

DontDeployDebug

A gem against brain-farts.

How many times have you accidentally committed a debug statement and deployed it? To production? Ugh! I've been there, brothers and sisters! I've done it more times than I care to remember. So many that I finally decided to do something about it.

What?

DontDeployDebug is a Capistrano plugin that halts the deploy if finds debugging statement in your code.

It's only been tested with Capistrano 2. It requires the deploy server (e.g. server to which the code is being deployed) to have UNIX-style find(1) and grep(1) commands available in the deloy users path.

Example:

    triggering after callbacks for `deploy:finalize_update'
  * 2013-11-05 16:38:44 executing `deploy:find_ruby_breakpoints'
  * executing "find /home/deploy/app/releases/20131105233842 -name \"*.rb\" -exec grep -Hn 'debugger\|binding.pry' {} \\;"
    servers: ["server.example.org"]
    [server.example.org] executing command
    command finished in 621ms

*** Ruby debugger breakpoint found in deployed code. Deploy halted. ***

There was code found that contains debugging breakpoints:

  /testfile.rb:3:require 'ruby-debug'; debugger

Please remove the code, commit the change and try your deploy again.
If you feel you have reached this message in error, please consult
https://github.com/xunker/dont_deploy_debug to learn how to exclude
certain files, or how to tune the detection parameters. To override
this check, set the 'IGNORE_RUBY_BREAKPOINTS' variable to true:

  $ IGNORE_RUBY_BREAKPOINTS=true cap <environment> deploy

*** [deploy:update_code] rolling back
  * executing "rm -rf /home/deploy/app/releases/20131105233842; true"
    servers: ["server.example.org"]
    [server.example.org] executing command
    command finished in 159ms

Why?

Because even the rockstar-iest of ninjas sometimes forget to remove a 'debug'.

How?

It's a gem that hooks in to your Capistrano deploy process. After the code is updated on the server, but before it's made "live", the gem scans the release path for ruby source files that have "debug" statements in them. If any are found, the deploy is halted and rolled back, and a list of the offending files is displayed to the user.

By default, the gem looks for statements in *.rb that are like:

require 'ruby-debug'; debugger

require 'ruby-debug'
debugger

debugger;

binding.pry

The gem will ignore test/*, spec/*, features/* and config/deploy.rb.

Ruby only?

Yes, for now. But if there is any interest it could be easily modified for any language where the source was parsable on the deployment server.

Installation

Add this line to your application's Gemfile:

# ":require => false" is important!  
gem 'dont_deploy_debug', :require =>  false

Or from the command line if you aren't using bunder:

$ gem install dont_deploy_debug

Then, add the following to your Capistrano deploy.rb:

require 'capistrano/dont_deploy_debug'

For basic usage, this is all that is required.

Configuration

Enable or disable the check

Be default, every deploy will be checked regardless of environment. This can be set programmatically by altering the 'skip_ruby_breakpoint_check' setting in your deloy.rb file:

# turn off for all
set :skip_ruby_breakpoint_check, true

# skip on stage
set :skip_ruby_breakpoint_check, (fetch(:rails_env) == 'stage')

# on for everyone (default)
set :skip_ruby_breakpoint_check, false

Files to exclude from check

By default, test/*, spec/*, features/* and config/deploy.rb are ignored. You can modify this behaviour by changing the 'exclude_from_ruby_breakpoint_check' setting in your deploy.rb and adding or removing regular expressions:

set :exclude_from_ruby_breakpoint_check, [
  /^\/config\/deploy\.rb$/,
  /^\/spec\//,
  /^\/test\//,
  /^\/features\//,
  /^\/something_else_here\//,
]

Paths are relative from release_path and are prefixed with a / (slash).

Breakpoint patterns

By default, the gem will look for variations of:

require 'ruby-debug'; debugger

binding.pry

This can be changed by altering the "ruby_breakpoint_patterns" setting in your deploy.rb and adding or removing regular expressions:

set :ruby_breakpoint_patterns, [
  /require [\'\"]ruby-debug[\'\"][;\n]\s*debugger/,
  /^\s*debugger[;\n]/,
  /^\s*debugger\s*$/,
  /\bbinding\.pry\b/,
  /some_other_debugger/
]

Server-side find and grep command

To first find the files, the gem executes a find of the release path to get "coarse" list of files and then lets grep do the actual check. The command used by default is:

find #{release_path} -name "*.rb" -exec grep -Hn 'debugger\|binding.pry' {} \;

A find with grep is used instead of a recursive grep for better compatibility with non-GNU grep found some systems.

You can change this command in your deploy.rb with the "ruby_breakpoint_grep_command" setting:

# default value is:
#   Proc.new { "find #{release_path} -name \"*.rb\" -exec grep -Hn #{fetch(:ruby_breakpoint_trigger)} {} \\;" }

# pass it a Proc object so we can read release_path and other variables
# It MUST return a string
set :ruby_breakpoint_grep_command, Proc.new { "some better grep here" }

If you only want to change the pattern that grep() uses, you can set "ruby_breakpoint_trigger" instead:

# default value is " 'debugger\|binding.pry' "
# note the single quotes!
set :ruby_breakpoint_trigger, " 'some_other_pattern' "

Skipping check from command line

Finally, if you just want to deploy the damn'ed thing and skip the check temporarily, you can set the "IGNORE_RUBY_BREAKPOINTS" shell variable:

$ IGNORE_RUBY_BREAKPOINTS=true cap <environment> deploy

TODO

Caveats

This gem has not been throughly tested in any way. Like seriously. I use it, but I'm the only one so far. I've used it on Redhat and Debian derived systems, and it will likely work in most linuxes. It should work on any BSD system, but YMMV.

If you find a case where it doesn't work please let me know.