r10k 3.5.1 → 3.9.0

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.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/.github/pull_request_template.md +4 -1
  3. data/.github/workflows/docker.yml +4 -1
  4. data/.github/workflows/release.yml +3 -2
  5. data/.github/workflows/rspec_tests.yml +81 -0
  6. data/.travis.yml +8 -1
  7. data/CHANGELOG.mkd +43 -2
  8. data/CODEOWNERS +2 -2
  9. data/README.mkd +13 -4
  10. data/doc/common-patterns.mkd +1 -0
  11. data/doc/dynamic-environments/configuration.mkd +143 -39
  12. data/doc/dynamic-environments/usage.mkd +12 -11
  13. data/doc/puppetfile.mkd +23 -3
  14. data/docker/Gemfile +1 -1
  15. data/docker/Makefile +7 -4
  16. data/docker/docker-compose.yml +18 -0
  17. data/docker/r10k/Dockerfile +4 -3
  18. data/docker/r10k/docker-entrypoint.sh +0 -1
  19. data/docker/r10k/release.Dockerfile +3 -2
  20. data/docker/spec/dockerfile_spec.rb +26 -32
  21. data/integration/tests/git_source/git_source_repeated_remote.rb +68 -0
  22. data/integration/tests/user_scenario/basic_workflow/multi_env_custom_forge_git_module.rb +2 -1
  23. data/integration/tests/user_scenario/basic_workflow/multi_env_custom_forge_git_module_static.rb +2 -1
  24. data/integration/tests/user_scenario/basic_workflow/multi_source_custom_forge_git_module.rb +1 -1
  25. data/integration/tests/user_scenario/basic_workflow/single_env_custom_forge_git_module.rb +2 -1
  26. data/integration/tests/user_scenario/complex_workflow/multi_env_add_change_remove.rb +1 -1
  27. data/integration/tests/user_scenario/complex_workflow/multi_env_remove_re-add.rb +1 -1
  28. data/integration/tests/user_scenario/complex_workflow/multi_env_unamanaged.rb +1 -1
  29. data/lib/r10k/action/deploy/display.rb +9 -3
  30. data/lib/r10k/action/deploy/environment.rb +39 -14
  31. data/lib/r10k/action/deploy/module.rb +4 -1
  32. data/lib/r10k/action/runner.rb +34 -0
  33. data/lib/r10k/cli/deploy.rb +14 -7
  34. data/lib/r10k/cli/puppetfile.rb +5 -5
  35. data/lib/r10k/environment/base.rb +9 -2
  36. data/lib/r10k/environment/git.rb +17 -2
  37. data/lib/r10k/environment/name.rb +22 -4
  38. data/lib/r10k/environment/svn.rb +11 -2
  39. data/lib/r10k/environment/with_modules.rb +28 -20
  40. data/lib/r10k/forge/module_release.rb +2 -2
  41. data/lib/r10k/git.rb +1 -0
  42. data/lib/r10k/git/cache.rb +12 -4
  43. data/lib/r10k/git/rugged/credentials.rb +39 -2
  44. data/lib/r10k/git/stateful_repository.rb +4 -0
  45. data/lib/r10k/initializers.rb +2 -0
  46. data/lib/r10k/module/base.rb +8 -0
  47. data/lib/r10k/module/forge.rb +16 -4
  48. data/lib/r10k/module/git.rb +42 -24
  49. data/lib/r10k/module/local.rb +1 -1
  50. data/lib/r10k/module/svn.rb +14 -11
  51. data/lib/r10k/puppetfile.rb +30 -12
  52. data/lib/r10k/settings.rb +30 -3
  53. data/lib/r10k/source/base.rb +5 -0
  54. data/lib/r10k/source/git.rb +26 -3
  55. data/lib/r10k/source/hash.rb +4 -2
  56. data/lib/r10k/source/svn.rb +5 -1
  57. data/lib/r10k/util/setopts.rb +33 -12
  58. data/lib/r10k/version.rb +1 -1
  59. data/locales/r10k.pot +71 -43
  60. data/r10k.gemspec +1 -1
  61. data/spec/fixtures/unit/action/r10k_creds.yaml +9 -0
  62. data/spec/shared-examples/subprocess-runner.rb +11 -5
  63. data/spec/unit/action/deploy/display_spec.rb +4 -0
  64. data/spec/unit/action/deploy/environment_spec.rb +154 -12
  65. data/spec/unit/action/deploy/module_spec.rb +40 -1
  66. data/spec/unit/action/puppetfile/install_spec.rb +1 -0
  67. data/spec/unit/action/runner_spec.rb +48 -1
  68. data/spec/unit/environment/git_spec.rb +19 -2
  69. data/spec/unit/environment/name_spec.rb +28 -0
  70. data/spec/unit/environment/svn_spec.rb +12 -0
  71. data/spec/unit/environment/with_modules_spec.rb +74 -0
  72. data/spec/unit/forge/module_release_spec.rb +14 -10
  73. data/spec/unit/git/cache_spec.rb +10 -0
  74. data/spec/unit/git/rugged/credentials_spec.rb +79 -2
  75. data/spec/unit/git_spec.rb +3 -3
  76. data/spec/unit/module/forge_spec.rb +6 -0
  77. data/spec/unit/module/git_spec.rb +56 -1
  78. data/spec/unit/module_spec.rb +59 -9
  79. data/spec/unit/puppetfile_spec.rb +61 -7
  80. data/spec/unit/settings_spec.rb +12 -0
  81. data/spec/unit/source/git_spec.rb +49 -1
  82. data/spec/unit/util/setopts_spec.rb +25 -1
  83. metadata +9 -11
  84. data/azure-pipelines.yml +0 -86
