r10k 1.0.0 → 1.1.0rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -49,7 +49,33 @@ Puppetfile (http://bombasticmonkey.com/librarian-puppet/).
49
49
  end
50
50
  end
51
51
  self.command.add_command(Install.command)
52
-
52
+ module Check
53
+ def self.command
54
+ @cmd ||= Cri::Command.define do
55
+ name 'check'
56
+ usage 'check'
57
+ summary 'Try and load the Puppetfile to verify the syntax is correct.'
58
+ run do |opts,args,cmd|
59
+ puppetfile_root = Dir.getwd
60
+ puppetfile_path = ENV['PUPPETFILE_DIR']
61
+ puppetfile = ENV['PUPPETFILE']
62
+
63
+ puppetfile = R10K::Puppetfile.new(puppetfile_root, puppetfile_path, puppetfile)
64
+ begin
65
+ puppetfile.load
66
+ rescue LoadError => ex
67
+ $stderr.puts "ERROR: Puppetfile bad syntax"
68
+ ex.backtrace.each do |line|
69
+ puts line
70
+ end
71
+ exit 1
72
+ end
73
+ exit 0
74
+ end
75
+ end
76
+ end
77
+ end
78
+ self.command.add_command(Check.command)
53
79
  module Purge
54
80
  def self.command
55
81
  @cmd ||= Cri::Command.define do
@@ -59,8 +59,10 @@ class Deployment
59
59
  private
60
60
 
61
61
  def load_sources
62
- @_sources = @config.setting(:sources).map do |(name, hash)|
63
- R10K::Deployment::Source.vivify(name, hash)
62
+ sources = @config.setting(:sources)
63
+ prefix = sources.length > 1
64
+ @_sources = sources.map do |(name, hash)|
65
+ R10K::Deployment::Source.vivify(name, hash, prefix)
64
66
  end
65
67
  end
66
68
 
@@ -57,7 +57,7 @@ class Config
57
57
  def apply_config_settings
58
58
  cachedir = setting(:cachedir)
59
59
  if cachedir
60
- R10K::Git::Cache.cache_root = cachedir
60
+ R10K::Git::Cache.settings[:cache_root] = cachedir
61
61
  end
62
62
  end
63
63
 
@@ -27,11 +27,13 @@ class Environment
27
27
  # @param [String] remote
28
28
  # @param [String] basedir
29
29
  # @param [String] dirname The directory to clone the root into, defaults to ref
30
- def initialize(ref, remote, basedir, dirname = nil)
30
+ # @param [String] source_name An additional string which may be used with ref to build dirname
31
+ def initialize(ref, remote, basedir, dirname = nil, source_name = "")
31
32
  @ref = ref
32
33
  @remote = remote
33
34
  @basedir = basedir
34
- @dirname = sanitize_dirname(dirname || ref)
35
+ alternate_name = source_name.empty? ? ref : source_name + "_" + ref
36
+ @dirname = sanitize_dirname(dirname || alternate_name)
35
37
 
36
38
  @working_dir = R10K::Git::WorkingDir.new(@ref, @remote, @basedir, @dirname)
37
39
 
@@ -67,7 +69,7 @@ class Environment
67
69
 
68
70
  # Strip out non-word characters in an environment directory name
69
71
  #
70
- # Puppet can only use word characers (letter, digit, underscore) in
72
+ # Puppet can only use word characters (letter, digit, underscore) in
71
73
  # environment names; this cleans up environment names to avoid traversals
72
74
  # and similar issues.
73
75
  #
@@ -27,20 +27,23 @@ class Source
27
27
  # @return [Array<R10K::Deployment::Environment>] All environments for this source
28
28
  attr_reader :environments
29
29
 
30
- def self.vivify(name, attrs)
30
+ def self.vivify(name, attrs, prefix = false)
31
31
  remote = (attrs.delete(:remote) || attrs.delete('remote'))
32
32
  basedir = (attrs.delete(:basedir) || attrs.delete('basedir'))
33
+ prefix_config = (attrs.delete(:prefix) || attrs.delete('prefix'))
34
+ prefix_outcome = prefix_config.nil? ? prefix : prefix_config
33
35
 
34
36
  raise ArgumentError, "Unrecognized attributes for #{self.name}: #{attrs.inspect}" unless attrs.empty?
35
- new(name, remote, basedir)
37
+ new(name, remote, basedir, prefix_outcome)
36
38
  end
37
39
 
38
- def initialize(name, remote, basedir)
40
+ def initialize(name, remote, basedir, prefix = nil)
39
41
  @name = name
40
42
  @remote = remote
41
43
  @basedir = basedir
44
+ @prefix = prefix.nil? ? false : prefix
42
45
 
43
- @cache = R10K::Git::Cache.new(@remote)
46
+ @cache = R10K::Git::Cache.generate(@remote)
44
47
 
45
48
  load_environments
46
49
  end
@@ -56,6 +59,16 @@ class Source
56
59
  @basedir
57
60
  end
58
61
 
62
+ def current_contents
63
+ dir = self.managed_directory
64
+ glob_part = @prefix ? @name.to_s() + '_*' : '*'
65
+ glob_exp = File.join(dir, glob_part)
66
+
67
+ Dir.glob(glob_exp).map do |fname|
68
+ File.basename fname
69
+ end
70
+ end
71
+
59
72
  # List all environments that should exist in the basedir for this source
60
73
  # @note This implements a required method for the Purgeable mixin
61
74
  # @return [Array<String>]
@@ -68,7 +81,11 @@ class Source
68
81
  def load_environments
69
82
  if @cache.cached?
70
83
  @environments = @cache.branches.map do |branch|
71
- R10K::Deployment::Environment.new(branch, @remote, @basedir)
84
+ if @prefix
85
+ R10K::Deployment::Environment.new(branch, @remote, @basedir, nil, @name.to_s())
86
+ else
87
+ R10K::Deployment::Environment.new(branch, @remote, @basedir)
88
+ end
72
89
  end
73
90
  else
74
91
  @environments = []
@@ -1,6 +1,9 @@
1
1
  require 'r10k/logging'
2
2
  require 'r10k/git/repository'
3
3
 
4
+ require 'r10k/settings'
5
+ require 'r10k/registry'
6
+
4
7
  module R10K
5
8
  module Git
6
9
  class Cache < R10K::Git::Repository
@@ -8,36 +11,16 @@ class Cache < R10K::Git::Repository
8
11
  #
9
12
  # @see man git-clone(1)
10
13
 
11
- class << self
12
-
13
- # @!attribute [r] cache_root
14
- # @return [String] The directory to use as the cache.
15
- attr_writer :cache_root
14
+ include R10K::Settings::Mixin
16
15
 
17
- def cache_root
18
- @cache_root
19
- end
16
+ def_setting_attr :cache_root, File.expand_path('~/.r10k/git')
20
17
 
21
- # Memoize class instances and return existing instances.
22
- #
23
- # This allows objects to mark themselves as cached to prevent unnecessary
24
- # cache refreshes.
25
- #
26
- # @param [String] remote A git remote URL
27
- # @return [R10K::Synchro::Git]
28
- def new(remote)
29
- @repos ||= {}
30
- unless @repos[remote]
31
- obj = self.allocate
32
- obj.send(:initialize, remote)
33
- @repos[remote] = obj
34
- end
35
- @repos[remote]
36
- end
18
+ def self.registry
19
+ @registry ||= R10K::Registry.new(self)
20
+ end
37
21
 
38
- def clear!
39
- @repos = {}
40
- end
22
+ def self.generate(remote)
23
+ registry.generate(remote)
41
24
  end
42
25
 
43
26
  include R10K::Logging
@@ -46,12 +29,6 @@ class Cache < R10K::Git::Repository
46
29
  # @return [String] The git repository remote
47
30
  attr_reader :remote
48
31
 
49
- # @!attribute [r] cache_root
50
- # Where to keep the git object cache. Defaults to ~/.r10k/git if a class
51
- # level value is not set.
52
- # @return [String] The directory to use as the cache
53
- attr_reader :cache_root
54
-
55
32
  # @!attribute [r] path
56
33
  # @return [String] The path to the git cache repository
57
34
  attr_reader :path
@@ -61,9 +38,7 @@ class Cache < R10K::Git::Repository
61
38
  def initialize(remote)
62
39
  @remote = remote
63
40
 
64
- @cache_root = self.class.cache_root || default_cache_root
65
-
66
- @path = File.join(@cache_root, sanitized_dirname)
41
+ @path = File.join(settings[:cache_root], sanitized_dirname)
67
42
  end
68
43
 
69
44
  def sync
@@ -85,7 +60,11 @@ class Cache < R10K::Git::Repository
85
60
  git "fetch --prune", :git_dir => @path
86
61
  else
87
62
  logger.debug "Creating new git cache for #{@remote.inspect}"
88
- FileUtils.mkdir_p cache_root unless File.exist? @cache_root
63
+
64
+ unless File.exist? settings[:cache_root]
65
+ FileUtils.mkdir_p settings[:cache_root]
66
+ end
67
+
89
68
  git "clone --mirror #{@remote} #{@path}"
90
69
  end
91
70
  end
@@ -119,10 +98,6 @@ class Cache < R10K::Git::Repository
119
98
  @remote.gsub(/[^@\w\.-]/, '-')
120
99
  end
121
100
 
122
- def default_cache_root
123
- File.expand_path('~/.r10k/git')
124
- end
125
-
126
101
  def git_dir
127
102
  @path
128
103
  end
@@ -37,7 +37,7 @@ class WorkingDir < R10K::Git::Repository
37
37
 
38
38
  @full_path = File.join(@basedir, @dirname)
39
39
 
40
- @cache = R10K::Git::Cache.new(@remote)
40
+ @cache = R10K::Git::Cache.generate(@remote)
41
41
  end
42
42
 
43
43
  # Synchronize the local git repository.
@@ -78,6 +78,7 @@ class WorkingDir < R10K::Git::Repository
78
78
  # that doing a normal `git pull` on a directory will work.
79
79
  git "clone --reference #{@cache.path} #{@remote} #{@full_path}"
80
80
  git "remote add cache #{@cache.path}", :path => @full_path
81
+ git "checkout #{@ref}", :path => @full_path
81
82
  end
82
83
 
83
84
  def fetch
data/lib/r10k/module.rb CHANGED
@@ -2,9 +2,8 @@ require 'r10k'
2
2
 
3
3
  module R10K::Module
4
4
 
5
- # Register an inheriting class for later generation
6
- def self.included(klass)
7
- klass.extend self
5
+ # Register an module implementation for later generation
6
+ def self.register(klass)
8
7
  @klasses ||= []
9
8
  @klasses << klass
10
9
  end
@@ -30,13 +29,7 @@ module R10K::Module
30
29
  end
31
30
  end
32
31
 
33
- attr_accessor :name, :basedir
34
-
35
- # @return [String] The full filesystem path to the module.
36
- def full_path
37
- File.join(@basedir, @name)
38
- end
32
+ require 'r10k/module/base'
33
+ require 'r10k/module/git'
34
+ require 'r10k/module/forge'
39
35
  end
40
-
41
- require 'r10k/module/git'
42
- require 'r10k/module/forge'
@@ -0,0 +1,10 @@
1
+ require 'r10k/module'
2
+
3
+ class R10K::Module::Base
4
+ attr_accessor :name, :basedir
5
+
6
+ # @return [String] The full filesystem path to the module.
7
+ def full_path
8
+ File.join(@basedir, @name)
9
+ end
10
+ end
@@ -1,4 +1,3 @@
1
- require 'r10k'
2
1
  require 'r10k/module'
3
2
  require 'r10k/errors'
4
3
  require 'r10k/logging'
@@ -8,11 +7,9 @@ require 'systemu'
8
7
  require 'semver'
9
8
  require 'json'
10
9
 
11
- module R10K
12
- module Module
13
- class Forge
10
+ class R10K::Module::Forge < R10K::Module::Base
14
11
 
15
- include R10K::Module
12
+ R10K::Module.register(self)
16
13
 
17
14
  def self.implement?(name, args)
18
15
  !!(name.match %r[\w+/\w+])
@@ -40,9 +37,16 @@ class Forge
40
37
  #logger.debug1 "Module #{@full_name} already matches version #{@version}"
41
38
  elsif File.exist? metadata_path
42
39
  #logger.debug "Module #{@full_name} is installed but doesn't match version #{@version}, upgrading"
40
+
41
+ # A Pulp based puppetforge http://www.pulpproject.org/ wont support
42
+ # `puppet module install abc/xyz --version=v1.5.9` but puppetlabs forge
43
+ # will support `puppet module install abc/xyz --version=1.5.9`
44
+ #
45
+ # Removing v from the semver for constructing the command ensures
46
+ # compatibility across both
43
47
  cmd = []
44
48
  cmd << 'upgrade'
45
- cmd << "--version=#{@version}" if @version
49
+ cmd << "--version=#{@version.to_s.sub(/^v/,'')}" if @version
46
50
  cmd << "--ignore-dependencies"
47
51
  cmd << @full_name
48
52
  pmt cmd
@@ -51,7 +55,7 @@ class Forge
51
55
  #logger.debug "Module #{@full_name} is not installed"
52
56
  cmd = []
53
57
  cmd << 'install'
54
- cmd << "--version=#{@version}" if @version
58
+ cmd << "--version=#{@version.to_s.sub(/^v/,'')}" if @version
55
59
  cmd << "--ignore-dependencies"
56
60
  cmd << @full_name
57
61
  pmt cmd
@@ -101,5 +105,3 @@ class Forge
101
105
  stdout
102
106
  end
103
107
  end
104
- end
105
- end
@@ -1,12 +1,10 @@
1
- require 'r10k'
2
1
  require 'r10k/module'
3
2
  require 'r10k/git/working_dir'
4
3
  require 'forwardable'
5
4
 
6
- module R10K
7
- module Module
8
- class Git
9
- include R10K::Module
5
+ class R10K::Module::Git < R10K::Module::Base
6
+
7
+ R10K::Module.register(self)
10
8
 
11
9
  def self.implement?(name, args)
12
10
  args.is_a? Hash and args.has_key?(:git)
@@ -30,5 +28,3 @@ class Git
30
28
  @ref
31
29
  end
32
30
  end
33
- end
34
- end
@@ -57,6 +57,11 @@ class Puppetfile
57
57
  @forge = forge
58
58
  end
59
59
 
60
+ # @param [String] moduledir
61
+ def set_moduledir(moduledir)
62
+ @moduledir = moduledir
63
+ end
64
+
60
65
  # @param [String] name
61
66
  # @param [*Object] args
62
67
  def add_module(name, args)
@@ -99,6 +104,10 @@ class Puppetfile
99
104
  @librarian.set_forge(location)
100
105
  end
101
106
 
107
+ def moduledir(location)
108
+ @librarian.set_moduledir(location)
109
+ end
110
+
102
111
  def method_missing(method, *args)
103
112
  raise NoMethodError, "unrecognized declaration '#{method}'"
104
113
  end
@@ -0,0 +1,32 @@
1
+ module R10K
2
+
3
+ # R10K::Registry implements a generic object memoization container. It caches
4
+ # new objects and returns cached objects based on the instantiation arguments.
5
+ class Registry
6
+
7
+ # Initialize a new registry with a given class
8
+ #
9
+ # @param klass [Class] The class to memoize
10
+ # @param method [Symbol] The method name to use when creating objects.
11
+ # Defaults to :new.
12
+ def initialize(klass, method = :new)
13
+ @klass = klass
14
+ @method = method
15
+ @instances = {}
16
+ end
17
+
18
+ # Create a new object, or return a memoized object.
19
+ #
20
+ # @param args [*Object] The arguments to pass to the initialize method
21
+ #
22
+ # @return [Object] A memoized instance of the registered class
23
+ def generate(*args)
24
+ @instances[args] ||= @klass.send(@method, *args)
25
+ end
26
+
27
+ # Clear all memoized objects
28
+ def clear!
29
+ @instances = {}
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,6 @@
1
+ module R10K
2
+ module Settings
3
+ require 'r10k/settings/container'
4
+ require 'r10k/settings/mixin'
5
+ end
6
+ end
@@ -0,0 +1,87 @@
1
+ # Defines a collection for application settings
2
+ #
3
+ # This implements a hierarchical interface to application settings. Containers
4
+ # can define an optional parent container that will be used for default options
5
+ # if those options aren't set on the given container.
6
+ class R10K::Settings::Container
7
+
8
+ # @!attribute [r] valid_keys
9
+ # @return [Set<Symbol>] All valid keys defined on the container or parent container.
10
+ attr_accessor :valid_keys
11
+
12
+ # @param parent [R10K::Settings::Container] An optional parent container
13
+ def initialize(parent = nil)
14
+ @parent = parent
15
+
16
+ @valid_keys = Set.new
17
+ @settings = {}
18
+ end
19
+
20
+ # Look up a value in the container. The lookup checks the current container,
21
+ # and then falls back to the parent container if it's given.
22
+ #
23
+ # @param key [Symbol] The lookup key
24
+ #
25
+ # @return [Object, nil] The retrieved value if present.
26
+ #
27
+ # @raise [R10K::Settings::Container::InvalidKey] If the looked up key isn't
28
+ # a valid key.
29
+ def [](key)
30
+ validate_key! key
31
+
32
+ if @settings[key]
33
+ @settings[key]
34
+ elsif @parent and (pkey = @parent[key])
35
+ @settings[key] = pkey
36
+ pkey
37
+ end
38
+ end
39
+
40
+ # Set a value on the container
41
+ #
42
+ # @param key [Symbol] The lookup key
43
+ # @param value [Object] The value to store in the container
44
+ #
45
+ # @raise [R10K::Settings::Container::InvalidKey] If the looked up key isn't
46
+ # a valid key.
47
+ def []=(key, value)
48
+ validate_key! key
49
+
50
+ @settings[key] = value
51
+ end
52
+
53
+ # Define a valid container key
54
+ #
55
+ # @note This should only be used by {#R10K::Settings::ClassSettings}
56
+ #
57
+ # @param key [Symbol]
58
+ # @return [void]
59
+ def add_valid_key(key)
60
+ @valid_keys.add(key)
61
+ end
62
+
63
+ # Determine if a key is a valid setting.
64
+ #
65
+ # @param key [Symbol]
66
+ #
67
+ # @return [true, false]
68
+ def valid_key?(key)
69
+ if @valid_keys.include?(key)
70
+ true
71
+ elsif @parent and @parent.valid_key?(key)
72
+ @valid_keys.add(key)
73
+ true
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ def validate_key!(key)
80
+ unless valid_key?(key)
81
+ raise InvalidKey, "Key #{key} is not a valid key"
82
+ end
83
+ end
84
+
85
+ # @api private
86
+ class InvalidKey < StandardError; end
87
+ end
@@ -0,0 +1,45 @@
1
+ module R10K::Settings::Mixin
2
+
3
+ def self.included(klass)
4
+ klass.send(:include, InstanceMethods)
5
+ klass.send(:extend, ClassMethods)
6
+ end
7
+
8
+ module InstanceMethods
9
+
10
+ # @return [R10K::Settings::Container] A settings container for the given instance.
11
+ def settings
12
+ @settings ||= R10K::Settings::Container.new(self.class.settings)
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+
18
+ # Define a setting and optional default on the extending class.
19
+ #
20
+ # @param key [Symbol]
21
+ # @param default [Object]
22
+ #
23
+ # @return [void]
24
+ def def_setting_attr(key, default = nil)
25
+ defaults.add_valid_key(key)
26
+ defaults[key] = default if default
27
+ end
28
+
29
+ # A singleton settings container for storing immutable default configuration
30
+ # on the extending class.
31
+ #
32
+ # @return [R10K::Settings::Container]
33
+ def defaults
34
+ @defaults ||= R10K::Settings::Container.new
35
+ end
36
+
37
+ # A singleton settings container for storing manual setting configurations
38
+ # on the extending class.
39
+ #
40
+ # @return [R10K::Settings::Container]
41
+ def settings
42
+ @settings ||= R10K::Settings::Container.new(defaults)
43
+ end
44
+ end
45
+ end
data/lib/r10k/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module R10K
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.0rc1'
3
3
  end
@@ -0,0 +1,8 @@
1
+ name 'branan-eight_hundred'
2
+ version '8.0.0'
3
+ source 'https://github.com/branan/puppet-module-eight_hundred'
4
+ author 'Branan Purvine-Riley'
5
+ license 'Apache License 2.0'
6
+ summary '800 modules! WOOOOOOO!'
7
+ description '800 modules! WOOOOOOOOOOOOOOOOOO!'
8
+ project_page 'https://github.com/branan/puppet-module-eight_hundred'
@@ -0,0 +1,19 @@
1
+ {
2
+ "checksums": {
3
+ "Modulefile": "1e780d794bcd6629dc3006129fc02edf"
4
+ },
5
+ "license": "Apache License 2.0",
6
+ "types": [
7
+
8
+ ],
9
+ "version": "8.0.0",
10
+ "dependencies": [
11
+
12
+ ],
13
+ "summary": "800 modules! WOOOOOOO!",
14
+ "source": "https://github.com/branan/puppet-module-eight_hundred",
15
+ "description": "800 modules! WOOOOOOOOOOOOOOOOOO!",
16
+ "author": "Branan Purvine-Riley",
17
+ "name": "branan-eight_hundred",
18
+ "project_page": "https://github.com/branan/puppet-module-eight_hundred"
19
+ }
@@ -0,0 +1,10 @@
1
+ require 'r10k'
2
+
3
+ PROJECT_ROOT = File.expand_path('..', File.dirname(__FILE__))
4
+
5
+ RSpec.configure do |config|
6
+ # Filter out integration tests by default
7
+ #
8
+ # To run integration tests, run `rspec --tag integration`
9
+ config.filter_run_excluding :integration => true
10
+ end
@@ -11,6 +11,11 @@ describe R10K::Deployment::Environment do
11
11
  subject.dirname.should == 'master'
12
12
  end
13
13
 
14
+ it 'uses the ref and a provided source name in the default dirname' do
15
+ subject = described_class.new(ref, remote, '/tmp', nil, "the")
16
+ subject.dirname.should == 'the_master'
17
+ end
18
+
14
19
  it 'allows a specific dirname to be set' do
15
20
  subject = described_class.new(ref, remote, '/tmp', 'sourcename_master')
16
21
  subject.dirname.should == 'sourcename_master'
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ require 'r10k/deployment/source'
3
+
4
+ describe R10K::Deployment::Source do
5
+ let(:name) { 'do_not_name_a_branch_this' }
6
+ let(:remote) { 'git://github.com/adrienthebo/r10k-fixture-repo' }
7
+ let(:basedir) { '/tmp' }
8
+
9
+ describe 'environments' do
10
+ it 'uses the name as a prefix when told' do
11
+ subject = described_class.new(name, remote, basedir, true)
12
+ subject.fetch_remote()
13
+ subject.environments.length.should > 0
14
+ subject.environments.first.dirname.should start_with name
15
+ end
16
+
17
+ it 'avoids using the name as a prefix when told' do
18
+ subject = described_class.new(name, remote, basedir, false)
19
+ subject.fetch_remote()
20
+ subject.environments.length.should > 0
21
+ subject.environments.first.dirname.should_not start_with name
22
+ end
23
+ end
24
+ end
@@ -2,10 +2,6 @@ require 'spec_helper'
2
2
 
3
3
  describe R10K::Git::WorkingDir do
4
4
 
5
- before do
6
- R10K::Git::Cache.stubs(:cache_root).returns '/tmp'
7
- end
8
-
9
5
  describe "initializing" do
10
6
  it "generates a new cache for the remote" do
11
7
  wd = described_class.new('master', 'git://github.com/adrienthebo/r10k-fixture-repo', '/tmp')
@@ -4,12 +4,12 @@ require 'spec_helper'
4
4
 
5
5
  describe R10K::Module::Forge do
6
6
  before :each do
7
- Object.expects(:systemu).never
7
+ allow_any_instance_of(Object).to receive(:systemu).and_raise "Tests should never invoke system calls"
8
8
  end
9
9
 
10
10
  before :each do
11
- s = stub(:debug2 => nil, :debug1 => nil, :debug => nil, :info => nil)
12
- described_class.any_instance.stubs(:logger).returns s
11
+ log = double('stub logger').as_null_object
12
+ described_class.any_instance.stub(:logger).and_return log
13
13
  end
14
14
 
15
15
  describe "implementing the Puppetfile spec" do
@@ -54,9 +54,8 @@ describe R10K::Module::Forge do
54
54
  its(:version) { should eq 'v8.0.0' }
55
55
 
56
56
  it "should try to upgrade the module" do
57
- # "v80.0.0" ? Seriously? Where did the "v" come from?
58
- expected = %w{upgrade --version=v80.0.0 --ignore-dependencies branan/eight_hundred}
59
- subject.expects(:pmt).with(expected)
57
+ expected = %w{upgrade --version=80.0.0 --ignore-dependencies branan/eight_hundred}
58
+ expect(subject).to receive(:pmt).with(expected)
60
59
  subject.sync
61
60
  end
62
61
  end
@@ -65,12 +64,12 @@ describe R10K::Module::Forge do
65
64
  subject { described_class.new('branan/eight_hundred', fixture_modulepath, '7.0.0') }
66
65
 
67
66
  it { should_not be_insync }
68
- its(:version) { should eq 'v8.0.0' }
67
+ its(:version) { should eq '8.0.0' }
69
68
 
70
69
  it "should try to downgrade the module" do
71
70
  # Again with the magical "v" prefix to the version.
72
- expected = %w{upgrade --version=v7.0.0 --ignore-dependencies branan/eight_hundred}
73
- subject.expects(:pmt).with(expected)
71
+ expected = %w{upgrade --version=7.0.0 --ignore-dependencies branan/eight_hundred}
72
+ expect(subject).to receive(:pmt).with(expected)
74
73
  subject.sync
75
74
  end
76
75
  end
@@ -82,8 +81,8 @@ describe R10K::Module::Forge do
82
81
  its(:version) { should eq SemVer::MIN }
83
82
 
84
83
  it "should try to install the module" do
85
- expected = %w{install --version=v8.0.0 --ignore-dependencies branan/eight_hundred}
86
- subject.expects(:pmt).with(expected)
84
+ expected = %w{install --version=8.0.0 --ignore-dependencies branan/eight_hundred}
85
+ expect(subject).to receive(:pmt).with(expected)
87
86
  subject.sync
88
87
  end
89
88
  end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ require 'r10k/registry'
4
+
5
+ describe R10K::Registry do
6
+
7
+ describe "setting up a new registry" do
8
+ let(:klass) do
9
+ dubs = double('test class')
10
+ allow(dubs).to receive(:new) { |*args| args }
11
+ dubs
12
+ end
13
+
14
+ it "can create new objects" do
15
+ registry = described_class.new(klass)
16
+ expect(registry.generate).to eq []
17
+ end
18
+
19
+ describe "defining object arity" do
20
+
21
+ it "handles unary objects" do
22
+ expect(klass).to receive(:new).with(:foo)
23
+
24
+ registry = described_class.new(klass)
25
+ expect(registry.generate(:foo)).to eq [:foo]
26
+ end
27
+
28
+ it "handles ternary objects" do
29
+ expect(klass).to receive(:new).with(:foo, :bar, :baz)
30
+
31
+ registry = described_class.new(klass)
32
+ expect(registry.generate(:foo, :bar, :baz)).to eq [:foo, :bar, :baz]
33
+ end
34
+
35
+ it 'handles n-ary objects' do
36
+ args = %w[a bunch of arbitrary objects]
37
+ expect(klass).to receive(:new).with(*args)
38
+
39
+ registry = described_class.new(klass)
40
+ expect(registry.generate(*args)).to eq args
41
+ end
42
+
43
+ it 'fails when the required arguments are not matched' do
44
+ expect(klass).to receive(:new).and_raise ArgumentError, "not enough args"
45
+
46
+ registry = described_class.new(klass)
47
+ expect { registry.generate('arity is hard') }.to raise_error ArgumentError, "not enough args"
48
+ end
49
+ end
50
+
51
+ it "can specify the constructor method" do
52
+ expect(klass).to receive(:from_json).and_return "this is json, right?"
53
+
54
+ registry = described_class.new(klass, :from_json)
55
+ expect(registry.generate).to eq "this is json, right?"
56
+ end
57
+ end
58
+
59
+
60
+ it "returns a memoized object if it's been created before" do
61
+ registry = described_class.new(String)
62
+ first = registry.generate "bam!"
63
+ second = registry.generate "bam!"
64
+
65
+ expect(first.object_id).to eq second.object_id
66
+ end
67
+
68
+ it 'can clear registered objects' do
69
+ registry = described_class.new(String)
70
+
71
+ first = registry.generate "bam!"
72
+ registry.clear!
73
+ second = registry.generate "bam!"
74
+
75
+ expect(first.object_id).to_not eq second.object_id
76
+
77
+ end
78
+ end
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ require 'r10k/settings'
4
+
5
+ describe R10K::Settings::Container do
6
+
7
+ describe 'validating keys' do
8
+ it 'can add new valid keys' do
9
+ subject.add_valid_key(:v)
10
+ subject[:v]
11
+ end
12
+
13
+ it 'can check if a key is valid' do
14
+ subject.add_valid_key(:v)
15
+ expect(subject.valid_key?(:v)).to be_true
16
+ end
17
+
18
+ it 'can list all valid keys' do
19
+ subject.add_valid_key(:v)
20
+ subject.add_valid_key(:w)
21
+
22
+ expect(subject.valid_keys).to include :v
23
+ expect(subject.valid_keys).to include :w
24
+ end
25
+ end
26
+
27
+ describe 'specifying settings' do
28
+ it 'fails if a setting application uses an invalid key' do
29
+ expect { subject[:invalid] = 'fail' }.to raise_error R10K::Settings::Container::InvalidKey
30
+ end
31
+
32
+ it 'can look up values that it sets' do
33
+ subject.add_valid_key :v
34
+ subject[:v] = 'set'
35
+ expect(subject[:v]).to eq 'set'
36
+ end
37
+ end
38
+
39
+ describe 'looking up settings' do
40
+ before do
41
+ subject.add_valid_key :v
42
+ end
43
+
44
+ it 'fails if a setting lookup uses an invalid key' do
45
+ expect { subject[:invalid] }.to raise_error R10K::Settings::Container::InvalidKey
46
+ end
47
+
48
+ it 'returns nil if a key is valid but no setting is present' do
49
+ expect(subject[:v]).to be_nil
50
+ end
51
+
52
+ describe 'with a parent container' do
53
+ let(:parent) { described_class.new.tap { |p| p.add_valid_key :v } }
54
+ subject { described_class.new(parent) }
55
+
56
+ it 'uses its setting over a parent value' do
57
+ subject[:v] = 'child'
58
+ parent[:v] = 'parent'
59
+ expect(subject[:v]).to eq 'child'
60
+ end
61
+
62
+ it 'falls back to the parent value if it does not have a value' do
63
+ parent[:v] = 'parent'
64
+ expect(subject[:v]).to eq 'parent'
65
+ end
66
+ end
67
+ end
68
+ end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: r10k
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
5
- prerelease:
4
+ version: 1.1.0rc1
5
+ prerelease: 5
6
6
  platform: ruby
7
7
  authors:
8
8
  - Adrien Thebo
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-05-31 00:00:00.000000000 Z
12
+ date: 2013-09-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: colored
@@ -34,7 +34,7 @@ dependencies:
34
34
  requirements:
35
35
  - - ~>
36
36
  - !ruby/object:Gem::Version
37
- version: 2.3.0
37
+ version: 2.4.0
38
38
  type: :runtime
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
@@ -42,7 +42,7 @@ dependencies:
42
42
  requirements:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
- version: 2.3.0
45
+ version: 2.4.0
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: systemu
48
48
  requirement: !ruby/object:Gem::Requirement
@@ -98,7 +98,7 @@ dependencies:
98
98
  requirements:
99
99
  - - ~>
100
100
  - !ruby/object:Gem::Version
101
- version: 2.10.0
101
+ version: 2.14.0
102
102
  type: :development
103
103
  prerelease: false
104
104
  version_requirements: !ruby/object:Gem::Requirement
@@ -106,27 +106,10 @@ dependencies:
106
106
  requirements:
107
107
  - - ~>
108
108
  - !ruby/object:Gem::Version
109
- version: 2.10.0
110
- - !ruby/object:Gem::Dependency
111
- name: mocha
112
- requirement: !ruby/object:Gem::Requirement
113
- none: false
114
- requirements:
115
- - - ~>
116
- - !ruby/object:Gem::Version
117
- version: 0.10.5
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
- requirements:
123
- - - ~>
124
- - !ruby/object:Gem::Version
125
- version: 0.10.5
126
- description: ! " R10K is an implementation of the Dynamic Puppet environments based
127
- on git repositories\n as described in http://puppetlabs.com/blog/git-workflow-and-puppet-environments/.
128
- It\n aggressively caches and tries to minimize network activity to ensure that
129
- interactive\n deployment is as fast as possible.\n"
109
+ version: 2.14.0
110
+ description: ! " R10K provides a general purpose toolset for deploying Puppet environments
111
+ and modules.\n It implements the Puppetfile format and provides a native implementation
112
+ of Puppet\n dynamic environments.\n"
130
113
  email: adrien@somethingsinistral.net
131
114
  executables:
132
115
  - r10k
@@ -137,7 +120,9 @@ files:
137
120
  - lib/r10k.rb
138
121
  - lib/r10k/errors.rb
139
122
  - lib/r10k/logging.rb
123
+ - lib/r10k/registry.rb
140
124
  - lib/r10k/deployment.rb
125
+ - lib/r10k/settings.rb
141
126
  - lib/r10k/git/errors.rb
142
127
  - lib/r10k/git/cache.rb
143
128
  - lib/r10k/git/working_dir.rb
@@ -152,7 +137,6 @@ files:
152
137
  - lib/r10k/deployment/config.rb
153
138
  - lib/r10k/deployment/source.rb
154
139
  - lib/r10k/util/purgeable.rb
155
- - lib/r10k/util/interp.rb
156
140
  - lib/r10k/cli/environment.rb
157
141
  - lib/r10k/cli/environment/list.rb
158
142
  - lib/r10k/cli/environment/deploy.rb
@@ -165,19 +149,27 @@ files:
165
149
  - lib/r10k/cli/module/list.rb
166
150
  - lib/r10k/cli/module/deploy.rb
167
151
  - lib/r10k/cli/version.rb
152
+ - lib/r10k/settings/container.rb
153
+ - lib/r10k/settings/mixin.rb
168
154
  - lib/r10k/task/environment.rb
169
155
  - lib/r10k/task/deployment.rb
170
156
  - lib/r10k/task/module.rb
171
157
  - lib/r10k/task/puppetfile.rb
172
158
  - lib/r10k/task.rb
159
+ - lib/r10k/module/base.rb
173
160
  - lib/r10k/module/forge.rb
174
161
  - lib/r10k/module/git.rb
175
162
  - lib/r10k/version.rb
176
163
  - lib/semver.rb
164
+ - spec/spec_helper.rb
165
+ - spec/fixtures/module/forge/eight_hundred/metadata.json
166
+ - spec/fixtures/module/forge/eight_hundred/Modulefile
167
+ - spec/unit/registry_spec.rb
177
168
  - spec/unit/module_spec.rb
178
169
  - spec/unit/git/working_dir_spec.rb
179
- - spec/unit/git/cache_spec.rb
180
170
  - spec/unit/deployment/environment_spec.rb
171
+ - spec/unit/deployment/source_spec.rb
172
+ - spec/unit/settings/container_spec.rb
181
173
  - spec/unit/module/forge_spec.rb
182
174
  homepage: http://github.com/adrienthebo/r10k
183
175
  licenses: []
@@ -194,18 +186,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
194
186
  required_rubygems_version: !ruby/object:Gem::Requirement
195
187
  none: false
196
188
  requirements:
197
- - - ! '>='
189
+ - - ! '>'
198
190
  - !ruby/object:Gem::Version
199
- version: '0'
191
+ version: 1.3.1
200
192
  requirements: []
201
193
  rubyforge_project:
202
194
  rubygems_version: 1.8.23
203
195
  signing_key:
204
196
  specification_version: 3
205
- summary: Dynamic Puppet environments with Git
197
+ summary: Puppet environment and module deployment
206
198
  test_files:
199
+ - spec/unit/registry_spec.rb
207
200
  - spec/unit/module_spec.rb
208
201
  - spec/unit/git/working_dir_spec.rb
209
- - spec/unit/git/cache_spec.rb
210
202
  - spec/unit/deployment/environment_spec.rb
203
+ - spec/unit/deployment/source_spec.rb
204
+ - spec/unit/settings/container_spec.rb
211
205
  - spec/unit/module/forge_spec.rb
206
+ has_rdoc:
@@ -1,25 +0,0 @@
1
-
2
- module R10K; end
3
- module R10K::Util; end
4
-
5
- module R10K::Util::Interp
6
-
7
- # Interpolate a string with a given scope
8
- #
9
- # @param [String] string
10
- # @param [Hash] scope
11
- #
12
- # @return [String]
13
- def interpolate_string(string, scope)
14
-
15
- interp = string.clone
16
-
17
- while (matchdata = interp.match /%\{.+?\}/)
18
- var_name = matchdata[1].intern
19
- var_data = scope[var_name]
20
- interp.gsub!(/%\{#{var_name}\}/, var_data)
21
- end
22
-
23
- interp
24
- end
25
- end
@@ -1,37 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe R10K::Git::Cache, 'memoizing objects' do
4
-
5
- it "returns the same object when a remote is duplicated" do
6
- first = described_class.new('foo')
7
- second = described_class.new('foo')
8
-
9
- first.should be second
10
- end
11
-
12
- it "wipes the memoized objects when .clear! is called" do
13
- first = described_class.new('foo')
14
- described_class.clear!
15
- second = described_class.new('foo')
16
-
17
- first.should_not be second
18
- end
19
- end
20
-
21
- describe R10K::Git::Cache do
22
-
23
- after do
24
- described_class.clear!
25
- end
26
-
27
- describe 'setting the cache root' do
28
- it 'defaults to ~/.r10k/git' do
29
- described_class.new('foo').cache_root.should match %r[/\.r10k/git]
30
- end
31
-
32
- it 'uses the class cache root if set' do
33
- described_class.stubs(:cache_root).returns '/var/spool/r10k'
34
- described_class.new('foo').cache_root.should == '/var/spool/r10k'
35
- end
36
- end
37
- end