r10k 2.5.5 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 1751a994285442b34b30d2274ed0049c242ad7b4
4
- data.tar.gz: bea09a73ff5954f2f434ab018c307f3efc59e420
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NTZjY2UzMDMyMTJlNjIzZmQzNzk4MGViMGMzMjM0Yzc2MzdkZjg2MQ==
5
+ data.tar.gz: !binary |-
6
+ YTE1ZjhkYzBiZjY1YTFiOGUyMTliM2Q2MDAzNzg3YzA4NjUyN2Q0Ng==
5
7
  SHA512:
6
- metadata.gz: 727021b3144cdf93ccadb11c9718ceccc2f054bc310614fdec5881e1ae704b65b50a385ceed17f68b446cc31ee5ed5bdd194c7c3ae66bf1183c0fd17de55b10d
7
- data.tar.gz: 9975f54ffa36bdbd0a5c27d0478fca297f95a151a957b931fc12749f5d0fe62c5655afa3979f03bf6c4ea09cc0cd31dc40c4b7ed85caa1ecd63e3a0a990c7737
8
+ metadata.gz: !binary |-
9
+ NDRiNTI5NDA3NGQzNmVjODZjN2NlNmMyYjVjMjVjM2ZkYjNiMmY0ZWUyMjNj
10
+ NWI1NjExNTk2NDJhM2M0NjFlN2ExZTVmNGU5MzRmNjJjYWY1NzliMGY2Mzgy
11
+ NmUyN2FlNzZjMDAwMWFhMTdmZDA4ZTY4NThiZTBlMmM5MWZjOGE=
12
+ data.tar.gz: !binary |-
13
+ MmM4YzFlNTBmNTYyMzMxYjA0Zjc2YWU0OTJlMzQ1YzFmM2E2NDEzZGM2MWZi
14
+ NTczNzVhODdhNTc0Yjg0OWVhYjIxOTUwY2NkOTUyYmY0MzMyY2FhNDc1Mzhj
15
+ YWNlYTVjMGMwYjJmNjUwMDIxMTFiOTg4NTE4Yjk3ODVlNjg3Mzg=
@@ -5,6 +5,7 @@ script: "bundle exec rspec --color --format documentation spec/unit"
5
5
  notifications:
6
6
  email: false
7
7
  sudo: false
8
+ before_install: gem update bundler
8
9
  rvm:
9
10
  - "2.3.0"
10
11
  - "2.2.0"
@@ -1,6 +1,26 @@
1
1
  CHANGELOG
2
2
  =========
3
3
 
4
+ 2.6.0
5
+ -----
6
+
7
+ ### New Features
8
+
9
+ (RK-307) Branches can now be ignored by prefixes during deployment.
10
+
11
+ (RK-305) Add --no-force to deploy action to avoid overwriting local module changes.
12
+
13
+ (RK-264) Add --force action to puppetfile install to force overwriting local
14
+ module changes.
15
+
16
+ (RK-291) (RK-304) Add caching of forge modules.
17
+
18
+ ### Changes
19
+
20
+ (RK-306) Remove the dependency on semantic_puppet.
21
+
22
+ (RK-161) Deprecate the usage of PUPPETFILE and PUPPETFILE_DIR environment variables.
23
+
4
24
  2.5.5
5
25
  -----
6
26
 
@@ -356,6 +356,32 @@ sources:
356
356
  * if `false` (default) environment folder will not be prefixed
357
357
  * if `String` environment folder will be prefixed with the `prefix` value.
358
358
 
359
+ ### ignore_branch_prefixes
360
+
361
+ The 'ignore_branch_prefixes' setting causes environments to be ignored which match in part or whole
362
+ to any of the prefixes listed in the setting.
363
+ The setting is a list of strings. Each branch in
364
+ the 'git' repo will have its name tested against all prefixes and, if the prefix
365
+ is found, then an environment will not be deployed for this branch.
366
+ If no 'ignore_branch_prefixes' is specified, then all branches in the 'git' repo will
367
+ be deployed (default behavior).
368
+
369
+ #### ignore_branch_prefixes behaviour
370
+ * if empty, deploy environments for all branches
371
+ * for each branch in git repo
372
+ ** if `branch.name` has a prefix found in `ignore_branch_prefixes`, then do not deploy an environment for branch
373
+
374
+ Example: do not deploy branches with names starting with (or completely named) 'test' or 'dev'.
375
+ ```yaml
376
+ ---
377
+ sources:
378
+ mysource:
379
+ basedir: '/etc/puppet/environments'
380
+ ignore_branch_prefixes:
381
+ - 'test'
382
+ - 'dev'
383
+ ```
384
+
359
385
  Examples
360
386
  --------
361
387
 
@@ -306,7 +306,7 @@ The given 'install\_path' can be an absolute path or a path relative to the base
306
306
  the environment. Note that r10k will exit with an error if you attempt to set the
307
307
  'path' option to a directory outside of the environment.
308
308
 
309
- ## Environment variables
309
+ ## Environment variables (**DEPRECATED** as of 2.5.6)
310
310
 
311
311
  It is possible to set an alternate name/location for your `Puppetfile` and
312
312
  `modules` directory. This is useful if you want to control multiple environments
@@ -76,6 +76,10 @@ def r10k_revert_environment(host, commit_sha, git_repo_path)
76
76
  #Force push changes to remote.
77
77
  git_on(host, 'push origin --mirror --force', git_repo_path)
78
78
  git_on(host, 'push origin --mirror --force', git_repo_path)
79
+
80
+ #Remove r10k cache
81
+ cachedir = '/var/cache/r10k'
82
+ on(master, "rm -rf #{cachedir}")
79
83
  end
80
84
 
81
85
  # Clean-up the r10k environment on the master to bring it back to a known good state.
@@ -102,6 +106,13 @@ def clean_up_r10k(master, commit_sha, git_repo_path)
102
106
  step 'Reset Git Repo to Known Good State'
103
107
  r10k_revert_environment(master, commit_sha, git_repo_path)
104
108
 
109
+ # RK-297 workaround. Without this, tests will fail with an error like the following:
110
+ # [2017-06-02 11:11:46 - ERROR] Object not found - no match for id (60e4ea82c9fdf86974a13f78b839a497325de04b)
111
+ # This cleanup should not be necessary when RK-297 has been resolved.
112
+ #
113
+ step 'Remove git directories from codedir to prevent cache errors'
114
+ on(master, "find #{environment_path } -name .git -type d -print0 | xargs -r0 -- rm -r")
115
+
105
116
  step 'Restore Original "production" Environment'
