toolshed 1.0.5 → 1.0.6

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: 97f1edaf94718d33dd532dd486c88a9be34763ba
4
- data.tar.gz: f916422d538d77d894a4474735fbd729e46e8030
3
+ metadata.gz: 215029306670114b410a3c8e153734c8b6d9ce3d
4
+ data.tar.gz: 27c11d5351604e6dcb24c3bd5f3c00a98f69c6fd
5
5
  SHA512:
6
- metadata.gz: b31baee2db1a9feabfbd79455cd3946c91d2368ea0c53485f58c1bfb2d79e4e46bdf28188c90377695aa9f3ab3f2b8cace9b9954855a9e3ab0c0f2f323c45d20
7
- data.tar.gz: ee8fd8db4073acbe54ac95f04c14641c618d106e3c93e011e912c57728311113e5787367a9db4341c25fbc903a761958881c2a8ac780ab3b5a271fb8b19cc67a
6
+ metadata.gz: f8fa73f9315ebae7f0d46d0cdb17a526a0593abf6b871f6a8c24857ca336e372efb8ce525f1e13f45013c50abbc814a1c739923e094a5507de940b401d13ffc7
7
+ data.tar.gz: 9251f783275043a902ba2b889a0e11e1f982d9f72c18faf2976be8f65f470069651022efa9f478bd779ac479fcff1f0745e7b6bc0e4ea7c60f20eaf927a11dff
data/lib/toolshed/base.rb CHANGED
@@ -11,7 +11,7 @@ module Toolshed
11
11
  result = {}
12
12
  Open3.popen3(command) do |stdin, stdout, stderr, wait_thr|
13
13
  begin
14
- Timeout.timeout(seconds) do
14
+ ::Timeout.timeout(seconds) do
15
15
  stdin.close # make sure the subprocess is done
16
16
 
17
17
  a_stdout = []
@@ -27,7 +27,7 @@ module Toolshed
27
27
  exit_status = wait_thr.value # Process::Status object returned.
28
28
  result.merge!(stdout: a_stdout, stderr: a_stderr, all: all, process_status: exit_status) # rubocop:disable Metrics/LineLength
29
29
  end
30
- rescue Timeout::Error
30
+ rescue ::Timeout::Error
31
31
  Process.kill('KILL', wait_thr.pid)
32
32
  Toolshed.logger.fatal "Unable to perform the '#{command}' command in the allowed amount of time of #{seconds} seconds. Exiting." # rubocop:disable Metrics/LineLength
33
33
  Toolshed.die
data/lib/toolshed/cli.rb CHANGED
@@ -19,9 +19,8 @@ module Toolshed
19
19
  end
20
20
 
21
21
  def load_config(command_class)
22
- Toolshed::Client.load_credentials
23
22
  Toolshed.add_file_log_source(command_class.class.name)
24
- Toolshed.logger.info "Credentials loaded from #{File.absolute_path(Toolshed::Client.instance.credentials_loaded_from)}" # rubocop:disable Metrics/LineLength
23
+ Toolshed.logger.info "Credentials loaded from #{File.absolute_path(Toolshed::Client.instance.toolshedrc_path)}" # rubocop:disable Metrics/LineLength
25
24
  rescue => e
26
25
  Toolshed.logger.fatal "Error loading your credentials: #{e.message}"
27
26
  end
@@ -1,91 +1,55 @@
1
- require 'singleton'
1
+ require 'toolshed/error'
2
+ require 'toolshed/hash'
2
3
  require 'toolshed/version'
4
+
5
+ require 'erb'
6
+ require 'singleton'
3
7
  require 'yaml'
4
8
 
5
9
  module Toolshed
6
10
  # This is responsible for loading .toolshedrc file
7
- class Client
11
+ class Client < Hash
8
12
  include Singleton
9
13
 
10
- attr_accessor :debug,
11
- :git_quiet,
12
- :use_defaults,
13
- :github_username,
14
- :github_password,
15
- :github_token,
16
- :use_defaults,
17
- :pull_from_repository_user,
18
- :pull_from_repository_name,
19
- :pull_from_remote_name,
20
- :push_to_repository_user,
21
- :push_to_remote_name,
22
- :use_git_submodules,
23
- :git_tool,
24
- :pivotal_tracker_username,
25
- :pivotal_tracker_password,
26
- :default_pivotal_tracker_project_id,
27
- :ticket_tracker_username,
28
- :ticket_tracker_password,
29
- :default_ticket_tracker_project,
30
- :ticket_tracking_tool,
31
- :ticket_tracker_owner,
32
- :ticket_status_for_complete,
33
- :default_pull_request_title_format,
34
- :time_tracking_tool,
35
- :time_tracking_username,
36
- :time_tracking_password,
37
- :time_tracking_owner,
38
- :time_tracking_default_project_id,
39
- :load_credentials_if_necessary,
40
- :log_path,
41
- :credentials_loaded_from
42
-
43
14
  GITHUB_BASE_API_URL = 'https://api.github.com/'
44
15
  PIVOTAL_TRACKER_BASE_API_URL = 'https://www.pivotaltracker.com/services/v5/'
45
16
 
46
- class << self
47
- def config_path
48
- ENV['TOOLSHED_CONFIG'] || '~/.toolshedrc'
49
- end
17
+ attr_reader :struct
50
18
 
51
- def load_credentials # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
52
- credentials = Client.read_credenials
53
- instance.github_username ||= credentials['github_username']
54
- instance.github_password ||= credentials['github_password']
55
- instance.github_token ||= credentials['github_token']
56
- instance.pivotal_tracker_username ||= credentials['pivotal_tracker_username']
57
- instance.pivotal_tracker_password ||= credentials['pivotal_tracker_password']
58
- instance.default_pivotal_tracker_project_id ||= credentials['default_pivotal_tracker_project_id'] # rubocop:disable Metrics/LineLength
59
- instance.ticket_tracker_username ||= credentials['ticket_tracker_username']
60
- instance.ticket_tracker_password ||= credentials['ticket_tracker_password']
61
- instance.ticket_tracker_owner ||= credentials['ticket_tracker_owner']
62
- instance.ticket_status_for_complete ||= credentials['ticket_status_for_complete']
63
- instance.default_ticket_tracker_project ||= credentials['default_ticket_tracker_project'] # rubocop:disable Metrics/LineLength
64
- instance.pull_from_remote_name ||= credentials['pull_from_remote_name']
65
- instance.pull_from_repository_user ||= credentials['pull_from_repository_user']
66
- instance.pull_from_repository_name ||= credentials['pull_from_repository_name']
67
- instance.push_to_repository_user ||= credentials['push_to_repository_user']
68
- instance.push_to_remote_name ||= credentials['push_to_remote_name']
69
- instance.ticket_tracking_tool ||= credentials['ticket_tracking_tool'] # rubocop:disable Metrics/LineLength
70
- instance.use_git_submodules ||= credentials['use_git_submodules']
71
- instance.git_tool ||= credentials['git_tool']
72
- instance.time_tracking_username ||= credentials['time_tracking_username']
73
- instance.time_tracking_password ||= credentials['time_tracking_password']
74
- instance.time_tracking_owner ||= credentials['time_tracking_owner']
75
- instance.time_tracking_default_project_id ||= credentials['time_tracking_default_project_id'] # rubocop:disable Metrics/LineLength
76
- instance.time_tracking_tool ||= credentials['time_tracking_tool']
77
- instance.git_quiet ||= (credentials['git_quiet']) ? '&> /dev/null' : ''
78
- instance.use_defaults ||= credentials['use_defaults']
79
- instance.default_pull_request_title_format ||= credentials['default_pull_request_title_format'] # rubocop:disable Metrics/LineLength
80
- instance.log_path ||= credentials['log_path']
81
- instance.credentials_loaded_from ||= load_credentials_from
82
- end
19
+ def initialize
20
+ load_toolshedrc_configuration
21
+ @struct = to_ostruct
22
+ end
83
23
 
84
- def read_credenials
85
- YAML.load_file(File.expand_path(load_credentials_from))
24
+ def load_toolshedrc_configuration
25
+ toolshedrc_configurations = YAML.load(ERB.new(File.read(toolshedrc_path)).result)
26
+ raise CorruptFileException, 'Toolshedrc file is not configured properly.' unless toolshedrc_configurations.is_a?(Hash)
27
+ self.merge!(toolshedrc_configurations)
28
+ end
29
+
30
+ def method_missing(*args)
31
+ begin
32
+ if args.first.to_s.end_with?('=')
33
+ val = args.last
34
+ my_h = self
35
+ args.each_with_index do |arg, index|
36
+ arg = arg.to_s.gsub('=', '')
37
+ next_arg_val = args[index + 1].to_s.gsub('=', '')
38
+ my_h = my_h[arg] unless next_arg_val == val.to_s
39
+ my_h[arg] = val if next_arg_val == val.to_s && !my_h[arg].nil?
40
+ my_h.merge!(arg => val) if next_arg_val == val.to_s && my_h[arg].nil?
41
+ end
42
+ @struct = to_ostruct
43
+ else
44
+ struct.send(args.first)
45
+ end
46
+ rescue NoMethodError => e
47
+ Toolshed.die(e.message)
86
48
  end
49
+ end
87
50
 
88
- def load_credentials_from
51
+ def toolshedrc_path
52
+ @toolshedrc_path ||= begin
89
53
  dir = Dir.pwd
90
54
  while File.expand_path(dir) != '/'
91
55
  unless File.exist?("#{dir}/.toolshedrc")
@@ -95,7 +59,6 @@ module Toolshed
95
59
  credentials_loaded_from = "#{dir}/.toolshedrc"
96
60
  break
97
61
  end
98
-
99
62
  credentials_loaded_from
100
63
  end
101
64
  end
@@ -13,7 +13,7 @@ module Toolshed
13
13
  options_parser = OptionParser.new do |opts|
14
14
  opts.banner = cli_options[:banner] if cli_options[:banner]
15
15
  cli_options[:options].each do |option_name, option_variables|
16
- letter_map = ('a'..'z').map { |letter| letter }
16
+ letter_map = ('a'..'z').map { |letter| letter }.delete_if { |letter| letter == 'h' }
17
17
  short_on = (option_variables[:short_on]) ? option_variables[:short_on] : letter_map[rand(letter_map.length)] # rubocop:disable Metrics/LineLength
18
18
  on = (option_variables[:on]) ? option_variables[:on] : "--#{option_name.to_s.split('_').join('-')} [ARG]" # rubocop:disable Metrics/LineLength
19
19
  opts.on(short_on, on) do |opt|
@@ -21,6 +21,10 @@ module Toolshed
21
21
  options.merge!(option_name => value)
22
22
  end
23
23
  end
24
+ opts.on_tail("-h", "--help", "Show this message") do
25
+ puts opts
26
+ exit
27
+ end
24
28
  end
25
29
  options_parser.order! if options_parser
26
30
  begin
@@ -0,0 +1,56 @@
1
+ require 'toolshed/commands/base'
2
+ require 'toolshed/databases/mysql/backup'
3
+
4
+ module Toolshed
5
+ module Commands
6
+ module Mysql
7
+ # Responsible for handing backup of mysql database
8
+ class Backup < Toolshed::Commands::Base
9
+ def self.cli_options # rubocop:disable MethodLength
10
+ {
11
+ banner: 'Usage: mysql backup [options]',
12
+ options: {
13
+ local_host: {
14
+ short_on: '-l'
15
+ },
16
+ path: {
17
+ short_on: '-p'
18
+ },
19
+ username: {
20
+ short_on: '-u'
21
+ },
22
+ password: {
23
+ short_on: '-d'
24
+ },
25
+ name: {
26
+ short_on: '-n'
27
+ },
28
+ wait_time: {
29
+ short_on: '-w'
30
+ }
31
+ }
32
+ }
33
+ end
34
+
35
+ def execute(_args, options = nil)
36
+ options = options_with_defaults(options)
37
+ Toolshed.logger.info ''
38
+ Toolshed::Databases::Mysql::Backup.new(options).execute
39
+ Toolshed.logger.info ''
40
+ Toolshed.die
41
+ end
42
+
43
+ private
44
+
45
+ def options_with_defaults(options = nil)
46
+ options ||= {}
47
+ options[:local_host] ||= 'localhost'
48
+ options[:path] ||= read_user_input("Storage Path (/tmp/test/#{Time.now.utc.getlocal.strftime('%Y%m%d')}.sql) ?", required: true)
49
+ options[:username] ||= read_user_input('Username?', required: true)
50
+ options[:name] ||= read_user_input('Database Name?', required: true)
51
+ options
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -36,6 +36,9 @@ module Toolshed
36
36
  },
37
37
  verbose_output: {
38
38
  short_on: '-v'
39
+ },
40
+ timeout_period: {
41
+ short_on: '-t'
39
42
  }
40
43
  }
41
44
  }
@@ -8,17 +8,17 @@ module Toolshed
8
8
  end
9
9
 
10
10
  def execute(args, options = {})
11
- ticket_tracker_class = Object.const_get("Toolshed::TicketTracking::#{Toolshed::Client.ticket_tracking_tool.camel_case}")
11
+ ticket_tracker_class = Object.const_get("Toolshed::TicketTracking::#{Toolshed::Client.instance.ticket_tracking_tool.camel_case}")
12
12
 
13
13
  use_project_id = Object.const_get("#{ticket_tracker_class}::USE_PROJECT_ID") rescue false
14
14
  if use_project_id
15
- ticket_tracker_project_id = read_user_input_project("Project ID (Default: #{Toolshed::Client.default_pivotal_tracker_project_id}):", options.merge!({ default: Toolshed::Client.default_pivotal_tracker_project_id }))
15
+ ticket_tracker_project_id = read_user_input_project("Project ID (Default: #{Toolshed::Client.instance.default_pivotal_tracker_project_id}):", options.merge!({ default: Toolshed::Client.instance.default_pivotal_tracker_project_id }))
16
16
  options.merge!({ project_id: ticket_tracker_project_id })
17
17
  end
18
18
 
19
19
  use_project_name = Object.const_get("#{ticket_tracker_class}::USE_PROJECT_NAME") rescue false
20
20
  if use_project_name
21
- ticket_tracker_project_name = read_user_input_project("Project Name (Default: #{Toolshed::Client.default_ticket_tracker_project}):", options.merge!({ default: Toolshed::Client.default_ticket_tracker_project }))
21
+ ticket_tracker_project_name = read_user_input_project("Project Name (Default: #{Toolshed::Client.instance.default_ticket_tracker_project}):", options.merge!({ default: Toolshed::Client.instance.default_ticket_tracker_project }))
22
22
  options.merge!({ project: ticket_tracker_project_name })
