This repository has been archived by the owner on Dec 8, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add installer and remove the need for any configuration (#61)
* Add installer and remove the need for any configuration * Fix readme * Cleanup readme * Add docs * Finish installer * Update * Define config * Fix tests * Update config template * Update readme * Fix readme * Fix tests * Check for tagged logger * Update schema version
- Loading branch information
1 parent
e902787
commit 6c03473
Showing
21 changed files
with
834 additions
and
367 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#!/usr/bin/env ruby | ||
|
||
$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")) | ||
require "timber/cli" | ||
|
||
begin | ||
Timber::CLI.run | ||
rescue => e | ||
raise e if $DEBUG | ||
STDERR.puts e.message | ||
STDERR.puts e.backtrace.join("\n") | ||
exit 1 | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module Timber | ||
class AuthCheck | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
require "optparse" | ||
require "yaml" | ||
require "timber" | ||
|
||
|
||
require "timber/cli/api" | ||
require "timber/cli/application" | ||
require "timber/cli/io_helper" | ||
require "timber/cli/messages" | ||
|
||
require "timber/cli/install" | ||
|
||
module Timber | ||
class CLI | ||
AVAILABLE_COMMANDS = %w(install).freeze | ||
|
||
class << self | ||
attr_accessor :options | ||
|
||
def run(argv = ARGV) | ||
@options = {} | ||
global = global_option_parser | ||
commands = command_option_parser | ||
global.order!(argv) | ||
command = argv.shift | ||
if command | ||
if AVAILABLE_COMMANDS.include?(command) | ||
commands[command].parse!(argv) | ||
case command.to_sym | ||
when :install | ||
Timber::CLI::Install.run(argv.shift) | ||
end | ||
else | ||
puts "Command '#{command}' does not exist, run timber -h to "\ | ||
"see the help" | ||
exit(1) | ||
end | ||
else | ||
# Print help | ||
puts global | ||
exit(0) | ||
end | ||
end | ||
|
||
def global_option_parser | ||
OptionParser.new do |o| | ||
o.banner = "Usage: timber <command> [options]" | ||
|
||
o.on "-v", "--version", "Print version and exit" do |_arg| | ||
puts "Timber #{Timber::VERSION}" | ||
exit(0) | ||
end | ||
|
||
o.on "-h", "--help", "Show help and exit" do | ||
puts o | ||
exit(0) | ||
end | ||
|
||
o.separator "" | ||
o.separator "Available commands: #{AVAILABLE_COMMANDS.join(", ")}" | ||
end | ||
end | ||
|
||
def command_option_parser | ||
{ | ||
"install" => OptionParser.new | ||
} | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
require "base64" | ||
require "json" | ||
require "net/https" | ||
require "securerandom" | ||
require "uri" | ||
|
||
module Timber | ||
class CLI | ||
class API | ||
class APIKeyInvalidError < StandardError | ||
def message | ||
"Uh oh! The API key supplied is invalid. Please ensure that you copied the" \ | ||
" key properly.\n\n#{Messages.obtain_key_instructions}" | ||
end | ||
end | ||
|
||
class NoAPIKeyError < StandardError | ||
def message | ||
"Uh oh! You didn't supply an API key.\n\n#{Messages.obtain_key_instructions}" | ||
end | ||
end | ||
|
||
TIMBER_API_URI = URI.parse('https://api.timber.io') | ||
APPLICATION_PATH = "/installer/application".freeze | ||
EVENT_PATH = "/installer/events".freeze | ||
HAS_LOGS_PATH = "/installer/has_logs".freeze | ||
USER_AGENT = "Timber Ruby/#{Timber::VERSION} (HTTP)".freeze | ||
|
||
def initialize(api_key) | ||
@api_key = api_key | ||
@session_id = SecureRandom.uuid | ||
end | ||
|
||
def application! | ||
get!(APPLICATION_PATH) | ||
end | ||
|
||
def event!(name, data = {}) | ||
post!(EVENT_PATH, event: {name: name, data: data}) | ||
end | ||
|
||
def wait_for_logs(iteration = 0, &block) | ||
if block_given? | ||
yield iteration | ||
end | ||
|
||
sleep 0.5 | ||
|
||
res = get!(HAS_LOGS_PATH) | ||
|
||
case res.code | ||
when "202" | ||
wait_for_logs(iteration + 1, &block) | ||
|
||
when "204" | ||
true | ||
end | ||
end | ||
|
||
private | ||
def get!(path) | ||
req = Net::HTTP::Get.new(path) | ||
issue!(req) | ||
end | ||
|
||
def post!(path, body) | ||
req = Net::HTTP::Post.new(path) | ||
req.body = body.to_json | ||
req['Content-Type'] = "application/json" | ||
issue!(req) | ||
end | ||
|
||
def issue!(req) | ||
req['Authorization'] = "Basic #{encoded_api_key}" | ||
req['User-Agent'] = USER_AGENT | ||
req['X-Installer-Session-Id'] = @session_id | ||
res = http.start do |http| | ||
http.request(req) | ||
end | ||
|
||
if res.code == "401" | ||
raise NoAPIKeyError.new | ||
elsif res.code == "403" | ||
raise APIKeyInvalidError.new | ||
else | ||
res | ||
end | ||
end | ||
|
||
def http | ||
@http ||= begin | ||
http = Net::HTTP.new(TIMBER_API_URI.host, TIMBER_API_URI.port) | ||
http.use_ssl = true | ||
http.verify_mode = OpenSSL::SSL::VERIFY_NONE | ||
http | ||
end | ||
end | ||
|
||
def encoded_api_key | ||
Base64.urlsafe_encode64(@api_key).chomp | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
require "json" | ||
|
||
module Timber | ||
class CLI | ||
class Application | ||
|
||
attr_reader :api_key, :environment, :framework_type, :heroku_drain_url, :language_type, | ||
:name, :platform_type | ||
|
||
def initialize(api) | ||
res = api.application! | ||
parsed_body = JSON.parse(res.body) | ||
application_data = parsed_body.fetch("data") | ||
@api_key = application_data.fetch("api_key") | ||
@environment = application_data.fetch("environment") | ||
@framework_type = application_data.fetch("framework_type") | ||
@heroku_drain_url = application_data.fetch("heroku_drain_url") | ||
@language_type = application_data.fetch("language_type") | ||
@name = application_data.fetch("name") | ||
@platform_type = application_data.fetch("platform_type") | ||
end | ||
|
||
def heroku? | ||
platform_type == "heroku" | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
require "fileutils" | ||
|
||
module Timber | ||
class CLI | ||
class Install | ||
EXCLUDED_ENVIRONMENTS = ["test"].freeze | ||
|
||
class << self | ||
include IOHelper | ||
|
||
def run(api_key) | ||
puts "" | ||
puts colorize(Messages.header, :green) | ||
puts colorize(Messages.separator, :green) | ||
puts colorize(Messages.contact, :green) | ||
puts colorize(Messages.separator, :green) | ||
puts "" | ||
|
||
if !api_key | ||
puts colorize(Messages.no_api_key_provided, :red) | ||
return | ||
end | ||
|
||
api = API.new(api_key) | ||
|
||
api.event!(:started) | ||
|
||
app = Application.new(api) | ||
|
||
puts "Woot! Your API 🔑 is valid. Here are you application details:" | ||
puts "" | ||
puts "Name: #{app.name} (#{app.environment})" | ||
puts "Framework: #{app.framework_type}" | ||
puts "Platform: #{app.platform_type}" | ||
puts "" | ||
|
||
case ask_yes_no("Are the above details correct?") | ||
when :yes | ||
if app.heroku? | ||
puts "" | ||
puts Messages.separator | ||
puts "" | ||
puts Messages.heroku_install(app) | ||
puts "" | ||
|
||
else | ||
puts "" | ||
puts Messages.separator | ||
puts "" | ||
puts "How would you like configure Timber?" | ||
puts "" | ||
puts "1) Using environment variables" | ||
puts "2) Configuring in my app" | ||
puts "" | ||
|
||
case ask("Enter your choice: (1/2) ") | ||
when "1" | ||
puts "" | ||
puts Messages.http_environment_variables(app.api_key) | ||
puts "" | ||
|
||
when "2" | ||
puts "" | ||
write Messages.task_start("Creating config/initializers/timber.rb") | ||
|
||
create_initializer("http", app) | ||
|
||
puts colorize(Messages.task_complete("Creating config/initializers/timber.rb"), :green) | ||
end | ||
|
||
send_test_messages(api_key) | ||
end | ||
|
||
api.wait_for_logs do |iteration| | ||
write Messages.task_start("Waiting for logs") | ||
write Messages.spinner(iteration) | ||
end | ||
|
||
puts colorize(Messages.task_complete("Waiting for logs"), :green) | ||
|
||
puts "" | ||
puts Messages.separator | ||
puts "" | ||
puts Messages.finish | ||
|
||
api.event!(:success) | ||
|
||
collect_feedback(api) | ||
|
||
when :no | ||
puts "" | ||
puts "Bummer. Head to this URL to update the details:" | ||
puts "" | ||
puts " #{Messages.edit_app_url(app)}" | ||
puts "" | ||
puts "exiting..." | ||
return false | ||
end | ||
end | ||
|
||
private | ||
def create_initializer(log_device, app) | ||
body = "config = Timber::Config.instance\n" \ | ||
"config.log_device = Timber::LogDevices::HTTP.new(\"#{app.api_key}\")\n\n" \ | ||
"# More config options can be found at: https://timber.io/docs/ruby/configuration/\n" \ | ||
"#\n" \ | ||
"# Question? Need help?\n" \ | ||
"# * Docs: https://timber.io/docs\n" \ | ||
"# * Support: support@timber.io" \ | ||
|
||
FileUtils.mkdir_p(File.join(Dir.pwd, "config", "initializers")) | ||
File.write(File.join(Dir.pwd, "config/initializers/timber.rb"), body) | ||
end | ||
|
||
def send_test_messages(api_key) | ||
write Messages.task_start("Sending test logs") | ||
|
||
http_device = LogDevices::HTTP.new(api_key) | ||
logger = Logger.new(http_device) | ||
logger.info("test") | ||
|
||
puts colorize(Messages.task_complete("Sending test logs"), :green) | ||
end | ||
|
||
def collect_feedback(api) | ||
puts "" | ||
rating = ask("How would rate this install experience? 1 (bad) - 5 (perfect)") | ||
case rating | ||
when "4", "5" | ||
api.event!(:feedback, rating: rating.to_i) | ||
puts "" | ||
puts Messages.we_love_you_too | ||
|
||
when "1", "2", "3" | ||
puts "" | ||
puts Messages.bad_experience_message | ||
puts "" | ||
|
||
comments = ask("Type your comments (enter sends)") | ||
|
||
api.event!(:feedback, rating: rating.to_i, comments: comments) | ||
|
||
puts "" | ||
puts "Thank you! We take feedback seriously and will work to improve this." | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.