toolshed 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8a8dfde43412cec6304d3bc7b42485ea14d225c5
4
- data.tar.gz: 52bbbc59f4384c7ead365df2a4aed53d3f486521
3
+ metadata.gz: f2284363dbacddbe04adfd021331c5a27870e279
4
+ data.tar.gz: 739d370c284895290ae0a7213a75123c5d23c9e7
5
5
  SHA512:
6
- metadata.gz: 6ddf6b5dcce569a0bc312f8a266b70cbc5d79be95ea318d7fadded6036b99143d394fcab632fc7d8c7c156cf324677d28de154fa56edab22308f91ddf79efbbc
7
- data.tar.gz: 50c8a2c080727e008ab404f5b03d34481c9cc9cf892cd5cf89f24f42e608f9f772f2393af4f0c315e8182e34b76923a6641b9e5aa4801a229d02e75c66255d44
6
+ metadata.gz: 8a50e84f7789f7443e01de39d64708970dbe948e8ed441c9b2a166b7a51ffb4e4c3559d73a9705aa08f1b5ea238afd5b3b019a08cf5dd6180a4ecfedb1317f84
7
+ data.tar.gz: 595834a2bbf3cdae26a088a28dfa32dceef915a754e0c9432fe0f8c64112acfc3f186be061ee72771331c079712297b14dc903a9516492eff7c1346f325940cd
data/lib/toolshed/cli.rb CHANGED
@@ -7,42 +7,23 @@ module Toolshed
7
7
 
8
8
  # CLI is responsible for executing the initial command
9
9
  class CLI
10
- def execute(command_name, args, options = {})
11
- load_config(command_name)
12
- command = send(command_name)
13
- if command
14
- begin
15
- command.new.execute(args, options)
16
- rescue Toolshed::Error => e
17
- Toolshed.logger.fatal "An error occurred: #{e.message}"
18
- rescue RuntimeError => e
19
- Toolshed.logger.fatal "An error occurred: #{e.message}"
20
- end
21
- else
22
- fail CommandNotFound, "Unknown command: #{command_name}"
10
+ def execute(command_class, args, options = {})
11
+ load_config(command_class)
12
+ begin
13
+ command_class.new.execute(args, options)
14
+ rescue Toolshed::Error => e
15
+ Toolshed.logger.fatal "An error occurred: #{e.message}"
16
+ rescue RuntimeError => e
17
+ Toolshed.logger.fatal "An error occurred: #{e.message}"
23
18
  end
24
19
  end
25
20
 
26
- def load_config(command_name)
21
+ def load_config(command_class)
27
22
  Toolshed::Client.load_credentials
28
- Toolshed.add_file_log_source(command_name)
23
+ Toolshed.add_file_log_source(command_class.class.name)
29
24
  Toolshed.logger.info "Credentials loaded from #{File.absolute_path(Toolshed::Client.instance.credentials_loaded_from)}" # rubocop:disable Metrics/LineLength
30
25
  rescue => e
31
26
  Toolshed.logger.fatal "Error loading your credentials: #{e.message}"
32
27
  end
33
-
34
- def method_missing(method_name)
35
- require "toolshed/commands/#{method_name}"
36
- "Toolshed::Commands::#{translate_method_name(method_name)}".split('::').inject(Object) { |o, c| o.const_get c } # rubocop:disable Metrics/LineLength
37
- rescue NameError => e
38
- Toolshed.logger.fatal e.message
39
- Toolshed.die
40
- end
41
-
42
- def translate_method_name(name)
43
- name = name.to_s
44
- name.upcase! if %w(ssh).include?(name.downcase)
45
- name.camel_case
46
- end
47
28
  end
48
29
  end
@@ -5,10 +5,10 @@ module Toolshed
5
5
  module Commands
6
6
  # Base class for all commands responsible for common methods
7
7
  class Base
8
- def initialize(_options = {})
8
+ def initialize(options = {})
9
9
  end
10
10
 
11
- def self.parse(command, cli_options = {}) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/LineLength, Metrics/CyclomaticComplexity
11
+ def self.parse(command_class, cli_options = {}) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/LineLength, Metrics/CyclomaticComplexity
12
12
  options = {}
13
13
  options_parser = OptionParser.new do |opts|
14
14
  opts.banner = cli_options[:banner] if cli_options[:banner]
@@ -25,7 +25,7 @@ module Toolshed
25
25
  options_parser.order! if options_parser
