abide_dev_utils 0.17.0 → 0.17.1

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 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