gitlab_git 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9ebc1cee0bc0da6849ff4478d3cee6b2fa682bd5
4
- data.tar.gz: e8045557695439ad9bcbee5c995f1f7d849980e3
3
+ metadata.gz: 8c8f85ff5ac6e3846697e0a4e5c479cd608bffdd
4
+ data.tar.gz: 29c128efbfffb375d443274f6c49b3641443321e
5
5
  SHA512:
6
- metadata.gz: 0b92618fc978892b8aa0151aa92cc0cd8bda29c606ec2fc8d073df306fc42be37752a09cce9b52415780ffa4cdf00f7e63417990aa5311a9c0673ee96786b102
7
- data.tar.gz: d8e5aaefc1720e67e118a663e4ee6a905d3df356a60533f91d89be136f6161f6318c308759d2a3cb5f6a7fc562c20e75d79dc20c0fb91b32ea8a76e5179062e0
6
+ metadata.gz: ab12c3ab17f22500f9483f4cabbd01aa94f098b11990373399df73676e9756c809f1af6ce957e8608d5e0286bf2d69c6ef3db613d5b92698215e997bd40a3376
7
+ data.tar.gz: 5bb1ab43d66022fce5d2c20eda9b17270a0f0d0ddea1f600771c583054c78b1a05258d140edcb36515597f9b8e82c03e766ef8e3c22fa53bff91c168ea5d66b0
@@ -0,0 +1,23 @@
1
+ module Gitlab
2
+ module Git
3
+ class Blame
4
+
5
+ attr_accessor :repository, :sha, :path
6
+
7
+ def initialize(repository, sha, path)
8
+ @repository, @sha, @path = repository, sha, path
9
+ end
10
+
11
+ def each
12
+ raw_blame = Grit::Blob.blame(repository.repo, sha, path)
13
+
14
+ raw_blame.each do |commit, lines|
15
+ next unless commit
16
+
17
+ commit = Gitlab::Git::Commit.new(commit)
18
+ yield(commit, lines)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,44 @@
1
+ module Gitlab
2
+ module Git
3
+ class Blob
4
+ include Linguist::BlobHelper
5
+
6
+ attr_accessor :raw_blob
7
+
8
+ def initialize(repository, sha, ref, path)
9
+ @repository, @sha, @ref = repository, sha, ref
10
+
11
+ @commit = @repository.commit(sha)
12
+ @raw_blob = @repository.tree(@commit, path)
13
+ end
14
+
15
+ def data
16
+ if raw_blob
17
+ raw_blob.data
18
+ else
19
+ nil
20
+ end
21
+ end
22
+
23
+ def name
24
+ raw_blob.name
25
+ end
26
+
27
+ def exists?
28
+ raw_blob
29
+ end
30
+
31
+ def empty?
32
+ !data || data == ''
33
+ end
34
+
35
+ def mode
36
+ raw_blob.mode
37
+ end
38
+
39
+ def size
40
+ raw_blob.size
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,140 @@
1
+ # Gitlab::Git::Commit is a wrapper around native Grit::Commit object
2
+ # We dont want to use grit objects inside app/
3
+ # It helps us easily migrate to rugged in future
4
+ module Gitlab
5
+ module Git
6
+ class Commit
7
+ attr_accessor :raw_commit, :head, :refs,
8
+ :id, :authored_date, :committed_date, :message,
9
+ :author_name, :author_email, :parent_ids,
10
+ :committer_name, :committer_email
11
+
12
+ def initialize(raw_commit, head = nil)
13
+ raise "Nil as raw commit passed" unless raw_commit
14
+
15
+ if raw_commit.is_a?(Hash)
16
+ init_from_hash(raw_commit)
17
+ else
18
+ init_from_grit(raw_commit)
19
+ end
20
+
21
+ @head = head
22
+ end
23
+
24
+ def serialize_keys
25
+ @serialize_keys ||= %w(id authored_date committed_date author_name author_email committer_name committer_email message parent_ids).map(&:to_sym)
26
+ end
27
+
28
+ def sha
29
+ id
30
+ end
31
+
32
+ def short_id(length = 10)
33
+ id.to_s[0..length]
34
+ end
35
+
36
+ def safe_message
37
+ @safe_message ||= message
38
+ end
39
+
40
+ def created_at
41
+ committed_date
42
+ end
43
+
44
+ # Was this commit committed by a different person than the original author?
45
+ def different_committer?
46
+ author_name != committer_name || author_email != committer_email
47
+ end
48
+
49
+ def parent_id
50
+ parent_ids.first
51
+ end
52
+
53
+ # Shows the diff between the commit's parent and the commit.
54
+ #
55
+ # Cuts out the header and stats from #to_patch and returns only the diff.
56
+ def to_diff
57
+ # see Grit::Commit#show
58
+ patch = to_patch
59
+
60
+ # discard lines before the diff
61
+ lines = patch.split("\n")
62
+ while !lines.first.start_with?("diff --git") do
63
+ lines.shift
64
+ end
65
+ lines.pop if lines.last =~ /^[\d.]+$/ # Git version
66
+ lines.pop if lines.last == "-- " # end of diff
67
+ lines.join("\n")
68
+ end
69
+
70
+ def has_zero_stats?
71
+ stats.total.zero?
72
+ rescue
73
+ true
74
+ end
75
+
76
+ def no_commit_message
77
+ "--no commit message"
78
+ end
79
+
80
+ def to_hash
81
+ hash = {}
82
+
83
+ keys = serialize_keys
84
+
85
+ keys.each do |key|
86
+ hash[key] = send(key)
87
+ end
88
+
89
+ hash
90
+ end
91
+
92
+ def date
93
+ committed_date
94
+ end
95
+
96
+ def diffs
97
+ raw_commit.diffs.map { |diff| Gitlab::Git::Diff.new(diff) }
98
+ end
99
+
100
+ def parents
101
+ raw_commit.parents
102
+ end
103
+
104
+ def tree
105
+ raw_commit.tree
106
+ end
107
+
108
+ def stats
109
+ raw_commit.tree
110
+ end
111
+
112
+ def to_patch
113
+ raw_commit.to_patch
114
+ end
115
+
116
+ private
117
+
118
+ def init_from_grit(grit)
119
+ @raw_commit = grit
120
+ @id = grit.id
121
+ @message = grit.message
122
+ @authored_date = grit.authored_date
123
+ @committed_date = grit.committed_date
124
+ @author_name = grit.author.name
125
+ @author_email = grit.author.email
126
+ @committer_name = grit.committer.name
127
+ @committer_email = grit.committer.email
128
+ @parent_ids = grit.parents.map(&:id)
129
+ end
130
+
131
+ def init_from_hash(hash)
132
+ raw_commit = hash.symbolize_keys
133
+
134
+ serialize_keys.each do |key|
135
+ send(:"#{key}=", raw_commit[key.to_sym])
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,35 @@
1
+ module Gitlab
2
+ module Git
3
+ class Compare
4
+ attr_accessor :commits, :commit, :diffs, :same
5
+
6
+ def initialize(repository, from, to)
7
+ @commits, @diffs = [], []
8
+ @commit = nil
9
+ @same = false
10
+
11
+ return unless from && to
12
+
13
+ first = repository.commit(to.try(:strip))
14
+ last = repository.commit(from.try(:strip))
15
+
16
+ return unless first && last
17
+
18
+ if first.id == last.id
19
+ @same = true
20
+ return
21
+ end
22
+
23
+ @commit = first
24
+ @commits = repository.commits_between(last.id, first.id)
25
+
26
+ @diffs = if @commits.size > 100
27
+ []
28
+ else
29
+ repository.repo.diff(last.id, first.id) rescue []
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+
@@ -0,0 +1,63 @@
1
+ # Gitlab::Git::Diff is a wrapper around native Grit::Diff object
2
+ # We dont want to use grit objects inside app/
3
+ # It helps us easily migrate to rugged in future
4
+ module Gitlab
5
+ module Git
6
+ class Diff
7
+ BROKEN_DIFF = "--broken-diff"
8
+
9
+ attr_accessor :raw_diff
10
+
11
+ # Diff properties
12
+ attr_accessor :old_path, :new_path, :a_mode, :b_mode, :diff
13
+
14
+ # Stats properties
15
+ attr_accessor :new_file, :renamed_file, :deleted_file
16
+
17
+ def initialize(raw_diff)
18
+ raise "Nil as raw diff passed" unless raw_diff
19
+
20
+ if raw_diff.is_a?(Hash)
21
+ init_from_hash(raw_diff)
22
+ else
23
+ init_from_grit(raw_diff)
24
+ end
25
+ end
26
+
27
+ def serialize_keys
28
+ @serialize_keys ||= %w(diff new_path old_path a_mode b_mode new_file renamed_file deleted_file).map(&:to_sym)
29
+ end
30
+
31
+ def to_hash
32
+ hash = {}
33
+
34
+ keys = serialize_keys
35
+
36
+ keys.each do |key|
37
+ hash[key] = send(key)
38
+ end
39
+
40
+ hash
41
+ end
42
+
43
+ private
44
+
45
+ def init_from_grit(grit)
46
+ @raw_diff = grit
47
+
48
+ serialize_keys.each do |key|
49
+ send(:"#{key}=", grit.send(key))
50
+ end
51
+ end
52
+
53
+ def init_from_hash(hash)
54
+ raw_diff = hash.symbolize_keys
55
+
56
+ serialize_keys.each do |key|
57
+ send(:"#{key}=", raw_diff[key.to_sym])
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+
@@ -0,0 +1,20 @@
1
+ module Gitlab
2
+ module Git
3
+ module Popen
4
+ def popen(cmd, path)
5
+ vars = { "PWD" => path }
6
+ options = { :chdir => path }
7
+
8
+ @cmd_output = ""
9
+ @cmd_status = 0
10
+ Open3.popen3(vars, cmd, options) do |stdin, stdout, stderr, wait_thr|
11
+ @cmd_status = wait_thr.value.exitstatus
12
+ @cmd_output << stdout.read
13
+ @cmd_output << stderr.read
14
+ end
15
+
16
+ return @cmd_output, @cmd_status
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,225 @@
1
+ # Gitlab::Git::Gitlab::Git::Commit is a wrapper around native Grit::Repository object
2
+ # We dont want to use grit objects inside app/
3
+ # It helps us easily migrate to rugged in future
4
+ module Gitlab
5
+ module Git
6
+ class Repository
7
+ include Gitlab::Git::Popen
8
+
9
+ class NoRepository < StandardError; end
10
+
11
+ class << self
12
+ attr_accessor :repos_path
13
+ end
14
+
15
+ # Repository directory name with namespace direcotry
16
+ # Examples:
17
+ # gitlab/gitolite
18
+ # diaspora
19
+ #
20
+ attr_accessor :path_with_namespace
21
+
22
+ # Grit repo object
23
+ attr_accessor :repo
24
+
25
+ # Default branch in the repository
26
+ attr_accessor :root_ref
27
+
28
+ def initialize(path_with_namespace, root_ref = 'master')
29
+ @root_ref = root_ref || "master"
30
+ @path_with_namespace = path_with_namespace
31
+
32
+ # Init grit repo object
33
+ repo
34
+ end
35
+
36
+ def raw
37
+ repo
38
+ end
39
+
40
+ def path_to_repo
41
+ @path_to_repo ||= File.join(repos_path, "#{path_with_namespace}.git")
42
+ end
43
+
44
+ def repos_path
45
+ self.class.repos_path
46
+ end
47
+
48
+ def repo
49
+ @repo ||= Grit::Repo.new(path_to_repo)
50
+ rescue Grit::NoSuchPathError
51
+ raise NoRepository.new('no repository for such path')
52
+ end
53
+
54
+ def commit(commit_id = nil)
55
+ commit = if commit_id
56
+ # Find repo.refs first,
57
+ # because if commit_id is "tag name",
58
+ # repo.commit(commit_id) returns wrong commit sha
59
+ # that is git tag object sha.
60
+ ref = repo.refs.find {|r| r.name == commit_id}
61
+ if ref
62
+ ref.commit
63
+ else
64
+ repo.commit(commit_id)
65
+ end
66
+ else
67
+ repo.commits(root_ref).first
68
+ end
69
+
70
+ decorate_commit(commit) if commit
71
+ end
72
+
73
+ def commits_with_refs(n = 20)
74
+ commits = repo.branches.map { |ref| decorate_commit(ref.commit, ref) }
75
+
76
+ commits.sort! do |x, y|
77
+ y.committed_date <=> x.committed_date
78
+ end
79
+
80
+ commits[0..n]
81
+ end
82
+
83
+ def commits(ref, path = nil, limit = nil, offset = nil)
84
+ if path && path != ''
85
+ repo.log(ref, path, max_count: limit, skip: offset, follow: true)
86
+ elsif limit && offset
87
+ repo.commits(ref, limit.to_i, offset.to_i)
88
+ else
89
+ repo.commits(ref)
90
+ end.map{ |c| decorate_commit(c) }
91
+ end
92
+
93
+ def commits_between(from, to)
94
+ repo.commits_between(from, to).map { |c| decorate_commit(c) }
95
+ end
96
+
97
+ def last_commit_for(ref, path = nil)
98
+ commits(ref, path, 1).first
99
+ end
100
+
101
+ # Returns an Array of branch names
102
+ # sorted by name ASC
103
+ def branch_names
104
+ branches.map(&:name)
105
+ end
106
+
107
+ # Returns an Array of Branches
108
+ def branches
109
+ repo.branches.sort_by(&:name)
110
+ end
111
+
112
+ # Returns an Array of tag names
113
+ def tag_names
114
+ repo.tags.collect(&:name).sort.reverse
115
+ end
116
+
117
+ # Returns an Array of Tags
118
+ def tags
119
+ repo.tags.sort_by(&:name).reverse
120
+ end
121
+
122
+ # Returns an Array of branch and tag names
123
+ def ref_names
124
+ [branch_names + tag_names].flatten
125
+ end
126
+
127
+ def heads
128
+ @heads ||= repo.heads
129
+ end
130
+
131
+ def tree(fcommit, path = nil)
132
+ fcommit = commit if fcommit == :head
133
+ tree = fcommit.tree
134
+ path ? (tree / path) : tree
135
+ end
136
+
137
+ def has_commits?
138
+ !!commit
139
+ rescue Grit::NoSuchPathError
140
+ false
141
+ end
142
+
143
+ def empty?
144
+ !has_commits?
145
+ end
146
+
147
+ # Discovers the default branch based on the repository's available branches
148
+ #
149
+ # - If no branches are present, returns nil
150
+ # - If one branch is present, returns its name
151
+ # - If two or more branches are present, returns the one that has a name
152
+ # matching root_ref (default_branch or 'master' if default_branch is nil)
153
+ def discover_default_branch
154
+ if branch_names.length == 0
155
+ nil
156
+ elsif branch_names.length == 1
157
+ branch_names.first
158
+ else
159
+ branch_names.select { |v| v == root_ref }.first
160
+ end
161
+ end
162
+
163
+ # Archive Project to .tar.gz
164
+ #
165
+ # Already packed repo archives stored at
166
+ # app_root/tmp/repositories/project_name/project_name-commit-id.tag.gz
167
+ #
168
+ def archive_repo(ref)
169
+ ref = ref || self.root_ref
170
+ commit = self.commit(ref)
171
+ return nil unless commit
172
+
173
+ # Build file path
174
+ file_name = self.path_with_namespace.gsub("/","_") + "-" + commit.id.to_s + ".tar.gz"
175
+ storage_path = Rails.root.join("tmp", "repositories")
176
+ file_path = File.join(storage_path, self.path_with_namespace, file_name)
177
+
178
+ # Put files into a directory before archiving
179
+ prefix = File.basename(self.path_with_namespace) + "/"
180
+
181
+ # Create file if not exists
182
+ unless File.exists?(file_path)
183
+ FileUtils.mkdir_p File.dirname(file_path)
184
+ file = self.repo.archive_to_file(ref, prefix, file_path)
185
+ end
186
+
187
+ file_path
188
+ end
189
+
190
+ # Return repo size in megabytes
191
+ # Cached in redis
192
+ def size
193
+ Rails.cache.fetch(cache_key(:size)) do
194
+ size = popen('du -s', path_to_repo).first.strip.to_i
195
+ (size.to_f / 1024).round(2)
196
+ end
197
+ end
198
+
199
+ def expire_cache
200
+ Rails.cache.delete(cache_key(:size))
201
+ end
202
+
203
+ def cache_key(type)
204
+ "#{type}:#{path_with_namespace}"
205
+ end
206
+
207
+ def diffs_between(source_branch, target_branch)
208
+ # Only show what is new in the source branch compared to the target branch, not the other way around.
209
+ # The linex below with merge_base is equivalent to diff with three dots (git diff branch1...branch2)
210
+ # From the git documentation: "git diff A...B" is equivalent to "git diff $(git-merge-base A B) B"
211
+ common_commit = repo.git.native(:merge_base, {}, [target_branch, source_branch]).strip
212
+ repo.diff(common_commit, source_branch).map { |diff| Gitlab::Git::Diff.new(diff) }
213
+
214
+ rescue Grit::Git::GitTimeout
215
+ [Gitlab::Git::Diff::BROKEN_DIFF]
216
+ end
217
+
218
+ protected
219
+
220
+ def decorate_commit(commit, ref = nil)
221
+ Gitlab::Git::Commit.new(commit, ref)
222
+ end
223
+ end
224
+ end
225
+ end
@@ -0,0 +1,75 @@
1
+ module Gitlab
2
+ module Git
3
+ class Stats
4
+ attr_accessor :repo, :ref
5
+
6
+ def initialize repo, ref
7
+ @repo, @ref = repo, ref
8
+ end
9
+
10
+ def authors
11
+ @authors ||= collect_authors
12
+ end
13
+
14
+ def commits_count
15
+ @commits_count ||= repo.commit_count(ref)
16
+ end
17
+
18
+ def files_count
19
+ args = [ref, '-r', '--name-only' ]
20
+ repo.git.run(nil, 'ls-tree', nil, {}, args).split("\n").count
21
+ end
22
+
23
+ def authors_count
24
+ authors.size
25
+ end
26
+
27
+ def graph
28
+ @graph ||= build_graph
29
+ end
30
+
31
+ protected
32
+
33
+ def collect_authors
34
+ shortlog = repo.git.shortlog({e: true, s: true }, ref)
35
+
36
+ authors = []
37
+
38
+ lines = shortlog.split("\n")
39
+
40
+ lines.each do |line|
41
+ data = line.split("\t")
42
+ commits = data.first
43
+ author = Grit::Actor.from_string(data.last)
44
+
45
+ authors << OpenStruct.new(
46
+ name: author.name,
47
+ email: author.email,
48
+ commits: commits.to_i
49
+ )
50
+ end
51
+
52
+ authors.sort_by(&:commits).reverse
53
+ end
54
+
55
+ def build_graph n = 4
56
+ from, to = (Date.today.prev_day(n*7)), Date.today
57
+ args = ['--all', "--since=#{from.to_s}", '--format=%ad' ]
58
+ rev_list = repo.git.run(nil, 'rev-list', nil, {}, args).split("\n")
59
+
60
+ commits_dates = rev_list.values_at(* rev_list.each_index.select {|i| i.odd?})
61
+ commits_dates = commits_dates.map { |date_str| Time.parse(date_str).to_date.to_s(:date) }
62
+
63
+ commits_per_day = from.upto(to).map do |day|
64
+ commits_dates.count(day.to_date.to_s)
65
+ end
66
+
67
+ OpenStruct.new(
68
+ labels: from.upto(to).map { |day| day.strftime('%b %d') },
69
+ commits: commits_per_day,
70
+ weeks: n
71
+ )
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,52 @@
1
+ module Gitlab
2
+ module Git
3
+ class Tree
4
+ attr_accessor :repository, :sha, :path, :ref, :raw_tree, :id
5
+
6
+ def initialize(repository, sha, ref = nil, path = nil)
7
+ @repository, @sha, @ref, @path = repository, sha, ref, path
8
+
9
+ @path = nil if !@path || @path == ''
10
+
11
+ # Load tree from repository
12
+ @commit = @repository.commit(@sha)
13
+ @raw_tree = @repository.tree(@commit, @path)
14
+ end
15
+
16
+ def exists?
17
+ raw_tree
18
+ end
19
+
20
+ def empty?
21
+ trees.empty? && blobs.empty?
22
+ end
23
+
24
+ def trees
25
+ entries.select { |t| t.is_a?(Grit::Tree) }
26
+ end
27
+
28
+ def blobs
29
+ entries.select { |t| t.is_a?(Grit::Blob) }
30
+ end
31
+
32
+ def is_blob?
33
+ raw_tree.is_a?(Grit::Blob)
34
+ end
35
+
36
+ def up_dir?
37
+ path && path != ''
38
+ end
39
+
40
+ def readme
41
+ @readme ||= blobs.find { |c| c.name =~ /^readme/i }
42
+ end
43
+
44
+ protected
45
+
46
+ def entries
47
+ raw_tree.contents
48
+ end
49
+ end
50
+ end
51
+ end
52
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab_git
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitriy Zaporozhets
@@ -73,6 +73,15 @@ extensions: []
73
73
  extra_rdoc_files: []
74
74
  files:
75
75
  - lib/gitlab_git.rb
76
+ - lib/gitlab_git/blame.rb
77
+ - lib/gitlab_git/blob.rb
78
+ - lib/gitlab_git/commit.rb
79
+ - lib/gitlab_git/compare.rb
80
+ - lib/gitlab_git/diff.rb
81
+ - lib/gitlab_git/popen.rb
82
+ - lib/gitlab_git/repository.rb
83
+ - lib/gitlab_git/stats.rb
84
+ - lib/gitlab_git/tree.rb
76
85
  homepage: http://rubygems.org/gems/gitlab_git
77
86
  licenses: []
78
87
  metadata: {}