26
26
  begin
27
27
  cli = Toolshed::CLI.new
28
- cli.execute(command, ARGV, options)
28
+ cli.execute(command_class, ARGV, options)
29
29
  rescue Toolshed::CommandNotFound => e
30
30
  Toolshed.logger.fatal e.message
31
31
  Toolshed.die
@@ -34,7 +34,8 @@ module Toolshed
34
34
 
35
35
  def read_user_input(message, options = {})
36
36
  return options[:default] if Toolshed::Client.instance.use_defaults
37
- required = options[:required] || false
37
+ required = options[:required].is_a?(TrueClass)
38
+
38
39
  value = ''
39
40
  if required
40
41
  value = prompt_user_input(message, options) while value.empty?
@@ -44,6 +45,15 @@ module Toolshed
44
45
  value
45
46
  end
46
47
 
48
+ def read_user_input_password(password, prompt_message='Password:')
49
+ return password unless password.nil? || password.empty?
50
+ system "stty -echo"
51
+ puts prompt_message
52
+ value = $stdin.gets.chomp.strip
53
+ system "stty echo"
54
+ value
55
+ end
56
+
47
57
  def read_user_input_title(message, options = {})
48
58
  return options[:title] if options.key?(:title)
49
59
  read_user_input(message, options)
@@ -0,0 +1,43 @@
1
+ require 'toolshed/commands/scp_base'
2
+
3
+ module Toolshed
4
+ module Commands
5
+ module SCP
6
+ # Responsible for handing downloading of files
7
+ class Download < Toolshed::Commands::SCPBase
8
+ def self.cli_options # rubocop:disable MethodLength
9
+ {
10
+ banner: 'Usage: scp download [options]',
11
+ options: {
12
+ remote_host: {
13
+ short_on: '-r'
14
+ },
15
+ remote_path: {
16
+ short_on: '-d'
17
+ },
18
+ local_path: {
19
+ short_on: '-s'
20
+ },
21
+ username: {
22
+ short_on: '-u'
23
+ },
24
+ password: {
25
+ short_on: '-p'
26
+ },
27
+ verbose_output: {
28
+ short_on: '-v'
29
+ }
30
+ }
31
+ }
32
+ end
33
+
34
+ def execute(_args, options = nil)
35
+ options ||= nil
36
+ Toolshed.logger.info ''
37
+ Toolshed::ServerAdministration::SCP.new(scp_options(options)).download
38
+ Toolshed.die
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,43 @@
1
+ require 'toolshed/commands/scp_base'
2
+
3
+ module Toolshed
4
+ module Commands
5
+ module SCP
6
+ # Responsible for handing uploading of files
7
+ class Upload < Toolshed::Commands::SCPBase
8
+ def self.cli_options # rubocop:disable MethodLength
9
+ {
10
+ banner: 'Usage: scp upload [options]',
11
+ options: {
12
+ remote_host: {
13
+ short_on: '-r'
14
+ },
15
+ remote_path: {
16
+ short_on: '-d'
17
+ },
18
+ local_path: {
19
+ short_on: '-s'
20
+ },
21
+ username: {
22
+ short_on: '-u'
23
+ },
24
+ password: {
25
+ short_on: '-p'
26
+ },
27
+ verbose_output: {
28
+ short_on: '-v'
29
+ }
30
+ }
31
+ }
32
+ end
33
+
34
+ def execute(_args, options = nil)
35
+ options ||= nil
36
+ Toolshed.logger.info ''
37
+ Toolshed::ServerAdministration::SCP.new(scp_options(options)).upload
38
+ Toolshed.die
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ require 'toolshed/commands/base'
2
+ require 'toolshed/server_administration/scp'
3
+
4
+ module Toolshed
5
+ module Commands
6
+ # Shared code between scp classes
7
+ class SCPBase < Toolshed::Commands::Base
8
+ private
9
+
10
+ def scp_options(options = nil) # rubocop:disable AbcSize
11
+ options ||= {}
12
+ options[:remote_host] = read_user_input('Remote Host?', required: true) if options[:remote_host].nil? # rubocop:disable LineLength
13
+ options[:remote_path] = read_user_input('Remote Path?', required: true) if options[:remote_path].nil? # rubocop:disable LineLength
14
+ options[:local_path] = read_user_input('Local Path?', required: true) if options[:local_path].nil? # rubocop:disable LineLength
15
+ options[:username] = read_user_input('Username?', required: true) if options[:username].nil? # rubocop:disable LineLength
16
+ options[:password] = read_user_input_password(options[:password])
17
+ options
18
+ end
19
+ end
20
+ end
21
+ end
@@ -44,46 +44,77 @@ class EntryPoint
44
44
  end
