/
git.rb
148 lines (120 loc) · 4.65 KB
/
git.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# stolen wholesale from capistrano, thanks Jamis!
class Git
# Performs a clone on the remote machine, then checkout on the branch
# you want to deploy.
def initialize(opts={})
@configuration = opts
end
def configuration
@configuration
end
def git
res = configuration[:git_ssh_wrapper] ? "GIT_SSH=#{configuration[:git_ssh_wrapper]} git" : 'git'
res = "sudo -u #{configuration[:user]} #{res}" if configuration[:user]
res
end
def respository
configuration[:repository]
end
def checkout(revision, destination)
remote = origin
args = []
args << "-o #{remote}" unless remote == 'origin'
if depth = configuration[:git_shallow_clone]
args << "--depth #{depth}"
end
execute = []
if args.empty?
execute << "#{git} clone #{verbose} #{configuration[:repository]} #{destination}"
else
execute << "#{git} clone #{verbose} #{args.join(' ')} #{configuration[:repository]} #{destination}"
end
# checkout into a local branch rather than a detached HEAD
execute << "cd #{destination} && #{git} checkout #{verbose} -b deploy #{revision}"
if configuration[:git_enable_submodules]
execute << "#{git} submodule #{verbose} init"
execute << "#{git} submodule #{verbose} update"
end
execute.join(" && ")
end
# An expensive export. Performs a checkout as above, then
# removes the repo.
def export(revision, destination)
checkout(revision, destination) << " && rm -Rf #{destination}/.git"
end
# Merges the changes to 'head' since the last fetch, for remote_cache
# deployment strategy
def sync(revision, destination)
remote = origin
execute = []
execute << "cd #{destination}"
# Use git-config to setup a remote tracking branches. Could use
# git-remote but it complains when a remote of the same name already
# exists, git-config will just silenty overwrite the setting every
# time. This could cause wierd-ness in the remote cache if the url
# changes between calls, but as long as the repositories are all
# based from each other it should still work fine.
if remote != 'origin'
execute << "#{git} config remote.#{remote}.url #{configuration[:repository]}"
execute << "#{git} config remote.#{remote}.fetch +refs/heads/*:refs/remotes/#{remote}/*"
end
# since we're in a local branch already, just reset to specified revision rather than merge
execute << "#{git} fetch #{verbose} #{remote} && #{git} reset #{verbose} --hard #{revision}"
if configuration[:git_enable_submodules]
execute << "#{git} submodule #{verbose} init"
execute << "#{git} submodule #{verbose} update"
end
execute.join(" && ")
end
# Returns a string of diffs between two revisions
def diff(from, to=nil)
from << "..#{to}" if to
scm :diff, from
end
# Returns a log of changes between the two revisions (inclusive).
def log(from, to=nil)
scm :log, "#{from}..#{to}"
end
# Getting the actual commit id, in case we were passed a tag
# or partial sha or something - it will return the sha if you pass a sha, too
def query_revision(revision)
raise ArgumentError, "Deploying remote branches is no longer supported. Specify the remote branch as a local branch for the git repository you're deploying from (ie: '#{revision.gsub('origin/', '')}' rather than '#{revision}')." if revision =~ /^origin\//
return revision if revision =~ /^[0-9a-f]{40}$/
command = scm('ls-remote', configuration[:repository], revision)
result = nil
begin
result = yield(command)
rescue ChefDeployFailure => e
raise obvious_error("Could not access the remote Git repository. If this is a private repository, please verify that the deploy key for your application has been added to your remote Git account.", e)
end
rev, ref = result.split(/[\t\n]/)
newrev = nil
if ref.sub(/refs\/.*?\//, '').strip == revision
newrev = rev
end
raise "Unable to resolve revision for '#{revision}' on repository '#{configuration[:repository]}'." unless newrev =~ /^[0-9a-f]{40}$/
return newrev
end
def scm(*args)
[git, *args].compact.join(" ")
end
def head
configuration[:branch] || 'HEAD'
end
def origin
configuration[:remote] || 'origin'
end
private
# If verbose output is requested, return nil, otherwise return the
# command-line switch for "quiet" ("-q").
def verbose
nil#configuration[:scm_verbose] ? nil : "-q"
end
# Build an error string that stands out in a log file
def obvious_error(message, e)
"#{stars}\n#{message}\n#{stars}\n#{e.message}#{stars}"
end
def stars
("\n"+'*'*80)*2
end
end