Class: HerokuGarden::CommandLine
- Inherits:
-
Object
- Object
- HerokuGarden::CommandLine
- Defined in:
- lib/herokugarden/command_line.rb
Overview
This wraps the Heroku::Client class with higher-level actions suitable for use from the command line.
Defined Under Namespace
Classes: CommandFailed
Instance Attribute Summary collapse
-
#credentials ⇒ Object
Returns the value of attribute credentials.
Instance Method Summary collapse
- #add_collaborator(name, email, access) ⇒ Object
- #add_key(keyfile = nil) ⇒ Object
- #ask_for_credentials ⇒ Object
- #ask_for_password ⇒ Object
- #ask_for_password_on_windows ⇒ Object
- #attempt_git_transition(gitconfig, app_name, domain) ⇒ Object
- #authkey ⇒ Object
- #authkey_read(filename) ⇒ Object
- #authkey_type(key_type) ⇒ Object
- #clone(args) ⇒ Object
- #collaborators(args) ⇒ Object
- #create(args) ⇒ Object
- #credentials_file ⇒ Object
- #delete_credentials ⇒ Object
- #destroy(args) ⇒ Object
-
#display(msg) ⇒ Object
^^^ Deprecated.
- #echo_off ⇒ Object
- #echo_on ⇒ Object
- #execute(command, args) ⇒ Object
- #extract_error(response) ⇒ Object
- #extract_key! ⇒ Object
- #extract_option(args, options, valid_values = nil) ⇒ Object
- #find_key ⇒ Object
-
#get_credentials ⇒ Object
:nodoc:.
- #git_repo_for(name) ⇒ Object
- #git_transition(args) ⇒ Object
-
#heroku ⇒ Object
:nodoc:.
- #home_directory ⇒ Object
- #info(args) ⇒ Object
-
#init_heroku ⇒ Object
:nodoc:.
- #keys(*args) ⇒ Object
- #list(args) ⇒ Object
- #list_collaborators(name) ⇒ Object
- #list_keys ⇒ Object
- #parse_error_xml(body) ⇒ Object
-
#password ⇒ Object
:nodoc:.
- #rake(args) ⇒ Object
- #read_credentials ⇒ Object
- #remove_collaborator(name, email) ⇒ Object
- #remove_key(arg) ⇒ Object
- #retry_login? ⇒ Boolean
- #running_on_windows? ⇒ Boolean
- #save_credentials ⇒ Object
- #set_credentials_permissions ⇒ Object
- #sharing(args) ⇒ Object
- #update(args) ⇒ Object
- #update_collaborator(name, email, access) ⇒ Object
-
#upload_authkey(*args) ⇒ Object
vvv Deprecated.
-
#user ⇒ Object
:nodoc:.
- #write_credentials ⇒ Object
Instance Attribute Details
#credentials ⇒ Object
Returns the value of attribute credentials.
194 195 196 |
# File 'lib/herokugarden/command_line.rb', line 194 def credentials @credentials end |
Instance Method Details
#add_collaborator(name, email, access) ⇒ Object
123 124 125 |
# File 'lib/herokugarden/command_line.rb', line 123 def add_collaborator(name, email, access) display heroku.add_collaborator(name, email, access) end |
#add_key(keyfile = nil) ⇒ Object
368 369 370 371 372 373 374 |
# File 'lib/herokugarden/command_line.rb', line 368 def add_key(keyfile=nil) keyfile ||= find_key key = File.read(keyfile) display "Uploading ssh public key #{keyfile}" heroku.add_key(key) end |
#ask_for_credentials ⇒ Object
241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/herokugarden/command_line.rb', line 241 def ask_for_credentials puts "Enter your Heroku credentials." print "Email: " user = gets.strip print "Password: " password = running_on_windows? ? ask_for_password_on_windows : ask_for_password [ user, password ] end |
#ask_for_password ⇒ Object
270 271 272 273 274 275 276 |
# File 'lib/herokugarden/command_line.rb', line 270 def ask_for_password echo_off password = gets.strip puts echo_on return password end |
#ask_for_password_on_windows ⇒ Object
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/herokugarden/command_line.rb', line 253 def ask_for_password_on_windows require "Win32API" char = nil password = '' while char = Win32API.new("crtdll", "_getch", [ ], "L").Call do break if char == 10 || char == 13 # received carriage return or newline if char == 127 || char == 8 # backspace and delete password.slice!(-1, 1) else password << char.chr end end puts return password end |
#attempt_git_transition(gitconfig, app_name, domain) ⇒ Object
181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/herokugarden/command_line.rb', line 181 def attempt_git_transition(gitconfig, app_name, domain) heroku.host = domain if [nil, 'true'].include?(heroku.info(app_name, true)[:stack2]) raise HerokuGarden::CommandLine::CommandFailed, "#{app_name} is running on the Heroku production platform.\nThis git repo URL is valid and does not need to be changed." else File.open(Dir.pwd + '/.git/config', 'w') do |f| f.write gitconfig.gsub("url = [email protected]:#{app_name}.git", "url = [email protected]:#{app_name}.git") end display "This git repo for #{app_name} has been updated to the new herokugarden.com URL." end end |
#authkey ⇒ Object
416 417 418 419 420 421 422 423 |
# File 'lib/herokugarden/command_line.rb', line 416 def authkey return @ssh_key if @ssh_key %w( rsa dsa ).each do |key_type| key = authkey_type(key_type) return key if key end raise "Your ssh public key was not found. Make sure you have a rsa or dsa key in #{home_directory}/.ssh, or specify the full path to the keyfile." end |
#authkey_read(filename) ⇒ Object
412 413 414 |
# File 'lib/herokugarden/command_line.rb', line 412 def authkey_read(filename) File.read(filename) if File.exists?(filename) end |
#authkey_type(key_type) ⇒ Object
408 409 410 |
# File 'lib/herokugarden/command_line.rb', line 408 def authkey_type(key_type) authkey_read("#{home_directory}/.ssh/id_#{key_type}.pub") end |
#clone(args) ⇒ Object
78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/herokugarden/command_line.rb', line 78 def clone(args) name = args.shift.downcase.strip rescue "" if name.length == 0 or name.slice(0, 1) == '-' display "Usage: herokugarden clone <app>" display "(this command is deprecated in favor of using the git repo url directly)" else cmd = "git clone #{git_repo_for(name)}" display cmd system cmd end end |
#collaborators(args) ⇒ Object
119 120 121 |
# File 'lib/herokugarden/command_line.rb', line 119 def collaborators(args) sharing(args) end |
#create(args) ⇒ Object
51 52 53 54 55 |
# File 'lib/herokugarden/command_line.rb', line 51 def create(args) name = args.shift.downcase.strip rescue nil name = heroku.create(name, {}) display "Created http://#{name}.#{heroku.host}/ | git@#{heroku.host}:#{name}.git" end |
#credentials_file ⇒ Object
214 215 216 |
# File 'lib/herokugarden/command_line.rb', line 214 def credentials_file "#{home_directory}/.heroku/herokugarden_credentials" end |
#delete_credentials ⇒ Object
315 316 317 |
# File 'lib/herokugarden/command_line.rb', line 315 def delete_credentials FileUtils.rm_f(credentials_file) end |
#destroy(args) ⇒ Object
90 91 92 93 94 95 96 97 98 |
# File 'lib/herokugarden/command_line.rb', line 90 def destroy(args) name = args.shift.strip.downcase rescue "" if name.length == 0 or name.slice(0, 1) == '-' display "Usage: herokugarden destroy <app>" else heroku.destroy(name) display "Destroyed #{name}" end end |
#display(msg) ⇒ Object
^^^ Deprecated
426 427 428 |
# File 'lib/herokugarden/command_line.rb', line 426 def display(msg) puts msg end |
#echo_off ⇒ Object
233 234 235 |
# File 'lib/herokugarden/command_line.rb', line 233 def echo_off system "stty -echo" end |
#echo_on ⇒ Object
237 238 239 |
# File 'lib/herokugarden/command_line.rb', line 237 def echo_on system "stty echo" end |
#execute(command, args) ⇒ Object
8 9 10 11 12 13 14 15 16 17 18 |
# File 'lib/herokugarden/command_line.rb', line 8 def execute(command, args) send(command, args) rescue RestClient::Unauthorized display "Authentication failure" rescue RestClient::ResourceNotFound display "Resource not found. (Did you mistype the app name?)" rescue RestClient::RequestFailed => e display extract_error(e.response) rescue HerokuGarden::CommandLine::CommandFailed => e display e. end |
#extract_error(response) ⇒ Object
434 435 436 437 438 439 440 |
# File 'lib/herokugarden/command_line.rb', line 434 def extract_error(response) return "Not found" if response.code.to_i == 404 msg = parse_error_xml(response.body) rescue '' msg = 'Internal server error' if msg.empty? msg end |
#extract_key! ⇒ Object
402 403 404 405 406 |
# File 'lib/herokugarden/command_line.rb', line 402 def extract_key! return unless key_path = extract_option(ARGV, ['-k', '--key']) raise "Please inform the full path for your ssh public key" if File.directory?(key_path) raise "Could not read ssh public key in #{key_path}" unless @ssh_key = authkey_read(key_path) end |
#extract_option(args, options, valid_values = nil) ⇒ Object
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 |
# File 'lib/herokugarden/command_line.rb', line 319 def extract_option(args, , valid_values=nil) values = .is_a?(Array) ? : [] return unless opt_index = args.select { |a| values.include? a }.first opt_value = args[args.index(opt_index) + 1] rescue nil # remove option from args args.delete(opt_index) args.delete(opt_value) if valid_values opt_value = opt_value.downcase if opt_value raise CommandFailed, "Invalid value '#{opt_value}' for option #{values.last}" unless valid_values.include?(opt_value) end block_given? ? yield(opt_value) : opt_value end |
#find_key ⇒ Object
386 387 388 389 390 391 392 |
# File 'lib/herokugarden/command_line.rb', line 386 def find_key %w(rsa dsa).each do |key_type| keyfile = "#{home_directory}/.ssh/id_#{key_type}.pub" return keyfile if File.exists? keyfile end raise CommandFailed, "No ssh public key found in #{home_directory}/.ssh/id_[rd]sa.pub. You may want to specify the full path to the keyfile." end |
#get_credentials ⇒ Object
:nodoc:
218 219 220 221 222 223 224 225 |
# File 'lib/herokugarden/command_line.rb', line 218 def get_credentials # :nodoc: return if @credentials unless @credentials = read_credentials @credentials = ask_for_credentials save_credentials end @credentials end |
#git_repo_for(name) ⇒ Object
142 143 144 |
# File 'lib/herokugarden/command_line.rb', line 142 def git_repo_for(name) "git@#{heroku.host}:#{name}.git" end |
#git_transition(args) ⇒ Object
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/herokugarden/command_line.rb', line 156 def git_transition(args) unless File.exists?(Dir.pwd + '/.git') raise HerokuGarden::CommandLine::CommandFailed, "The current directory is not a git repository.\nBe sure to cd into the app's directory and try again." end gitconfig = File.read(Dir.pwd + '/.git/config') if gitconfig.match(/url = git@herokugarden\.com:(.+)\.git/) raise HerokuGarden::CommandLine::CommandFailed, "This git repo for #{app_name} is already up to date and pointing at herokugarden.com." end if app_name_match = gitconfig.match(/url = git@heroku\.com:(.+)\.git/) app_name = app_name_match[1] begin attempt_git_transition(gitconfig, app_name, 'heroku.com') rescue RestClient::ResourceNotFound begin attempt_git_transition(gitconfig, app_name, 'herokugarden.com') rescue RestClient::ResourceNotFound raise HerokuGarden::CommandLine::CommandFailed, "The current directory does not contain a known Heroku app." end end else raise HerokuGarden::CommandLine::CommandFailed, "The current directory does not contain a known Heroku app." end end |
#heroku ⇒ Object
:nodoc:
196 197 198 |
# File 'lib/herokugarden/command_line.rb', line 196 def heroku # :nodoc: @heroku ||= init_heroku end |
#home_directory ⇒ Object
430 431 432 |
# File 'lib/herokugarden/command_line.rb', line 430 def home_directory running_on_windows? ? ENV['USERPROFILE'] : ENV['HOME'] end |
#info(args) ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/herokugarden/command_line.rb', line 29 def info(args) name = args.shift.downcase.strip rescue "" if name.length == 0 or name.slice(0, 1) == '-' display "Usage: herokugarden info <app>" else attrs = heroku.info(name) display "=== #{attrs[:name]}" display "Web URL: http://#{attrs[:name]}.#{heroku.host}/" display "Domain name: http://#{attrs[:domain_name]}/" if attrs[:domain_name] display "Git Repo: git@#{heroku.host}:#{attrs[:name]}.git" display "Mode: #{ attrs[:production] == 'true' ? 'production' : 'development' }" display "Public: #{ attrs[:'share-public'] == 'true' ? 'true' : 'false' }" first = true lead = "Collaborators:" attrs[:collaborators].each do |collaborator| display "#{first ? lead : ' ' * lead.length} #{collaborator[:email]} (#{collaborator[:access]})" first = false end end end |
#init_heroku ⇒ Object
:nodoc:
200 201 202 |
# File 'lib/herokugarden/command_line.rb', line 200 def init_heroku # :nodoc: HerokuGarden::Client.new(user, password, ENV['HEROKU_HOST'] || 'herokugarden.com') end |
#keys(*args) ⇒ Object
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 |
# File 'lib/herokugarden/command_line.rb', line 336 def keys(*args) args = args.first # something weird with ruby argument passing if args.empty? list_keys return end extract_option(args, '--add') do |keyfile| add_key(keyfile) return end extract_option(args, '--remove') do |arg| remove_key(arg) return end display "Usage: heroku keys [--add or --remove]" end |
#list(args) ⇒ Object
20 21 22 23 24 25 26 27 |
# File 'lib/herokugarden/command_line.rb', line 20 def list(args) list = heroku.list if list.size > 0 display list.join("\n") else display "You have no apps." end end |
#list_collaborators(name) ⇒ Object
137 138 139 140 |
# File 'lib/herokugarden/command_line.rb', line 137 def list_collaborators(name) list = heroku.list_collaborators(name) display list.map { |c| "#{c[:email]} (#{c[:access]})" }.join("\n") end |
#list_keys ⇒ Object
356 357 358 359 360 361 362 363 364 365 366 |
# File 'lib/herokugarden/command_line.rb', line 356 def list_keys keys = heroku.keys if keys.empty? display "No keys for #{user}" else display "=== #{keys.size} key#{keys.size > 1 ? 's' : ''} for #{user}" keys.each do |key| display key end end end |
#parse_error_xml(body) ⇒ Object
442 443 444 445 |
# File 'lib/herokugarden/command_line.rb', line 442 def parse_error_xml(body) xml_errors = REXML::Document.new(body).elements.to_a("//errors/error") xml_errors.map { |a| a.text }.join(" / ") end |
#password ⇒ Object
:nodoc:
209 210 211 212 |
# File 'lib/herokugarden/command_line.rb', line 209 def password # :nodoc: get_credentials @credentials[1] end |
#rake(args) ⇒ Object
146 147 148 149 150 151 152 153 154 |
# File 'lib/herokugarden/command_line.rb', line 146 def rake(args) app_name = args.shift.strip.downcase rescue "" cmd = args.join(' ') if app_name.length == 0 or cmd.length == 0 display "Usage: herokugarden rake <app> <command>" else puts heroku.rake(app_name, cmd) end end |
#read_credentials ⇒ Object
227 228 229 230 231 |
# File 'lib/herokugarden/command_line.rb', line 227 def read_credentials if File.exists? credentials_file return File.read(credentials_file).split("\n") end end |
#remove_collaborator(name, email) ⇒ Object
132 133 134 135 |
# File 'lib/herokugarden/command_line.rb', line 132 def remove_collaborator(name, email) heroku.remove_collaborator(name, email) display "Collaborator removed" end |
#remove_key(arg) ⇒ Object
376 377 378 379 380 381 382 383 384 |
# File 'lib/herokugarden/command_line.rb', line 376 def remove_key(arg) if arg == 'all' heroku.remove_all_keys display "All keys removed." else heroku.remove_key(arg) display "Key #{arg} removed." end end |
#retry_login? ⇒ Boolean
296 297 298 299 300 |
# File 'lib/herokugarden/command_line.rb', line 296 def retry_login? @login_attempts ||= 0 @login_attempts += 1 @login_attempts < 3 end |
#running_on_windows? ⇒ Boolean
447 448 449 |
# File 'lib/herokugarden/command_line.rb', line 447 def running_on_windows? RUBY_PLATFORM =~ /mswin32/ end |
#save_credentials ⇒ Object
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/herokugarden/command_line.rb', line 278 def save_credentials begin write_credentials add_key rescue RestClient::Unauthorized => e delete_credentials raise e unless retry_login? display "\nAuthentication failed" @credentials = ask_for_credentials @heroku = init_heroku retry rescue Exception => e delete_credentials raise e end end |
#set_credentials_permissions ⇒ Object
310 311 312 313 |
# File 'lib/herokugarden/command_line.rb', line 310 def FileUtils.chmod 0700, File.dirname(credentials_file) FileUtils.chmod 0600, credentials_file end |
#sharing(args) ⇒ Object
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/herokugarden/command_line.rb', line 100 def sharing(args) name = args.shift.strip.downcase rescue "" if name.length == 0 or name.slice(0, 1) == '-' display "Usage: herokugarden sharing <app>" else access = extract_option(args, '--access', %w( edit view )) || 'view' extract_option(args, '--add') do |email| return add_collaborator(name, email, access) end extract_option(args, '--update') do |email| return update_collaborator(name, email, access) end extract_option(args, '--remove') do |email| return remove_collaborator(name, email) end return list_collaborators(name) end end |
#update(args) ⇒ Object
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/herokugarden/command_line.rb', line 57 def update(args) name = args.shift.downcase.strip rescue "" raise CommandFailed, "Invalid app name" if name.length == 0 or name.slice(0, 1) == '-' attributes = {} extract_option(args, '--name') do |new_name| attributes[:name] = new_name end extract_option(args, '--public', %w( true false )) do |public| attributes[:share_public] = (public == 'true') end extract_option(args, '--mode', %w( production development )) do |mode| attributes[:production] = (mode == 'production') end raise CommandFailed, "Nothing to update" if attributes.empty? heroku.update(name, attributes) app_name = attributes[:name] || name display "http://#{app_name}.#{heroku.host}/ updated" end |
#update_collaborator(name, email, access) ⇒ Object
127 128 129 130 |
# File 'lib/herokugarden/command_line.rb', line 127 def update_collaborator(name, email, access) heroku.update_collaborator(name, email, access) display "Collaborator updated" end |
#upload_authkey(*args) ⇒ Object
vvv Deprecated
395 396 397 398 399 400 |
# File 'lib/herokugarden/command_line.rb', line 395 def upload_authkey(*args) extract_key! display "Uploading ssh public key" display "(upload_authkey is deprecated, please use \"heroku keys --add\" instead)" heroku.add_key(authkey) end |
#user ⇒ Object
:nodoc:
204 205 206 207 |
# File 'lib/herokugarden/command_line.rb', line 204 def user # :nodoc: get_credentials @credentials[0] end |
#write_credentials ⇒ Object
302 303 304 305 306 307 308 |
# File 'lib/herokugarden/command_line.rb', line 302 def write_credentials FileUtils.mkdir_p(File.dirname(credentials_file)) File.open(credentials_file, 'w') do |f| f.puts self.credentials end end |