Skip to content

Instantly share code, notes, and snippets.

@AntoineAugusti
Created March 13, 2017 12:40
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AntoineAugusti/a379d4060da40e1ec4218a4e6e3974dc to your computer and use it in GitHub Desktop.
Save AntoineAugusti/a379d4060da40e1ec4218a4e6e3974dc to your computer and use it in GitHub Desktop.
Code for the blog article about Reporting console commands in Rails
is_staging_or_prod = Rails.env.production? || Rails.env.staging?
dyno_in_run_mode = ENV.fetch('DYNO', 'nope').starts_with?('run')
dev_name = ENV.fetch('DEV_NAME', '')
if is_staging_or_prod && dyno_in_run_mode
raise Drivy::Errors::DevNameNotSetError if dev_name.blank?
# Override how printing to sdtout works by sending
# the output of stdout to a Slack webhook also.
# When writing commands in irb, irb prints to stdout
class << STDOUT
include Drivy::Console::ReportCommand
alias :usual_write :write
def write(string)
usual_write(string)
send_command_to_slack(dev_name, string)
end
end
end
module Drivy::Console::ReportCommand
def send_command_to_slack(developer_name, command_output)
return unless has_command? && has_output?(command_output)
# Documentation is at https://api.slack.com/docs/message-attachments
fields = [
{
title: "Command",
value: wrap_command(read_command),
short: true,
},
{
title: "Output",
value: wrap_command(parse_output(command_output)),
short: false,
},
{
title: "Developer",
value: developer_name,
short: true,
}
]
env_color, env_title = env_params
params = {
attachments: [
{
fields: fields,
color: env_color,
footer: "Console #{env_title} spy",
footer_icon: "https://drivy-prod-static.s3.amazonaws.com/slack/spy-small.png",
ts: Time.zone.now.to_i,
mrkdwn_in: ["fields"],
}
]
}
response = slack_client.post('', params)
raise "Failed to notify Slack of console command, status: #{response.status}" unless response.success?
end
private
def env_params
if Rails.env.production?
return ["#e74c3c", "production"] # red
elsif Rails.env.staging?
return ["#f1c40f", "staging"] # orange
else
return ["#2ecc71", "development"] # yellow
end
end
def wrap_command(value)
"```#{value}```"
end
def parse_output(command_output)
command_output.gsub('=>', '').strip
end
def has_command?
Readline::HISTORY.length >= 1
end
def has_output?(command_output)
return false unless command_output.instance_of? String
command_output.strip.start_with? "=>"
end
def read_command
Readline::HISTORY[Readline::HISTORY.length-1]
end
def slack_client
endpoint = ENV.fetch('SLACK_WEBHOOK_CONSOLE', '')
raise "SLACK_WEBHOOK_CONSOLE is not defined" if endpoint.blank?
Faraday.new(url: endpoint) do |c|
c.request :json
c.adapter Faraday.default_adapter
end
end
end
@rahul
Copy link

rahul commented May 20, 2018

Hey, thank you for this creative way of reporting commands in Rails to slack.

I'm facing an issue that's preventing me from deploying this.

Heroku's build process seems to kick off a one-off dyno' in order to deploy the application, which satisfies the dyno_in_run_mode` check in the code.

But at the time of deployment, ENV['DEV_NAME'] isn't expected to be set. We're expecting the dev pass along a temporary environment variable whenever they start the rails console (eg: heroku run EXEC_USER_NAME=rahul rails console).

So, due to the missing DEV_NAME, the deployment fails because dyno_in_run_mode is true during deployment.

Is this an issue that you've come across?

@mzaragoza
Copy link

Hi, Thanks for building this. I was just wondering how to get it to fire on the console load for the first time.

@AntoineAugusti
Copy link
Author

@rahul You're supposed to pass the env variable to the one-off dyno on Heroku. This means, as you found out, passing an env variable to the Heroku CLI.

@AntoineAugusti
Copy link
Author

@mzaragoza You can put it in the initializer. This code is executed at console boot if I remember well. Just after this line https://gist.github.com/AntoineAugusti/a379d4060da40e1ec4218a4e6e3974dc#file-console_spy_initializer-rb-L6 should do the trick.

@mzaragoza
Copy link

@AntoineAugusti Thanks for your help.
I was wondering if there is a way to back multiple lines?

An example I type this into the console

def test
  puts 'test'
end

then console_spy returns with:

Command: end
Output: : test

I would like that the command would say that the Command would be something like

def test
  puts 'test'
end

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment