cl-magic 0.3.8 → 0.3.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aee6512ae8cbee738242f87ec89baa10a56c04c2600fdf766c93f7844d6d6a38
4
- data.tar.gz: d43a49eca90391948305353fa7d0242bf5bf14504492531bf9cda43bd7a4d0cf
3
+ metadata.gz: 42235afcff8b801982ca721b3217756dad15a401063e59310900dd595c05a4e2
4
+ data.tar.gz: a49e3798271b7cef9f8e82d9b0a6e9846e9a56a1de1d4d75d91ed81e2291d237
5
5
  SHA512:
6
- metadata.gz: 3b040f7fe5dfccd9c62395d433a1c445f9c246e27b98636c0af318beca7e62ac7a4a082bdfdf1f68e8e602b2652ff3a9c961f611a317de5d2555262652405544
7
- data.tar.gz: 4a0ced863718cfe30127ff57f18698ef641ae520245094166d511310b7995f55c08e3644e8028044e27389681250e8c63c7850bf44c43e933546aa8bc2bbb557
6
+ metadata.gz: 5319a3c52cc59b51c2a6a0e8469cc7085e6485765c335ba44bf6709937c8eb7d12b4b410c78ebb71b283faabd466d647b9109399b20ea9e72ffc4d5fdfa6b252
7
+ data.tar.gz: 5f016f4f25736f492b0985fe4ebe5cfb0f33597cf8a365d240743f7635c8142db1726c6c17ffac9a4f6a34946e6864e8a0eabda6b8ef89dd5068f6f14161dc06
data/Gemfile.lock CHANGED
@@ -1,7 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cl-magic (0.3.8)
4
+ cl-magic (0.3.9)
5
+ activesupport
5
6
  optparse-subcommand
6
7
  pastel
7
8
  tty-command
@@ -11,7 +12,15 @@ PATH
11
12
  GEM
12
13
  remote: https://rubygems.org/
13
14
  specs:
15
+ activesupport (7.0.6)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (>= 1.6, < 2)
18
+ minitest (>= 5.1)
19
+ tzinfo (~> 2.0)
14
20
  byebug (11.1.3)
21
+ concurrent-ruby (1.2.2)
22
+ i18n (1.14.1)
23
+ concurrent-ruby (~> 1.0)
15
24
  minitest (5.18.0)
16
25
  optparse-subcommand (1.0.0)
17
26
  pastel (0.8.0)
@@ -31,6 +40,8 @@ GEM
31
40
  tty-screen (~> 0.8)
32
41
  wisper (~> 2.0)
33
42
  tty-screen (0.8.1)
43
+ tzinfo (2.0.6)
44
+ concurrent-ruby (~> 1.0)
34
45
  wisper (2.0.1)
35
46
 
36
47
  PLATFORMS
data/README.md CHANGED
@@ -20,4 +20,18 @@ cd $MAGIC_DIR bundle install --path=vendor
20
20
 
21
21
  # symlink
22
22
  ln -s $MAGIC_DIR/bin/cl /usr/local/bin
23
- ```
23
+ ```
24
+
25
+ ## Development
26
+
27
+ If you installed the gem, you need to remove the simlink
28
+
29
+ ```
30
+ rm /usr/local/bin/cl
31
+ ```
32
+
33
+ Then sim-link to your cl-magic source code's bin script
34
+
35
+ ```
36
+ ln -s $(pwd)/bin/cl /usr/local/bin
37
+ ```
data/cl-magic.gemspec CHANGED
@@ -34,5 +34,7 @@ Gem::Specification.new do |spec|
34
34
  spec.add_dependency "tty-command"
35
35
  spec.add_dependency "tty-prompt"
36
36
  spec.add_dependency "pastel"
37
+ spec.add_dependency "activesupport"
37
38
  spec.add_development_dependency "byebug"
39
+
38
40
  end
data/lib/cl/magic/cl-auth CHANGED
@@ -41,6 +41,12 @@ end
41
41
  def aws_okta(options)
42
42
  is_tty = $stdout.isatty
43
43
 
44
+ if options[:aws_profile].nil?
45
+ puts
46
+ @logger.info "Note: have you run 'aws-okta add' already?"
47
+ puts
48
+ end
49
+
44
50
  # pick profile
45
51
  profiles = get_aws_profiles()
46
52
  profile = pick_single_result(profiles, "Pick aws profile", options[:aws_profile])
@@ -56,7 +62,7 @@ def aws_okta(options)
56
62
  # do work
57
63
  if is_tty
58
64
  puts
59
- @logger.info "export into your environment with"
65
+ @logger.info "now export into your environment with"
60
66
  puts
61
67
  puts "export $(#{history_command})"
62
68
  else
data/lib/cl/magic/cl-dk CHANGED
@@ -80,21 +80,23 @@ end
80
80
  #
81
81
 
82
82
  def print_dk_help_line(key, help)
83
- if help.nil?
84
- @logger.puts("#{key.ljust(15, ' ')} ???no help???")
85
- else
86
- key = key.ljust(15, ' ')
87
- help_parts = help.split(";")
83
+ if $stdout.isatty
84
+ if help.nil?
85
+ @logger.puts("#{key.ljust(15, ' ')} ???no help???")
86
+ else
87
+ key = key.ljust(15, ' ')
88
+ help_parts = help.split(";")
88
89
 
89
- # first line
90
- @logger.puts(key, help_parts.shift)
90
+ # first line
91
+ @logger.puts(key, help_parts.shift)
91
92
 
92
- # following lines
93
- padding = "".ljust(15, ' ')
94
- help_parts.each do |p|
95
- @logger.puts(padding, p)
93
+ # following lines
94
+ padding = "".ljust(15, ' ')
95
+ help_parts.each do |p|
96
+ @logger.puts(padding, p)
97
+ end
98
+ @logger.puts("") if help.end_with?(";")
96
99
  end
97
- puts("") if help.end_with?(";")
98
100
  end
99
101
  end
100
102
 
@@ -131,7 +133,7 @@ def print_dk_help(dk_parts_hash, dk_make_hash, args)
131
133
  puts "ADDITIONAL TURNKEY COMMANDS"
132
134
  puts " - dk set-world sets the location of the world directory"
133
135
  puts " - dk make turnkey commands for a project"
134
- puts " - dk save-parts save parts so they are automatically applied to commands"
136
+ puts " - dk set-parts save parts so they are automatically applied to commands"
135
137
  puts ""
136
138
  puts "-------------------------"
137
139
  end
@@ -139,21 +141,27 @@ def print_dk_help(dk_parts_hash, dk_make_hash, args)
139
141
  end
140
142
 
141
143
  def print_make_help(dk_parts_hash, dk_make_hash)
142
- puts ""
143
- puts "Usage: dk [DK_PARTS] make COMMAND"
144
- puts ""
145
- puts "Make commands designed to make your developer experience more turnkey"
146
- puts ""
147
- puts "Parts:"
148
- dk_parts_hash.keys.each do |key|
149
- print_dk_help_line(key, dk_parts_hash[key].fetch('help'))
150
- end
151
- puts ""
152
- puts "Commands:"
153
- dk_make_hash.keys.each do |key|
154
- print_dk_help_line(key, dk_make_hash[key].fetch('help'))
144
+ if $stdout.isatty
145
+ puts ""
146
+ puts "Usage: dk [DK_PARTS] make COMMAND"
147
+ puts ""
148
+ puts "Make commands designed to make your developer experience more turnkey"
149
+ puts ""
150
+ puts "Parts:"
151
+ dk_parts_hash.keys.each do |key|
152
+ print_dk_help_line(key, dk_parts_hash[key].fetch('help'))
153
+ end
154
+ puts ""
155
+ puts "Commands:"
156
+ dk_make_hash.keys.each do |key|
157
+ print_dk_help_line(key, dk_make_hash[key].fetch('help'))
158
+ end
159
+ puts ""
160
+ else
161
+ dk_make_hash.keys.each do |key|
162
+ puts key
163
+ end
155
164
  end
156
- puts ""
157
165
  end
158
166
 
159
167
  def print_set_world_help()
@@ -227,10 +235,10 @@ end
227
235
  def merge_world_files(compose_hash, show_help=false)
228
236
  dk_proj_path = get_world_project_path()
229
237
  if dk_proj_path
230
- print_dk_help_line("dk-project-path", "#{dk_proj_path}") if show_help
238
+ print_dk_help_line("dk-project-path", "#{dk_proj_path}") if show_help and $stdout.isatty
231
239
 
232
240
  Dir.glob("#{dk_proj_path}/*.yml").sort.each do |filepath|
233
- print_dk_help_line("dk-world", "#{filepath}") if show_help
241
+ print_dk_help_line("dk-world", "#{filepath}") if show_help and $stdout.isatty
234
242
 
235
243
  # read file and replace
236
244
  contents = File.read(filepath)
@@ -274,10 +282,12 @@ def merge_parts_save_and_prep_args(compose_hash, dk_parts_hash, dk_make_hash, sa
274
282
  print_dk_help(dk_parts_hash, dk_make_hash, args)
275
283
 
276
284
  def print_and_merge_part(part_key, dk_part, compose_hash)
277
- # print
278
- help_str = dk_part.fetch('help')
279
- print_dk_help_line("#{part_key}", "#{help_str ? '- ' + help_str : ''}") if dk_part.keys.any?
280
285
 
286
+ # print
287
+ if $stdout.isatty
288
+ help_str = dk_part.fetch('help')
289
+ print_dk_help_line("#{part_key}", "#{help_str ? '- ' + help_str : ''}") if dk_part.keys.any?
290
+ end
281
291
  # merge
282
292
  return dk_merge_and_remove(compose_hash, dk_part)
283
293
  end
@@ -305,7 +315,7 @@ def merge_parts_save_and_prep_args(compose_hash, dk_parts_hash, dk_make_hash, sa
305
315
  break
306
316
  end
307
317
  end
308
- puts "" # tailing line break
318
+ @logger.puts "" if $stdout.isatty # tailing line break
309
319
  tempfile.write(compose_hash.to_yaml) # write it to the tempfile
310
320
 
311
321
  # clone args
@@ -423,7 +433,7 @@ def run_dk_make(compose_args, dk_make_hash, dk_parts_hash, selected_part_keys)
423
433
  make_commands.each_with_index do |key, i|
424
434
 
425
435
  if not dk_make_hash.has_key?(key)
426
- puts "#{key} - command not found"
436
+ @logger.error "#{key} - command not found"
427
437
  exit 1
428
438
  else
429
439
 
@@ -463,7 +473,7 @@ def prep_make_command(c, selected_part_keys)
463
473
  c = interpolate_parts_into_command(c, selected_part_keys)
464
474
 
465
475
  # logging
466
- @logger.puts ""
476
+ @logger.puts "" if $stdout.isatty
467
477
  @logger.wait(c)
468
478
  cmd = "cd #{@working_dir} && #{c}"
469
479
  end
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env ruby
2
+ # Fetch jira issues, status changelogs and save them to a file
3
+ require 'optparse'
4
+ require 'optparse/subcommand'
5
+ require 'tty-command'
6
+ require 'tty-prompt'
7
+
8
+ require 'cl/magic/common/common_options.rb'
9
+ require 'cl/magic/common/logging.rb'
10
+ require 'cl/magic/common/jira.rb'
11
+
12
+ require 'net/http'
13
+ require 'json'
14
+
15
+ require 'byebug'
16
+
17
+ @logger = get_logger()
18
+ @cl_cmd_name = File.basename(__FILE__).split('-').join(' ')
19
+
20
+ #
21
+ # Features
22
+ #
23
+
24
+ def do_work(options)
25
+ break_at_one_page = false # when developing, set this to true
26
+ jira = Jira.new options[:base_uri], options[:username], options[:token], break_at_one_page
27
+
28
+ puts ""
29
+ @logger.wait "fetch epics"
30
+ epic_ids = jira.get_epic_ids(options[:project], options[:epic_wildcard])
31
+ @logger.success "#{epic_ids.count} epics"
32
+
33
+ puts ""
34
+ @logger.wait "fetch issues"
35
+ issues = jira.get_issues(options[:project], epic_ids)
36
+ @logger.success "#{issues.count} issues"
37
+
38
+ puts ""
39
+ @logger.wait "fetch & merge change logs"
40
+ issues = collect_status_changelogs(jira, issues, options)
41
+ @logger.success ""
42
+
43
+ puts ""
44
+ @logger.wait "saving file"
45
+ output_filepath = File.join(@working_dir, options[:output_filename])
46
+ File.open(output_filepath, 'w') do |file|
47
+ issues.each do |issue|
48
+ file.puts(issue.to_json)
49
+ end
50
+ end
51
+
52
+ @logger.success " #{output_filepath}"
53
+ end
54
+
55
+ #
56
+ # Options
57
+ #
58
+
59
+ options = {
60
+ output_filename: "jira-fetch-#{Time.now.strftime("%Y%m%d%H%M%S")}.datafile"
61
+ }
62
+ global_banner = <<DOC
63
+
64
+ Fetch jira issues, status changelogs and save them to a file
65
+
66
+ Usage: #{@cl_cmd_name} [options]
67
+
68
+ DOC
69
+
70
+ global = OptionParser.new do |g|
71
+ g.banner = global_banner
72
+ add_help_and_verbose(g)
73
+
74
+ g.on("--base-uri URI", "base uri for jira (ex. https://company.atlassian.net)") do |v|
75
+ options[:base_uri] = v
76
+ end
77
+
78
+ g.on("-u", "--username USERNAME", "jira username") do |v|
79
+ options[:username] = v
80
+ end
81
+
82
+ g.on("-t", "--token TOKEN", "jira token (you can create one, google it)") do |v|
83
+ options[:token] = v
84
+ end
85
+
86
+ g.on("-p", "--project KEY", "jira project to fetch from") do |v|
87
+ options[:project] = v
88
+ end
89
+
90
+ g.on("-w", "--epic-wildcard TEXT", "wildcard to filter the epics by") do |v|
91
+ options[:epic_wildcard] = v
92
+ end
93
+
94
+ g.on("-f", "--output-filename NAME", "the name of the output file (defaults to jira-fetch-timestamp.datafile)") do |v|
95
+ options[:output_filename] = v
96
+ end
97
+
98
+ end
99
+
100
+ #
101
+ # Run
102
+ #
103
+
104
+ @working_dir = ENV['CL_WORKING_DIR'] # passed through cl-magic to here
105
+ global.parse(ARGV)
106
+
107
+ # error on token right away
108
+ if options[:token].nil?
109
+ @logger.error "missing --token"
110
+ exit
111
+ end
112
+
113
+ # prompt for missing options
114
+ ask_and_store_option(options, :base_uri, "base_uri: ")
115
+ ask_and_store_option(options, :username, "username: ")
116
+ ask_and_store_option(options, :project, "project: ")
117
+ ask_and_store_option(options, :epic_wildcard, "epic_wildcard: ")
118
+ ask_and_store_option(options, :output_filename, "output_filename: ")
119
+
120
+ # display full command
121
+ write_history("""#{@cl_cmd_name} \\
122
+ --base-uri=#{options[:base_uri]} \\
123
+ --username=#{options[:username]} \\
124
+ --project=#{options[:project]} \\
125
+ --epic-wildcard=#{options[:epic_wildcard]}
126
+ """)
127
+
128
+ do_work(options)
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env ruby
2
+ # Fetch jira issues print stats
3
+ require 'optparse'
4
+ require 'optparse/subcommand'
5
+ require 'tty-command'
6
+ require 'tty-prompt'
7
+ require 'active_support/all'
8
+
9
+ require 'cl/magic/common/common_options.rb'
10
+ require 'cl/magic/common/logging.rb'
11
+ require 'cl/magic/common/jira.rb'
12
+
13
+ require 'net/http'
14
+ require 'json'
15
+
16
+ require 'byebug'
17
+
18
+ @logger = get_logger()
19
+ @cl_cmd_name = File.basename(__FILE__).split('-').join(' ')
20
+
21
+ #
22
+ # Features
23
+ #
24
+
25
+ def get_issues_from_datafile(options)
26
+ issues = []
27
+ filepath = File.join(@working_dir, options[:data_filepath])
28
+ File.foreach(filepath) do |line|
29
+ issue = JSON.parse(line)
30
+ issuetype = issue["fields"]["issuetype"]["name"]
31
+
32
+ # filter if needed
33
+ issues << issue unless options[:exclude_issuetypes].include?(issuetype)
34
+ end
35
+ return issues
36
+ end
37
+
38
+ def oldest_issue_date(issues)
39
+ return issues.collect {|i| Date.parse(i["fields"]["created"])}.sort.first
40
+ end
41
+
42
+ def do_work(options)
43
+ issues = get_issues_from_datafile(options)
44
+ oldest_date = oldest_issue_date(issues)
45
+ iter_date_range(oldest_date) do |start_date, end_date|
46
+ stat_hashes = issues_to_stat_hashes(issues, start_date, end_date, options)
47
+ counts = print_stats(stat_hashes, start_date, end_date)
48
+ puts counts # print each time range
49
+ end
50
+ end
51
+
52
+ def iter_date_range(start_date)
53
+ current_date = start_date.beginning_of_week
54
+ while current_date < 1.week.ago.end_of_week
55
+ yield current_date, current_date.end_of_week
56
+ current_date += 2.weeks # increment
57
+ end
58
+ end
59
+
60
+ def issues_to_stat_hashes(issues, start_date, end_date, options)
61
+
62
+ # parse dates for changelogs
63
+ issues.each do |issue|
64
+ issue["status_changelogs"].each do |l|
65
+ date_string = l["created"]
66
+ l["created"] = Date.parse(date_string) unless date_string.class == Date
67
+ end
68
+ end
69
+
70
+ # collect stat hashes
71
+ return issues.collect do |issue|
72
+
73
+ # skip if issue is out of range
74
+ issue_created = Date.parse(issue["fields"]["created"])
75
+ if issue_created > end_date
76
+ nil
77
+ else
78
+ # get in-range status change
79
+ status_changelog = nil
80
+ status_changelog = issue["status_changelogs"]
81
+ .select { |l| l["created"] > end_date }
82
+ .sort_by { |l| l["created"] }.last if start_date && end_date
83
+
84
+ # exclude issue types
85
+ if status_changelog and options[:exclude_issuetypes].include?(status_changelog["toString"])
86
+ nil
87
+ else
88
+ # yield stat hash
89
+ {
90
+ issuetype: issue["fields"]["issuetype"]["name"],
91
+ status: status_changelog ? status_changelog["toString"] : issue["fields"]["status"]["name"]
92
+ }
93
+ end
94
+ end
95
+ end.compact
96
+ end
97
+
98
+ def print_stats(stat_hashes, start_date, end_date)
99
+ counts = {
100
+ start_date: start_date.strftime("%m-%d-%Y"),
101
+ end_date: end_date.strftime("%m-%d-%Y"),
102
+ total_todo: 0,
103
+ total_done: 0,
104
+ total: stat_hashes ? stat_hashes.count : 0
105
+ }
106
+ return counts unless stat_hashes.any?
107
+ stat_hashes.each do |stat|
108
+
109
+ issuetype = stat[:issuetype]
110
+ status = stat[:status]
111
+
112
+ # count all
113
+ increment(counts, "status_#{issuetype.downcase.underscore}")
114
+
115
+ # count by status
116
+ case status
117
+ when "Ready","Rework","In Progress","In QA","Ready For Code Review","In Code Review"
118
+ increment(counts, :total_todo)
119
+ when "Ready to Deploy","Closed"
120
+ increment(counts, :total_done)
121
+ # else
122
+ # raise "invalid ticket status: #{status}"
123
+ end
124
+ end
125
+ return counts
126
+ end
127
+
128
+ def increment(hash, key)
129
+ if hash.key? key
130
+ hash[key] += 1
131
+ else
132
+ hash[key] = 1
133
+ end
134
+ end
135
+
136
+ #
137
+ # Options
138
+ #
139
+
140
+ options = {
141
+ exclude_issuetypes: []
142
+ }
143
+ global_banner = <<DOC
144
+
145
+ Process jira fetch file an return stats
146
+
147
+ Usage: #{@cl_cmd_name} [options]
148
+
149
+ DOC
150
+
151
+ global = OptionParser.new do |g|
152
+ g.banner = global_banner
153
+ add_help_and_verbose(g)
154
+
155
+ g.on("-f", "--data-filepath FILEPATH", "relative path to file produced by 'cl jira fetch' command") do |v|
156
+ options[:data_filepath] = v
157
+ end
158
+
159
+ g.on("-e", "--exclude-issuetypes CSV", "comma separated list of issuetypes you want to exclude") do |v|
160
+ options[:exclude_issuetypes] = v.split(',')
161
+ options[:exclude_issuetypes] << "Won't Do"
162
+ end
163
+ end
164
+
165
+ #
166
+ # Run
167
+ #
168
+
169
+ @working_dir = ENV['CL_WORKING_DIR'] # passed through cl-magic to here
170
+ global.parse(ARGV)
171
+
172
+ # prompt for missing options
173
+ ask_and_store_option(options, :data_filepath, "data_filepath: ")
174
+
175
+ # display full command
176
+ write_history("""#{@cl_cmd_name} \\
177
+ --data-filepath=#{options[:data_filepath]}
178
+ """)
179
+
180
+ do_work(options)
@@ -1,3 +1,4 @@
1
+ require 'tty-prompt'
1
2
 
2
3
  def add_help_and_verbose(opts)
3
4
  add_verbose(opts)
@@ -13,4 +14,10 @@ def add_help(opts)
13
14
  puts opts
14
15
  exit
15
16
  end
16
- end
17
+ end
18
+
19
+ def ask_and_store_option(options, key, question)
20
+ if options[key].nil?
21
+ options[key] = TTY::Prompt.new.ask(question)
22
+ end
23
+ end
@@ -0,0 +1,162 @@
1
+ require 'byebug'
2
+
3
+ class Jira
4
+
5
+ def initialize(base_uri, username, token, break_at_one_page=false)
6
+ @base_uri = base_uri.chomp("/")
7
+ @username = username
8
+ @token = token
9
+ @break_at_one_page = break_at_one_page
10
+ end
11
+
12
+ #
13
+ # Fetch: Issues & Change Logs
14
+ #
15
+
16
+ def get_epic_ids(project, epic_wildcard)
17
+ jql_query = "project = \"#{project}\" AND issuetype = Epic AND text ~ \"#{epic_wildcard}\""
18
+ results = run_jql_query(jql_query)
19
+ return results.select{|h| h['fields']['summary'].start_with? epic_wildcard}.map {|h| h['id']}
20
+ end
21
+
22
+ def get_issues(project, epic_ids)
23
+ jql_query = "project = \"#{project}\" AND parentEpic IN (#{epic_ids.join(',')})"
24
+ return run_jql_query(jql_query)
25
+ end
26
+
27
+ def get_issue_status_changelog(issue_key)
28
+ uri = URI.parse("#{@base_uri}/rest/api/2/issue/#{issue_key}/changelog")
29
+ jira_get(uri) do |response|
30
+ result = JSON.parse(response.body)
31
+ return result["values"]
32
+ end
33
+ end
34
+
35
+ #
36
+ # Helpers: GET & POST
37
+ #
38
+
39
+ def jira_get(uri)
40
+ http = Net::HTTP.new(uri.host, uri.port)
41
+ http.use_ssl = true
42
+
43
+ # get request
44
+ request = Net::HTTP::Get.new(uri.path)
45
+ request.basic_auth(@username, @token)
46
+
47
+ # fetch
48
+ response = http.request(request)
49
+ if response.code == '200'
50
+ yield response
51
+ else
52
+ raise "Jira query failed with HTTP status code #{response.code}"
53
+ end
54
+ end
55
+
56
+ def jira_post(uri, body)
57
+ http = Net::HTTP.new(uri.host, uri.port)
58
+ http.use_ssl = true
59
+
60
+ # post request
61
+ request = Net::HTTP::Post.new(uri.path)
62
+ request.basic_auth(@username, @token)
63
+ request.content_type = 'application/json'
64
+ request.body = body.to_json
65
+
66
+ # fetch
67
+ response = http.request(request)
68
+ if response.code == '200'
69
+ yield response
70
+ else
71
+ raise "Jira query failed with HTTP status code #{response.code}"
72
+ end
73
+ end
74
+
75
+ #
76
+ # Fetch: JQL Query
77
+ #
78
+
79
+ def run_jql_query(jql)
80
+ start_at = 0
81
+ max_results = 50
82
+ total_results = nil
83
+ all_results = []
84
+
85
+ page_loop = true
86
+ while page_loop
87
+
88
+ uri = URI("#{@base_uri}/rest/api/2/search")
89
+ body = { jql: jql, startAt: start_at, maxResults: max_results }
90
+
91
+ # post
92
+ jira_post(uri, body) do |response|
93
+ result = JSON.parse(response.body)
94
+
95
+ # get issues
96
+ issues = result['issues']
97
+ all_results += issues
98
+
99
+ # debug: one page only
100
+ if @break_at_one_page
101
+ page_loop = false
102
+ break
103
+ end
104
+
105
+ # paginate
106
+ total_results ||= result['total']
107
+ if all_results.count == total_results
108
+ page_loop = false # we got them all, stop paging
109
+ else
110
+ start_at += max_results # else next page
111
+ end
112
+ end
113
+
114
+ print '.' # loop
115
+ end
116
+ all_results.map {|h| h}
117
+ end
118
+ end
119
+
120
+ #
121
+ # Collect status changelogs
122
+ #
123
+ # Given a array of jira issue hashes
124
+ # * fetch the change log
125
+ # * filter down to status changes
126
+ # * add it to the issue hash as ["status_changelogs"]
127
+ #
128
+
129
+ def collect_status_changelogs(jira, issues, options)
130
+ final_issue_hashes = []
131
+
132
+ issues.each do |issue|
133
+ issue_key = issue["key"]
134
+ issue["status_changelogs"] = []
135
+
136
+ # fetch change log
137
+ print '.'
138
+ changelogs = jira.get_issue_status_changelog(issue_key)
139
+
140
+ changelogs.each do |change_log|
141
+
142
+ # all items that are status changes
143
+ status_logs = change_log["items"].select {|i| i["field"]=="status"}
144
+ status_logs = status_logs.collect do |status_log|
145
+ {
146
+ "key": issue_key,
147
+ "created": change_log["created"],
148
+ "toString": status_log["toString"],
149
+ "fromString": status_log["fromString"]
150
+ }
151
+ end
152
+
153
+ # append them to issue
154
+ status_logs.each do |status_log|
155
+ issue["status_changelogs"] << status_log
156
+ end if status_logs.count > 0
157
+ end
158
+
159
+ final_issue_hashes << issue # save
160
+ end
161
+ return final_issue_hashes
162
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Cl
4
4
  module Magic
5
- VERSION = "0.3.8"
5
+ VERSION = "0.3.9"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cl-magic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.8
4
+ version: 0.3.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Don Najd
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-21 00:00:00.000000000 Z
11
+ date: 2023-07-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: activesupport
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: byebug
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -132,6 +146,8 @@ files:
132
146
  - lib/cl/magic/cl-gc-tags
133
147
  - lib/cl/magic/cl-glab-commit
134
148
  - lib/cl/magic/cl-history
149
+ - lib/cl/magic/cl-jira-fetch
150
+ - lib/cl/magic/cl-jira-stats
135
151
  - lib/cl/magic/cl-kube-cp
136
152
  - lib/cl/magic/cl-kube-deployment
137
153
  - lib/cl/magic/cl-kube-ktx
@@ -145,6 +161,7 @@ files:
145
161
  - lib/cl/magic/cl-vault
146
162
  - lib/cl/magic/common/common_options.rb
147
163
  - lib/cl/magic/common/gcloud.rb
164
+ - lib/cl/magic/common/jira.rb
148
165
  - lib/cl/magic/common/kubectl.rb
149
166
  - lib/cl/magic/common/logging.rb
150
167
  - lib/cl/magic/common/parse_and_pick.rb