23
23
  end
24
24
 
@@ -0,0 +1,39 @@
1
+ require 'toolshed/error'
2
+ require 'toolshed/password'
3
+
4
+ module Toolshed
5
+ module Databases
6
+ module Mysql
7
+ class Backup
8
+ include Toolshed::Password
9
+
10
+ attr_reader :local_host, :name, :path, :password, :username, :wait_time
11
+
12
+ def initialize(options = nil)
13
+ options ||= {}
14
+ @local_host = options[:local_host]
15
+ @name = options[:name]
16
+ @path = options[:path]
17
+ @password = options[:password]
18
+ @username = options[:username]
19
+ @wait_time = options[:wait_time] || 120
20
+ end
21
+
22
+ def execute
23
+ raise TypeError, "Wait time passed in is not a number #{wait_time}" unless wait_time.is_a?(Fixnum)
24
+ Toolshed.logger.info "Starting execution of mysqldump -h #{local_host} -u #{username} #{hidden_password_param} #{name} > #{path}."
25
+ Toolshed::Base.wait_for_command("mysqldump -h #{local_host} -u #{username} #{password_param} #{name} > #{path}", wait_time)
26
+ Toolshed.logger.info 'mysqldump has completed.'
27
+ end
28
+
29
+ def password_param
30
+ password.nil? || password.empty? ? '' : "-p #{password_from_config(password)}"
31
+ end
32
+
33
+ def hidden_password_param
34
+ password_param.empty? ? '' : '-p *******'
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -21,22 +21,22 @@ class EntryPoint
21
21
  # @TODO - clean this up as it should really be part of the command it's being used in not globally.
22
22
  global = OptionParser.new do |opts|
23
23
  opts.on("-u", "--github-username [ARG]") do |username|
24
- Toolshed::Client.github_username = username
24
+ Toolshed::Client.instance.github_username = username
25
25
  end
26
26
  opts.on("-p", "--github-password [ARG]") do |password|
27
- Toolshed::Client.github_password = password
27
+ Toolshed::Client.instance.github_password = password
28
28
  end
29
29
  opts.on("-t", "--github-token [ARG]") do |token|
30
- Toolshed::Client.github_token = token
30
+ Toolshed::Client.instance.github_token = token
31
31
  end
32
32
  opts.on("-u", "--pivotal-tracker-username [ARG]") do |username|
33
- Toolshed::Client.pivotal_tracker_username = username
33
+ Toolshed::Client.instance.pivotal_tracker_username = username
34
34
  end
35
35
  opts.on("-p", "--pivotal-tracker-password [ARG]") do |password|
36
- Toolshed::Client.pivotal_tracker_password = password
36
+ Toolshed::Client.instance.pivotal_tracker_password = password
37
37
  end
38
38
  opts.on("-d", "--debug [ARG]") do
39
- Toolshed::Client.debug = true
39
+ Toolshed::Client.instance.debug = true
40
40
  end
41
41
  opts.on('-v', '--version', 'Version') do
42
42
  Toolshed::Version.banner
@@ -108,9 +108,11 @@ Available Commands:
108
108
  toolshed delete_branch
109
109
  toolshed get_daily_time_update
110
110
  toolshed list_branches
111
+ toolshed mysql backup
111
112
  toolshed push_branch
112
113
  toolshed rename_branch
113
114
  toolshed scp download
115
+ toolshed scp upload
114
116
  toolshed ssh
115
117
  toolshed ticket_information
116
118
  toolshed update_pivotal_tracker_story_status
@@ -1,13 +1,8 @@
1
1
  module Toolshed
2
- class Error < StandardError
3
- end
4
-
5
- class RecordExists < Error
6
- end
7
-
8
- class RecordNotFoundError < Error
9
- end
10
-
11
- class AuthenticationFailed < Error
12
- end
2
+ class Error < StandardError; end
3
+ class RecordExists < Error; end
4
+ class RecordNotFoundError < Error; end
5
+ class AuthenticationFailed < Error; end
6
+ class SSHResponseException < Error; end
7
+ class CorruptFileException < StandardError; end
13
8
  end
