caperoma 0.1.0 → 4.0.1
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 +5 -5
- data/.ruby-version +1 -0
- data/Capefile +48 -0
- data/Capefile.template +48 -0
- data/Capefile.test +20 -0
- data/Gemfile +25 -10
- data/Gemfile.lock +196 -77
- data/HELP +321 -0
- data/README.md +528 -0
- data/Rakefile +73 -18
- data/VERSION +1 -1
- data/bin/caperoma +47 -11
- data/caperoma.gemspec +144 -45
- data/config/crontab +10 -0
- data/config/schedule.rb +21 -0
- data/lib/caperoma.rb +409 -9
- data/lib/caperoma/models/account.rb +47 -0
- data/lib/caperoma/models/application_record.rb +5 -0
- data/lib/caperoma/models/branch.rb +6 -0
- data/lib/caperoma/models/project.rb +14 -0
- data/lib/caperoma/models/property.rb +5 -0
- data/lib/caperoma/models/report.rb +177 -0
- data/lib/caperoma/models/report_recipient.rb +6 -0
- data/lib/caperoma/models/reports/daily_report.rb +23 -0
- data/lib/caperoma/models/reports/retrospective_report.rb +19 -0
- data/lib/caperoma/models/reports/three_day_report.rb +19 -0
- data/lib/caperoma/models/task.rb +368 -0
- data/lib/caperoma/models/tasks/bug.rb +36 -0
- data/lib/caperoma/models/tasks/chore.rb +40 -0
- data/lib/caperoma/models/tasks/feature.rb +27 -0
- data/lib/caperoma/models/tasks/fix.rb +56 -0
- data/lib/caperoma/models/tasks/meeting.rb +40 -0
- data/lib/caperoma/models/tasks/modules/git.rb +65 -0
- data/lib/caperoma/models/tasks/task_with_commit.rb +40 -0
- data/lib/caperoma/models/tasks/task_with_separate_branch.rb +42 -0
- data/lib/caperoma/services/airbrake_email_processor.rb +47 -0
- data/lib/caperoma/services/pivotal_fetcher.rb +108 -0
- data/lib/caperoma/version.rb +9 -0
- data/spec/caperoma_spec.rb +3 -21
- data/spec/factories/accounts.rb +10 -0
- data/spec/factories/branches.rb +9 -0
- data/spec/factories/projects.rb +8 -0
- data/spec/factories/report_recipients.rb +7 -0
- data/spec/factories/reports.rb +16 -0
- data/spec/factories/tasks.rb +37 -0
- data/spec/features/bug_spec.rb +60 -0
- data/spec/features/chore_spec.rb +60 -0
- data/spec/features/command_unknown_spec.rb +14 -0
- data/spec/features/config_spec.rb +161 -0
- data/spec/features/feature_spec.rb +60 -0
- data/spec/features/finish_spec.rb +18 -0
- data/spec/features/fix_spec.rb +60 -0
- data/spec/features/meeting_spec.rb +22 -0
- data/spec/features/projects_spec.rb +17 -0
- data/spec/features/report_recipientss_spec.rb +117 -0
- data/spec/features/reports_spec.rb +65 -0
- data/spec/features/status_spec.rb +33 -0
- data/spec/features/version_spec.rb +11 -0
- data/spec/models/account_spec.rb +51 -0
- data/spec/models/branch_spec.rb +8 -0
- data/spec/models/bug_spec.rb +33 -0
- data/spec/models/chore_spec.rb +33 -0
- data/spec/models/daily_report_spec.rb +38 -0
- data/spec/models/feature_spec.rb +33 -0
- data/spec/models/fix_spec.rb +55 -0
- data/spec/models/meeting_spec.rb +33 -0
- data/spec/models/project_spec.rb +11 -0
- data/spec/models/report_recipient_spec.rb +22 -0
- data/spec/models/report_spec.rb +16 -0
- data/spec/models/retrospective_report_spec.rb +38 -0
- data/spec/models/task_spec.rb +613 -0
- data/spec/models/task_with_commit_spec.rb +105 -0
- data/spec/models/task_with_separate_branch_spec.rb +97 -0
- data/spec/models/three_day_report_spec.rb +49 -0
- data/spec/spec_helper.rb +26 -16
- data/spec/support/capefile_generator.rb +36 -0
- data/spec/support/database_cleaner.rb +21 -0
- data/spec/support/stubs.rb +178 -9
- metadata +283 -42
- data/.document +0 -5
- data/README.rdoc +0 -26
- data/lib/caperoma/credentials.rb +0 -13
- data/lib/caperoma/jira_client.rb +0 -57
- data/spec/caperoma/credentials_spec.rb +0 -25
- data/spec/caperoma/jira_spec.rb +0 -35
@@ -0,0 +1,177 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Report < ApplicationRecord
|
4
|
+
include ActionView::Helpers::TextHelper
|
5
|
+
has_many :tasks
|
6
|
+
|
7
|
+
after_initialize :set_variables
|
8
|
+
|
9
|
+
after_create :assign_unreported_tasks
|
10
|
+
after_create :send_email, if: :not_test?
|
11
|
+
after_create :update_content
|
12
|
+
|
13
|
+
def self.schedule
|
14
|
+
# may screw up existing cron tasks
|
15
|
+
puts 'Turning on auto reports'
|
16
|
+
root = File.dirname __dir__
|
17
|
+
crontab_file = File.join root, 'config', 'crontab'
|
18
|
+
`crontab #{crontab_file}`
|
19
|
+
# > whenever --update-crontab caperoma
|
20
|
+
puts 'Auto reports turned on'
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.unschedule
|
24
|
+
puts 'Turning off auto reports'
|
25
|
+
puts 'pending'
|
26
|
+
puts 'Auto reports turned off'
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def set_variables
|
32
|
+
@smtp = Net::SMTP.new 'smtp.gmail.com', 587
|
33
|
+
@smtp.enable_starttls
|
34
|
+
@account = Account.gmail
|
35
|
+
end
|
36
|
+
|
37
|
+
# most of it is related to email formatting
|
38
|
+
|
39
|
+
def assign_unreported_tasks
|
40
|
+
unreported_tasks.update_all(report_sti_key => id)
|
41
|
+
end
|
42
|
+
|
43
|
+
def send_email
|
44
|
+
@smtp.start('gmail.com', @account.email, @account.password, :login, &send_email_method)
|
45
|
+
end
|
46
|
+
|
47
|
+
def send_email_method
|
48
|
+
proc { @smtp.send_message(report_msg, @account.email, to_addresses) }
|
49
|
+
end
|
50
|
+
|
51
|
+
def unreported_tasks
|
52
|
+
Task.finished.where(report_sti_key => nil)
|
53
|
+
end
|
54
|
+
|
55
|
+
def report_sti_key
|
56
|
+
self.class.to_s.foreign_key
|
57
|
+
end
|
58
|
+
|
59
|
+
def update_content
|
60
|
+
update content: report_msg
|
61
|
+
end
|
62
|
+
|
63
|
+
def reported_tasks
|
64
|
+
tasks.finished.order(finished_at: :desc)
|
65
|
+
end
|
66
|
+
|
67
|
+
def total_time_spent
|
68
|
+
"#{hours_spent}h #{remaining_minutes_spent}m"
|
69
|
+
end
|
70
|
+
|
71
|
+
def hours_spent
|
72
|
+
(total_time_spent_in_minutes / 60).to_i
|
73
|
+
end
|
74
|
+
|
75
|
+
def remaining_minutes_spent
|
76
|
+
(total_time_spent_in_minutes - hours_spent * 60).to_i
|
77
|
+
end
|
78
|
+
|
79
|
+
def total_time_spent_in_minutes
|
80
|
+
reported_tasks.all.collect(&:time_spent_in_minutes).sum
|
81
|
+
end
|
82
|
+
|
83
|
+
def not_test?
|
84
|
+
ENV['CAPEROMA_INTEGRATION_TEST'].blank? && ENV['CAPEROMA_TEST'].blank?
|
85
|
+
end
|
86
|
+
|
87
|
+
def to_addresses
|
88
|
+
ReportRecipient.all.collect(&:email)
|
89
|
+
end
|
90
|
+
|
91
|
+
def report_msg
|
92
|
+
report_msg_content.join("\n")
|
93
|
+
end
|
94
|
+
|
95
|
+
def report_msg_content
|
96
|
+
["subject: #{report_subject}", 'Content-Type: text/html; charset=UTF-8', report_body]
|
97
|
+
end
|
98
|
+
|
99
|
+
def formatted_day(day)
|
100
|
+
day.strftime('%b %-d')
|
101
|
+
end
|
102
|
+
|
103
|
+
def formatted_start_day
|
104
|
+
formatted_day(start_day)
|
105
|
+
end
|
106
|
+
|
107
|
+
def formatted_end_day
|
108
|
+
formatted_day(end_day)
|
109
|
+
end
|
110
|
+
|
111
|
+
def timeframe
|
112
|
+
[formatted_start_day, formatted_end_day].join(' - ')
|
113
|
+
end
|
114
|
+
|
115
|
+
def report_subject
|
116
|
+
[subject_name, subject_timeframe].join(' ')
|
117
|
+
end
|
118
|
+
|
119
|
+
def subject_timeframe
|
120
|
+
"(#{timeframe})"
|
121
|
+
end
|
122
|
+
|
123
|
+
def report_body
|
124
|
+
[
|
125
|
+
"\n",
|
126
|
+
"<h2>Done during #{timeframe}:</h2>",
|
127
|
+
"<br />",
|
128
|
+
"<table style=\"width: 100%;text-align: left;\">",
|
129
|
+
"<thead>",
|
130
|
+
"<tr><th>Jira</th><th>Pivotal</th><th>Title</th><th>Time spent</th></tr>",
|
131
|
+
"</thead>",
|
132
|
+
"<tbody>",
|
133
|
+
reported_tasks_rows,
|
134
|
+
"</tbody>",
|
135
|
+
"</table>",
|
136
|
+
"<br />",
|
137
|
+
"<strong>Total time spent during #{timeframe}:</strong> #{total_time_spent}."
|
138
|
+
].flatten.join("\n")
|
139
|
+
end
|
140
|
+
|
141
|
+
def reported_tasks_rows
|
142
|
+
reported_tasks.collect { |task| table_row(task) }.join("\n")
|
143
|
+
end
|
144
|
+
|
145
|
+
def table_row(task)
|
146
|
+
'<tr>' + task_row_data(task).collect{|task| '<td>' + task + '</td>' }.join("\n") + '</tr>'
|
147
|
+
end
|
148
|
+
|
149
|
+
def task_row_data(task)
|
150
|
+
[
|
151
|
+
jira_url_or_blank(task),
|
152
|
+
pivotal_url_or_blank(task),
|
153
|
+
formatted_title(task),
|
154
|
+
task.time_spent
|
155
|
+
]
|
156
|
+
end
|
157
|
+
|
158
|
+
def formatted_title(task)
|
159
|
+
truncate(task.title, length: 90)
|
160
|
+
end
|
161
|
+
|
162
|
+
def jira_url_or_blank(task)
|
163
|
+
task.jira_key.present? ? jira_formatted_url(task) : ''
|
164
|
+
end
|
165
|
+
|
166
|
+
def jira_formatted_url(task)
|
167
|
+
"<a href=\"#{task.jira_live_url}\">#{task.jira_key}</a>"
|
168
|
+
end
|
169
|
+
|
170
|
+
def pivotal_url_or_blank(task)
|
171
|
+
task.pivotal_id.present? ? pivotal_formatted_url(task) : ''
|
172
|
+
end
|
173
|
+
|
174
|
+
def pivotal_formatted_url(task)
|
175
|
+
"<a href=\"#{task.pivotal_url}\">#{task.pivotal_id}</a>"
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class DailyReport < Report
|
4
|
+
has_many :tasks
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def subject_name
|
9
|
+
'Daily Report'
|
10
|
+
end
|
11
|
+
|
12
|
+
def body_heading
|
13
|
+
'Today'
|
14
|
+
end
|
15
|
+
|
16
|
+
def timeframe
|
17
|
+
formatted_day(start_day)
|
18
|
+
end
|
19
|
+
|
20
|
+
def start_day
|
21
|
+
Date.today
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class RetrospectiveReport < Report
|
4
|
+
has_many :tasks
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def subject_name
|
9
|
+
'Weekly Report'
|
10
|
+
end
|
11
|
+
|
12
|
+
def start_day
|
13
|
+
Date.today.beginning_of_week
|
14
|
+
end
|
15
|
+
|
16
|
+
def end_day
|
17
|
+
Date.today
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,368 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class Task < ActiveRecord::Base
|
3
|
+
include Git
|
4
|
+
|
5
|
+
belongs_to :project
|
6
|
+
belongs_to :daily_report
|
7
|
+
belongs_to :three_day_report
|
8
|
+
belongs_to :retrospective_report
|
9
|
+
|
10
|
+
validates :title, presence: true
|
11
|
+
validates :pivotal_id, length: { minimum: 6 }, allow_blank: true, numericality: { only_integer: true }
|
12
|
+
|
13
|
+
before_create :generate_uuid
|
14
|
+
before_create :set_start_time
|
15
|
+
|
16
|
+
after_create :create_issue_on_jira, if: :create_on_jira?
|
17
|
+
after_create :start_issue_on_jira, if: :start_on_jira?
|
18
|
+
after_create :create_issue_on_pivotal, if: :create_on_pivotal?
|
19
|
+
after_create :start_issue_on_pivotal, if: :start_on_pivotal?
|
20
|
+
after_save :output_jira_key, if: :output_jira_key?
|
21
|
+
|
22
|
+
scope :unfinished, -> { where(finished_at: nil) }
|
23
|
+
scope :finished, -> { where.not(finished_at: nil) }
|
24
|
+
|
25
|
+
def self.finish_started(comment)
|
26
|
+
puts 'Finishing current task'
|
27
|
+
unfinished.each { |task| task.finish(comment) }
|
28
|
+
puts 'Current task finished'
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.pause_started(comment)
|
32
|
+
puts 'Pausing current task'
|
33
|
+
unfinished.each { |task| task.pause(comment) }
|
34
|
+
puts 'Current task paused'
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.abort_started(comment)
|
38
|
+
puts 'Aborting current task'
|
39
|
+
unfinished.each { |task| task.abort(comment) }
|
40
|
+
puts 'Current task aborted'
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.abort_started_without_time(comment)
|
44
|
+
puts 'Aborting current task without putting time into Jira'
|
45
|
+
unfinished.each { |task| task.abort_without_time(comment) }
|
46
|
+
puts 'Current task aborted without putting time into Jira'
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.status
|
50
|
+
if unfinished.length == 0
|
51
|
+
puts "You are not working on anything now."
|
52
|
+
else
|
53
|
+
unfinished.each do |task|
|
54
|
+
puts "You are working on: "
|
55
|
+
puts "Title: #{task.title}"
|
56
|
+
puts "Type: #{task.type}"
|
57
|
+
puts "Jira ID: #{task.jira_key}." if task.jira_key.present?
|
58
|
+
puts "Pivotal ID: #{task.pivotal_id} (#{task.pivotal_url})" if task.pivotal_id.present?
|
59
|
+
puts "Time spent at the moment: #{task.time_spent_so_far}"
|
60
|
+
puts "Pull request will be sent to this branch: #{task.parent_branch}" if task.parent_branch.present?
|
61
|
+
puts "Project location: #{task.project.folder_path}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
attr_writer :additional_time
|
67
|
+
|
68
|
+
def finish(comment)
|
69
|
+
# full pull request
|
70
|
+
update_attribute(:finished_at, Time.now)
|
71
|
+
close_issue_on_jira
|
72
|
+
log_work_to_jira(comment)
|
73
|
+
finish_on_pivotal if pivotal_id.present?
|
74
|
+
puts time_spent
|
75
|
+
end
|
76
|
+
|
77
|
+
def pause(comment = 'Done')
|
78
|
+
# finish with commit & push but without pull request
|
79
|
+
update_attribute(:finished_at, Time.now)
|
80
|
+
close_issue_on_jira
|
81
|
+
log_work_to_jira(comment)
|
82
|
+
finish_on_pivotal if pivotal_id.present?
|
83
|
+
puts time_spent
|
84
|
+
end
|
85
|
+
|
86
|
+
def abort(comment)
|
87
|
+
# finish without commit or push
|
88
|
+
update_attribute(:finished_at, Time.now)
|
89
|
+
close_issue_on_jira
|
90
|
+
log_work_to_jira(comment)
|
91
|
+
finish_on_pivotal if pivotal_id.present?
|
92
|
+
puts time_spent
|
93
|
+
end
|
94
|
+
|
95
|
+
def abort_without_time(comment)
|
96
|
+
# finish without commit or push
|
97
|
+
update_attribute(:finished_at, Time.now)
|
98
|
+
close_issue_on_jira
|
99
|
+
# the task closes on Jira, but is still running in Pivotal
|
100
|
+
puts time_spent
|
101
|
+
end
|
102
|
+
|
103
|
+
def time_spent_so_far
|
104
|
+
result = TimeDifference.between(started_at, Time.now).in_minutes
|
105
|
+
|
106
|
+
hours = (result / 60).to_i
|
107
|
+
minutes = (result - hours * 60).to_i
|
108
|
+
|
109
|
+
"#{hours}h #{minutes}m"
|
110
|
+
end
|
111
|
+
|
112
|
+
def time_spent
|
113
|
+
result = TimeDifference.between(started_at, finished_at).in_minutes
|
114
|
+
|
115
|
+
hours = (result / 60).to_i
|
116
|
+
minutes = (result - hours * 60).to_i
|
117
|
+
|
118
|
+
"#{hours}h #{minutes}m"
|
119
|
+
end
|
120
|
+
|
121
|
+
def pivotal_url
|
122
|
+
"https://www.pivotaltracker.com/story/show/#{pivotal_id}" if pivotal_id.present?
|
123
|
+
end
|
124
|
+
|
125
|
+
def jira_live_url
|
126
|
+
"#{project.jira_url}browse/#{jira_key}" if jira_key.present?
|
127
|
+
end
|
128
|
+
|
129
|
+
def time_spent_in_minutes
|
130
|
+
TimeDifference.between(started_at, finished_at).in_minutes # TODO: test
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def story_type
|
136
|
+
'chore' # default is chore, it's never used directly
|
137
|
+
end
|
138
|
+
|
139
|
+
def create_on_jira?
|
140
|
+
Account.jira.present? && ENV['CAPEROMA_INTEGRATION_TEST'].blank?
|
141
|
+
end
|
142
|
+
|
143
|
+
def start_on_jira?
|
144
|
+
jira_key.present? && Account.jira.present? && ENV['CAPEROMA_INTEGRATION_TEST'].blank?
|
145
|
+
end
|
146
|
+
|
147
|
+
def create_on_pivotal?
|
148
|
+
pivotal_id.blank? && this_is_a_type_a_user_wants_to_create? && Account.pivotal.present? && ENV['CAPEROMA_INTEGRATION_TEST'].blank?
|
149
|
+
end
|
150
|
+
|
151
|
+
def start_on_pivotal?
|
152
|
+
pivotal_id.present? && Account.pivotal.present? && ENV['CAPEROMA_INTEGRATION_TEST'].blank?
|
153
|
+
end
|
154
|
+
|
155
|
+
def this_is_a_type_a_user_wants_to_create?
|
156
|
+
false
|
157
|
+
end
|
158
|
+
|
159
|
+
def generate_uuid
|
160
|
+
self.uuid = SecureRandom.uuid
|
161
|
+
end
|
162
|
+
|
163
|
+
def set_start_time
|
164
|
+
time = Time.now
|
165
|
+
time -= @additional_time.to_i.minutes if @additional_time.present?
|
166
|
+
self.started_at = time
|
167
|
+
end
|
168
|
+
|
169
|
+
def output_jira_key
|
170
|
+
puts jira_key
|
171
|
+
end
|
172
|
+
|
173
|
+
def output_jira_key?
|
174
|
+
jira_key.present? && ENV['CAPEROMA_INTEGRATION_TEST'].blank?
|
175
|
+
end
|
176
|
+
|
177
|
+
def start_issue_on_pivotal_data
|
178
|
+
Jbuilder.encode do |j|
|
179
|
+
j.current_state 'started'
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def start_issue_on_pivotal
|
184
|
+
if not_test?
|
185
|
+
conn = Faraday.new(url: 'https://www.pivotaltracker.com/') do |c|
|
186
|
+
c.adapter Faraday.default_adapter
|
187
|
+
end
|
188
|
+
|
189
|
+
response = conn.put do |request|
|
190
|
+
request.url "services/v5/stories/#{pivotal_id}"
|
191
|
+
request.body = start_issue_on_pivotal_data
|
192
|
+
request.headers['User-Agent'] = 'Caperoma'
|
193
|
+
request.headers['Content-Type'] = 'application/json'
|
194
|
+
request.headers['X-TrackerToken'] = Account.pivotal.password
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def finish_on_pivotal_data
|
200
|
+
Jbuilder.encode do |j|
|
201
|
+
j.current_state 'finished'
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def finish_on_pivotal
|
206
|
+
if not_test?
|
207
|
+
conn = Faraday.new(url: 'https://www.pivotaltracker.com/') do |c|
|
208
|
+
c.adapter Faraday.default_adapter
|
209
|
+
end
|
210
|
+
|
211
|
+
response = conn.put do |request|
|
212
|
+
request.url "services/v5/stories/#{pivotal_id}"
|
213
|
+
request.body = finish_on_pivotal_data
|
214
|
+
request.headers['User-Agent'] = 'Caperoma'
|
215
|
+
request.headers['Content-Type'] = 'application/json'
|
216
|
+
request.headers['X-TrackerToken'] = Account.pivotal.password
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def start_issue_on_jira_data
|
222
|
+
Jbuilder.encode do |j|
|
223
|
+
j.transition { j.id project.jira_transition_id_in_progress }
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def start_issue_on_jira
|
228
|
+
if not_test?
|
229
|
+
conn = Faraday.new(url: project.jira_url) do |c|
|
230
|
+
c.basic_auth(Account.jira.email, Account.jira.password)
|
231
|
+
c.adapter Faraday.default_adapter
|
232
|
+
end
|
233
|
+
|
234
|
+
conn.post do |request|
|
235
|
+
request.url "rest/api/3/issue/#{jira_key}/transitions"
|
236
|
+
request.body = start_issue_on_jira_data
|
237
|
+
request.headers['User-Agent'] = 'Caperoma'
|
238
|
+
request.headers['Content-Type'] = 'application/json'
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def close_issue_on_jira_data
|
244
|
+
Jbuilder.encode do |j|
|
245
|
+
j.transition { j.id project.jira_transition_id_done }
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def close_issue_on_jira
|
250
|
+
if not_test?
|
251
|
+
conn = Faraday.new(url: project.jira_url) do |c|
|
252
|
+
c.basic_auth(Account.jira.email, Account.jira.password)
|
253
|
+
c.adapter Faraday.default_adapter
|
254
|
+
end
|
255
|
+
|
256
|
+
response = conn.post do |request|
|
257
|
+
request.url "rest/api/3/issue/#{jira_key}/transitions"
|
258
|
+
request.body = close_issue_on_jira_data
|
259
|
+
request.headers['User-Agent'] = 'Caperoma'
|
260
|
+
request.headers['Content-Type'] = 'application/json'
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def log_work_to_jira_data(comment = 'Done')
|
266
|
+
Jbuilder.encode do |j|
|
267
|
+
j.comment comment
|
268
|
+
j.started current_time
|
269
|
+
j.timeSpent time_spent
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def log_work_to_jira(comment = 'Done')
|
274
|
+
if not_test?
|
275
|
+
conn = Faraday.new(url: project.jira_url) do |c|
|
276
|
+
c.basic_auth(Account.jira.email, Account.jira.password)
|
277
|
+
c.adapter Faraday.default_adapter
|
278
|
+
end
|
279
|
+
|
280
|
+
result = conn.post do |request|
|
281
|
+
request.url "rest/api/3/issue/#{jira_key}/worklog"
|
282
|
+
request.body = log_work_to_jira_data(comment)
|
283
|
+
request.headers['User-Agent'] = 'Caperoma'
|
284
|
+
request.headers['Content-Type'] = 'application/json'
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
def current_time
|
290
|
+
Time.now.in_time_zone('UTC').strftime('%Y-%m-%dT%H:%M:00.000+0000')
|
291
|
+
end
|
292
|
+
|
293
|
+
def issue_type
|
294
|
+
project.feature_jira_task_id
|
295
|
+
end
|
296
|
+
|
297
|
+
def create_issue_on_pivotal_data
|
298
|
+
Jbuilder.encode do |j|
|
299
|
+
j.current_state 'unstarted'
|
300
|
+
j.estimate 1
|
301
|
+
j.name title.to_s
|
302
|
+
j.story_type story_type
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def create_issue_on_pivotal
|
307
|
+
if not_test?
|
308
|
+
conn = Faraday.new(url: 'https://www.pivotaltracker.com/') do |c|
|
309
|
+
c.adapter Faraday.default_adapter
|
310
|
+
end
|
311
|
+
|
312
|
+
response = conn.post do |request|
|
313
|
+
request.url "services/v5/projects/#{project.pivotal_tracker_project_id}/stories"
|
314
|
+
request.body = create_issue_on_pivotal_data
|
315
|
+
request.headers['User-Agent'] = 'Caperoma'
|
316
|
+
request.headers['Content-Type'] = 'application/json'
|
317
|
+
request.headers['X-TrackerToken'] = Account.pivotal.password
|
318
|
+
end
|
319
|
+
|
320
|
+
result = JSON.parse response.body
|
321
|
+
|
322
|
+
update_attributes(
|
323
|
+
pivotal_id: result['id']
|
324
|
+
)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def create_issue_on_jira_data
|
329
|
+
Jbuilder.encode do |j|
|
330
|
+
j.fields do
|
331
|
+
j.project { j.id project.jira_project_id.to_s }
|
332
|
+
j.issuetype { j.id issue_type }
|
333
|
+
j.summary title.to_s
|
334
|
+
j.assignee do
|
335
|
+
j.name Account.jira.username
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
def create_issue_on_jira
|
342
|
+
if not_test?
|
343
|
+
conn = Faraday.new(url: project.jira_url) do |c|
|
344
|
+
c.basic_auth(Account.jira.email, Account.jira.password)
|
345
|
+
c.adapter Faraday.default_adapter
|
346
|
+
end
|
347
|
+
|
348
|
+
response = conn.post do |request|
|
349
|
+
request.url 'rest/api/3/issue.json'
|
350
|
+
request.body = create_issue_on_jira_data
|
351
|
+
request.headers['User-Agent'] = 'Caperoma'
|
352
|
+
request.headers['Content-Type'] = 'application/json'
|
353
|
+
end
|
354
|
+
|
355
|
+
result = JSON.parse response.body
|
356
|
+
|
357
|
+
update_attributes(
|
358
|
+
jira_id: result['id'],
|
359
|
+
jira_key: result['key'],
|
360
|
+
jira_url: result['self']
|
361
|
+
)
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
def not_test?
|
366
|
+
ENV['CAPEROMA_INTEGRATION_TEST'].blank?
|
367
|
+
end
|
368
|
+
end
|