caperoma 0.1.0 → 4.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|