45
45
 
46
46
  global.order!
47
- command = ARGV.shift
48
- if command.nil?
47
+ if command_parts.length == 0
49
48
  usage
50
- elsif command == 'version'
49
+ elsif command_parts[0] == 'version'
51
50
  Toolshed::Version.banner
52
51
  Toolshed.die
53
52
  else
54
- command_class = nil
55
- command_class_name = command.camel_case
53
+ command_class = default_command_class_string
54
+ attempts = 0
56
55
  begin
57
- require "toolshed/commands/#{command.to_s}"
58
- command_class = "Toolshed::Commands::#{command_class_name}".split('::').inject(Object) { |o,c| o.const_get c }
59
- rescue NameError
60
- command_class = "Toolshed::Commands::#{command_class_name.upcase}".split('::').inject(Object) { |o,c| o.const_get c }
56
+ require "toolshed/commands/#{command_parts.join('/')}"
57
+ command_class = command_class.split('::').inject(Object) { |o,c| o.const_get c }
58
+ rescue NameError => e
59
+ name_error_name = e.message.sub('wrong constant name ', '')
60
+ name_error_name = e.message.sub('uninitialized constant ', '')
61
+ command_class = command_class.sub(name_error_name, name_error_name.upcase)
62
+ attempts += 1
63
+ retry unless attempts > command_parts.length
61
64
  end
62
- Toolshed::Commands::Base.parse(command, command_class.cli_options)
65
+ Toolshed::Commands::Base.parse(command_class, command_class.cli_options)
63
66
  end
64
67
  end
65
68
  end
66
69
 
70
+ def command_parts
71
+ @command_parts ||= begin
72
+ command_parts = []
73
+ arguments_left = true
74
+ until !arguments_left
75
+ if ARGV.first.nil? || ARGV.first.start_with?('--') || ARGV.first.start_with?('-')
76
+ arguments_left = false
77
+ else
78
+ command_parts << ARGV.shift
79
+ end
80
+ end
81
+ command_parts
82
+ end
83
+ end
84
+
85
+ def default_command_class_string
86
+ command_class = "Toolshed::Commands"
87
+ command_parts.each do |command_part|
88
+ if command_part.include?('_')
89
+ command_class = "#{command_class}::#{command_part.split('_').map(&:capitalize).join('')}"
90
+ else
91
+ command_class = "#{command_class}::#{command_part.capitalize}"
92
+ end
93
+ end
94
+ command_class
95
+ end
96
+
67
97
  def usage
68
98
  $stdout.puts <<EOF
69
99
  Please see toolshedrc.sample to create your toolshedrc settings file.
70
100
 
71
101
  Available Commands:
72
102
 
73
- checkout_branch
74
- create_branch
75
- create_pivotal_tracker_note
76
- create_pull_request
77
- create_ticket_comment
78
- delete_branch
79
- get_daily_time_update
80
- list_branches
81
- push_branch
82
- rename_branch
83
- ssh
84
- ticket_information
85
- update_pivotal_tracker_story_status
86
- update_ticket_status
103
+ toolshed checkout_branch
104
+ toolshed create_branch
105
+ toolshed create_pivotal_tracker_note
106
+ toolshed create_pull_request
107
+ toolshed create_ticket_comment
108
+ toolshed delete_branch
109
+ toolshed get_daily_time_update
110
+ toolshed list_branches
111
+ toolshed push_branch
112
+ toolshed rename_branch
113
+ toolshed scp download
114
+ toolshed ssh
115
+ toolshed ticket_information
116
+ toolshed update_pivotal_tracker_story_status
117
+ toolshed update_ticket_status
87
118
  EOF
88
119
  end
89
120
  end
@@ -0,0 +1 @@
1
+ class RequiredOptionException < StandardError;
@@ -160,7 +160,8 @@ module Toolshed
160
160
  results = Toolshed::Base.wait_for_command('git branch -avv')
161
161
  results[:stdout].each do |stdout|
162
162
  next if /remotes.*/.match(stdout) || /HEAD.*/.match(stdout)
