toolshed 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +11 -0
  4. data/.toolshedrc.sample +32 -0
  5. data/README.md +159 -2
  6. data/Rakefile +3 -3
  7. data/bin/toolshed +6 -1
  8. data/lib/toolshed.rb +38 -28
  9. data/lib/toolshed/base.rb +33 -11
  10. data/lib/toolshed/cli.rb +30 -38
  11. data/lib/toolshed/client.rb +87 -293
  12. data/lib/toolshed/commands/base.rb +65 -23
  13. data/lib/toolshed/commands/checkout_branch.rb +15 -2
  14. data/lib/toolshed/commands/create_branch.rb +34 -29
  15. data/lib/toolshed/commands/create_pivotal_tracker_note.rb +9 -3
  16. data/lib/toolshed/commands/create_pull_request.rb +115 -68
  17. data/lib/toolshed/commands/create_ticket_comment.rb +17 -1
  18. data/lib/toolshed/commands/delete_branch.rb +34 -3
  19. data/lib/toolshed/commands/get_daily_time_update.rb +20 -3
  20. data/lib/toolshed/commands/list_branches.rb +16 -5
  21. data/lib/toolshed/commands/push_branch.rb +28 -9
  22. data/lib/toolshed/commands/rename_branch.rb +29 -0
  23. data/lib/toolshed/commands/ssh.rb +44 -3
  24. data/lib/toolshed/commands/ticket_information.rb +30 -4
  25. data/lib/toolshed/commands/update_pivotal_tracker_story_status.rb +9 -3
  26. data/lib/toolshed/commands/update_ticket_status.rb +8 -2
  27. data/lib/toolshed/entry_point.rb +89 -0
  28. data/lib/toolshed/git.rb +59 -0
  29. data/lib/toolshed/git/branch.rb +224 -0
  30. data/lib/toolshed/git/github.rb +45 -57
  31. data/lib/toolshed/git/validator.rb +14 -0
  32. data/lib/toolshed/logger.rb +46 -0
  33. data/lib/toolshed/password.rb +11 -6
  34. data/lib/toolshed/server_administration/ssh.rb +4 -2
  35. data/lib/toolshed/ticket_tracking/jira.rb +8 -6
  36. data/lib/toolshed/ticket_tracking/pivotal_tracker.rb +8 -6
  37. data/lib/toolshed/time_tracking/harvest.rb +8 -14
  38. data/lib/toolshed/version.rb +25 -1
  39. data/test/commands/checkout_branch_test.rb +11 -7
  40. data/test/commands/create_branch_test.rb +29 -24
  41. data/test/commands/create_pull_request_test.rb +39 -31
  42. data/test/commands/delete_branch_test.rb +35 -25
  43. data/test/commands/get_daily_time_update_test.rb +8 -8
  44. data/test/commands/push_branch_test.rb +27 -15
  45. data/test/commands/rename_branch_test.rb +59 -0
  46. data/test/git/git_helper.rb +5 -5
  47. data/test/git/git_test.rb +36 -31
  48. data/test/git/github_test.rb +9 -46
  49. data/test/helper.rb +11 -11
  50. data/test/server_administration/ssh_test.rb +1 -0
  51. data/test/ticket_tracking/jira_test.rb +18 -16
  52. data/test/time_tracking/harvest_test.rb +8 -6
  53. data/toolshed.gemspec +23 -20
  54. metadata +95 -46
  55. data/bin/toolshed.rb +0 -261
  56. data/lib/toolshed/git/git.rb +0 -119
@@ -1,11 +1,28 @@
1
1
  module Toolshed
2
2
  module Commands
3
3
  class GetDailyTimeUpdate
4
+ def self.cli_options
5
+ {
6
+ banner: 'Usage: get_daily_time_update [options]',
7
+ options: {
8
+ format: {
9
+ short_on: '-f',
10
+ },
11
+ use_defaults: {
12
+ short_on: '-d'
13
+ },
14
+ project_id: {
15
+ short_on: '-p',
16
+ }
17
+ }
18
+ }
19
+ end
20
+
4
21
  def execute(args, options = {})
5
22
  begin
