abide_dev_utils 0.16.0 → 0.17.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 +34 -18
- data/abide_dev_utils.gemspec +2 -2
- data/lib/abide_dev_utils/cem/generate/reference.rb +14 -4
- data/lib/abide_dev_utils/cli/jira.rb +38 -31
- data/lib/abide_dev_utils/jira/client.rb +65 -0
- data/lib/abide_dev_utils/jira/client_builder.rb +107 -0
- data/lib/abide_dev_utils/jira/dry_run.rb +133 -0
- data/lib/abide_dev_utils/jira/finder.rb +62 -0
- data/lib/abide_dev_utils/jira/helper.rb +41 -0
- data/lib/abide_dev_utils/jira/issue_builder.rb +110 -0
- data/lib/abide_dev_utils/jira.rb +37 -165
- data/lib/abide_dev_utils/version.rb +1 -1
- metadata +18 -12
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0216511efe504da6597b81a7b494975377b8afe013697e37f9985467a6a4fa14
|
|
4
|
+
data.tar.gz: '08265323331b31cb17e875b951ce89dfcb83bbb9649c0df97513cff26355f713'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9cbd439058affe3311587d81d4dfe75191abe9f9fb1a1f8c964c2a8187f02cf9057943e4bacd5aaeb1676c936cccdd5e196b9d4a0822ed0c725d06fe0c46f0d3
|
|
7
|
+
data.tar.gz: f01c66b8079d9d257de1158f4a1f9f529b2e9e31c8eb04a19fa21fee63f34b2fa018b8e3bba8eefce2bf90d20f23249e27a83126f54057232aef6bd7658cbe0a
|
data/Gemfile.lock
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
abide_dev_utils (0.
|
|
4
|
+
abide_dev_utils (0.17.0)
|
|
5
5
|
cmdparse (~> 3.0)
|
|
6
6
|
facterdb (>= 1.21)
|
|
7
7
|
google-cloud-storage (~> 1.34)
|
|
8
8
|
hashdiff (~> 1.0)
|
|
9
9
|
jira-ruby (~> 2.2)
|
|
10
10
|
nokogiri (~> 1.13)
|
|
11
|
-
puppet (>=
|
|
11
|
+
puppet (>= 7.0.0)
|
|
12
12
|
puppet-strings (>= 2.7)
|
|
13
13
|
ruby-progressbar (~> 1.11)
|
|
14
14
|
selenium-webdriver (~> 4.0.0.beta4)
|
|
@@ -17,7 +17,7 @@ GEM
|
|
|
17
17
|
remote: https://rubygems.org/
|
|
18
18
|
specs:
|
|
19
19
|
CFPropertyList (2.3.6)
|
|
20
|
-
activesupport (7.0.
|
|
20
|
+
activesupport (7.0.7.2)
|
|
21
21
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
22
22
|
i18n (>= 1.6, < 2)
|
|
23
23
|
minitest (>= 5.1)
|
|
@@ -29,15 +29,15 @@ GEM
|
|
|
29
29
|
console (~> 1.10)
|
|
30
30
|
nio4r (~> 2.3)
|
|
31
31
|
timers (~> 4.1)
|
|
32
|
-
async-http (0.
|
|
32
|
+
async-http (0.60.2)
|
|
33
33
|
async (>= 1.25)
|
|
34
34
|
async-io (>= 1.28)
|
|
35
35
|
async-pool (>= 0.2)
|
|
36
|
-
protocol-http (~> 0.
|
|
37
|
-
protocol-http1 (~> 0.
|
|
38
|
-
protocol-http2 (~> 0.
|
|
39
|
-
traces (
|
|
40
|
-
async-http-faraday (0.
|
|
36
|
+
protocol-http (~> 0.24.0)
|
|
37
|
+
protocol-http1 (~> 0.15.0)
|
|
38
|
+
protocol-http2 (~> 0.15.0)
|
|
39
|
+
traces (>= 0.10.0)
|
|
40
|
+
async-http-faraday (0.12.0)
|
|
41
41
|
async-http (~> 0.42)
|
|
42
42
|
faraday
|
|
43
43
|
async-io (1.33.0)
|
|
@@ -69,7 +69,7 @@ GEM
|
|
|
69
69
|
faraday-http-cache (2.3.0)
|
|
70
70
|
faraday (>= 0.8)
|
|
71
71
|
faraday-net_http (2.0.3)
|
|
72
|
-
fast_gettext (
|
|
72
|
+
fast_gettext (2.3.0)
|
|
73
73
|
fiber-local (1.0.0)
|
|
74
74
|
gem-release (2.2.2)
|
|
75
75
|
github_changelog_generator (1.16.4)
|
|
@@ -120,7 +120,7 @@ GEM
|
|
|
120
120
|
hiera (3.12.0)
|
|
121
121
|
hocon (1.4.0)
|
|
122
122
|
httpclient (2.8.3)
|
|
123
|
-
i18n (1.
|
|
123
|
+
i18n (1.14.1)
|
|
124
124
|
concurrent-ruby (~> 1.0)
|
|
125
125
|
jgrep (1.5.4)
|
|
126
126
|
jira-ruby (2.3.0)
|
|
@@ -133,12 +133,16 @@ GEM
|
|
|
133
133
|
memoist (0.16.2)
|
|
134
134
|
method_source (1.0.0)
|
|
135
135
|
mini_mime (1.1.2)
|
|
136
|
-
minitest (5.
|
|
136
|
+
minitest (5.19.0)
|
|
137
137
|
multi_json (1.15.0)
|
|
138
138
|
multipart-post (2.3.0)
|
|
139
139
|
nio4r (2.5.8)
|
|
140
|
+
nokogiri (1.15.2-arm64-darwin)
|
|
141
|
+
racc (~> 1.4)
|
|
140
142
|
nokogiri (1.15.2-x86_64-darwin)
|
|
141
143
|
racc (~> 1.4)
|
|
144
|
+
nokogiri (1.15.2-x86_64-linux)
|
|
145
|
+
racc (~> 1.4)
|
|
142
146
|
oauth (0.6.2)
|
|
143
147
|
snaky_hash (~> 2.0)
|
|
144
148
|
version_gem (~> 1.1)
|
|
@@ -150,16 +154,27 @@ GEM
|
|
|
150
154
|
parser (3.1.2.0)
|
|
151
155
|
ast (~> 2.4.1)
|
|
152
156
|
protocol-hpack (1.4.2)
|
|
153
|
-
protocol-http (0.
|
|
154
|
-
protocol-http1 (0.
|
|
157
|
+
protocol-http (0.24.7)
|
|
158
|
+
protocol-http1 (0.15.1)
|
|
155
159
|
protocol-http (~> 0.22)
|
|
156
|
-
protocol-http2 (0.
|
|
160
|
+
protocol-http2 (0.15.1)
|
|
157
161
|
protocol-hpack (~> 1.4)
|
|
158
162
|
protocol-http (~> 0.18)
|
|
159
163
|
pry (0.14.1)
|
|
160
164
|
coderay (~> 1.1)
|
|
161
165
|
method_source (~> 1.0)
|
|
162
166
|
public_suffix (4.0.7)
|
|
167
|
+
puppet (7.24.0)
|
|
168
|
+
concurrent-ruby (~> 1.0, < 1.2.0)
|
|
169
|
+
deep_merge (~> 1.0)
|
|
170
|
+
facter (> 2.0.1, < 5)
|
|
171
|
+
fast_gettext (>= 1.1, < 3)
|
|
172
|
+
hiera (>= 3.2.1, < 4)
|
|
173
|
+
locale (~> 2.1)
|
|
174
|
+
multi_json (~> 1.10)
|
|
175
|
+
puppet-resource_api (~> 1.5)
|
|
176
|
+
scanf (~> 1.0)
|
|
177
|
+
semantic_puppet (~> 1.0)
|
|
163
178
|
puppet (7.24.0-universal-darwin)
|
|
164
179
|
CFPropertyList (~> 2.2)
|
|
165
180
|
concurrent-ruby (~> 1.0, < 1.2.0)
|
|
@@ -241,7 +256,7 @@ GEM
|
|
|
241
256
|
version_gem (~> 1.1, >= 1.1.1)
|
|
242
257
|
thor (1.2.2)
|
|
243
258
|
timers (4.3.3)
|
|
244
|
-
traces (0.
|
|
259
|
+
traces (0.11.1)
|
|
245
260
|
trailblazer-option (0.1.2)
|
|
246
261
|
tzinfo (2.0.6)
|
|
247
262
|
concurrent-ruby (~> 1.0)
|
|
@@ -252,6 +267,7 @@ GEM
|
|
|
252
267
|
yard (0.9.34)
|
|
253
268
|
|
|
254
269
|
PLATFORMS
|
|
270
|
+
arm64-darwin-22
|
|
255
271
|
x86_64-darwin-19
|
|
256
272
|
x86_64-darwin-20
|
|
257
273
|
x86_64-linux
|
|
@@ -260,7 +276,7 @@ DEPENDENCIES
|
|
|
260
276
|
abide_dev_utils!
|
|
261
277
|
bundler
|
|
262
278
|
console
|
|
263
|
-
fast_gettext (
|
|
279
|
+
fast_gettext (>= 2.0)
|
|
264
280
|
gem-release
|
|
265
281
|
github_changelog_generator
|
|
266
282
|
pry
|
|
@@ -273,4 +289,4 @@ DEPENDENCIES
|
|
|
273
289
|
rubocop-rspec (~> 2.1)
|
|
274
290
|
|
|
275
291
|
BUNDLED WITH
|
|
276
|
-
2.
|
|
292
|
+
2.4.19
|
data/abide_dev_utils.gemspec
CHANGED
|
@@ -34,7 +34,7 @@ Gem::Specification.new do |spec|
|
|
|
34
34
|
# Prod dependencies
|
|
35
35
|
spec.add_dependency 'nokogiri', '~> 1.13'
|
|
36
36
|
spec.add_dependency 'cmdparse', '~> 3.0'
|
|
37
|
-
spec.add_dependency 'puppet', '>=
|
|
37
|
+
spec.add_dependency 'puppet', '>= 7.0.0'
|
|
38
38
|
spec.add_dependency 'puppet-strings', '>= 2.7'
|
|
39
39
|
spec.add_dependency 'jira-ruby', '~> 2.2'
|
|
40
40
|
spec.add_dependency 'ruby-progressbar', '~> 1.11'
|
|
@@ -56,7 +56,7 @@ Gem::Specification.new do |spec|
|
|
|
56
56
|
spec.add_development_dependency 'rubocop-ast', '~> 1.4'
|
|
57
57
|
spec.add_development_dependency 'rubocop-performance', '~> 1.9'
|
|
58
58
|
spec.add_development_dependency 'rubocop-i18n', '~> 3.0'
|
|
59
|
-
spec.add_development_dependency 'fast_gettext', '
|
|
59
|
+
spec.add_development_dependency 'fast_gettext', '>= 2.0'
|
|
60
60
|
|
|
61
61
|
# For more information and examples about making a new gem, checkout our
|
|
62
62
|
# guide at: https://bundler.io/guides/creating_gem.html
|
|
@@ -382,7 +382,12 @@ module AbideDevUtils
|
|
|
382
382
|
# @valid_level is populated in verify_profile_and_level_selections from the fact that we've given
|
|
383
383
|
# the generator a list of levels we want to use. If we didn't give it a list of levels, then we
|
|
384
384
|
# want to use all of the levels that the control supports from @control.
|
|
385
|
-
@
|
|
385
|
+
if @framework == 'stig'
|
|
386
|
+
@md.add_ul('Supported MAC Levels:')
|
|
387
|
+
else
|
|
388
|
+
@md.add_ul('Supported Levels:')
|
|
389
|
+
end
|
|
390
|
+
|
|
386
391
|
if @valid_level.empty?
|
|
387
392
|
@control.levels.each do |l|
|
|
388
393
|
@md.add_ul(@md.code(l), indent: 1)
|
|
@@ -400,7 +405,12 @@ module AbideDevUtils
|
|
|
400
405
|
# @valid_profile is populated in verify_profile_and_level_selections from the fact that we've given
|
|
401
406
|
# the generator a list of profiles we want to use. If we didn't give it a list of profiles, then we
|
|
402
407
|
# want to use all of the profiles that the control supports from @control.
|
|
403
|
-
@
|
|
408
|
+
if @framework == 'stig'
|
|
409
|
+
@md.add_ul('Supported Confidentiality:')
|
|
410
|
+
else
|
|
411
|
+
@md.add_ul('Supported Profiles:')
|
|
412
|
+
end
|
|
413
|
+
|
|
404
414
|
if @valid_profile.empty?
|
|
405
415
|
@control.profiles.each do |l|
|
|
406
416
|
@md.add_ul(@md.code(l), indent: 1)
|
|
@@ -413,7 +423,7 @@ module AbideDevUtils
|
|
|
413
423
|
end
|
|
414
424
|
|
|
415
425
|
def control_alternate_ids_builder
|
|
416
|
-
return if @framework == 'stig'
|
|
426
|
+
# return if @framework == 'stig'
|
|
417
427
|
|
|
418
428
|
@md.add_ul('Alternate Config IDs:')
|
|
419
429
|
@control.alternate_ids.each do |l|
|
|
@@ -459,7 +469,7 @@ module AbideDevUtils
|
|
|
459
469
|
|
|
460
470
|
@control.title.nil? ? out_str.unshift(" #{@control.id.dump}:") : out_str.unshift(" #{@control.title.dump}:")
|
|
461
471
|
out_str.unshift(' control_configs:')
|
|
462
|
-
out_str.unshift("#{@module_name}::config:")
|
|
472
|
+
out_str.unshift("#{@module_name.split('-').last}::config:")
|
|
463
473
|
@md.add_ul('Hiera Configuration Example:')
|
|
464
474
|
@md.add_code_block(out_str.join("\n"), language: 'yaml')
|
|
465
475
|
rescue StandardError => e
|
|
@@ -6,9 +6,6 @@ require 'abide_dev_utils/jira'
|
|
|
6
6
|
|
|
7
7
|
module Abide
|
|
8
8
|
module CLI
|
|
9
|
-
CONFIG = AbideDevUtils::Config
|
|
10
|
-
JIRA = AbideDevUtils::Jira
|
|
11
|
-
|
|
12
9
|
class JiraCommand < CmdParse::Command
|
|
13
10
|
CMD_NAME = 'jira'
|
|
14
11
|
CMD_SHORT = 'Commands related to Jira tickets'
|
|
@@ -38,11 +35,9 @@ module Abide
|
|
|
38
35
|
end
|
|
39
36
|
|
|
40
37
|
def execute
|
|
41
|
-
|
|
42
|
-
myself = JIRA.myself(client)
|
|
43
|
-
return if myself.attrs['name'].empty?
|
|
38
|
+
return if AbideDevUtils::Jira.client.myself.attrs['displayName'].empty?
|
|
44
39
|
|
|
45
|
-
Abide::CLI::OUTPUT.simple("Successfully authenticated user #{myself.attrs['
|
|
40
|
+
Abide::CLI::OUTPUT.simple("Successfully authenticated user #{AbideDevUtils::Jira.client.myself.attrs['displayName']}!")
|
|
46
41
|
end
|
|
47
42
|
end
|
|
48
43
|
|
|
@@ -59,8 +54,7 @@ module Abide
|
|
|
59
54
|
end
|
|
60
55
|
|
|
61
56
|
def execute(issue)
|
|
62
|
-
|
|
63
|
-
issue = client.Issue.find(issue)
|
|
57
|
+
issue = AbideDevUtils::Jira.client.find(:issue, issue)
|
|
64
58
|
console = @data[:file].nil?
|
|
65
59
|
out_json = issue.attrs.select { |_, v| !v.nil? || !v.empty? }
|
|
66
60
|
Abide::CLI::OUTPUT.json(out_json, console: console, file: @data[:file])
|
|
@@ -83,13 +77,15 @@ module Abide
|
|
|
83
77
|
end
|
|
84
78
|
|
|
85
79
|
def execute(project, summary, *subtasks)
|
|
86
|
-
|
|
87
|
-
issue = JIRA.new_issue(client, project, summary)
|
|
80
|
+
issue = AbideDevUtils::Jira.client.create(:issue, project: project, summary: summary)
|
|
88
81
|
Abide::CLI::OUTPUT.simple("Successfully created #{issue.attrs['key']}")
|
|
89
82
|
return if subtasks.nil? || subtasks.empty?
|
|
90
83
|
|
|
91
84
|
Abide::CLI::OUTPUT.simple('Creatings subtasks...')
|
|
92
|
-
|
|
85
|
+
subtasks.each do |sum|
|
|
86
|
+
subtask = AbideDevUtils::Jira.client.create(:subtask, parent: issue, summary: sum)
|
|
87
|
+
Abide::CLI::OUTPUT.simple("Successfully created #{subtask.attrs['key']}")
|
|
88
|
+
end
|
|
93
89
|
end
|
|
94
90
|
end
|
|
95
91
|
|
|
@@ -107,11 +103,8 @@ module Abide
|
|
|
107
103
|
|
|
108
104
|
def execute(report, project)
|
|
109
105
|
Abide::CLI::VALIDATE.file(report)
|
|
110
|
-
@data[:dry_run] = false if @data[:dry_run].nil?
|
|
111
|
-
client = JIRA.client(options: {})
|
|
112
|
-
proj = JIRA.project(client, project)
|
|
113
106
|
File.open(report) do |f|
|
|
114
|
-
|
|
107
|
+
AbideDevUtils::Jira.new_issues_from_coverage(project, JSON.parse(f.read), dry_run: @data[:dry_run])
|
|
115
108
|
end
|
|
116
109
|
end
|
|
117
110
|
end
|
|
@@ -127,14 +120,30 @@ module Abide
|
|
|
127
120
|
argument_desc(PATH: 'An XCCDF file', PROJECT: 'A Jira project')
|
|
128
121
|
options.on('-d', '--dry-run', 'Print to console instead of saving objects') { |_| @data[:dry_run] = true }
|
|
129
122
|
options.on('-e [EPIC]', '--epic [EPIC]', 'If given, tasks will be created and assigned to this epic. Takes form <PROJECT>-<NUM>') { |e| @data[:epic] = e }
|
|
123
|
+
options.on('-l [LEVEL]', '--level [LEVEL]', 'Only create tasks for rules belonging to the matching level. Takes a string that is treated as RegExp') do |x|
|
|
124
|
+
@data[:level] = x
|
|
125
|
+
end
|
|
126
|
+
options.on('-p [PROFILE]', '--profile [PROFILE]', 'Only create tasks for rules belonging to the matching profile. Takes a string that is treated as RegExp') do |x|
|
|
127
|
+
@data[:profile] = x
|
|
128
|
+
end
|
|
130
129
|
end
|
|
131
130
|
|
|
132
131
|
def execute(path, project)
|
|
133
132
|
Abide::CLI::VALIDATE.file(path)
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
133
|
+
# Each control gets assigned labels based on the levels and profiles it supports.
|
|
134
|
+
# Those labels all take the form "level_<level>_<profile>". This allows us to
|
|
135
|
+
# filter the controls we want to create tasks for by level and profile.
|
|
136
|
+
@data[:label_include] = nil
|
|
137
|
+
@data[:label_include] = "level_#{@data[:level]}_" if @data[:level]
|
|
138
|
+
@data[:label_include] = "#{@data[:label_include]}#{@data[:profile]}" if @data[:profile]
|
|
139
|
+
Abide::CLI::Output.simple "Label include: #{@data[:label_include]}"
|
|
140
|
+
AbideDevUtils::Jira.new_issues_from_xccdf(
|
|
141
|
+
project,
|
|
142
|
+
path,
|
|
143
|
+
epic: @data[:epic],
|
|
144
|
+
dry_run: @data[:dry_run],
|
|
145
|
+
label_include: @data[:label_include],
|
|
146
|
+
)
|
|
138
147
|
end
|
|
139
148
|
end
|
|
140
149
|
|
|
@@ -167,17 +176,15 @@ module Abide
|
|
|
167
176
|
def execute(path1, path2, project)
|
|
168
177
|
Abide::CLI::VALIDATE.file(path1)
|
|
169
178
|
Abide::CLI::VALIDATE.file(path2)
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
auto_approve: @data[:auto_approve],
|
|
180
|
-
diff_opts: @data[:diff_opts])
|
|
179
|
+
AbideDevUtils::Jira.new_issues_from_xccdf_diff(
|
|
180
|
+
project,
|
|
181
|
+
path1,
|
|
182
|
+
path2,
|
|
183
|
+
epic: @data[:epic],
|
|
184
|
+
dry_run: @data[:dry_run],
|
|
185
|
+
auto_approve: @data[:auto_approve],
|
|
186
|
+
diff_opts: @data[:diff_opts],
|
|
187
|
+
)
|
|
181
188
|
end
|
|
182
189
|
end
|
|
183
190
|
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'client_builder'
|
|
4
|
+
require_relative 'dry_run'
|
|
5
|
+
require_relative 'finder'
|
|
6
|
+
require_relative 'helper'
|
|
7
|
+
require_relative 'issue_builder'
|
|
8
|
+
require_relative '../config'
|
|
9
|
+
require_relative '../errors/jira'
|
|
10
|
+
|
|
11
|
+
module AbideDevUtils
|
|
12
|
+
module Jira
|
|
13
|
+
class Client
|
|
14
|
+
extend DryRun
|
|
15
|
+
|
|
16
|
+
dry_run :create, :find, :myself
|
|
17
|
+
|
|
18
|
+
attr_accessor :default_project
|
|
19
|
+
attr_reader :config
|
|
20
|
+
|
|
21
|
+
def initialize(dry_run: false, **options)
|
|
22
|
+
@dry_run = dry_run
|
|
23
|
+
@options = options
|
|
24
|
+
@config = AbideDevUtils::Config.config_section('jira')
|
|
25
|
+
@default_project = @config[:default_project]
|
|
26
|
+
@client = nil
|
|
27
|
+
@finder = nil
|
|
28
|
+
@issue_builder = nil
|
|
29
|
+
@helper = nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def myself
|
|
33
|
+
@myself ||= finder.myself
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def find(type, id)
|
|
37
|
+
raise ArgumentError, "Invalid type #{type}" unless finder.respond_to?(type.to_sym)
|
|
38
|
+
|
|
39
|
+
finder.send(type.to_sym, id)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def create(type, **fields)
|
|
43
|
+
issue_builder.create(type, **fields)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def helper
|
|
47
|
+
@helper ||= Helper.new(self, dry_run: @dry_run)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def client
|
|
53
|
+
@client ||= ClientBuilder.new(@config, **@options).build
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def finder
|
|
57
|
+
@finder ||= Finder.new(client)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def issue_builder
|
|
61
|
+
@issue_builder ||= IssueBuilder.new(client, finder)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'jira-ruby'
|
|
4
|
+
require_relative '../prompt'
|
|
5
|
+
|
|
6
|
+
module AbideDevUtils
|
|
7
|
+
module Jira
|
|
8
|
+
class ClientBuilder
|
|
9
|
+
def initialize(config, **options)
|
|
10
|
+
@options = options
|
|
11
|
+
@config = config
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def username
|
|
15
|
+
find_option_value(:username)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def username=(username)
|
|
19
|
+
@options[:username] = username
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def password
|
|
23
|
+
if find_option_value(:password)
|
|
24
|
+
'********'
|
|
25
|
+
else
|
|
26
|
+
nil
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def password=(password)
|
|
31
|
+
@options[:password] = password
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def site
|
|
35
|
+
find_option_value(:site)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def site=(site)
|
|
39
|
+
@options[:site] = site
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def context_path
|
|
43
|
+
find_option_value(:context_path, default: '')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def context_path=(context_path)
|
|
47
|
+
@options[:context_path] = context_path
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def auth_type
|
|
51
|
+
find_option_value(:auth_type, default: :basic)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def auth_type=(auth_type)
|
|
55
|
+
@options[:auth_type] = auth_type
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def http_debug
|
|
59
|
+
find_option_value(:http_debug, default: false)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def http_debug=(http_debug)
|
|
63
|
+
@options[:http_debug] = http_debug
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def build
|
|
67
|
+
JIRA::Client.new({
|
|
68
|
+
username: find_option_value(:username, prompt: true),
|
|
69
|
+
password: find_option_value(:password, prompt: true),
|
|
70
|
+
site: find_option_value(:site, prompt: 'Jira site URL'),
|
|
71
|
+
context_path: find_option_value(:context_path, default: ''),
|
|
72
|
+
auth_type: find_option_value(:auth_type, default: :basic),
|
|
73
|
+
http_debug: find_option_value(:http_debug, default: false),
|
|
74
|
+
})
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
def find_option_value(key, default: nil, prompt: nil)
|
|
80
|
+
if prompt
|
|
81
|
+
find_option_value_or_prompt(key, prompt)
|
|
82
|
+
else
|
|
83
|
+
find_option_value_or_default(key, default)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def find_option_val(key)
|
|
88
|
+
@options[key] || @config[key] || ENV["JIRA_#{key.to_s.upcase}"]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def find_option_value_or_prompt(key, prompt = 'Enter value')
|
|
92
|
+
case key
|
|
93
|
+
when /password/i
|
|
94
|
+
find_option_val(key) || AbideDevUtils::Prompt.password
|
|
95
|
+
when /username/i
|
|
96
|
+
find_option_val(key) || AbideDevUtils::Prompt.username
|
|
97
|
+
else
|
|
98
|
+
find_option_val(key) || AbideDevUtils::Prompt.single_line(prompt)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def find_option_value_or_default(key, default)
|
|
103
|
+
find_option_val(key) || default
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../output'
|
|
4
|
+
|
|
5
|
+
module AbideDevUtils
|
|
6
|
+
module Jira
|
|
7
|
+
module DryRun
|
|
8
|
+
def dry_run(*method_names)
|
|
9
|
+
method_names.each do |method_name|
|
|
10
|
+
proxy = Module.new do
|
|
11
|
+
define_method(method_name) do |*args, **kwargs|
|
|
12
|
+
if !!@dry_run
|
|
13
|
+
case method_name
|
|
14
|
+
when %r{^create}
|
|
15
|
+
AbideDevUtils::Output.simple("DRY RUN: #{self.class.name}##{method_name}(#{args[0]}, #{args[1].map { |k, v| "#{k}: #{v.inspect}" }.join(', ')})")
|
|
16
|
+
sleep 0.1
|
|
17
|
+
return DummyIssue.new if args[0].match?(%r{^issue$})
|
|
18
|
+
return DummySubtask.new if args[0].match?(%r{^subtask$})
|
|
19
|
+
when %r{^find}
|
|
20
|
+
AbideDevUtils::Output.simple("DRY RUN: #{self.class.name}##{method_name}(#{args[0]}, #{args[1].inspect})")
|
|
21
|
+
return DummyIssue.new if args[0].match?(%r{^issue$})
|
|
22
|
+
return DummySubtask.new if args[0].match?(%r{^subtask$})
|
|
23
|
+
return DummyProject.new if args[0].match?(%r{^project$})
|
|
24
|
+
|
|
25
|
+
"Dummy #{args[0].capitalize}"
|
|
26
|
+
else
|
|
27
|
+
AbideDevUtils::Output.simple("DRY RUN: #{self.class.name}##{method_name}(#{args.map(&:inspect).join(', ')})")
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
super(*args, **kwargs)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
self.prepend(proxy)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def dry_run_simple(*method_names)
|
|
39
|
+
method_names.each do |method_name|
|
|
40
|
+
proxy = Module.new do
|
|
41
|
+
define_method(method_name) do |*args, **kwargs|
|
|
42
|
+
return if !!@dry_run
|
|
43
|
+
|
|
44
|
+
super(*args, **kwargs)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
self.prepend(proxy)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def dry_run_return_true(*method_names)
|
|
52
|
+
method_names.each do |method_name|
|
|
53
|
+
proxy = Module.new do
|
|
54
|
+
define_method(method_name) do |*args, **kwargs|
|
|
55
|
+
return true if !!@dry_run
|
|
56
|
+
|
|
57
|
+
super(*args, **kwargs)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
self.prepend(proxy)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def dry_run_return_false(*method_names)
|
|
65
|
+
method_names.each do |method_name|
|
|
66
|
+
proxy = Module.new do
|
|
67
|
+
define_method(method_name) do |*args, **kwargs|
|
|
68
|
+
return false if !!@dry_run
|
|
69
|
+
|
|
70
|
+
super(*args, **kwargs)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
self.prepend(proxy)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
class Dummy
|
|
78
|
+
attr_reader :dummy
|
|
79
|
+
|
|
80
|
+
def initialize
|
|
81
|
+
@dummy = true
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class DummyIssue < Dummy
|
|
86
|
+
attr_reader :summary, :key
|
|
87
|
+
|
|
88
|
+
def initialize
|
|
89
|
+
super
|
|
90
|
+
@summary = 'Dummy Issue'
|
|
91
|
+
@key = 'DUM-111'
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def attrs
|
|
95
|
+
{
|
|
96
|
+
'fields' => {
|
|
97
|
+
'project' => 'dummy',
|
|
98
|
+
'priority' => 'dummy',
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
class DummySubtask < DummyIssue
|
|
105
|
+
def initialize
|
|
106
|
+
super
|
|
107
|
+
@summary = 'Dummy Subtask'
|
|
108
|
+
@key = 'DUM-222'
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def attrs
|
|
112
|
+
{
|
|
113
|
+
'fields' => {
|
|
114
|
+
'project' => 'dummy',
|
|
115
|
+
'priority' => 'dummy',
|
|
116
|
+
'parent' => DummyIssue.new,
|
|
117
|
+
},
|
|
118
|
+
}
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
class DummyProject < Dummy
|
|
123
|
+
attr_reader :key, :issues
|
|
124
|
+
|
|
125
|
+
def initialize
|
|
126
|
+
super
|
|
127
|
+
@key = 'DUM'
|
|
128
|
+
@issues = [DummyIssue.new, DummySubtask.new]
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../errors/jira'
|
|
4
|
+
|
|
5
|
+
module AbideDevUtils
|
|
6
|
+
module Jira
|
|
7
|
+
class Finder
|
|
8
|
+
def initialize(client)
|
|
9
|
+
@client = client
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def myself
|
|
13
|
+
client.User.myself
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @param id [String] The project key or ID
|
|
17
|
+
def project(id)
|
|
18
|
+
return id if id.is_a?(client.Project.target_class)
|
|
19
|
+
|
|
20
|
+
client.Project.find(id)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @param id [String] The issue key or summary
|
|
24
|
+
def issue(id)
|
|
25
|
+
return id if id.is_a?(client.Issue.target_class)
|
|
26
|
+
|
|
27
|
+
client.Issue.find(id)
|
|
28
|
+
rescue URI::InvalidURIError
|
|
29
|
+
iss = client.Issue.all.find { |i| i.summary == id }
|
|
30
|
+
raise AbideDevUtils::Errors::Jira::FindIssueError, id if iss.nil?
|
|
31
|
+
|
|
32
|
+
iss
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @param id [String] The issuetype ID or name
|
|
36
|
+
def issuetype(id)
|
|
37
|
+
return id if id.is_a?(client.Issuetype.target_class)
|
|
38
|
+
|
|
39
|
+
if id.match?(%r{^\d+$})
|
|
40
|
+
client.Issuetype.find(id)
|
|
41
|
+
else
|
|
42
|
+
client.Issuetype.all.find { |i| i.name == id }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @param id [String] The priority ID or name
|
|
47
|
+
def priority(id)
|
|
48
|
+
return id if id.is_a?(client.Priority.target_class)
|
|
49
|
+
|
|
50
|
+
if id.match?(%r{^\d+$})
|
|
51
|
+
client.Priority.find(id)
|
|
52
|
+
else
|
|
53
|
+
client.Priority.all.find { |i| i.name == id }
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
attr_reader :client
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'dry_run'
|
|
4
|
+
|
|
5
|
+
module AbideDevUtils
|
|
6
|
+
module Jira
|
|
7
|
+
class Helper
|
|
8
|
+
extend DryRun
|
|
9
|
+
|
|
10
|
+
dry_run_simple :add_issue_label
|
|
11
|
+
dry_run_return_false :summary_exist?
|
|
12
|
+
|
|
13
|
+
def initialize(client, dry_run: false)
|
|
14
|
+
@client = client
|
|
15
|
+
@dry_run = dry_run
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @param project [JIRA::Resource::Project, String]
|
|
19
|
+
def all_project_issues_attrs(project)
|
|
20
|
+
project = @client.find(:project, project)
|
|
21
|
+
project.issues.collect(&:attrs)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @param issue [JIRA::Resource::Issue, String]
|
|
25
|
+
# @param label [String]
|
|
26
|
+
def add_issue_label(issue, label)
|
|
27
|
+
issue = @client.find(:issue, issue)
|
|
28
|
+
return if issue.labels.include?(label)
|
|
29
|
+
|
|
30
|
+
issue.labels << label
|
|
31
|
+
issue.save
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @param summary [String]
|
|
35
|
+
# @param issue_attrs [Array<Hash>]
|
|
36
|
+
def summary_exist?(summary, issue_attrs)
|
|
37
|
+
issue_attrs.any? { |attrs| attrs['fields'].key?('summary') && attrs['fields']['summary'] == summary }
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../errors/jira'
|
|
4
|
+
|
|
5
|
+
module AbideDevUtils
|
|
6
|
+
module Jira
|
|
7
|
+
class IssueBuilder
|
|
8
|
+
CUSTOM_FIELDS = {
|
|
9
|
+
'epic_link' => 'customfield_10014',
|
|
10
|
+
'epic_name' => 'customfield_10011',
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
13
|
+
FIELD_DEFAULTS = {
|
|
14
|
+
'issuetype' => 'Task',
|
|
15
|
+
'priority' => 'Medium',
|
|
16
|
+
'labels' => ['abide_dev_utils'],
|
|
17
|
+
}.freeze
|
|
18
|
+
|
|
19
|
+
REQUIRED_FIELDS = %w[project summary].freeze
|
|
20
|
+
|
|
21
|
+
def initialize(client, finder)
|
|
22
|
+
@client = client
|
|
23
|
+
@finder = finder
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def can_create?(type)
|
|
27
|
+
respond_to?("create_#{type}".to_sym, true)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def create(type, **fields)
|
|
31
|
+
type = type.to_s.downcase.to_sym
|
|
32
|
+
raise ArgumentError, "Invalid type \"#{type}\"; no method \"create_#{type}\"" unless can_create?(type)
|
|
33
|
+
|
|
34
|
+
fields = process_fields(fields)
|
|
35
|
+
send("create_#{type}".to_sym, **fields)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
attr_reader :client
|
|
41
|
+
|
|
42
|
+
def create_issue(**fields)
|
|
43
|
+
iss = client.Issue.build
|
|
44
|
+
iss.save({ 'fields' => fields })
|
|
45
|
+
iss
|
|
46
|
+
rescue StandardError => e
|
|
47
|
+
raise AbideDevUtils::Errors::Jira::CreateIssueError, e
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def create_subtask(**fields)
|
|
51
|
+
fields['parent'] = find_if_not_type(:issue, client.Issue.target_class, fields['parent'])
|
|
52
|
+
issue_fields = fields['parent'].attrs['fields']
|
|
53
|
+
fields['project'] = issue_fields['project']
|
|
54
|
+
fields['issuetype'] = find_if_not_type(:issuetype, client.Issuetype.target_class, 'Sub-task')
|
|
55
|
+
fields['priority'] = issue_fields['priority']
|
|
56
|
+
iss = client.Issue.build
|
|
57
|
+
iss.save({ 'fields' => fields })
|
|
58
|
+
iss
|
|
59
|
+
rescue StandardError => e
|
|
60
|
+
raise AbideDevUtils::Errors::Jira::CreateSubtaskError, e
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def process_fields(fields)
|
|
64
|
+
fields = fields.dup
|
|
65
|
+
normalize_field_keys!(fields)
|
|
66
|
+
validate_required_fields!(fields)
|
|
67
|
+
normalize_field_values(fields)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def validate_required_fields!(fields)
|
|
71
|
+
missing = REQUIRED_FIELDS.reject { |f| fields.key?(f) }
|
|
72
|
+
raise "Missing required field(s) \"#{missing}\"; present fields: \"#{fields.keys}\"" unless missing.empty?
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def normalize_field_keys!(fields)
|
|
76
|
+
fields.transform_keys! { |k| k.to_s.downcase }
|
|
77
|
+
fields.transform_keys! { |k| CUSTOM_FIELDS[k] || k }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def normalize_field_values(fields)
|
|
81
|
+
fields = FIELD_DEFAULTS.merge(fields).map do |k, v|
|
|
82
|
+
v = case k
|
|
83
|
+
when 'labels'
|
|
84
|
+
v.is_a?(Array) ? v : [v]
|
|
85
|
+
when 'issuetype'
|
|
86
|
+
find_if_not_type(:issuetype, client.Issuetype.target_class, v)
|
|
87
|
+
when 'parent'
|
|
88
|
+
find_if_not_type(:issue, client.Issue.target_class, v)
|
|
89
|
+
when 'priority'
|
|
90
|
+
find_if_not_type(:priority, client.Priority.target_class, v)
|
|
91
|
+
when 'epic_link', CUSTOM_FIELDS['epic_link']
|
|
92
|
+
find_if_not_type(:issue, client.Issue.target_class, v)&.key || v
|
|
93
|
+
when 'project'
|
|
94
|
+
find_if_not_type(:project, client.Project.target_class, v)
|
|
95
|
+
else
|
|
96
|
+
v
|
|
97
|
+
end
|
|
98
|
+
[k, v]
|
|
99
|
+
end
|
|
100
|
+
fields.to_h
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def find_if_not_type(typesym, typeklass, obj)
|
|
104
|
+
return obj if obj.is_a?(typeklass)
|
|
105
|
+
|
|
106
|
+
@finder.send(typesym, obj)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
data/lib/abide_dev_utils/jira.rb
CHANGED
|
@@ -5,6 +5,7 @@ require 'abide_dev_utils/output'
|
|
|
5
5
|
require 'abide_dev_utils/prompt'
|
|
6
6
|
require 'abide_dev_utils/config'
|
|
7
7
|
require 'abide_dev_utils/errors/jira'
|
|
8
|
+
require_relative 'jira/client'
|
|
8
9
|
|
|
9
10
|
module AbideDevUtils
|
|
10
11
|
module Jira
|
|
@@ -14,195 +15,58 @@ module AbideDevUtils
|
|
|
14
15
|
UPD_EPIC_SUMMARY_PREFIX = '::BENCHMARK UPDATE::'
|
|
15
16
|
PROGRESS_BAR_FORMAT = '%a %e %P% Created: %c of %C'
|
|
16
17
|
|
|
17
|
-
def self.
|
|
18
|
-
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def self.issue(client, issue)
|
|
22
|
-
client.Issue.find(issue)
|
|
23
|
-
rescue URI::InvalidURIError
|
|
24
|
-
iss = client.Issue.all.find { |i| i.summary == issue }
|
|
25
|
-
raise ERRORS::FindIssueError, issue unless iss
|
|
26
|
-
|
|
27
|
-
iss
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def self.myself(client)
|
|
31
|
-
client.User.myself
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def self.issuetype(client, id)
|
|
35
|
-
if id.match?(%r{^\d+$})
|
|
36
|
-
client.Issuetype.find(id)
|
|
37
|
-
else
|
|
38
|
-
client.Issuetype.all.find { |i| i.name == id }
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def self.priority(client, id)
|
|
43
|
-
if id.match?(%r{^\d+$})
|
|
44
|
-
client.Priority.find(id)
|
|
45
|
-
else
|
|
46
|
-
client.Priority.all.find { |i| i.name == id }
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def self.all_project_issues_attrs(project)
|
|
51
|
-
raw_issues = project.issues
|
|
52
|
-
raw_issues.collect(&:attrs)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def self.add_issue_label(iss, label, dry_run: false)
|
|
56
|
-
return if dry_run || iss.labels.include?(label)
|
|
57
|
-
|
|
58
|
-
iss.labels << profile_summary
|
|
59
|
-
iss.save
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def self.new_issue(client, project, summary, description: nil, labels: ['abide_dev_utils'], epic: nil, dry_run: false)
|
|
63
|
-
if dry_run
|
|
64
|
-
sleep(0.2)
|
|
65
|
-
return Dummy.new(summary)
|
|
66
|
-
end
|
|
67
|
-
fields = {}
|
|
68
|
-
fields['summary'] = summary
|
|
69
|
-
fields['project'] = project(client, project)
|
|
70
|
-
fields['reporter'] = myself(client)
|
|
71
|
-
fields['issuetype'] = issuetype(client, 'Task')
|
|
72
|
-
fields['priority'] = priority(client, '6')
|
|
73
|
-
fields['description'] = description if description
|
|
74
|
-
fields['labels'] = labels
|
|
75
|
-
epic = issue(client, epic) if epic && !epic.is_a?(JIRA::Resource::Issue)
|
|
76
|
-
fields['customfield_10006'] = epic.key if epic # Epic_Link
|
|
77
|
-
iss = client.Issue.build
|
|
78
|
-
raise ERRORS::CreateIssueError, iss.attrs unless iss.save({ 'fields' => fields })
|
|
79
|
-
|
|
80
|
-
iss
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def self.new_epic(client, project, summary, dry_run: false)
|
|
84
|
-
AbideDevUtils::Output.simple("#{dr_prefix(dry_run)}Creating epic '#{summary}'")
|
|
85
|
-
if dry_run
|
|
86
|
-
sleep(0.2)
|
|
87
|
-
return Dummy.new(summary)
|
|
88
|
-
end
|
|
89
|
-
fields = {
|
|
90
|
-
'summary' => summary,
|
|
91
|
-
'project' => project(client, project),
|
|
92
|
-
'reporter' => myself(client),
|
|
93
|
-
'issuetype' => issuetype(client, 'Epic'),
|
|
94
|
-
'customfield_10007' => summary, # Epic Name
|
|
95
|
-
}
|
|
96
|
-
iss = client.Issue.build
|
|
97
|
-
raise ERRORS::CreateEpicError, iss.attrs unless iss.save({ 'fields' => fields })
|
|
98
|
-
|
|
99
|
-
iss
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
# This should probably be threaded in the future
|
|
103
|
-
def self.bulk_new_issue(client, project, summaries, dry_run: false)
|
|
104
|
-
summaries.each { |s| new_issue(client, project, s, dry_run: dry_run) }
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def self.new_subtask(client, issue, summary, dry_run: false)
|
|
108
|
-
if dry_run
|
|
109
|
-
sleep(0.2)
|
|
110
|
-
return Dummy.new
|
|
111
|
-
end
|
|
112
|
-
issue_fields = issue.attrs['fields']
|
|
113
|
-
fields = {}
|
|
114
|
-
fields['parent'] = issue
|
|
115
|
-
fields['summary'] = summary
|
|
116
|
-
fields['project'] = issue_fields['project']
|
|
117
|
-
fields['reporter'] = myself(client)
|
|
118
|
-
fields['issuetype'] = issuetype(client, '5')
|
|
119
|
-
fields['priority'] = issue_fields['priority']
|
|
120
|
-
subtask = client.Issue.build
|
|
121
|
-
raise ERRORS::CreateSubtaskError, subtask.attrs unless subtask.save({ 'fields' => fields })
|
|
122
|
-
|
|
123
|
-
subtask
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def self.bulk_new_subtask(client, issue, summaries, dry_run: false)
|
|
127
|
-
summaries.each do |s|
|
|
128
|
-
new_subtask(client, issue, s, dry_run: dry_run)
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
def self.client(options: {})
|
|
133
|
-
opts = merge_options(options)
|
|
134
|
-
return client_from_prompts if opts.empty?
|
|
135
|
-
|
|
136
|
-
opts[:username] = AbideDevUtils::Prompt.username if opts[:username].nil?
|
|
137
|
-
opts[:password] = AbideDevUtils::Prompt.password if opts[:password].nil?
|
|
138
|
-
opts[:site] = AbideDevUtils::Prompt.single_line('Jira URL') if opts[:site].nil?
|
|
139
|
-
opts[:context_path] = '' if opts[:context_path].nil?
|
|
140
|
-
opts[:auth_type] = :basic if opts[:auth_type].nil?
|
|
141
|
-
JIRA::Client.new(opts)
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def self.client_from_prompts(http_debug: false)
|
|
145
|
-
options = {}
|
|
146
|
-
options[:username] = AbideDevUtils::Prompt.username
|
|
147
|
-
options[:password] = AbideDevUtils::Prompt.password
|
|
148
|
-
options[:site] = AbideDevUtils::Prompt.single_line('Jira URL')
|
|
149
|
-
options[:context_path] = ''
|
|
150
|
-
options[:auth_type] = :basic
|
|
151
|
-
options[:http_debug] = http_debug
|
|
152
|
-
JIRA::Client.new(options)
|
|
153
|
-
end
|
|
18
|
+
def self.client(memo: true, dry_run: false, **options)
|
|
19
|
+
return AbideDevUtils::Jira::Client.new(dry_run: dry_run, **options) unless memo
|
|
154
20
|
|
|
155
|
-
|
|
156
|
-
client = client_from_prompts(http_debug)
|
|
157
|
-
project = AbideDevUtils::Prompt.single_line('Project').upcase
|
|
158
|
-
client.Project.find(project)
|
|
21
|
+
@client ||= AbideDevUtils::Jira::Client.new(dry_run: dry_run, **options)
|
|
159
22
|
end
|
|
160
23
|
|
|
161
24
|
def self.new_issues_from_coverage(client, project, report, dry_run: false)
|
|
162
25
|
dr_prefix = dry_run ? 'DRY RUN: ' : ''
|
|
163
|
-
|
|
26
|
+
client(dry_run: dry_run) # Initializes the client if needed
|
|
27
|
+
i_attrs = client.helper.all_project_issues_attrs(project)
|
|
164
28
|
rep_sums = summaries_from_coverage_report(report)
|
|
165
29
|
rep_sums.each do |k, v|
|
|
166
|
-
next if summary_exist?(k, i_attrs)
|
|
30
|
+
next if client.helper.summary_exist?(k, i_attrs)
|
|
167
31
|
|
|
168
|
-
parent
|
|
169
|
-
|
|
170
|
-
parent_issue = issue(client, parent.attrs['key']) unless parent.respond_to?(:dummy)
|
|
32
|
+
AbideDevUtils::Output.simple("#{dr_prefix}Creating parent issue #{k}...")
|
|
33
|
+
parent = client.create(:issue, project: project, summary: k.to_s)
|
|
171
34
|
AbideDevUtils::Output.simple("#{dr_prefix}Creating subtasks, this can take a while...")
|
|
172
35
|
progress = AbideDevUtils::Output.progress(title: "#{dr_prefix}Creating Subtasks", total: nil)
|
|
173
36
|
v.each do |s|
|
|
174
|
-
next if summary_exist?(s, i_attrs)
|
|
37
|
+
next if client.helper.summary_exist?(s, i_attrs)
|
|
175
38
|
|
|
176
39
|
progress.title = "#{dr_prefix}#{s}"
|
|
177
|
-
|
|
40
|
+
client.create(:subtask, parent: parent, summary: s)
|
|
178
41
|
progress.increment
|
|
179
42
|
end
|
|
180
43
|
end
|
|
181
44
|
end
|
|
182
45
|
|
|
183
|
-
def self.new_issues_from_xccdf(
|
|
184
|
-
|
|
46
|
+
def self.new_issues_from_xccdf(project, xccdf_path, epic: nil, dry_run: false, label_include: nil)
|
|
47
|
+
client(dry_run: dry_run) # Initializes the client if needed
|
|
48
|
+
i_attrs = client.helper.all_project_issues_attrs(project)
|
|
185
49
|
xccdf = AbideDevUtils::XCCDF::Benchmark.new(xccdf_path)
|
|
186
50
|
# We need to get the actual epic Issue object, or create it if it doesn't exist
|
|
187
51
|
epic = if epic.nil?
|
|
188
52
|
new_epic_summary = "#{COV_PARENT_SUMMARY_PREFIX}#{xccdf.title}"
|
|
189
|
-
if summary_exist?(new_epic_summary, i_attrs)
|
|
190
|
-
issue
|
|
53
|
+
if client.helper.summary_exist?(new_epic_summary, i_attrs)
|
|
54
|
+
client.find(:issue, new_epic_summary)
|
|
191
55
|
else
|
|
192
56
|
unless AbideDevUtils::Prompt.yes_no("#{dr_prefix(dry_run)}Create new epic '#{new_epic_summary}'?")
|
|
193
57
|
AbideDevUtils::Output.simple("#{dr_prefix(dry_run)}Aborting")
|
|
194
58
|
exit(0)
|
|
195
59
|
end
|
|
196
|
-
|
|
60
|
+
client.create(:issue, project: project, summary: new_epic_summary, issuetype: 'Epic', epic_name: new_epic_summary)
|
|
197
61
|
end
|
|
198
62
|
else
|
|
199
|
-
issue
|
|
63
|
+
client.find(:issue, epic)
|
|
200
64
|
end
|
|
201
65
|
# Now we need to find out which issues we need to create for the benchmark
|
|
202
66
|
# The profiles that the control belongs to will be added as an issue label
|
|
203
67
|
to_create = {}
|
|
204
68
|
summaries_from_xccdf(xccdf).each do |profile_summary, control_summaries|
|
|
205
|
-
control_summaries.reject { |s| summary_exist?(s, i_attrs) }.each do |control_summary|
|
|
69
|
+
control_summaries.reject { |s| client.helper.summary_exist?(s, i_attrs) }.each do |control_summary|
|
|
206
70
|
if to_create.key?(control_summary)
|
|
207
71
|
to_create[control_summary] << profile_summary.split.join('_').downcase
|
|
208
72
|
else
|
|
@@ -211,6 +75,13 @@ module AbideDevUtils
|
|
|
211
75
|
end
|
|
212
76
|
end
|
|
213
77
|
|
|
78
|
+
# If we have a label_include, we need to filter out any controls that don't have that label
|
|
79
|
+
unless label_include.nil?
|
|
80
|
+
to_create = to_create.select do |_control_summary, labels|
|
|
81
|
+
labels.any? { |l| l.match?(label_include) }
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
214
85
|
unless AbideDevUtils::Prompt.yes_no("#{dr_prefix(dry_run)}Create #{to_create.keys.count} new Jira issues?")
|
|
215
86
|
AbideDevUtils::Output.simple("#{dr_prefix(dry_run)}Aborting")
|
|
216
87
|
exit(0)
|
|
@@ -222,31 +93,32 @@ module AbideDevUtils
|
|
|
222
93
|
to_create.each do |control_summary, labels|
|
|
223
94
|
abrev = control_summary.length > 40 ? control_summary[0..60] : control_summary
|
|
224
95
|
progress.log("#{dr_prefix(dry_run)}Creating #{abrev}...")
|
|
225
|
-
|
|
96
|
+
client.create(:issue, project: project, summary: control_summary, labels: labels, epic_link: epic)
|
|
226
97
|
progress.increment
|
|
227
98
|
end
|
|
228
99
|
progress.finish
|
|
229
100
|
AbideDevUtils::Output.simple("#{dr_prefix(dry_run)}Done creating tasks in Epic '#{epic.summary}'")
|
|
230
101
|
end
|
|
231
102
|
|
|
232
|
-
def self.new_issues_from_xccdf_diff(
|
|
103
|
+
def self.new_issues_from_xccdf_diff(project, xccdf1_path, xccdf2_path, epic: nil, dry_run: false, auto_approve: false, diff_opts: {})
|
|
233
104
|
require 'abide_dev_utils/xccdf/diff'
|
|
234
105
|
diff = AbideDevUtils::XCCDF::Diff::BenchmarkDiff.new(xccdf1_path, xccdf2_path, diff_opts)
|
|
235
|
-
|
|
106
|
+
client(dry_run: dry_run) # Initializes the client if needed
|
|
107
|
+
i_attrs = client.helper.all_project_issues_attrs(project)
|
|
236
108
|
# We need to get the actual epic Issue object, or create it if it doesn't exist
|
|
237
109
|
epic = if epic.nil?
|
|
238
|
-
new_epic_summary = "#{
|
|
239
|
-
if summary_exist?(new_epic_summary, i_attrs)
|
|
240
|
-
issue
|
|
110
|
+
new_epic_summary = "#{COV_PARENT_SUMMARY_PREFIX}#{xccdf.title}"
|
|
111
|
+
if client.helper.summary_exist?(new_epic_summary, i_attrs)
|
|
112
|
+
client.find(:issue, new_epic_summary)
|
|
241
113
|
else
|
|
242
|
-
unless AbideDevUtils::Prompt.yes_no("#{dr_prefix(dry_run)}Create new epic '#{new_epic_summary}'?"
|
|
114
|
+
unless AbideDevUtils::Prompt.yes_no("#{dr_prefix(dry_run)}Create new epic '#{new_epic_summary}'?")
|
|
243
115
|
AbideDevUtils::Output.simple("#{dr_prefix(dry_run)}Aborting")
|
|
244
116
|
exit(0)
|
|
245
117
|
end
|
|
246
|
-
|
|
118
|
+
client.create(:issue, project: project, summary: new_epic_summary, issuetype: 'Epic', epic_name: new_epic_summary)
|
|
247
119
|
end
|
|
248
120
|
else
|
|
249
|
-
issue
|
|
121
|
+
client.find(:issue, epic)
|
|
250
122
|
end
|
|
251
123
|
to_create = {}
|
|
252
124
|
diff.diff[:rules].each do |key, val|
|
|
@@ -288,7 +160,7 @@ module AbideDevUtils
|
|
|
288
160
|
format: PROGRESS_BAR_FORMAT)
|
|
289
161
|
approved_create.each do |summary, description|
|
|
290
162
|
progress.log("#{dr_prefix(dry_run)}Creating #{summary}...")
|
|
291
|
-
|
|
163
|
+
client.create(:issue, project: project, summary: summary, description: description, labels: [], epic_link: epic)
|
|
292
164
|
progress.increment
|
|
293
165
|
end
|
|
294
166
|
progress.finish
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: abide_dev_utils
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.17.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- abide-team
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-
|
|
11
|
+
date: 2023-11-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: nokogiri
|
|
@@ -44,14 +44,14 @@ dependencies:
|
|
|
44
44
|
requirements:
|
|
45
45
|
- - ">="
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version:
|
|
47
|
+
version: 7.0.0
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - ">="
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version:
|
|
54
|
+
version: 7.0.0
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: puppet-strings
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -322,16 +322,16 @@ dependencies:
|
|
|
322
322
|
name: fast_gettext
|
|
323
323
|
requirement: !ruby/object:Gem::Requirement
|
|
324
324
|
requirements:
|
|
325
|
-
- - "
|
|
325
|
+
- - ">="
|
|
326
326
|
- !ruby/object:Gem::Version
|
|
327
|
-
version: '
|
|
327
|
+
version: '2.0'
|
|
328
328
|
type: :development
|
|
329
329
|
prerelease: false
|
|
330
330
|
version_requirements: !ruby/object:Gem::Requirement
|
|
331
331
|
requirements:
|
|
332
|
-
- - "
|
|
332
|
+
- - ">="
|
|
333
333
|
- !ruby/object:Gem::Version
|
|
334
|
-
version: '
|
|
334
|
+
version: '2.0'
|
|
335
335
|
description: Provides a CLI with helpful utilities for developing compliance Puppet
|
|
336
336
|
code
|
|
337
337
|
email:
|
|
@@ -404,6 +404,12 @@ files:
|
|
|
404
404
|
- lib/abide_dev_utils/files.rb
|
|
405
405
|
- lib/abide_dev_utils/gcloud.rb
|
|
406
406
|
- lib/abide_dev_utils/jira.rb
|
|
407
|
+
- lib/abide_dev_utils/jira/client.rb
|
|
408
|
+
- lib/abide_dev_utils/jira/client_builder.rb
|
|
409
|
+
- lib/abide_dev_utils/jira/dry_run.rb
|
|
410
|
+
- lib/abide_dev_utils/jira/finder.rb
|
|
411
|
+
- lib/abide_dev_utils/jira/helper.rb
|
|
412
|
+
- lib/abide_dev_utils/jira/issue_builder.rb
|
|
407
413
|
- lib/abide_dev_utils/markdown.rb
|
|
408
414
|
- lib/abide_dev_utils/mixins.rb
|
|
409
415
|
- lib/abide_dev_utils/output.rb
|
|
@@ -448,7 +454,7 @@ metadata:
|
|
|
448
454
|
homepage_uri: https://github.com/puppetlabs/abide_dev_utils
|
|
449
455
|
source_code_uri: https://github.com/puppetlabs/abide_dev_utils
|
|
450
456
|
changelog_uri: https://github.com/puppetlabs/abide_dev_utils
|
|
451
|
-
post_install_message:
|
|
457
|
+
post_install_message:
|
|
452
458
|
rdoc_options: []
|
|
453
459
|
require_paths:
|
|
454
460
|
- lib
|
|
@@ -463,8 +469,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
463
469
|
- !ruby/object:Gem::Version
|
|
464
470
|
version: '0'
|
|
465
471
|
requirements: []
|
|
466
|
-
rubygems_version: 3.
|
|
467
|
-
signing_key:
|
|
472
|
+
rubygems_version: 3.4.18
|
|
473
|
+
signing_key:
|
|
468
474
|
specification_version: 4
|
|
469
475
|
summary: Helper utilities for developing compliance Puppet code
|
|
470
476
|
test_files: []
|