r10k 3.8.0 → 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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/docker.yml +4 -1
  3. data/.github/workflows/release.yml +3 -2
  4. data/.github/workflows/rspec_tests.yml +1 -1
  5. data/.travis.yml +8 -1
  6. data/CHANGELOG.mkd +10 -0
  7. data/CODEOWNERS +1 -1
  8. data/doc/common-patterns.mkd +1 -0
  9. data/doc/dynamic-environments/configuration.mkd +90 -43
  10. data/doc/dynamic-environments/usage.mkd +7 -7
  11. data/doc/puppetfile.mkd +23 -3
  12. data/docker/Gemfile +1 -1
  13. data/docker/Makefile +4 -3
  14. data/docker/docker-compose.yml +18 -0
  15. data/docker/r10k/Dockerfile +1 -1
  16. data/docker/r10k/docker-entrypoint.sh +0 -1
  17. data/docker/r10k/release.Dockerfile +1 -1
  18. data/docker/spec/dockerfile_spec.rb +26 -32
  19. data/integration/tests/git_source/git_source_repeated_remote.rb +2 -2
  20. data/integration/tests/user_scenario/basic_workflow/multi_env_custom_forge_git_module.rb +2 -1
  21. data/integration/tests/user_scenario/basic_workflow/multi_env_custom_forge_git_module_static.rb +2 -1
  22. data/integration/tests/user_scenario/basic_workflow/multi_source_custom_forge_git_module.rb +1 -1
  23. data/integration/tests/user_scenario/basic_workflow/single_env_custom_forge_git_module.rb +2 -1
  24. data/lib/r10k/action/deploy/display.rb +9 -3
  25. data/lib/r10k/action/deploy/environment.rb +36 -14
  26. data/lib/r10k/cli/deploy.rb +5 -3
  27. data/lib/r10k/environment/base.rb +1 -1
  28. data/lib/r10k/environment/git.rb +17 -2
  29. data/lib/r10k/environment/name.rb +22 -4
  30. data/lib/r10k/environment/svn.rb +11 -2
  31. data/lib/r10k/environment/with_modules.rb +1 -1
  32. data/lib/r10k/git/rugged/credentials.rb +22 -15
  33. data/lib/r10k/module/forge.rb +15 -3
  34. data/lib/r10k/module/git.rb +24 -23
  35. data/lib/r10k/module/local.rb +1 -1
  36. data/lib/r10k/module/svn.rb +14 -11
  37. data/lib/r10k/settings.rb +6 -1
  38. data/lib/r10k/source/base.rb +5 -0
  39. data/lib/r10k/source/git.rb +4 -1
  40. data/lib/r10k/source/hash.rb +4 -2
  41. data/lib/r10k/source/svn.rb +5 -1
  42. data/lib/r10k/util/setopts.rb +33 -12
  43. data/lib/r10k/version.rb +1 -1
  44. data/locales/r10k.pot +22 -18
  45. data/r10k.gemspec +1 -1
  46. data/spec/unit/action/deploy/display_spec.rb +4 -0
  47. data/spec/unit/action/deploy/environment_spec.rb +111 -10
  48. data/spec/unit/environment/git_spec.rb +16 -0
  49. data/spec/unit/environment/name_spec.rb +28 -0
  50. data/spec/unit/environment/svn_spec.rb +12 -0
  51. data/spec/unit/git/rugged/credentials_spec.rb +10 -0
  52. data/spec/unit/module/forge_spec.rb +6 -0
  53. data/spec/unit/module/git_spec.rb +1 -1
  54. data/spec/unit/module_spec.rb +59 -9
  55. data/spec/unit/util/setopts_spec.rb +25 -1
  56. metadata +5 -11
  57. data/azure-pipelines.yml +0 -87
@@ -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 = []
@@ -67,22 +67,10 @@ class R10K::Git::Rugged::Credentials
67
67
  end
68
68
 
69
69
  if token_path = per_repo_oauth_token || R10K::Git.settings[:oauth_token]
70
- if token_path == '-'
71
- token = $stdin.read.strip
72
- logger.debug2 _("Using OAuth token from stdin for URL %{url}") % { url: url }
73
- elsif File.readable?(token_path)
74
- token = File.read(token_path).strip
75
- logger.debug2 _("Using OAuth token from %{token_path} for URL %{url}") % { token_path: token_path, url: url }
76
- else
77
- raise R10K::Git::GitError, _("%{path} is missing or unreadable, cannot load OAuth token") % { path: token_path }
78
- end
79
-
80
- unless valid_token?(token)
81
- raise R10K::Git::GitError, _("Supplied OAuth token contains invalid characters.")
82
- end
70
+ @oauth_token ||= extract_token(token_path, url)
83
71
 
84
72
  user = 'x-oauth-token'
85
- password = token
73
+ password = @oauth_token
86
74
  else
87
75
  user = get_git_username(url, username_from_url)
88
76
  password = URI.parse(url).password || ''
@@ -90,10 +78,29 @@ class R10K::Git::Rugged::Credentials
90
78
  Rugged::Credentials::UserPassword.new(username: user, password: password)
91
79
  end
92
80
 
81
+ def extract_token(token_path, url)
82
+ if token_path == '-'
83
+ token = $stdin.read.strip
84
+ logger.debug2 _("Using OAuth token from stdin for URL %{url}") % { url: url }
85
+ elsif File.readable?(token_path)
86
+ token = File.read(token_path).strip
87
+ logger.debug2 _("Using OAuth token from %{token_path} for URL %{url}") % { token_path: token_path, url: url }
88
+ else
89
+ raise R10K::Git::GitError, _("%{path} is missing or unreadable, cannot load OAuth token") % { path: token_path }
90
+ end
91
+
92
+ unless valid_token?(token)
93
+ raise R10K::Git::GitError, _("Supplied OAuth token contains invalid characters.")
94
+ end
95
+
96
+ token
97
+ end
98
+
93
99
  # This regex is the only real requirement for OAuth token format,
94
100
  # per https://www.oauth.com/oauth2-servers/access-tokens/access-token-response/
101
+ # Bitbucket's tokens also can include an underscore, so that is added here.
95
102
  def valid_token?(token)
96
- return token =~ /^[\w\-\.~\+\/]+$/
103
+ return token =~ /^[\w\-\.~_\+\/]+$/
97
104
  end
98
105
 
99
106
  def get_default_credentials(url, username_from_url)
@@ -13,7 +13,7 @@ class R10K::Module::Forge < R10K::Module::Base
13
13
  R10K::Module.register(self)
14
14
 
15
15
  def self.implement?(name, args)
16
- !!(name.match %r[\w+[/-]\w+]) && valid_version?(args)
16
+ (args.is_a?(Hash) && args[:type].to_s == 'forge') || (!!(name.match %r[\w+[/-]\w+]) && valid_version?(args))
17
17
  end
18
18
 
19
19
  def self.valid_version?(expected_version)
@@ -32,13 +32,25 @@ class R10K::Module::Forge < R10K::Module::Base
32
32
 
33
33
  include R10K::Logging
34
34
 
35
- def initialize(title, dirname, expected_version, environment=nil)
35
+ include R10K::Util::Setopts
36
+
37
+ def initialize(title, dirname, opts, environment=nil)
36
38
  super
37
39
 
38
40
  @metadata_file = R10K::Module::MetadataFile.new(path + 'metadata.json')
39
41
  @metadata = @metadata_file.read
40
42
 
41
- @expected_version = expected_version || current_version || :latest
43
+ if opts.is_a?(Hash)
44
+ setopts(opts, {
45
+ # Standard option interface
46
+ :version => :expected_version,
47
+ :source => ::R10K::Util::Setopts::Ignore,
48
+ :type => ::R10K::Util::Setopts::Ignore,
49
+ })
50
+ else
51
+ @expected_version = opts || current_version || :latest
52
+ end
53
+
42
54
  @v3_module = PuppetForge::V3::Module.new(:slug => @title)
43
55
  end
44
56
 
@@ -8,7 +8,7 @@ class R10K::Module::Git < R10K::Module::Base
8
8
  R10K::Module.register(self)
9
9
 
10
10
  def self.implement?(name, args)
11
- args.is_a? Hash and args.has_key?(:git)
11
+ args.is_a?(Hash) && (args.has_key?(:git) || args[:type].to_s == 'git')
12
12
  rescue
13
13
  false
14
14
  end
