abide_dev_utils 0.17.0 → 0.17.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0216511efe504da6597b81a7b494975377b8afe013697e37f9985467a6a4fa14
4
- data.tar.gz: '08265323331b31cb17e875b951ce89dfcb83bbb9649c0df97513cff26355f713'
3
+ metadata.gz: ba0491c8fbcaa0a69015c410a2aa7e61ac61e6b30caca6fb5b334d22fd77069c
4
+ data.tar.gz: 119c837a5ea897957e63744ec3f38a7567222d7dbb5b952302ec71cd70aafc24
5
5
  SHA512:
6
- metadata.gz: 9cbd439058affe3311587d81d4dfe75191abe9f9fb1a1f8c964c2a8187f02cf9057943e4bacd5aaeb1676c936cccdd5e196b9d4a0822ed0c725d06fe0c46f0d3
7
- data.tar.gz: f01c66b8079d9d257de1158f4a1f9f529b2e9e31c8eb04a19fa21fee63f34b2fa018b8e3bba8eefce2bf90d20f23249e27a83126f54057232aef6bd7658cbe0a
6
+ metadata.gz: 492066b562bee8dd3c3d3b465396a569d66a66200018bb74e606c8f3a78320853ecc71a8f30ee0c4f18194dbdc0d8679ff8c32fd38fbaf7936267eae1b35d5eb
7
+ data.tar.gz: 2766d7c84c887b573cd9cb23f5d2aa869a4f238e5208ab2377832827e88d44056d180226a31c93ee242ed954d6aaf65b0e075d282b65ba53ea475ae1adb8e45a
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- abide_dev_utils (0.17.0)
4
+ abide_dev_utils (0.17.1)
5
5
  cmdparse (~> 3.0)
6
6
  facterdb (>= 1.21)
7
7
  google-cloud-storage (~> 1.34)
@@ -118,7 +118,12 @@ module Abide
118
118
  short_desc(CMD_SHORT)
119
119
  long_desc(CMD_LONG)
120
120
  argument_desc(PATH: 'An XCCDF file', PROJECT: 'A Jira project')
121
- options.on('-d', '--dry-run', 'Print to console instead of saving objects') { |_| @data[:dry_run] = true }
121
+ options.on('-d', '--dry-run', 'Runs through mock issue creation. Useful for testing, but not reliable for knowing what exactly will be created. Use --explain for more accurate information.') do
122
+ @data[:dry_run] = true
123
+ end
124
+ options.on('-x', '--explain', 'Shows a report of all the controls that will and won\'t be created as issues, and why. DOES NOT create issues.') do
125
+ @data[:explain] = true
126
+ end
122
127
  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
128
  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
129
  @data[:level] = x
@@ -136,12 +141,13 @@ module Abide
136
141
  @data[:label_include] = nil
137
142
  @data[:label_include] = "level_#{@data[:level]}_" if @data[:level]
138
143
  @data[:label_include] = "#{@data[:label_include]}#{@data[:profile]}" if @data[:profile]
139
- Abide::CLI::Output.simple "Label include: #{@data[:label_include]}"
144
+ Abide::CLI::OUTPUT.simple "Label include: #{@data[:label_include]}"
140
145
  AbideDevUtils::Jira.new_issues_from_xccdf(
141
146
  project,
142
147
  path,
143
148
  epic: @data[:epic],
144
149
  dry_run: @data[:dry_run],
150
+ explain: @data[:explain],
145
151
  label_include: @data[:label_include],
146
152
  )
147
153
  end
@@ -47,6 +47,10 @@ module AbideDevUtils
47
47
  @helper ||= Helper.new(self, dry_run: @dry_run)
48
48
  end
49
49
 
50
+ def translate_issue_custom_field(name)
51
+ IssueBuilder::CUSTOM_FIELDS[name] || IssueBuilder::CUSTOM_FIELDS.invert[name]
52
+ end
53
+
50
54
  private
51
55
 
52
56
  def client
@@ -12,19 +12,20 @@ module AbideDevUtils
12
12
  if !!@dry_run
13
13
  case method_name
14
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(', ')})")
15
+ AbideDevUtils::Output.simple("DRY RUN: #{self.class.name}##{method_name}(#{args[0]}, #{kwargs.map { |k, v| "#{k}: #{v.inspect}" }.join(', ')})")
16
16
  sleep 0.1
17
17
  return DummyIssue.new if args[0].match?(%r{^issue$})
18
18
  return DummySubtask.new if args[0].match?(%r{^subtask$})
19
19
  when %r{^find}
20
- AbideDevUtils::Output.simple("DRY RUN: #{self.class.name}##{method_name}(#{args[0]}, #{args[1].inspect})")
20
+ AbideDevUtils::Output.simple("DRY RUN: #{self.class.name}##{method_name}(#{args[0]}, #{kwargs.inspect})")
21
21
  return DummyIssue.new if args[0].match?(%r{^issue$})
22
22
  return DummySubtask.new if args[0].match?(%r{^subtask$})
23
23
  return DummyProject.new if args[0].match?(%r{^project$})
24
+ return [] if args[0].match?(%r{^issues_by_jql$})
24
25
 
25
26
  "Dummy #{args[0].capitalize}"
26
27
  else
27
- AbideDevUtils::Output.simple("DRY RUN: #{self.class.name}##{method_name}(#{args.map(&:inspect).join(', ')})")
28
+ AbideDevUtils::Output.simple("DRY RUN: #{self.class.name}##{method_name}(#{args.map(&:inspect).join(', ')}, #{kwargs.map { |k, v| "#{k}: #{v.inspect}" }.join(', ')})")
28
29
  end
29
30
  else
30
31
  super(*args, **kwargs)
@@ -77,7 +78,7 @@ module AbideDevUtils
77
78
  class Dummy
78
79
  attr_reader :dummy
79
80
 
80
- def initialize
81
+ def initialize(*_args, **_kwargs)
81
82
  @dummy = true
82
83
  end
83
84
  end
@@ -85,10 +86,14 @@ module AbideDevUtils
85
86
  class DummyIssue < Dummy
86
87
  attr_reader :summary, :key
87
88
 
88
- def initialize
89
+ def initialize(summary = 'Dummy Issue', key = 'DUM-111')
89
90
  super
90
- @summary = 'Dummy Issue'
91
- @key = 'DUM-111'
91
+ @summary = summary
92
+ @key = key
93
+ end
94
+
95
+ def labels
96
+ @labels ||= ['abide_dev_utils']
92
97
  end
93
98
 
94
99
  def attrs
@@ -102,10 +107,8 @@ module AbideDevUtils
102
107
  end
103
108
 
104
109
  class DummySubtask < DummyIssue
105
- def initialize
106
- super
107
- @summary = 'Dummy Subtask'
108
- @key = 'DUM-222'
110
+ def initialize(summary = 'Dummy Subtask', key = 'DUM-222')
111
+ super(summary, key)
109
112
  end
110
113
 
111
114
  def attrs
@@ -122,7 +125,7 @@ module AbideDevUtils
122
125
  class DummyProject < Dummy
123
126
  attr_reader :key, :issues
124
127
 
125
- def initialize
128
+ def initialize(key = 'DUM', issues = [DummyIssue.new, DummySubtask.new])
126
129
  super
127
130
  @key = 'DUM'
128
131
  @issues = [DummyIssue.new, DummySubtask.new]
@@ -32,6 +32,12 @@ module AbideDevUtils
32
32
  iss
33
33
  end
34
34
 
35
+ # @param jql [String] The JQL query
36
+ # @return [Array<JIRA::Resource::Issue>]
37
+ def issues_by_jql(jql)
38
+ client.Issue.jql(jql, max_results: 1000)
39
+ end
40
+
35
41
  # @param id [String] The issuetype ID or name
36
42
  def issuetype(id)
37
43
  return id if id.is_a?(client.Issuetype.target_class)
@@ -43,7 +43,9 @@ module AbideDevUtils
43
43
  end
44
44
  end
45
45
 
46
- def self.new_issues_from_xccdf(project, xccdf_path, epic: nil, dry_run: false, label_include: nil)
46
+ ToCreateData = Struct.new(:summary, :labels, :should_create, :metadata)
47
+
48
+ def self.new_issues_from_xccdf(project, xccdf_path, epic: nil, dry_run: false, explain: false, label_include: nil)
47
49
  client(dry_run: dry_run) # Initializes the client if needed
48
50
  i_attrs = client.helper.all_project_issues_attrs(project)
49
51
  xccdf = AbideDevUtils::XCCDF::Benchmark.new(xccdf_path)
@@ -64,42 +66,112 @@ module AbideDevUtils
64
66
  end
65
67
  # Now we need to find out which issues we need to create for the benchmark
66
68
  # The profiles that the control belongs to will be added as an issue label
67
- to_create = {}
69
+ to_create = []
68
70
  summaries_from_xccdf(xccdf).each do |profile_summary, control_summaries|
69
- control_summaries.reject { |s| client.helper.summary_exist?(s, i_attrs) }.each do |control_summary|
70
- if to_create.key?(control_summary)
71
- to_create[control_summary] << profile_summary.split.join('_').downcase
71
+ control_summaries.each do |control_summary|
72
+ existing_to_create = to_create.find { |tc| tc.summary == control_summary }
73
+ if existing_to_create
74
+ existing_to_create.labels << profile_summary.split.join('_').downcase
72
75
  else
73
- to_create[control_summary] = [profile_summary.split.join('_').downcase]
76
+ new_to_create = ToCreateData.new(
77
+ summary: control_summary,
78
+ labels: [profile_summary.split.join('_').downcase],
79
+ should_create: true,
80
+ metadata: {
81
+ epic_key: epic.key,
82
+ project: project,
83
+ },
84
+ )
85
+ to_create << new_to_create
74
86
  end
75
87
  end
76
88
  end
77
89
 
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
90
+ final_to_create = filter_to_create(to_create, label_include, project, epic)
91
+
92
+ return explain_this(to_create) if explain
84
93
 
85
- unless AbideDevUtils::Prompt.yes_no("#{dr_prefix(dry_run)}Create #{to_create.keys.count} new Jira issues?")
94
+ unless AbideDevUtils::Prompt.yes_no("#{dr_prefix(dry_run)}Create #{final_to_create.count} new Jira issues?")
86
95
  AbideDevUtils::Output.simple("#{dr_prefix(dry_run)}Aborting")
87
96
  exit(0)
88
97
  end
89
98
 
90
99
  progress = AbideDevUtils::Output.progress(title: "#{dr_prefix(dry_run)}Creating issues",
91
- total: to_create.keys.count,
100
+ total: final_to_create.count,
92
101
  format: PROGRESS_BAR_FORMAT)
93
- to_create.each do |control_summary, labels|
94
- abrev = control_summary.length > 40 ? control_summary[0..60] : control_summary
102
+ final_to_create.each do |tc|
103
+ abrev = tc.summary.length > 40 ? tc.summary[0..60] : tc.summary
95
104
  progress.log("#{dr_prefix(dry_run)}Creating #{abrev}...")
96
- client.create(:issue, project: project, summary: control_summary, labels: labels, epic_link: epic)
105
+ client.create(:issue, project: project, summary: tc.summary, labels: tc.labels, epic_link: epic)
97
106
  progress.increment
98
107
  end
99
108
  progress.finish
100
109
  AbideDevUtils::Output.simple("#{dr_prefix(dry_run)}Done creating tasks in Epic '#{epic.summary}'")
101
110
  end
102
111
 
112
+ def self.filter_to_create(to_create, label_include, project, epic)
113
+ not_already_exists = filter_already_exists(to_create, project, epic)
114
+ AbideDevUtils::Output.simple(
115
+ "Filtered out #{to_create.count - not_already_exists.count} issues that already existed",
116
+ )
117
+ only_label_include = filter_label_include(not_already_exists, label_include)
118
+ AbideDevUtils::Output.simple(
119
+ "Filtered out #{not_already_exists.count - only_label_include.count} issues that didn't include the label #{label_include}",
120
+ )
121
+ only_label_include
122
+ end
123
+
124
+ def self.filter_already_exists(to_create, project, epic)
125
+ AbideDevUtils::Output.simple('Checking if issues already exist...')
126
+ project = client.find(:project, project)
127
+ epic = client.find(:issue, epic)
128
+ issues = client.find(:issues_by_jql, "project = \"#{project.key}\" AND 'Epic Link' = \"#{epic.key}\"")
129
+ to_create.reject do |tc|
130
+ if issues.any? { |i| i.summary == tc.summary }
131
+ tc.metadata[:already_exists] = true
132
+ tc.should_create = false
133
+ true
134
+ else
135
+ tc.metadata[:already_exists] = false
136
+ false
137
+ end
138
+ end
139
+ end
140
+
141
+ # If we have a label_include, we need to filter out any controls that don't have that label
142
+ def self.filter_label_include(to_create, label_include)
143
+ return to_create if label_include.nil?
144
+
145
+ AbideDevUtils::Output.simple("Filtering out controls that don't match label include: #{label_include}")
146
+ to_create.select do |tc|
147
+ if tc.labels.any? { |l| l.match?(label_include) }
148
+ tc.metadata[:label_include] = true
149
+ true
150
+ else
151
+ tc.metadata[:label_include] = false
152
+ tc.should_create = false
153
+ false
154
+ end
155
+ end
156
+ end
157
+
158
+ def self.explain_this(to_create)
159
+ should_create = to_create.select(&:should_create)
160
+ should_not_create = to_create.reject(&:should_create)
161
+ AbideDevUtils::Output.simple(AbideDevUtils::Output.simple_section_separator('EXPLAIN'))
162
+ AbideDevUtils::Output.simple("Will create #{should_create.count} issues")
163
+ AbideDevUtils::Output.simple("Will not create #{should_not_create.count} issues")
164
+ AbideDevUtils::Output.simple(AbideDevUtils::Output.simple_section_separator('WILL CREATE'))
165
+ should_create.each do |tc|
166
+ AbideDevUtils::Output.simple("\"#{tc.summary}\"; labels: #{tc.labels}; metadata: #{tc.metadata}")
167
+ end
168
+ AbideDevUtils::Output.simple(AbideDevUtils::Output.simple_section_separator('WILL NOT CREATE'))
169
+ should_not_create.each do |tc|
170
+ AbideDevUtils::Output.simple("\"#{tc.summary}\"; labels: #{tc.labels}; metadata: #{tc.metadata}")
171
+ end
172
+ exit(0)
173
+ end
174
+
103
175
  def self.new_issues_from_xccdf_diff(project, xccdf1_path, xccdf2_path, epic: nil, dry_run: false, auto_approve: false, diff_opts: {})
104
176
  require 'abide_dev_utils/xccdf/diff'
105
177
  diff = AbideDevUtils::XCCDF::Diff::BenchmarkDiff.new(xccdf1_path, xccdf2_path, diff_opts)
@@ -10,6 +10,14 @@ require 'abide_dev_utils/files'
10
10
  module AbideDevUtils
11
11
  module Output
12
12
  FWRITER = AbideDevUtils::Files::Writer.new
13
+ def self.simple_section_separator(section_text, sepchar: '#', width: 60, **_)
14
+ section_text = section_text.to_s
15
+ section_text = section_text[0..width - 4] if section_text.length > width
16
+ section_text = " #{section_text} "
17
+ section_sep_line = sepchar * width
18
+ [section_sep_line, section_text.center(width, sepchar), section_sep_line].join("\n")
19
+ end
20
+
13
21
  def self.simple(msg, stream: $stdout, **_)
14
22
  case msg
15
23
  when Hash
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AbideDevUtils
4
- VERSION = "0.17.0"
4
+ VERSION = "0.17.1"
5
5
  end
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.17.0
4
+ version: 0.17.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - abide-team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-11-02 00:00:00.000000000 Z
11
+ date: 2023-11-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri