jira_reporting 0.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 +7 -0
- data/.gitignore +21 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +52 -0
- data/Rakefile +6 -0
- data/auth.yml.example +10 -0
- data/bin/jira_reporting +50 -0
- data/bin/jira_sla_update +54 -0
- data/bin/kpi_report +204 -0
- data/bin/maint_vs_enh +127 -0
- data/bin/platform_stability_kpi_report +215 -0
- data/bin/pr-report.rb +23 -0
- data/bin/quarter_report +65 -0
- data/bin/sla_update_closed_issues +38 -0
- data/bin/sla_warning +36 -0
- data/bin/time_in_dev +56 -0
- data/jira_reporting.gemspec +37 -0
- data/lib/auto_hash.rb +21 -0
- data/lib/code_climate.rb +35 -0
- data/lib/jira_issue.rb +288 -0
- data/lib/jira_reporting.rb +27 -0
- data/lib/jira_reporting/connection.rb +16 -0
- data/lib/jira_reporting/sla_report.rb +103 -0
- data/lib/jira_reporting/sla_tracker.rb +183 -0
- data/lib/jira_reporting/triage_tracker.rb +69 -0
- data/lib/jira_reporting/version.rb +3 -0
- data/lib/pull_request.rb +104 -0
- data/optoro_holidays.yaml +71 -0
- data/spec/jira_reporting_spec.rb +11 -0
- data/spec/spec_helper.rb +2 -0
- metadata +313 -0
data/bin/maint_vs_enh
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift "#{File.dirname(__FILE__)}/../lib"
|
4
|
+
require 'jira_reporting'
|
5
|
+
require 'pry-byebug'
|
6
|
+
require 'active_support'
|
7
|
+
require 'yaml'
|
8
|
+
require 'code_climate'
|
9
|
+
require 'auto_hash'
|
10
|
+
require 'pull_request'
|
11
|
+
require 'yaml/dbm'
|
12
|
+
|
13
|
+
auth = YAML.load_file('auth.yml')
|
14
|
+
|
15
|
+
jira_username = auth["jira"]["username"]
|
16
|
+
jira_password = auth["jira"]["password"]
|
17
|
+
JiraReporting.connect! jira_username, jira_password
|
18
|
+
|
19
|
+
start_date = (ARGV[0] && Date.parse(ARGV[0])) || 30.days.ago
|
20
|
+
end_date = (ARGV[1] && Date.parse(ARGV[1])) || 1.day.ago
|
21
|
+
|
22
|
+
start_date = start_date.strftime("%Y-%m-%d")
|
23
|
+
end_date = end_date.strftime("%Y-%m-%d")
|
24
|
+
|
25
|
+
puts "Start: #{start_date} END: #{end_date}"
|
26
|
+
|
27
|
+
def db
|
28
|
+
@db ||= YAML::DBM.open('maint_vs_enh_cache', DBM::WRCREAT)
|
29
|
+
end
|
30
|
+
|
31
|
+
def cache_issues(start_date, end_date)
|
32
|
+
|
33
|
+
# This takes a while
|
34
|
+
# query = %Q{
|
35
|
+
# project in (BULQ, DT, BLINQ.com, OptiTurn, "Tech Support", Tech)
|
36
|
+
# and status was "In Progress" DURING ("#{start_date}", "#{end_date}")
|
37
|
+
# }
|
38
|
+
query = %Q{
|
39
|
+
status was "In Progress" DURING ("#{start_date}", "#{end_date}")
|
40
|
+
}
|
41
|
+
|
42
|
+
puts "Searching jira: #{query}"
|
43
|
+
issues = JiraIssue.find(query)
|
44
|
+
puts "Search complete."
|
45
|
+
|
46
|
+
issue_count = issues.count
|
47
|
+
issues.each_with_index do |issue, index|
|
48
|
+
print "#{index + 1}/#{issue_count} (#{(((index+1).to_r/issue_count)*100).to_i }%) #{issue.key} "
|
49
|
+
if !db[issue.key]
|
50
|
+
issue.changelog
|
51
|
+
db[issue.key] = issue
|
52
|
+
puts "found"
|
53
|
+
else
|
54
|
+
puts "cached"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# cache_issues(start_date, end_date)
|
60
|
+
|
61
|
+
# binding.pry
|
62
|
+
# puts "yep"
|
63
|
+
|
64
|
+
# status_ages = {}
|
65
|
+
# if !db[issue.key] || !db[issue.key][:in_progress_duration]
|
66
|
+
# in_progress_duration = issue.status_duration_during("In Progress", start_date, end_date)
|
67
|
+
# db[issue.key] = {
|
68
|
+
# type: issue.type,
|
69
|
+
# in_progress_duration: in_progress_duration,
|
70
|
+
# issue: issue
|
71
|
+
# }
|
72
|
+
# end
|
73
|
+
# status_ages = db[issue.key][:status_ages]
|
74
|
+
|
75
|
+
# puts "#{issue.key} #{issue.type} (#{index + 1}/#{issue_count})"
|
76
|
+
# type_times[issue.type] += (status_ages["In Progress"] || 0)
|
77
|
+
# type_counts[issue.type] += 1
|
78
|
+
# puts type_times
|
79
|
+
# puts type_counts
|
80
|
+
|
81
|
+
# type_counts.keys.each { |type|
|
82
|
+
# puts [type, type_counts[type], type_times[type]].join(",")
|
83
|
+
# }
|
84
|
+
|
85
|
+
# binding.pry
|
86
|
+
|
87
|
+
puts "Loading issues"
|
88
|
+
issues = db.values
|
89
|
+
count = issues.count
|
90
|
+
|
91
|
+
puts "Dumping issues"
|
92
|
+
File.open("result.csv", "w") do |csv|
|
93
|
+
csv.puts("project,key,type,assignee,mover,in_progress_hours,summary,epic_key,epic_name,start,end")
|
94
|
+
issues.each_with_index do |issue, index|
|
95
|
+
puts "Processing... #{index+1}/#{count}"
|
96
|
+
|
97
|
+
epic_key = issue.orig["fields"]["customfield_10008"]
|
98
|
+
if epic_key
|
99
|
+
epic_issue = db[epic_key] || JiraIssue.find("issue = #{epic_key}").first
|
100
|
+
db[epic_key] ||= epic_issue
|
101
|
+
epic_name = epic_issue.orig["fields"]["customfield_10009"] if epic_issue
|
102
|
+
end
|
103
|
+
|
104
|
+
status_ages = issue.status_ages
|
105
|
+
out_of_in_progress_by = issue.status_changes.select{|c| c[:status] == "In Progress"}.last.andand[:author_out]
|
106
|
+
summary = issue.summary
|
107
|
+
summary.gsub!(',','')
|
108
|
+
epic_name ||= ""
|
109
|
+
epic_name.gsub!(',','')
|
110
|
+
row = [
|
111
|
+
issue.project,
|
112
|
+
issue.key,
|
113
|
+
issue.type,
|
114
|
+
(issue.orig["fields"]["assignee"].andand["name"] || ""),
|
115
|
+
out_of_in_progress_by || "",
|
116
|
+
status_ages["In Progress"] || 0,
|
117
|
+
summary,
|
118
|
+
epic_key || "",
|
119
|
+
epic_name || "",
|
120
|
+
issue.created_at,
|
121
|
+
issue.status_changes.last[:start]
|
122
|
+
].join(",")
|
123
|
+
puts row
|
124
|
+
csv.puts(row)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
@@ -0,0 +1,215 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
PROJECT_ROOT = "#{File.dirname(__FILE__)}/../"
|
3
|
+
|
4
|
+
$:.unshift "#{File.dirname(__FILE__)}/../lib"
|
5
|
+
require 'jira_reporting'
|
6
|
+
require 'active_support'
|
7
|
+
require 'yaml'
|
8
|
+
require 'code_climate'
|
9
|
+
require 'auto_hash'
|
10
|
+
require 'pull_request'
|
11
|
+
require 'os'
|
12
|
+
|
13
|
+
report = AutoHash.new
|
14
|
+
|
15
|
+
auth = YAML.load_file(File.join(PROJECT_ROOT,'auth.yml'))
|
16
|
+
jira_username = auth["jira"]["username"]
|
17
|
+
jira_password = auth["jira"]["password"]
|
18
|
+
JiraReporting.connect! jira_username, jira_password
|
19
|
+
|
20
|
+
# If run on a day to calculate stats for the previous week, do not have to enter a start or end date.
|
21
|
+
start_date = (ARGV[0] && Date.parse(ARGV[0])) || 7.day.ago
|
22
|
+
end_date = (ARGV[1] && Date.parse(ARGV[1])) || 0.day.ago
|
23
|
+
|
24
|
+
start_date = start_date.strftime("%Y-%m-%d")
|
25
|
+
end_date = end_date.strftime("%Y-%m-%d")
|
26
|
+
|
27
|
+
puts ''
|
28
|
+
puts "Report dates - START: #{start_date} END: #{end_date}"
|
29
|
+
puts ''
|
30
|
+
|
31
|
+
puts 'Beginning report data pull...'
|
32
|
+
puts ''
|
33
|
+
|
34
|
+
# Closed issues during given date range
|
35
|
+
closed_ticket_query = %Q{
|
36
|
+
project = "Tech Support"
|
37
|
+
AND "SLA: Closed at" >= "#{start_date}"
|
38
|
+
AND "SLA: Closed at" < "#{end_date}"
|
39
|
+
AND status != "Not Accepted"
|
40
|
+
AND status != "Can't Reproduce"
|
41
|
+
AND type != Epic
|
42
|
+
}
|
43
|
+
puts "The following query will be run for closed tickets: #{closed_ticket_query}"
|
44
|
+
|
45
|
+
# Created issues during given date range
|
46
|
+
created_ticket_query = %Q{
|
47
|
+
project = "Tech Support"
|
48
|
+
AND created >= "#{start_date}"
|
49
|
+
AND created < "#{end_date}"
|
50
|
+
AND status != "Not Accepted"
|
51
|
+
AND status != "Can't Reproduce"
|
52
|
+
AND type != Epic
|
53
|
+
}
|
54
|
+
puts ''
|
55
|
+
puts "The following query will be run for created tickets: #{created_ticket_query}"
|
56
|
+
|
57
|
+
ISSUE_SEGMENTS = %i{bug operational feature research affects_warehouse_users affects_customers affects_client_corporate_users affects_internal_optoro_users}
|
58
|
+
|
59
|
+
# This method creates a hash object of issue arrays divided segments as keys.
|
60
|
+
def segment_issues(issues, segments)
|
61
|
+
segmented_issues = segments.inject({}){|segments_hash, segment| segments_hash[segment] = []; segments_hash }
|
62
|
+
issues.each do |issue|
|
63
|
+
segments.each do |segment|
|
64
|
+
segmented_issues[segment] << issue if issue.send("#{segment}?")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
segmented_issues
|
68
|
+
end
|
69
|
+
|
70
|
+
created_ts_issues = JiraIssue.find(created_ticket_query)
|
71
|
+
total_created_ts_issues = created_ts_issues.count
|
72
|
+
created_segmented_issues = segment_issues(created_ts_issues, ISSUE_SEGMENTS)
|
73
|
+
created_ts_bug_count = created_segmented_issues[:bug].count
|
74
|
+
created_ts_ops_count = created_segmented_issues[:operational].count
|
75
|
+
created_ts_feature_requests = created_segmented_issues[:feature].count
|
76
|
+
created_ts_research_requests = created_segmented_issues[:research].count
|
77
|
+
created_ts_affecting_wh_users = created_segmented_issues[:affects_warehouse_users].count
|
78
|
+
created_ts_affecting_customers = created_segmented_issues[:affects_customers].count
|
79
|
+
created_ts_affecting_client_corporate_users = created_segmented_issues[:affects_client_corporate_users].count
|
80
|
+
created_ts_affecting_internal_users = created_segmented_issues[:affects_internal_optoro_users].count
|
81
|
+
created_ts_over_triage_sla = created_ts_issues.select { |issue| issue.over_triage_sla? == true }.count
|
82
|
+
created_ts_triaged_by_ed = created_ts_issues.select { |issue| issue.triager == 'ewright' }.count
|
83
|
+
created_ts_triaged_by_gabriel = created_ts_issues.select { |issue| issue.triager == 'gzurita' }.count
|
84
|
+
created_ts_triaged_by_spencer = created_ts_issues.select { |issue| issue.triager == 'sgilbert' }.count
|
85
|
+
created_ts_triaged_by_jason = created_ts_issues.select { |issue| issue.triager == 'jfogg' }.count
|
86
|
+
|
87
|
+
closed_ts_issues = JiraIssue.find(closed_ticket_query)
|
88
|
+
|
89
|
+
sla_counted_issues = closed_ts_issues.reject { |issue| issue.sla_due_time.nil? }
|
90
|
+
|
91
|
+
total_ts_cumulative_delay = sla_counted_issues.inject(0){|sum, issue| sum + issue.sum_total_time_over_sla }
|
92
|
+
total_closed_ts_issues = closed_ts_issues.count
|
93
|
+
total_sla_counted_issues = sla_counted_issues.count
|
94
|
+
total_on_time_issues = sla_counted_issues.select { |issue| issue.over_sla.nil? || issue.over_sla? == false }.count
|
95
|
+
closed_segmented_issues = segment_issues(closed_ts_issues, ISSUE_SEGMENTS)
|
96
|
+
closed_ts_bug_count = closed_segmented_issues[:bug].count
|
97
|
+
closed_ts_ops_count = closed_segmented_issues[:operational].count
|
98
|
+
closed_ts_feature_requests = closed_segmented_issues[:feature].count
|
99
|
+
closed_ts_research_requests = closed_segmented_issues[:research].count
|
100
|
+
|
101
|
+
tickets_created_to_tickets_closed = ( total_created_ts_issues.to_f / total_closed_ts_issues.to_f * 100 ).round(2)
|
102
|
+
|
103
|
+
report[:week] = {
|
104
|
+
closed_ts_cumulative_delay: total_ts_cumulative_delay,
|
105
|
+
closed_ts_count: total_closed_ts_issues,
|
106
|
+
closed_bug_count: closed_ts_bug_count,
|
107
|
+
closed_ops_count: closed_ts_ops_count,
|
108
|
+
closed_feature_requests: closed_ts_feature_requests,
|
109
|
+
closed_research_requests: closed_ts_research_requests,
|
110
|
+
created_ts_count: total_created_ts_issues,
|
111
|
+
created_bug_count: created_ts_bug_count,
|
112
|
+
created_ops_count: created_ts_ops_count,
|
113
|
+
created_feature_requests: created_ts_feature_requests,
|
114
|
+
created_research_requests: created_ts_research_requests,
|
115
|
+
created_issues_affecting_wh_users: created_ts_affecting_wh_users,
|
116
|
+
created_issues_affecting_customers: created_ts_affecting_customers,
|
117
|
+
created_issues_affecting_client_corporate_users: created_ts_affecting_client_corporate_users,
|
118
|
+
created_issues_affecting_internal_users: created_ts_affecting_internal_users,
|
119
|
+
tickets_created_to_closed_ratio: tickets_created_to_tickets_closed,
|
120
|
+
created_issues_over_triage_sla: created_ts_over_triage_sla,
|
121
|
+
created_issues_triaged_by_ed: created_ts_triaged_by_ed,
|
122
|
+
created_issues_triaged_by_gabriel: created_ts_triaged_by_gabriel,
|
123
|
+
created_issues_triaged_by_spencer: created_ts_triaged_by_spencer,
|
124
|
+
created_issues_triaged_by_jason: created_ts_triaged_by_jason
|
125
|
+
}
|
126
|
+
|
127
|
+
puts ''
|
128
|
+
|
129
|
+
priorities = closed_ts_issues.group_by(&:priority)
|
130
|
+
|
131
|
+
[:p1,:p2,:p3,:p4,:p5].each do |priority|
|
132
|
+
closed = priorities[priority] || []
|
133
|
+
trend_hit = 1.0
|
134
|
+
trend_hit = closed.select{|issue| issue.over_sla.nil? || issue.over_sla? == false }.length / closed.length.to_f if closed.any?
|
135
|
+
|
136
|
+
report[:sla][priority] = {
|
137
|
+
avg_hit_rate: (trend_hit * 100).round(2),
|
138
|
+
}
|
139
|
+
|
140
|
+
puts "Average hit rate for #{priority.to_s.upcase} tickets: #{(trend_hit * 100).round(2)}%"
|
141
|
+
puts ''
|
142
|
+
end
|
143
|
+
|
144
|
+
puts ''
|
145
|
+
puts 'The following issues went over SLA during the queried period:'
|
146
|
+
closed_ts_issues.sort_by(&:priority).each do |issue|
|
147
|
+
if issue.over_sla?
|
148
|
+
puts "#{issue.priority}\t#{issue.key}\t#{issue.assigned_team}"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
puts ''
|
153
|
+
puts "These issues did not meet Platform Stability's triage goals:"
|
154
|
+
closed_ts_issues.sort_by(&:priority).each do |issue|
|
155
|
+
if issue.over_triage_sla?
|
156
|
+
puts "#{issue.priority}\t#{issue.key}\t#{issue.triager}"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
overall_hit = total_on_time_issues.to_f / total_sla_counted_issues.to_f
|
161
|
+
report[:sla][:overall][:avg_hit_rate] = (overall_hit * 100).round(2)
|
162
|
+
puts ''
|
163
|
+
puts "Overall Avg Hit Rate: #{(overall_hit * 100).round(2)}%"
|
164
|
+
|
165
|
+
def copy_paste_string(report)
|
166
|
+
[
|
167
|
+
report[:week][:closed_ts_cumulative_delay].to_s,
|
168
|
+
report[:sla][:overall][:avg_hit_rate].to_s + '%',
|
169
|
+
report[:sla][:p1][:avg_hit_rate].to_s + '%',
|
170
|
+
report[:sla][:p2][:avg_hit_rate].to_s + '%',
|
171
|
+
report[:sla][:p3][:avg_hit_rate].to_s + '%',
|
172
|
+
report[:sla][:p4][:avg_hit_rate].to_s + '%',
|
173
|
+
report[:week][:closed_ts_count],
|
174
|
+
report[:week][:closed_bug_count].to_s,
|
175
|
+
report[:week][:closed_ops_count].to_s,
|
176
|
+
report[:week][:closed_feature_requests].to_s,
|
177
|
+
report[:week][:closed_research_requests].to_s,
|
178
|
+
report[:week][" "].to_s,
|
179
|
+
report[:week][:created_ts_count].to_s,
|
180
|
+
report[:week][:created_bug_count].to_s,
|
181
|
+
report[:week][:created_ops_count].to_s,
|
182
|
+
report[:week][:created_feature_requests].to_s,
|
183
|
+
report[:week][:created_research_requests].to_s,
|
184
|
+
report[:week][:created_issues_affecting_wh_users].to_s,
|
185
|
+
report[:week][:created_issues_affecting_customers].to_s,
|
186
|
+
report[:week][:created_issues_affecting_client_corporate_users].to_s,
|
187
|
+
report[:week][:created_issues_affecting_internal_users].to_s,
|
188
|
+
report[:week][" "].to_s,
|
189
|
+
report[:week][:tickets_created_to_closed_ratio].to_s + '%',
|
190
|
+
report[:week][" "].to_s,
|
191
|
+
report[:week][:created_issues_over_triage_sla].to_s,
|
192
|
+
report[:week][:created_issues_triaged_by_ed].to_s,
|
193
|
+
report[:week][:created_issues_triaged_by_gabriel].to_s,
|
194
|
+
report[:week][:created_issues_triaged_by_spencer].to_s,
|
195
|
+
report[:week][:created_issues_triaged_by_jason].to_s
|
196
|
+
].join("\n")
|
197
|
+
end
|
198
|
+
|
199
|
+
# Copy/pasteable
|
200
|
+
puts "Copy/paste:\n----------"
|
201
|
+
puts copy_paste_string(report)
|
202
|
+
puts "-----------"
|
203
|
+
|
204
|
+
case
|
205
|
+
when OS.linux? == true
|
206
|
+
IO.popen("xclip -selection clipboard", "r+") do |xclip|
|
207
|
+
xclip.puts copy_paste_string(report)
|
208
|
+
end
|
209
|
+
when OS.mac? == true
|
210
|
+
IO.popen("pbcopy", "r+") do |pbcopy|
|
211
|
+
pbcopy.puts copy_paste_string(report)
|
212
|
+
end
|
213
|
+
else
|
214
|
+
puts "The automatic copying of the kpi report stats failed. Please manually copy and paste the output into the KPI spreadsheet"
|
215
|
+
end
|
data/bin/pr-report.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift "#{File.dirname(__FILE__)}/../lib"
|
4
|
+
require 'pull_request'
|
5
|
+
require 'pry-byebug'
|
6
|
+
|
7
|
+
auth = YAML.load_file('auth.yml')
|
8
|
+
jira_username = auth["jira"]["username"]
|
9
|
+
jira_password = auth["jira"]["password"]
|
10
|
+
JiraReporting.connect! jira_username, jira_password
|
11
|
+
|
12
|
+
github_token = auth["github"]["api_token"]
|
13
|
+
PullRequest.connect(github_token)
|
14
|
+
|
15
|
+
prs = PullRequest.get_prs('inventory')
|
16
|
+
binding.pry
|
17
|
+
|
18
|
+
keys = [:pr_number, :jira, :title, :created, :requester, :cl, :ci, :code_reviewed, :needs_testing, :project, :issue_current_sprint, :issue_status]
|
19
|
+
puts keys.to_csv
|
20
|
+
prs.each do |pr|
|
21
|
+
puts pr.to_csv
|
22
|
+
end
|
23
|
+
|
data/bin/quarter_report
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'jira_reporting'
|
3
|
+
require 'pry'
|
4
|
+
require 'byebug'
|
5
|
+
|
6
|
+
username = "hi"
|
7
|
+
password = "there"
|
8
|
+
start_date = "2014-07-01"
|
9
|
+
end_date = "2014-10-01"
|
10
|
+
|
11
|
+
JiraReporting.connect! username, password
|
12
|
+
|
13
|
+
r = JiraReporting::SLAReport.new
|
14
|
+
query = %Q{project = "Tech Support" AND status not in ("Not Accepted", "Can't Reproduce") AND "Support xt Resolved" >= #{start_date} AND "Support xt Resolved" < #{end_date}}
|
15
|
+
issues = r.find_all(query)
|
16
|
+
rept = issues.map{|i| JiraIssue.new(i) }
|
17
|
+
prios = rept.group_by(&:priority)
|
18
|
+
|
19
|
+
|
20
|
+
hour = 60 * 60.0
|
21
|
+
ideal_times = {
|
22
|
+
p1: 2 * hour,
|
23
|
+
p2: 24 * hour,
|
24
|
+
p3: (24 * hour) * 3, # 5 business days
|
25
|
+
p4: (24 * hour) * 5 # 5 business days
|
26
|
+
}
|
27
|
+
|
28
|
+
[:p1,:p2,:p3,:p4,:p5].each do |priority|
|
29
|
+
set = prios[priority] || []
|
30
|
+
open, closed = set.partition(&:open?)
|
31
|
+
trend_time = closed.inject(0){|s,t| s + t.sla_diff } / closed.length.to_f
|
32
|
+
|
33
|
+
|
34
|
+
trend_resolution_time = ""
|
35
|
+
if closed.any?
|
36
|
+
mm, ss = trend_time.divmod(60)
|
37
|
+
hh, mm = mm.divmod(60)
|
38
|
+
dd, hh = hh.divmod(24)
|
39
|
+
trend_resolution_time = "#{dd}d #{hh.to_i}h #{mm.to_i}m #{ss.to_i}s"
|
40
|
+
end
|
41
|
+
|
42
|
+
unless priority == :p4
|
43
|
+
ideal_time = ideal_times[priority]
|
44
|
+
multiple_off_ideal = trend_time.to_f / ideal_time
|
45
|
+
end
|
46
|
+
|
47
|
+
trend_hit = 0
|
48
|
+
trend_hit = closed.select{|t| t.sla_diff <= 0 }.length / closed.length.to_f if closed.any?
|
49
|
+
|
50
|
+
puts "#{priority.to_s.upcase}:"
|
51
|
+
puts "Open Tickets: #{open.count}"
|
52
|
+
puts "Closed Tickets: #{closed.count}"
|
53
|
+
puts "Avg Diff to SLA: #{trend_resolution_time}"
|
54
|
+
puts "Avg SLA Multiple: #{multiple_off_ideal.round(2)}x" unless priority == :p4
|
55
|
+
puts "Avg Hit Rate: #{(trend_hit * 100).round(2)}%"
|
56
|
+
puts ""
|
57
|
+
end
|
58
|
+
|
59
|
+
overall_hit = rept.select{|t| t.sla_diff <= 0 }.length / rept.length.to_f
|
60
|
+
puts ""
|
61
|
+
puts "Overall Avg Hit Rate: #{(overall_hit * 100).round(2)}%"
|
62
|
+
|
63
|
+
binding.pry
|
64
|
+
|
65
|
+
puts 2 + 2
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
PROJECT_ROOT = "#{File.dirname(__FILE__)}/../"
|
4
|
+
|
5
|
+
$:.unshift "#{File.dirname(__FILE__)}/../lib"
|
6
|
+
require 'jira_reporting'
|
7
|
+
require 'pry-byebug'
|
8
|
+
require 'active_support'
|
9
|
+
require 'yaml'
|
10
|
+
|
11
|
+
auth = YAML.load_file(File.join(PROJECT_ROOT,'auth.yml'))
|
12
|
+
jira_username = auth["jira"]["username"]
|
13
|
+
jira_password = auth["jira"]["password"]
|
14
|
+
JiraReporting.connect! jira_username, jira_password
|
15
|
+
|
16
|
+
# Open TS issues
|
17
|
+
query = %Q{
|
18
|
+
project = TS
|
19
|
+
AND ("Support xt Requester Review" >= startOfWeek(-1)
|
20
|
+
OR "Support xt On Production" >= startOfWeek(-1)
|
21
|
+
OR "Support xt Merged" >=startOfWeek(-1) )
|
22
|
+
AND status != "Not Accepted"
|
23
|
+
AND type != Epic
|
24
|
+
}
|
25
|
+
|
26
|
+
ts_issues = JiraIssue.find(query).sort_by(&:sla_time_ratio)
|
27
|
+
|
28
|
+
ts_issues.each do |issue|
|
29
|
+
issue.set_sla_due_time! if issue.sla_due_time.nil?
|
30
|
+
issue.set_sla_triaged_at! if issue.sla_triaged_at.nil?
|
31
|
+
issue.set_over_triage_sla! if issue.over_triage_sla.nil?
|
32
|
+
issue.set_sla_closed_at! if issue.sla_closed_at.nil?
|
33
|
+
issue.set_sla_due_warning! if issue.sla_due_warning.nil?
|
34
|
+
issue.set_over_sla! if issue.over_sla.nil?
|
35
|
+
puts "#{issue.priority} #{issue.key} #{issue.summary} has been updated."
|
36
|
+
end
|
37
|
+
|
38
|
+
puts 'SLA due time and overdue status update complete.'
|