Skip to content

Commit d2fa843

Browse files
authored
Merge pull request #39 from github/kpaulisse-arbitrary-command-line-pass
Pass command line arguments to Puppet
2 parents f42d09b + 8319fc9 commit d2fa843

File tree

12 files changed

+443
-0
lines changed

12 files changed

+443
-0
lines changed

doc/optionsref.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,12 @@ Usage: octocatalog-diff [command line options]
137137
Symlinks to create for the to branch
138138
--from-create-symlinks STRING1[,STRING2[,...]]
139139
Symlinks to create for the from branch
140+
--command-line STRING1[,STRING2[,...]]
141+
Command line arguments globally
142+
--to-command-line STRING1[,STRING2[,...]]
143+
Command line arguments for the to branch
144+
--from-command-line STRING1[,STRING2[,...]]
145+
Command line arguments for the from branch
140146
--pass-env-vars VAR1[,VAR2[,...]]
141147
Environment variables to pass
142148
--[no-]suppress-absent-file-details
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# frozen_string_literal: true
2+
3+
# Provide additional command line flags to set when running Puppet to compile catalogs.
4+
# @param parser [OptionParser object] The OptionParser argument
5+
# @param options [Hash] Options hash being constructed; this is modified in this method.
6+
OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:command_line) do
7+
has_weight 510
8+
9+
def parse(parser, options)
10+
OctocatalogDiff::CatalogDiff::Cli::Options.option_globally_or_per_branch(
11+
parser: parser,
12+
options: options,
13+
cli_name: 'command-line',
14+
option_name: 'command_line',
15+
desc: 'Command line arguments',
16+
datatype: []
17+
)
18+
end
19+
end

lib/octocatalog-diff/catalog-util/command.rb

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,62 @@ def puppet_command
9595
cmdline << "--ssldir=#{Shellwords.escape(File.join(@compilation_dir, 'var', 'ssl'))}"
9696
cmdline << "--confdir=#{Shellwords.escape(@compilation_dir)}"
9797

98+
# Other parameters provided by the user
99+
override_and_append_commandline_with_user_supplied_arguments(cmdline)
100+
98101
# Return full command
99102
cmdline.join(' ')
100103
end
104+
105+
private
106+
107+
# Private: Mutate the command line with arguments that were passed directly from the
108+
# user. This appends new arguments and overwrites existing arguments.
109+
# @param cmdline [Array] Existing command line - mutated by this method
110+
def override_and_append_commandline_with_user_supplied_arguments(cmdline)
111+
return unless @options[:command_line].is_a?(Array)
112+
113+
@options[:command_line].each do |opt|
114+
# Validate format: Accept '--key=value' or '--key' only.
115+
unless opt =~ /\A--([^=\s]+)(=.+)?\z/
116+
raise ArgumentError, "Command line option '#{opt}' does not match format '--SOME_OPTION=SOME_VALUE'"
117+
end
118+
key = Regexp.last_match(1)
119+
val = Regexp.last_match(2)
120+
121+
# The key should not contain any shell metacharacters. Ensure that this is the case.
122+
unless key == Shellwords.escape(key)
123+
raise ArgumentError, "Command line option '#{key}' is invalid."
124+
end
125+
126+
# If val is nil, then it's a '--key' argument. Else, it's a '--key=value' argument. Escape
127+
# the value to ensure it do not break the shell interpretation.
128+
new_setting = if val.nil?
129+
"--#{key}"
130+
else
131+
"--#{key}=#{Shellwords.escape(val.sub(/\A=/, ''))}"
132+
end
133+
134+
# Determine if command line already contains this setting. If yes, the setting provided
135+
# here should override. If no, then append to the commandline.
136+
ind = key_position(cmdline, key)
137+
if ind.nil?
138+
cmdline << new_setting
139+
else
140+
cmdline[ind] = new_setting
141+
end
142+
end
143+
end
144+
145+
# Private: Determine if the key (given by --key) is already defined in the
146+
# command line. Returns nil if it is not already defined, otherwise returns
147+
# the index.
148+
# @param cmdline [Array] Existing command line
149+
# @param key [String] Key to look up
150+
# @return [Fixnum] Index of where key is defined (nil if undefined)
151+
def key_position(cmdline, key)
152+
cmdline.index { |x| x == "--#{key}" || x =~ /\A--#{key}=/ }
153+
end
101154
end
102155
end
103156
end
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
modulepath = ./modules
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
node default {
2+
file { '/tmp/environment-foo-site':
3+
content => 'File created from environments/foo/manifests/site.pp',
4+
}
5+
include foo
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class foo {
2+
file { '/tmp/environment-foo-module':
3+
content => 'Created by environments/foo modules/foo',
4+
}
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node default {
2+
file { '/tmp/environment-production-site':
3+
content => 'File created from environments/production/manifests/site.pp',
4+
}
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node default {
2+
file { '/tmp/foo':
3+
content => 'File created from manifests/site.pp',
4+
}
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class foo {
2+
file { '/tmp/foo-module':
3+
content => 'Created by main modules/foo',
4+
}
5+
}
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
# frozen_string_literal: true
2+
3+
require_relative 'integration_helper'
4+
5+
OctocatalogDiff::Spec.require_path('/catalog')
6+
7+
describe 'passes command line options to puppet' do
8+
context 'with one argument passed' do
9+
before(:all) do
10+
@result = OctocatalogDiff::Integration.integration(
11+
spec_repo_new: 'arbitrary-command-line',
12+
spec_fact_file: 'facts.yaml',
13+
argv: [
14+
'-n', 'rspec-node.github.net', '--no-parallel', '--preserve-environments',
15+
'--from-catalog', OctocatalogDiff::Spec.fixture_path('catalogs/default-catalog-v4.json'),
16+
'--command-line', '--environment=foo'
17+
]
18+
)
19+
end
20+
21+
it 'should compile without exceptions' do
22+
expect(@result.exitcode).to eq(2), OctocatalogDiff::Integration.format_exception(@result)
23+
expect(@result.exception).to be_nil
24+
end
25+
26+
it 'should contain resource from environments/foo site.pp' do
27+
expect(OctocatalogDiff::Spec.array_contains_partial_array?(
28+
@result.diffs,
29+
['+', "File\f/tmp/environment-foo-site"]
30+
)).to eq(true)
31+
end
32+
33+
it 'should contain resource from environments/foo modules/foo' do
34+
expect(OctocatalogDiff::Spec.array_contains_partial_array?(
35+
@result.diffs,
36+
['+', "File\f/tmp/environment-foo-module"]
37+
)).to eq(true)
38+
end
39+
40+
it 'should not contain resource from environments/production' do
41+
expect(OctocatalogDiff::Spec.array_contains_partial_array?(
42+
@result.diffs,
43+
['+', "File\f/tmp/environment-production-site"]
44+
)).to eq(false)
45+
end
46+
47+
it 'should not contain resource from main modules/foo' do
48+
expect(OctocatalogDiff::Spec.array_contains_partial_array?(
49+
@result.diffs,
50+
['+', "File\f/tmp/foo-module"]
51+
)).to eq(false)
52+
end
53+
end
54+
55+
context 'with argument passed only to one catalog' do
56+
before(:all) do
57+
@result = OctocatalogDiff::Integration.integration(
58+
spec_repo_new: 'arbitrary-command-line',
59+
spec_fact_file: 'facts.yaml',
60+
argv: [
61+
'-n', 'rspec-node.github.net', '--no-parallel', '--preserve-environments',
62+
'-f', '.',
63+
'--to-command-line', '--environment=foo'
64+
]
65+
)
66+
end
67+
68+
it 'should compile without exceptions' do
69+
expect(@result.exitcode).to eq(2), OctocatalogDiff::Integration.format_exception(@result)
70+
expect(@result.exception).to be_nil
71+
end
72+
73+
it 'should contain resource from environments/foo site.pp only in to catalog' do
74+
expect(OctocatalogDiff::Spec.array_contains_partial_array?(
75+
@result.diffs,
76+
['+', "File\f/tmp/environment-foo-site"]
77+
)).to eq(true)
78+
end
79+
80+
it 'should contain resource from environments/foo modules/foo only in to catalog' do
81+
expect(OctocatalogDiff::Spec.array_contains_partial_array?(
82+
@result.diffs,
83+
['+', "File\f/tmp/environment-foo-module"]
84+
)).to eq(true)
85+
end
86+
87+
it 'should contain resource from environments/production only in from catalog' do
88+
expect(OctocatalogDiff::Spec.array_contains_partial_array?(
89+
@result.diffs,
90+
['-', "File\f/tmp/environment-production-site"]
91+
)).to eq(true)
92+
end
93+
end
94+
95+
context 'with override of an argument' do
96+
before(:all) do
97+
@result = OctocatalogDiff::Integration.integration(
98+
spec_repo_new: 'arbitrary-command-line',
99+
spec_fact_file: 'facts.yaml',
100+
argv: [
101+
'-n', 'rspec-node.github.net', '--no-parallel', '--preserve-environments',
102+
'--from-catalog', OctocatalogDiff::Spec.fixture_path('catalogs/default-catalog-v4.json'),
103+
'--command-line', '--environment=foo',
104+
'--environment', 'production'
105+
]
106+
)
107+
end
108+
109+
it 'should compile without exceptions' do
110+
expect(@result.exitcode).to eq(2), OctocatalogDiff::Integration.format_exception(@result)
111+
expect(@result.exception).to be_nil
112+
end
113+
114+
it 'should contain resource from environments/foo site.pp' do
115+
expect(OctocatalogDiff::Spec.array_contains_partial_array?(
116+
@result.diffs,
117+
['+', "File\f/tmp/environment-foo-site"]
118+
)).to eq(true)
119+
end
120+
121+
it 'should contain resource from environments/foo modules/foo' do
122+
expect(OctocatalogDiff::Spec.array_contains_partial_array?(
123+
@result.diffs,
124+
['+', "File\f/tmp/environment-foo-module"]
125+
)).to eq(true)
126+
end
127+
128+
it 'should not contain resource from environments/production' do
129+
expect(OctocatalogDiff::Spec.array_contains_partial_array?(
130+
@result.diffs,
131+
['+', "File\f/tmp/environment-production-site"]
132+
)).to eq(false)
133+
end
134+
135+
it 'should not contain resource from main modules/foo' do
136+
expect(OctocatalogDiff::Spec.array_contains_partial_array?(
137+
@result.diffs,
138+
['+', "File\f/tmp/foo-module"]
139+
)).to eq(false)
140+
end
141+
end
142+
143+
context 'with multiple arguments' do
144+
before(:all) do
145+
@result = OctocatalogDiff::Integration.integration(
146+
spec_repo_new: 'arbitrary-command-line',
147+
spec_fact_file: 'facts.yaml',
148+
argv: [
149+
'-n', 'rspec-node.github.net', '--no-parallel', '--preserve-environments',
150+
'--from-catalog', OctocatalogDiff::Spec.fixture_path('catalogs/default-catalog-v4.json'),
151+
'--command-line', '--environment=foo',
152+
'--command-line', '--modulepath=modules'
153+
]
154+
)
155+
end
156+
157+
it 'should compile without exceptions' do
158+
expect(@result.exitcode).to eq(2), OctocatalogDiff::Integration.format_exception(@result)
159+
expect(@result.exception).to be_nil
160+
end
161+
162+
it 'should contain resource from environments/foo site.pp' do
163+
expect(OctocatalogDiff::Spec.array_contains_partial_array?(
164+
@result.diffs,
165+
['+', "File\f/tmp/environment-foo-site"]
166+
)).to eq(true)
167+
end
168+
169+
it 'should not contain resource from environments/foo modules/foo' do
170+
expect(OctocatalogDiff::Spec.array_contains_partial_array?(
171+
@result.diffs,
172+
['+', "File\f/tmp/environment-foo-module"]
173+
)).to eq(false)
174+
end
175+
176+
it 'should not contain resource from environments/production' do
177+
expect(OctocatalogDiff::Spec.array_contains_partial_array?(
178+
@result.diffs,
179+
['+', "File\f/tmp/environment-production-site"]
180+
)).to eq(false)
181+
end
182+
183+
it 'should contain resource from main modules/foo' do
184+
expect(OctocatalogDiff::Spec.array_contains_partial_array?(
185+
@result.diffs,
186+
['+', "File\f/tmp/foo-module"]
187+
)).to eq(true)
188+
end
189+
end
190+
end

0 commit comments

Comments
 (0)