forked from square/kochiku
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgit_repo.rb
133 lines (108 loc) · 4.22 KB
/
git_repo.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
require 'cocaine'
require 'fileutils'
class GitRepo
class RefNotFoundError < StandardError; end
WORKING_DIR = Rails.root.join('tmp', 'build-partition')
class << self
def inside_copy(repository, sha)
cached_repo_path = cached_repo_for(repository)
synchronize_cache_repo(cached_repo_path)
Dir.mktmpdir(nil, WORKING_DIR) do |dir|
Cocaine::CommandLine.new("git clone", "--config remote.origin.pushurl=#{repository.url} #{cached_repo_path} #{dir}").run
Dir.chdir(dir) do
raise RefNotFoundError, "repo:#{repository.url}, sha:#{sha}" unless system("git rev-list --quiet -n1 #{sha}")
Cocaine::CommandLine.new("git checkout", "--quiet :commit").run(commit: sha)
yield dir
end
end
end
def inside_repo(repository, sync: true)
cached_repo_path = cached_repo_for(repository)
Dir.chdir(cached_repo_path) do
synchronize_with_remote('origin') if sync
yield
end
end
def load_kochiku_yml(repository, ref)
inside_repo(repository) do
raise RefNotFoundError, "repo:#{repository.url}, sha:#{ref}" unless system("git rev-list --quiet -n1 #{ref}")
read_repo_config(ref)
end
end
def included_in_promotion_ref?(build_ref, promotion_ref)
# --is-ancestor was added in git 1.8.0
# exit -> 1: not an ancestor
# exit -> 128: the commit does not exist
ancestor_cmd = Cocaine::CommandLine.new("git merge-base", "--is-ancestor #{build_ref} #{promotion_ref}", :expected_outcodes => [0, 1, 128])
ancestor_cmd.run
ancestor_cmd.exit_status == 0
end
def branch_exist?(branch)
exist_cmd = Cocaine::CommandLine.new("git rev-parse", "--verify --quiet #{branch}", expected_outcodes: [0, 1])
exist_cmd.run
exist_cmd.exit_status == 0
end
private
KOCHIKU_YML_LOCS = [
'kochiku.yml',
'config/kochiku.yml',
'config/ci/kochiku.yml',
].freeze
def read_repo_config(ref)
command = Cocaine::CommandLine.new("git show", ":ref::file",
{ :swallow_stderr => true, :expected_outcodes => [0, 128] })
KOCHIKU_YML_LOCS.each do |loc|
file = command.run(:ref => ref, :file => loc)
return YAML.load(file) if command.exit_status == 0
end
nil
end
def cached_repo_for(repository)
cached_repo_path = WORKING_DIR.join(repository.namespace, "#{repository.name}.git")
if !cached_repo_path.directory?
FileUtils.mkdir_p(WORKING_DIR.join(repository.namespace))
clone_bare_repo(repository, cached_repo_path)
else
harmonize_remote_url(cached_repo_path, repository.url_for_fetching)
end
cached_repo_path
end
# Update the remote url for the git repository if it has changed
def harmonize_remote_url(cached_repo_path, expected_url)
Dir.chdir(cached_repo_path) do
remote_url = Cocaine::CommandLine.new("git config", "--get remote.origin.url").run.chomp
if remote_url != expected_url
Rails.logger.info "#{remote_url.inspect} does not match #{expected_url.inspect}. Updating it."
Cocaine::CommandLine.new("git remote", "set-url origin #{expected_url}").run
end
end
nil
end
def synchronize_cache_repo(cached_repo_path)
Dir.chdir(cached_repo_path) do
# update the cached repo
synchronize_with_remote('origin')
end
end
def clone_bare_repo(repo, cached_repo_path)
# Note: the --config option was added in git 1.7.7
Cocaine::CommandLine.new(
"git clone",
"--bare --quiet --config remote.origin.pushurl=#{repo.url} --config remote.origin.fetch='+refs/heads/*:refs/heads/*' --config remote.origin.tagopt='--no-tags' #{repo.url_for_fetching} #{cached_repo_path}"
).run
end
def synchronize_with_remote(name)
Cocaine::CommandLine.new("git fetch", "--quiet --prune #{name}").run
rescue Cocaine::ExitStatusError => e
# likely caused by another 'git fetch' that is currently in progress. Wait a few seconds and try again
tries = (tries || 0) + 1
if tries < 3
Rails.logger.warn(e)
sleep(15 * tries)
retry
else
raise e
end
end
end
end