Skip to content

Commit b706d69

Browse files
authored
Merge pull request #121 from github/kpaulisse-fact-file-per-branch
Fact file per branch
2 parents 45b420f + c158d14 commit b706d69

File tree

7 files changed

+163
-13
lines changed

7 files changed

+163
-13
lines changed

lib/octocatalog-diff/cli/options.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,14 +112,17 @@ def self.option_globally_or_per_branch_string(opts)
112112
translated = translate_option(opts[:translator], x)
113113
options[to_option] ||= translated
114114
options[from_option] ||= translated
115+
post_process(opts[:post_process], options)
115116
end
116117
parser.on("--to-#{flag}", "#{desc} for the to branch") do |x|
117118
validate_option(opts[:validator], x) if opts[:validator]
118119
options[to_option] = translate_option(opts[:translator], x)
120+
post_process(opts[:post_process], options)
119121
end
120122
parser.on("--from-#{flag}", "#{desc} for the from branch") do |x|
121123
validate_option(opts[:validator], x) if opts[:validator]
122124
options[from_option] = translate_option(opts[:translator], x)
125+
post_process(opts[:post_process], options)
123126
end
124127
end
125128

@@ -178,6 +181,15 @@ def self.translate_option(translator, value)
178181
return value if translator.nil?
179182
translator.call(value)
180183
end
184+
185+
# Code that can run after a translation and operate upon all options. This returns nothing but may
186+
# modify options that were input.
187+
# @param processor [Code] Processor function
188+
# @param options [Hash] Options hash
189+
def self.post_process(processor, options)
190+
return if processor.nil?
191+
processor.call(options)
192+
end
181193
end
182194
end
183195
end

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

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,38 @@
77
has_weight 150
88

99
def parse(parser, options)
10-
parser.on('--fact-file FILENAME', 'Fact file to use instead of node lookup') do |fact_file|
11-
raise Errno::ENOENT, 'Invalid fact file provided' unless File.file?(fact_file)
12-
facts = nil
13-
local_opts = { fact_file_string: File.read(fact_file) }
14-
if fact_file =~ /\.ya?ml$/
15-
facts = OctocatalogDiff::Facts.new(local_opts.merge(backend: :yaml))
16-
elsif fact_file =~ /\.json$/
17-
facts = OctocatalogDiff::Facts.new(local_opts.merge(backend: :json))
18-
else
19-
raise ArgumentError, 'I do not know how to parse the provided fact file. Needs .yaml or .json extension.'
10+
OctocatalogDiff::Cli::Options.option_globally_or_per_branch(
11+
parser: parser,
12+
options: options,
13+
cli_name: 'fact-file',
14+
option_name: 'facts',
15+
desc: 'Override fact',
16+
datatype: '',
17+
validator: ->(fact_file) { File.file?(fact_file) && (fact_file =~ /\.ya?ml$/ || fact_file =~ /\.json$/) },
18+
translator: lambda do |fact_file|
19+
local_opts = { fact_file_string: File.read(fact_file) }
20+
if fact_file =~ /\.ya?ml$/
21+
OctocatalogDiff::Facts.new(local_opts.merge(backend: :yaml))
22+
elsif fact_file =~ /\.json$/
23+
OctocatalogDiff::Facts.new(local_opts.merge(backend: :json))
24+
else
25+
# :nocov:
26+
# Believed to be a bug condition since the validator should kick this out before it ever gets here.
27+
raise ArgumentError, 'I do not know how to parse the provided fact file. Needs .yaml or .json extension.'
28+
# :nocov:
29+
end
30+
end,
31+
post_process: lambda do |opts|
32+
unless options[:node]
33+
%w[to_facts from_facts facts].each do |opt|
34+
next unless opts[opt.to_sym] && opts[opt.to_sym].node
35+
opts[:node] = opts[opt.to_sym].node
36+
break
37+
end
38+
end
39+
40+
options[:facts] ||= options[:to_facts]
2041
end
21-
options[:facts] = facts
22-
options[:node] ||= facts.facts['name']
23-
end
42+
)
2443
end
2544
end

lib/octocatalog-diff/facts.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ def dup
4141
self.class.new(@options, @orig_facts)
4242
end
4343

44+
# Node - get the node name, either as set explicitly or as determined from the facts themselves.
45+
# @return [String] Node name, explicit or guessed
46+
def node
47+
return @node unless @node.nil? || @node.empty?
48+
return facts['name'] if facts.key?('name')
49+
return facts['values']['fqdn'] if facts.key?('values') && facts['values'].key?('fqdn')
50+
''
51+
end
52+
4453
# Facts - returned the 'cleansed' facts.
4554
# Clean up facts by setting 'name' to the node if given, and deleting _timestamp and expiration
4655
# which may cause Puppet catalog compilation to fail if the facts are old.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--- !ruby/object:Puppet::Node::Facts
2+
name: rspec-node.xyz.github.net
3+
values:
4+
_timestamp: '2016-03-16 16:02:13 -0500'
5+
apt_update_last_success: 1458162123
6+
architecture: amd64
7+
clientcert: rspec-node.github.net
8+
datacenter: xyz
9+
domain: xyz.github.net
10+
fqdn: rspec-node.xyz.github.net
11+
ipaddress: 10.30.50.70
12+
kernel: Linux
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# frozen_string_literal: true
2+
3+
require_relative 'integration_helper'
4+
5+
require 'json'
6+
7+
describe 'fact files by branch' do
8+
before(:all) do
9+
@result = OctocatalogDiff::Integration.integration_cli(
10+
[
11+
'-n', 'rspec-node.github.net',
12+
'--bootstrapped-to-dir', OctocatalogDiff::Spec.fixture_path('repos/fact-overrides'),
13+
'--bootstrapped-from-dir', OctocatalogDiff::Spec.fixture_path('repos/fact-overrides'),
14+
'--output-format', 'json',
15+
'--fact-file', OctocatalogDiff::Spec.fixture_path('facts/valid-facts.yaml'),
16+
'--to-fact-file', OctocatalogDiff::Spec.fixture_path('facts/valid-facts-different-ip.yaml'),
17+
'--puppet-binary', OctocatalogDiff::Spec::PUPPET_BINARY,
18+
'--fact-override', 'foofoo=barbar',
19+
'-d'
20+
]
21+
)
22+
end
23+
24+
it 'should exit with status 2' do
25+
expect(@result.exitcode).to eq(2), @result.stderr
26+
end
27+
28+
it 'should contain the correct diffs' do
29+
parse_result = JSON.parse(@result.stdout)['diff'].map { |x| OctocatalogDiff::Spec.remove_file_and_line(x) }
30+
expect(parse_result.size).to eq(1)
31+
expect(parse_result).to include(
32+
'diff_type' => '~',
33+
'type' => 'File',
34+
'title' => '/tmp/ipaddress',
35+
'structure' => %w(parameters content),
36+
'old_value' => '10.20.30.40',
37+
'new_value' => '10.30.50.70'
38+
)
39+
end
40+
41+
it 'should log the correct messages' do
42+
expect(@result.stderr).to match(/Catalog for . will be built with OctocatalogDiff::Catalog::Computed/)
43+
expect(@result.stderr).to match(/Override foofoo from nil to "barbar"/)
44+
expect(@result.stderr).to match(/Diffs computed for rspec-node.github.net/)
45+
end
46+
end

spec/octocatalog-diff/tests/cli/options/fact_file_spec.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,30 @@
4848
end.to raise_error(Errno::ENOENT)
4949
end
5050
end
51+
52+
describe '#opt_to_fact_file' do
53+
it 'should distinguish between the to-facts and from-facts' do
54+
fact_file_1 = OctocatalogDiff::Spec.fixture_path('facts/facts.yaml')
55+
fact_file_2 = OctocatalogDiff::Spec.fixture_path('facts/valid-facts.yaml')
56+
result = run_optparse(['--from-fact-file', fact_file_1, '--to-fact-file', fact_file_2])
57+
58+
result_facts_1 = result[:from_facts].facts
59+
expect(result_facts_1).to be_a_kind_of(Hash)
60+
expect(result_facts_1['name']).to eq('rspec-node.xyz.github.net')
61+
expect(result_facts_1['values']).to be_a_kind_of(Hash)
62+
expect(result_facts_1['values']['fqdn']).to eq('rspec-node.xyz.github.net')
63+
expect(result_facts_1['values']['ipaddress']).to be_nil
64+
expect(result_facts_1['values'].keys).not_to include('expiration')
65+
66+
result_facts_2 = result[:to_facts].facts
67+
expect(result_facts_2).to be_a_kind_of(Hash)
68+
expect(result_facts_2['name']).to eq('rspec-node.xyz.github.net')
69+
expect(result_facts_2['values']).to be_a_kind_of(Hash)
70+
expect(result_facts_2['values']['fqdn']).to eq('rspec-node.xyz.github.net')
71+
expect(result_facts_2['values']['ipaddress']).to eq('10.20.30.40')
72+
expect(result_facts_2['values'].keys).not_to include('expiration')
73+
74+
expect(result[:facts]).to eq(result[:to_facts])
75+
end
76+
end
5177
end

spec/octocatalog-diff/tests/facts_spec.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,32 @@
8080
end
8181
end
8282

83+
describe '#node' do
84+
let(:opts) { { backend: :yaml, fact_file_string: File.read(OctocatalogDiff::Spec.fixture_path('facts/facts.yaml')) } }
85+
86+
it 'should return the node if set explicitly' do
87+
obj = OctocatalogDiff::Facts.new(opts.merge(node: 'fluffy-kittens.example.com'))
88+
expect(obj.node).to eq('fluffy-kittens.example.com')
89+
end
90+
91+
it 'should return the node from the facts name in the fact file' do
92+
obj = OctocatalogDiff::Facts.new(opts)
93+
expect(obj.node).to eq('rspec-node.xyz.github.net')
94+
end
95+
96+
it 'should return the FQDN' do
97+
obj = OctocatalogDiff::Facts.new(opts)
98+
allow(obj).to receive(:facts).and_return('values' => { 'fqdn' => 'foobar.example.com' })
99+
expect(obj.node).to eq('foobar.example.com')
100+
end
101+
102+
it 'should return empty if all else fails' do
103+
obj = OctocatalogDiff::Facts.new(opts)
104+
allow(obj).to receive(:facts).and_return({})
105+
expect(obj.node).to eq('')
106+
end
107+
end
108+
83109
context 'test individual methods' do
84110
before(:all) do
85111
opts = {

0 commit comments

Comments
 (0)