163
- branch_name = /.*\s{3,}/.match(stdout)[0]
163
+ matches = /([^\s]+)/.match(stdout)
164
+ branch_name = matches[0]
164
165
  branch_name = branch_name.gsub('*', '')
165
166
  branch_info_match = /\[[a-z].*\]/.match(stdout)
166
167
  branch_info = ''
@@ -1,47 +1,23 @@
1
- module Toolshed
2
- class Password
3
- attr_accessor :password, :sudo_password
4
-
5
- def initialize(options={})
6
- self.password = options[:password] ||= ''
7
- self.sudo_password = options[:sudo_password] ||= ''
8
- end
9
-
10
- def read_user_input_password(type, prompt_message='Password:')
11
- value = self.send(type)
12
- unless value.nil? || value.empty?
13
- read_password_from_configuration(type)
14
- else
15
- prompt_user_to_input_password(prompt_message)
16
- end
17
- end
18
-
19
- protected
1
+ require 'toolshed/client'
20
2
 
21
- def prompt_user_to_input_password(message)
22
- system "stty -echo"
23
- puts message
24
- value = get_password_input
25
- system "stty echo"
26
-
27
- value
28
- end
29
-
30
- def get_password_input
31
- $stdin.gets.chomp.strip
32
- end
3
+ module Toolshed
4
+ module Password
5
+ def password_from_config(password)
6
+ return '' if password.nil? || password.empty?
33
7
 
34
- def read_password_from_configuration(type)
35
- begin
36
- credentials = Toolshed::Client.read_credenials
37
- if credentials[self.send(type)]
38
- credentials[self.send(type)]
39
- else
40
- self.send(type)
41
- end
42
- rescue => e
43
- puts e.inspect
8
+ begin
9
+ credentials = Toolshed::Client.read_credenials
10
+ password_parts = password.split(':')
11
+ password_parts.each do |password_part|
12
+ return password if credentials[password_part].nil?
13
+ credentials = credentials[password_part]
44
14
  end
15
+ rescue => e
16
+ Toolshed::Logger.instance.fatal e.message
17
+ Toolshed::Logger.instance.fatal e.inspect
18
+ return password
45
19
  end
20
+ credentials
21
+ end
46
22
  end
47
23
  end
@@ -0,0 +1,46 @@
1
+ require 'toolshed/server_administration/ssh'
2
+ require 'toolshed/password'
3
+
4
+ require 'net/scp'
5
+ require 'ruby-progressbar'
6
+
7
+ module Toolshed
8
+ module ServerAdministration
9
+ # Handles SCP file from one place to another
10
+ class SCP
11
+ include Toolshed::Password
12
+
13
+ attr_reader :local_path, :password, :remote_host, :remote_path, :username, :verbose_output # rubocop:disable LineLength
14
+
15
+ def initialize(options = nil)
16
+ options ||= {}
17
+
18
+ @password = options[:password]
19
+ @remote_host = options[:remote_host]
20
+ @remote_path = options[:remote_path]
21
+ @local_path = options[:local_path]
22
+ @username = options[:username]
23
+ @verbose_output = options[:verbose_output]
24
+ end
25
+
26
+ def download
27
+ Toolshed.logger.info "Attempting to SCP from #{username}@#{remote_host}:#{remote_path} to #{local_path}." # rubocop:disable LineLength
28
+ Net::SCP.download!(remote_host, username, remote_path, local_path, ssh: { password: password_from_config(password) }, recursive: true) # rubocop:disable LineLength
29
+ on_complete
30
+ end
31
+
32
+ def upload
33
+ Toolshed.logger.info "Attempting to SCP from #{local_path} to #{username}@#{remote_host}:#{remote_path}." # rubocop:disable LineLength
34
+ Net::SCP.upload!(remote_host, username, local_path, remote_path, ssh: { password: password_from_config(password) }, recursive: true) # rubocop:disable LineLength
35
+ on_complete
36
+ end
37
+
38
+ private
39
+
40
+ def on_complete
41
+ Toolshed.logger.info ''
42
+ Toolshed.logger.info 'SCP file transfer has completed.'
43
+ end
44
+ end
45
+ end
46
+ end
@@ -4,24 +4,31 @@ require 'net/ssh'
4
4
 
5
5
  module Toolshed
6
6
  module ServerAdministration
7
+ # SSH class that can ssh to a host and perform commands
7
8
  class SSH
