r10k 1.1.4 → 1.2.0rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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/execution.rb
CHANGED
@@ -13,6 +13,7 @@ module Execution
|
|
13
13
|
# @params [Hash] opts
|
14
14
|
#
|
15
15
|
# @option opts [String] :event An optional log event name. Defaults to cmd.
|
16
|
+
# @option opts [String] :cwd The working directory to use when executing the command
|
16
17
|
#
|
17
18
|
# @raise [R10K::ExecutionFailure] If the executed command exited with a
|
18
19
|
# nonzero exit code.
|
@@ -20,11 +21,13 @@ module Execution
|
|
20
21
|
# @return [String] the stdout from the command
|
21
22
|
def execute(cmd, opts = {})
|
22
23
|
|
23
|
-
|
24
|
+
logger.warn "R10K::Execution#execute is deprecated, use R10K::Util::Subprocess"
|
25
|
+
|
26
|
+
event = (opts.delete(:event) || cmd)
|
24
27
|
|
25
28
|
logger.debug1 "Execute: #{event.inspect}"
|
26
29
|
|
27
|
-
status, stdout, stderr = systemu(cmd)
|
30
|
+
status, stdout, stderr = systemu(cmd, opts)
|
28
31
|
|
29
32
|
logger.debug2 "[#{event}] STDOUT: #{stdout.chomp}" unless stdout.empty?
|
30
33
|
logger.debug2 "[#{event}] STDERR: #{stderr.chomp}" unless stderr.empty?
|
data/lib/r10k/git/cache.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
require 'r10k/logging'
|
2
|
+
|
3
|
+
require 'r10k/git'
|
2
4
|
require 'r10k/git/repository'
|
3
5
|
|
4
6
|
require 'r10k/settings'
|
5
7
|
require 'r10k/registry'
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
#
|
12
|
-
# @see man git-clone(1)
|
9
|
+
# Mirror a git repository for use shared git object repositories
|
10
|
+
#
|
11
|
+
# @see man git-clone(1)
|
12
|
+
class R10K::Git::Cache < R10K::Git::Repository
|
13
13
|
|
14
14
|
include R10K::Settings::Mixin
|
15
15
|
|
@@ -25,28 +25,24 @@ class Cache < R10K::Git::Repository
|
|
25
25
|
|
26
26
|
include R10K::Logging
|
27
27
|
|
28
|
-
# @!attribute [r] remote
|
29
|
-
# @return [String] The git repository remote
|
30
|
-
attr_reader :remote
|
31
|
-
|
32
28
|
# @!attribute [r] path
|
29
|
+
# @deprecated
|
33
30
|
# @return [String] The path to the git cache repository
|
34
|
-
|
31
|
+
def path
|
32
|
+
logger.warn "#{self.class}#path is deprecated; use #git_dir"
|
33
|
+
@git_dir
|
34
|
+
end
|
35
35
|
|
36
36
|
# @param [String] remote
|
37
37
|
# @param [String] cache_root
|
38
38
|
def initialize(remote)
|
39
39
|
@remote = remote
|
40
40
|
|
41
|
-
@
|
41
|
+
@git_dir = File.join(settings[:cache_root], sanitized_dirname)
|
42
42
|
end
|
43
43
|
|
44
44
|
def sync
|
45
|
-
if @synced
|
46
|
-
# XXX This gets really spammy. Might be good to turn it on later, but for
|
47
|
-
# general work it's way much.
|
48
|
-
#logger.debug "#{@remote} already synced this run, not syncing again"
|
49
|
-
else
|
45
|
+
if not @synced
|
50
46
|
sync!
|
51
47
|
@synced = true
|
52
48
|
end
|
@@ -54,41 +50,35 @@ class Cache < R10K::Git::Repository
|
|
54
50
|
|
55
51
|
def sync!
|
56
52
|
if cached?
|
57
|
-
|
58
|
-
# general work it's way much.
|
59
|
-
#logger.debug "Updating existing cache at #{@path}"
|
60
|
-
git "fetch --prune", :git_dir => @path
|
53
|
+
fetch
|
61
54
|
else
|
62
55
|
logger.debug "Creating new git cache for #{@remote.inspect}"
|
63
56
|
|
57
|
+
# TODO extract this to an initialization step
|
64
58
|
unless File.exist? settings[:cache_root]
|
65
59
|
FileUtils.mkdir_p settings[:cache_root]
|
66
60
|
end
|
67
61
|
|
68
|
-
git
|
62
|
+
git ['clone', '--mirror', @remote, git_dir]
|
63
|
+
end
|
64
|
+
rescue R10K::Util::Subprocess::SubprocessError => e
|
65
|
+
msg = e.result.stderr.slice(/^fatal: .*$/)
|
66
|
+
if msg
|
67
|
+
raise R10K::Git::GitError, "Couldn't update git cache for #{@remote}: #{msg.inspect}"
|
68
|
+
else
|
69
|
+
raise e
|
69
70
|
end
|
70
71
|
end
|
71
72
|
|
72
73
|
# @return [Array<String>] A list the branches for the git repository
|
73
74
|
def branches
|
74
|
-
output = git
|
75
|
-
output.
|
76
|
-
# the `git branch` command returns output like this:
|
77
|
-
# <pre>
|
78
|
-
# 0.11.x
|
79
|
-
# 0.12.x
|
80
|
-
# * master
|
81
|
-
# passenger_scoping
|
82
|
-
# </pre>
|
83
|
-
#
|
84
|
-
# The string index notation strips off the leading whitespace/asterisk
|
85
|
-
str[2..-1]
|
86
|
-
end
|
75
|
+
output = git %w[for-each-ref refs/heads --format %(refname)], :git_dir => git_dir
|
76
|
+
output.scan(%r[refs/heads/(.*)$]).flatten
|
87
77
|
end
|
88
78
|
|
89
79
|
# @return [true, false] If the repository has been locally cached
|
90
80
|
def cached?
|
91
|
-
File.exist?
|
81
|
+
File.exist? git_dir
|
92
82
|
end
|
93
83
|
|
94
84
|
private
|
@@ -97,10 +87,4 @@ class Cache < R10K::Git::Repository
|
|
97
87
|
def sanitized_dirname
|
98
88
|
@remote.gsub(/[^@\w\.-]/, '-')
|
99
89
|
end
|
100
|
-
|
101
|
-
def git_dir
|
102
|
-
@path
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
90
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'r10k/git/ref'
|
2
|
+
require 'r10k/git/repository'
|
3
|
+
|
4
|
+
# commit: A 40-byte hex representation of a SHA1 referencing a specific commit
|
5
|
+
# @see https://www.kernel.org/pub/software/scm/git/docs/gitglossary.html
|
6
|
+
# @api private
|
7
|
+
class R10K::Git::Commit < R10K::Git::Ref
|
8
|
+
|
9
|
+
# @!attribute [r] commit
|
10
|
+
# @return [String] The git commit
|
11
|
+
attr_reader :commit
|
12
|
+
alias :ref :commit
|
13
|
+
|
14
|
+
def initialize(commit, repository = nil)
|
15
|
+
@commit = commit
|
16
|
+
@repository = repository
|
17
|
+
end
|
18
|
+
|
19
|
+
def fetch?
|
20
|
+
! resolvable?
|
21
|
+
end
|
22
|
+
end
|
data/lib/r10k/git/errors.rb
CHANGED
@@ -1,34 +1,43 @@
|
|
1
|
+
require 'r10k/errors'
|
2
|
+
|
1
3
|
module R10K
|
2
|
-
module Git
|
3
|
-
class NonexistentHashError < StandardError
|
4
|
-
# Raised when a hash was requested that can't be found in the repository
|
4
|
+
module Git
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
class GitError < R10KError
|
7
|
+
end
|
8
8
|
|
9
|
-
|
10
|
-
super(msg)
|
9
|
+
class UnresolvableRefError < GitError
|
11
10
|
|
12
|
-
|
13
|
-
|
11
|
+
attr_reader :ref
|
12
|
+
attr_reader :git_dir
|
14
13
|
|
15
|
-
|
14
|
+
def initialize(*args)
|
15
|
+
super
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
msg = super
|
20
|
-
if msg and msg.match(HASHLIKE)
|
21
|
-
msg = "Could not locate hash #{msg.inspect} in repository"
|
22
|
-
elsif msg.nil?
|
23
|
-
msg = "Could not locate hash in repository"
|
17
|
+
@hash = @options[:ref]
|
18
|
+
@git_dir = @options[:git_dir]
|
24
19
|
end
|
25
20
|
|
26
|
-
|
27
|
-
|
28
|
-
|
21
|
+
HASHLIKE = %r[[A-Fa-f0-9]]
|
22
|
+
|
23
|
+
# Print a friendly error message if an object hash is given as the message
|
24
|
+
def message
|
25
|
+
if @mesg
|
26
|
+
msg = @mesg
|
27
|
+
else
|
28
|
+
msg = "Could not locate hash"
|
29
29
|
|
30
|
-
|
30
|
+
if @hash
|
31
|
+
msg << " '#{@hash}'"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
if @git_dir
|
36
|
+
msg << " at #{@git_dir}"
|
37
|
+
end
|
38
|
+
|
39
|
+
msg
|
40
|
+
end
|
31
41
|
end
|
32
42
|
end
|
33
43
|
end
|
34
|
-
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'r10k/git'
|
2
|
+
require 'r10k/git/ref'
|
3
|
+
require 'r10k/git/repository'
|
4
|
+
|
5
|
+
|
6
|
+
# head: A named reference to the commit at the tip of a branch. Heads are
|
7
|
+
# stored in a file in $GIT_DIR/refs/heads/ directory. except when using packed
|
8
|
+
#
|
9
|
+
# @see https://www.kernel.org/pub/software/scm/git/docs/gitglossary.html
|
10
|
+
# @api private
|
11
|
+
class R10K::Git::Head < R10K::Git::Ref
|
12
|
+
|
13
|
+
# @!attribute [r] head
|
14
|
+
# @return [String] The git head
|
15
|
+
attr_reader :head
|
16
|
+
alias :ref :head
|
17
|
+
|
18
|
+
def initialize(head, repository = nil)
|
19
|
+
@head = head
|
20
|
+
@repository = repository
|
21
|
+
end
|
22
|
+
|
23
|
+
# def sha1
|
24
|
+
# TODO ensure that @head is an actual head as opposed to a tag or other
|
25
|
+
# hooliganism.
|
26
|
+
#end
|
27
|
+
|
28
|
+
# If we are tracking a branch, we should always try to fetch a newer version
|
29
|
+
# of that branch.
|
30
|
+
def fetch?
|
31
|
+
true
|
32
|
+
end
|
33
|
+
end
|
data/lib/r10k/git/ref.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'r10k/git'
|
2
|
+
require 'r10k/git/repository'
|
3
|
+
|
4
|
+
# ref: A 40-byte hex representation of a SHA1 or a name that denotes a
|
5
|
+
# particular object. They may be stored in a file under $GIT_DIR/refs/
|
6
|
+
# directory, or in the $GIT_DIR/packed-refs file.
|
7
|
+
#
|
8
|
+
# @see https://www.kernel.org/pub/software/scm/git/docs/gitglossary.html
|
9
|
+
# @api private
|
10
|
+
class R10K::Git::Ref
|
11
|
+
|
12
|
+
# @!attribute [r] ref
|
13
|
+
# @return [String] The git reference
|
14
|
+
attr_reader :ref
|
15
|
+
|
16
|
+
# @!attribute [rw] repository
|
17
|
+
# @return [R10K::Git::Repository] A git repository that can be used to
|
18
|
+
# resolve the git reference to a commit.
|
19
|
+
attr_accessor :repository
|
20
|
+
|
21
|
+
def initialize(ref, repository = nil)
|
22
|
+
@ref = ref
|
23
|
+
@repository = repository
|
24
|
+
end
|
25
|
+
|
26
|
+
# Can we locate the commit in the related repository?
|
27
|
+
def resolvable?
|
28
|
+
sha1
|
29
|
+
true
|
30
|
+
rescue R10K::Git::UnresolvableRefError
|
31
|
+
false
|
32
|
+
end
|
33
|
+
|
34
|
+
# Should we try to fetch this ref?
|
35
|
+
#
|
36
|
+
# Since we don't know the type of this ref, we have to assume that it might
|
37
|
+
# be a branch and always update accordingly.
|
38
|
+
def fetch?
|
39
|
+
true
|
40
|
+
end
|
41
|
+
|
42
|
+
def sha1
|
43
|
+
if @repository.nil?
|
44
|
+
raise ArgumentError, "Cannot resolve #{self.inspect}: no associated git repository"
|
45
|
+
else
|
46
|
+
@repository.rev_parse(ref)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def ==(other)
|
51
|
+
other.sha1 == self.sha1
|
52
|
+
rescue ArgumentError, R10K::Git::UnresolvableRefError
|
53
|
+
false
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_s
|
57
|
+
ref
|
58
|
+
end
|
59
|
+
|
60
|
+
def inspect
|
61
|
+
"#<#{self.class}: #{to_s}>"
|
62
|
+
end
|
63
|
+
end
|
data/lib/r10k/git/repository.rb
CHANGED
@@ -1,74 +1,103 @@
|
|
1
|
-
require 'r10k/
|
2
|
-
require 'r10k/
|
1
|
+
require 'r10k/git'
|
2
|
+
require 'r10k/util/subprocess'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
class Repository
|
7
|
-
# Define an abstract base class for git repositories.
|
8
|
-
|
9
|
-
include R10K::Execution
|
4
|
+
# Define an abstract base class for git repositories.
|
5
|
+
class R10K::Git::Repository
|
10
6
|
|
11
7
|
# @!attribute [r] remote
|
12
8
|
# @return [String] The URL to the git repository
|
13
9
|
attr_reader :remote
|
14
10
|
|
15
11
|
# @!attribute [r] basedir
|
16
|
-
# @return [String] The
|
12
|
+
# @return [String] The directory containing the repository
|
17
13
|
attr_reader :basedir
|
18
14
|
|
19
15
|
# @!attribute [r] dirname
|
20
|
-
# @return [String] The name
|
16
|
+
# @return [String] The name of the directory
|
21
17
|
attr_reader :dirname
|
22
18
|
|
23
|
-
#
|
19
|
+
# @!attribute [r] git_dir
|
20
|
+
# Set the path to the git directory. For git repositories with working copies
|
21
|
+
# this will be `$working_dir/.git`; for bare repositories this will be
|
22
|
+
# `bare-repo.git`
|
23
|
+
# @return [String] The path to the git directory
|
24
|
+
attr_reader :git_dir
|
25
|
+
|
26
|
+
# Resolve a ref to a git commit. The given pattern can be a commit, tag,
|
27
|
+
# or a local or remote branch
|
28
|
+
#
|
29
|
+
# @param [String] pattern
|
24
30
|
#
|
25
|
-
# @
|
31
|
+
# @return [String] The dereferenced hash of `pattern`
|
32
|
+
def resolve_ref(pattern)
|
33
|
+
commit = nil
|
34
|
+
begin
|
35
|
+
all_commits = git ['show-ref', '-s', pattern], :git_dir => git_dir
|
36
|
+
commit = all_commits.lines.first
|
37
|
+
rescue R10K::Util::Subprocess::SubprocessError
|
38
|
+
end
|
39
|
+
|
40
|
+
if commit.nil?
|
41
|
+
begin
|
42
|
+
commit = git ['rev-parse', "#{ref}^{commit}"], :git_dir => git_dir
|
43
|
+
rescue R10K::Util::Subprocess::SubprocessError
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
if commit
|
48
|
+
commit.chomp
|
49
|
+
else
|
50
|
+
raise R10K::Git::UnresolvableRefError.new(:ref => pattern, :git_dir => git_dir)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
alias rev_parse resolve_ref
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# Fetch objects and refs from the given git remote
|
26
58
|
#
|
27
|
-
# @
|
28
|
-
def
|
29
|
-
|
30
|
-
commit.chomp
|
31
|
-
rescue R10K::ExecutionFailure
|
32
|
-
raise R10K::Git::NonexistentHashError.new(ref, git_dir)
|
59
|
+
# @param remote [#to_s] The remote name to fetch from
|
60
|
+
def fetch(remote = 'origin')
|
61
|
+
git ['fetch', '--prune', remote], :git_dir => @git_dir
|
33
62
|
end
|
34
63
|
|
35
64
|
# Wrap git commands
|
36
65
|
#
|
37
|
-
# @param [String]
|
38
|
-
# @param [Hash] opts
|
66
|
+
# @param cmd [Array<String>] cmd The arguments for the git prompt
|
67
|
+
# @param opts [Hash] opts
|
39
68
|
#
|
69
|
+
# @option opts [String] :path
|
40
70
|
# @option opts [String] :git_dir
|
41
71
|
# @option opts [String] :work_tree
|
42
|
-
# @option opts [String] :work_tree
|
43
72
|
#
|
44
73
|
# @raise [R10K::ExecutionFailure] If the executed command exited with a
|
45
74
|
# nonzero exit code.
|
46
75
|
#
|
47
76
|
# @return [String] The git command output
|
48
|
-
def git(
|
49
|
-
|
50
|
-
|
51
|
-
log_event = "git #{command_line_args}"
|
52
|
-
log_event << ", args: #{opts.inspect}" unless opts.empty?
|
53
|
-
|
77
|
+
def git(cmd, opts = {})
|
78
|
+
argv = %w{git}
|
54
79
|
|
55
80
|
if opts[:path]
|
56
|
-
|
57
|
-
|
81
|
+
argv << "--git-dir" << File.join(opts[:path], '.git')
|
82
|
+
argv << "--work-tree" << opts[:path]
|
58
83
|
else
|
59
84
|
if opts[:git_dir]
|
60
|
-
|
85
|
+
argv << "--git-dir" << opts[:git_dir]
|
61
86
|
end
|
62
87
|
if opts[:work_tree]
|
63
|
-
|
88
|
+
argv << "--work-tree" << opts[:work_tree]
|
64
89
|
end
|
65
90
|
end
|
66
91
|
|
67
|
-
|
68
|
-
|
92
|
+
argv.concat(cmd)
|
93
|
+
|
94
|
+
subproc = R10K::Util::Subprocess.new(argv)
|
95
|
+
subproc.raise_on_fail = true
|
96
|
+
subproc.logger = self.logger
|
97
|
+
|
98
|
+
result = subproc.execute
|
69
99
|
|
70
|
-
|
100
|
+
# todo ensure that logging always occurs even if the command fails to run
|
101
|
+
result.stdout
|
71
102
|
end
|
72
103
|
end
|
73
|
-
end
|
74
|
-
end
|