Skip to content

Commit 9d9c786

Browse files
authored
Merge branch 'kpaulisse-release-1-0' into kpaulisse-release-1-0-doc
2 parents 5996ff4 + 66383a9 commit 9d9c786

File tree

13 files changed

+235
-34
lines changed

13 files changed

+235
-34
lines changed

doc/dev/api/v1/objects/diff.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ Note that this is a pass-through of information provided in the Puppet catalog,
4444

4545
Note also that if the diff represents removal of a resource, this will return `nil`, because the resource does not exist in the new catalog.
4646

47+
#### `#new_location` (Hash)
48+
49+
Returns a hash containing `:file` (equal to `#new_file`) and `:line` (equal to `#new_line`) when either is defined. Returns `nil` if both are undefined.
50+
4751
#### `#new_value` (Object)
4852

4953
Returns the value of the resource from the new catalog.
@@ -111,6 +115,10 @@ Note that this is a pass-through of information provided in the Puppet catalog,
111115

112116
Note also that if the diff represents addition of a resource, this will return `nil`, because the resource does not exist in the old catalog.
113117

118+
#### `#old_location` (Hash)
119+
120+
Returns a hash containing `:file` (equal to `#old_file`) and `:line` (equal to `#old_line`) when either is defined. Returns `nil` if both are undefined.
121+
114122
#### `#old_value` (Object)
115123

116124
Returns the value of the resource from the old catalog.
@@ -249,4 +257,5 @@ These methods are available for debugging or development purposes but are not gu
249257
- `#inspect` (String): Returns inspection of object
250258
- `#raw` (Array): Returns internal array data structure of the "diff"
251259
- `#to_h` (Hash): Returns object as a hash, where keys are above described methods
260+
- `#to_h_with_string_keys` (Hash): Returns object as a hash, where keys are above described methods; keys are strings, not symbols
252261
- `#[]` (Object): Retrieve indexed array elements from raw internal array object

doc/optionsref.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Usage: octocatalog-diff [command line options]
2727
--bootstrap-then-exit Bootstrap from-dir and/or to-dir and then exit
2828
--[no-]color Enable/disable colors in output
2929
-o, --output-file FILENAME Output results into FILENAME
30-
--output-format FORMAT Output format: text,json
30+
--output-format FORMAT Output format: text,json,legacy_json
3131
-d, --[no-]debug Print debugging messages to STDERR
3232
-q, --[no-]quiet Quiet (no status messages except errors)
3333
--ignore "Type1[Title1],Type2[Title2],..."
@@ -708,10 +708,12 @@ to ignore any changes for any defined type where this tag is set. (<a href="../l
708708
<pre><code>--output-format FORMAT</code></pre>
709709
</td>
710710
<td valign=top>
711-
Output format: text,json
711+
Output format: text,json,legacy_json
712712
</td>
713713
<td valign=top>
714-
Output format option (<a href="../lib/octocatalog-diff/cli/options/output_format.rb">output_format.rb</a>)
714+
Output format option. 'text' is human readable text, 'json' is an array of differences
715+
identified by human readable keys (the preferred octocatalog-diff 1.x format), and 'legacy_json' is an
716+
array of differences, where each difference is an array (the octocatalog-diff 0.x format). (<a href="../lib/octocatalog-diff/cli/options/output_format.rb">output_format.rb</a>)
715717
</td>
716718
</tr>
717719

lib/octocatalog-diff/api/v1/diff.rb

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,13 @@ class Diff
2222
# Constructor: Accepts a diff in the traditional array format and stores it.
2323
# @param raw [Array] Diff in the traditional format
2424
def initialize(raw)
25+
if raw.is_a?(OctocatalogDiff::API::V1::Diff)
26+
@raw = raw.raw
27+
return
28+
end
29+
2530
unless raw.is_a?(Array)
26-
raise ArgumentError, 'OctocatalogDiff::API::V1::Diff#initialize expects Array argument'
31+
raise ArgumentError, "OctocatalogDiff::API::V1::Diff#initialize expects Array argument (got #{raw.class})"
2732
end
2833
@raw = raw
2934
end
@@ -119,6 +124,22 @@ def new_line
119124
x.nil? ? nil : x['line']
120125
end
121126

127+
# Public: Get the "old" location, i.e. location in the "from" catalog
128+
# @return [Hash] <file:, line:> of resource
129+
def old_location
130+
return nil if addition?
131+
return @raw[3] if removal?
132+
@raw[4]
133+
end
134+
135+
# Public: Get the "new" location, i.e. location in the "to" catalog
136+
# @return [Hash] <file:, line:> of resource
137+
def new_location
138+
return @raw[3] if addition?
139+
return nil if removal?
140+
@raw[5]
141+
end
142+
122143
# Public: Convert this object to a hash
123144
# @return [Hash] Hash with keys set by these methods
124145
def to_h
@@ -132,10 +153,20 @@ def to_h
132153
old_file: old_file,
133154
old_line: old_line,
134155
new_file: new_file,
135-
new_line: new_line
156+
new_line: new_line,
157+
old_location: old_location,
158+
new_location: new_location
136159
}
137160
end
138161

162+
# Public: Convert this object to a hash with string keys
163+
# @return [Hash] Hash with keys set by these methods, with string keys
164+
def to_h_with_string_keys
165+
result = {}
166+
to_h.each { |key, val| result[key.to_s] = val }
167+
result
168+
end
169+
139170
# Public: String inspection
140171
# @return [String] String for inspection
141172
def inspect
@@ -147,24 +178,6 @@ def inspect
147178
def to_s
148179
raw.inspect
149180
end
150-
151-
private
152-
153-
# Private: Get the "old" location, i.e. location in the "from" catalog
154-
# @return [Hash] <file:, line:> of resource
155-
def old_location
156-
return nil if addition?
157-
return @raw[3] if removal?
158-
@raw[4]
159-
end
160-
161-
# Private: Get the "new" location, i.e. location in the "to" catalog
162-
# @return [Hash] <file:, line:> of resource
163-
def new_location
164-
return @raw[3] if addition?
165-
return nil if removal?
166-
@raw[5]
167-
end
168181
end
169182
end
170183
end

lib/octocatalog-diff/catalog-diff/display.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# frozen_string_literal: true
22

3+
require_relative '../api/v1/diff'
34
require_relative 'differ'
45
require_relative 'display/json'
6+
require_relative 'display/legacy_json'
57
require_relative 'display/text'
68

79
module OctocatalogDiff
@@ -21,8 +23,9 @@ class Display
2123
# @param logger [Logger] Logger object
2224
# @return [String] Text output for provided diff
2325
def self.output(diff_in, options = {}, logger = nil)
24-
diff = diff_in.is_a?(OctocatalogDiff::CatalogDiff::Differ) ? diff_in.diff : diff_in
25-
raise ArgumentError, "text_output requires Array<Diff results>; passed in #{diff_in.class}" unless diff.is_a?(Array)
26+
diff_x = diff_in.is_a?(OctocatalogDiff::CatalogDiff::Differ) ? diff_in.diff : diff_in
27+
raise ArgumentError, "text_output requires Array<Diff results>; passed in #{diff_in.class}" unless diff_x.is_a?(Array)
28+
diff = diff_x.map { |x| OctocatalogDiff::API::V1::Diff.new(x) }
2629

2730
# req_format means 'requested format' because 'format' has a built-in meaning to Ruby
2831
req_format = options.fetch(:format, :color_text)
@@ -41,6 +44,9 @@ def self.output(diff_in, options = {}, logger = nil)
4144
when :json
4245
logger.debug 'Generating JSON output' if logger
4346
OctocatalogDiff::CatalogDiff::Display::Json.generate(diff, opts, logger)
47+
when :legacy_json
48+
logger.debug 'Generating Legacy JSON output' if logger
49+
OctocatalogDiff::CatalogDiff::Display::LegacyJson.generate(diff, opts, logger)
4450
when :text
4551
logger.debug 'Generating non-colored text output' if logger
4652
OctocatalogDiff::CatalogDiff::Display::Text.generate(diff, opts.merge(color: false), logger)

lib/octocatalog-diff/catalog-diff/display/json.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
module OctocatalogDiff
88
module CatalogDiff
99
class Display
10-
# Display the output from a diff in JSON format.
10+
# Display the output from a diff in JSON format. This is the new format, used in octocatalog-diff
11+
# 1.x, where each diff is represented by an hash with named keys.
1112
class Json < OctocatalogDiff::CatalogDiff::Display
1213
# Generate JSON representation of the 'diff' suitable for further analysis.
1314
# @param diff [Array<Diff results>] The diff which *must* be in this format
@@ -16,7 +17,7 @@ class Json < OctocatalogDiff::CatalogDiff::Display
1617
# @param _logger [Logger] Not used here
1718
def self.generate(diff, options = {}, _logger = nil)
1819
result = {
19-
'diff' => diff
20+
'diff' => diff.map(&:to_h_with_string_keys)
2021
}
2122
result['header'] = options[:header] unless options[:header].nil?
2223
result.to_json
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# frozen_string_literal: true
2+
3+
require_relative '../display'
4+
5+
require 'json'
6+
7+
module OctocatalogDiff
8+
module CatalogDiff
9+
class Display
10+
# Display the output from a diff in JSON format. This is the legacy format, used in octocatalog-diff
11+
# 0.x, where each diff is represented by an array.
12+
class LegacyJson < OctocatalogDiff::CatalogDiff::Display
13+
# Generate JSON representation of the 'diff' suitable for further analysis.
14+
# @param diff [Array<Diff results>] The diff which *must* be in this format
15+
# @param options [Hash] Options which are:
16+
# - :header => [String] Header to print; no header is printed if not specified
17+
# @param _logger [Logger] Not used here
18+
def self.generate(diff, options = {}, _logger = nil)
19+
result = {
20+
'diff' => diff.map(&:raw)
21+
}
22+
result['header'] = options[:header] unless options[:header].nil?
23+
result.to_json
24+
end
25+
end
26+
end
27+
end
28+
end

lib/octocatalog-diff/cli/options/output_format.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
# frozen_string_literal: true
22

3-
# Output format option
3+
# Output format option. 'text' is human readable text, 'json' is an array of differences
4+
# identified by human readable keys (the preferred octocatalog-diff 1.x format), and 'legacy_json' is an
5+
# array of differences, where each difference is an array (the octocatalog-diff 0.x format).
46
# @param parser [OptionParser object] The OptionParser argument
57
# @param options [Hash] Options hash being constructed; this is modified in this method.
68
OctocatalogDiff::Cli::Options::Option.newoption(:output_format) do
79
has_weight 100
810

911
def parse(parser, options)
10-
valid = %w(text json)
12+
valid = %w(text json legacy_json)
1113
parser.on('--output-format FORMAT', "Output format: #{valid.join(',')}") do |fmt|
1214
raise ArgumentError, "Invalid format. Must be one of: #{valid.join(',')}" unless valid.include?(fmt)
1315
options[:format] = fmt.to_sym

lib/octocatalog-diff/cli/printer.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@ def initialize(options, logger)
1919
# The method to call externally, passing in diffs. This takes the appropriate action
2020
# based on options, which is either to write the result into an output file, or print
2121
# the result on STDOUT. Does not return anything.
22-
# @param diffs [OctocatalogDiff::CatalogDiff::Differ] Difference array
22+
# @param diffs [Array<Diffs>] Array of differences
2323
# @param from_dir [String] Directory in which "from" catalog was compiled
2424
# @param to_dir [String] Directory in which "to" catalog was compiled
2525
def printer(diffs, from_dir = nil, to_dir = nil)
26+
unless diffs.is_a?(Array)
27+
raise ArgumentError, "printer() expects an array, not #{diffs.class}"
28+
end
2629
display_opts = @options.merge(compilation_from_dir: from_dir, compilation_to_dir: to_dir)
2730
diff_text = OctocatalogDiff::CatalogDiff::Display.output(diffs, display_opts, @logger)
2831
if @options[:output_file].nil?

spec/octocatalog-diff/integration/outputs_spec.rb

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
expect(result[:output]).to match(pattern)
5252
end
5353

54-
it 'should write JSON output to a specified file' do
54+
it 'should write 1.x JSON output to a specified file' do
5555
output_file = File.join(@tmpdir, 'octo-output.json')
5656
argv = default_argv.concat ['-o', output_file, '--output-format', 'json']
5757
result = OctocatalogDiff::Integration.integration(argv: argv)
@@ -63,6 +63,46 @@
6363
expect(data).to be_a_kind_of(Hash)
6464
expect(data['header']).to eq(nil)
6565
expect(data['diff']).to be_a_kind_of(Array)
66+
67+
answer = {
68+
'diff_type' => '~',
69+
'type' => 'File',
70+
'title' => '/usr/bin/node-waf',
71+
'structure' => %w(parameters ensure),
72+
'old_value' => '/usr/share/nvm/0.8.11/bin/node-waf',
73+
'new_value' => 'link',
74+
'old_file' => '/environments/production/modules/nodejs/manifests/init.pp',
75+
'old_line' => 55,
76+
'new_file' => '/environments/production/modules/nodejs/manifests/init.pp',
77+
'new_line' => 55,
78+
'old_location' => { 'file' => '/environments/production/modules/nodejs/manifests/init.pp', 'line' => 55 },
79+
'new_location' => { 'file' => '/environments/production/modules/nodejs/manifests/init.pp', 'line' => 55 }
80+
}
81+
expect(data['diff']).to include(answer)
82+
end
83+
84+
it 'should write 0.x JSON output to a specified file' do
85+
output_file = File.join(@tmpdir, 'octo-output.json')
86+
argv = default_argv.concat ['-o', output_file, '--output-format', 'legacy_json']
87+
result = OctocatalogDiff::Integration.integration(argv: argv)
88+
expect(result[:exitcode]).to eq(2), OctocatalogDiff::Integration.format_exception(result)
89+
expect(result[:logs]).to match(/Wrote diff to #{Regexp.escape(output_file)}/)
90+
expect(File.file?(output_file)).to eq(true)
91+
content = File.read(output_file)
92+
data = JSON.parse(content)
93+
expect(data).to be_a_kind_of(Hash)
94+
expect(data['header']).to eq(nil)
95+
expect(data['diff']).to be_a_kind_of(Array)
96+
97+
answer = [
98+
'!',
99+
"File\f/usr/bin/npm\fparameters\ftarget",
100+
'/usr/share/nvm/0.8.11/bin/npm',
101+
nil,
102+
{ 'file' => '/environments/production/modules/nodejs/manifests/init.pp', 'line' => 46 },
103+
{ 'file' => '/environments/production/modules/nodejs/manifests/init.pp', 'line' => 46 }
104+
]
105+
expect(data['diff']).to include(answer)
66106
end
67107

68108
it 'should write JSON output to the screen' do

spec/octocatalog-diff/tests/api/v1/diff_spec.rb

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,44 @@
273273
end
274274
end
275275

276+
describe '#old_location' do
277+
it 'should return nil for addition' do
278+
testobj = described_class.new(add_2)
279+
expect(testobj.old_location).to be_nil
280+
end
281+
282+
it 'should return location for removal' do
283+
testobj = described_class.new(del_2)
284+
expect(testobj.old_location).to eq(loc_1)
285+
end
286+
287+
it 'should return location for change' do
288+
testobj = described_class.new(chg_2)
289+
expect(testobj.old_location).to eq(loc_1)
290+
end
291+
end
292+
293+
describe '#new_location' do
294+
it 'should return location for addition' do
295+
testobj = described_class.new(add_2)
296+
expect(testobj.new_location).to eq(loc_2)
297+
end
298+
299+
it 'should return nil for removal' do
300+
testobj = described_class.new(del_2)
301+
expect(testobj.new_location).to be_nil
302+
end
303+
304+
it 'should return location for change' do
305+
testobj = described_class.new(chg_2)
306+
expect(testobj.new_location).to eq(loc_2)
307+
end
308+
end
309+
276310
describe '#to_h' do
277311
it 'should return a hash with the expected keys and values' do
278-
methods = %w(diff_type type title structure old_value new_value old_line new_line old_file new_file)
312+
methods = %w(diff_type type title structure old_value new_value)
313+
.concat %w(old_line new_line old_file new_file old_location new_location)
279314
testobj = described_class.new(chg_2)
280315
result = testobj.to_h
281316
methods.each do |method_name|
@@ -286,6 +321,20 @@
286321
end
287322
end
288323

324+
describe '#to_h_with_string_keys' do
325+
it 'should return a hash with the expected keys and values' do
326+
methods = %w(diff_type type title structure old_value new_value)
327+
.concat %w(old_line new_line old_file new_file old_location new_location)
328+
testobj = described_class.new(chg_2)
329+
result = testobj.to_h_with_string_keys
330+
methods.each do |method_name|
331+
method = method_name.to_sym
332+
expect(result.key?(method.to_s)).to eq(true)
333+
expect(result[method.to_s]).to eq(testobj.send(method))
334+
end
335+
end
336+
end
337+
289338
describe '#inspect' do
290339
it 'should return a string' do
291340
testobj = described_class.new(chg_2)
@@ -301,6 +350,12 @@
301350
end
302351

303352
describe '#initialize' do
353+
it 'should set up raw object when called with an instance of itself' do
354+
obj1 = described_class.new(chg_2)
355+
testobj = described_class.new(obj1)
356+
expect(testobj.raw).to eq(chg_2)
357+
end
358+
304359
it 'should raise ArgumentError if called with a non-array' do
305360
expect { described_class.new('foo') }.to raise_error(ArgumentError)
306361
end

0 commit comments

Comments
 (0)