abide_dev_utils 0.16.0 → 0.17.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|