@@ -33,10 +33,31 @@ class R10K::Module::Git < R10K::Module::Base
33
33
  # @return [String]
34
34
  attr_reader :default_override_ref
35
35
 
36
- def initialize(title, dirname, args, environment=nil)
36
+ include R10K::Util::Setopts
37
+
38
+ def initialize(title, dirname, opts, environment=nil)
37
39
  super
40
+ setopts(opts, {
41
+ # Standard option interface
42
+ :version => :desired_ref,
43
+ :source => :remote,
44
+ :type => ::R10K::Util::Setopts::Ignore,
45
+
46
+ # Type-specific options
47
+ :branch => :desired_ref,
48
+ :tag => :desired_ref,
49
+ :commit => :desired_ref,
50
+ :ref => :desired_ref,
51
+ :git => :remote,
52
+ :default_branch => :default_ref,
53
+ :default_branch_override => :default_override_ref,
54
+ })
55
+
56
+ @desired_ref ||= 'master'
38
57
 
39
- parse_options(@args)
58
+ if @desired_ref == :control_branch && @environment && @environment.respond_to?(:ref)
59
+ @desired_ref = @environment.ref
60
+ end
40
61
 
41
62
  @repo = R10K::Git::StatefulRepository.new(@remote, @dirname, @name)
42
63
  end
@@ -103,24 +124,4 @@ class R10K::Module::Git < R10K::Module::Base
103
124
  raise ArgumentError, _(msg.join(' ')) % vars
104
125
  end
105
126
  end
106
-
107
- def parse_options(options)
108
- ref_opts = [:branch, :tag, :commit, :ref]
109
- known_opts = [:git, :default_branch, :default_branch_override] + ref_opts
110
-
111
- unhandled = options.keys - known_opts
112
- unless unhandled.empty?
113
- raise ArgumentError, _("Unhandled options %{unhandled} specified for %{class}") % {unhandled: unhandled, class: self.class}
114
- end
115
-
116
- @remote = options[:git]
117
-
118
- @desired_ref = ref_opts.find { |key| break options[key] if options.has_key?(key) } || 'master'
119
- @default_ref = options[:default_branch]
120
- @default_override_ref = options[:default_branch_override]
121
-
122
- if @desired_ref == :control_branch && @environment && @environment.respond_to?(:ref)
123
- @desired_ref = @environment.ref
124
- end
125
- end
126
127
  end
@@ -9,7 +9,7 @@ class R10K::Module::Local < R10K::Module::Base
9
9
  R10K::Module.register(self)
10
10
 
11
11
  def self.implement?(name, args)
12
- args.is_a?(Hash) && args[:local]
12
+ args.is_a?(Hash) && (args[:local] || args[:type].to_s == 'local')
13
13
  end
14
14
 
15
15
  include R10K::Logging
@@ -7,7 +7,7 @@ class R10K::Module::SVN < R10K::Module::Base
7
7
  R10K::Module.register(self)
8
8
 
9
9
  def self.implement?(name, args)
10
- args.is_a? Hash and args.has_key? :svn
10
+ args.is_a?(Hash) && (args.has_key?(:svn) || args[:type].to_s == 'svn')
11
11
  end
12
12
 
13
13
  # @!attribute [r] expected_revision
@@ -36,18 +36,21 @@ class R10K::Module::SVN < R10K::Module::Base
36
36
 
37
37
  include R10K::Util::Setopts
38
38
 
39
- INITIALIZE_OPTS = {
40
- :svn => :url,
41
- :rev => :expected_revision,
42
- :revision => :expected_revision,
43
- :username => :self,
44
- :password => :self
45
- }
46
-
47
39
  def initialize(name, dirname, opts, environment=nil)
48
40
  super
49
-
50
- setopts(opts, INITIALIZE_OPTS)
41
+ setopts(opts, {
42
+ # Standard option interface
43
+ :source => :url,
44
+ :version => :expected_revision,
45
+ :type => ::R10K::Util::Setopts::Ignore,
46
+
47
+ # Type-specific options
48
+ :svn => :url,
49
+ :rev => :expected_revision,
50
+ :revision => :expected_revision,
51
+ :username => :self,
52
+ :password => :self
53
+ })
51
54
 
52
55
  @working_dir = R10K::SVN::WorkingDir.new(@path, :username => @username, :password => @password)
