commits_helper.rb 7.88 KB
Newer Older
gitlabhq's avatar
gitlabhq committed
1
module CommitsHelper
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
  # Returns a link to the commit author. If the author has a matching user and
  # is a member of the current @project it will link to the team member page.
  # Otherwise it will link to the author email as specified in the commit.
  #
  # options:
  #  avatar: true will prepend the avatar image
  #  size:   size of the avatar image in px
  def commit_author_link(commit, options = {})
    commit_person_link(commit, options.merge(source: :author))
  end

  # Just like #author_link but for the committer.
  def commit_committer_link(commit, options = {})
    commit_person_link(commit, options.merge(source: :committer))
  end

18 19
  def image_diff_class(diff)
    if diff.deleted_file
20
      "deleted"
21
    elsif diff.new_file
22
      "added"
23 24 25 26
    else
      nil
    end
  end
27

28 29
  def commit_to_html(commit, project, inline = true)
    template = inline ? "inline_commit" : "commit"
30
    render "projects/commits/#{template}", commit: commit, project: project unless commit.nil?
31
  end
32

33 34 35 36 37 38
  # Breadcrumb links for a Project and, if applicable, a tree path
  def commits_breadcrumbs
    return unless @project && @ref

    # Add the root project link and the arrow icon
    crumbs = content_tag(:li) do
Vinnie Okada's avatar
Vinnie Okada committed
39 40 41 42
      link_to(
        @project.path,
        namespace_project_commits_path(@project.namespace, @project, @ref)
      )
43 44 45 46 47 48
    end

    if @path
      parts = @path.split('/')

      parts.each_with_index do |part, i|
49
        crumbs << content_tag(:li) do
50
          # The text is just the individual part, but the link needs all the parts before it
Vinnie Okada's avatar
Vinnie Okada committed
51 52 53 54 55 56 57 58
          link_to(
            part,
            namespace_project_commits_path(
              @project.namespace,
              @project,
              tree_join(@ref, parts[0..i].join('/'))
            )
          )
59 60 61 62 63 64 65
        end
      end
    end

    crumbs.html_safe
  end

66 67 68 69 70 71 72 73
  # Return Project default branch, if it present in array
  # Else - first branch in array (mb last actual branch)
  def commit_default_branch(project, branches)
    branches.include?(project.default_branch) ? branches.delete(project.default_branch) : branches.pop
  end

  # Returns the sorted alphabetically links to branches, separated by a comma
  def commit_branches_links(project, branches)
74
    branches.sort.map do |branch|
Vinnie Okada's avatar
Vinnie Okada committed
75 76 77
      link_to(
        namespace_project_tree_path(project.namespace, project, branch)
      ) do
78
        content_tag :span, class: 'label label-gray' do
79
          icon('code-fork') + ' ' + branch
80 81 82
        end
      end
    end.join(" ").html_safe
83 84
  end

85 86 87
  # Returns the sorted links to tags, separated by a comma
  def commit_tags_links(project, tags)
    sorted = VersionSorter.rsort(tags)
88
    sorted.map do |tag|
Vinnie Okada's avatar
Vinnie Okada committed
89 90 91 92
      link_to(
        namespace_project_commits_path(project.namespace, project,
                                       project.repository.find_tag(tag).name)
      ) do
93
        content_tag :span, class: 'label label-gray' do
94
          icon('tag') + ' ' + tag
95 96 97
        end
      end
    end.join(" ").html_safe
98 99
  end

100
  def link_to_browse_code(project, commit)
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
    if @path.blank?
      return link_to(
        "Browse Files",
        namespace_project_tree_path(project.namespace, project, commit),
        class: "btn btn-default"
      )
    end

    return unless current_controller?(:projects, :commits)

    if @repo.blob_at(commit.id, @path)
      return link_to(
        "Browse File",
        namespace_project_blob_path(project.namespace, project,
                                    tree_join(commit.id, @path)),
        class: "btn btn-default"
      )
    elsif @path.present?
      return link_to(
        "Browse Directory",
        namespace_project_tree_path(project.namespace, project,
                                    tree_join(commit.id, @path)),
        class: "btn btn-default"
      )
125 126 127
    end
  end

128
  def revert_commit_link(commit, continue_to_path, btn_class: nil, has_tooltip: true)
129 130
    return unless current_user

131
    tooltip = "Revert this #{commit.change_type_title} in a new merge request" if has_tooltip
132

133
    if can_collaborate_with_project?
134
      btn_class = "btn btn-warning btn-#{btn_class}" unless btn_class.nil?
135
      link_to 'Revert', '#modal-revert-commit', 'data-toggle' => 'modal', 'data-container' => 'body', title: (tooltip if has_tooltip), class: "#{btn_class} #{'has-tooltip' if has_tooltip}"
136
    elsif can?(current_user, :fork_project, @project)
137 138 139 140 141 142
      continue_params = {
        to: continue_to_path,
        notice: edit_in_new_fork_notice + ' Try to revert this commit again.',
        notice_now: edit_in_new_fork_notice_now
      }
      fork_path = namespace_project_forks_path(@project.namespace, @project,
Rubén Dávila's avatar
Rubén Dávila committed
143 144
        namespace_key: current_user.namespace.id,
        continue: continue_params)
145

146
      btn_class = "btn btn-grouped btn-warning" unless btn_class.nil?
147 148

      link_to 'Revert', fork_path, class: btn_class, method: :post, 'data-toggle' => 'tooltip', 'data-container' => 'body', title: (tooltip if has_tooltip)
149 150 151
    end
  end

152
  def cherry_pick_commit_link(commit, continue_to_path, btn_class: nil, has_tooltip: true)
153 154 155 156 157
    return unless current_user

    tooltip = "Cherry-pick this #{commit.change_type_title} in a new merge request"

    if can_collaborate_with_project?
158
      btn_class = "btn btn-default btn-#{btn_class}" unless btn_class.nil?
159
      link_to 'Cherry-pick', '#modal-cherry-pick-commit', 'data-toggle' => 'modal', 'data-container' => 'body', title: (tooltip if has_tooltip), class: "#{btn_class} #{'has-tooltip' if has_tooltip}"
160 161 162 163 164 165 166 167 168 169
    elsif can?(current_user, :fork_project, @project)
      continue_params = {
        to: continue_to_path,
        notice: edit_in_new_fork_notice + ' Try to cherry-pick this commit again.',
        notice_now: edit_in_new_fork_notice_now
      }
      fork_path = namespace_project_forks_path(@project.namespace, @project,
        namespace_key: current_user.namespace.id,
        continue: continue_params)

170 171
      btn_class = "btn btn-grouped btn-close" unless btn_class.nil?
      link_to 'Cherry-pick', fork_path, class: "#{btn_class}", method: :post, 'data-toggle' => 'tooltip', 'data-container' => 'body', title: (tooltip if has_tooltip)
172
    end
173 174
  end

175 176 177 178 179 180 181 182 183 184 185
  protected

  # Private: Returns a link to a person. If the person has a matching user and
  # is a member of the current @project it will link to the team member page.
  # Otherwise it will link to the person email as specified in the commit.
  #
  # options:
  #  source: one of :author or :committer
  #  avatar: true will prepend the avatar image
  #  size:   size of the avatar image in px
  def commit_person_link(commit, options = {})
186
    user = commit.send(options[:source])
187

188 189
    source_name = clean(commit.send "#{options[:source]}_name".to_sym)
    source_email = clean(commit.send "#{options[:source]}_email".to_sym)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
190

191
    person_name = user.try(:name) || source_name
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
192

193 194
    text =
      if options[:avatar]
Phil Hughes's avatar
Phil Hughes committed
195
        %Q{<span class="commit-#{options[:source]}-name">#{person_name}</span>}
196 197 198
      else
        person_name
      end
199

200
    options = {
201
      class: "commit-#{options[:source]}-link has-tooltip",
202
      title: source_email
203 204
    }

205
    if user.nil?
206
      mail_to(source_email, text.html_safe, options)
207
    else
208
      link_to(text.html_safe, user_path(user), options)
209 210
    end
  end
211

212
  def view_file_btn(commit_sha, diff_new_path, project)
Vinnie Okada's avatar
Vinnie Okada committed
213 214
    link_to(
      namespace_project_blob_path(project.namespace, project,
215
                                  tree_join(commit_sha, diff_new_path)),
Annabel Dunstone's avatar
Annabel Dunstone committed
216
      class: 'btn view-file js-view-file btn-file-option'
Vinnie Okada's avatar
Vinnie Okada committed
217
    ) do
skv's avatar
skv committed
218 219 220 221
      raw('View file @') + content_tag(:span, commit_sha[0..6],
                                       class: 'commit-short-id')
    end
  end
222 223 224 225

  def truncate_sha(sha)
    Commit.truncate_sha(sha)
  end
226 227 228 229

  def clean(string)
    Sanitize.clean(string, remove_contents: true)
  end
230 231 232 233 234 235 236 237 238 239 240

  def limited_commits(commits)
    if commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
      [
        commits.first(MergeRequestDiff::COMMITS_SAFE_SIZE),
        commits.size - MergeRequestDiff::COMMITS_SAFE_SIZE
      ]
    else
      [commits, 0]
    end
  end
gitlabhq's avatar
gitlabhq committed
241
end