Class: Commit

Inherits:
Object
  • Object
show all
Extended by:
ActiveModel::Naming
Includes:
ActiveModel::Conversion, Mentionable, Participable, Referable, StaticModel
Defined in:
app/models/commit.rb

Constant Summary collapse

DIFF_SAFE_LINES =
Gitlab::Git::DiffCollection::DEFAULT_LIMITS[:max_lines]
DIFF_HARD_LIMIT_FILES =

Commits above this size will not be rendered in HTML

1000
DIFF_HARD_LIMIT_LINES =
50000

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from StaticModel

#[], #destroyed?, #new_record?, #persisted?, #to_param

Methods included from Mentionable

#all_references, #create_cross_references!, #create_new_cross_references!, #gfm_reference, #local_reference, #mentioned_users, #referenced_mentionables

Methods included from Participable

#participants

Constructor Details

#initialize(raw_commit, project) ⇒ Commit

Returns a new instance of Commit


52
53
54
55
56
57
# File 'app/models/commit.rb', line 52

def initialize(raw_commit, project)
  raise "Nil as raw commit passed" unless raw_commit

  @raw = raw_commit
  @project = project
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *args, &block) ⇒ Object


197
198
199
# File 'app/models/commit.rb', line 197

def method_missing(m, *args, &block)
  @raw.send(m, *args, &block)
end

Instance Attribute Details

#projectObject

Returns the value of attribute project


13
14
15
# File 'app/models/commit.rb', line 13

def project
  @project
end

#rawObject

Returns the value of attribute raw


50
51
52
# File 'app/models/commit.rb', line 50

def raw
  @raw
end

Class Method Details

.decorate(commits, project) ⇒ Object


22
23
24
25
26
27
28
29
30
# File 'app/models/commit.rb', line 22

def decorate(commits, project)
  commits.map do |commit|
    if commit.kind_of?(Commit)
      commit
    else
      self.new(commit, project)
    end
  end
end

.diff_line_count(diffs) ⇒ Object

Calculate number of lines to render for diffs


33
34
35
# File 'app/models/commit.rb', line 33

def diff_line_count(diffs)
  diffs.reduce(0) { |sum, d| sum + Gitlab::Git::Util.count_lines(d.diff) }
end

83
84
85
# File 'app/models/commit.rb', line 83

def self.link_reference_pattern
  @link_reference_pattern ||= super("commit", /(?<commit>\h{7,40})/)
end

.max_diff_optionsObject


42
43
44
45
46
47
# File 'app/models/commit.rb', line 42

def max_diff_options
  {
    max_files: DIFF_HARD_LIMIT_FILES,
    max_lines: DIFF_HARD_LIMIT_LINES,
  }
end

.reference_patternObject

Pattern used to extract commit references from text

The SHA can be between 7 and 40 hex characters.

This pattern supports cross-project references.


76
77
78
79
80
81
# File 'app/models/commit.rb', line 76

def self.reference_pattern
  @reference_pattern ||= %r{
    (?:#{Project.reference_pattern}#{reference_prefix})?
    (?<commit>\h{7,40})
  }x
end

.reference_prefixObject


67
68
69
# File 'app/models/commit.rb', line 67

def self.reference_prefix
  '@'
end

.truncate_sha(sha) ⇒ Object

Truncate sha to 8 characters


38
39
40
# File 'app/models/commit.rb', line 38

def truncate_sha(sha)
  sha[0..7]
end

Instance Method Details

#==(other) ⇒ Object


63
64
65
# File 'app/models/commit.rb', line 63

def ==(other)
  (self.class === other) && (raw == other.raw)
end

#authorObject


177
178
179
# File 'app/models/commit.rb', line 177

def author
  @author ||= User.find_by_any_email(author_email.downcase)
end

#change_type_titleObject


261
262
263
# File 'app/models/commit.rb', line 261

def change_type_title
  merged_merge_request ? 'merge request' : 'commit'
end

#cherry_pick_branch_nameObject


223
224
225
# File 'app/models/commit.rb', line 223

def cherry_pick_branch_name
  project.repository.next_branch("cherry-pick-#{short_id}", mild: true)
end

#ci_commitsObject


210
211
212
# File 'app/models/commit.rb', line 210

def ci_commits
  @ci_commits ||= project.ci_commits.where(sha: sha)
end

#closes_issues(current_user = self.committer) ⇒ Object

Discover issues should be closed when this commit is pushed to a project's default branch.


173
174
175
# File 'app/models/commit.rb', line 173

def closes_issues(current_user = self.committer)
  Gitlab::ClosingIssueExtractor.new(project, current_user).closed_by_message(safe_message)
end

#committerObject


181
182
183
# File 'app/models/commit.rb', line 181

def committer
  @committer ||= User.find_by_any_email(committer_email.downcase)
end

#descriptionObject

Returns the commits description

cut off, ellipses (`&hellp;`) are prepended to the commit message.


138
139
140
141
142
143
144
145
146
# File 'app/models/commit.rb', line 138

def description
  title_end = safe_message.index("\n")
  @description ||=
    if (!title_end && safe_message.length > 100) || (title_end && title_end > 100)
      "" << safe_message[80..-1]
    else
      safe_message.split("\n", 2)[1].try(:chomp)
    end
end

#description?Boolean

Returns:

  • (Boolean)

148
149
150
# File 'app/models/commit.rb', line 148

def description?
  description.present?
end

#diff_line_countObject


103
104
105
106
# File 'app/models/commit.rb', line 103

def diff_line_count
  @diff_line_count ||= Commit::diff_line_count(self.diffs)
  @diff_line_count
end

#has_been_reverted?(current_user = nil, noteable = self) ⇒ Boolean

Returns:

  • (Boolean)

253
254
255
256
257
258
259
# File 'app/models/commit.rb', line 253

def has_been_reverted?(current_user = nil, noteable = self)
  Gitlab::ReferenceExtractor.lazily do
    noteable.notes.system.flat_map do |note|
      note.all_references(current_user).commits
    end
  end.any? { |commit_ref| commit_ref.reverts_commit?(self) }
end

#hook_attrs(with_changed_files: false) ⇒ Object


152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'app/models/commit.rb', line 152

def hook_attrs(with_changed_files: false)
  data = {
    id: id,
    message: safe_message,
    timestamp: committed_date.xmlschema,
    url: Gitlab::UrlBuilder.build(self),
    author: {
      name: author_name,
      email: author_email
    }
  }

  if with_changed_files
    data.merge!(repo_changes)
  end

  data
end

#idObject


59
60
61
# File 'app/models/commit.rb', line 59

def id
  @raw.id
end

Returns a string describing the commit for use in a link title

Example

"Commit: Alex Denisov - Project git clone panel"

113
114
115
# File 'app/models/commit.rb', line 113

def link_title
  "Commit: #{author_name} - #{title}"
end

#merge_commit?Boolean

Returns:

  • (Boolean)

243
244
245
# File 'app/models/commit.rb', line 243

def merge_commit?
  parents.size > 1
end

#merged_merge_requestObject


247
248
249
250
251
# File 'app/models/commit.rb', line 247

def merged_merge_request
  return @merged_merge_request if defined?(@merged_merge_request)

  @merged_merge_request = project.merge_requests.find_by(merge_commit_sha: id) if merge_commit?
end

#notesObject


193
194
195
# File 'app/models/commit.rb', line 193

def notes
  project.notes.for_commit_id(self.id)
end

#parentObject


189
190
191
# File 'app/models/commit.rb', line 189

def parent
  @parent ||= project.commit(self.parent_id) if self.parent_id
end

#parentsObject


185
186
187
# File 'app/models/commit.rb', line 185

def parents
  @parents ||= parent_ids.map { |id| project.commit(id) }
end

95
96
97
98
99
100
101
# File 'app/models/commit.rb', line 95

def reference_link_text(from_project = nil)
  if cross_project_reference?(from_project)
    project.to_reference + self.class.reference_prefix + self.short_id
  else
    self.short_id
  end
end

#respond_to_missing?(method, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)

201
202
203
# File 'app/models/commit.rb', line 201

def respond_to_missing?(method, include_private = false)
  @raw.respond_to?(method, include_private) || super
end

#revert_branch_nameObject


219
220
221
# File 'app/models/commit.rb', line 219

def revert_branch_name
  "revert-#{short_id}"
end

#revert_descriptionObject


227
228
229
230
231
232
233
# File 'app/models/commit.rb', line 227

def revert_description
  if merged_merge_request
    "This reverts merge request #{merged_merge_request.to_reference}"
  else
    "This reverts commit #{sha}"
  end
end

#revert_messageObject


235
236
237
# File 'app/models/commit.rb', line 235

def revert_message
  %Q{Revert "#{title.strip}"\n\n#{revert_description}}
end

#reverts_commit?(commit) ⇒ Boolean

Returns:

  • (Boolean)

239
240
241
# File 'app/models/commit.rb', line 239

def reverts_commit?(commit)
  description? && description.include?(commit.revert_description)
end

#short_idObject

Truncate sha to 8 characters


206
207
208
# File 'app/models/commit.rb', line 206

def short_id
  @raw.short_id(7)
end

#statusObject


214
215
216
217
# File 'app/models/commit.rb', line 214

def status
  return @status if defined?(@status)
  @status ||= ci_commits.status
end

#titleObject

Returns the commits title.

Usually, the commit title is the first line of the commit message. In case this first line is longer than 100 characters, it is cut off after 80 characters and ellipses (`&hellp;`) are appended.


122
123
124
125
126
127
128
129
130
131
132
133
# File 'app/models/commit.rb', line 122

def title
  title = safe_message

  return no_commit_message if title.blank?

  title_end = title.index("\n")
  if (!title_end && title.length > 100) || (title_end && title_end > 100)
    title[0..79] << ""
  else
    title.split("\n", 2).first
  end
end

#to_reference(from_project = nil) ⇒ Object


87
88
89
90
91
92
93
# File 'app/models/commit.rb', line 87

def to_reference(from_project = nil)
  if cross_project_reference?(from_project)
    project.to_reference + self.class.reference_prefix + self.id
  else
    self.id
  end
end