r10k 1.1.4 → 1.2.0rc1
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.
- checksums.yaml +8 -8
- data/.gitignore +1 -0
- data/.nodeset.yml +7 -0
- data/.rspec +1 -0
- data/.travis.yml +2 -1
- data/CHANGELOG +17 -12
- data/Gemfile +8 -0
- data/README.markdown +4 -2
- data/Rakefile +1 -0
- data/doc/dynamic-environments.markdown +206 -0
- data/doc/puppetfile.markdown +87 -0
- data/lib/r10k/cli.rb +1 -1
- data/lib/r10k/errors.rb +30 -3
- data/lib/r10k/execution.rb +5 -2
- data/lib/r10k/git/cache.rb +26 -42
- data/lib/r10k/git/commit.rb +22 -0
- data/lib/r10k/git/errors.rb +31 -22
- data/lib/r10k/git/head.rb +33 -0
- data/lib/r10k/git/ref.rb +63 -0
- data/lib/r10k/git/repository.rb +65 -36
- data/lib/r10k/git/tag.rb +26 -0
- data/lib/r10k/git/working_dir.rb +93 -83
- data/lib/r10k/git.rb +14 -0
- data/lib/r10k/module/forge.rb +129 -62
- data/lib/r10k/module/git.rb +72 -6
- data/lib/r10k/module/metadata.rb +47 -0
- data/lib/r10k/module/svn.rb +99 -0
- data/lib/r10k/module.rb +1 -0
- data/lib/r10k/module_repository/forge.rb +64 -0
- data/lib/r10k/module_repository.rb +8 -0
- data/lib/r10k/semver.rb +1 -1
- data/lib/r10k/svn/working_dir.rb +76 -0
- data/lib/r10k/task/deployment.rb +21 -28
- data/lib/r10k/util/subprocess/io.rb +12 -0
- data/lib/r10k/util/subprocess/result.rb +36 -0
- data/lib/r10k/util/subprocess/runner.rb +88 -0
- data/lib/r10k/util/subprocess.rb +107 -0
- data/lib/r10k/version.rb +1 -1
- data/r10k.gemspec +11 -1
- data/spec/fixtures/vcr/cassettes/R10K_ModuleRepository_Forge/and_the_expected_version_is_latest/can_fetch_all_versions_of_a_given_module.yml +42 -0
- data/spec/fixtures/vcr/cassettes/R10K_ModuleRepository_Forge/and_the_expected_version_is_latest/can_fetch_the_latest_version_of_a_given_module.yml +42 -0
- data/spec/fixtures/vcr/cassettes/R10K_ModuleRepository_Forge/looking_up_versions/can_fetch_all_versions_of_a_given_module.yml +42 -0
- data/spec/fixtures/vcr/cassettes/R10K_ModuleRepository_Forge/looking_up_versions/can_fetch_the_latest_version_of_a_given_module.yml +42 -0
- data/spec/fixtures/vcr/cassettes/R10K_ModuleRepository_Forge/looking_up_versions.yml +42 -0
- data/spec/fixtures/vcr/cassettes/R10K_Module_Forge/and_the_expected_version_is_latest/sets_the_expected_version_based_on_the_latest_forge_version.yml +42 -0
- data/spec/rspec-system-r10k/puppetfile.rb +24 -0
- data/spec/rspec-system-r10k/tmpdir.rb +32 -0
- data/spec/shared-examples/git-ref.rb +49 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/system/module/forge/install_spec.rb +51 -0
- data/spec/system/module/git/install_spec.rb +117 -0
- data/spec/system/module/svn/install_spec.rb +51 -0
- data/spec/system/module/svn/update_spec.rb +38 -0
- data/spec/system/spec_helper.rb +60 -0
- data/spec/system/system-helpers.rb +4 -0
- data/spec/system/version_spec.rb +7 -0
- data/spec/system-provisioning/el.rb +38 -0
- data/spec/unit/deployment/source_spec.rb +1 -1
- data/spec/unit/git/cache_spec.rb +38 -0
- data/spec/unit/git/commit_spec.rb +33 -0
- data/spec/unit/git/head_spec.rb +27 -0
- data/spec/unit/git/ref_spec.rb +68 -0
- data/spec/unit/git/tag_spec.rb +31 -0
- data/spec/unit/module/forge_spec.rb +157 -37
- data/spec/unit/module/git_spec.rb +49 -0
- data/spec/unit/module/metadata_spec.rb +68 -0
- data/spec/unit/module/svn_spec.rb +146 -0
- data/spec/unit/module_repository/forge_spec.rb +32 -0
- metadata +151 -8
data/lib/r10k/git/tag.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'r10k/git/ref'
|
2
|
+
require 'r10k/git/repository'
|
3
|
+
|
4
|
+
# tag: A ref under refs/tags/ namespace that points to an object of an
|
5
|
+
# arbitrary type (typically a tag points to either a tag or a commit object).
|
6
|
+
# In contrast to a head, a tag is not updated by the commit command. A tag is
|
7
|
+
# most typically used to mark a particular point in the commit ancestry chain.
|
8
|
+
#
|
9
|
+
# @see https://www.kernel.org/pub/software/scm/git/docs/gitglossary.html
|
10
|
+
# @api private
|
11
|
+
class R10K::Git::Tag < R10K::Git::Ref
|
12
|
+
|
13
|
+
# @!attribute [r] tag
|
14
|
+
# @return [String] The git tag
|
15
|
+
attr_reader :tag
|
16
|
+
alias :ref :tag
|
17
|
+
|
18
|
+
def initialize(tag, repository = nil)
|
19
|
+
@tag = tag
|
20
|
+
@repository = repository
|
21
|
+
end
|
22
|
+
|
23
|
+
def fetch?
|
24
|
+
! resolvable?
|
25
|
+
end
|
26
|
+
end
|
data/lib/r10k/git/working_dir.rb
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
require 'r10k/logging'
|
3
|
+
require 'r10k/git'
|
3
4
|
require 'r10k/git/cache'
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
# working directories only contain checked out files and all object files are
|
12
|
-
# shared.
|
6
|
+
# Implements sparse git repositories with shared objects
|
7
|
+
#
|
8
|
+
# Working directory instances use the git alternatives object store, so that
|
9
|
+
# working directories only contain checked out files and all object files are
|
10
|
+
# shared.
|
11
|
+
class R10K::Git::WorkingDir < R10K::Git::Repository
|
13
12
|
|
14
13
|
include R10K::Logging
|
15
14
|
|
@@ -20,124 +19,135 @@ class WorkingDir < R10K::Git::Repository
|
|
20
19
|
attr_reader :cache
|
21
20
|
|
22
21
|
# @!attribute [r] ref
|
23
|
-
# @return [
|
22
|
+
# @return [R10K::Git::Ref] The git reference to use check out in the given directory
|
24
23
|
attr_reader :ref
|
25
24
|
|
26
|
-
#
|
25
|
+
# @!attribute [r] remote
|
26
|
+
# @return [String] The actual remote used as an upstream for this module.
|
27
|
+
attr_reader :remote
|
28
|
+
|
29
|
+
# Create a new shallow git working directory
|
27
30
|
#
|
28
|
-
# @param [String]
|
29
|
-
# @param [String]
|
30
|
-
# @param [String]
|
31
|
-
# @param [String]
|
31
|
+
# @param ref [String, R10K::Git::Ref]
|
32
|
+
# @param remote [String]
|
33
|
+
# @param basedir [String]
|
34
|
+
# @param dirname [String]
|
32
35
|
def initialize(ref, remote, basedir, dirname = nil)
|
33
|
-
|
36
|
+
|
34
37
|
@remote = remote
|
35
38
|
@basedir = basedir
|
36
39
|
@dirname = dirname || ref
|
37
40
|
|
38
41
|
@full_path = File.join(@basedir, @dirname)
|
42
|
+
@git_dir = File.join(@full_path, '.git')
|
39
43
|
|
40
44
|
@cache = R10K::Git::Cache.generate(@remote)
|
45
|
+
|
46
|
+
if ref.is_a? String
|
47
|
+
@ref = R10K::Git::Ref.new(ref, self)
|
48
|
+
else
|
49
|
+
@ref = ref
|
50
|
+
@ref.repository = self
|
51
|
+
end
|
41
52
|
end
|
42
53
|
|
43
54
|
# Synchronize the local git repository.
|
44
55
|
def sync
|
45
|
-
|
46
|
-
@cache.sync
|
47
|
-
|
48
|
-
if cloned?
|
49
|
-
fetch
|
50
|
-
else
|
56
|
+
if not cloned?
|
51
57
|
clone
|
58
|
+
elsif fetch?
|
59
|
+
fetch_from_cache
|
60
|
+
checkout(@ref)
|
61
|
+
elsif needs_checkout?
|
62
|
+
checkout(@ref)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def update
|
67
|
+
if fetch?
|
68
|
+
fetch_from_cache
|
69
|
+
checkout(@ref)
|
70
|
+
elsif needs_checkout?
|
71
|
+
checkout(@ref)
|
52
72
|
end
|
53
|
-
reset
|
54
73
|
end
|
55
74
|
|
56
75
|
# Determine if repo has been cloned into a specific dir
|
57
76
|
#
|
58
77
|
# @return [true, false] If the repo has already been cloned
|
59
78
|
def cloned?
|
60
|
-
File.directory? git_dir
|
79
|
+
File.directory? @git_dir
|
61
80
|
end
|
81
|
+
alias :git? :cloned?
|
62
82
|
|
63
|
-
|
83
|
+
# Does a directory exist where we expect a working dir to be?
|
84
|
+
# @return [true, false]
|
85
|
+
def exist?
|
86
|
+
File.directory? @full_path
|
87
|
+
end
|
64
88
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
89
|
+
# check out the given ref
|
90
|
+
#
|
91
|
+
# @param ref [R10K::Git::Ref] The git reference to check out
|
92
|
+
def checkout(ref)
|
93
|
+
if ref.resolvable?
|
94
|
+
git ["checkout", "--force", @ref.sha1], :path => @full_path
|
70
95
|
else
|
71
|
-
|
96
|
+
raise R10K::Git::UnresolvableRefError.new(
|
97
|
+
"Cannot check out unresolvable ref '#{@ref}'",
|
98
|
+
:git_dir => @full_path)
|
72
99
|
end
|
73
100
|
end
|
74
101
|
|
75
|
-
#
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
git "remote add cache #{@cache.path}", :path => @full_path
|
81
|
-
git "checkout #{@ref}", :path => @full_path
|
102
|
+
# The currently checked out HEAD
|
103
|
+
#
|
104
|
+
# @return [R10k::Git::Head]
|
105
|
+
def current
|
106
|
+
R10K::Git::Head.new('HEAD', self)
|
82
107
|
end
|
83
108
|
|
84
|
-
def
|
85
|
-
|
86
|
-
git "fetch --prune cache", :path => @full_path
|
109
|
+
def outdated?
|
110
|
+
@ref.fetch? or needs_checkout?
|
87
111
|
end
|
88
112
|
|
89
|
-
|
90
|
-
def reset
|
91
|
-
commit = cache.rev_parse(@ref)
|
92
|
-
current = rev_parse('HEAD')
|
93
|
-
|
94
|
-
if commit == current
|
95
|
-
logger.debug1 "Git repo #{@full_path} is already at #{commit}, no need to reset"
|
96
|
-
return
|
97
|
-
end
|
113
|
+
private
|
98
114
|
|
99
|
-
|
100
|
-
|
101
|
-
rescue R10K::ExecutionFailure => e
|
102
|
-
logger.error "Unable to locate commit object #{commit} in git repo #{@full_path}"
|
103
|
-
raise
|
104
|
-
end
|
115
|
+
def fetch?
|
116
|
+
@ref.fetch?
|
105
117
|
end
|
106
118
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
# @return [String] The dereferenced hash of `ref`
|
112
|
-
def rev_parse(ref)
|
113
|
-
commit = git "rev-parse #{ref}^{commit}", :path => @full_path
|
114
|
-
commit.chomp
|
115
|
-
rescue R10K::ExecutionFailure => e
|
116
|
-
logger.error "Could not resolve ref #{ref.inspect} for git repo #{@full_path}"
|
117
|
-
raise
|
119
|
+
def fetch_from_cache
|
120
|
+
set_cache_remote
|
121
|
+
@cache.sync
|
122
|
+
fetch('cache')
|
118
123
|
end
|
119
124
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
125
|
+
def set_cache_remote
|
126
|
+
if self.remote != @cache.remote
|
127
|
+
git ["remote", "set-url", "cache", @cache.git_dir], :path => @full_path
|
128
|
+
end
|
129
|
+
end
|
124
130
|
|
125
|
-
|
131
|
+
# Perform a non-bare clone of a git repository.
|
132
|
+
def clone
|
133
|
+
@cache.sync
|
126
134
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
end
|
135
|
+
# We do the clone against the target repo using the `--reference` flag so
|
136
|
+
# that doing a normal `git pull` on a directory will work.
|
137
|
+
git ["clone", "--reference", @cache.git_dir, @remote, @full_path]
|
138
|
+
git ["remote", "add", "cache", @cache.git_dir], :path => @full_path
|
139
|
+
checkout(@ref)
|
140
|
+
end
|
134
141
|
|
135
|
-
|
142
|
+
def needs_fetch?
|
143
|
+
ref.fetch?
|
136
144
|
end
|
137
145
|
|
138
|
-
|
139
|
-
|
146
|
+
# Does the expected ref match the actual ref?
|
147
|
+
def needs_checkout?
|
148
|
+
expected = ref.sha1
|
149
|
+
actual = rev_parse('HEAD')
|
150
|
+
|
151
|
+
! (expected == actual)
|
140
152
|
end
|
141
153
|
end
|
142
|
-
end
|
143
|
-
end
|
data/lib/r10k/git.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module R10K
|
2
|
+
module Git
|
3
|
+
require 'r10k/git/errors'
|
4
|
+
|
5
|
+
require 'r10k/git/ref'
|
6
|
+
require 'r10k/git/tag'
|
7
|
+
require 'r10k/git/head'
|
8
|
+
require 'r10k/git/commit'
|
9
|
+
|
10
|
+
require 'r10k/git/repository'
|
11
|
+
require 'r10k/git/cache'
|
12
|
+
require 'r10k/git/working_dir'
|
13
|
+
end
|
14
|
+
end
|
data/lib/r10k/module/forge.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
require 'r10k/module'
|
2
2
|
require 'r10k/errors'
|
3
3
|
require 'r10k/logging'
|
4
|
+
require 'r10k/module/metadata'
|
5
|
+
require 'r10k/util/subprocess'
|
6
|
+
require 'r10k/module_repository/forge'
|
4
7
|
|
8
|
+
require 'pathname'
|
5
9
|
require 'fileutils'
|
6
|
-
require 'systemu'
|
7
10
|
require 'r10k/semver'
|
8
|
-
require 'json'
|
9
11
|
|
10
12
|
class R10K::Module::Forge < R10K::Module::Base
|
11
13
|
|
@@ -17,91 +19,156 @@ class R10K::Module::Forge < R10K::Module::Base
|
|
17
19
|
|
18
20
|
include R10K::Logging
|
19
21
|
|
20
|
-
|
22
|
+
# @!attribute [r] author
|
23
|
+
# @return [String] The Forge module author
|
24
|
+
attr_reader :author
|
21
25
|
|
22
|
-
|
23
|
-
|
26
|
+
# @deprecated
|
27
|
+
def owner
|
28
|
+
logger.warn "#{self.inspect}#owner is deprecated; use #author instead"
|
29
|
+
@author
|
30
|
+
end
|
31
|
+
|
32
|
+
# @!attribute [r] full_name
|
33
|
+
# @return [String] The fully qualified module name
|
34
|
+
attr_reader :full_name
|
35
|
+
|
36
|
+
def initialize(full_name, basedir, args)
|
37
|
+
@full_name = full_name
|
24
38
|
@basedir = basedir
|
25
39
|
|
26
|
-
@
|
40
|
+
@author, @name = full_name.split('/')
|
41
|
+
|
42
|
+
@full_path = Pathname.new(File.join(@basedir, @name))
|
43
|
+
|
44
|
+
@metadata = R10K::Module::Metadata.new(@full_path + 'metadata.json')
|
27
45
|
|
28
46
|
if args.is_a? String
|
29
|
-
@
|
47
|
+
@expected_version = R10K::SemVer.new(args)
|
48
|
+
elsif args.is_a? Symbol and args == :latest
|
49
|
+
@expected_version = args
|
30
50
|
end
|
31
51
|
end
|
32
52
|
|
33
53
|
def sync(options = {})
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
47
|
-
cmd = []
|
48
|
-
cmd << 'upgrade'
|
49
|
-
cmd << "--version=#{@version.to_s.sub(/^v/,'')}" if @version
|
50
|
-
cmd << "--ignore-dependencies"
|
51
|
-
cmd << @full_name
|
52
|
-
pmt cmd
|
53
|
-
else
|
54
|
-
FileUtils.mkdir @basedir unless File.directory? @basedir
|
55
|
-
#logger.debug "Module #{@full_name} is not installed"
|
56
|
-
cmd = []
|
57
|
-
cmd << 'install'
|
58
|
-
cmd << "--version=#{@version.to_s.sub(/^v/,'')}" if @version
|
59
|
-
cmd << "--ignore-dependencies"
|
60
|
-
cmd << @full_name
|
61
|
-
pmt cmd
|
54
|
+
case status
|
55
|
+
when :absent
|
56
|
+
install
|
57
|
+
when :outdated
|
58
|
+
upgrade
|
59
|
+
when :mismatched
|
60
|
+
reinstall
|
62
61
|
end
|
63
62
|
end
|
64
63
|
|
65
|
-
# @return [R10K::SemVer
|
66
|
-
def
|
67
|
-
if
|
68
|
-
|
69
|
-
else
|
70
|
-
R10K::SemVer::MIN
|
64
|
+
# @return [R10K::SemVer] The expected version that the module
|
65
|
+
def expected_version
|
66
|
+
if @expected_version == :latest
|
67
|
+
set_version_from_forge
|
71
68
|
end
|
69
|
+
@expected_version
|
72
70
|
end
|
73
71
|
|
74
|
-
|
75
|
-
|
72
|
+
|
73
|
+
# @return [R10K::SemVer] The version of the currently installed module
|
74
|
+
def current_version
|
75
|
+
@metadata.version
|
76
76
|
end
|
77
77
|
|
78
|
-
|
79
|
-
|
78
|
+
alias version current_version
|
79
|
+
|
80
|
+
def exist?
|
81
|
+
@full_path.exist?
|
80
82
|
end
|
81
83
|
|
82
|
-
def
|
83
|
-
|
84
|
+
def insync?
|
85
|
+
status == :insync
|
86
|
+
end
|
87
|
+
|
88
|
+
# Determine the status of the forge module.
|
89
|
+
#
|
90
|
+
# @return [Symbol] :absent If the directory doesn't exist
|
91
|
+
# @return [Symbol] :mismatched If the module is not a forge module, or
|
92
|
+
# isn't the right forge module
|
93
|
+
# @return [Symbol] :outdated If the installed module is older than expected
|
94
|
+
# @return [Symbol] :insync If the module is in the desired state
|
95
|
+
def status
|
96
|
+
if not self.exist?
|
97
|
+
# The module is not installed
|
98
|
+
return :absent
|
99
|
+
elsif not @metadata.exist?
|
100
|
+
# The directory exists but doesn't have a metadata file; it probably
|
101
|
+
# isn't a forge module.
|
102
|
+
return :mismatched
|
103
|
+
end
|
104
|
+
|
105
|
+
# The module is present and has a metadata file, read the metadata to
|
106
|
+
# determine the state of the module.
|
107
|
+
@metadata.read
|
108
|
+
|
109
|
+
if not @author == @metadata.author
|
110
|
+
# This is a forge module but the installed module is a different author
|
111
|
+
# than the expected author.
|
112
|
+
return :mismatched
|
113
|
+
end
|
114
|
+
|
115
|
+
if expected_version && (expected_version != @metadata.version)
|
116
|
+
return :outdated
|
117
|
+
end
|
118
|
+
|
119
|
+
return :insync
|
84
120
|
end
|
85
121
|
|
86
122
|
private
|
87
123
|
|
88
|
-
def
|
89
|
-
|
90
|
-
|
91
|
-
|
124
|
+
def install
|
125
|
+
FileUtils.mkdir @basedir unless File.directory? @basedir
|
126
|
+
cmd = []
|
127
|
+
cmd << 'install'
|
128
|
+
cmd << "--version=#{expected_version}" if expected_version
|
129
|
+
cmd << "--ignore-dependencies"
|
130
|
+
cmd << @full_name
|
131
|
+
pmt cmd
|
132
|
+
end
|
92
133
|
|
93
|
-
|
134
|
+
def upgrade
|
135
|
+
cmd = []
|
136
|
+
cmd << 'upgrade'
|
137
|
+
cmd << "--version=#{expected_version}" if expected_version
|
138
|
+
cmd << "--ignore-dependencies"
|
139
|
+
cmd << @full_name
|
140
|
+
pmt cmd
|
141
|
+
end
|
94
142
|
|
95
|
-
|
96
|
-
|
143
|
+
def uninstall
|
144
|
+
FileUtils.rm_rf full_path
|
145
|
+
end
|
97
146
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
147
|
+
def reinstall
|
148
|
+
uninstall
|
149
|
+
install
|
150
|
+
end
|
151
|
+
|
152
|
+
# Wrap puppet module commands
|
153
|
+
#
|
154
|
+
# @param argv [Array<String>]
|
155
|
+
#
|
156
|
+
# @return [String] The stdout from the executed command
|
157
|
+
def pmt(argv)
|
158
|
+
argv = ['puppet', 'module', '--modulepath', @basedir] + argv
|
159
|
+
|
160
|
+
subproc = R10K::Util::Subprocess.new(argv)
|
161
|
+
subproc.raise_on_fail = true
|
162
|
+
subproc.logger = self.logger
|
163
|
+
|
164
|
+
result = subproc.execute
|
165
|
+
|
166
|
+
result.stdout
|
167
|
+
end
|
168
|
+
|
169
|
+
def set_version_from_forge
|
170
|
+
repo = R10K::ModuleRepository::Forge.new
|
171
|
+
expected = repo.latest_version(@full_name)
|
172
|
+
@expected_version = R10K::SemVer.new(expected)
|
106
173
|
end
|
107
174
|
end
|