Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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

This comment has been minimized.

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

This comment has been minimized.

Copy link

mzaragoza commented Nov 15, 2019

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

@AntoineAugusti

This comment has been minimized.

Copy link
Owner Author

AntoineAugusti commented Nov 16, 2019

@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

This comment has been minimized.

Copy link
Owner Author

AntoineAugusti commented Nov 16, 2019

@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

This comment has been minimized.

Copy link

mzaragoza commented Dec 9, 2019

@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
You can’t perform that action at this time.