53
56
  end
data/lib/r10k/settings.rb CHANGED
@@ -122,11 +122,16 @@ module R10K
122
122
  end,
123
123
  }),
124
124
 
125
- Definition.new(:purge_whitelist, {
125
+ Definition.new(:purge_allowlist, {
126
126
  :desc => "A list of filename patterns to be excluded from any purge operations. Patterns are matched relative to the root of each deployed environment, if you want a pattern to match recursively you need to use the '**' glob in your pattern. Basic shell style globs are supported.",
127
127
  :default => [],
128
128
  }),
129
129
 
130
+ Definition.new(:purge_whitelist, {
131
+ :desc => "Deprecated; please use purge_allowlist instead. This setting will be removed in a future version.",
132
+ :default => [],
133
+ }),
134
+
130
135
  Definition.new(:generate_types, {
131
136
  :desc => "Controls whether to generate puppet types after deploying an environment. Defaults to false.",
132
137
  :default => false,
@@ -31,10 +31,15 @@ class R10K::Source::Base
31
31
  # @option options [Boolean, String] :prefix If a String this becomes the prefix.
32
32
  # If true, will use the source name as the prefix. All sources should respect this option.
33
33
  # Defaults to false for no environment prefix.
34
+ # @option options [String] :strip_component If a string, this value will be
35
+ # removed from the beginning of each generated environment's name, if
36
+ # present. If the string is contained within two "/" characters, it will
37
+ # be treated as a regular expression.
34
38
  def initialize(name, basedir, options = {})
35
39
  @name = name
36
40
  @basedir = Pathname.new(basedir).cleanpath.to_s
37
41
  @prefix = options.delete(:prefix)
42
+ @strip_component = options.delete(:strip_component)
38
43
  @puppetfile_name = options.delete(:puppetfile_name)
39
44
  @options = options
40
45
  end
@@ -145,7 +145,10 @@ class R10K::Source::Git < R10K::Source::Base
145
145
  private
146
146
 
147
147
  def branch_names
148
- opts = {:prefix => @prefix, :invalid => @invalid_branches, :source => @name}
148
+ opts = {prefix: @prefix,
149
+ invalid: @invalid_branches,
150
+ source: @name,
151
+ strip_component: @strip_component}
149
152
  branches = @cache.branches
150
153
  if @ignore_branch_prefixes && !@ignore_branch_prefixes.empty?
151
154
  branches = filter_branches_by_regexp(branches, @ignore_branch_prefixes)
@@ -152,8 +152,10 @@ class R10K::Source::Hash < R10K::Source::Base
152
152
  R10K::Util::SymbolizeKeys.symbolize_keys!(opts)
153
153
  memo.merge({
154
154
  name => opts.merge({
155
- :basedir => @basedir,
156
- :dirname => R10K::Environment::Name.new(name, {prefix: @prefix, source: @name}).dirname
155
+ basedir: @basedir,
156
+ dirname: R10K::Environment::Name.new(name, {prefix: @prefix,
157
+ source: @name,
158
+ strip_component: @strip_component}).dirname
157
159
  })
158
160
  })
159
161
  end
@@ -121,7 +121,11 @@ class R10K::Source::SVN < R10K::Source::Base
121
121
 
122
122
  def names_and_paths
123
123
  branches = []
124
- opts = {:prefix => @prefix, :correct => false, :validate => false, :source => @name}
124
+ opts = {prefix: @prefix,
125
+ correct: false,
126
+ validate: false,
127
+ source: @name,
128
+ strip_component: @strip_component}
125
129
  branches << [R10K::Environment::Name.new('production', opts), "#{@remote}/trunk"]
126
130
  additional_branch_names = @svn_remote.branches
127
131
  if @ignore_branch_prefixes && !@ignore_branch_prefixes.empty?
@@ -7,6 +7,10 @@ module R10K
7
7
  # supports Ruby 1.8.7+ we cannot use that functionality.
8
8
  module Setopts
9
9
 
10
+ class Ignore; end
11
+
12
+ include R10K::Logging
13
+
10
14
  private
11
15
 
12
16
  # @param opts [Hash]
@@ -31,22 +35,39 @@ module R10K
31
35
  # setopts(opts, allowed)
32
36
  # @trace # => nil
33
37
  #
34
- def setopts(opts, allowed)
38
+ def setopts(opts, allowed, raise_on_unhandled: true)
39
+ processed_vars = {}
35
40
  opts.each_pair do |key, value|
36
41
  if allowed.key?(key)
37
- rhs = allowed[key]
38
- case rhs
39
- when NilClass, FalseClass
40
- # Ignore nil options
41
- when :self, TrueClass
42
- # tr here is because instance variables cannot have hyphens in their names.
43
- instance_variable_set("@#{key}".tr('-','_').to_sym, value)
44
- else
45
- # tr here same as previous
46
- instance_variable_set("@#{rhs}".tr('-','_').to_sym, value)
42
+ # Ignore nil options and explicit ignore param
43
+ next unless rhs = allowed[key]
44
+ next if rhs == ::R10K::Util::Setopts::Ignore
45
+
46
+ var = case rhs
47
+ when :self, TrueClass
48
+ # tr here is because instance variables cannot have hyphens in their names.
49
+ "@#{key}".tr('-','_').to_sym
50
+ else
51
+ # tr here same as previous
52
+ "@#{rhs}".tr('-','_').to_sym
53
+ end
54
+
55
+ if processed_vars.include?(var)
56
+ # This should be a raise, but that would be a behavior change and
57
+ # should happen on a SemVer boundry.
58
+ logger.warn _("%{class_name} parameters '%{a}' and '%{b}' conflict. Specify one or the other, but not both" \
59
+ % {class_name: self.class.name, a: processed_vars[var], b: key})
47
60
  end
61
+
62
+ instance_variable_set(var, value)
63
+ processed_vars[var] = key
48
64
  else
49
- raise ArgumentError, _("%{class_name} cannot handle option '%{key}'") % {class_name: self.class.name, key: key}
65
+ err_str = _("%{class_name} cannot handle option '%{key}'") % {class_name: self.class.name, key: key}
66
+ if raise_on_unhandled
67
+ raise ArgumentError, err_str
68
+ else
69
+ logger.warn(err_str)
70
+ end
50
71
  end
51
72
  end
52
73
  end
data/lib/r10k/version.rb CHANGED
@@ -2,5 +2,5 @@ module R10K
2
2
  # When updating to a new major (X) or minor (Y) version, include `#major` or
3
3
  # `#minor` (respectively) in your commit message to trigger the appropriate
4
4
  # release. Otherwise, a new patch (Z) version will be released.
5
- VERSION = '3.8.0'
5
+ VERSION = '3.9.0'
6
6
  end
data/locales/r10k.pot CHANGED
@@ -6,11 +6,11 @@
6
6
  #, fuzzy
7
7
  msgid ""
8
8
  msgstr ""
9
- "Project-Id-Version: r10k 3.4.1-133-g2007a86\n"
9
+ "Project-Id-Version: r10k 3.4.1-151-g93d38cb\n"
10
10
  "\n"
11
11
  "Report-Msgid-Bugs-To: docs@puppetlabs.com\n"
12
- "POT-Creation-Date: 2021-02-12 02:00+0000\n"
13
- "PO-Revision-Date: 2021-02-12 02:00+0000\n"
12
+ "POT-Creation-Date: 2021-03-15 17:00+0000\n"
13
+ "PO-Revision-Date: 2021-03-15 17:00+0000\n"
14
14
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
15
15
  "Language-Team: LANGUAGE <LL@li.org>\n"
16
16
  "Language: \n"
@@ -103,10 +103,14 @@ msgstr ""
103
103
  msgid "Unable to load sources; the supplied configuration does not define the 'sources' key"
104
104
  msgstr ""
105
105
 
106
- #: ../lib/r10k/environment/base.rb:61 ../lib/r10k/environment/base.rb:77 ../lib/r10k/environment/base.rb:86 ../lib/r10k/source/base.rb:64
106
+ #: ../lib/r10k/environment/base.rb:61 ../lib/r10k/environment/base.rb:77 ../lib/r10k/environment/base.rb:86 ../lib/r10k/source/base.rb:69
107
107
  msgid "%{class} has not implemented method %{method}"
108
108
  msgstr ""
109
109
 
110
+ #: ../lib/r10k/environment/name.rb:78
111
+ msgid "Improper configuration value given for strip_component setting in %{src} source. Value must be a string, a /regex/, false, or omitted. Got \"%{val}\" (%{type})"
112
+ msgstr ""
113
+
110
114
  #: ../lib/r10k/environment/with_modules.rb:60
111
115
  msgid "Environment and %{src} both define the \"%{name}\" module"
112
116
  msgstr ""
@@ -231,31 +235,31 @@ msgstr ""
231
235
  msgid "Unable to use SSH key auth for %{url}: private key %{private_key} is missing or unreadable"
232
236
  msgstr ""
233
237
 
234
- #: ../lib/r10k/git/rugged/credentials.rb:72
238
+ #: ../lib/r10k/git/rugged/credentials.rb:84
235
239
  msgid "Using OAuth token from stdin for URL %{url}"
236
240
  msgstr ""
237
241
 
238
- #: ../lib/r10k/git/rugged/credentials.rb:75
242
+ #: ../lib/r10k/git/rugged/credentials.rb:87
239
243
  msgid "Using OAuth token from %{token_path} for URL %{url}"
240
244
  msgstr ""
241
245
 
242
- #: ../lib/r10k/git/rugged/credentials.rb:77
246
+ #: ../lib/r10k/git/rugged/credentials.rb:89
243
247
  msgid "%{path} is missing or unreadable, cannot load OAuth token"
244
248
  msgstr ""
245
249
 
246
- #: ../lib/r10k/git/rugged/credentials.rb:81
250
+ #: ../lib/r10k/git/rugged/credentials.rb:93
247
251
  msgid "Supplied OAuth token contains invalid characters."
248
252
  msgstr ""
249
253
 
250
- #: ../lib/r10k/git/rugged/credentials.rb:110
254
+ #: ../lib/r10k/git/rugged/credentials.rb:117
251
255
  msgid "URL %{url} includes the username %{username}, using that user for authentication."
252
256
  msgstr ""
253
257
 
254
- #: ../lib/r10k/git/rugged/credentials.rb:113
258
+ #: ../lib/r10k/git/rugged/credentials.rb:120
255
259
  msgid "URL %{url} did not specify a user, using %{user} from configuration"
256
260
  msgstr ""
257
261
 
258
- #: ../lib/r10k/git/rugged/credentials.rb:116
262
+ #: ../lib/r10k/git/rugged/credentials.rb:123
259
263
  msgid "URL %{url} did not specify a user, using current user %{user}"
260
264
  msgstr ""
261
265
 
@@ -327,18 +331,14 @@ msgstr ""
327
331
  msgid "Module name (%{title}) must match either 'modulename' or 'owner/modulename'"
328
332
  msgstr ""
329
333
 
330
- #: ../lib/r10k/module/forge.rb:70 ../lib/r10k/module/forge.rb:99
334
+ #: ../lib/r10k/module/forge.rb:81 ../lib/r10k/module/forge.rb:110
331
335
  msgid "The module %{title} does not exist on %{url}."
332
336
  msgstr ""
333
337
 
334
- #: ../lib/r10k/module/forge.rb:174
338
+ #: ../lib/r10k/module/forge.rb:185
335
339
  msgid "Forge module names must match 'owner/modulename', instead got #{title}"
336
340
  msgstr ""
337
341
 
338
- #: ../lib/r10k/module/git.rb:113
339
- msgid "Unhandled options %{unhandled} specified for %{class}"
340
- msgstr ""
341
-
342
342
  #: ../lib/r10k/module/local.rb:34
343
343
  msgid "Module %{title} is a local module, always indicating synced."
344
344
  msgstr ""
@@ -546,7 +546,11 @@ msgstr ""
546
546
  msgid "Unable to remove unmanaged path: %{path}"
547
547
  msgstr ""
548
548
 
549
- #: ../lib/r10k/util/setopts.rb:49
549
+ #: ../lib/r10k/util/setopts.rb:58
550
+ msgid "%{class_name} parameters '%{a}' and '%{b}' conflict. Specify one or the other, but not both"
551
+ msgstr ""
552
+
553
+ #: ../lib/r10k/util/setopts.rb:65
550
554
  msgid "%{class_name} cannot handle option '%{key}'"
551
555
  msgstr ""
552
556