toolshed 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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