6
- time_tracking_class = Object.const_get("Toolshed::TimeTracking::#{Toolshed::Client.time_tracking_tool.camel_case}")
23
+ time_tracking_class = Object.const_get("Toolshed::TimeTracking::#{Toolshed::Client.instance.time_tracking_tool.camel_case}")
7
24
 
8
- time_tracking_project_id = read_user_input_project_id("Project ID (Default: #{Toolshed::Client.time_tracking_default_project_id}):", options.merge!({ default: Toolshed::Client.time_tracking_default_project_id }))
25
+ time_tracking_project_id = read_user_input_project_id("Project ID (Default: #{Toolshed::Client.instance.time_tracking_default_project_id}):", options.merge!({ default: Toolshed::Client.instance.time_tracking_default_project_id }))
9
26
  options.merge!({ project_id: time_tracking_project_id })
10
27
  time_tracker = time_tracking_class.create_instance(options)
11
28
 
@@ -19,7 +36,7 @@ module Toolshed
19
36
 
20
37
  def read_user_input_project_id(message, options)
21
38
  return options[:project_id] if (options.has_key?(:project_id))
22
- return options[:default] if (Toolshed::Client.use_defaults)
39
+ return options[:default] if (Toolshed::Client.instance.use_defaults)
23
40
 
24
41
  puts message
25
42
  value = $stdin.gets.chomp
@@ -1,12 +1,23 @@
1
+ require 'toolshed/git'
2
+
1
3
  module Toolshed
2
4
  module Commands
3
5
  class ListBranches
6
+ def self.cli_options
7
+ {
8
+ banner: 'Usage: list_branches [options]',
9
+ options: {
10
+ repository_name: {
11
+ short_on: '-r',
12
+ },
13
+ }
14
+ }
15
+ end
16
+
4
17
  def execute(args, options = {})
5
- git = Toolshed::Git::Github.new
6
- branches = git.list_branches
7
- branches.each do |branch|
8
- puts branch['name']
9
- end
18
+ branch = Toolshed::Git::Branch.new
19
+ branch.list
20
+ Toolshed.die
10
21
  end
11
22
  end
12
23
  end
@@ -1,11 +1,30 @@
1
- module Toolshed
2
- module Commands
3
- class PushBranch
4
- def execute(args, options = {})
5
- branch_name = Toolshed::Git::Base.push(options)
6
- puts "#{branch_name} has been pushed"
7
- return
8
- end
9
- end
1
+ require 'toolshed/commands/base'
2
+ require 'toolshed/git'
3
+
4
+ class Toolshed::Commands::PushBranch < Toolshed::Commands::Base
5
+ def initialize(options = {})
6
+ super(options)
7
+ end
8
+
9
+ def self.cli_options
10
+ {
11
+ banner: 'Usage: push_branch [options]',
12
+ options: {
13
+ force_command: {
14
+ short_on: '-f',
15
+ default: true
16
+ },
17
+ branch_name: {
18
+ short_on: '-b'
19
+ }
20
+ }
21
+ }
22
+ end
23
+
24
+ def execute(args, options = {})
25
+ Toolshed.logger.info "Running toolshed push_branch with #{options.inspect}"
26
+ branch = Toolshed::Git::Branch.new(options)
27
+ branch.push
28
+ Toolshed.die
10
29
  end
11
30
  end
@@ -0,0 +1,29 @@
1
+ require 'toolshed/commands/base'
2
+ require 'toolshed/git/branch'
3
+
4
+ class Toolshed::Commands::RenameBranch < Toolshed::Commands::Base
5
+ def self.cli_options
6
+ {
7
+ banner: 'Usage: rename_branch [options]',
8
+ options: {
9
+ branch_name: {
10
+ short_on: '-b'
11
+ },
12
+ new_branch_name: {
13
+ short_on: '-n'
14
+ }
15
+ }
16
+ }
17
+ end
18
+
19
+ def execute(args, options = {})
20
+ Toolshed.logger.info "Running toolshed rename_branch with #{options.inspect}"
21
+
22
+ options[:branch_name] = options[:branch_name] || read_user_input('Branch name?', required: true)
23
+ new_branch_name = options[:new_branch_name] || read_user_input('New Branch name?', required: true)
24
+
25
+ branch = Toolshed::Git::Branch.new(options)
26
+ branch.rename(new_branch_name)
27
+ Toolshed.die
28
+ end
29
+ end
@@ -1,14 +1,55 @@
1
+ require 'toolshed/server_administration/ssh'
2
+
1
3
  module Toolshed
2
4
  module Commands
3
5
  class SSH
6
+ def self.cli_options
7
+ {
8
+ banner: 'Usage: ssh [options]',
9
+ options: {
10
+ use_sudo: {
11
+ short_on: '-e'
12
+ },
13
+ host: {
14
+ short_on: '-o'
15
+ },
16
+ connection_string_options: {
17
+ short_on: '-n'
18
+ },
19
+ commands: {
20
+ short_on: '-c'
21
+ },
22
+ password: {
23
+ short_on: '-p'
24
+ },
25
+ prompt_for_password: {
26
+ short_on: '-r'
27
+ },
28
+ user: {
29
+ short_on: '-u'
30
+ },
31
+ keys: {
32
+ short_on: '-k'
33
+ },
34
+ sudo_password: {
35
+ short_on: '-s'
36
+ },
37
+ verbose_output: {
38
+ short_on: '-v'
39
+ }
40
+ }
41
+ }
42
+ end
43
+
4
44
  def execute(args, options = {})
5
- puts "running ssh command with options #{options.inspect}" unless options[:verbose_output].blank?
45
+ Toolshed.logger.info "Running ssh command with options #{options.inspect}" unless options[:verbose_output].nil? || options[:verbose_output].empty? # rubocop:disable Metrics/LineLength
6
46
  begin
7
47
  ssh = Toolshed::ServerAdministration::SSH.new(options)
8
48
  ssh.execute
9
49
  rescue => e
10
- puts e.inspect
11
- puts "Unable to connect to #{options[:host]}"
50
+ Toolshed.logger.fatal e.message
51
+ Toolshed.logger.fatal "Unable to connect to #{options[:host]}"
52
+ Toolshed.die
12
53
  end
13
54
  end
14
55
  end
@@ -1,23 +1,49 @@
1
+ require 'toolshed/git'
2
+
1
3
  module Toolshed
2
4
  module Commands
3
5
  class TicketInformation
6
+ def self.cli_options
7
+ {
8
+ banner: 'Usage: ticket_information [options]',
9
+ options: {
10
+ use_defaults: {
11
+ short_on: '-d'
12
+ },
13
+ clipboard: {
14
+ short_on: '-c'
15
+ },
16
+ field: {
17
+ short_on: '-f'
18
+ },
19
+ formatted_string: {
20
+ short_on: '-fs'
21
+ }
22
+ }
23
+ }
24
+ end
25
+
26
+ def branch
27
+ @branch ||= Toolshed::Git::Branch.new
28
+ end
29
+
4
30
  def execute(args, options = {})
5
31
  begin
6
- ticket_tracker_class = Object.const_get("Toolshed::TicketTracking::#{Toolshed::Client.ticket_tracking_tool.camel_case}")
32
+ ticket_tracker_class = Object.const_get("Toolshed::TicketTracking::#{Toolshed::Client.instance.ticket_tracking_tool.camel_case}")
7
33
 
8
34
  use_project_id = Object.const_get("#{ticket_tracker_class}::USE_PROJECT_ID") rescue false
9
35
  if use_project_id
10
- 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 }))
36
+ 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 }))
11
37
  options.merge!({ project_id: ticket_tracker_project_id })
12
38
  end
13
39
 
14
40
  use_project_name = Object.const_get("#{ticket_tracker_class}::USE_PROJECT_NAME") rescue false
15
41
  if use_project_name
16
- 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 }))
42
+ 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 }))
17
43
  options.merge!({ project: ticket_tracker_project_name })
18
44
  end
19
45
 
20
- default_ticket_id = Toolshed::TicketTracking::story_id_from_branch_name(Toolshed::Git::Base.branch_name)
46
+ default_ticket_id = Toolshed::TicketTracking::story_id_from_branch_name(branch.name)
21
47
  ticket_id = read_user_input_ticket_id("Story ID (Default: #{default_ticket_id}):", options.merge!({ default: default_ticket_id }))
