gitlab_git 1.0.1 → 1.0.2

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 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: {}