Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent Rake's sh command from echoing the command

Tags:

ruby

rake

Whenever I call sh from rake it often echos the command that will be ran right before it is run. How can I prevent sh from logging the commands to stdout. I'd like to prevent this as I have api keys in the command I am calling, and I don't want to expose them in my build log.

like image 710
TerribleDev Avatar asked Jul 03 '16 17:07

TerribleDev


1 Answers

There are two parts to solving this. The first is to pass the verbose: false option, which will prevent the command from being printed before it's executed:

$ cat Rakefile
SECRET = 'foobarbaz'

task :foo do
  sh "echo #{SECRET} > secrets.txt", verbose: false
end

$ rake foo
(no output)

However, this doesn't help if there's an error, since Rake will print the failed command if it returns an error:

$ cat Rakefile
SECRET = 'foobarbaz'

task :foo do
  sh "echo #{SECRET} > secrets.txt; exit 1", verbose: false
end

$ rake foo
rake aborted!
Command failed with status (1): [echo foobarbaz > secrets.txt; exit 1...]
...

The solution is hinted at in the docs for sh:

If a block is given, upon command completion the block is called with an OK flag (true on a zero exit status) and a Process::Status object. Without a block a RuntimeError is raised when the command exits non-zero.

You can see where the default behavior comes from in the Rake source. The solution, then, is to supply our own block:

$ cat Rakefile
SECRET = "foobarbaz"

task :foo do
  sh "echo #{SECRET} > secrets.txt; exit 1", verbose: false do |ok, status|
    unless ok
      fail "Command failed with status (#{status.exitstatus}): [command hidden]"
    end
  end
end

$ rake foo
rake aborted!
Command failed with status (1): [command hidden]
...

Looks good!

If you find yourself needing this in multiple places, you could write a convenience method; something like this:

def quiet_sh(*cmd)
  options = (Hash === cmd.last) ? cmd.pop : {}
  options = { verbose: false }.merge(options)

  sh *cmd, options do |ok, status|
    unless ok
      fail "Command failed with status (#{status.exitstatus}): [command hidden]"
    end
  end
end

SECRET = "foobarbaz"

task :foo do
  quiet_sh "do_secret_things"
end
like image 89
Jordan Running Avatar answered Oct 15 '22 14:10

Jordan Running