@@ -0,0 +1,36 @@
1
+ require 'ostruct'
2
+
3
+ class Hash
4
+ # Recursively converts a <tt>Hash</tt> and all nested <tt>Hash</tt>es to
5
+ # <tt>OpenStruct</tt>s. Especially useful for parsing YAML.
6
+ # yaml=<<EOY
7
+ # subject: Programming Languages
8
+ # languages:
9
+ # - name : Ruby
10
+ # creator : Matz
11
+ # - name : Python
12
+ # creator : Guido van Rossum
13
+ # - name : Perl
14
+ # creator : Larry Wall
15
+ # EOY
16
+ # struct = YAML.load(yaml).to_ostruct
17
+ # struct.subject
18
+ # #=> "Programming Languages"
19
+ # struct.languages.first
20
+ # #=> #<OpenStruct name="Ruby", creator="Matz">
21
+ # struct.languages.first.creator
22
+ # #=> "Matz"
23
+ def to_ostruct
24
+ arr = map do |k, v|
25
+ case v
26
+ when Hash
27
+ [k, v.to_ostruct]
28
+ when Array
29
+ [k, v.map { |el| el.respond_to?(:to_ostruct) ? el.to_ostruct : el }]
30
+ else
31
+ [k, v]
32
+ end
33
+ end
34
+ OpenStruct.new(Hash[arr])
35
+ end
36
+ end
@@ -1,23 +1,23 @@
1
+ require 'toolshed'
1
2
  require 'toolshed/client'
2
3
 
3
4
  module Toolshed
5
+ # Password module looks up password from configuration file if its found
4
6
  module Password
5
7
  def password_from_config(password)
6
8
  return '' if password.nil? || password.empty?
7
9
 
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]
14
- end
15
- rescue => e
16
- Toolshed::Logger.instance.fatal e.message
17
- Toolshed::Logger.instance.fatal e.inspect
18
- return password
10
+ translated_password = Toolshed.configuration
11
+ password_parts = password.split(':')
12
+ password_parts.each do |password_part|
13
+ return password if translated_password[password_part].nil?
14
+ translated_password = translated_password[password_part]
19
15
  end
20
- credentials
16
+ return translated_password
17
+ rescue => e
18
+ Toolshed::Logger.instance.fatal e.message
19
+ Toolshed::Logger.instance.fatal e.inspect
20
+ return password
21
21
  end
22
22
  end
23
23
  end
@@ -1,4 +1,6 @@
1
+ require 'toolshed/error'
1
2
  require 'toolshed/password'
3
+ require 'toolshed/timeout'
2
4
 
3
5
  require 'net/ssh'
4
6
 
@@ -9,7 +11,7 @@ module Toolshed
9
11
  include Toolshed::Password
10
12
 
11
13
  attr_accessor :channel, :commands, :data, :host, :keys, :password, :ssh_options, :sudo_password, :user # rubocop:disable LineLength
12
- attr_reader :silent
14
+ attr_reader :silent, :timeout
13
15
 
14
16
  def initialize(options = nil) # rubocop:disable AbcSize, CyclomaticComplexity, PerceivedComplexity, LineLength
15
17
  options ||= {}
@@ -23,18 +25,27 @@ module Toolshed
23
25
  @password = options[:password] || ''
24
26
  @data = []
25
27
  @silent = options[:silent] || false
28
+ timeout_period = options[:timeout_period].to_i || 30
29
+ @timeout = Toolshed::Timeout.new(timeout_period: timeout_period)
26
30
 
27
31
  set_ssh_options
28
32
  end
29
33
 
30
34
  def execute
31
- Net::SSH.start(host, user, ssh_options) do |ssh|
32
- ssh.open_channel do |channel|
33
- self.channel = channel
34
- request_pty
35
- run_commands
35
+ begin
36
+ timeout.start do
37
+ Net::SSH.start(host, user, ssh_options) do |ssh|
38
+ ssh.open_channel do |channel|
39
+ self.channel = channel
40
+ request_pty
41
+ run_commands
42
+ end
43
+ ssh.loop
44
+ end
36
45
  end
37
- ssh.loop
46
+ rescue Toolshed::Timeout::Error => e
47
+ Toolshed.logger.fatal e.message
48
+ raise SSHResponseException, "Unable to handle response for #{data.last}"
38
49
  end
39
50
  data
40
51
  end
@@ -55,6 +66,7 @@ module Toolshed
55
66
 
56
67
  def request_pty
57
68
  channel.request_pty do |_ch, success|
69
+ timeout.reset_start_time
58
70
  unless silent
59
71
  message = (success) ? 'Successfully obtained pty' : 'Could not obtain pty'
60
72
  puts message
@@ -70,6 +82,7 @@ module Toolshed
70
82
 
71
83
  def on_extended_data
72
84
  channel.on_extended_data do |_ch, _type, data|
85
+ timeout.reset_start_time
73
86
  puts "stderr: #{data}" unless silent
74
87
  end
75
88
  end
@@ -78,13 +91,13 @@ module Toolshed
78
91
  channel.on_data do |_ch, data|
79
92
  puts "#{data}" unless silent
80
93
  self.data << data
94
+ timeout.reset_start_time
81
95
  send_data(data)
82
96
  end
83
97
  end
84
98
 
85
99
  def send_data(data)
86
100
  send_password_data if data =~ /password/
87
- # send_yes_no_data if data =~ /Do you want to continue \[Y\/n\]?/
88
101
  send_yes_no_data if data =~ %r{Do you want to continue [Y/n]?}
89
102
  end
90
103
 
@@ -24,7 +24,6 @@ module Toolshed
24
24
  end
25
25
 
26
26
  self.token = ::PivotalTracker::Client.token(username, password)
27
-
28
27
  self.project_id = (options[:project_id].nil?) ? Toolshed::Client.instance.default_pivotal_tracker_project_id : options[:project_id]
29
28
  @pt_project = ::PivotalTracker::Project.find(self.project_id)
30
29
  self.story = @pt_project.stories.find(options[:ticket_id])
@@ -0,0 +1,95 @@
1
+ require 'time'
2
+
3
+ module Toolshed
4
+ THIS_FILE = /\A#{Regexp.quote(__FILE__)}:/o
5
+ CALLER_OFFSET = ((c = caller[0]) && THIS_FILE =~ c) ? 1 : 0
6
+ private_constant :THIS_FILE, :CALLER_OFFSET
7
+
8
+ # https://github.com/ruby/ruby/blob/trunk/lib/timeout.rb
9
+ # This code had to be modified so the timeout could be extended instead of just being a fixnum.
10
+ # This is import for the SSH client as we want it to keep running for an unlimited time period as
11
+ # long as we are getting output from the client. When that stops then the timeout needs to kick in
12
+ # just in case the server is no longer responding or a connection got lost. Too bad ruby core doesn't
13
+ # already support something like this.
14
+ class Timeout
15
+ attr_accessor :start_time
16
+ attr_reader :timeout_period
17
+
18
+ def initialize(options = nil)
19
+ options ||= {}
20
+ @timeout_period = options[:timeout_period] || 30
21
+ @start_time = options[:start_time] || Time.now.utc.to_i
22
+ end
23
+
24
+ def reset_start_time
25
+ @start_time = Time.now.utc.to_i
26
+ end
27
+
28
+ def start(klass = nil) #:yield: +sec+
29
+ return yield(timeout_period) if timeout_period == nil or timeout_period.zero?
30
+ message = "execution expired in #{timeout_period} seconds".freeze
31
+ e = Error
32
+ bl = proc do |exception|
33
+ begin
34
+ x = Thread.current
35
+ y = Thread.start {
36
+ begin
37
+ sleep(1) until timed_out?
38
+ rescue => e
39
+ x.raise e
40
+ else
41
+ x.raise exception, message
42
+ end
43
+ }
44
+ return yield(timeout_period)
45
+ ensure
46
+ if y
47
+ y.kill
48
+ y.join # make sure y is dead.
49
+ end
50
+ end
51
+ end
52
+ if klass
53
+ begin
54
+ bl.call(klass)
55
+ rescue klass => e
56
+ bt = e.backtrace
57
+ end
58
+ else
59
+ bt = Error.catch(message, &bl)
60
+ end
61
+ level = -caller(CALLER_OFFSET).size-2
62
+ while THIS_FILE =~ bt[level]
63
+ bt.delete_at(level)
64
+ end
65
+ raise(e, message, bt)
66
+ end
67
+
68
+ def timed_out?
69
+ Time.now.utc.to_i - start_time > timeout_period
70
+ end
71
+
72
+ # Raised by Timeout#timeout when the block times out.
73
+ class Error < RuntimeError
74
+ attr_reader :thread
75
+
76
+ def self.catch(*args)
77
+ exc = new(*args)
78
+ exc.instance_variable_set(:@thread, Thread.current)
79
+ ::Kernel.catch(exc) {yield exc}
80
+ end
81
+
82
+ def exception(*)
83
+ # TODO: use Fiber.current to see if self can be thrown
84
+ if self.thread == Thread.current
85
+ bt = caller
86
+ begin
87
+ throw(self, bt)
88
+ rescue UncaughtThrowError
89
+ end
90
+ end
91
+ self
92
+ end
93
+ end
94
+ end
95
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Module for toolshed
4
4
  module Toolshed
5
- VERSION = '1.0.5'
5
+ VERSION = '1.0.6'
6
6
 
7
7
  # Display the version information with the toolshed banner
8
8
  class Version
data/lib/toolshed.rb CHANGED
@@ -15,7 +15,7 @@ module Toolshed
15
15
 
16
16
  class << self
17
17
  def add_file_log_source(command_name = '')
18
- log_path = Toolshed::Client.instance.log_path
18
+ log_path = Toolshed.configuration.log_path
19
19
  return if log_path.nil? || log_path.empty?
20
20
 
21
21
  FileUtils.mkdir_p(log_path)
@@ -27,6 +27,10 @@ module Toolshed
27
27
  logger.add_log_source(file)
28
28
  end
29
29
 
30
+ def configuration
31
+ Toolshed::Client.instance
32
+ end
33
+
30
34
  def deprecate(message = nil)
31
35
  message ||= 'You are using deprecated behavior which will be removed from the next major or minor release.' # rubocop:disable Metrics/LineLength
32
36
  warn("DEPRECATION WARNING: #{message}")
data/test/.toolshedrc CHANGED
@@ -1 +1,3 @@
1
1
  server_password: "tester1234"
2
+ use_git_submodules: false
3
+ git_quiet: ''
@@ -103,26 +103,18 @@ class CreatePullRequestTest < Test::Unit::TestCase
103
103
  pivotal_tracker_mock = mock('PivotalTracker::Client')
104
104
  pivotal_tracker_mock.stubs(:id => '1')
105
105
 
106
- PivotalTracker::Project.expects(:find).
107
- with(Toolshed::Client.instance.default_pivotal_tracker_project_id).
108
- returns(pivotal_tracker_mock)
106
+ PivotalTracker::Project.expects(:find).with(Toolshed::Client.instance.default_pivotal_tracker_project_id).returns(pivotal_tracker_mock)
109
107
 
110
108
  # mock up the story information
111
109
  pivotal_tracker_story_mock = mock('PivotalTracker::Story')
112
110
  pivotal_tracker_story_mock.stubs(:url => 'http://www.example.com', :id => '1', :name => "Test Title")
113
111
 
114
- pivotal_tracker_mock.expects(:stories).
115
- returns(pivotal_tracker_story_mock)
112
+ pivotal_tracker_mock.expects(:stories).returns(pivotal_tracker_story_mock)
116
113
 
117
- pivotal_tracker_story_mock.expects(:find).
118
- with('1').
119
- returns(pivotal_tracker_story_mock)
114
+ pivotal_tracker_story_mock.expects(:find).with('1').returns(pivotal_tracker_story_mock)
120
115
 
121
- Toolshed::TicketTracking::PivotalTracker.any_instance.expects(:title).
122
- returns("Sample")
123
-
124
- Toolshed::TicketTracking::PivotalTracker.any_instance.expects(:url).
125
- returns("github.com/pulls/1")
116
+ Toolshed::TicketTracking::PivotalTracker.any_instance.expects(:title).returns("Sample")
117
+ Toolshed::TicketTracking::PivotalTracker.any_instance.expects(:url).returns("github.com/pulls/1")
126
118
 
127
119
  # stub the possible input
128
120
  Toolshed::Commands::CreatePullRequest.any_instance.stubs(:read_user_input_ticket_tracker_ticket_id).returns('1')
@@ -0,0 +1,38 @@
1
+ require 'commands/commands_helper'
2
+ require 'toolshed/commands/mysql/backup'
3
+
4
+ module Test
5
+ module Commands
6
+ module Mysql
7
+ class BackupTest < Test::Unit::TestCase
8
+ def setup
9
+ Toolshed::Logger.instance.instance_variable_set(:@logs, { debug: [], fatal: [], info: [], warn: [] })
10
+ Toolshed.expects(:die).at_least(0).returns('Exiting')
11
+ end
12
+
13
+ def teardown
14
+ Toolshed::Logger.instance.instance_variable_set(:@logs, { debug: [], fatal: [], info: [], warn: [] })
15
+ end
16
+
17
+ def test_execute
18
+ Toolshed::Base.expects(:wait_for_command).returns(true)
19
+
20
+ path = '/tmp/testing/test.sql'
21
+ username = 'test'
22
+ password = 'test'
23
+ name = 'localdb'
24
+
25
+ mysql_backup_command = Toolshed::Commands::Mysql::Backup.new
26
+ mysql_backup_command.execute({}, path: path, username: username, password: password, name: name)
27
+
28
+ assert Toolshed::Logger.instance.logs[:info].include?("Starting execution of mysqldump -h localhost -u #{username} -p ******* #{name} > #{path}.")
29
+ assert Toolshed::Logger.instance.logs[:info].include?('mysqldump has completed.')
30
+ end
31
+
32
+ def test_cli_options
33
+ assert 'Usage: mysql backup [options]', Toolshed::Commands::Mysql::Backup.cli_options[:banner]
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,45 @@
1
+ require 'commands/commands_helper'
2
+ require 'toolshed/databases/mysql/backup'
3
+
4
+ module Test
5
+ module Databases
6
+ module Mysql
7
+ class BackupTest < Test::Unit::TestCase
8
+ def setup
9
+ Toolshed::Logger.instance.instance_variable_set(:@logs, { debug: [], fatal: [], info: [], warn: [] })
10
+ Toolshed.expects(:die).at_least(0).returns('Exiting')
11
+ end
12
+
13
+ def teardown
14
+ Toolshed::Logger.instance.instance_variable_set(:@logs, { debug: [], fatal: [], info: [], warn: [] })
15
+ end
16
+
17
+ def test_execute
18
+ Toolshed::Base.expects(:wait_for_command).returns(true)
19
+
20
+ path = '/tmp/testing/test.sql'
21
+ username = 'test'
22
+ password = 'test'
23
+ name = 'localdb'
24
+
25
+ Toolshed::Databases::Mysql::Backup.new(path: path, username: username, password: password, name: name, local_host: 'localhost').execute
26
+
27
+ assert Toolshed::Logger.instance.logs[:info].include?("Starting execution of mysqldump -h localhost -u #{username} -p ******* #{name} > #{path}.")
28
+ assert Toolshed::Logger.instance.logs[:info].include?('mysqldump has completed.')
29
+ end
30
+
31
+ def test_raises_type_error_if_wait_time_is_not_a_fixnum
32
+ path = '/tmp/testing/test.sql'
33
+ username = 'test'
34
+ password = 'test'
35
+ name = 'localdb'
36
+
37
+ ex = assert_raises TypeError do
38
+ Toolshed::Databases::Mysql::Backup.new(path: path, username: username, password: password, name: name, local_host: 'localhost', wait_time: 'bla').execute
39
+ end
40
+ assert_equal 'Wait time passed in is not a number bla', ex.message
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
data/test/helper.rb CHANGED
@@ -21,9 +21,7 @@ require 'toolshed'
21
21
  require 'toolshed/logger'
22
22
 
23
23
  Test::Unit.at_start do
24
- Toolshed::Client.instance.use_git_submodules = false
25
24
  #Toolshed::Client.git_quiet = '&> /dev/null' unless ENV['RUNNING_ON_CI']
26
- Toolshed::Client.instance.git_quiet = ''
27
25
 
28
26
  I18n.config.enforce_available_locales = true
29
27
 
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.5
4
+ version: 1.0.6
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-10-03 00:00:00.000000000 Z
11
+ date: 2015-10-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -349,6 +349,7 @@ files:
349
349
  - lib/toolshed/commands/delete_branch.rb
350
350
  - lib/toolshed/commands/get_daily_time_update.rb
351
351
  - lib/toolshed/commands/list_branches.rb
352
+ - lib/toolshed/commands/mysql/backup.rb
352
353
  - lib/toolshed/commands/push_branch.rb
353
354
  - lib/toolshed/commands/rename_branch.rb
354
355
  - lib/toolshed/commands/scp/download.rb
@@ -358,6 +359,7 @@ files:
358
359
  - lib/toolshed/commands/ticket_information.rb
359
360
  - lib/toolshed/commands/update_pivotal_tracker_story_status.rb
360
361
  - lib/toolshed/commands/update_ticket_status.rb
362
+ - lib/toolshed/databases/mysql/backup.rb
361
363
  - lib/toolshed/entry_point.rb
362
364
  - lib/toolshed/error.rb
363
365
  - lib/toolshed/exceptions.rb
@@ -365,6 +367,7 @@ files:
365
367
  - lib/toolshed/git/branch.rb
366
368
  - lib/toolshed/git/github.rb
367
369
  - lib/toolshed/git/validator.rb
370
+ - lib/toolshed/hash.rb
368
371
  - lib/toolshed/logger.rb
369
372
  - lib/toolshed/password.rb
370
373
  - lib/toolshed/server_administration/scp.rb
@@ -374,6 +377,7 @@ files:
374
377
  - lib/toolshed/ticket_tracking/ticket_tracking.rb
375
378
  - lib/toolshed/time_tracking/harvest.rb
376
379
  - lib/toolshed/time_tracking/time_tracking.rb
380
+ - lib/toolshed/timeout.rb
377
381
  - lib/toolshed/version.rb
378
382
  - test/.toolshedrc
379
383
  - test/commands/checkout_branch_test.rb
@@ -382,11 +386,13 @@ files:
382
386
  - test/commands/create_pull_request_test.rb
383
387
  - test/commands/delete_branch_test.rb
384
388
  - test/commands/get_daily_time_update_test.rb
389
+ - test/commands/mysql/backup_test.rb
385
390
  - test/commands/push_branch_test.rb
386
391
  - test/commands/rename_branch_test.rb
387
392
  - test/commands/scp/download_test.rb
388
393
  - test/commands/scp/upload_test.rb
389
394
  - test/config.rb
395
+ - test/databases/mysql/backup_test.rb
390
396
  - test/git/git_helper.rb
391
397
  - test/git/git_test.rb
392
398
  - test/git/github_test.rb
@@ -430,11 +436,13 @@ test_files:
430
436
  - test/commands/create_pull_request_test.rb
431
437
  - test/commands/delete_branch_test.rb
432
438
  - test/commands/get_daily_time_update_test.rb
439
+ - test/commands/mysql/backup_test.rb
433
440
  - test/commands/push_branch_test.rb
434
441
  - test/commands/rename_branch_test.rb
435
442
  - test/commands/scp/download_test.rb
436
443
  - test/commands/scp/upload_test.rb
437
444
  - test/config.rb
445
+ - test/databases/mysql/backup_test.rb
438
446
  - test/git/git_helper.rb
439
447
  - test/git/git_test.rb
440
448
  - test/git/github_test.rb