Commit 0c4bb849 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge pull request #7762 from jubianchi/commit-closing-issues

Allow commit messages to close several issues at once
parents 1050f523 b21a2d82
...@@ -11,7 +11,7 @@ v 7.8.0 ...@@ -11,7 +11,7 @@ v 7.8.0
- -
- -
- -
- - Allow more variations for commit messages closing issues (Julien Bianchi and Hannes Rosenögger)
- -
- -
- -
......
...@@ -77,7 +77,7 @@ production: &base ...@@ -77,7 +77,7 @@ production: &base
# This happens when the commit is pushed or merged into the default branch of a project. # This happens when the commit is pushed or merged into the default branch of a project.
# When not specified the default issue_closing_pattern as specified below will be used. # When not specified the default issue_closing_pattern as specified below will be used.
# Tip: you can test your closing pattern at http://rubular.com # Tip: you can test your closing pattern at http://rubular.com
# issue_closing_pattern: '([Cc]lose[sd]|[Ff]ixe[sd]) #(\d+)' # issue_closing_pattern: '((?:[Cc]los(?:e[sd]|ing)|[Ff]ix(?:e[sd]|ing)?) +(?:(?:issues? +)?#\d+(?:(?:, *| +and +)?))+)'
## Default project features settings ## Default project features settings
default_projects_features: default_projects_features:
......
...@@ -109,7 +109,7 @@ Settings.gitlab['signup_enabled'] ||= true if Settings.gitlab['signup_enabled']. ...@@ -109,7 +109,7 @@ Settings.gitlab['signup_enabled'] ||= true if Settings.gitlab['signup_enabled'].
Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].nil? Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].nil?
Settings.gitlab['restricted_visibility_levels'] = Settings.send(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], []) Settings.gitlab['restricted_visibility_levels'] = Settings.send(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], [])
Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil? Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil?
Settings.gitlab['issue_closing_pattern'] = '([Cc]lose[sd]|[Ff]ixe[sd]) #(\d+)' if Settings.gitlab['issue_closing_pattern'].nil? Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]|ing)|[Ff]ix(?:e[sd]|ing)?) +(?:(?:issues? +)?#\d+(?:(?:, *| +and +)?))+)' if Settings.gitlab['issue_closing_pattern'].nil?
Settings.gitlab['default_projects_features'] ||= {} Settings.gitlab['default_projects_features'] ||= {}
Settings.gitlab['webhook_timeout'] ||= 10 Settings.gitlab['webhook_timeout'] ||= 10
Settings.gitlab.default_projects_features['issues'] = true if Settings.gitlab.default_projects_features['issues'].nil? Settings.gitlab.default_projects_features['issues'] = true if Settings.gitlab.default_projects_features['issues'].nil?
......
...@@ -3,14 +3,19 @@ module Gitlab ...@@ -3,14 +3,19 @@ module Gitlab
ISSUE_CLOSING_REGEX = Regexp.new(Gitlab.config.gitlab.issue_closing_pattern) ISSUE_CLOSING_REGEX = Regexp.new(Gitlab.config.gitlab.issue_closing_pattern)
def self.closed_by_message_in_project(message, project) def self.closed_by_message_in_project(message, project)
md = ISSUE_CLOSING_REGEX.match(message) issues = []
if md
unless message.nil?
md = message.scan(ISSUE_CLOSING_REGEX)
md.each do |ref|
extractor = Gitlab::ReferenceExtractor.new extractor = Gitlab::ReferenceExtractor.new
extractor.analyze(md[0], project) extractor.analyze(ref[0], project)
extractor.issues_for(project) issues += extractor.issues_for(project)
else
[]
end end
end end
issues.uniq
end
end end
end end
require 'spec_helper'
describe Gitlab::ClosingIssueExtractor do
let(:project) { create(:project) }
let(:issue) { create(:issue, project: project) }
let(:iid1) { issue.iid }
describe :closed_by_message_in_project do
context 'with a single reference' do
it do
message = "Awesome commit (Closes ##{iid1})"
subject.closed_by_message_in_project(message, project).should == [issue]
end
it do
message = "Awesome commit (closes ##{iid1})"
subject.closed_by_message_in_project(message, project).should == [issue]
end
it do
message = "Closed ##{iid1}"
subject.closed_by_message_in_project(message, project).should == [issue]
end
it do
message = "closed ##{iid1}"
subject.closed_by_message_in_project(message, project).should == [issue]
end
it do
message = "Awesome commit (fixes ##{iid1})"
subject.closed_by_message_in_project(message, project).should == [issue]
end
it do
message = "Awesome commit (fix ##{iid1})"
subject.closed_by_message_in_project(message, project).should == [issue]
end
end
context 'with multiple references' do
let(:other_issue) { create(:issue, project: project) }
let(:third_issue) { create(:issue, project: project) }
let(:iid2) { other_issue.iid }
let(:iid3) { third_issue.iid }
it 'fetches issues in single line message' do
message = "Closes ##{iid1} and fix ##{iid2}"
subject.closed_by_message_in_project(message, project).
should == [issue, other_issue]
end
it 'fetches comma-separated issues references in single line message' do
message = "Closes ##{iid1}, closes ##{iid2}"
subject.closed_by_message_in_project(message, project).
should == [issue, other_issue]
end
it 'fetches comma-separated issues numbers in single line message' do
message = "Closes ##{iid1}, ##{iid2} and ##{iid3}"
subject.closed_by_message_in_project(message, project).
should == [issue, other_issue, third_issue]
end
it 'fetches issues in multi-line message' do
message = "Awesome commit (closes ##{iid1})\nAlso fixes ##{iid2}"
subject.closed_by_message_in_project(message, project).
should == [issue, other_issue]
end
it 'fetches issues in hybrid message' do
message = "Awesome commit (closes ##{iid1})\n"\
"Also fixing issues ##{iid2}, ##{iid3} and #4"
subject.closed_by_message_in_project(message, project).
should == [issue, other_issue, third_issue]
end
end
end
end
...@@ -57,16 +57,12 @@ eos ...@@ -57,16 +57,12 @@ eos
let(:other_issue) { create :issue, project: other_project } let(:other_issue) { create :issue, project: other_project }
it 'detects issues that this commit is marked as closing' do it 'detects issues that this commit is marked as closing' do
stub_const('Gitlab::ClosingIssueExtractor::ISSUE_CLOSING_REGEX',
/Fixes #\d+/)
commit.stub(safe_message: "Fixes ##{issue.iid}") commit.stub(safe_message: "Fixes ##{issue.iid}")
commit.closes_issues(project).should == [issue] commit.closes_issues(project).should == [issue]
end end
it 'does not detect issues from other projects' do it 'does not detect issues from other projects' do
ext_ref = "#{other_project.path_with_namespace}##{other_issue.iid}" ext_ref = "#{other_project.path_with_namespace}##{other_issue.iid}"
stub_const('Gitlab::ClosingIssueExtractor::ISSUE_CLOSING_REGEX',
/^([Cc]loses|[Ff]ixes)/)
commit.stub(safe_message: "Fixes #{ext_ref}") commit.stub(safe_message: "Fixes #{ext_ref}")
commit.closes_issues(project).should be_empty commit.closes_issues(project).should be_empty
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment