cl-magic 0.3.8 → 0.3.9

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