106
117
  on(master, "#{r10k_fqp} deploy environment -v")
107
118
 
@@ -66,7 +66,5 @@ git_add_commit_push(master, 'production', 'add Puppetfile', git_environments_pat
66
66
  on(master, "#{r10k_fqp} deploy environment -p", :accept_all_exit_codes => true) do |r|
67
67
  regex = /proxy.*ilovecatvideos\.com/
68
68
  assert(r.exit_code == 1, 'expected error code was not observed')
69
- expect_failure('Failure due to RK-262') do
70
- assert_match(regex, r.stderr, 'The expected error message was not observed' )
71
- end
69
+ assert_match(regex, r.stderr, 'The expected error message was not observed' )
72
70
  end
@@ -13,6 +13,8 @@ module R10K
13
13
 
14
14
  include R10K::Action::Deploy::DeployHelpers
15
15
 
16
+ attr_reader :force
17
+
16
18
  def initialize(opts, argv, settings = nil)
17
19
  settings ||= {}
18
20
  @purge_levels = settings.fetch(:deploy, {}).fetch(:purge_levels, [])
@@ -20,6 +22,8 @@ module R10K
20
22
 
21
23
  super
22
24
 
25
+ # @force here is used to make it easier to reason about
26
+ @force = !@no_force
23
27
  @argv = @argv.map { |arg| arg.gsub(/\W/,'_') }
24
28
  end
25
29
 
@@ -117,7 +121,7 @@ module R10K
117
121
 
118
122
  def visit_module(mod)
119
123
  logger.info _("Deploying Puppetfile content %{mod_path}") % {mod_path: mod.path}
120
- mod.sync
124
+ mod.sync(force: @force)
121
125
  end
122
126
 
123
127
  def write_environment_info!(environment, started_at, success)
@@ -142,7 +146,7 @@ module R10K
142
146
  end
143
147
 
144
148
  def allowed_initialize_opts
145
- super.merge(puppetfile: :self, cachedir: :self)
149
+ super.merge(puppetfile: :self, cachedir: :self, :'no-force' => :self)
146
150
  end
147
151
  end
148
152
  end
@@ -10,6 +10,17 @@ module R10K
10
10
 
11
11
  include R10K::Action::Deploy::DeployHelpers
12
12
 
13
+ attr_reader :force
14
+
15
+ def initialize(opts, argv, settings = nil)
16
+ settings ||= {}
17
+
18
+ super
19
+
20
+ # @force here is used to make it easier to reason about
21
+ @force = !@no_force
22
+ end
23
+
13
24
  def call
14
25
  @visit_ok = true
15
26
 
@@ -50,14 +61,14 @@ module R10K
50
61
  def visit_module(mod)
51
62
  if @argv.include?(mod.name)
52
63
  logger.info _("Deploying module %{mod_path}") % {mod_path: mod.path}
53
- mod.sync
64
+ mod.sync(force: @force)
54
65
  else
55
66
  logger.debug1(_("Only updating modules %{modules}, skipping module %{mod_name}") % {modules: @argv.inspect, mod_name: mod.name})
56
67
  end
57
68
  end
58
69
 
59
70
  def allowed_initialize_opts
60
- super.merge(environment: true)
71
+ super.merge(environment: true, :'no-force' => :self)
61
72
  end
62
73
  end
63
74
  end
@@ -8,10 +8,16 @@ module R10K
8
8
  #
9
9
  # @api private
10
10
  # @deprecated The use of these environment variables is deprecated and
11
- # will be removed in 2.0.0.
11
+ # will be removed in 3.0.0.
12
12
  class CriRunner < R10K::Action::CriRunner
13
+
14
+ include R10K::Logging
15
+
13
16
  def handle_opts(opts)
14
17
  opts[:root] ||= wd
18
+ if env['PUPPETFILE_DIR'] || env['PUPPETFILE']
19
+ logger.warn _("The use of the PUPPETFILE and PUPPETFILE_DIR environment variables is deprecated.")
20
+ end
15
21
  opts[:moduledir] ||= env['PUPPETFILE_DIR']
16
22
  opts[:puppetfile] ||= env['PUPPETFILE']
17
23
  super(opts)
@@ -10,7 +10,7 @@ module R10K
10
10
 
11
11
  def call
12
12
  @visit_ok = true
13
- pf = R10K::Puppetfile.new(@root, @moduledir, @puppetfile)
13
+ pf = R10K::Puppetfile.new(@root, @moduledir, @puppetfile, nil , @force)
14
14
  pf.accept(self)
15
15
  @visit_ok
16
16
  end
@@ -26,17 +26,18 @@ module R10K
26
26
  end
27
27
 
28
28
  def visit_module(mod)
29
+ @force ||= false
29
30
  logger.info _("Updating module %{mod_path}") % {mod_path: mod.path}
30
31
 
31
32
  if mod.respond_to?(:desired_ref) && mod.desired_ref == :control_branch
32
33
  logger.warn _("Cannot track control repo branch for content '%{name}' when not part of a 'deploy' action, will use default if available." % {name: mod.name})
33
34
  end
34
35
 
35
- mod.sync(force: false) # Don't force sync for 'puppetfile install' RK-265
36
+ mod.sync(force: @force)
36
37
  end
37
38
 
38
39
  def allowed_initialize_opts
39
- super.merge(root: :self, puppetfile: :self, moduledir: :self)
40
+ super.merge(root: :self, puppetfile: :self, moduledir: :self, force: :self )
40
41
  end
41
42
  end
42
43
  end
@@ -22,6 +22,7 @@ module R10K::CLI
22
22
  DESCRIPTION
23
23
 
24
24
  required nil, :cachedir, 'Specify a cachedir, overriding the value in config'
25
+ flag nil, :'no-force', 'Prevent the overwriting of local module modifications'
25
26
 
26
27
  run do |opts, args, cmd|
27
28
  puts cmd.help(:verbose => opts[:verbose])
@@ -30,10 +30,9 @@ Puppetfile (http://bombasticmonkey.com/librarian-puppet/).
30
30
  name 'install'
31
31
  usage 'install'
32
32
  summary 'Install all modules from a Puppetfile'
33
-
34
33
  required nil, :moduledir, 'Path to install modules to'
35
34
  required nil, :puppetfile, 'Path to puppetfile'
36
- # @todo add --no-purge option
35
+ flag nil, :force, 'Force locally changed files to be overwritten'
37
36
  runner R10K::Action::Puppetfile::CriRunner.wrap(R10K::Action::Puppetfile::Install)
38
37
  end
39
38
  end
@@ -13,6 +13,7 @@ module R10K
13
13
 
14
14
  def_setting_attr :proxy
15
15
  def_setting_attr :baseurl
16
+ def_setting_attr :cache_root, File.expand_path(ENV['HOME'] ? '~/.r10k/cache': '/root/.r10k/cache')
16
17
 
17
18
  include R10K::Logging
18
19
 
@@ -27,6 +28,18 @@ module R10K
27
28
  # @return [Pathname] Where the module tarball will be downloaded to.
28
29
  attr_accessor :download_path
29
30
 
31
+ # @!attribute [rw] tarball_cache_path
32
+ # @return [Pathname] Where the module tarball will be cached to.
33
+ attr_accessor :tarball_cache_path
34
+
35
+ # @!attribute [rw] tarball_cache_root
36
+ # @return [Pathname] Directory where the module tarball will be cached to.
37
+ attr_accessor :tarball_cache_root
38
+
39
+ # @!attribute [rw] md5_file_path
40
+ # @return [Pathname] Where the md5 of the cached tarball is stored.
41
+ attr_accessor :md5_file_path
42
+
30
43
  # @!attribute [rw] unpack_path
31
44
  # @return [Pathname] Where the module will be unpacked to.
32
45
  attr_accessor :unpack_path
@@ -41,9 +54,17 @@ module R10K
41
54
  # objects are created in the class instances and thus are not shared with
42
55
  # subclasses.
43
56
  PuppetForge::V3::Release.conn = PuppetForge::V3::Base.conn
57
+
44
58
  @forge_release = PuppetForge::V3::Release.new({ :name => @full_name, :version => @version, :slug => "#{@full_name}-#{@version}" })
45
59
 
46
- @download_path = Pathname.new(Dir.mktmpdir) + (@forge_release.slug + '.tar.gz')
60
+ tarball_name = @forge_release.slug + '.tar.gz'
61
+ @download_path = Pathname.new(Dir.mktmpdir) + (tarball_name)
62
+ @tarball_cache_root = Pathname.new(settings[:cache_root]) + (@forge_release.slug + "/tarball/")
63
+ @tarball_cache_path = @tarball_cache_root + tarball_name
64
+
65
+ md5_filename = @forge_release.slug + '.md5'
66
+ @md5_file_path = @tarball_cache_root + md5_filename
67
+
47
68
  @unpack_path = Pathname.new(Dir.mktmpdir) + @forge_release.slug
48
69
  end
49
70
 
@@ -65,34 +86,83 @@ module R10K
65
86
  cleanup
66
87
  end
67
88
 
68
- # Download the module release to {#download_path}
89
+ # Download the module release to {#download_path} and cache to {#tarball_cache_path}
69
90
  #
70
91
  # @return [void]
71
92
  def download
72
- logger.debug1 "Downloading #{@forge_release.slug} from #{PuppetForge::Release.conn.url_prefix} to #{@download_path}"
73
- @forge_release.download(download_path)
93
+ if @tarball_cache_path.exist?
94
+ logger.debug1 "Using cached copy of #{@forge_release.slug} tarball"
95
+ else
96
+ logger.debug1 "Downloading #{@forge_release.slug} from #{PuppetForge::Release.conn.url_prefix} to #{@download_path}"
97
+ @forge_release.download(download_path)
98
+ FileUtils::mkdir_p(@tarball_cache_root)
99
+ FileUtils::mv(@download_path, @tarball_cache_path)
100
+ end
74
101
  end
75
102
 
76
- # Verify the module release downloaded to {#download_path} against the
77
- # module release checksum given by the Puppet Forge
103
+ # Verify the module release cached in {#tarball_cache_path} against the
104
+ # module release checksum given by the Puppet Forge. On mismatch, remove
105
+ # the cached copy.
78
106
  #
79
- # @raise [PuppetForge::V3::Release::ChecksumMismatch] The
80
- # downloaded module release checksum doesn't match the expected Forge
81
- # module release checksum.
82
107
  # @return [void]
83
108
  def verify
84
- logger.debug1 "Verifying that #{download_path} matches checksum #{@forge_release.file_md5}"
85
- @forge_release.verify(download_path)
109
+ logger.debug1 "Verifying that #{@tarball_cache_path} matches checksum"
110
+
111
+ md5_of_tarball = Digest::MD5.hexdigest(File.read(@tarball_cache_path))
112
+
113
+ if @md5_file_path.exist?
114
+ verify_from_md5_file(md5_of_tarball)
115
+ else
116
+ verify_from_forge(md5_of_tarball)
117
+ end
86
118
  end
87
119
 
88
- # Unpack the module release at {#download_path} into the given target_dir
120
+ # Verify the md5 of the cached tarball against the
121
+ # module release checksum stored in the cache as well.
122
+ # On mismatch, remove the cached copy of both files.
123
+ #
124
+ # @raise [PuppetForge::V3::Release::ChecksumMismatch] The
125
+ # cached module release checksum doesn't match the cached checksum.
126
+ #
127
+ # @return [void]
128
+ def verify_from_md5_file(md5_of_tarball)
129
+ md5_from_file = File.read(@md5_file_path).strip
130
+ if md5_of_tarball != md5_from_file
131
+ logger.error "MD5 of #{@tarball_cache_path} (#{md5_of_tarball}) does not match checksum #{md5_from_file} in #{@md5_file_path}. Removing both files."
132
+ cleanup_cached_tarball_path
133
+ cleanup_md5_file_path
134
+ raise PuppetForge::V3::Release::ChecksumMismatch.new
135
+ end
136
+ end
137
+
138
+ # Verify the md5 of the cached tarball against the
139
+ # module release checksum from the forge.
140
+ # On mismatch, remove the cached copy of the tarball.
141
+ #
142
+ # @raise [PuppetForge::V3::Release::ChecksumMismatch] The
143
+ # cached module release checksum doesn't match the forge checksum.
144
+ #
145
+ # @return [void]
146
+ def verify_from_forge(md5_of_tarball)
147
+ md5_from_forge = @forge_release.file_md5
148
+ #compare file_md5 to md5_of_tarball
149
+ if md5_of_tarball != md5_from_forge
150
+ logger.debug1 "MD5 of #{@tarball_cache_path} (#{md5_of_tarball}) does not match checksum #{md5_from_forge} found on the forge. Removing tarball."
151
+ cleanup_cached_tarball_path
152
+ raise PuppetForge::V3::Release::ChecksumMismatch.new
153
+ else
154
+ File.write(@md5_file_path, md5_from_forge)
155
+ end
156
+ end
157
+
158
+ # Unpack the module release at {#tarball_cache_path} into the given target_dir
89
159
  #
90
160
  # @param target_dir [Pathname] The final path where the module release
91
161
  # should be unpacked/installed into.
92
162
  # @return [void]
93
163
  def unpack(target_dir)
94
- logger.debug1 _("Unpacking %{download_path} to %{target_dir} (with tmpdir %{tmp_path})") % {download_path: download_path, target_dir: target_dir, tmp_path: unpack_path}
95
- file_lists = PuppetForge::Unpacker.unpack(download_path.to_s, target_dir.to_s, unpack_path.to_s)
164
+ logger.debug1 _("Unpacking %{tarball_cache_path} to %{target_dir} (with tmpdir %{tmp_path})") % {tarball_cache_path: tarball_cache_path, target_dir: target_dir, tmp_path: unpack_path}
165
+ file_lists = PuppetForge::Unpacker.unpack(tarball_cache_path.to_s, target_dir.to_s, unpack_path.to_s)
96
166
  logger.debug2 _("Valid files unpacked: %{valid_files}") % {valid_files: file_lists[:valid]}
97
167
  if !file_lists[:invalid].empty?
98
168
  logger.debug1 _("These files existed in the module's tar file, but are invalid filetypes and were not unpacked: %{invalid_files}") % {invalid_files: file_lists[:invalid]}
@@ -121,6 +191,20 @@ module R10K
121
191
  download_path.delete
122
192
  end
123
193
  end
194
+
195
+ # Remove the cached module release.
196
+ def cleanup_cached_tarball_path
197
+ if tarball_cache_path.exist?
198
+ tarball_cache_path.delete
199
+ end
200
+ end
201
+
202
+ # Remove the module release md5.
203
+ def cleanup_md5_file_path
204
+ if md5_file_path.exist?
205
+ md5_file_path.delete
206
+ end
207
+ end
124
208
  end
125
209
  end
126
210
  end
@@ -31,6 +31,7 @@ module R10K
31
31
  end
32
32
 
33
33
  with_setting(:cachedir) { |value| R10K::Git::Cache.settings[:cache_root] = value }
34
+ with_setting(:cachedir) { |value| R10K::Forge::ModuleRelease.settings[:cache_root] = value }
34
35
 
35
36
  with_setting(:git) { |value| GitInitializer.new(value).call }
36
37
  with_setting(:forge) { |value| ForgeInitializer.new(value).call }
@@ -6,7 +6,7 @@ require 'r10k/forge/module_release'
6
6
 
7
7
  require 'pathname'
8
8
  require 'fileutils'
9
- require 'puppet_forge'
9
+ require 'puppet_forge/util'
10
10
 
11
11
  class R10K::Module::Forge < R10K::Module::Base
12
12
 
@@ -17,7 +17,7 @@ class R10K::Module::Forge < R10K::Module::Base
17
17
  end
18
18
 
19
19
  def self.valid_version?(expected_version)
20
- expected_version == :latest || expected_version.nil? || SemanticPuppet::Version.valid?(expected_version)
20
+ expected_version == :latest || expected_version.nil? || PuppetForge::Util.version_valid?(expected_version)
21
21
  end
22
22
 
23
23
  # @!attribute [r] metadata
@@ -33,11 +33,18 @@ class Puppetfile
33
33
  # @return [R10K::Environment] Optional R10K::Environment that this Puppetfile belongs to.
34
34
  attr_accessor :environment
35
35
 
36
+ # @!attribute [rw] force
37
+ # @return [Boolean] Overwrite any locally made changes
38
+ attr_accessor :force
39
+
36
40
  # @param [String] basedir
37
41
  # @param [String] moduledir The directory to install the modules, default to #{basedir}/modules
38
42
  # @param [String] puppetfile_path The path to the Puppetfile, default to #{basedir}/Puppetfile
39
- def initialize(basedir, moduledir = nil, puppetfile_path = nil)
43
+ # @param [String] puppetfile_name The name of the Puppetfile, default to 'Puppetfile'
44
+ # @param [Boolean] force Shall we overwrite locally made changes?
45
+ def initialize(basedir, moduledir = nil, puppetfile_path = nil, puppetfile_name = nil, force = nil )
40
46
  @basedir = basedir
47
+ @force = force || false
41
48
  @moduledir = moduledir || File.join(basedir, 'modules')
42
49
  @puppetfile_path = puppetfile_path || File.join(basedir, 'Puppetfile')
43
50
 
@@ -51,6 +51,10 @@ module R10K
51
51
  :desc => "An optional proxy server to use when interacting with Git sources via HTTP(S).",
52
52
  :default => :inherit,
53
53
  }),
54
+
55
+ Definition.new(:ignore_branch_prefixes, {
56
+ :desc => "Array of strings used to prefix branch names that will not be deployed as environments.",
57
+ }),
54
58
  ])
55
59
  },
56
60
  {
@@ -36,6 +36,11 @@ class R10K::Source::Git < R10K::Source::Base
36
36
  # Puppet environments will be handled.
37
37
  attr_reader :invalid_branches
38
38
 
39
+ # @!attribute [r] ignore_branch_prefixes
40
+ # @return [Array<String>] Array of strings used to remove repository branches
41
+ # that will be deployed as environments.
42
+ attr_reader :ignore_branch_prefixes
43
+
39
44
  # Initialize the given source.
40
45
  #
41
46
  # @param name [String] The identifier for this source.
@@ -53,8 +58,9 @@ class R10K::Source::Git < R10K::Source::Base
53
58
 
54
59
  @environments = []
55
60
 
56
- @remote = options[:remote]
61
+ @remote = options[:remote]
57
62
  @invalid_branches = (options[:invalid_branches] || 'correct_and_warn')
63
+ @ignore_branch_prefixes = options[:ignore_branch_prefixes]
58
64
 
59
65
  @cache = R10K::Git.cache.generate(@remote)
60
66
  end
@@ -109,11 +115,27 @@ class R10K::Source::Git < R10K::Source::Base
109
115
  environments.map {|env| env.dirname }
110
116
  end
111
117
 
118
+ def filter_branches(branches, ignore_prefixes)
119
+ filter = Regexp.new("^#{Regexp.union(ignore_prefixes)}")
120
+ branches = branches.reject do |branch|
121
+ result = filter.match(branch)
122
+ if result
123
+ logger.warn _("Branch %{branch} filtered out by ignore_branch_prefixes %{ibp}") % {branch: branch, ibp: @ignore_branch_prefixes}
124
+ end
125
+ result
126
+ end
127
+ branches
128
+ end
129
+
112
130
  private
113
131
 
114
132
  def branch_names
115
133
  opts = {:prefix => @prefix, :invalid => @invalid_branches, :source => @name}
116
- @cache.branches.map do |branch|
134
+ branches = @cache.branches
135
+ if @ignore_branch_prefixes && !@ignore_branch_prefixes.empty?
136
+ branches = filter_branches(branches, @ignore_branch_prefixes)
137
+ end
138
+ branches.map do |branch|
117
139
  R10K::Environment::Name.new(branch, opts)
118
140
  end
119
141
  end
@@ -37,6 +37,11 @@ class R10K::Source::SVN < R10K::Source::Base
37
37
  # @api private
38
38
  attr_reader :password
39
39
 
40
+ # @!attribute [r] ignore_branch_prefixes
41
+ # @return [Array<String>] Array of strings used to remove repository branches
42
+ # that will be deployed as environments.
43
+ attr_reader :ignore_branch_prefixes
44
+
40
45
  include R10K::Util::Setopts
41
46
 
42
47
  # Initialize the given source.
@@ -56,6 +61,7 @@ class R10K::Source::SVN < R10K::Source::Base
56
61
  setopts(options, {:remote => :self, :username => :self, :password => :self})
57
62
  @environments = []
58
63
  @svn_remote = R10K::SVN::Remote.new(@remote, :username => @username, :password => @password)
64
+ @ignore_branch_prefixes = options[:ignore_branch_prefixes]
59
65
  end
60
66
 
61
67
  # Enumerate the environments associated with this SVN source.
@@ -97,18 +103,32 @@ class R10K::Source::SVN < R10K::Source::Base
97
103
 
98
104
  include R10K::Logging
99
105
 
106
+ def filter_branches(branches, ignore_prefixes)
107
+ filter = Regexp.new("^(#{ignore_prefixes.join('|')})")
108
+ branches = branches.reject do |branch|
109
+ result = filter.match(branch)
110
+ if result
111
+ logger.warn _("Branch %{branch} filtered out by ignore_branch_prefixes %{ibp}") % {branch: branch, ibp: @ignore_branch_prefixes}
112
+ end
113
+ result
114
+ end
115
+ branches
116
+ end
117
+
100
118
  private
101
119
 
102
120
  def names_and_paths
103
121
  branches = []
104
-
105
122
  opts = {:prefix => @prefix, :correct => false, :validate => false, :source => @name}
106
-
107
123
  branches << [R10K::Environment::Name.new('production', opts), "#{@remote}/trunk"]
108
- @svn_remote.branches.each do |branch|
109
- branches << [R10K::Environment::Name.new(branch, opts), "#{@remote}/branches/#{branch}"]
124
+ additional_branch_names = @svn_remote.branches
125
+ if @ignore_branch_prefixes && !@ignore_branch_prefixes.empty?
126
+ additional_branch_names = filter_branches(additional_branch_names, @ignore_branch_prefixes)
110
127
  end
111
128
 
129
+ additional_branch_names.each do |branch|
130
+ branches << [R10K::Environment::Name.new(branch, opts), "#{@remote}/branches/#{branch}"]
131
+ end
112
132
  branches
113
133
  end
114
134
  end
@@ -39,9 +39,11 @@ module R10K
39
39
  when NilClass, FalseClass
40
40
  # Ignore nil options
41
41
  when :self, TrueClass
42
- instance_variable_set("@#{key}".to_sym, value)
42
+ # tr here is because instance variables cannot have hyphens in their names.
43
+ instance_variable_set("@#{key}".tr('-','_').to_sym, value)
43
44
  else
44
- instance_variable_set("@#{rhs}".to_sym, value)
45
+ # tr here same as previous
46
+ instance_variable_set("@#{rhs}".tr('-','_').to_sym, value)
45
47
  end
46
48
  else
47
49
  raise ArgumentError, _("%{class_name} cannot handle option '%{key}'") % {class_name: self.class.name, key: key}
@@ -1,3 +1,3 @@
1
1
  module R10K
2
- VERSION = '2.5.5'
2
+ VERSION = '2.6.0'
3
3
  end
@@ -28,8 +28,7 @@ Gem::Specification.new do |s|
28
28
  s.add_dependency 'log4r', '1.1.10'
29
29
  s.add_dependency 'multi_json', '~> 1.10'
30
30
 
31
- s.add_dependency 'puppet_forge', '~> 2.2'
32
- s.add_dependency 'semantic_puppet', '~> 0.1.0'
31
+ s.add_dependency 'puppet_forge', '~> 2.2.8'
33
32
 
34
33
  s.add_dependency 'gettext-setup', '~> 0.5'
35
34
 
@@ -13,5 +13,27 @@ shared_examples_for "a puppetfile action" do
13
13
  it "accepts the :moduledir option" do
14
14
  described_class.new({moduledir: "/some/nonexistent/path/modules"}, [])
15
15
  end
16
+
17
+ end
18
+ end
19
+
20
+ shared_examples_for "a puppetfile install action" do
21
+ describe "initializing" do
22
+ it "accepts the :root option" do
23
+ described_class.new({root: "/some/nonexistent/path"}, [])
24
+ end
25
+
26
+ it "accepts the :puppetfile option" do
27
+ described_class.new({puppetfile: "/some/nonexistent/path/Puppetfile"}, [])
28
+ end
29
+
30
+ it "accepts the :moduledir option" do
31
+ described_class.new({moduledir: "/some/nonexistent/path/modules"}, [])
32
+ end
33
+
34
+ it "accepts the :force option" do
35
+ described_class.new({force: true}, [])
36
+ end
37
+
16
38
  end
17
39
  end
@@ -19,6 +19,10 @@ describe R10K::Action::Deploy::Environment do
19
19
  described_class.new({puppetfile: true}, [])
20
20
  end
21
21
 
22
+ it "can accept a no-force option" do
23
+ described_class.new({:'no-force' => true}, [])
24
+ end
25
+
22
26
  it "normalizes environment names in the arg vector"
23
27
  end
24
28
 
@@ -53,6 +57,14 @@ describe R10K::Action::Deploy::Environment do
53
57
  end
54
58
  end
55
59
 
60
+ describe "with no-force" do
61
+ subject { described_class.new({ config: "/some/nonexistent/path", puppetfile: true, :'no-force' => true}, %w[first]) }
62
+
63
+ it "tries to preserve local modifications" do
64
+ expect(subject.force).to equal(false)
65
+ end
66
+ end
67
+
56
68
  describe "purge_levels" do
57
69
  let(:settings) { { deploy: { purge_levels: purge_levels } } }
58
70
 
@@ -13,5 +13,18 @@ describe R10K::Action::Deploy::Module do
13
13
  it "accepts an environment option" do
14
14
  described_class.new({environment: "production"}, [])
15
15
  end
16
+
17
+ it "can accept a no-force option" do
18
+ described_class.new({:'no-force' => true}, [])
19
+ end
20
+ end
21
+
22
+ describe "with no-force" do
23
+
24
+ subject { described_class.new({ config: "/some/nonexistent/path", :'no-force' => true}, [] )}
25
+
26
+ it "tries to preserve local modifications" do
27
+ expect(subject.force).to equal(false)
28
+ end
16
29
  end
17
30
  end
@@ -7,11 +7,12 @@ describe R10K::Action::Puppetfile::Install do
7
7
 
8
8
  let(:puppetfile) { R10K::Puppetfile.new('/some/nonexistent/path', nil, nil) }
9
9
 
10
- before do
11
- allow(R10K::Puppetfile).to receive(:new).with("/some/nonexistent/path", nil, nil).and_return(puppetfile)
10
+ before(:each) do
11
+ allow(puppetfile).to receive(:load!).and_return(nil)
12
+ allow(R10K::Puppetfile).to receive(:new).with("/some/nonexistent/path", nil, nil, nil, nil).and_return(puppetfile)
12
13
  end
13
14
 
14
- it_behaves_like "a puppetfile action"
15
+ it_behaves_like "a puppetfile install action"
15
16
 
16
17
  describe "installing modules" do
17
18
  let(:modules) do
@@ -55,14 +56,27 @@ describe R10K::Action::Puppetfile::Install do
55
56
 
56
57
  it "can use a custom puppetfile path" do
57
58
  subject = described_class.new({root: "/some/nonexistent/path", puppetfile: "/some/other/path/Puppetfile"}, [])
58
- expect(R10K::Puppetfile).to receive(:new).with("/some/nonexistent/path", nil, "/some/other/path/Puppetfile").and_return(puppetfile)
59
+ expect(R10K::Puppetfile).to receive(:new).with("/some/nonexistent/path", nil, "/some/other/path/Puppetfile", nil, nil).and_return(puppetfile)
59
60
  subject.call
60
61
  end
61
62
 
62
63
  it "can use a custom moduledir path" do
63
64
  subject = described_class.new({root: "/some/nonexistent/path", moduledir: "/some/other/path/site-modules"}, [])
64
- expect(R10K::Puppetfile).to receive(:new).with("/some/nonexistent/path", "/some/other/path/site-modules", nil).and_return(puppetfile)
65
+ expect(R10K::Puppetfile).to receive(:new).with("/some/nonexistent/path", "/some/other/path/site-modules", nil, nil, nil).and_return(puppetfile)
65
66
  subject.call
66
67
  end
67
68
  end
69
+
70
+ describe "forcing to overwrite local changes" do
71
+ before do
72
+ allow(puppetfile).to receive(:modules).and_return([])
73
+ end
74
+
75
+ it "can use the force overwrite option" do
76
+ subject = described_class.new({root: "/some/nonexistent/path", force: true}, [])
77
+ expect(R10K::Puppetfile).to receive(:new).with("/some/nonexistent/path", nil, nil, nil, true).and_return(puppetfile)
78
+ subject.call
79
+ end
80
+
81
+ end
68
82
  end
@@ -7,35 +7,105 @@ describe R10K::Forge::ModuleRelease do
7
7
  subject { described_class.new('branan-eight_hundred', '8.0.0') }
8
8
 
9
9
  let(:forge_release_class) { PuppetForge::V3::Release }
10
+ let(:md5_digest_class) { Digest::MD5 }
10
11
 
11
12
  let(:download_path) { instance_double('Pathname') }
13
+ let(:tarball_cache_path) { instance_double('Pathname') }
14
+ let(:tarball_cache_root) { instance_double('Pathname') }
12
15
  let(:unpack_path) { instance_double('Pathname') }
13
16
  let(:target_dir) { instance_double('Pathname') }
17
+ let(:md5_file_path) { instance_double('Pathname') }
18
+
14
19
  let(:file_lists) { {:valid=>['valid_ex'], :invalid=>[], :symlinks=>['symlink_ex']} }
15
20
 
21
+ let(:file_contents) { "skeletor's closet" }
22
+ let(:md5_of_tarball) { "something_hexy" }
23
+ let(:good_md5) { md5_of_tarball }
24
+ let(:bad_md5) { "different_hexy_thing" }
25
+
16
26
  before do
17
27
  subject.download_path = download_path
28
+ subject.tarball_cache_path = tarball_cache_path
29
+ subject.tarball_cache_root = tarball_cache_root
18
30
  subject.unpack_path = unpack_path
31
+ subject.md5_file_path = md5_file_path
32
+ end
33
+
34
+ context "no cached tarball" do
35
+ describe '#download' do
36
+ it "downloads the module from the forge into `download_path`" do
37
+ expect(tarball_cache_path).to receive(:exist?).and_return(false)
38
+ expect(subject.forge_release).to receive(:download).with(download_path)
39
+ allow(FileUtils).to receive(:mkdir_p).with(tarball_cache_root)
40
+ expect(FileUtils).to receive(:mv).with(download_path, tarball_cache_path)
41
+ subject.download
42
+ end
43
+ end
19
44
  end
20
45
 
21
- describe '#download' do
22
- it "downloads the module from the forge into `download_path`" do
23
- expect(subject.forge_release).to receive(:download).with(download_path)
24
- subject.download
46
+ context "with cached tarball" do
47
+ describe '#download' do
48
+ it "does not download a new tarball" do
49
+ expect(tarball_cache_path).to receive(:exist?).and_return(true)
50
+ expect(subject.forge_release).not_to receive(:download).with(download_path)
51
+ subject.download
52
+ end
25
53
  end
26
54
  end
27
55
 
28
56
  describe '#verify' do
29
- it "verifies the module checksum based on the Forge file checksum" do
30
- allow(subject.forge_release).to receive(:file_md5).and_return('something')
31
- expect(subject.forge_release).to receive(:verify).with(download_path)
57
+
58
+ it "verifies using the file md5, if that exists" do
59
+ allow(File).to receive(:read).and_return(file_contents)
60
+ allow(md5_digest_class).to receive(:hexdigest).and_return(md5_of_tarball)
61
+ allow(md5_file_path).to receive(:exist?).and_return(true)
62
+ expect(subject).to receive(:verify_from_md5_file).with(md5_of_tarball)
32
63
  subject.verify
33
64
  end
65
+
66
+ it "verifies using the forge file_md5, if no md5 file exists" do
67
+ allow(File).to receive(:read).and_return(file_contents)
68
+ allow(md5_digest_class).to receive(:hexdigest).and_return(md5_of_tarball)
69
+ allow(md5_file_path).to receive(:exist?).and_return(false)
70
+ expect(subject).to receive(:verify_from_forge).with(md5_of_tarball)
71
+ subject.verify
72
+ end
73
+ end
74
+
75
+ describe '#verify_from_md5_file' do
76
+
77
+ it "does nothing when the checksums match" do
78
+ expect(File).to receive(:read).with(md5_file_path).and_return(good_md5)
79
+ expect(subject).not_to receive(:cleanup_cached_tarball_path)
80
+ subject.verify_from_md5_file(md5_of_tarball)
81
+ end
82
+
83
+ it "raises an error and cleans up when the checksums do not match" do
84
+ expect(File).to receive(:read).with(md5_file_path).and_return(bad_md5)
85
+ expect(subject).to receive(:cleanup_cached_tarball_path)
86
+ expect(subject).to receive(:cleanup_md5_file_path)
87
+ expect { subject.verify_from_md5_file(md5_of_tarball) }.to raise_error(PuppetForge::V3::Release::ChecksumMismatch)
88
+ end
89
+ end
90
+
91
+ describe '#verify_from_forge' do
92
+ it "write the md5 to file when the checksums match" do
93
+ expect(subject.forge_release).to receive(:file_md5).and_return(good_md5)
94
+ expect(subject).not_to receive(:cleanup_cached_tarball_path)
95
+ expect(File).to receive(:write).with(md5_file_path, good_md5)
96
+ subject.verify_from_forge(md5_of_tarball)
97
+ end
98
+
99
+ it "raises an error and cleans up when the checksums do not match" do
100
+ expect(subject.forge_release).to receive(:file_md5).and_return(bad_md5)
101
+ expect(subject).to receive(:cleanup_cached_tarball_path)
102
+ expect { subject.verify_from_forge(md5_of_tarball) }.to raise_error(PuppetForge::V3::Release::ChecksumMismatch)
103
+ end
34
104
  end
35
105
 
36
106
  describe '#unpack' do
37
- it "unpacks the module tarball in `download_path` into the provided target path" do
38
- expect(PuppetForge::Unpacker).to receive(:unpack).with(download_path.to_s, target_dir.to_s, unpack_path.to_s).\
107
+ it "unpacks the module tarball in `tarball_cache_path` into the provided target path" do
108
+ expect(PuppetForge::Unpacker).to receive(:unpack).with(tarball_cache_path.to_s, target_dir.to_s, unpack_path.to_s).\
39
109
  and_return({:valid=>["extractedmodule/metadata.json"], :invalid=>[], :symlinks=>[]})
40
110
  subject.unpack(target_dir)
41
111
  end
@@ -52,7 +122,7 @@ describe R10K::Forge::ModuleRelease do
52
122
  end
53
123
 
54
124
  describe "#cleanup" do
55
- it "cleans up the download and unpack paths" do
125
+ it "cleans up the unpack paths" do
56
126
  expect(subject).to receive(:cleanup_unpack_path)
57
127
  expect(subject).to receive(:cleanup_download_path)
58
128
  subject.cleanup
@@ -62,6 +62,40 @@ describe R10K::Source::Git do
62
62
  expect(master_env.dirname).to eq 'master'
63
63
  end
64
64
  end
65
+
66
+ describe "generate_environments respects ignore_branch_prefixes setting" do
67
+ before do
68
+ allow(subject.cache).to receive(:branches).and_return ['master', 'development', 'production', 'not_dev_test_me', 'dev_test', 'dev', 'test_2']
69
+ subject.instance_variable_set(:@ignore_branch_prefixes, ['dev', 'test'])
70
+ end
71
+
72
+ let(:environments) { subject.generate_environments }
73
+
74
+ it "creates an environment for each branch not in ignore_branch_prefixes" do
75
+ expect(subject.generate_environments.size).to eq(3)
76
+ end
77
+
78
+ it "copies the source remote to the environment" do
79
+ expect(environments[0].remote).to eq subject.remote
80
+ expect(environments[1].remote).to eq subject.remote
81
+ expect(environments[2].remote).to eq subject.remote
82
+ end
83
+
84
+ it "uses the branch name as the directory by default" do
85
+ expect(environments[0].dirname).to eq 'master'
86
+ expect(environments[1].dirname).to eq 'production'
87
+ expect(environments[2].dirname).to eq 'not_dev_test_me'
88
+ end
89
+ end
90
+
91
+ describe "filtering branches with ignore prefixes" do
92
+ let(:branches) { ['master', 'development', 'production', 'not_dev_test_me', 'dev_test', 'dev', 'test_2'] }
93
+ let(:ignore_prefixes) { ['dev', 'test'] }
94
+
95
+ it "filters branches" do
96
+ expect(subject.filter_branches(branches, ignore_prefixes)).to eq(['master', 'production', 'not_dev_test_me'])
97
+ end
98
+ end
65
99
  end
66
100
 
67
101
  describe R10K::Source::Git, "handling invalid branch names" do
@@ -61,6 +61,34 @@ describe R10K::Source::SVN do
61
61
  expect(environments[3].dirname).to eq 'robobutler'
62
62
  end
63
63
  end
64
+
65
+ describe "generate_environments respects ignore_branch_prefixes setting" do
66
+ before do
67
+ allow(subject.svn_remote).to receive(:branches).and_return ['master', 'development', 'not_dev_test_me', 'dev_test', 'dev', 'test_2']
68
+ subject.instance_variable_set(:@ignore_branch_prefixes, ['dev', 'test'])
69
+ end
70
+
71
+ let(:environments) { subject.generate_environments }
72
+
73
+ it "creates an environment for each branch not in ignore_branch_prefixes" do
74
+ expect(subject.generate_environments.size).to eq(3)
75
+ end
76
+
77
+ it "uses the branch name as the directory by default" do
78
+ expect(environments[0].name).to eq 'production'
79
+ expect(environments[1].name).to eq 'master'
80
+ expect(environments[2].name).to eq 'not_dev_test_me'
81
+ end
82
+ end
83
+
84
+ describe "filtering branches with ignore prefixes" do
85
+ let(:branches) { ['master', 'development', 'production', 'not_dev_test_me', 'dev_test', 'dev', 'test_2'] }
86
+ let(:ignore_prefixes) { ['dev', 'test'] }
87
+
88
+ it "filters branches" do
89
+ expect(subject.filter_branches(branches, ignore_prefixes)).to eq(['master', 'production', 'not_dev_test_me'])
90
+ end
91
+ end
64
92
  end
65
93
 
66
94
  describe R10K::Source::SVN, 'when prefixing is enabled' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: r10k
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.5
4
+ version: 2.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adrien Thebo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-02 00:00:00.000000000 Z
11
+ date: 2017-12-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colored
@@ -28,14 +28,14 @@ dependencies:
28
28
  name: cri
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ~>
32
32
  - !ruby/object:Gem::Version
33
33
  version: 2.6.1
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: 2.6.1
41
41
  - !ruby/object:Gem::Dependency
@@ -56,126 +56,111 @@ dependencies:
56
56
  name: multi_json
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ~>
60
60
  - !ruby/object:Gem::Version
61
61
  version: '1.10'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ~>
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.10'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: puppet_forge
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ~>
74
74
  - !ruby/object:Gem::Version
75
- version: '2.2'
75
+ version: 2.2.8
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ~>
81
81
  - !ruby/object:Gem::Version
82
- version: '2.2'
83
- - !ruby/object:Gem::Dependency
84
- name: semantic_puppet
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: 0.1.0
90
- type: :runtime
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: 0.1.0
82
+ version: 2.2.8
97
83
  - !ruby/object:Gem::Dependency
98
84
  name: gettext-setup
99
85
  requirement: !ruby/object:Gem::Requirement
100
86
  requirements:
101
- - - "~>"
87
+ - - ~>
102
88
  - !ruby/object:Gem::Version
103
89
  version: '0.5'
104
90
  type: :runtime
105
91
  prerelease: false
106
92
  version_requirements: !ruby/object:Gem::Requirement
107
93
  requirements:
108
- - - "~>"
94
+ - - ~>
109
95
  - !ruby/object:Gem::Version
110
96
  version: '0.5'
111
97
  - !ruby/object:Gem::Dependency
112
98
  name: rspec
113
99
  requirement: !ruby/object:Gem::Requirement
114
100
  requirements:
115
- - - "~>"
101
+ - - ~>
116
102
  - !ruby/object:Gem::Version
117
103
  version: '3.1'
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
107
  requirements:
122
- - - "~>"
108
+ - - ~>
123
109
  - !ruby/object:Gem::Version
124
110
  version: '3.1'
125
111
  - !ruby/object:Gem::Dependency
126
112
  name: rake
127
113
  requirement: !ruby/object:Gem::Requirement
128
114
  requirements:
129
- - - ">="
115
+ - - ! '>='
130
116
  - !ruby/object:Gem::Version
131
117
  version: '0'
132
118
  type: :development
133
119
  prerelease: false
134
120
  version_requirements: !ruby/object:Gem::Requirement
135
121
  requirements:
136
- - - ">="
122
+ - - ! '>='
137
123
  - !ruby/object:Gem::Version
138
124
  version: '0'
139
125
  - !ruby/object:Gem::Dependency
140
126
  name: yard
141
127
  requirement: !ruby/object:Gem::Requirement
142
128
  requirements:
143
- - - "~>"
129
+ - - ~>
144
130
  - !ruby/object:Gem::Version
145
131
  version: 0.8.7.3
146
132
  type: :development
147
133
  prerelease: false
148
134
  version_requirements: !ruby/object:Gem::Requirement
149
135
  requirements:
150
- - - "~>"
136
+ - - ~>
151
137
  - !ruby/object:Gem::Version
152
138
  version: 0.8.7.3
153
139
  - !ruby/object:Gem::Dependency
154
140
  name: minitar
155
141
  requirement: !ruby/object:Gem::Requirement
156
142
  requirements:
157
- - - "~>"
143
+ - - ~>
158
144
  - !ruby/object:Gem::Version
159
145
  version: 0.6.1
160
146
  type: :development
161
147
  prerelease: false
162
148
  version_requirements: !ruby/object:Gem::Requirement
163
149
  requirements:
164
- - - "~>"
150
+ - - ~>
165
151
  - !ruby/object:Gem::Version
166
152
  version: 0.6.1
167
- description: |2
168
- R10K provides a general purpose toolset for deploying Puppet environments and modules.
169
- It implements the Puppetfile format and provides a native implementation of Puppet
170
- dynamic environments.
153
+ description: ! " R10K provides a general purpose toolset for deploying Puppet environments
154
+ and modules.\n It implements the Puppetfile format and provides a native implementation
155
+ of Puppet\n dynamic environments.\n"
171
156
  email: adrien@somethingsinistral.net
172
157
  executables:
173
158
  - r10k
174
159
  extensions: []
175
160
  extra_rdoc_files: []
176
161
  files:
177
- - ".gitignore"
178
- - ".travis.yml"
162
+ - .gitignore
163
+ - .travis.yml
179
164
  - CHANGELOG.mkd
180
165
  - CONTRIBUTING.mkd
181
166
  - Gemfile
@@ -515,18 +500,19 @@ require_paths:
515
500
  - lib
516
501
  required_ruby_version: !ruby/object:Gem::Requirement
517
502
  requirements:
518
- - - ">="
503
+ - - ! '>='
519
504
  - !ruby/object:Gem::Version
520
505
  version: 1.9.3
521
506
  required_rubygems_version: !ruby/object:Gem::Requirement
522
507
  requirements:
523
- - - ">="
508
+ - - ! '>='
524
509
  - !ruby/object:Gem::Version
525
510
  version: '0'
526
511
  requirements: []
527
512
  rubyforge_project:
528
- rubygems_version: 2.2.5
513
+ rubygems_version: 2.4.8
529
514
  signing_key:
530
515
  specification_version: 4
531
516
  summary: Puppet environment and module deployment
532
517
  test_files: []
518
+ has_rdoc: