Commit 2611d9f6 authored by Stan Hu's avatar Stan Hu

Add a system note and update relevant merge requests when a branch is deleted or re-added

If a branch is deleted with an open merge request, amended offline, and then pushed again,
GitLab doesn't bother to update the merge request even though the last commit ID and/or
code may have changed. This MR ensures that each push will update any relevant merge
requests and adds a system note if this happens as well.

Closes #2926
parent bd3689e9
......@@ -3,6 +3,7 @@ Please view this file on the master branch, on stable branches it's out of date.
v 8.1.0 (unreleased)
- Fix error preventing displaying of commit data for a directory with a leading dot (Stan Hu)
- Speed up load times of issue detail pages by roughly 1.5x
- Add a system note and update relevant merge requests when a branch is deleted or re-added (Stan Hu)
- Make diff file view easier to use on mobile screens (Stan Hu)
- Improved performance of finding users by username or Email address
- Fix bug where merge request comments created by API would not trigger notifications (Stan Hu)
......
......@@ -163,7 +163,8 @@ def compare_result
merge_request.fetch_ref
# Get latest sha of branch from source project
source_sha = merge_request.source_project.commit(source_branch).sha
source_commit = merge_request.source_project.commit(source_branch)
source_sha = source_commit.try(:sha)
Gitlab::CompareResult.new(
Gitlab::Git::Compare.new(
......
......@@ -49,10 +49,13 @@ def execute(project, user, oldrev, newrev, ref)
elsif push_to_existing_branch?(ref, oldrev)
# Collect data for this git push
@push_commits = project.repository.commits_between(oldrev, newrev)
project.update_merge_requests(oldrev, newrev, ref, @user)
process_commit_messages(ref)
end
# Update merge requests that may be affected by this push. A new branch
# could cause the last commit of a merge request to change.
project.update_merge_requests(oldrev, newrev, ref, @user)
@push_data = build_push_data(oldrev, newrev, ref)
# If CI was disabled but .gitlab-ci.yml file was pushed
......
......@@ -6,12 +6,22 @@ def execute(oldrev, newrev, ref)
@oldrev, @newrev = oldrev, newrev
@branch_name = Gitlab::Git.ref_name(ref)
@fork_merge_requests = @project.fork_merge_requests.opened
@commits = @project.repository.commits_between(oldrev, newrev)
@commits = []
@merge_requests = merge_requests_for_branch
# Leave a system note if a branch were deleted/added
if Gitlab::Git.blank_ref?(oldrev) or Gitlab::Git.blank_ref?(newrev)
presence = Gitlab::Git.blank_ref?(oldrev) ? 'added' : 'deleted'
comment_mr_branch_presence_changed(presence)
else
@commits = @project.repository.commits_between(oldrev, newrev)
close_merge_requests
comment_mr_with_commits
end
close_merge_requests
reload_merge_requests
execute_mr_web_hooks
comment_mr_with_commits
true
end
......@@ -31,7 +41,6 @@ def close_merge_requests
commit_ids.include?(merge_request.last_commit.id)
end
merge_requests.uniq.select(&:source_project).each do |merge_request|
MergeRequests::PostMergeService.
new(merge_request.target_project, @current_user).
......@@ -46,11 +55,7 @@ def force_push?
# Refresh merge request diff if we push to source or target branch of merge request
# Note: we should update merge requests from forks too
def reload_merge_requests
merge_requests = @project.merge_requests.opened.by_branch(@branch_name).to_a
merge_requests += @fork_merge_requests.by_branch(@branch_name).to_a
merge_requests = filter_merge_requests(merge_requests)
merge_requests.each do |merge_request|
@merge_requests.each do |merge_request|
if merge_request.source_branch == @branch_name || force_push?
merge_request.reload_code
......@@ -70,13 +75,20 @@ def reload_merge_requests
end
end
# Add comment about pushing new commits to merge requests
def comment_mr_with_commits
merge_requests = @project.origin_merge_requests.opened.where(source_branch: @branch_name).to_a
merge_requests += @fork_merge_requests.where(source_branch: @branch_name).to_a
merge_requests = filter_merge_requests(merge_requests)
# Add comment about branches being deleted or added to merge requests
def comment_mr_branch_presence_changed(presence)
merge_requests = merge_requests_for_branch
merge_requests.each do |merge_request|
SystemNoteService.change_branch_presence(
merge_request, merge_request.project, @current_user,
'source', @branch_name, presence)
end
end
# Add comment about pushing new commits to merge requests
def comment_mr_with_commits
@merge_requests.each do |merge_request|
mr_commit_ids = Set.new(merge_request.commits.map(&:id))
new_commits, existing_commits = @commits.partition do |commit|
......@@ -91,14 +103,7 @@ def comment_mr_with_commits
# Call merge request webhook with update branches
def execute_mr_web_hooks
merge_requests = @project.origin_merge_requests.opened
.where(source_branch: @branch_name)
.to_a
merge_requests += @fork_merge_requests.where(source_branch: @branch_name)
.to_a
merge_requests = filter_merge_requests(merge_requests)
merge_requests.each do |merge_request|
@merge_requests.each do |merge_request|
execute_hooks(merge_request, 'update')
end
end
......@@ -106,5 +111,11 @@ def execute_mr_web_hooks
def filter_merge_requests(merge_requests)
merge_requests.uniq.select(&:source_project)
end
def merge_requests_for_branch
merge_requests = @project.origin_merge_requests.opened.where(source_branch: @branch_name).to_a
merge_requests += @fork_merge_requests.where(source_branch: @branch_name).to_a
filter_merge_requests(merge_requests)
end
end
end
......@@ -168,6 +168,25 @@ def self.change_branch(noteable, project, author, branch_type, old_branch, new_b
create_note(noteable: noteable, project: project, author: author, note: body)
end
# Called when a branch in Noteable is added or deleted
#
# noteable - Noteable object
# project - Project owning noteable
# author - User performing the change
# branch_type - 'source' or 'target'
# branch - branch name
# presence - 'deleted' or 'created'
#
# Example Note text:
#
# "Target branch `feature` deleted"
#
# Returns the created Note object
def self.change_branch_presence(noteable, project, author, branch_type, branch, presence)
body = "#{branch_type} branch `#{branch}` #{presence}".capitalize
create_note(noteable: noteable, project: project, author: author, note: body)
end
# Called when a Mentionable references a Noteable
#
# noteable - Noteable object being referenced
......
......@@ -112,6 +112,14 @@
it { expect(@event.project).to eq(project) }
it { expect(@event.action).to eq(Event::PUSHED) }
it { expect(@event.data).to eq(service.push_data) }
context "Updates merge requests" do
it "when pushing a new branch for the first time" do
expect(project).to receive(:update_merge_requests).
with(@blankrev, 'newrev', 'refs/heads/master', user)
service.execute(project, user, @blankrev, 'newrev', 'refs/heads/master')
end
end
end
describe "Web Hooks" do
......
......@@ -106,6 +106,25 @@
it { expect(@fork_merge_request.notes).to be_empty }
end
context 'push new branch that exists in a merge request' do
let(:refresh_service) { service.new(@fork_project, @user) }
before do
allow(refresh_service).to receive(:execute_hooks)
refresh_service.execute(Gitlab::Git::BLANK_SHA, @newrev, 'refs/heads/master')
reload_mrs
end
it 'should execute hooks with update action' do
expect(refresh_service).to have_received(:execute_hooks).
with(@fork_merge_request, 'update')
end
it { expect(@merge_request.notes).to be_empty }
it { expect(@merge_request).to be_open }
it { expect(@fork_merge_request.notes.last.note).to include('Source branch `master` added') }
it { expect(@fork_merge_request).to be_open }
end
def reload_mrs
@merge_request.reload
@fork_merge_request.reload
......
......@@ -242,6 +242,18 @@
end
end
describe '.change_branch_presence' do
subject { described_class.change_branch_presence(noteable, project, author, 'source', 'feature', 'deleted') }
it_behaves_like 'a system note'
context 'when source branch deleted' do
it 'sets the note text' do
expect(subject.note).to eq "Source branch `feature` deleted"
end
end
end
describe '.cross_reference' do
subject { described_class.cross_reference(noteable, mentioner, author) }
......
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