toolshed 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +14 -0
- data/Rakefile +11 -0
- data/bin/toolshed.rb +95 -16
- data/lib/toolshed/base.rb +7 -0
- data/lib/toolshed/cli.rb +13 -6
- data/lib/toolshed/client.rb +105 -83
- data/lib/toolshed/commands/checkout_branch.rb +26 -0
- data/lib/toolshed/commands/create_branch.rb +60 -0
- data/lib/toolshed/commands/create_pivotal_tracker_note.rb +9 -4
- data/lib/toolshed/commands/create_pull_request.rb +137 -0
- data/lib/toolshed/commands/delete_branch.rb +27 -0
- data/lib/toolshed/commands/get_daily_time_update.rb +21 -0
- data/lib/toolshed/commands/get_pivotal_tracker_story_information.rb +6 -3
- data/lib/toolshed/commands/list_branches.rb +13 -0
- data/lib/toolshed/commands/push_branch.rb +11 -0
- data/lib/toolshed/commands/update_pivotal_tracker_story_status.rb +8 -5
- data/lib/toolshed/git/git.rb +134 -0
- data/lib/toolshed/git/github.rb +88 -0
- data/lib/toolshed/ticket_tracking/pivotal_tracker.rb +111 -0
- data/lib/toolshed/ticket_tracking/ticket_tracking.rb +6 -0
- data/lib/toolshed/time_tracking/harvest.rb +68 -0
- data/lib/toolshed/time_tracking/time_tracking.rb +6 -0
- data/lib/toolshed/version.rb +1 -1
- data/lib/toolshed.rb +8 -2
- data/test/commands/checkout_branch_test.rb +28 -0
- data/test/commands/commands_helper.rb +2 -0
- data/test/commands/create_branch_test.rb +44 -0
- data/test/commands/create_pull_request_test.rb +125 -0
- data/test/commands/delete_branch_test.rb +75 -0
- data/test/commands/push_branch_test.rb +49 -0
- data/test/config.rb +1 -0
- data/test/git/git_helper.rb +31 -0
- data/test/git/git_test.rb +115 -0
- data/test/git/github_test.rb +91 -0
- data/test/helper.rb +98 -0
- data/toolshed.gemspec +8 -0
- metadata +151 -9
- data/lib/toolshed/commands/checkout_git_branch.rb +0 -23
- data/lib/toolshed/commands/create_git_branch.rb +0 -28
- data/lib/toolshed/commands/create_github_pull_request.rb +0 -77
- data/lib/toolshed/commands/push_git_branch.rb +0 -10
- data/lib/toolshed/github.rb +0 -89
- data/lib/toolshed/pivotal_tracker.rb +0 -87
@@ -0,0 +1,137 @@
|
|
1
|
+
module Toolshed
|
2
|
+
module Commands
|
3
|
+
class CreatePullRequest
|
4
|
+
def execute(args, options = {})
|
5
|
+
# see what branch is checked out and where we are branched from
|
6
|
+
puts "Current Branch: #{Toolshed::Git::Base.branch_name}"
|
7
|
+
puts "Branched From: #{Toolshed::Git::Base.branched_from}"
|
8
|
+
puts "Using Defaults: #{(Toolshed::Client.use_defaults.nil?) ? 'No' : 'Yes'}"
|
9
|
+
|
10
|
+
unless (Toolshed::Client.ticket_tracking_tool.empty?)
|
11
|
+
ticket_tracking_url = ''
|
12
|
+
ticket_tracking_title = ''
|
13
|
+
ticket_id = ''
|
14
|
+
|
15
|
+
begin
|
16
|
+
ticket_tracker_class = Object.const_get("Toolshed::TicketTracking::#{Toolshed::Client.ticket_tracking_tool.camel_case}")
|
17
|
+
|
18
|
+
if Object.const_get("#{ticket_tracker_class}::USE_PROJECT_ID")
|
19
|
+
ticket_tracker_project_id = read_user_input_ticket_tracker_project_id("Project ID (Default: #{Toolshed::Client.default_pivotal_tracker_project_id}):", { default: Toolshed::Client.default_pivotal_tracker_project_id })
|
20
|
+
options.merge!({ project_id: ticket_tracker_project_id })
|
21
|
+
end
|
22
|
+
|
23
|
+
ticket_tracker = ticket_tracker_class.create_instance(options)
|
24
|
+
|
25
|
+
# @TODO - refactor this code into the git module seems more appropriate since it's performing git functions
|
26
|
+
ticket_id = read_user_input_ticket_tracker_ticket_id("Ticket ID (Default: #{Toolshed::TicketTracking::PivotalTracker::story_id_from_branch_name(Toolshed::Git::Base.branch_name)}):", { default: Toolshed::TicketTracking::PivotalTracker::story_id_from_branch_name(Toolshed::Git::Base.branch_name) })
|
27
|
+
ticket_information = ticket_tracker.story_information(ticket_id)
|
28
|
+
|
29
|
+
ticket_tracking_url = ticket_information.url
|
30
|
+
ticket_tracking_title = ticket_tracker_class.clean(ticket_information.name)
|
31
|
+
ticket_id = ticket_information.id
|
32
|
+
|
33
|
+
puts "Ticket Tracking URL: #{ticket_tracking_url}"
|
34
|
+
puts "Ticket Tracking title: #{ticket_tracking_title}"
|
35
|
+
puts "Ticket ID: #{ticket_id}"
|
36
|
+
rescue
|
37
|
+
puts "Ticket tracking tool is not supported at this time"
|
38
|
+
return
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
pull_request_url = ''
|
43
|
+
begin
|
44
|
+
git_tool_class = Object.const_get("Toolshed::Git::#{Toolshed::Client.git_tool.camel_case}")
|
45
|
+
git_tool = git_tool_class.create_instance
|
46
|
+
|
47
|
+
# create the pull request prompt when needed
|
48
|
+
title = read_user_input_pull_request_title("Pull request title (Default: #{ticket_tracking_title}):", options.merge!({ :default => ticket_tracking_title }))
|
49
|
+
body = read_user_input_pull_request_body("Pull request body (Default: #{ticket_tracking_url}):", options.merge!({ :default => ticket_tracking_url }))
|
50
|
+
|
51
|
+
puts "Pull request being created"
|
52
|
+
git_pull_request_result = git_tool.create_pull_request(title, body)
|
53
|
+
pull_request_url = git_pull_request_result["html_url"]
|
54
|
+
|
55
|
+
add_note_to_ticket = read_user_input_add_note_to_ticket("Would you like to add a note with the pull request url?")
|
56
|
+
if (add_note_to_ticket)
|
57
|
+
result = ticket_tracker.add_note(ticket_id, pull_request_url)
|
58
|
+
result = ticket_tracker.update_ticket_status(ticket_id, Object.const_get("#{ticket_tracker_class}::DEFAULT_COMPLETED_STATUS"))
|
59
|
+
end
|
60
|
+
|
61
|
+
puts "Created Pull Request: #{pull_request_url}"
|
62
|
+
rescue => e
|
63
|
+
puts e.message
|
64
|
+
exit
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def read_user_input_add_note_to_ticket(message)
|
69
|
+
return true if (Toolshed::Client.use_defaults)
|
70
|
+
|
71
|
+
puts message
|
72
|
+
value = $stdin.gets.chomp
|
73
|
+
|
74
|
+
until (%w(y n).include?(value.downcase))
|
75
|
+
puts "Value must be Y or N"
|
76
|
+
puts message
|
77
|
+
value = $stdin.gets.chomp
|
78
|
+
end
|
79
|
+
|
80
|
+
(value == 'y') ? true : false
|
81
|
+
end
|
82
|
+
|
83
|
+
def read_user_input_pull_request_title(message, options)
|
84
|
+
return options[:title] if (options.has_key?(:title))
|
85
|
+
return options[:default] if (Toolshed::Client.use_defaults)
|
86
|
+
|
87
|
+
puts message
|
88
|
+
value = $stdin.gets.chomp
|
89
|
+
if (value.empty?)
|
90
|
+
value = default
|
91
|
+
end
|
92
|
+
|
93
|
+
value
|
94
|
+
end
|
95
|
+
|
96
|
+
def read_user_input_pull_request_body(message, options)
|
97
|
+
return options[:body] if (options.has_key?(:body))
|
98
|
+
return options[:default] if (Toolshed::Client.use_defaults)
|
99
|
+
|
100
|
+
puts message
|
101
|
+
value = $stdin.gets.chomp
|
102
|
+
|
103
|
+
if (value.empty?)
|
104
|
+
value = default
|
105
|
+
end
|
106
|
+
|
107
|
+
value
|
108
|
+
end
|
109
|
+
|
110
|
+
def read_user_input_ticket_tracker_project_id(message, options)
|
111
|
+
return options[:default] if (Toolshed::Client.use_defaults)
|
112
|
+
|
113
|
+
puts message
|
114
|
+
value = $stdin.gets.chomp
|
115
|
+
|
116
|
+
if (value.empty?)
|
117
|
+
value = default
|
118
|
+
end
|
119
|
+
|
120
|
+
value
|
121
|
+
end
|
122
|
+
|
123
|
+
def read_user_input_ticket_tracker_ticket_id(message, options)
|
124
|
+
return options[:default] if (Toolshed::Client.use_defaults)
|
125
|
+
|
126
|
+
puts message
|
127
|
+
value = $stdin.gets.chomp
|
128
|
+
|
129
|
+
if (value.empty?)
|
130
|
+
value = default
|
131
|
+
end
|
132
|
+
|
133
|
+
value
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Toolshed
|
2
|
+
module Commands
|
3
|
+
class DeleteBranch
|
4
|
+
def execute(args, options = {})
|
5
|
+
branch_name = read_user_input("Ticket ID or branch name:", options)
|
6
|
+
branch_name = Toolshed::Git::Base.delete(branch_name)
|
7
|
+
puts "#{branch_name} has been deleted"
|
8
|
+
return
|
9
|
+
end
|
10
|
+
|
11
|
+
def read_user_input(message, options)
|
12
|
+
return options[:branch_name] if (options.has_key?(:branch_name))
|
13
|
+
|
14
|
+
puts message
|
15
|
+
value = $stdin.gets.chomp
|
16
|
+
|
17
|
+
until (!value.empty?)
|
18
|
+
puts "Branch name cannot be empty"
|
19
|
+
puts message
|
20
|
+
value = $stdin.gets.chomp
|
21
|
+
end
|
22
|
+
|
23
|
+
value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Toolshed
|
2
|
+
module Commands
|
3
|
+
class GetDailyTimeUpdate
|
4
|
+
def execute(args, options = {})
|
5
|
+
if (Toolshed::Client.time_tracking_tool == 'harvest')
|
6
|
+
harvest = Toolshed::TimeTracking::Harvest.new
|
7
|
+
|
8
|
+
puts "Getting time entries:"
|
9
|
+
|
10
|
+
notes = harvest.previous
|
11
|
+
notes = "#{notes}\n\n#{harvest.today}"
|
12
|
+
|
13
|
+
puts notes
|
14
|
+
else
|
15
|
+
puts "Time tracking tool is undefined implementation needed"
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -9,10 +9,13 @@ module Toolshed
|
|
9
9
|
project_id = Toolshed::Client.default_pivotal_tracker_project_id
|
10
10
|
end
|
11
11
|
|
12
|
-
pivotal_tracker = Toolshed::PivotalTracker.new({
|
13
|
-
|
12
|
+
pivotal_tracker = Toolshed::TicketTracking::PivotalTracker.new({
|
13
|
+
project_id: project_id,
|
14
|
+
username: Toolshed::TicketTracking::PivotalTracker.username,
|
15
|
+
password: Toolshed::TicketTracking::PivotalTracker.password,
|
16
|
+
})
|
14
17
|
|
15
|
-
default_story_id = Toolshed::PivotalTracker::story_id_from_branch_name(
|
18
|
+
default_story_id = Toolshed::TicketTracking::PivotalTracker::story_id_from_branch_name(Toolshed::Git::Base.branch_name)
|
16
19
|
print "Story ID (Default: #{default_story_id})? "
|
17
20
|
story_id = $stdin.gets.chomp.strip
|
18
21
|
if (story_id == '')
|
@@ -10,20 +10,23 @@ module Toolshed
|
|
10
10
|
project_id = Toolshed::Client.default_pivotal_tracker_project_id
|
11
11
|
end
|
12
12
|
|
13
|
-
pivotal_tracker = Toolshed::PivotalTracker.new({
|
14
|
-
|
13
|
+
pivotal_tracker = Toolshed::TicketTracking::PivotalTracker.new({
|
14
|
+
project_id: project_id,
|
15
|
+
username: Toolshed::TicketTracking::PivotalTracker.username,
|
16
|
+
password: Toolshed::TicketTracking::PivotalTracker.password,
|
17
|
+
})
|
15
18
|
|
16
|
-
default_story_id = Toolshed::PivotalTracker::story_id_from_branch_name(
|
19
|
+
default_story_id = Toolshed::TicketTracking::PivotalTracker::story_id_from_branch_name(Toolshed::Git::Base.branch_name)
|
17
20
|
print "Story ID (Default: #{default_story_id})? "
|
18
21
|
story_id = $stdin.gets.chomp.strip
|
19
22
|
if (story_id == '')
|
20
23
|
story_id = default_story_id
|
21
24
|
end
|
22
25
|
|
23
|
-
print "Status (Default: #{Toolshed::PivotalTracker::STORY_STATUS_DEFAULT})? "
|
26
|
+
print "Status (Default: #{Toolshed::TicketTracking::PivotalTracker::STORY_STATUS_DEFAULT})? "
|
24
27
|
story_status = $stdin.gets.chomp.strip
|
25
28
|
if (story_status == '')
|
26
|
-
story_status = Toolshed::PivotalTracker::STORY_STATUS_DEFAULT
|
29
|
+
story_status = Toolshed::TicketTracking::PivotalTracker::STORY_STATUS_DEFAULT
|
27
30
|
end
|
28
31
|
|
29
32
|
begin
|
@@ -0,0 +1,134 @@
|
|
1
|
+
module Toolshed
|
2
|
+
module Git
|
3
|
+
DEFAULT_GIT_TOOL = 'github'
|
4
|
+
|
5
|
+
def branch_name
|
6
|
+
# branch information
|
7
|
+
branch_name = `git rev-parse --abbrev-ref HEAD`.strip
|
8
|
+
end
|
9
|
+
|
10
|
+
def branched_from
|
11
|
+
branched_from = `git rev-parse --abbrev-ref --symbolic-full-name @{u}`.split('/')[-1].strip
|
12
|
+
end
|
13
|
+
|
14
|
+
def branch_name_from_id(id)
|
15
|
+
branch_name = `git branch | grep \"#{id}\"`.gsub("*", "").strip
|
16
|
+
end
|
17
|
+
|
18
|
+
def checkout(branch_name)
|
19
|
+
branch_name = Toolshed::Git::Base.branch_name_from_id(branch_name)
|
20
|
+
until system("git checkout #{branch_name} #{Toolshed::Client.git_quiet}")
|
21
|
+
sleep 1
|
22
|
+
end
|
23
|
+
|
24
|
+
unless (Toolshed::Git::Base.git_submodule_command.empty?)
|
25
|
+
until system(Toolshed::Git::Base.git_submodule_command)
|
26
|
+
sleep 1
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
branch_name
|
31
|
+
end
|
32
|
+
|
33
|
+
def delete(branch_name)
|
34
|
+
branch_name = Toolshed::Git::Base.branch_name_from_id(branch_name)
|
35
|
+
|
36
|
+
# if delete your current branch checkout master so it can be deleted
|
37
|
+
if (branch_name == Toolshed::Git::Base.branch_name)
|
38
|
+
Toolshed::Git::Base.checkout('master')
|
39
|
+
end
|
40
|
+
|
41
|
+
until system("git push #{Toolshed::Client.push_to_remote_name} :#{branch_name}; git branch -D #{branch_name}")
|
42
|
+
sleep 1
|
43
|
+
end
|
44
|
+
|
45
|
+
branch_name
|
46
|
+
end
|
47
|
+
|
48
|
+
def git_submodule_command
|
49
|
+
git_submodule_command = ''
|
50
|
+
if (Toolshed::Client.use_git_submodules)
|
51
|
+
git_submodule_command = "git submodule update #{Toolshed::Client.git_quiet}"
|
52
|
+
end
|
53
|
+
|
54
|
+
git_submodule_command
|
55
|
+
end
|
56
|
+
|
57
|
+
def clean_branch_name(branch_name)
|
58
|
+
branch_name.strip.downcase.tr(" ", "_").gsub("-", "").gsub("&", "").gsub("/", "_").gsub(".", "_").gsub("'", "").gsub("__", "_").gsub(":", "")
|
59
|
+
end
|
60
|
+
|
61
|
+
def push(options = {})
|
62
|
+
branch_name = (options.has_key?(:branch_name)) ? Toolshed::Git::Base.branch_name_from_id(options[:branch_name]) : Toolshed::Git::Base.branch_name
|
63
|
+
force_command = (options.has_key?(:force_command)) ? '--force' : ''
|
64
|
+
|
65
|
+
until system("git push #{Toolshed::Client.push_to_remote_name} #{branch_name} #{force_command}")
|
66
|
+
sleep 1
|
67
|
+
end
|
68
|
+
|
69
|
+
branch_name
|
70
|
+
end
|
71
|
+
|
72
|
+
class GitValidator
|
73
|
+
include Veto.validator
|
74
|
+
|
75
|
+
validates :from_remote_name, :presence => true
|
76
|
+
validates :from_remote_branch_name, :presence => true
|
77
|
+
validates :to_remote_name, :presence => true
|
78
|
+
validates :to_remote_branch_name, :presence => true
|
79
|
+
end
|
80
|
+
|
81
|
+
class Base
|
82
|
+
extend Toolshed::Git
|
83
|
+
|
84
|
+
attr_accessor :from_remote_name, :from_remote_branch_name, :to_remote_name, :to_remote_branch_name, :validator
|
85
|
+
|
86
|
+
def initialize(options={})
|
87
|
+
# options with defaults
|
88
|
+
self.from_remote_name = Toolshed::Client.pull_from_remote_name
|
89
|
+
unless (options[:from_remote_name].nil?)
|
90
|
+
self.from_remote_name = options[:from_remote_name]
|
91
|
+
end
|
92
|
+
|
93
|
+
self.to_remote_name = Toolshed::Client.push_to_remote_name
|
94
|
+
unless (options[:to_remote_name].nil?)
|
95
|
+
self.to_remote_name = options[:to_remote_name]
|
96
|
+
end
|
97
|
+
|
98
|
+
# options that do not have a default
|
99
|
+
unless (options[:from_remote_branch_name].nil?)
|
100
|
+
self.from_remote_branch_name = options[:from_remote_branch_name]
|
101
|
+
end
|
102
|
+
|
103
|
+
unless (options[:to_remote_branch_name].nil?)
|
104
|
+
self.to_remote_branch_name = options[:to_remote_branch_name]
|
105
|
+
end
|
106
|
+
|
107
|
+
self.validator = ::Toolshed::Git::GitValidator.new
|
108
|
+
end
|
109
|
+
|
110
|
+
def create_branch
|
111
|
+
self.validator.validate!(self)
|
112
|
+
|
113
|
+
new_branch_name = Toolshed::Git::Base.clean_branch_name(self.to_remote_branch_name)
|
114
|
+
until system("git remote update #{Toolshed::Client.git_quiet}")
|
115
|
+
sleep 1
|
116
|
+
end
|
117
|
+
|
118
|
+
until system("git checkout -b #{new_branch_name} #{self.from_remote_name}/#{self.from_remote_branch_name} #{Toolshed::Client.git_quiet}")
|
119
|
+
sleep 1
|
120
|
+
end
|
121
|
+
|
122
|
+
unless (Toolshed::Git::Base.git_submodule_command.empty?)
|
123
|
+
until system(Toolshed::Git::Base.git_submodule_command)
|
124
|
+
sleep 1
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
until system("git push #{self.to_remote_name} #{new_branch_name} #{Toolshed::Client.git_quiet}")
|
129
|
+
sleep 1
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Toolshed
|
2
|
+
module Git
|
3
|
+
class Github < Base
|
4
|
+
extend Toolshed::Git
|
5
|
+
include HTTParty
|
6
|
+
|
7
|
+
attr_accessor :default_options
|
8
|
+
|
9
|
+
def initialize(options={})
|
10
|
+
super(options)
|
11
|
+
|
12
|
+
username = Toolshed::Client::github_username
|
13
|
+
password = Toolshed::Client::github_password
|
14
|
+
|
15
|
+
unless (options[:username].nil?)
|
16
|
+
username = options[:username]
|
17
|
+
end
|
18
|
+
|
19
|
+
unless (options[:password].nil?)
|
20
|
+
password = options[:password]
|
21
|
+
end
|
22
|
+
|
23
|
+
@auth = { username: username, password: password }
|
24
|
+
self.default_options = {
|
25
|
+
:headers => {
|
26
|
+
"User-Agent" => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1309.0 Safari/537.17"
|
27
|
+
},
|
28
|
+
basic_auth: @auth,
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_pull_request(title, body, options={})
|
33
|
+
options.merge!(self.default_options)
|
34
|
+
options.merge!({
|
35
|
+
body: {
|
36
|
+
title: title,
|
37
|
+
body: body,
|
38
|
+
head: "#{Toolshed::Client.github_username}:#{Toolshed::Git::Base.branch_name}",
|
39
|
+
base: Toolshed::Git::Base.branched_from
|
40
|
+
}.to_json
|
41
|
+
})
|
42
|
+
|
43
|
+
response = HTTParty.post("#{Toolshed::Client::GITHUB_BASE_API_URL}repos/#{Toolshed::Client.pull_from_repository_user}/#{Toolshed::Client.pull_from_repository_name}/pulls", options).response
|
44
|
+
response = JSON.parse(response.body)
|
45
|
+
if (response["errors"].nil?)
|
46
|
+
response
|
47
|
+
else
|
48
|
+
raise "validation errors #{response.inspect}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def list_branches(options={})
|
53
|
+
options.merge!(self.default_options)
|
54
|
+
|
55
|
+
response = HTTParty.get("#{Toolshed::Client::GITHUB_BASE_API_URL}repos/#{Toolshed::Client.github_username}/#{Toolshed::Client.pull_from_repository_name}/branches", options).response
|
56
|
+
response = JSON.parse(response.body)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.username
|
60
|
+
username = Toolshed::Client::github_username
|
61
|
+
if (username.nil?)
|
62
|
+
# prompt to ask for username
|
63
|
+
puts "Github username? "
|
64
|
+
username = $stdin.gets.chomp.strip
|
65
|
+
end
|
66
|
+
|
67
|
+
return username
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.password
|
71
|
+
password = Toolshed::Client::github_password
|
72
|
+
if (password.nil?)
|
73
|
+
# prompt to ask for password
|
74
|
+
system "stty -echo"
|
75
|
+
puts "Github password? "
|
76
|
+
password = $stdin.gets.chomp.strip
|
77
|
+
system "stty echo"
|
78
|
+
end
|
79
|
+
|
80
|
+
return password
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.create_instance
|
84
|
+
Toolshed::Git::Github.new({ username: Toolshed::Git::Github.username, password: Toolshed::Git::Github.password })
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Toolshed
|
2
|
+
module TicketTracking
|
3
|
+
class PivotalTracker
|
4
|
+
extend TicketTracking
|
5
|
+
include HTTParty
|
6
|
+
|
7
|
+
DEFAULT_COMPLETED_STATUS = 'finished'
|
8
|
+
USE_PROJECT_ID = true
|
9
|
+
|
10
|
+
attr_accessor :project_id, :token
|
11
|
+
|
12
|
+
def initialize(options={})
|
13
|
+
username = Toolshed::Client::pivotal_tracker_username
|
14
|
+
password = Toolshed::Client::pivotal_tracker_password
|
15
|
+
|
16
|
+
unless (options[:username].nil?)
|
17
|
+
username = options[:username]
|
18
|
+
end
|
19
|
+
|
20
|
+
unless (options[:password].nil?)
|
21
|
+
password = options[:password]
|
22
|
+
end
|
23
|
+
|
24
|
+
self.token = ::PivotalTracker::Client.token(username, password)
|
25
|
+
|
26
|
+
self.project_id = (options[:project_id].nil?) ? Toolshed::Client.default_pivotal_tracker_project_id : options[:project_id]
|
27
|
+
@pt_project = ::PivotalTracker::Project.find(self.project_id)
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# Instance methods
|
32
|
+
#
|
33
|
+
def story_information(story_id)
|
34
|
+
return @pt_project.stories.find(story_id)
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_note(story_id, note_text)
|
38
|
+
story = @pt_project.stories.find(story_id)
|
39
|
+
results = story.notes.create(text: note_text)
|
40
|
+
end
|
41
|
+
|
42
|
+
def update_ticket_status(story_id, current_state, options={})
|
43
|
+
options.merge!({
|
44
|
+
:headers => {
|
45
|
+
"X-TrackerToken" => self.token,
|
46
|
+
"User-Agent" => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1309.0 Safari/537.17",
|
47
|
+
"Content-Type" => "application/json",
|
48
|
+
},
|
49
|
+
body: {
|
50
|
+
current_state: current_state
|
51
|
+
}.to_json
|
52
|
+
})
|
53
|
+
|
54
|
+
response = HTTParty.put("#{Toolshed::Client::PIVOTAL_TRACKER_BASE_API_URL}projects/#{self.project_id}/stories/#{story_id}", options).response
|
55
|
+
response = JSON.parse(response.body)
|
56
|
+
|
57
|
+
if (response["error"].nil?)
|
58
|
+
response
|
59
|
+
else
|
60
|
+
raise "validation errors #{response.inspect}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Class methods
|
66
|
+
#
|
67
|
+
def self.story_id_from_branch_name(branch_name)
|
68
|
+
story_id = branch_name.split("_")[0]
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.username
|
72
|
+
username = Toolshed::Client::pivotal_tracker_username
|
73
|
+
if (username.nil?)
|
74
|
+
# prompt to ask for username
|
75
|
+
puts "PivotalTracker username? "
|
76
|
+
username = $stdin.gets.chomp.strip
|
77
|
+
end
|
78
|
+
|
79
|
+
return username
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.password
|
83
|
+
password = Toolshed::Client::pivotal_tracker_password
|
84
|
+
if (password.nil?)
|
85
|
+
# prompt to ask for password
|
86
|
+
system "stty -echo"
|
87
|
+
puts "PivotalTracker password? "
|
88
|
+
password = $stdin.gets.chomp.strip
|
89
|
+
system "stty echo"
|
90
|
+
end
|
91
|
+
|
92
|
+
return password
|
93
|
+
end
|
94
|
+
|
95
|
+
#
|
96
|
+
# Get the pivotal tracker object based off of the project_id
|
97
|
+
#
|
98
|
+
def self.create_instance(options={})
|
99
|
+
unless (options.has_key?(:project_id))
|
100
|
+
raise 'Unable to use PivotalTracker as project id was not supplied'
|
101
|
+
end
|
102
|
+
|
103
|
+
pivotal_tracker = Toolshed::TicketTracking::PivotalTracker.new({ project_id: options[:project_id], username: Toolshed::TicketTracking::PivotalTracker.username, password: Toolshed::TicketTracking::PivotalTracker.password })
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.clean(title)
|
107
|
+
title.gsub("'", "").gsub("\"", "")
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Toolshed
|
2
|
+
module TimeTracking
|
3
|
+
class Harvest
|
4
|
+
extend TimeTracking
|
5
|
+
|
6
|
+
MAX_ATTEMPTS = 10
|
7
|
+
|
8
|
+
attr_accessor :harvest_client, :project_id
|
9
|
+
|
10
|
+
def initialize(options={})
|
11
|
+
username = Toolshed::Client::time_tracking_username
|
12
|
+
password = Toolshed::Client::time_tracking_password
|
13
|
+
owner = Toolshed::Client.time_tracking_owner
|
14
|
+
|
15
|
+
unless (options[:username].nil?)
|
16
|
+
username = options[:username]
|
17
|
+
end
|
18
|
+
|
19
|
+
unless (options[:password].nil?)
|
20
|
+
password = options[:password]
|
21
|
+
end
|
22
|
+
|
23
|
+
unless (options[:sub_domain].nil?)
|
24
|
+
owner = options[:sub_domain]
|
25
|
+
end
|
26
|
+
|
27
|
+
self.harvest_client = ::Harvest.client('ackmanndickenson', 'jwaller@ackmanndickenson.com', 'V0AU2gRMLhs1')
|
28
|
+
self.project_id = self.get_project_id
|
29
|
+
end
|
30
|
+
|
31
|
+
def previous(days_ago=1)
|
32
|
+
notes = "Previous:\n\n"
|
33
|
+
|
34
|
+
time_entries = self.harvest_client.time.all((DateTime.now - days_ago), self.project_id)
|
35
|
+
if (time_entries.size > 0 || days_ago == Toolshed::TimeTracking::Harvest::MAX_ATTEMPTS)
|
36
|
+
time_entries.each do |time_entry|
|
37
|
+
notes = "#{notes}#{time_entry.notes}\n"
|
38
|
+
end
|
39
|
+
else
|
40
|
+
notes = self.previous(days_ago + 1)
|
41
|
+
end
|
42
|
+
|
43
|
+
notes
|
44
|
+
end
|
45
|
+
|
46
|
+
def today
|
47
|
+
notes = "Today:\n\n"
|
48
|
+
|
49
|
+
time_entries = self.harvest_client.time.all(Time.now, self.project_id)
|
50
|
+
time_entries.each do |time_entry|
|
51
|
+
notes = "#{notes}#{time_entry.notes}\n"
|
52
|
+
end
|
53
|
+
|
54
|
+
notes
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_project_id
|
58
|
+
print "Project ID (Default: #{Toolshed::Client.time_tracking_default_project_id})? "
|
59
|
+
project_id = $stdin.gets.chomp.strip
|
60
|
+
if (project_id == '')
|
61
|
+
project_id = Toolshed::Client.time_tracking_default_project_id
|
62
|
+
end
|
63
|
+
|
64
|
+
project_id
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/toolshed/version.rb
CHANGED