22
48
  options.merge!({ ticket_id: ticket_id })
23
49
 
@@ -1,13 +1,19 @@
1
+ require 'toolshed/git'
2
+
1
3
  module Toolshed
2
4
  module Commands
3
5
  class UpdatePivotalTrackerStoryStatus
4
6
  STORY_STATUS_DEFAULT = 'finished'
5
7
 
8
+ def branch
9
+ @branch ||= Toolshed::Git::Branch.new
10
+ end
11
+
6
12
  def execute(args, options = {})
7
- print "Project ID (Default: #{Toolshed::Client.default_pivotal_tracker_project_id})? "
13
+ print "Project ID (Default: #{Toolshed::Client.instance.default_pivotal_tracker_project_id})? "
8
14
  project_id = $stdin.gets.chomp.strip
9
15
  if (project_id == '')
10
- project_id = Toolshed::Client.default_pivotal_tracker_project_id
16
+ project_id = Toolshed::Client.instance.default_pivotal_tracker_project_id
11
17
  end
12
18
 
13
19
  pivotal_tracker = Toolshed::TicketTracking::PivotalTracker.new({
@@ -16,7 +22,7 @@ module Toolshed
16
22
  password: Toolshed::TicketTracking::PivotalTracker.password,
17
23
  })
18
24
 
19
- default_story_id = Toolshed::TicketTracking::PivotalTracker::story_id_from_branch_name(Toolshed::Git::Base.branch_name)
25
+ default_story_id = Toolshed::TicketTracking::PivotalTracker::story_id_from_branch_name(branch.name)
20
26
  print "Story ID (Default: #{default_story_id})? "
21
27
  story_id = $stdin.gets.chomp.strip
22
28
  if (story_id == '')
@@ -1,6 +1,12 @@
1
+ require 'toolshed/git'
2
+
1
3
  module Toolshed
2
4
  module Commands
3
5
  class UpdateTicketStatus
6
+ def branch
7
+ @branch ||= Toolshed::Git::Branch.new
8
+ end
9
+
4
10
  def execute(args, options = {})
5
11
  ticket_tracker_class = Object.const_get("Toolshed::TicketTracking::#{Toolshed::Client.ticket_tracking_tool.camel_case}")
6
12
 
@@ -16,7 +22,7 @@ module Toolshed
16
22
  options.merge!({ project: ticket_tracker_project_name })
17
23
  end
18
24
 
19
- default_ticket_id = Toolshed::TicketTracking::story_id_from_branch_name(Toolshed::Git::Base.branch_name)
25
+ default_ticket_id = Toolshed::TicketTracking::story_id_from_branch_name(branch.name)
20
26
  ticket_id = read_user_input_ticket_id("Ticket ID (Default: #{default_ticket_id}):", options.merge!({ default: default_ticket_id }))
21
27
  options.merge!({ ticket_id: ticket_id })
22
28
 
@@ -63,7 +69,7 @@ module Toolshed
63
69
  puts message
64
70
  value = $stdin.gets.chomp
65
71
 
66
- until (!value.blank?)
72
+ until !value.nil? && !value.empty?
67
73
  puts "Status must be passed in"
68
74
  puts message
69
75
  value = $stdin.gets.chomp
@@ -0,0 +1,89 @@
1
+ require 'toolshed'
2
+ require 'toolshed/cli'
3
+ require 'toolshed/base'
4
+ require 'toolshed/commands/base'
5
+ require 'optparse'
6
+ require 'singleton'
7
+
8
+ class EntryPoint
9
+ include Singleton
10
+
11
+ attr_accessor :cli
12
+
13
+ def initialize
14
+ self.cli = Toolshed::CLI.new
15
+ end
16
+
17
+ def execute
18
+ if $0.split("/").last == 'toolshed'
19
+ options = {}
20
+
21
+ # @TODO - clean this up as it should really be part of the command it's being used in not globally.
22
+ global = OptionParser.new do |opts|
23
+ opts.on("-u", "--github-username [ARG]") do |username|
24
+ Toolshed::Client.github_username = username
25
+ end
26
+ opts.on("-p", "--github-password [ARG]") do |password|
27
+ Toolshed::Client.github_password = password
28
+ end
29
+ opts.on("-t", "--github-token [ARG]") do |token|
30
+ Toolshed::Client.github_token = token
31
+ end
32
+ opts.on("-u", "--pivotal-tracker-username [ARG]") do |username|
33
+ Toolshed::Client.pivotal_tracker_username = username
34
+ end
35
+ opts.on("-p", "--pivotal-tracker-password [ARG]") do |password|
36
+ Toolshed::Client.pivotal_tracker_password = password
37
+ end
38
+ opts.on("-d", "--debug [ARG]") do
39
+ Toolshed::Client.debug = true
40
+ end
41
+ opts.on('-v', '--version', 'Version') do
42
+ Toolshed::Version.banner
43
+ end
44
+ end
45
+
46
+ global.order!
47
+ command = ARGV.shift
48
+ if command.nil?
49
+ usage
50
+ elsif command == 'version'
51
+ Toolshed::Version.banner
52
+ Toolshed.die
53
+ else
54
+ command_class = nil
55
+ command_class_name = command.camel_case
56
+ 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 }
61
+ end
62
+ Toolshed::Commands::Base.parse(command, command_class.cli_options)
63
+ end
64
+ end
65
+ end
66
+
67
+ def usage
68
+ $stdout.puts <<EOF
69
+ Please see toolshedrc.sample to create your toolshedrc settings file.
70
+
71
+ Available Commands:
72
+
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
87
+ EOF
88
+ end
89
+ end
@@ -0,0 +1,59 @@
1
+ require 'toolshed/base'
2
+ require 'toolshed/git/validator'
3
+ require 'highline/import'
4
+
5
+ module Toolshed
6
+ class Git
7
+ require 'toolshed/git/branch'
8
+
9
+ DEFAULT_GIT_TOOL = 'github'
10
+ DEFAULT_BRANCH_FROM = 'master'
11
+
12
+ attr_accessor :from_remote_name, :from_remote_branch_name, :to_remote_name, :to_remote_branch_name, :validator, :passed_branch_name, :force
13
+
14
+ def initialize(options = {})
15
+ # options with defaults
16
+ self.from_remote_name = Toolshed::Client.instance.pull_from_remote_name
17
+ unless (options[:from_remote_name].nil?)
18
+ self.from_remote_name = options[:from_remote_name]
19
+ end
20
+
21
+ self.to_remote_name = Toolshed::Client.instance.push_to_remote_name
22
+ unless (options[:to_remote_name].nil?)
23
+ self.to_remote_name = options[:to_remote_name]
24
+ end
25
+
26
+ # options that do not have a default
27
+ unless (options[:from_remote_branch_name].nil?)
28
+ self.from_remote_branch_name = options[:from_remote_branch_name]
29
+ end
30
+
31
+ unless (options[:to_remote_branch_name].nil?)
32
+ self.to_remote_branch_name = options[:to_remote_branch_name]
33
+ end
34
+
35
+ self.validator = ::Toolshed::Git::Validator.new
36
+ self.passed_branch_name = options[:branch_name] || ''
37
+ self.force = (options.key?(:force_command)) ? '--force' : ''
38
+ end
39
+
40
+ class << self
41
+ def git_submodule_command
42
+ git_submodule_command = ''
43
+ git_submodule_command = "git submodule update #{Toolshed::Client.instance.git_quiet}" if Toolshed::Client.instance.use_git_submodules
44
+ git_submodule_command
45
+ end
46
+
47
+ def clean_branch_name(branch_name)
48
+ branch_name.strip.downcase.tr(' ', '_').gsub('&', '').gsub('.', '_').gsub("'", '').gsub(':', '').gsub(',', '').gsub('>', '').gsub('__', '_')
49
+ end
50
+ end
51
+
52
+ def remote_update
53
+ results = Toolshed::Base.wait_for_command("git remote update #{Toolshed::Client.instance.git_quiet}")
54
+ results[:all].each do |out|
55
+ Toolshed.logger.info out
56
+ end
57
+ end
58
+ end
59
+ end