puppet-armature 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +6 -5
- data/TODO.md +0 -8
- data/bin/armature +21 -6
- data/lib/armature.rb +12 -4
- data/lib/armature/cache.rb +98 -73
- data/lib/armature/environments.rb +53 -20
- data/lib/armature/errors.rb +7 -0
- data/lib/armature/puppetfile.rb +41 -17
- data/lib/armature/ref/base.rb +21 -0
- data/lib/armature/ref/identity.rb +5 -0
- data/lib/armature/ref/immutable.rb +5 -0
- data/lib/armature/ref/mutable.rb +5 -0
- data/lib/armature/repo.rb +56 -0
- data/lib/armature/repo/forge.rb +154 -0
- data/lib/armature/repo/git.rb +228 -0
- data/lib/armature/run.rb +44 -13
- data/lib/armature/util.rb +51 -2
- data/lib/armature/version.rb +2 -1
- data/puppet-armature.gemspec +1 -1
- data/test/deploy_test.rb +39 -39
- data/test/helpers.rb +27 -25
- data/test/puppetfile_test.rb +41 -0
- metadata +12 -4
- data/lib/armature/gitrepo.rb +0 -139
data/lib/armature/puppetfile.rb
CHANGED
@@ -2,26 +2,52 @@ module Armature
|
|
2
2
|
class Puppetfile
|
3
3
|
attr_reader :results
|
4
4
|
|
5
|
-
def initialize()
|
5
|
+
def initialize(cache)
|
6
|
+
@cache = cache
|
6
7
|
@results = {}
|
8
|
+
@logger = Logging.logger[self]
|
9
|
+
@forge_url = "https://forge.puppet.com"
|
7
10
|
end
|
8
11
|
|
12
|
+
### FIXME this will have access to @cache and @results
|
9
13
|
def include(path)
|
10
14
|
instance_eval(IO.read(path), path)
|
11
15
|
@results
|
12
16
|
end
|
13
17
|
|
14
|
-
def
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
def forge(url)
|
19
|
+
@forge_url = url.chomp("/")
|
20
|
+
end
|
21
|
+
|
22
|
+
def mod(full_name, options={})
|
23
|
+
name = full_name.split("-", 2).last()
|
24
|
+
Armature::Environments.assert_valid_module_name(name)
|
20
25
|
|
21
26
|
if @results[name]
|
22
27
|
raise "Module #{name} declared twice"
|
23
28
|
end
|
24
29
|
|
30
|
+
if options.is_a?(String) || options == {} || options == nil
|
31
|
+
_mod_forge(full_name, name, options)
|
32
|
+
elsif options[:git]
|
33
|
+
_mod_git(name, options)
|
34
|
+
else
|
35
|
+
raise "Invalid mod call: #{full_name} #{options}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def _mod_forge(full_name, name, version="latest")
|
40
|
+
if version == nil || version == {}
|
41
|
+
version = "latest"
|
42
|
+
end
|
43
|
+
|
44
|
+
repo = Repo::Forge.from_url(@cache, @forge_url, full_name)
|
45
|
+
ref = repo.general_ref(version)
|
46
|
+
@logger.debug("mod #{name}: #{ref}")
|
47
|
+
@results[name] = { :name => name, :ref => ref }
|
48
|
+
end
|
49
|
+
|
50
|
+
def _mod_git(name, options={})
|
25
51
|
options = Armature::Util.process_options(options, {
|
26
52
|
:commit => nil,
|
27
53
|
:tag => nil,
|
@@ -31,45 +57,43 @@ module Armature
|
|
31
57
|
:git => nil,
|
32
58
|
})
|
33
59
|
|
60
|
+
repo = Repo::Git.from_url(@cache, options[:git])
|
34
61
|
ref = nil
|
35
62
|
|
36
63
|
if options[:commit]
|
37
64
|
if ref
|
38
65
|
raise "Module #{name} has more than one of :commit, :tag, :branch, or :ref"
|
39
66
|
end
|
40
|
-
ref = options[:commit]
|
67
|
+
ref = repo.identity_ref(options[:commit])
|
41
68
|
end
|
42
69
|
|
43
70
|
if options[:tag]
|
44
71
|
if ref
|
45
72
|
raise "Module #{name} has more than one of :commit, :tag, :branch, or :ref"
|
46
73
|
end
|
47
|
-
ref =
|
74
|
+
ref = repo.tag_ref(options[:tag])
|
48
75
|
end
|
49
76
|
|
50
77
|
if options[:branch]
|
51
78
|
if ref
|
52
79
|
raise "Module #{name} has more than one of :commit, :tag, :branch, or :ref"
|
53
80
|
end
|
54
|
-
ref =
|
81
|
+
ref = repo.branch_ref(options[:branch])
|
55
82
|
end
|
56
83
|
|
57
84
|
if options[:ref]
|
58
85
|
if ref
|
59
86
|
raise "Module #{name} has more than one of :commit, :tag, :branch, or :ref"
|
60
87
|
end
|
61
|
-
ref = options[:ref]
|
88
|
+
ref = repo.general_ref(options[:ref])
|
62
89
|
end
|
63
90
|
|
64
91
|
if ! ref
|
65
|
-
ref = "
|
92
|
+
ref = repo.branch_ref("master")
|
66
93
|
end
|
67
94
|
|
68
|
-
@
|
69
|
-
|
70
|
-
|
71
|
-
def forge(*arguments)
|
72
|
-
### error?
|
95
|
+
@logger.debug("mod #{name}: #{ref}")
|
96
|
+
@results[name] = { :name => name, :ref => ref }
|
73
97
|
end
|
74
98
|
end
|
75
99
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Armature::Ref
|
2
|
+
class Base
|
3
|
+
attr_reader :repo, :canonical_name, :identity, :human_type, :human_name
|
4
|
+
|
5
|
+
def initialize(repo, canonical_name, identity, human_type, human_name)
|
6
|
+
@repo = repo
|
7
|
+
@canonical_name = canonical_name
|
8
|
+
@identity = identity
|
9
|
+
@human_type = human_type
|
10
|
+
@human_name = human_name
|
11
|
+
end
|
12
|
+
|
13
|
+
def check_out
|
14
|
+
@repo.check_out(self)
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
"#{@human_type} \"#{@human_name}\""
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
class Armature::Repo
|
2
|
+
def self.from_path(cache, path)
|
3
|
+
# Called from the cache; don't check for an existing repo
|
4
|
+
self.new(cache, path)
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize(cache, repo_dir)
|
8
|
+
@cache = cache
|
9
|
+
@repo_dir = repo_dir
|
10
|
+
@logger = Logging.logger[self]
|
11
|
+
@url = nil
|
12
|
+
flush_memory!
|
13
|
+
|
14
|
+
@cache.register_repo(self)
|
15
|
+
end
|
16
|
+
|
17
|
+
# You may wish to override these methods
|
18
|
+
|
19
|
+
def url
|
20
|
+
@url
|
21
|
+
end
|
22
|
+
|
23
|
+
def check_out(ref)
|
24
|
+
end
|
25
|
+
|
26
|
+
def freshen!
|
27
|
+
flush_memory!
|
28
|
+
end
|
29
|
+
|
30
|
+
def flush_memory!
|
31
|
+
@fresh = false
|
32
|
+
end
|
33
|
+
|
34
|
+
# Generally these don't need to be overridden
|
35
|
+
|
36
|
+
def self.type
|
37
|
+
self.name.split('::').last().downcase()
|
38
|
+
end
|
39
|
+
|
40
|
+
def type
|
41
|
+
self.class.type()
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
url()
|
46
|
+
end
|
47
|
+
|
48
|
+
def freshen
|
49
|
+
if ! @fresh
|
50
|
+
freshen!
|
51
|
+
true
|
52
|
+
else
|
53
|
+
false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# Get a module from the Forge
|
2
|
+
class Armature::Repo::Forge < Armature::Repo
|
3
|
+
CANONICAL_FORGE_URL = "https://forge.puppet.com"
|
4
|
+
FORGE_URLS = [
|
5
|
+
"https://forge.puppetlabs.com",
|
6
|
+
"https://forgeapi.puppetlabs.com",
|
7
|
+
"https://forgeapi.puppet.com",
|
8
|
+
"http://forge.puppetlabs.com",
|
9
|
+
"http://forgeapi.puppetlabs.com",
|
10
|
+
"http://forge.puppet.com",
|
11
|
+
"http://forgeapi.puppet.com",
|
12
|
+
]
|
13
|
+
|
14
|
+
def self.normalize_forge_url(url)
|
15
|
+
url.chomp!("/")
|
16
|
+
if FORGE_URLS.include? url
|
17
|
+
CANONICAL_FORGE_URL
|
18
|
+
else
|
19
|
+
url
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Gets a repo object for a given Forge module. This just contains metadata.
|
24
|
+
def self.from_url(cache, forge_url, full_name)
|
25
|
+
forge_url = self.normalize_forge_url(forge_url)
|
26
|
+
|
27
|
+
url = "#{forge_url}/#{full_name}"
|
28
|
+
repo = cache.get_repo("forge", url)
|
29
|
+
if repo
|
30
|
+
return repo
|
31
|
+
end
|
32
|
+
|
33
|
+
repo_dir = cache.open_repo("forge", url) do |temp_path|
|
34
|
+
File.write("#{temp_path}/url", "#{url}\n")
|
35
|
+
File.write("#{temp_path}/forge_url", "#{forge_url}\n")
|
36
|
+
File.write("#{temp_path}/full_name", "#{full_name}\n")
|
37
|
+
|
38
|
+
Logging.logger[self].debug("Created stub repo for '#{url}'")
|
39
|
+
end
|
40
|
+
|
41
|
+
return self.new(cache, repo_dir)
|
42
|
+
end
|
43
|
+
|
44
|
+
def url
|
45
|
+
@url || File.read("#{@repo_dir}/url").chomp()
|
46
|
+
end
|
47
|
+
|
48
|
+
def forge_url
|
49
|
+
@forge_url || File.read("#{@repo_dir}/forge_url").chomp()
|
50
|
+
end
|
51
|
+
|
52
|
+
def full_name
|
53
|
+
@full_name || File.read("#{@repo_dir}/full_name").chomp()
|
54
|
+
end
|
55
|
+
|
56
|
+
# Ensure we've got the correct version and return its path
|
57
|
+
def check_out(ref)
|
58
|
+
@cache.open_ref(ref) do |object_path|
|
59
|
+
@cache.open_temp() do
|
60
|
+
@logger.debug("Downloading #{ref} from #{url}")
|
61
|
+
url = forge_url() + release_metadata(ref.identity, "file_uri")
|
62
|
+
|
63
|
+
tarball = Armature::Util::http_get(url)
|
64
|
+
|
65
|
+
# This extracts into a temp directory
|
66
|
+
Armature::Run::pipe_command(tarball, "tar", "xzf" , "-")
|
67
|
+
|
68
|
+
# Move everything into the object directory
|
69
|
+
extract_dir = Dir["*"].first()
|
70
|
+
Dir.entries(extract_dir).each do |child|
|
71
|
+
if ! [".", ".."].include?(child)
|
72
|
+
File.rename("#{extract_dir}/#{child}", "#{object_path}/#{child}")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def freshen!
|
80
|
+
flush_memory!
|
81
|
+
download_metadata()
|
82
|
+
end
|
83
|
+
|
84
|
+
def flush_memory!
|
85
|
+
@fresh = false
|
86
|
+
@metadata = nil
|
87
|
+
end
|
88
|
+
|
89
|
+
# Get ref object
|
90
|
+
def general_ref(version)
|
91
|
+
if version.nil? || version == "latest"
|
92
|
+
latest_ref()
|
93
|
+
else
|
94
|
+
version_ref(version)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def version_ref(version)
|
99
|
+
Armature::Ref::Immutable.new(self, version, version, "version", version)
|
100
|
+
end
|
101
|
+
|
102
|
+
def latest_ref
|
103
|
+
freshen()
|
104
|
+
version = metadata("current_release.version")
|
105
|
+
|
106
|
+
Armature::Ref::Mutable.new(self, "latest", version, "version", "latest")
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def metadata(path=nil)
|
112
|
+
### FIXME cache metadata in repo
|
113
|
+
@metadata ||= download_metadata()
|
114
|
+
return @metadata if path == nil
|
115
|
+
|
116
|
+
begin
|
117
|
+
dig(@metadata, path.split("."))
|
118
|
+
rescue => e
|
119
|
+
raise "Got invalid metadata from #{metadata_url()}: #{e}"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def release_metadata(version, path=nil)
|
124
|
+
metadata("releases").each do |release|
|
125
|
+
begin
|
126
|
+
if release["version"] == version
|
127
|
+
return dig(release, path.split("."))
|
128
|
+
end
|
129
|
+
rescue => e
|
130
|
+
raise "Got invalid metadata from #{metadata_url()}: #{e}"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
raise "Release #{version} not found"
|
135
|
+
end
|
136
|
+
|
137
|
+
def metadata_url
|
138
|
+
[forge_url(), "v3", "modules", full_name()].join("/")
|
139
|
+
end
|
140
|
+
|
141
|
+
def download_metadata
|
142
|
+
@fresh = true
|
143
|
+
@metadata = Armature::Util::http_get_json(metadata_url())
|
144
|
+
end
|
145
|
+
|
146
|
+
def dig(parent, path)
|
147
|
+
key = path.shift()
|
148
|
+
if path.length() == 0
|
149
|
+
parent[key]
|
150
|
+
else
|
151
|
+
dig(parent[key], path)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,228 @@
|
|
1
|
+
class Armature::Repo::Git < Armature::Repo
|
2
|
+
# Gets a repo object for a given URL. Mirrors the repo in the local cache
|
3
|
+
# if it doesn't already exist.
|
4
|
+
def self.from_url(cache, url)
|
5
|
+
repo = cache.get_repo("git", url)
|
6
|
+
if repo
|
7
|
+
return repo
|
8
|
+
end
|
9
|
+
|
10
|
+
fresh = false
|
11
|
+
repo_dir = cache.open_repo("git", url) do |temp_path|
|
12
|
+
Logging.logger[self].debug("Cloning '#{url}' for the first time")
|
13
|
+
|
14
|
+
# Mirror copies *all* refs, not just branches. Ignore output.
|
15
|
+
Armature::Run.clean_git("clone", "--quiet", "--mirror", url, temp_path)
|
16
|
+
fresh = true
|
17
|
+
|
18
|
+
Logging.logger[self].debug("Done cloning '#{url}'")
|
19
|
+
end
|
20
|
+
|
21
|
+
return self.new(cache, repo_dir, fresh)
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(cache, repo_dir, is_fresh=false)
|
25
|
+
super(cache, repo_dir)
|
26
|
+
@fresh = is_fresh
|
27
|
+
end
|
28
|
+
|
29
|
+
def url
|
30
|
+
@url ||= git("config", "--get", "remote.origin.url").chomp()
|
31
|
+
end
|
32
|
+
|
33
|
+
# Check out a ref from a repo and return the path
|
34
|
+
def check_out(ref)
|
35
|
+
@cache.open_ref(ref) do |object_path|
|
36
|
+
git "reset", "--hard", ref.identity, :work_dir=>object_path
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def freshen!
|
41
|
+
flush_memory!
|
42
|
+
|
43
|
+
@logger.info("Fetching from #{url}")
|
44
|
+
Armature::Util::lock(@repo_dir, File::LOCK_EX, "fetch") do
|
45
|
+
### FIXME Only flush memory if this makes changes
|
46
|
+
git "remote", "update", "--prune"
|
47
|
+
end
|
48
|
+
@fresh = true
|
49
|
+
end
|
50
|
+
|
51
|
+
def flush_memory!
|
52
|
+
@fresh = false
|
53
|
+
@ref_cache = {}
|
54
|
+
@rev_cache = {}
|
55
|
+
end
|
56
|
+
|
57
|
+
# Get ref object
|
58
|
+
def general_ref(ref_str)
|
59
|
+
return @ref_cache[ref_str] if @ref_cache[ref_str]
|
60
|
+
|
61
|
+
if ref_str.start_with? "refs/heads/"
|
62
|
+
return branch_ref(ref_str.sub("refs/heads/", ""))
|
63
|
+
end
|
64
|
+
|
65
|
+
if ref_str.start_with? "refs/tags/"
|
66
|
+
return tag_ref(ref_str.sub("refs/tags/", ""))
|
67
|
+
end
|
68
|
+
|
69
|
+
retry_fresh do
|
70
|
+
if ref_str.start_with? "refs/"
|
71
|
+
freshen()
|
72
|
+
return make_ref(Armature::Ref::Mutable, ref_str, rev_parse!(ref_str),
|
73
|
+
"ref", ref_str)
|
74
|
+
end
|
75
|
+
|
76
|
+
if sha = rev_parse("refs/heads/#{ref_str}")
|
77
|
+
return branch_ref(ref_str)
|
78
|
+
end
|
79
|
+
|
80
|
+
if sha = rev_parse("refs/tags/#{ref_str}")
|
81
|
+
return tag_ref(ref_str)
|
82
|
+
end
|
83
|
+
|
84
|
+
# This could trigger a retry
|
85
|
+
sha = rev_parse!(ref_str)
|
86
|
+
if sha_match? sha, ref_str
|
87
|
+
return identity_ref(sha)
|
88
|
+
end
|
89
|
+
|
90
|
+
# It exists, but it's outside of refs/. Treat it as mutable.
|
91
|
+
make_ref(Armature::Ref::Mutable, ref_str, sha, "ref", ref_str)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Get ref object for some sort of mutable ref we found in the FS cache
|
96
|
+
def mutable_fs_ref(ref_str)
|
97
|
+
freshen()
|
98
|
+
|
99
|
+
return @ref_cache[ref_str] if @ref_cache[ref_str]
|
100
|
+
|
101
|
+
if ref_str.start_with? "refs/heads/"
|
102
|
+
return branch_ref(ref_str.sub("refs/heads/", ""))
|
103
|
+
end
|
104
|
+
|
105
|
+
if ref_str.start_with? "refs/tags/"
|
106
|
+
return tag_ref(ref_str.sub("refs/tags/", ""))
|
107
|
+
end
|
108
|
+
|
109
|
+
make_ref(Armature::Ref::Mutable, ref_str, rev_parse!(ref_str), "ref", ref_str)
|
110
|
+
end
|
111
|
+
|
112
|
+
# The identity of an object itself, i.e. a SHA
|
113
|
+
def identity_ref(sha)
|
114
|
+
return @ref_cache[sha] if @ref_cache[sha]
|
115
|
+
|
116
|
+
real_sha = nil # needs to be bound to this scope
|
117
|
+
retry_fresh do
|
118
|
+
# real_sha will always be a full SHA, but sha might be partial
|
119
|
+
real_sha = rev_parse!(sha)
|
120
|
+
if ! sha_match? real_sha, sha
|
121
|
+
raise Armature::RefError, "'#{sha}' is not a Git SHA"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
make_ref(Armature::Ref::Identity, real_sha, real_sha, "revision", real_sha)
|
126
|
+
|
127
|
+
# If sha is partial, register it in the cache too.
|
128
|
+
@ref_cache[sha] = @ref_cache[real_sha]
|
129
|
+
end
|
130
|
+
|
131
|
+
def branch_ref(name)
|
132
|
+
ref_str = "refs/heads/#{name}"
|
133
|
+
freshen()
|
134
|
+
|
135
|
+
return @ref_cache[ref_str] if @ref_cache[ref_str]
|
136
|
+
|
137
|
+
sha = rev_parse!(ref_str)
|
138
|
+
_branch_ref(ref_str, name, sha)
|
139
|
+
end
|
140
|
+
|
141
|
+
def _branch_ref(ref_str, name, sha)
|
142
|
+
make_ref(Armature::Ref::Mutable, ref_str, sha, "branch", name)
|
143
|
+
@ref_cache[name] = @ref_cache[ref_str]
|
144
|
+
end
|
145
|
+
|
146
|
+
def tag_ref(name)
|
147
|
+
ref_str = "refs/tags/#{name}"
|
148
|
+
return @ref_cache[ref_str] if @ref_cache[ref_str]
|
149
|
+
|
150
|
+
sha = retry_fresh { rev_parse!(ref_str) }
|
151
|
+
make_ref(Armature::Ref::Immutable, ref_str, sha, "tag", name)
|
152
|
+
@ref_cache[name] = @ref_cache[ref_str]
|
153
|
+
end
|
154
|
+
|
155
|
+
def git(*arguments)
|
156
|
+
# This accepts a hash of options as the last argument
|
157
|
+
options = if arguments.last.is_a? Hash then arguments.pop else {} end
|
158
|
+
options = Armature::Util.process_options(options, { :work_dir => nil }, {})
|
159
|
+
|
160
|
+
if options[:work_dir]
|
161
|
+
work_dir_arguments = [ "--work-tree=" + options[:work_dir] ]
|
162
|
+
else
|
163
|
+
work_dir_arguments = []
|
164
|
+
end
|
165
|
+
|
166
|
+
command = [ "--git-dir=#{@repo_dir}" ] \
|
167
|
+
+ work_dir_arguments \
|
168
|
+
+ arguments
|
169
|
+
|
170
|
+
Armature::Run.clean_git(*command)
|
171
|
+
end
|
172
|
+
|
173
|
+
def get_branches()
|
174
|
+
freshen()
|
175
|
+
data = git("for-each-ref",
|
176
|
+
"--format", "%(objectname) %(refname)",
|
177
|
+
"refs/heads")
|
178
|
+
lines = data.split(/[\r\n]/).reject { |line| line == "" }
|
179
|
+
|
180
|
+
lines.map do |line|
|
181
|
+
sha, ref_str = line.split(' ', 2)
|
182
|
+
name = ref_str.sub("refs/heads/", "")
|
183
|
+
_branch_ref(ref_str, name, sha)
|
184
|
+
name
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
private
|
189
|
+
|
190
|
+
def retry_fresh
|
191
|
+
yield
|
192
|
+
rescue Armature::RefError
|
193
|
+
if @fresh
|
194
|
+
raise
|
195
|
+
end
|
196
|
+
|
197
|
+
@logger.debug("Got ref error; fetching to see if that helps.")
|
198
|
+
freshen()
|
199
|
+
yield
|
200
|
+
end
|
201
|
+
|
202
|
+
def make_ref(klass, ref_str, sha, type, name)
|
203
|
+
@ref_cache[ref_str] = klass.new(self, ref_str, sha, type, name)
|
204
|
+
end
|
205
|
+
|
206
|
+
# Get the SHA for a ref, or nil if it doesn't exist
|
207
|
+
def rev_parse(ref_str)
|
208
|
+
rev_parse!(ref_str)
|
209
|
+
rescue Armature::RefError
|
210
|
+
nil
|
211
|
+
end
|
212
|
+
|
213
|
+
# Get the SHA for a ref, or raise if it doesn't exist
|
214
|
+
def rev_parse!(ref_str)
|
215
|
+
if @rev_cache[ref_str]
|
216
|
+
@rev_cache[ref_str]
|
217
|
+
end
|
218
|
+
|
219
|
+
@rev_cache[ref_str] = git("rev-parse", "--verify", "#{ref_str}^{commit}").chomp
|
220
|
+
rescue Armature::Run::CommandFailureError
|
221
|
+
raise Armature::RefError, "no such ref '#{ref_str}' in repo '#{self}'"
|
222
|
+
end
|
223
|
+
|
224
|
+
# Check if a real (full) SHA matches a (possibly partial) candidate SHA
|
225
|
+
def sha_match? real, candidate
|
226
|
+
real.start_with? candidate
|
227
|
+
end
|
228
|
+
end
|