@@ -18,7 +18,8 @@ module R10K
18
18
  def initialize(opts, argv, settings = nil)
19
19
  settings ||= {}
20
20
  @purge_levels = settings.fetch(:deploy, {}).fetch(:purge_levels, [])
21
- @user_purge_whitelist = settings.fetch(:deploy, {}).fetch(:purge_whitelist, [])
21
+ @user_purge_allowlist = read_purge_allowlist(settings.fetch(:deploy, {}).fetch(:purge_whitelist, []),
22
+ settings.fetch(:deploy, {}).fetch(:purge_allowlist, []))
22
23
  @generate_types = settings.fetch(:deploy, {}).fetch(:generate_types, false)
23
24
 
24
25
  super
@@ -43,6 +44,23 @@ module R10K
43
44
 
44
45
  private
45
46
 
47
+ def read_purge_allowlist (whitelist, allowlist)
48
+ whitelist_has_content = !whitelist.empty?
49
+ allowlist_has_content = !allowlist.empty?
50
+ case
51
+ when whitelist_has_content == false && allowlist_has_content == false
52
+ []
53
+ when whitelist_has_content && allowlist_has_content
54
+ raise R10K::Error.new "Values found for both purge_whitelist and purge_allowlist. Setting " <<
55
+ "purge_whitelist is deprecated, please only use purge_allowlist."
56
+ when allowlist_has_content
57
+ allowlist
58
+ else
59
+ logger.warn "Setting purge_whitelist is deprecated; please use purge_allowlist instead."
60
+ whitelist
61
+ end
62
+ end
63
+
46
64
  def visit_deployment(deployment)
47
65
  # Ensure that everything can be preloaded. If we cannot preload all
48
66
  # sources then we can't fully enumerate all environments which
@@ -95,7 +113,7 @@ module R10K
95
113
  environment.sync
96
114
  logger.info _("Environment %{env_dir} is now at %{env_signature}") % {env_dir: environment.dirname, env_signature: environment.signature}
97
115
 
98
- if status == :absent || @puppetfile
116
+ if status == :absent || @modules
99
117
  if status == :absent
100
118
  logger.debug(_("Environment %{env_dir} is new, updating all modules") % {env_dir: environment.dirname})
101
119
  end
@@ -110,7 +128,7 @@ module R10K
110
128
  if @purge_levels.include?(:environment)
111
129
  if @visit_ok
112
130
  logger.debug("Purging unmanaged content for environment '#{environment.dirname}'...")
