Skip to content
Snippets Groups Projects
Commit 4dddaef8 authored by Douwe Maan's avatar Douwe Maan
Browse files

Automatically link commit ranges to compare page.

parent 0625d68f
No related branches found
No related tags found
No related merge requests found
Loading
@@ -27,6 +27,7 @@ v 7.9.0 (unreleased)
Loading
@@ -27,6 +27,7 @@ v 7.9.0 (unreleased)
- Add Bitbucket omniauth provider. - Add Bitbucket omniauth provider.
- Add Bitbucket importer. - Add Bitbucket importer.
- Support referencing issues to a project whose name starts with a digit - Support referencing issues to a project whose name starts with a digit
- Automatically link commit ranges to compare page: sha1...sha4 or sha1..sha4 (includes sha1 in comparison)
   
v 7.8.2 v 7.8.2
- Fix service migration issue when upgrading from versions prior to 7.3 - Fix service migration issue when upgrading from versions prior to 7.3
Loading
Loading
Loading
@@ -14,6 +14,7 @@ module Gitlab
Loading
@@ -14,6 +14,7 @@ module Gitlab
# * !123 for merge requests # * !123 for merge requests
# * $123 for snippets # * $123 for snippets
# * 123456 for commits # * 123456 for commits
# * 123456...7890123 for commit ranges (comparisons)
# #
# It also parses Emoji codes to insert images. See # It also parses Emoji codes to insert images. See
# http://www.emoji-cheat-sheet.com/ for a list of the supported icons. # http://www.emoji-cheat-sheet.com/ for a list of the supported icons.
Loading
@@ -133,13 +134,14 @@ module Gitlab
Loading
@@ -133,13 +134,14 @@ module Gitlab
|#{PROJ_STR}?\#(?<issue>([a-zA-Z\-]+-)?\d+) # Issue ID |#{PROJ_STR}?\#(?<issue>([a-zA-Z\-]+-)?\d+) # Issue ID
|#{PROJ_STR}?!(?<merge_request>\d+) # MR ID |#{PROJ_STR}?!(?<merge_request>\d+) # MR ID
|\$(?<snippet>\d+) # Snippet ID |\$(?<snippet>\d+) # Snippet ID
|(#{PROJ_STR}@)?(?<commit_range>[\h]{6,40}\.{2,3}[\h]{6,40}) # Commit range
|(#{PROJ_STR}@)?(?<commit>[\h]{6,40}) # Commit ID |(#{PROJ_STR}@)?(?<commit>[\h]{6,40}) # Commit ID
|(?<skip>gfm-extraction-[\h]{6,40}) # Skip gfm extractions. Otherwise will be parsed as commit |(?<skip>gfm-extraction-[\h]{6,40}) # Skip gfm extractions. Otherwise will be parsed as commit
) )
(?<suffix>\W)? # Suffix (?<suffix>\W)? # Suffix
}x.freeze }x.freeze
   
TYPES = [:user, :issue, :label, :merge_request, :snippet, :commit].freeze TYPES = [:user, :issue, :label, :merge_request, :snippet, :commit, :commit_range].freeze
   
def parse_references(text, project = @project) def parse_references(text, project = @project)
# parse reference links # parse reference links
Loading
@@ -290,6 +292,30 @@ module Gitlab
Loading
@@ -290,6 +292,30 @@ module Gitlab
end end
end end
   
def reference_commit_range(identifier, project = @project, prefix_text = nil)
from_id, to_id = identifier.split(/\.{2,3}/, 2)
inclusive = identifier !~ /\.{3}/
from_id << "^" if inclusive
if project.valid_repo? &&
from = project.repository.commit(from_id) &&
to = project.repository.commit(to_id)
options = html_options.merge(
title: "Commits #{from_id} through #{to_id}",
class: "gfm gfm-commit_range #{html_options[:class]}"
)
prefix_text = "#{prefix_text}@" if prefix_text
link_to(
"#{prefix_text}#{identifier}",
namespace_project_compare_url(project.namespace, project, from: from_id, to: to_id),
options
)
end
end
def reference_external_issue(identifier, project = @project, def reference_external_issue(identifier, project = @project,
prefix_text = nil) prefix_text = nil)
url = url_for_issue(identifier, project) url = url_for_issue(identifier, project)
Loading
Loading
module Gitlab module Gitlab
# Extract possible GFM references from an arbitrary String for further processing. # Extract possible GFM references from an arbitrary String for further processing.
class ReferenceExtractor class ReferenceExtractor
attr_accessor :users, :labels, :issues, :merge_requests, :snippets, :commits attr_accessor :users, :labels, :issues, :merge_requests, :snippets, :commits, :commit_ranges
   
include Markdown include Markdown
   
def initialize def initialize
@users, @labels, @issues, @merge_requests, @snippets, @commits = @users, @labels, @issues, @merge_requests, @snippets, @commits, @commit_ranges =
[], [], [], [], [], [] [], [], [], [], [], [], []
end end
   
def analyze(string, project) def analyze(string, project)
Loading
@@ -60,6 +60,16 @@ module Gitlab
Loading
@@ -60,6 +60,16 @@ module Gitlab
end.reject(&:nil?) end.reject(&:nil?)
end end
   
def commit_ranges_for(project = nil)
commit_ranges.map do |entry|
repo = entry[:project].repository if entry[:project]
if repo && should_lookup?(project, entry[:project])
from_id, to_id = entry[:id].split(/\.{2,3}/, 2)
[repo.commit(from_id), repo.commit(to_id)]
end
end.reject(&:nil?)
end
private private
   
def reference_link(type, identifier, project, _) def reference_link(type, identifier, project, _)
Loading
Loading
Loading
@@ -9,6 +9,7 @@ describe GitlabMarkdownHelper do
Loading
@@ -9,6 +9,7 @@ describe GitlabMarkdownHelper do
   
let(:user) { create(:user, username: 'gfm') } let(:user) { create(:user, username: 'gfm') }
let(:commit) { project.repository.commit } let(:commit) { project.repository.commit }
let(:earlier_commit){ project.repository.commit("HEAD~2") }
let(:issue) { create(:issue, project: project) } let(:issue) { create(:issue, project: project) }
let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
let(:snippet) { create(:project_snippet, project: project) } let(:snippet) { create(:project_snippet, project: project) }
Loading
@@ -53,6 +54,53 @@ describe GitlabMarkdownHelper do
Loading
@@ -53,6 +54,53 @@ describe GitlabMarkdownHelper do
to have_selector('a.gfm.foo') to have_selector('a.gfm.foo')
end end
   
describe "referencing a commit range" do
let(:expected) { namespace_project_compare_path(project.namespace, project, from: earlier_commit.id, to: commit.id) }
it "should link using a full id" do
actual = "What happened in #{earlier_commit.id}...#{commit.id}"
expect(gfm(actual)).to match(expected)
end
it "should link using a short id" do
actual = "What happened in #{earlier_commit.short_id}...#{commit.short_id}"
expected = namespace_project_compare_path(project.namespace, project, from: earlier_commit.short_id, to: commit.short_id)
expect(gfm(actual)).to match(expected)
end
it "should link inclusively" do
actual = "What happened in #{earlier_commit.id}..#{commit.id}"
expected = namespace_project_compare_path(project.namespace, project, from: "#{earlier_commit.id}^", to: commit.id)
expect(gfm(actual)).to match(expected)
end
it "should link with adjacent text" do
actual = "(see #{earlier_commit.id}...#{commit.id})"
expect(gfm(actual)).to match(expected)
end
it "should keep whitespace intact" do
actual = "Changes #{earlier_commit.id}...#{commit.id} dramatically"
expected = /Changes <a.+>#{earlier_commit.id}...#{commit.id}<\/a> dramatically/
expect(gfm(actual)).to match(expected)
end
it "should not link with an invalid id" do
actual = expected = "What happened in #{earlier_commit.id.reverse}...#{commit.id.reverse}"
expect(gfm(actual)).to eq(expected)
end
it "should include a title attribute" do
actual = "What happened in #{earlier_commit.id}...#{commit.id}"
expect(gfm(actual)).to match(/title="Commits #{earlier_commit.id} through #{commit.id}"/)
end
it "should include standard gfm classes" do
actual = "What happened in #{earlier_commit.id}...#{commit.id}"
expect(gfm(actual)).to match(/class="\s?gfm gfm-commit_range\s?"/)
end
end
describe "referencing a commit" do describe "referencing a commit" do
let(:expected) { namespace_project_commit_path(project.namespace, project, commit) } let(:expected) { namespace_project_commit_path(project.namespace, project, commit) }
   
Loading
Loading
Loading
@@ -31,6 +31,11 @@ describe Gitlab::ReferenceExtractor do
Loading
@@ -31,6 +31,11 @@ describe Gitlab::ReferenceExtractor do
expect(subject.commits).to eq([{ project: nil, id: '98cf0ae3' }]) expect(subject.commits).to eq([{ project: nil, id: '98cf0ae3' }])
end end
   
it 'extracts commit ranges' do
subject.analyze('here you go, a commit range: 98cf0ae3...98cf0ae4', nil)
expect(subject.commit_ranges).to eq([{ project: nil, id: '98cf0ae3...98cf0ae4' }])
end
it 'extracts multiple references and preserves their order' do it 'extracts multiple references and preserves their order' do
subject.analyze('@me and @you both care about this', nil) subject.analyze('@me and @you both care about this', nil)
expect(subject.users).to eq([ expect(subject.users).to eq([
Loading
@@ -100,5 +105,19 @@ describe Gitlab::ReferenceExtractor do
Loading
@@ -100,5 +105,19 @@ describe Gitlab::ReferenceExtractor do
expect(extracted[0].sha).to eq(commit.sha) expect(extracted[0].sha).to eq(commit.sha)
expect(extracted[0].message).to eq(commit.message) expect(extracted[0].message).to eq(commit.message)
end end
it 'accesses valid commit ranges' do
commit = project.repository.commit('master')
earlier_commit = project.repository.commit('master~2')
subject.analyze("this references commits #{earlier_commit.sha[0..6]}...#{commit.sha[0..6]}",
project)
extracted = subject.commit_ranges_for(project)
expect(extracted.size).to eq(1)
expect(extracted[0][0].sha).to eq(earlier_commit.sha)
expect(extracted[0][0].message).to eq(earlier_commit.message)
expect(extracted[0][1].sha).to eq(commit.sha)
expect(extracted[0][1].message).to eq(commit.message)
end
end end
end end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment