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
- Capistrano 3 compatibility
- Test with
capistrano-spec
(https://github.com/technicalpickles/capistrano-spec)
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.