113
- environment.purge!(:recurse => true, :whitelist => environment.whitelist(@user_purge_whitelist))
131
+ environment.purge!(:recurse => true, :whitelist => environment.whitelist(@user_purge_allowlist))
114
132
  else
115
133
  logger.debug("Not purging unmanaged content for environment '#{environment.dirname}' due to prior deploy failures.")
116
134
  end
@@ -145,17 +163,20 @@ module R10K
145
163
  end
146
164
 
147
165
  def write_environment_info!(environment, started_at, success)
148
- module_deploys = []
149
- begin
150
- environment.modules.each do |mod|
151
- name = mod.name
152
- version = mod.version
153
- sha = mod.repo.head rescue nil
154
- module_deploys.push({:name => name, :version => version, :sha => sha})
166
+ module_deploys =
167
+ begin
168
+ environment.modules.map do |mod|
169
+ props = mod.properties
170
+ {
171
+ name: mod.name,
172
+ version: props[:expected],
173
+ sha: props[:type] == :git ? props[:actual] : nil
174
+ }
175
+ end
176
+ rescue
177
+ logger.debug("Unable to get environment module deploy data for .r10k-deploy.json at #{environment.path}")
178
+ []
155
179
  end
156
- rescue
157
- logger.debug("Unable to get environment module deploy data for .r10k-deploy.json at #{environment.path}")
158
- end
159
180
 
160
181
  # make this file write as atomic as possible in pure ruby
161
182
  final = "#{environment.path}/.r10k-deploy.json"
@@ -183,11 +204,15 @@ module R10K
183
204
  end
184
205
 
185
206
  def allowed_initialize_opts
186
- super.merge(puppetfile: :self,
207
+ super.merge(puppetfile: :modules,
208
+ modules: :self,
187
209
  cachedir: :self,
188
210
  'no-force': :self,
189
211
  'generate-types': :self,
190
212
  'puppet-path': :self,
213
+ 'puppet-conf': :self,
214
+ 'private-key': :self,
215
+ 'oauth-token': :self,
191
216
  'default-branch-override': :self)
192
217
  end
193
218
  end
@@ -76,7 +76,10 @@ module R10K
76
76
  cachedir: :self,
77
77
  'no-force': :self,
78
78
  'generate-types': :self,
79
- 'puppet-path': :self)
79
+ 'puppet-path': :self,
80
+ 'puppet-conf': :self,
81
+ 'private-key': :self,
82
+ 'oauth-token': :self)
80
83
  end
81
84
  end
82
85
  end
@@ -46,6 +46,7 @@ module R10K
46
46
  overrides[:cachedir] = @opts[:cachedir] if @opts.key?(:cachedir)
47
47
  overrides[:deploy] = {} if @opts.key?(:'puppet-path') || @opts.key?(:'generate-types')
48
48
  overrides[:deploy][:puppet_path] = @opts[:'puppet-path'] if @opts.key?(:'puppet-path')
49
+ overrides[:deploy][:puppet_conf] = @opts[:'puppet-conf'] unless @opts[:'puppet-conf'].nil?
49
50
  overrides[:deploy][:generate_types] = @opts[:'generate-types'] if @opts.key?(:'generate-types')
50
51
 
51
52
  with_overrides = config_settings.merge(overrides) do |key, oldval, newval|
@@ -54,6 +55,10 @@ module R10K
54
55
  newval
55
56
  end
56
57
 
58
+ # Credentials from the CLI override both the global and per-repo
59
+ # credentials from the config, and so need to be handled specially
60
+ with_overrides = add_credential_overrides(with_overrides)
61
+
57
62
  @settings = R10K::Settings.global_settings.evaluate(with_overrides)
58
63
 
59
64
  R10K::Initializers::GlobalInitializer.new(@settings).call
@@ -91,6 +96,35 @@ module R10K
91
96
 
92
97
  results
93
98
  end
99
+
100
+ def add_credential_overrides(overrides)
101
+ sshkey_path = @opts[:'private-key']
102
+ token_path = @opts[:'oauth-token']
103
+
104
+ if sshkey_path && token_path
105
+ raise R10K::Error, "Cannot specify both an SSH key and a token to use with this deploy."
106
+ end
107
+
108
+ if sshkey_path
109
+ overrides[:git] ||= {}
110
+ overrides[:git][:private_key] = sshkey_path
111
+ if repo_settings = overrides[:git][:repositories]
112
+ repo_settings.each do |repo|
113
+ repo[:private_key] = sshkey_path
114
+ end
115
+ end
116
+ elsif token_path
117
+ overrides[:git] ||= {}
118
+ overrides[:git][:oauth_token] = token_path
119
+ if repo_settings = overrides[:git][:repositories]
120
+ repo_settings.each do |repo|
121
+ repo[:oauth_token] = token_path
122
+ end
123
+ end
124
+ end
125
+
126
+ overrides
127
+ end
94
128
  end
95
129
  end
96
130
  end
@@ -21,7 +21,7 @@ module R10K::CLI
21
21
  (https://puppet.com/docs/puppet/latest/environments_about.html).
22
22
  DESCRIPTION
23
23
 
24
- required nil, :cachedir, 'Specify a cachedir, overriding the value in config'
24
+ option nil, :cachedir, 'Specify a cachedir, overriding the value in config', argument: :required
25
25
  flag nil, :'no-force', 'Prevent the overwriting of local module modifications'
26
26
  flag nil, :'generate-types', 'Run `puppet generate types` after updating an environment'
27
27
  option nil, :'puppet-path', 'Path to puppet executable', argument: :required do |value, cmd|
@@ -31,6 +31,9 @@ module R10K::CLI
31
31
  exit 1
32
32
  end
33
33
  end
34
+ option nil, :'puppet-conf', 'Path to puppet.conf', argument: :required
35
+ option nil, :'private-key', 'Path to SSH key to use when cloning. Only valid with rugged provider', argument: :required
36
+ option nil, :'oauth-token', 'Path to OAuth token to use when cloning. Only valid with rugged provider', argument: :required
34
37
 
35
38
  run do |opts, args, cmd|
36
39
  puts cmd.help(:verbose => opts[:verbose])
@@ -52,7 +55,7 @@ branches.
52
55
 
53
56
  Environments can provide a Puppetfile at the root of the directory to deploy
54
57
  independent Puppet modules. To recursively deploy an environment, pass the
55
- `--puppetfile` flag to the command.
58
+ `--modules` flag to the command.
56
59
 
57
60
  **NOTE**: If an environment has a Puppetfile when it is instantiated a
58
61
  recursive update will be forced. It is assumed that environments are dependent
@@ -60,8 +63,10 @@ on modules specified in the Puppetfile and an update will be automatically
60
63
  scheduled. On subsequent deployments, Puppetfile deployment will default to off.
61
64
  DESCRIPTION
62
65
 
63
- flag :p, :puppetfile, 'Deploy modules from a puppetfile'
64
- required nil, :'default-branch-override', 'Specify a branchname to override the default branch in the puppetfile'
66
+ flag :p, :puppetfile, 'Deploy modules (deprecated, use -m)'
67
+ flag :m, :modules, 'Deploy modules'
68
+ option nil, :'default-branch-override', 'Specify a branchname to override the default branch in the puppetfile',
69
+ argument: :required
65
70
 
66
71
  runner R10K::Action::CriRunner.wrap(R10K::Action::Deploy::Environment)
67
72
  end
@@ -81,7 +86,7 @@ It will load the Puppetfile configurations out of all environments, and will
81
86
  try to deploy the given module names in all environments.
82
87
  DESCRIPTION
83
88
 
84
- required :e, :environment, 'Update the modules in the given environment'
89
+ option :e, :environment, 'Update the modules in the given environment', argument: :required
85
90
 
86
91
  runner R10K::Action::CriRunner.wrap(R10K::Action::Deploy::Module)
87
92
  end
@@ -96,10 +101,12 @@ try to deploy the given module names in all environments.
96
101
  usage 'display'
97
102
  summary 'Display environments and modules in the deployment'
98
103
 
99
- flag :p, :puppetfile, 'Display Puppetfile modules'
104
+ flag :p, :puppetfile, 'Display modules (deprecated, use -m)'
105
+ flag :m, :modules, 'Display modules'
100
106
  flag nil, :detail, 'Display detailed information'
101
107
  flag nil, :fetch, 'Update available environment lists from all remote sources'
102
- required nil, :format, 'Display output in a specific format. Valid values: json, yaml. Default: yaml'
108
+ option nil, :format, 'Display output in a specific format. Valid values: json, yaml. Default: yaml',
109
+ argument: :required
103
110
 
104
111
  runner R10K::Action::CriRunner.wrap(R10K::Action::Deploy::Display)
105
112
  end
@@ -30,8 +30,8 @@ Puppetfile (http://bombasticmonkey.com/librarian-puppet/).
30
30
  name 'install'
31
31
  usage 'install'
32
32
  summary 'Install all modules from a Puppetfile'
33
- required nil, :moduledir, 'Path to install modules to'
34
- required nil, :puppetfile, 'Path to puppetfile'
33
+ option nil, :moduledir, 'Path to install modules to', argument: :required
34
+ option nil, :puppetfile, 'Path to puppetfile', argument: :required
35
35
  flag nil, :force, 'Force locally changed files to be overwritten'
36
36
  runner R10K::Action::Puppetfile::CriRunner.wrap(R10K::Action::Puppetfile::Install)
37
37
  end
@@ -45,7 +45,7 @@ Puppetfile (http://bombasticmonkey.com/librarian-puppet/).
45
45
  usage 'check'
46
46
  summary 'Try and load the Puppetfile to verify the syntax is correct.'
47
47
 
48
- required nil, :puppetfile, 'Path to Puppetfile'
48
+ option nil, :puppetfile, 'Path to Puppetfile', argument: :required
49
49
  runner R10K::Action::Puppetfile::CriRunner.wrap(R10K::Action::Puppetfile::Check)
50
50
  end
51
51
  end
@@ -58,8 +58,8 @@ Puppetfile (http://bombasticmonkey.com/librarian-puppet/).
58
58
  usage 'purge'
59
59
  summary 'Purge unmanaged modules from a Puppetfile managed directory'
60
60
 
61
- required nil, :moduledir, 'Path to install modules to'
62
- required nil, :puppetfile, 'Path to Puppetfile'
61
+ option nil, :moduledir, 'Path to install modules to', argument: :required
62
+ option nil, :puppetfile, 'Path to Puppetfile', argument: :required
63
63
  runner R10K::Action::Puppetfile::CriRunner.wrap(R10K::Action::Puppetfile::Purge)
64
64
  end
65
65
  end
@@ -43,7 +43,7 @@ class R10K::Environment::Base
43
43
  @basedir = basedir
44
44
  @dirname = dirname
45
45
  @options = options
46
- @puppetfile_name = options[:puppetfile_name]
46
+ @puppetfile_name = options.delete(:puppetfile_name)
47
47
 
48
48
  @full_path = File.join(@basedir, @dirname)
49
49
  @path = Pathname.new(File.join(@basedir, @dirname))
@@ -103,6 +103,13 @@ class R10K::Environment::Base
103
103
  @puppetfile.modules
104
104
  end
105
105
 
106
+ # @return [Array<R10K::Module::Base>] Whether or not the given module
107
+ # conflicts with any modules already defined in the r10k environment
108
+ # object.
109
+ def module_conflicts?(mod)
110
+ false
111
+ end
112
+
106
113
  def accept(visitor)
107
114
  visitor.visit(:environment, self) do
108
115
  puppetfile.accept(visitor)
@@ -137,7 +144,7 @@ class R10K::Environment::Base
137
144
  end
138
145
 
139
146
  def generate_types!
140
- argv = [R10K::Settings.puppet_path, 'generate', 'types', '--environment', dirname, '--environmentpath', basedir]
147
+ argv = [R10K::Settings.puppet_path, 'generate', 'types', '--environment', dirname, '--environmentpath', basedir, '--config', R10K::Settings.puppet_conf]
141
148
  subproc = R10K::Util::Subprocess.new(argv)
142
149
  subproc.raise_on_fail = true
143
150
  subproc.logger = logger
@@ -27,6 +27,8 @@ class R10K::Environment::Git < R10K::Environment::WithModules
27
27
  # @return [R10K::Git::StatefulRepository] The git repo backing this environment
28
28
  attr_reader :repo
29
29
 
30
+ include R10K::Util::Setopts
31
+
30
32
  # Initialize the given Git environment.
31
33
  #
32
34
  # @param name [String] The unique name describing this environment.
@@ -38,8 +40,21 @@ class R10K::Environment::Git < R10K::Environment::WithModules
38
40
  # @param options [String] :ref The git reference to use for this environment
39
41
  def initialize(name, basedir, dirname, options = {})
40
42
  super
41
- @remote = options[:remote]
42
- @ref = options[:ref]
43
+ setopts(options, {
44
+ # Standard option interface
45
+ :version => :ref,
46
+ :source => :remote,
47
+ :type => ::R10K::Util::Setopts::Ignore,
48
+
49
+ # Type-specific options
50
+ :ref => :self,
51
+ :remote => :self,
52
+
53
+ }, raise_on_unhandled: false)
54
+ # TODO: in r10k 4.0.0, a major version bump, stop allowing garbage options.
55
+ # We only allow them now, here, on this object, because prior to adopting
56
+ # setopts in the constructor, this object type didn't do any validation
57
+ # checking of options passed, and would permit garbage parameters.
43
58
 
44
59
  @repo = R10K::Git::StatefulRepository.new(@remote, @basedir, @dirname)
45
60
  end
@@ -12,13 +12,13 @@ module R10K
12
12
  INVALID_CHARACTERS = %r[\W]
13
13
 
14
14
  def initialize(name, opts)
15
- @name = name
16
- @opts = opts
17
-
18
15
  @source = opts[:source]
19
16
  @prefix = opts[:prefix]
20
17
  @invalid = opts[:invalid]
21
18
 
19
+ @name = derive_name(name, opts[:strip_component])
20
+ @opts = opts
21
+
22
22
  case @invalid
23
23
  when 'correct_and_warn'
24
24
  @validate = true
@@ -71,8 +71,26 @@ module R10K
71
71
 
72
72
  private
73
73
 
74
- def derive_prefix(source,prefix)
74
+ def derive_name(name, strip_component)
75
+ return name unless strip_component
76
+
77
+ unless strip_component.is_a?(String)
78
+ raise _('Improper configuration value given for strip_component setting in %{src} source. ' \
79
+ 'Value must be a string, a /regex/, false, or omitted. Got "%{val}" (%{type})' \
80
+ % {src: @source, val: strip_component, type: strip_component.class})
81
+ end
75
82
 
83
+ if %r{^/.*/$}.match(strip_component)
84
+ regex = Regexp.new(strip_component[1..-2])
85
+ name.gsub(regex, '')
86
+ elsif name.start_with?(strip_component)
87
+ name[strip_component.size..-1]
88
+ else
89
+ name
90
+ end
91
+ end
92
+
93
+ def derive_prefix(source,prefix)
76
94
  if prefix == true
77
95
  "#{source}_"
78
96
  elsif prefix.is_a? String
@@ -44,8 +44,17 @@ class R10K::Environment::SVN < R10K::Environment::Base
44
44
  # @option options [String] :password The SVN password
45
45
  def initialize(name, basedir, dirname, options = {})
46
46
  super
47
+ setopts(options, {
48
+ # Standard option interface
49
+ :source => :remote,
50
+ :version => :expected_revision,
51
+ :type => ::R10K::Util::Setopts::Ignore,
47
52
 
48
- setopts(options, {:remote => :self, :username => :self, :password => :self, :puppetfile_name => :self })
53
+ # Type-specific options
54
+ :remote => :self,
55
+ :username => :self,
56
+ :password => :self,
57
+ })
49
58
 
50
59
  @working_dir = R10K::SVN::WorkingDir.new(Pathname.new(@full_path), :username => @username, :password => @password)
51
60
  end
@@ -61,7 +70,7 @@ class R10K::Environment::SVN < R10K::Environment::Base
61
70
  if @working_dir.is_svn?
62
71
  @working_dir.update
63
72
  else
64
- @working_dir.checkout(@remote)
73
+ @working_dir.checkout(@remote, @expected_revision)
65
74
  end
66
75
  @synced = true
67
76
  end
@@ -24,7 +24,7 @@ class R10K::Environment::WithModules < R10K::Environment::Base
24
24
  # @param options [String] :moduledir The path to install modules to
25
25
  # @param options [Hash] :modules Modules to add to the environment
26
26
  def initialize(name, basedir, dirname, options = {})
27
- super(name, basedir, dirname, options)
27
+ super
28
28
 
29
29
  @managed_content = {}
30
30
  @modules = []
@@ -46,10 +46,33 @@ class R10K::Environment::WithModules < R10K::Environment::Base
46
46
  # - The r10k environment object
47
47
  # - A Puppetfile in the environment's content
48
48
  def modules
49
- return @modules if @puppetfile.nil?
49
+ return @modules if puppetfile.nil?
50
50
 
51
- @puppetfile.load unless @puppetfile.loaded?
52
- @modules + @puppetfile.modules
51
+ puppetfile.load unless puppetfile.loaded?
52
+ @modules + puppetfile.modules
53
+ end
54
+
55
+ def module_conflicts?(mod_b)
56
+ conflict = @modules.any? { |mod_a| mod_a.name == mod_b.name }
57
+ return false unless conflict
58
+
59
+ msg_vars = {src: mod_b.origin, name: mod_b.name}
60
+ msg_error = _('Environment and %{src} both define the "%{name}" module' % msg_vars)
61
+ msg_continue = _("#{msg_error}. The %{src} definition will be ignored" % msg_vars)
62
+
63
+ case conflict_opt = @options[:module_conflicts]
64
+ when 'override_and_warn', nil
65
+ logger.warn msg_continue
66
+ when 'override'
67
+ logger.debug msg_continue
68
+ when 'error'
69
+ raise R10K::Error, msg_error
70
+ else
71
+ raise R10K::Error, _('Unexpected value for `module_conflicts` setting in %{env} ' \
72
+ 'environment: %{val}' % {env: self.name, val: conflict_opt})
73
+ end
74
+
75
+ true
53
76
  end
54
77
 
55
78
  def accept(visitor)
@@ -59,7 +82,6 @@ class R10K::Environment::WithModules < R10K::Environment::Base
59
82
  end
60
83
 
61
84
  puppetfile.accept(visitor)
62
- validate_no_module_conflicts
63
85
  end
64
86
  end
65
87
 
@@ -88,26 +110,12 @@ class R10K::Environment::WithModules < R10K::Environment::Base
88
110
  @managed_content[install_path] = Array.new unless @managed_content.has_key?(install_path)
89
111
 
90
112
  mod = R10K::Module.new(name, install_path, args, self.name)
91
- mod.origin = 'Environment'
113
+ mod.origin = :environment
92
114
 
93
115
  @managed_content[install_path] << mod.name
94
116
  @modules << mod
95
117
  end
96
118
 
97
- def validate_no_module_conflicts
98
- @puppetfile.load unless @puppetfile.loaded?
99
- conflicts = (@modules + @puppetfile.modules)
100
- .group_by { |mod| mod.name }
101
- .select { |_, v| v.size > 1 }
102
- .map(&:first)
103
- unless conflicts.empty?
104
- msg = _('Puppetfile cannot contain module names defined by environment %{name}') % {name: self.name}
105
- msg += ' '
106
- msg += _("Remove the conflicting definitions of the following modules: %{conflicts}" % { conflicts: conflicts.join(' ') })
107
- raise R10K::Error.new(msg)
108
- end
109
- end
110
-
111
119
  include R10K::Util::Purgeable
112
120
 
113
121
  # Returns an array of the full paths that can be purged.