8
- attr_accessor :keys, :password, :sudo_password, :host, :user, :ssh_options, :channel, :commands, :password
9
-
10
- def initialize(options={})
11
- self.password = options[:password] ||= ''
12
- self.sudo_password = options[:sudo_password] ||= ''
13
- self.keys = options[:keys] ||= ''
14
- self.host = options[:host] ||= ''
15
- self.user = options[:user] ||= ''
16
- self.ssh_options = options[:ssh_options] ||= {}
17
- self.commands = options[:commands] ||= ''
18
- self.password = Toolshed::Password.new(options)
9
+ include Toolshed::Password
10
+
11
+ attr_accessor :channel, :commands, :data, :host, :keys, :password, :ssh_options, :sudo_password, :user # rubocop:disable LineLength
12
+ attr_reader :silent
13
+
14
+ def initialize(options = nil) # rubocop:disable AbcSize, CyclomaticComplexity, PerceivedComplexity, LineLength
15
+ options ||= {}
16
+ @password = options[:password] || ''
17
+ @sudo_password = options[:sudo_password] || ''
18
+ @keys = options[:keys] || ''
19
+ @host = options[:host] || ''
20
+ @user = options[:user] || ''
21
+ @ssh_options = options[:ssh_options] || {}
22
+ @commands = options[:commands] || ''
23
+ @password = options[:password] || ''
24
+ @data = []
25
+ @silent = options[:silent] || false
19
26
 
20
27
  set_ssh_options
21
28
  end
22
29
 
23
30
  def execute
24
- Net::SSH.start(self.host, self.user, self.ssh_options) do |ssh|
31
+ Net::SSH.start(host, user, ssh_options) do |ssh|
25
32
  ssh.open_channel do |channel|
26
33
  self.channel = channel
27
34
  request_pty
@@ -29,14 +36,16 @@ module Toolshed
29
36
  end
30
37
  ssh.loop
31
38
  end
39
+ data
32
40
  end
33
41
 
34
42
  protected
35
43
 
36
44
  def run_commands
37
- # @TODO fix this so it does not just pass in the commands option but converts to a string i.e. command1;command2
38
- self.channel.exec(self.commands) do |ch, success|
39
- abort "Could not execute commands!" unless success
45
+ # @TODO fix this so it does not just pass in the commands option
46
+ # Converts to string like command1;command2
47
+ channel.exec(commands) do |_ch, success|
48
+ abort 'Could not execute commands!' unless success
40
49
 
41
50
  on_data
42
51
  on_extended_data
@@ -45,46 +54,55 @@ module Toolshed
45
54
  end
46
55
 
47
56
  def request_pty
48
- self.channel.request_pty do |ch, success|
49
- puts (success) ? "Successfully obtained pty" : "Could not obtain pty"
57
+ channel.request_pty do |_ch, success|
58
+ unless silent
59
+ message = (success) ? 'Successfully obtained pty' : 'Could not obtain pty'
60
+ puts message
61
+ end
50
62
  end
51
63
  end
52
64
 
53
65
  def on_close
54
- self.channel.on_close do |ch|
55
- puts "Channel is closing!"
66
+ channel.on_close do |_ch|
67
+ puts 'Channel is closing!' unless silent
56
68
  end
57
69
  end
58
70
 
59
71
  def on_extended_data
60
- self.channel.on_extended_data do |ch, type, data|
61
- puts "stderr: #{data}"
72
+ channel.on_extended_data do |_ch, _type, data|
73
+ puts "stderr: #{data}" unless silent
62
74
  end
63
75
  end
64
76
 
65
77
  def on_data
66
- self.channel.on_data do |ch, data|
67
- puts "#{data}"
78
+ channel.on_data do |_ch, data|
79
+ puts "#{data}" unless silent
80
+ self.data << data
68
81
  send_data(data)
69
82
  end
70
83
  end
71
84
 
72
85
  def send_data(data)
73
86
  send_password_data if data =~ /password/
74
- send_yes_no_data if data =~ /Do you want to continue \[Y\/n\]?/
87
+ # send_yes_no_data if data =~ /Do you want to continue \[Y\/n\]?/
88
+ send_yes_no_data if data =~ %r{Do you want to continue [Y/n]?}
75
89
  end
76
90
 
77
91
  def send_password_data
78
- self.channel.send_data "#{@password.read_user_input_password('sudo_password')}\n"
92
+ channel.send_data "#{password_from_config(sudo_password)}\n"
79
93
  end
80
94
 
81
95
  def send_yes_no_data
82
- self.channel.send_data "Y\n"
96
+ channel.send_data "Y\n"
83
97
  end
84
98
 
85
- def set_ssh_options
86
- self.ssh_options.merge!({ keys: [self.keys] }) unless keys.nil? || keys.empty?
87
- self.ssh_options.merge!({ password: self.password.read_user_input_password('password') }) if keys.nil? || keys.empty?
99
+ def set_ssh_options # rubocop:disable AbcSize
100
+ if keys.nil? || keys.empty?
101
+ final_password = password_from_config(password)
102
+ ssh_options.merge!(password: final_password)
103
+ else
104
+ ssh_options.merge!(keys: [keys]) unless keys.nil? || keys.empty?
105
+ end
88
106
  end
89
107
  end
90
108
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Module for toolshed
4
4
  module Toolshed
5
- VERSION = '1.0.3'
5
+ VERSION = '1.0.4'
6
6
 
7
7
  # Display the version information with the toolshed banner
8
8
  class Version
@@ -0,0 +1,34 @@
1
+ require 'commands/commands_helper'
2
+ require 'toolshed/commands/scp/download'
3
+ require 'net/scp'
4
+
5
+ module Test
6
+ module Commands
7
+ module SCP
8
+ class DownloadTest < Test::Unit::TestCase
9
+ def setup
10
+ Toolshed::Logger.instance.instance_variable_set(:@logs, { debug: [], fatal: [], info: [], warn: [] })
11
+ Toolshed.expects(:die).at_least(0).returns('Exiting')
12
+ end
13
+
14
+ def teardown
15
+ Toolshed::Logger.instance.instance_variable_set(:@logs, { debug: [], fatal: [], info: [], warn: [] })
16
+ end
17
+
18
+ def test_scp_upload
19
+ Net::SCP.expects(:download!).returns('downloaded')
20
+
21
+ scp_download_command = Toolshed::Commands::SCP::Download.new
22
+ scp_download_command.execute({}, password: 'test1234', username: 'test', remote_host: 'localhost', remote_path: '/tmp', local_path: '/tmp')
23
+
24
+ assert Toolshed::Logger.instance.logs[:info].include?('SCP file transfer has completed.')
25
+ assert Toolshed::Logger.instance.logs[:info].include?('Attempting to SCP from test@localhost:/tmp to /tmp.')
26
+ end
27
+
28
+ def test_cli_options
29
+ assert 'Usage: scp download [options]', Toolshed::Commands::SCP::Download.cli_options[:banner]
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,34 @@
1
+ require 'commands/commands_helper'
2
+ require 'toolshed/commands/scp/upload'
3
+ require 'net/scp'
4
+
5
+ module Test
6
+ module Commands
7
+ module SCP
8
+ class UploadTest < Test::Unit::TestCase
9
+ def setup
10
+ Toolshed::Logger.instance.instance_variable_set(:@logs, { debug: [], fatal: [], info: [], warn: [] })
11
+ Toolshed.expects(:die).at_least(0).returns('Exiting')
12
+ end
13
+
14
+ def teardown
15
+ Toolshed::Logger.instance.instance_variable_set(:@logs, { debug: [], fatal: [], info: [], warn: [] })
16
+ end
17
+
18
+ def test_scp_upload
19
+ Net::SCP.expects(:upload!).returns('uploaded')
20
+
21
+ scp_upload_command = Toolshed::Commands::SCP::Upload.new
22
+ scp_upload_command.execute({}, password: 'test1234', username: 'test', remote_host: 'localhost', remote_path: '/tmp', local_path: '/tmp')
23
+
24
+ assert Toolshed::Logger.instance.logs[:info].include?('SCP file transfer has completed.')
25
+ assert Toolshed::Logger.instance.logs[:info].include?('Attempting to SCP from /tmp to test@localhost:/tmp.')
26
+ end
27
+
28
+ def test_cli_options
29
+ assert 'Usage: scp upload [options]', Toolshed::Commands::SCP::Upload.cli_options[:banner]
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
data/test/helper.rb CHANGED
@@ -18,6 +18,7 @@ require 'fileutils'
18
18
  require 'json'
19
19
 
20
20
  require 'toolshed'
21
+ require 'toolshed/logger'
21
22
 
22
23
  Test::Unit.at_start do
23
24
  Toolshed::Client.instance.use_git_submodules = false
@@ -100,3 +101,27 @@ def capture_stdout(&block)
100
101
  end
101
102
  fake.string
102
103
  end
104
+
105
+ class Toolshed::Logger
106
+ attr_reader :logs
107
+
108
+ def initialize
109
+ @logs = { debug: [], fatal: [], info: [], warn: [] }
110
+ end
111
+
112
+ def debug(message)
113
+ logs[:debug] << message
114
+ end
115
+
116
+ def fatal(message)
117
+ logs[:fatal] << message
118
+ end
119
+
120
+ def info(message)
121
+ logs[:info] << message
122
+ end
123
+
124
+ def warn(message)
125
+ logs[:warn] << message
126
+ end
127
+ end
@@ -1,24 +1,10 @@
1
1
  require 'helper'
2
+ require 'toolshed/server_administration/scp'
2
3
 
3
4
  class PasswordTest < Test::Unit::TestCase
4
- def test_read_user_input_password
5
- password = Toolshed::Password.new({ password: 'test1234' })
6
- assert_equal password.read_user_input_password('password'), 'test1234'
7
- end
8
-
9
- def test_read_user_input_password_sudo
10
- password = Toolshed::Password.new({ sudo_password: 'test12345' })
11
- assert_equal password.read_user_input_password('sudo_password'), 'test12345'
12
- end
13
-
14
- def test_read_user_input_password_prompt
15
- password = Toolshed::Password.new({})
16
- password.expects(:get_password_input).returns('readin1234')
17
- assert_equal password.read_user_input_password('password'), 'readin1234'
18
- end
19
-
20
- def test_read_user_input_from_toolshedrc
21
- password = Toolshed::Password.new({ password: 'server_password' })
22
- assert_equal password.read_user_input_password('password'), 'tester1234'
5
+ def test_password_from_config
6
+ expected_password = 'tester1234'
7
+ actual_password = Toolshed::ServerAdministration::SCP.new({}).password_from_config('server_password')
8
+ assert_equal expected_password, actual_password
23
9
  end
24
10
  end
@@ -0,0 +1,37 @@
1
+ require 'commands/commands_helper'
2
+ require 'toolshed/commands/scp/download'
3
+ require 'net/scp'
4
+
5
+ module Test
6
+ module ServerAdministration
7
+ class SCPTest < Test::Unit::TestCase
8
+ def setup
9
+ Toolshed::Logger.instance.instance_variable_set(:@logs, { debug: [], fatal: [], info: [], warn: [] })
10
+ end
11
+
12
+ def teardown
13
+ Toolshed::Logger.instance.instance_variable_set(:@logs, { debug: [], fatal: [], info: [], warn: [] })
14
+ end
15
+
16
+ def test_scp_download
17
+ Net::SCP.expects(:download!).returns('downloaded')
18
+
19
+ scp = Toolshed::ServerAdministration::SCP.new(password: 'test1234', username: 'test', remote_host: 'localhost', remote_path: '/tmp', local_path: '/tmp')
20
+ scp.download
21
+
22
+ assert Toolshed::Logger.instance.logs[:info].include?('SCP file transfer has completed.')
23
+ assert Toolshed::Logger.instance.logs[:info].include?('Attempting to SCP from test@localhost:/tmp to /tmp.')
24
+ end
25
+
26
+ def test_scp_upload
27
+ Net::SCP.expects(:upload!).returns('uploaded')
28
+
29
+ scp = Toolshed::ServerAdministration::SCP.new(password: 'test1234', username: 'test', remote_host: 'localhost', remote_path: '/tmp', local_path: '/tmp')
30
+ scp.upload
31
+
32
+ assert Toolshed::Logger.instance.logs[:info].include?('SCP file transfer has completed.')
33
+ assert Toolshed::Logger.instance.logs[:info].include?('Attempting to SCP from /tmp to test@localhost:/tmp.')
34
+ end
35
+ end
36
+ end
37
+ end
data/toolshed.gemspec CHANGED
@@ -29,6 +29,8 @@ Gem::Specification.new do |spec|
29
29
  spec.add_dependency 'net-ssh', '2.9.2'
30
30
  spec.add_dependency 'term-ansicolor', '1.3.0'
31
31
  spec.add_dependency 'highline', '1.7.2'
32
+ spec.add_dependency 'net-scp', '1.2.1'
33
+ spec.add_dependency 'ruby-progressbar', '1.7.5'
32
34
 
33
35
  spec.add_development_dependency 'bundler'
34
36
  spec.add_development_dependency 'rake'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toolshed
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jake Waller
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-20 00:00:00.000000000 Z
11
+ date: 2015-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -150,6 +150,34 @@ dependencies:
150
150
  - - '='
151
151
  - !ruby/object:Gem::Version
152
152
  version: 1.7.2
153
+ - !ruby/object:Gem::Dependency
154
+ name: net-scp
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '='
158
+ - !ruby/object:Gem::Version
159
+ version: 1.2.1
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - '='
165
+ - !ruby/object:Gem::Version
166
+ version: 1.2.1
167
+ - !ruby/object:Gem::Dependency
168
+ name: ruby-progressbar
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - '='
172
+ - !ruby/object:Gem::Version
173
+ version: 1.7.5
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - '='
179
+ - !ruby/object:Gem::Version
180
+ version: 1.7.5
153
181
  - !ruby/object:Gem::Dependency
154
182
  name: bundler
155
183
  requirement: !ruby/object:Gem::Requirement
@@ -337,18 +365,23 @@ files:
337
365
  - lib/toolshed/commands/list_branches.rb
338
366
  - lib/toolshed/commands/push_branch.rb
339
367
  - lib/toolshed/commands/rename_branch.rb
368
+ - lib/toolshed/commands/scp/download.rb
369
+ - lib/toolshed/commands/scp/upload.rb
370
+ - lib/toolshed/commands/scp_base.rb
340
371
  - lib/toolshed/commands/ssh.rb
341
372
  - lib/toolshed/commands/ticket_information.rb
342
373
  - lib/toolshed/commands/update_pivotal_tracker_story_status.rb
343
374
  - lib/toolshed/commands/update_ticket_status.rb
344
375
  - lib/toolshed/entry_point.rb
345
376
  - lib/toolshed/error.rb
377
+ - lib/toolshed/exceptions.rb
346
378
  - lib/toolshed/git.rb
347
379
  - lib/toolshed/git/branch.rb
348
380
  - lib/toolshed/git/github.rb
349
381
  - lib/toolshed/git/validator.rb
350
382
  - lib/toolshed/logger.rb
351
383
  - lib/toolshed/password.rb
384
+ - lib/toolshed/server_administration/scp.rb
352
385
  - lib/toolshed/server_administration/ssh.rb
353
386
  - lib/toolshed/ticket_tracking/jira.rb
354
387
  - lib/toolshed/ticket_tracking/pivotal_tracker.rb
@@ -365,12 +398,15 @@ files:
365
398
  - test/commands/get_daily_time_update_test.rb
366
399
  - test/commands/push_branch_test.rb
367
400
  - test/commands/rename_branch_test.rb
401
+ - test/commands/scp/download_test.rb
402
+ - test/commands/scp/upload_test.rb
368
403
  - test/config.rb
369
404
  - test/git/git_helper.rb
370
405
  - test/git/git_test.rb
371
406
  - test/git/github_test.rb
372
407
  - test/helper.rb
373
408
  - test/password_test.rb
409
+ - test/server_administration/scp_test.rb
374
410
  - test/server_administration/ssh_test.rb
375
411
  - test/ticket_tracking/jira_test.rb
376
412
  - test/time_tracking/harvest_test.rb
@@ -395,7 +431,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
395
431
  version: '0'
396
432
  requirements: []
397
433
  rubyforge_project:
398
- rubygems_version: 2.4.5
434
+ rubygems_version: 2.4.5.1
399
435
  signing_key:
400
436
  specification_version: 4
401
437
  summary: Create a Github pull request with minimal work. Will automatically read ticket
@@ -410,12 +446,15 @@ test_files:
410
446
  - test/commands/get_daily_time_update_test.rb
411
447
  - test/commands/push_branch_test.rb
412
448
  - test/commands/rename_branch_test.rb
449
+ - test/commands/scp/download_test.rb
450
+ - test/commands/scp/upload_test.rb
413
451
  - test/config.rb
414
452
  - test/git/git_helper.rb
415
453
  - test/git/git_test.rb
416
454
  - test/git/github_test.rb
417
455
  - test/helper.rb
418
456
  - test/password_test.rb
457
+ - test/server_administration/scp_test.rb
419
458
  - test/server_administration/ssh_test.rb
420
459
  - test/ticket_tracking/jira_test.rb
421
460
  - test/time_tracking/harvest_test.rb