cl-magic 0.3.9 → 0.4.0
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 +4 -4
- data/Gemfile.lock +1 -1
- data/lib/cl/magic/cl-auth +12 -0
- data/lib/cl/magic/cl-dk +32 -30
- data/lib/cl/magic/cl-jira-fetch +5 -6
- data/lib/cl/magic/cl-jira-stats +86 -67
- data/lib/cl/magic/cl-poll +20 -5
- data/lib/cl/magic/common/jira.rb +4 -3
- data/lib/cl/magic/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '08b4655abcd92a0d5e3a779fdc7e0e09231c7cb15d073e06878c085227ef3f9d'
|
4
|
+
data.tar.gz: 63999d535d6ad18d22b8cff1e259b9b054bbf7faf75939e54c9819885ca24feb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4157d207e824e2d0a309790187873d3b6b02c41bd892fc3436e359cc1f4639044576129d1a8d36ac9a0faee8afa6dc2366db506f93401bf4165e93766435f3d7
|
7
|
+
data.tar.gz: 0bce3b21105e81dd1bc1d5656e941ceec30814bb01e19c16a7a5ee57eba98403093d7359eb9e113bd60b0850a87764b1241a08febe1881dcde74c303fb9d35be
|
data/Gemfile.lock
CHANGED
data/lib/cl/magic/cl-auth
CHANGED
@@ -61,6 +61,18 @@ def aws_okta(options)
|
|
61
61
|
# cmd = "aws-okta add" # old
|
62
62
|
# do work
|
63
63
|
if is_tty
|
64
|
+
|
65
|
+
# ensure we are logged in
|
66
|
+
begin
|
67
|
+
TTY::Command.new(:printer => :null).run("aws-okta exec #{options[:aws_profile]} -- env")
|
68
|
+
rescue TTY::Command::ExitError => e
|
69
|
+
if e.message.include? "Failed to authenticate"
|
70
|
+
@logger.info "authenticate first with: aws-okta add"
|
71
|
+
else
|
72
|
+
raise
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
64
76
|
puts
|
65
77
|
@logger.info "now export into your environment with"
|
66
78
|
puts
|
data/lib/cl/magic/cl-dk
CHANGED
@@ -41,7 +41,11 @@ end
|
|
41
41
|
|
42
42
|
def get_repo_basename()
|
43
43
|
command = "cd #{@working_dir} && basename $(git remote get-url origin 2> /dev/null) .git"
|
44
|
-
|
44
|
+
repo_basename = TTY::Command.new(:printer => :null).run(command).out.gsub('.git', '').strip.chomp
|
45
|
+
if repo_basename==".git" or repo_basename==""
|
46
|
+
return File.basename(@working_dir)
|
47
|
+
end
|
48
|
+
return repo_basename
|
45
49
|
end
|
46
50
|
|
47
51
|
def get_world_settings_filepath()
|
@@ -106,37 +110,35 @@ def print_dk_help(dk_parts_hash, dk_make_hash, args)
|
|
106
110
|
has_dk_commands = dk_parts_hash.keys.any?
|
107
111
|
|
108
112
|
if no_args or asked_for_help
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
puts " - World filepath: #{get_world_project_path()}"
|
119
|
-
puts ""
|
120
|
-
end
|
121
|
-
puts "PROJ PARTS"
|
122
|
-
dk_parts_hash.keys.each do |key|
|
123
|
-
print_dk_help_line(key, dk_parts_hash[key].fetch('help'))
|
124
|
-
end
|
125
|
-
puts ""
|
126
|
-
puts "YML TOKENS"
|
127
|
-
puts " - <dk-remove> removes section of yaml"
|
128
|
-
puts " - <dk-replace> replaces values in a yaml array"
|
129
|
-
puts " - <dk-world-path> absolute filepath to world directory"
|
130
|
-
puts " - <dk-project-path> absolute filepath to world/project directory"
|
131
|
-
puts " - <dk-working-path> absolute filepath to location dk command was run from"
|
132
|
-
puts ""
|
133
|
-
puts "ADDITIONAL TURNKEY COMMANDS"
|
134
|
-
puts " - dk set-world sets the location of the world directory"
|
135
|
-
puts " - dk make turnkey commands for a project"
|
136
|
-
puts " - dk set-parts save parts so they are automatically applied to commands"
|
113
|
+
puts ""
|
114
|
+
puts "Usage: dk [DK_PARTS] [COMPOSE_OPTIONS] COMPOSE_COMMAND"
|
115
|
+
puts ""
|
116
|
+
puts "Run docker compose while munging yamls in sophisticated ways."
|
117
|
+
puts ""
|
118
|
+
if get_repo_basename
|
119
|
+
puts "PROJ INFO"
|
120
|
+
puts " - Repo basename: #{get_repo_basename}"
|
121
|
+
puts " - World filepath: #{get_world_project_path()}"
|
137
122
|
puts ""
|
138
|
-
puts "-------------------------"
|
139
123
|
end
|
124
|
+
puts "PROJ PARTS"
|
125
|
+
dk_parts_hash.keys.each do |key|
|
126
|
+
print_dk_help_line(key, dk_parts_hash[key].fetch('help'))
|
127
|
+
end
|
128
|
+
puts ""
|
129
|
+
puts "YML TOKENS"
|
130
|
+
puts " - <dk-remove> removes section of yaml"
|
131
|
+
puts " - <dk-replace> replaces values in a yaml array"
|
132
|
+
puts " - <dk-world-path> absolute filepath to world directory"
|
133
|
+
puts " - <dk-project-path> absolute filepath to world/project directory"
|
134
|
+
puts " - <dk-working-path> absolute filepath to location dk command was run from"
|
135
|
+
puts ""
|
136
|
+
puts "ADDITIONAL TURNKEY COMMANDS"
|
137
|
+
puts " - dk set-world sets the location of the world directory"
|
138
|
+
puts " - dk make turnkey commands for a project"
|
139
|
+
puts " - dk set-parts save parts so they are automatically applied to commands"
|
140
|
+
puts ""
|
141
|
+
puts "-------------------------"
|
140
142
|
end
|
141
143
|
end
|
142
144
|
|
data/lib/cl/magic/cl-jira-fetch
CHANGED
@@ -12,8 +12,6 @@ require 'cl/magic/common/jira.rb'
|
|
12
12
|
require 'net/http'
|
13
13
|
require 'json'
|
14
14
|
|
15
|
-
require 'byebug'
|
16
|
-
|
17
15
|
@logger = get_logger()
|
18
16
|
@cl_cmd_name = File.basename(__FILE__).split('-').join(' ')
|
19
17
|
|
@@ -27,7 +25,7 @@ def do_work(options)
|
|
27
25
|
|
28
26
|
puts ""
|
29
27
|
@logger.wait "fetch epics"
|
30
|
-
epic_ids = jira.get_epic_ids(options[:project], options[:epic_wildcard])
|
28
|
+
epic_ids, epics = jira.get_epic_ids(options[:project], options[:epic_wildcard])
|
31
29
|
@logger.success "#{epic_ids.count} epics"
|
32
30
|
|
33
31
|
puts ""
|
@@ -44,8 +42,8 @@ def do_work(options)
|
|
44
42
|
@logger.wait "saving file"
|
45
43
|
output_filepath = File.join(@working_dir, options[:output_filename])
|
46
44
|
File.open(output_filepath, 'w') do |file|
|
47
|
-
issues.each do |
|
48
|
-
file.puts(
|
45
|
+
issues.each do |o|
|
46
|
+
file.puts(o.to_json)
|
49
47
|
end
|
50
48
|
end
|
51
49
|
|
@@ -122,7 +120,8 @@ write_history("""#{@cl_cmd_name} \\
|
|
122
120
|
--base-uri=#{options[:base_uri]} \\
|
123
121
|
--username=#{options[:username]} \\
|
124
122
|
--project=#{options[:project]} \\
|
125
|
-
--epic-wildcard=#{options[:epic_wildcard]}
|
123
|
+
--epic-wildcard=#{options[:epic_wildcard]} \\
|
124
|
+
--token
|
126
125
|
""")
|
127
126
|
|
128
127
|
do_work(options)
|
data/lib/cl/magic/cl-jira-stats
CHANGED
@@ -13,8 +13,6 @@ require 'cl/magic/common/jira.rb'
|
|
13
13
|
require 'net/http'
|
14
14
|
require 'json'
|
15
15
|
|
16
|
-
require 'byebug'
|
17
|
-
|
18
16
|
@logger = get_logger()
|
19
17
|
@cl_cmd_name = File.basename(__FILE__).split('-').join(' ')
|
20
18
|
|
@@ -28,70 +26,50 @@ def get_issues_from_datafile(options)
|
|
28
26
|
File.foreach(filepath) do |line|
|
29
27
|
issue = JSON.parse(line)
|
30
28
|
issuetype = issue["fields"]["issuetype"]["name"]
|
29
|
+
labels = issue["fields"]["labels"]
|
31
30
|
|
32
|
-
|
33
|
-
|
31
|
+
has_excluded_labels = (labels & options[:exclude_labels]).any?
|
32
|
+
is_excluded_issuetype = options[:exclude_issuetypes].include?(issuetype.downcase)
|
33
|
+
issues << issue unless has_excluded_labels or is_excluded_issuetype
|
34
34
|
end
|
35
35
|
return issues
|
36
36
|
end
|
37
37
|
|
38
|
-
def
|
39
|
-
return issues.collect {|i| Date.parse(i["fields"]["created"])}.sort.first
|
40
|
-
end
|
38
|
+
def in_range_issue_stats(issues, start_date, end_date, options)
|
41
39
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
40
|
+
def in_range_logs(start_date, end_date, issue)
|
41
|
+
return issue["status_changelogs"].select do |log|
|
42
|
+
(start_date..end_date).cover?(Date.parse(log["created"]))
|
43
|
+
end
|
49
44
|
end
|
50
|
-
end
|
51
45
|
|
52
|
-
|
53
|
-
|
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
|
46
|
+
# in-range
|
47
|
+
in_range_issues = issues.select do |issue|
|
59
48
|
|
60
|
-
|
49
|
+
# issue created date?
|
50
|
+
issue_in_range = Date.parse(issue["fields"]["created"]) < end_date
|
61
51
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
end
|
52
|
+
# logs created date?
|
53
|
+
logs_in_range = in_range_logs(start_date, end_date, issue).any?
|
54
|
+
|
55
|
+
# select if
|
56
|
+
(logs_in_range or issue_in_range)
|
68
57
|
end
|
69
58
|
|
70
|
-
#
|
71
|
-
return
|
59
|
+
# stat hashes
|
60
|
+
return in_range_issues.collect do |issue|
|
72
61
|
|
73
|
-
#
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
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
|
62
|
+
# most recent in-range log?
|
63
|
+
changelog = in_range_logs(start_date, end_date, issue)
|
64
|
+
.sort_by { |l| Date.parse(l["created"]) }.last
|
65
|
+
|
66
|
+
# yield stat hash
|
67
|
+
status = changelog ? changelog["toString"] : issue["fields"]["status"]["name"]
|
68
|
+
{
|
69
|
+
key: issue["key"],
|
70
|
+
issuetype: issue["fields"]["issuetype"]["name"],
|
71
|
+
status: status
|
72
|
+
}
|
95
73
|
end.compact
|
96
74
|
end
|
97
75
|
|
@@ -99,37 +77,70 @@ def print_stats(stat_hashes, start_date, end_date)
|
|
99
77
|
counts = {
|
100
78
|
start_date: start_date.strftime("%m-%d-%Y"),
|
101
79
|
end_date: end_date.strftime("%m-%d-%Y"),
|
80
|
+
total: 0,
|
102
81
|
total_todo: 0,
|
103
82
|
total_done: 0,
|
104
|
-
|
83
|
+
by_type: {}
|
105
84
|
}
|
106
|
-
return counts unless stat_hashes.any?
|
107
|
-
stat_hashes.each do |stat|
|
108
85
|
|
86
|
+
stat_hashes.each do |stat|
|
109
87
|
issuetype = stat[:issuetype]
|
110
88
|
status = stat[:status]
|
111
89
|
|
112
|
-
# count all
|
113
|
-
increment(counts, "status_#{issuetype.downcase.underscore}")
|
114
|
-
|
115
90
|
# count by status
|
116
91
|
case status
|
117
|
-
when "Ready","Rework","In Progress","In QA","Ready For Code Review","In Code Review"
|
92
|
+
when "To Do","Ready","Rework","In Progress","In QA","Ready For Code Review","In Code Review"
|
93
|
+
increment_type(counts, issuetype, :to_do)
|
118
94
|
increment(counts, :total_todo)
|
119
95
|
when "Ready to Deploy","Closed"
|
96
|
+
increment_type(counts, issuetype, :done)
|
120
97
|
increment(counts, :total_done)
|
121
|
-
|
122
|
-
|
98
|
+
else
|
99
|
+
# if status != "Won't Do"
|
100
|
+
# debugger
|
101
|
+
# end
|
123
102
|
end
|
103
|
+
|
104
|
+
# count totals
|
105
|
+
unless status=="Won't Do"
|
106
|
+
increment(counts, :total)
|
107
|
+
increment_type(counts, issuetype, :total)
|
108
|
+
end
|
109
|
+
|
124
110
|
end
|
125
111
|
return counts
|
126
112
|
end
|
127
113
|
|
114
|
+
def oldest_issue_date(issues)
|
115
|
+
return issues.collect {|i| Date.parse(i["fields"]["created"])}.sort.first.beginning_of_day
|
116
|
+
end
|
117
|
+
|
118
|
+
def increment_type(hash, type, status_category)
|
119
|
+
type = type.downcase.underscore
|
120
|
+
hash[:by_type][type] = {} unless hash[:by_type].key?(type)
|
121
|
+
hash[:by_type][type][status_category] ||= 0
|
122
|
+
hash[:by_type][type][status_category] += 1
|
123
|
+
end
|
124
|
+
|
128
125
|
def increment(hash, key)
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
126
|
+
hash[key] ||= 0
|
127
|
+
hash[key] += 1
|
128
|
+
end
|
129
|
+
|
130
|
+
def iter_date_range(start_date)
|
131
|
+
while start_date < Date.today.end_of_week
|
132
|
+
yield start_date.beginning_of_week.beginning_of_day, start_date.end_of_week.end_of_day
|
133
|
+
start_date += 1.weeks # increment
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def do_work(options)
|
138
|
+
issues = get_issues_from_datafile(options)
|
139
|
+
oldest_date = oldest_issue_date(issues).beginning_of_week
|
140
|
+
iter_date_range(oldest_date) do |start_date, end_date|
|
141
|
+
stat_hashes = in_range_issue_stats(issues, start_date, end_date, options)
|
142
|
+
counts = print_stats(stat_hashes, start_date, end_date)
|
143
|
+
puts counts # print each time range
|
133
144
|
end
|
134
145
|
end
|
135
146
|
|
@@ -160,6 +171,10 @@ global = OptionParser.new do |g|
|
|
160
171
|
options[:exclude_issuetypes] = v.split(',')
|
161
172
|
options[:exclude_issuetypes] << "Won't Do"
|
162
173
|
end
|
174
|
+
|
175
|
+
g.on("-l", "--exclude-labels CSV", "comma separated list of labels that will cause a ticket to be excluded") do |v|
|
176
|
+
options[:exclude_labels] = v.split(',')
|
177
|
+
end
|
163
178
|
end
|
164
179
|
|
165
180
|
#
|
@@ -171,10 +186,14 @@ global.parse(ARGV)
|
|
171
186
|
|
172
187
|
# prompt for missing options
|
173
188
|
ask_and_store_option(options, :data_filepath, "data_filepath: ")
|
189
|
+
options[:exclude_issuetypes] = [] if options[:exclude_issuetypes].nil?
|
190
|
+
options[:exclude_labels] = [] if options[:exclude_labels].nil?
|
174
191
|
|
175
192
|
# display full command
|
176
193
|
write_history("""#{@cl_cmd_name} \\
|
177
|
-
--data-filepath=#{options[:data_filepath]}
|
194
|
+
--data-filepath=#{options[:data_filepath]} \\
|
195
|
+
--exclude-issuetypes=#{options[:exclude_issuetypes].join(',')} \\
|
196
|
+
--exclude-labels=#{options[:exclude_labels].join(',')}
|
178
197
|
""")
|
179
198
|
|
180
199
|
do_work(options)
|
data/lib/cl/magic/cl-poll
CHANGED
@@ -17,10 +17,10 @@ require 'cl/magic/common/kubectl.rb'
|
|
17
17
|
# Features
|
18
18
|
#
|
19
19
|
|
20
|
-
def do_work(options)
|
20
|
+
def do_work(options, remaining_options)
|
21
21
|
while true
|
22
|
-
tty_command = TTY::Command.new(printer: :null)
|
23
|
-
out, err = tty_command.run(
|
22
|
+
tty_command = TTY::Command.new(printer: :null, pty: options[:pty])
|
23
|
+
out, err = tty_command.run("cd #{@working_dir} && #{remaining_options.join(' ')}")
|
24
24
|
puts out
|
25
25
|
puts
|
26
26
|
sleep(1)
|
@@ -31,7 +31,9 @@ end
|
|
31
31
|
# Options
|
32
32
|
#
|
33
33
|
|
34
|
-
options = {
|
34
|
+
options = {
|
35
|
+
pty: true
|
36
|
+
}
|
35
37
|
global_banner = <<DOC
|
36
38
|
|
37
39
|
A sandbox to try things
|
@@ -43,10 +45,23 @@ DOC
|
|
43
45
|
global = OptionParser.new do |g|
|
44
46
|
g.banner = global_banner
|
45
47
|
add_help_and_verbose(g)
|
48
|
+
|
49
|
+
g.on("--no-pty", "disable pseudo terminal") do |v|
|
50
|
+
options[:pty] = v
|
51
|
+
end
|
46
52
|
end
|
47
53
|
|
48
54
|
#
|
49
55
|
# Run
|
50
56
|
#
|
51
57
|
|
52
|
-
|
58
|
+
remaining_options = []
|
59
|
+
global.order! do |option|
|
60
|
+
remaining_options << option
|
61
|
+
end
|
62
|
+
|
63
|
+
global.parse(ARGV)
|
64
|
+
|
65
|
+
@working_dir = ENV['CL_WORKING_DIR'] # passed through cl-magic to here
|
66
|
+
|
67
|
+
do_work(options, remaining_options)
|
data/lib/cl/magic/common/jira.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'byebug'
|
2
1
|
|
3
2
|
class Jira
|
4
3
|
|
@@ -16,7 +15,9 @@ class Jira
|
|
16
15
|
def get_epic_ids(project, epic_wildcard)
|
17
16
|
jql_query = "project = \"#{project}\" AND issuetype = Epic AND text ~ \"#{epic_wildcard}\""
|
18
17
|
results = run_jql_query(jql_query)
|
19
|
-
|
18
|
+
epics = results.select{|h| h['fields']['summary'].start_with? epic_wildcard}
|
19
|
+
epic_ids = epics.map {|h| h['id']}
|
20
|
+
return epic_ids, epics
|
20
21
|
end
|
21
22
|
|
22
23
|
def get_issues(project, epic_ids)
|
@@ -153,7 +154,7 @@ def collect_status_changelogs(jira, issues, options)
|
|
153
154
|
# append them to issue
|
154
155
|
status_logs.each do |status_log|
|
155
156
|
issue["status_changelogs"] << status_log
|
156
|
-
end
|
157
|
+
end
|
157
158
|
end
|
158
159
|
|
159
160
|
final_issue_hashes << issue # save
|
data/lib/cl/magic/version.rb
CHANGED
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.
|
4
|
+
version: 0.4.0
|
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-07-
|
11
|
+
date: 2023-07-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|