Commit 70b05a83 authored by Douwe Maan's avatar Douwe Maan

Split up MergeRequestsController

parent 92f87f6d
...@@ -209,8 +209,8 @@ import initExperimentalFlags from './experimental_flags'; ...@@ -209,8 +209,8 @@ import initExperimentalFlags from './experimental_flags';
new MilestoneSelect(); new MilestoneSelect();
new gl.IssuableTemplateSelectors(); new gl.IssuableTemplateSelectors();
break; break;
case 'projects:merge_requests:new': case 'projects:merge_requests:creations:new':
case 'projects:merge_requests:new_diffs': case 'projects:merge_requests:creations:diffs':
case 'projects:merge_requests:edit': case 'projects:merge_requests:edit':
new gl.Diff(); new gl.Diff();
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
...@@ -247,10 +247,6 @@ import initExperimentalFlags from './experimental_flags'; ...@@ -247,10 +247,6 @@ import initExperimentalFlags from './experimental_flags';
shortcut_handler = new ShortcutsIssuable(true); shortcut_handler = new ShortcutsIssuable(true);
new ZenMode(); new ZenMode();
break; break;
case "projects:merge_requests:diffs":
new gl.Diff();
new ZenMode();
break;
case 'dashboard:activity': case 'dashboard:activity':
new gl.Activities(); new gl.Activities();
break; break;
...@@ -319,7 +315,7 @@ import initExperimentalFlags from './experimental_flags'; ...@@ -319,7 +315,7 @@ import initExperimentalFlags from './experimental_flags';
new gl.Members(); new gl.Members();
new UsersSelect(); new UsersSelect();
break; break;
case 'projects:members:show': case 'projects:settings:members:show':
new gl.MemberExpirationDate('.js-access-expiration-date-groups'); new gl.MemberExpirationDate('.js-access-expiration-date-groups');
new GroupsSelect(); new GroupsSelect();
new gl.MemberExpirationDate(); new gl.MemberExpirationDate();
...@@ -386,7 +382,7 @@ import initExperimentalFlags from './experimental_flags'; ...@@ -386,7 +382,7 @@ import initExperimentalFlags from './experimental_flags';
case 'search:show': case 'search:show':
new Search(); new Search();
break; break;
case 'projects:repository:show': case 'projects:settings:repository:show':
// Initialize Protected Branch Settings // Initialize Protected Branch Settings
new gl.ProtectedBranchCreate(); new gl.ProtectedBranchCreate();
new gl.ProtectedBranchEditList(); new gl.ProtectedBranchEditList();
...@@ -396,7 +392,7 @@ import initExperimentalFlags from './experimental_flags'; ...@@ -396,7 +392,7 @@ import initExperimentalFlags from './experimental_flags';
// Initialize expandable settings panels // Initialize expandable settings panels
initSettingsPanels(); initSettingsPanels();
break; break;
case 'projects:ci_cd:show': case 'projects:settings:ci_cd:show':
new gl.ProjectVariables(); new gl.ProjectVariables();
break; break;
case 'ci:lints:create': case 'ci:lints:create':
......
...@@ -168,9 +168,8 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion'; ...@@ -168,9 +168,8 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion';
// Activate a tab based on the current action // Activate a tab based on the current action
activateTab(action) { activateTab(action) {
const activate = action === 'show' ? 'notes' : action;
// important note: the .tab('show') method triggers 'shown.bs.tab' event itself // important note: the .tab('show') method triggers 'shown.bs.tab' event itself
$(`.merge-request-tabs a[data-action='${activate}']`).tab('show'); $(`.merge-request-tabs a[data-action='${action}']`).tab('show');
} }
// Replaces the current Merge Request-specific action in the URL with a new one // Replaces the current Merge Request-specific action in the URL with a new one
...@@ -185,7 +184,7 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion'; ...@@ -185,7 +184,7 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion';
// location.pathname # => "/namespace/project/merge_requests/1/diffs" // location.pathname # => "/namespace/project/merge_requests/1/diffs"
// //
// location.pathname # => "/namespace/project/merge_requests/1/diffs" // location.pathname # => "/namespace/project/merge_requests/1/diffs"
// setCurrentAction('notes') // setCurrentAction('show')
// location.pathname # => "/namespace/project/merge_requests/1" // location.pathname # => "/namespace/project/merge_requests/1"
// //
// location.pathname # => "/namespace/project/merge_requests/1/diffs" // location.pathname # => "/namespace/project/merge_requests/1/diffs"
...@@ -194,13 +193,13 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion'; ...@@ -194,13 +193,13 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion';
// //
// Returns the new URL String // Returns the new URL String
setCurrentAction(action) { setCurrentAction(action) {
this.currentAction = action === 'show' ? 'notes' : action; this.currentAction = action;
// Remove a trailing '/commits' '/diffs' '/pipelines' '/new' '/new/diffs' // Remove a trailing '/commits' '/diffs' '/pipelines'
let newState = location.pathname.replace(/\/(commits|diffs|pipelines|new|new\/diffs)(\.html)?\/?$/, ''); let newState = location.pathname.replace(/\/(commits|diffs|pipelines)(\.html)?\/?$/, '');
// Append the new action if we're on a tab other than 'notes' // Append the new action if we're on a tab other than 'notes'
if (this.currentAction !== 'notes') { if (this.currentAction !== 'show' && this.currentAction !== 'new') {
newState += `/${this.currentAction}`; newState += `/${this.currentAction}`;
} }
......
...@@ -78,7 +78,7 @@ module CreatesCommit ...@@ -78,7 +78,7 @@ module CreatesCommit
end end
def new_merge_request_path def new_merge_request_path
new_namespace_project_merge_request_path( namespace_project_new_merge_request_path(
@project_to_commit_into.namespace, @project_to_commit_into.namespace,
@project_to_commit_into, @project_to_commit_into,
merge_request: { merge_request: {
......
class Projects::MergeRequests::ApplicationController < Projects::ApplicationController
before_action :check_merge_requests_available!
before_action :merge_request
before_action :authorize_read_merge_request!
before_action :ensure_ref_fetched
private
def merge_request
@issuable = @merge_request ||= @project.merge_requests.find_by!(iid: params[:id])
end
# Make sure merge requests created before 8.0
# have head file in refs/merge-requests/
def ensure_ref_fetched
@merge_request.ensure_ref_fetched
end
def merge_request_params
params.require(:merge_request)
.permit(merge_request_params_attributes)
end
def merge_request_params_attributes
[
:assignee_id,
:description,
:force_remove_source_branch,
:lock_version,
:milestone_id,
:source_branch,
:source_project_id,
:state_event,
:target_branch,
:target_project_id,
:task_num,
:title,
label_ids: []
]
end
def set_pipeline_variables
@pipelines = @merge_request.all_pipelines
@pipeline = @merge_request.head_pipeline
@statuses_count = @pipeline.present? ? @pipeline.statuses.relevant.count : 0
end
end
class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::ApplicationController
include IssuableActions
before_action :authorize_can_resolve_conflicts!
def show
respond_to do |format|
format.html do
labels
end
format.json do
if @conflicts_list.can_be_resolved_in_ui?
render json: @conflicts_list
elsif @merge_request.can_be_merged?
render json: {
message: 'The merge conflicts for this merge request have already been resolved. Please return to the merge request.',
type: 'error'
}
else
render json: {
message: 'The merge conflicts for this merge request cannot be resolved through GitLab. Please try to resolve them locally.',
type: 'error'
}
end
end
end
end
def conflict_for_path
return render_404 unless @conflicts_list.can_be_resolved_in_ui?
file = @conflicts_list.file_for_path(params[:old_path], params[:new_path])
return render_404 unless file
render json: file, full_content: true
end
def resolve_conflicts
return render_404 unless @conflicts_list.can_be_resolved_in_ui?
if @merge_request.can_be_merged?
render status: :bad_request, json: { message: 'The merge conflicts for this merge request have already been resolved.' }
return
end
begin
::MergeRequests::Conflicts::ResolveService
.new(merge_request)
.execute(current_user, params)
flash[:notice] = 'All merge conflicts were resolved. The merge request can now be merged.'
render json: { redirect_to: namespace_project_merge_request_url(@project.namespace, @project, @merge_request, resolved_conflicts: true) }
rescue Gitlab::Conflict::ResolutionError => e
render status: :bad_request, json: { message: e.message }
end
end
def authorize_can_resolve_conflicts!
@conflicts_list = ::MergeRequests::Conflicts::ListService.new(@merge_request)
return render_404 unless @conflicts_list.can_be_resolved_by?(current_user)
end
end
class Projects::MergeRequests::CreationsController < Projects::MergeRequests::ApplicationController
include DiffForPath
include DiffHelper
skip_before_action :merge_request
skip_before_action :ensure_ref_fetched
before_action :authorize_create_merge_request!
before_action :apply_diff_view_cookie!, only: [:diffs, :diff_for_path]
before_action :build_merge_request, except: [:create]
def new
define_new_vars
end
def create
@target_branches ||= []
@merge_request = ::MergeRequests::CreateService.new(project, current_user, merge_request_params).execute
if @merge_request.valid?
redirect_to(merge_request_path(@merge_request))
else
@source_project = @merge_request.source_project
@target_project = @merge_request.target_project
define_new_vars
render action: "new"
end
end
def pipelines
@pipelines = @merge_request.all_pipelines
Gitlab::PollingInterval.set_header(response, interval: 10_000)
render json: {
pipelines: PipelineSerializer
.new(project: @project, current_user: @current_user)
.represent(@pipelines)
}
end
def diffs
@diffs = if @merge_request.can_be_created
@merge_request.diffs(diff_options)
else
[]
end
@diff_notes_disabled = true
@environment = @merge_request.environments_for(current_user).last
render json: { html: view_to_html_string('projects/merge_requests/creations/_diffs', diffs: @diffs, environment: @environment) }
end
def diff_for_path
@diffs = @merge_request.diffs(diff_options)
@diff_notes_disabled = true
render_diff_for_path(@diffs)
end
def branch_from
# This is always source
@source_project = @merge_request.nil? ? @project : @merge_request.source_project
if params[:ref].present?
@ref = params[:ref]
@commit = @repository.commit("refs/heads/#{@ref}")
end
render layout: false
end
def branch_to
@target_project = selected_target_project
if params[:ref].present?
@ref = params[:ref]
@commit = @target_project.commit("refs/heads/#{@ref}")
end
render layout: false
end
def update_branches
@target_project = selected_target_project
@target_branches = @target_project.repository.branch_names
render layout: false
end
private
def build_merge_request
params[:merge_request] ||= ActionController::Parameters.new(source_project: @project)
@merge_request = ::MergeRequests::BuildService.new(project, current_user, merge_request_params.merge(diff_options: diff_options)).execute
end
def define_new_vars
@noteable = @merge_request
@target_branches = if @merge_request.target_project
@merge_request.target_project.repository.branch_names
else
[]
end
@target_project = @merge_request.target_project
@source_project = @merge_request.source_project
@commits = @merge_request.compare_commits.reverse
@commit = @merge_request.diff_head_commit
@note_counts = Note.where(commit_id: @commits.map(&:id))
.group(:commit_id).count
@labels = LabelsFinder.new(current_user, project_id: @project.id).execute
set_pipeline_variables
end
def selected_target_project
if @project.id.to_s == params[:target_project_id] || @project.forked_project_link.nil?
@project
else
@project.forked_project_link.forked_from_project
end
end
end
class Projects::MergeRequests::DiffsController < Projects::MergeRequests::ApplicationController
include DiffForPath
include DiffHelper
include RendersNotes
before_action :apply_diff_view_cookie!
before_action :define_diff_vars
before_action :define_diff_comment_vars
def show
@environment = @merge_request.environments_for(current_user).last
render json: { html: view_to_html_string("projects/merge_requests/diffs/_diffs") }
end
def diff_for_path
render_diff_for_path(@diffs)
end
private
def define_diff_vars
@merge_request_diff =
if params[:diff_id]
@merge_request.merge_request_diffs.viewable.find(params[:diff_id])
else
@merge_request.merge_request_diff
end
@merge_request_diffs = @merge_request.merge_request_diffs.viewable.select_without_diff
@comparable_diffs = @merge_request_diffs.select { |diff| diff.id < @merge_request_diff.id }
if params[:start_sha].present?
@start_sha = params[:start_sha]
@start_version = @comparable_diffs.find { |diff| diff.head_commit_sha == @start_sha }
unless @start_version
@start_sha = @merge_request_diff.head_commit_sha
@start_version = @merge_request_diff
end
end
@compare =
if @start_sha
@merge_request_diff.compare_with(@start_sha)
else
@merge_request_diff
end
@diffs = @compare.diffs(diff_options)
end
def define_diff_comment_vars
@new_diff_note_attrs = {
noteable_type: 'MergeRequest',
noteable_id: @merge_request.id
}
@diff_notes_disabled = false
@use_legacy_diff_notes = !@merge_request.has_complete_diff_refs?
@grouped_diff_discussions = @merge_request.grouped_diff_discussions(@compare.diff_refs)
@notes = prepare_notes_for_rendering(@grouped_diff_discussions.values.flatten.flat_map(&:notes))
end
end
class Projects::MergeRequestsController < Projects::ApplicationController class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationController
include ToggleSubscriptionAction include ToggleSubscriptionAction
include DiffForPath
include DiffHelper
include IssuableActions include IssuableActions
include RendersNotes include RendersNotes
include ToggleAwardEmoji include ToggleAwardEmoji
include IssuableCollections include IssuableCollections
before_action :check_merge_requests_available! skip_before_action :merge_request, only: [:index, :bulk_update]
before_action :merge_request, only: [ skip_before_action :ensure_ref_fetched, only: [:index, :bulk_update]
:edit, :update, :show, :diffs, :commits, :conflicts, :conflict_for_path, :pipelines, :merge,
:pipeline_status, :ci_environments_status, :toggle_subscription, :cancel_merge_when_pipeline_succeeds, :remove_wip, :resolve_conflicts, :assign_related_issues, :commit_change_content
]
before_action :validates_merge_request, only: [:show, :diffs, :commits, :pipelines]
before_action :define_show_vars, only: [:diffs, :commits, :conflicts, :conflict_for_path, :builds, :pipelines]
before_action :ensure_ref_fetched, only: [:show, :diffs, :commits, :builds, :conflicts, :conflict_for_path, :pipelines]
before_action :close_merge_request_without_source_project, only: [:show, :diffs, :commits, :builds, :pipelines]
before_action :check_if_can_be_merged, only: :show
before_action :apply_diff_view_cookie!, only: [:new_diffs]
before_action :build_merge_request, only: [:new, :new_diffs]
# Allow read any merge_request
before_action :authorize_read_merge_request!
# Allow write(create) merge_request
before_action :authorize_create_merge_request!, only: [:new, :create]
# Allow modify merge_request
before_action :authorize_update_merge_request!, only: [:close, :edit, :update, :remove_wip, :sort] before_action :authorize_update_merge_request!, only: [:close, :edit, :update, :remove_wip, :sort]
before_action :authenticate_user!, only: [:assign_related_issues] before_action :authenticate_user!, only: [:assign_related_issues]
before_action :authorize_can_resolve_conflicts!, only: [:conflicts, :conflict_for_path, :resolve_conflicts]
def index def index
@collection_type = "MergeRequest" @collection_type = "MergeRequest"
@merge_requests = merge_requests_collection @merge_requests = merge_requests_collection
...@@ -72,10 +51,30 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -72,10 +51,30 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def show def show
validates_merge_request
ensure_ref_fetched
close_merge_request_without_source_project
check_if_can_be_merged
respond_to do |format| respond_to do |format|
format.html do format.html do
define_discussion_vars # Build a note object for comment form
define_show_vars @note = @project.notes.new(noteable: @merge_request)
@discussions = @merge_request.discussions
@notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes))
@noteable = @merge_request
@commits_count = @merge_request.commits_count
if @merge_request.locked_long_ago?
@merge_request.unlock_mr
@merge_request.close
end
labels
set_pipeline_variables
end end
format.json do format.json do
...@@ -98,198 +97,40 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -98,198 +97,40 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
end end
def diffs
apply_diff_view_cookie!
respond_to do |format|
format.html { define_discussion_vars }
format.json do
define_diff_vars
define_diff_comment_vars
@environment = @merge_request.environments_for(current_user).last
render json: { html: view_to_html_string("projects/merge_requests/show/_diffs") }
end
end
end
# With an ID param, loads the MR at that ID. Otherwise, accepts the same params as #new
# and uses that (unsaved) MR.
#
def diff_for_path
if params[:id]
merge_request
define_diff_vars
define_diff_comment_vars
else
build_merge_request
@compare = @merge_request
@diffs = @compare.diffs(diff_options)
@diff_notes_disabled = true
end
render_diff_for_path(@diffs)
end
def commits def commits
respond_to do |format|
format.html do
define_discussion_vars
render 'show'
end
format.json do
# Get commits from repository # Get commits from repository
# or from cache if already merged # or from cache if already merged
@commits = @merge_request.commits @commits = @merge_request.commits
@note_counts = Note.where(commit_id: @commits.map(&:id)) @note_counts = Note.where(commit_id: @commits.map(&:id))
.group(:commit_id).count .group(:commit_id).count
render json: { html: view_to_html_string('projects/merge_requests/show/_commits') } render json: { html: view_to_html_string('projects/merge_requests/_commits') }
end
end
end
def conflicts
respond_to do |format|
format.html { define_discussion_vars }
format.json do
if @conflicts_list.can_be_resolved_in_ui?
render json: @conflicts_list
elsif @merge_request.can_be_merged?
render json: {
message: 'The merge conflicts for this merge request have already been resolved. Please return to the merge request.',
type: 'error'
}
else
render json: {
message: 'The merge conflicts for this merge request cannot be resolved through GitLab. Please try to resolve them locally.',
type: 'error'
}
end
end
end
end
def conflict_for_path
return render_404 unless @conflicts_list.can_be_resolved_in_ui?
file = @conflicts_list.file_for_path(params[:old_path], params[:new_path])
return render_404 unless file
render json: file, full_content: true
end
def resolve_conflicts
return render_404 unless @conflicts_list.can_be_resolved_in_ui?
if @merge_request.can_be_merged?
render status: :bad_request, json: { message: 'The merge conflicts for this merge request have already been resolved.' }
return
end
begin
MergeRequests::Conflicts::ResolveService
.new(merge_request)
.execute(current_user, params)
flash[:notice] = 'All merge conflicts were resolved. The merge request can now be merged.'
render json: { redirect_to: namespace_project_merge_request_url(@project.namespace, @project, @merge_request, resolved_conflicts: true) }
rescue Gitlab::Conflict::ResolutionError => e
render status: :bad_request, json: { message: e.message }
end
end end
def pipelines def pipelines
@pipelines = @merge_request.all_pipelines @pipelines = @merge_request.all_pipelines
respond_to do |format|
format.html do
define_discussion_vars
render 'show'
end
format.json do
Gitlab::PollingInterval.set_header(response, interval: 10_000) Gitlab::PollingInterval.set_header(response, interval: 10_000)
render json: PipelineSerializer render json: PipelineSerializer
.new(project: @project, current_user: @current_user) .new(project: @project, current_user: @current_user)
.represent(@pipelines) .represent(@pipelines)
end end
end
end
def new
respond_to do |format|
format.html { define_new_vars }
format.json do
define_pipelines_vars
Gitlab::PollingInterval.set_header(response, interval: 10_000)
render json: {
pipelines: PipelineSerializer
.new(project: @project, current_user: @current_user)
.represent(@pipelines)
}
end
end
end
def new_diffs
respond_to do |format|
format.html do
define_new_vars
@show_changes_tab = true
render "new"
end
format.json do
@diffs = if @merge_request.can_be_created
@merge_request.diffs(diff_options)
else
[]
end
@diff_notes_disabled = true
@environment = @merge_request.environments_for(current_user).last
render json: { html: view_to_html_string('projects/merge_requests/_new_diffs', diffs: @diffs, environment: @environment) }
end
end
end
def create
@target_branches ||= []
@merge_request = MergeRequests::CreateService.new(project, current_user, merge_request_params).execute
if @merge_request.valid?
redirect_to(merge_request_path(@merge_request))
else
@source_project = @merge_request.source_project
@target_project = @merge_request.target_project
render action: "new"
end
end
def edit def edit
@source_project = @merge_request.source_project define_edit_vars
@target_project = @merge_request.target_project
@target_branches = @merge_request.target_project.repository.branch_names
end end
def update def update
@merge_request = MergeRequests::UpdateService.new(project, current_user, merge_request_params).execute(@merge_request) @merge_request = ::MergeRequests::UpdateService.new(project, current_user, merge_request_params).execute(@merge_request)
respond_to do |format| respond_to do |format|
format.html do format.html do
if @merge_request.valid? if @merge_request.valid?
redirect_to([@merge_request.target_project.namespace.becomes(Namespace), @merge_request.target_project, @merge_request]) redirect_to([@merge_request.target_project.namespace.becomes(Namespace), @merge_request.target_project, @merge_request])
else else
define_edit_vars
render :edit render :edit
end end
end end
...@@ -299,11 +140,13 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -299,11 +140,13 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
end end
rescue ActiveRecord::StaleObjectError rescue ActiveRecord::StaleObjectError
define_edit_vars if request.format.html?
render_conflict_response render_conflict_response
end end
def remove_wip def remove_wip
@merge_request = MergeRequests::UpdateService @merge_request = ::MergeRequests::UpdateService
.new(project, current_user, wip_event: 'unwip') .new(project, current_user, wip_event: 'unwip')
.execute(@merge_request) .execute(@merge_request)
...@@ -319,7 +162,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -319,7 +162,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
return access_denied! return access_denied!
end end
MergeRequests::MergeWhenPipelineSucceedsService ::MergeRequests::MergeWhenPipelineSucceedsService
.new(@project, current_user) .new(@project, current_user)
.cancel(@merge_request) .cancel(@merge_request)
...@@ -338,41 +181,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -338,41 +181,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
end end
def branch_from
# This is always source
@source_project = @merge_request.nil? ? @project : @merge_request.source_project
if params[:ref].present?
@ref = params[:ref]
@commit = @repository.commit("refs/heads/#{@ref}")
end
render layout: false
end
def branch_to
@target_project = selected_target_project
if params[:ref].present?
@ref = params[:ref]
@commit = @target_project.commit("refs/heads/#{@ref}")
end
render layout: false
end
def update_branches
@target_project = selected_target_project
@target_branches = @target_project.repository.branch_names
render layout: false
end
def assign_related_issues def assign_related_issues
result = MergeRequests::AssignIssuesService.new(project, current_user, merge_request: @merge_request).execute result = ::MergeRequests::AssignIssuesService.new(project, current_user, merge_request: @merge_request).execute
respond_to do |format|
format.html do
case result[:count] case result[:count]
when 0 when 0
flash[:error] = "Failed to assign you issues related to the merge request" flash[:error] = "Failed to assign you issues related to the merge request"
...@@ -384,8 +195,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -384,8 +195,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
redirect_to(merge_request_path(@merge_request)) redirect_to(merge_request_path(@merge_request))
end end
end
end
def pipeline_status def pipeline_status
render json: PipelineSerializer render json: PipelineSerializer
...@@ -432,17 +241,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -432,17 +241,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
protected protected
def selected_target_project
if @project.id.to_s == params[:target_project_id] || @project.forked_project_link.nil?
@project
else
@project.forked_project_link.forked_from_project
end
end
def merge_request
@issuable = @merge_request ||= @project.merge_requests.find_by!(iid: params[:id])
end
alias_method :subscribable_resource, :merge_request alias_method :subscribable_resource, :merge_request
alias_method :issuable, :merge_request alias_method :issuable, :merge_request
alias_method :awardable, :merge_request alias_method :awardable, :merge_request
...@@ -455,12 +253,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -455,12 +253,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
return render_404 unless can?(current_user, :admin_merge_request, @merge_request) return render_404 unless can?(current_user, :admin_merge_request, @merge_request)
end end
def authorize_can_resolve_conflicts!
@conflicts_list = MergeRequests::Conflicts::ListService.new(@merge_request)
return render_404 unless @conflicts_list.can_be_resolved_by?(current_user)
end
def validates_merge_request def validates_merge_request
# Show git not found page # Show git not found page
# if there is no saved commits between source & target branch # if there is no saved commits between source & target branch
...@@ -470,133 +262,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -470,133 +262,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
end end
def define_show_vars
@noteable = @merge_request
@commits_count = @merge_request.commits_count
if @merge_request.locked_long_ago?
@merge_request.unlock_mr
@merge_request.close
end
labels
define_pipelines_vars
end
# Discussion tab data is rendered on html responses of actions
# :show, :diff, :commits, :builds. but not when request the data through AJAX
def define_discussion_vars
# Build a note object for comment form
@note = @project.notes.new(noteable: @merge_request)
@discussions = @merge_request.discussions
@notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes))
end
def define_diff_vars
@merge_request_diff =
if params[:diff_id]
@merge_request.merge_request_diffs.viewable.find(params[:diff_id])
else
@merge_request.merge_request_diff
end
@merge_request_diffs = @merge_request.merge_request_diffs.viewable.select_without_diff
@comparable_diffs = @merge_request_diffs.select { |diff| diff.id < @merge_request_diff.id }
if params[:start_sha].present?
@start_sha = params[:start_sha]
@start_version = @comparable_diffs.find { |diff| diff.head_commit_sha == @start_sha }
unless @start_version
@start_sha = @merge_request_diff.head_commit_sha
@start_version = @merge_request_diff
end
end
@compare =
if @start_sha
@merge_request_diff.compare_with(@start_sha)
else
@merge_request_diff
end
@diffs = @compare.diffs(diff_options)
end
def define_diff_comment_vars
@new_diff_note_attrs = {
noteable_type: 'MergeRequest',
noteable_id: @merge_request.id
}
@diff_notes_disabled = false
@use_legacy_diff_notes = !@merge_request.has_complete_diff_refs?
@grouped_diff_discussions = @merge_request.grouped_diff_discussions(@compare.diff_refs)
@notes = prepare_notes_for_rendering(@grouped_diff_discussions.values.flatten.flat_map(&:notes))
end
def define_pipelines_vars
@pipelines = @merge_request.all_pipelines
@pipeline = @merge_request.head_pipeline
@statuses_count = @pipeline.present? ? @pipeline.statuses.relevant.count : 0
end
def define_new_vars
@noteable = @merge_request
@target_branches = if @merge_request.target_project
@merge_request.target_project.repository.branch_names
else
[]
end
@target_project = merge_request.target_project
@source_project = merge_request.source_project
@commits = @merge_request.compare_commits.reverse
@commit = @merge_request.diff_head_commit
@note_counts = Note.where(commit_id: @commits.map(&:id))
.group(:commit_id).count
@labels = LabelsFinder.new(current_user, project_id: @project.id).execute
@show_changes_tab = params[:show_changes].present?
define_pipelines_vars
end
def invalid_mr def invalid_mr
# Render special view for MR with removed target branch # Render special view for MR with removed target branch
render 'invalid' render 'invalid'
end end
def merge_request_params
params.require(:merge_request)
.permit(merge_request_params_attributes)
end
def merge_request_params_attributes
[
:assignee_id,
:description,
:force_remove_source_branch,
:lock_version,
:milestone_id,
:source_branch,
:source_project_id,
:state_event,
:target_branch,
:target_project_id,
:task_num,
:title,
label_ids: []
]
end
def merge_params def merge_params
params.permit(merge_params_attributes) params.permit(merge_params_attributes)
end end
...@@ -605,22 +275,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -605,22 +275,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
[:should_remove_source_branch, :commit_message] [:should_remove_source_branch, :commit_message]
end end
# Make sure merge requests created before 8.0
# have head file in refs/merge-requests/
def ensure_ref_fetched
@merge_request.ensure_ref_fetched
end
def merge_when_pipeline_succeeds_active? def merge_when_pipeline_succeeds_active?
params[:merge_when_pipeline_succeeds].present? && params[:merge_when_pipeline_succeeds].present? &&
@merge_request.head_pipeline && @merge_request.head_pipeline.active? @merge_request.head_pipeline && @merge_request.head_pipeline.active?
end end
def build_merge_request
params[:merge_request] ||= ActionController::Parameters.new(source_project: @project)
@merge_request = MergeRequests::BuildService.new(project, current_user, merge_request_params.merge(diff_options: diff_options)).execute
end
def close_merge_request_without_source_project def close_merge_request_without_source_project
if !@merge_request.source_project && @merge_request.open? if !@merge_request.source_project && @merge_request.open?
@merge_request.close @merge_request.close
...@@ -648,7 +307,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -648,7 +307,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
return :failed unless @merge_request.head_pipeline return :failed unless @merge_request.head_pipeline
if @merge_request.head_pipeline.active? if @merge_request.head_pipeline.active?
MergeRequests::MergeWhenPipelineSucceedsService ::MergeRequests::MergeWhenPipelineSucceedsService
.new(@project, current_user, merge_params) .new(@project, current_user, merge_params)
.execute(@merge_request) .execute(@merge_request)
...@@ -672,4 +331,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -672,4 +331,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def serializer def serializer
MergeRequestSerializer.new(current_user: current_user, project: merge_request.project) MergeRequestSerializer.new(current_user: current_user, project: merge_request.project)
end end
def define_edit_vars
@source_project = @merge_request.source_project
@target_project = @merge_request.target_project
@target_branches = @merge_request.target_project.repository.branch_names
end
end end
...@@ -131,10 +131,7 @@ module ApplicationHelper ...@@ -131,10 +131,7 @@ module ApplicationHelper
end end
def body_data_page def body_data_page
path = controller.controller_path.split('/') [*controller.controller_path.split('/'), controller.action_name].compact.join(':')
namespace = path.first if path.second
[namespace, controller.controller_name, controller.action_name].compact.join(':')
end end
# shortcut for gitlab config # shortcut for gitlab config
......
...@@ -284,7 +284,7 @@ module BlobHelper ...@@ -284,7 +284,7 @@ module BlobHelper
merge_project = can?(current_user, :create_merge_request, project) ? project : (current_user && current_user.fork_of(project)) merge_project = can?(current_user, :create_merge_request, project) ? project : (current_user && current_user.fork_of(project))
if merge_project if merge_project
options << link_to("create a merge request", new_namespace_project_merge_request_path(project.namespace, project)) options << link_to("create a merge request", namespace_project_new_merge_request_path(project.namespace, project))
end end
options options
......
...@@ -9,7 +9,7 @@ module CompareHelper ...@@ -9,7 +9,7 @@ module CompareHelper
end end
def create_mr_path(from = params[:from], to = params[:to], project = @project) def create_mr_path(from = params[:from], to = params[:to], project = @project)
new_namespace_project_merge_request_path( namespace_project_new_merge_request_path(
project.namespace, project.namespace,
project, project,
merge_request: { merge_request: {
......
module MergeRequestsHelper module MergeRequestsHelper
def new_mr_path_from_push_event(event) def new_mr_path_from_push_event(event)
target_project = event.project.default_merge_request_target target_project = event.project.default_merge_request_target
new_namespace_project_merge_request_path( namespace_project_new_merge_request_path(
event.project.namespace, event.project.namespace,
event.project, event.project,
new_mr_from_push_event(event, target_project) new_mr_from_push_event(event, target_project)
...@@ -48,7 +48,7 @@ module MergeRequestsHelper ...@@ -48,7 +48,7 @@ module MergeRequestsHelper
end end
def mr_change_branches_path(merge_request) def mr_change_branches_path(merge_request)
new_namespace_project_merge_request_path( namespace_project_new_merge_request_path(
@project.namespace, @project, @project.namespace, @project,
merge_request: { merge_request: {
source_project_id: merge_request.source_project_id, source_project_id: merge_request.source_project_id,
......
module NavHelper module NavHelper
def page_gutter_class def page_gutter_class
if current_path?('merge_requests#show') || if current_path?('merge_requests#show') ||
current_path?('merge_requests#diffs') || current_path?('projects/merge_requests/conflicts#show') ||
current_path?('merge_requests#commits') ||
current_path?('merge_requests#builds') ||
current_path?('merge_requests#conflicts') ||
current_path?('merge_requests#pipelines') ||
current_path?('issues#show') || current_path?('issues#show') ||
current_path?('milestones#show') current_path?('milestones#show')
if cookies[:collapsed_gutter] == 'true' if cookies[:collapsed_gutter] == 'true'
......
...@@ -49,7 +49,7 @@ module MergeRequests ...@@ -49,7 +49,7 @@ module MergeRequests
def url_for_new_merge_request(branch_name) def url_for_new_merge_request(branch_name)
merge_request_params = { source_branch: branch_name } merge_request_params = { source_branch: branch_name }
url = Gitlab::Routing.url_helpers.new_namespace_project_merge_request_url(project.namespace, project, merge_request: merge_request_params) url = Gitlab::Routing.url_helpers.namespace_project_new_merge_request_url(project.namespace, project, merge_request: merge_request_params)
{ branch_name: branch_name, url: url, new_merge_request: true } { branch_name: branch_name, url: url, new_merge_request: true }
end end
......
...@@ -10,7 +10,7 @@ module Projects ...@@ -10,7 +10,7 @@ module Projects
merge_requests = @project.forked_from_project.merge_requests.opened.from_project(@project) merge_requests = @project.forked_from_project.merge_requests.opened.from_project(@project)
merge_requests.each do |mr| merge_requests.each do |mr|
MergeRequests::CloseService.new(@project, @current_user).execute(mr) ::MergeRequests::CloseService.new(@project, @current_user).execute(mr)
end end
@project.forked_project_link.destroy @project.forked_project_link.destroy
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
= link_to 'New issue', new_namespace_project_issue_path(@project.namespace, @project) = link_to 'New issue', new_namespace_project_issue_path(@project.namespace, @project)
- if merge_project - if merge_project
%li %li
= link_to 'New merge request', new_namespace_project_merge_request_path(merge_project.namespace, merge_project) = link_to 'New merge request', namespace_project_new_merge_request_path(merge_project.namespace, merge_project)
- if create_project_snippet - if create_project_snippet
%li.header-new-project-snippet %li.header-new-project-snippet
= link_to 'New snippet', new_namespace_project_snippet_path(@project.namespace, @project) = link_to 'New snippet', new_namespace_project_snippet_path(@project.namespace, @project)
......
...@@ -31,7 +31,9 @@ ...@@ -31,7 +31,9 @@
%span.badge.count.issue_counter= number_with_delimiter(IssuesFinder.new(current_user, project_id: @project.id).execute.opened.count) %span.badge.count.issue_counter= number_with_delimiter(IssuesFinder.new(current_user, project_id: @project.id).execute.opened.count)
- if project_nav_tab? :merge_requests - if project_nav_tab? :merge_requests
= nav_link(controller: @project.default_issues_tracker? ? :merge_requests : [:merge_requests, :labels, :milestones]) do - controllers = [:merge_requests, 'projects/merge_requests/conflicts']
- controllers.push(:merge_requests, :labels, :milestones) unless @project.default_issues_tracker?
= nav_link(controller: controllers) do
= link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do = link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do
%span %span
Merge Requests Merge Requests
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
- if merge_project - if merge_project
%li %li
= link_to new_namespace_project_merge_request_path(merge_project.namespace, merge_project) do = link_to namespace_project_new_merge_request_path(merge_project.namespace, merge_project) do
= icon('tasks fw') = icon('tasks fw')
#{ _('New merge request') } #{ _('New merge request') }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
%li.commits-row{ data: { day: day } } %li.commits-row{ data: { day: day } }
%ul.content-list.commit-list %ul.content-list.commit-list
= render commits, project: project, ref: ref = render partial: 'projects/commits/commit', collection: commits, locals: { project: project, ref: ref }
- if hidden > 0 - if hidden > 0
%li.alert.alert-warning %li.alert.alert-warning
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
- if show_whitespace_toggle - if show_whitespace_toggle
- if current_controller?(:commit) - if current_controller?(:commit)
= commit_diff_whitespace_link(diffs.project, @commit, class: 'hidden-xs') = commit_diff_whitespace_link(diffs.project, @commit, class: 'hidden-xs')
- elsif current_controller?(:merge_requests) - elsif current_controller?('projects/merge_requests/diffs')
= diff_merge_request_whitespace_link(diffs.project, @merge_request, class: 'hidden-xs') = diff_merge_request_whitespace_link(diffs.project, @merge_request, class: 'hidden-xs')
- elsif current_controller?(:compare) - elsif current_controller?(:compare)
= diff_compare_whitespace_link(diffs.project, params[:from], params[:to], class: 'hidden-xs') = diff_compare_whitespace_link(diffs.project, params[:from], params[:to], class: 'hidden-xs')
......
...@@ -2,11 +2,10 @@ ...@@ -2,11 +2,10 @@
%h4 %h4
Too many changes to show. Too many changes to show.
.pull-right .pull-right
- if current_controller?(:commit) or current_controller?(:merge_requests)
- if current_controller?(:commit) - if current_controller?(:commit)
= link_to "Plain diff", namespace_project_commit_path(@project.namespace, @project, @commit, format: :diff), class: "btn btn-sm" = link_to "Plain diff", namespace_project_commit_path(@project.namespace, @project, @commit, format: :diff), class: "btn btn-sm"
= link_to "Email patch", namespace_project_commit_path(@project.namespace, @project, @commit, format: :patch), class: "btn btn-sm" = link_to "Email patch", namespace_project_commit_path(@project.namespace, @project, @commit, format: :patch), class: "btn btn-sm"
- elsif @merge_request && @merge_request.persisted? - elsif current_controller?('projects/merge_requests/diffs') && @merge_request&.persisted?
= link_to "Plain diff", merge_request_path(@merge_request, format: :diff), class: "btn btn-sm" = link_to "Plain diff", merge_request_path(@merge_request, format: :diff), class: "btn btn-sm"
= link_to "Email patch", merge_request_path(@merge_request, format: :patch), class: "btn btn-sm" = link_to "Email patch", merge_request_path(@merge_request, format: :patch), class: "btn btn-sm"
%p %p
......
- @content_class = "limit-container-width" unless fluid_layout
- page_title "#{@merge_request.title} (#{@merge_request.to_reference})", "Merge Requests"
- page_description @merge_request.description
- page_card_attributes @merge_request.card_attributes
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('diff_notes')
.merge-request{ 'data-url' => merge_request_path(@merge_request, format: :json), 'data-project-path' => project_path(@merge_request.project) }
= render "projects/merge_requests/show/mr_title"
.merge-request-details.issuable-details{ data: { id: @merge_request.project.id } }
= render "projects/merge_requests/show/mr_box"
- if @merge_request.source_branch_exists?
= render "projects/merge_requests/show/how_to_merge"
:javascript
window.gl.mrWidgetData = #{serialize_issuable(@merge_request)}
#js-vue-mr-widget.mr-widget
- content_for :page_specific_javascripts do
= webpack_bundle_tag 'common_vue'
= webpack_bundle_tag 'vue_merge_request_widget'
.content-block.content-block-small.emoji-list-container
= render 'award_emoji/awards_block', awardable: @merge_request, inline: true
.merge-request-tabs-holder{ class: ("js-tabs-affix" unless ENV['RAILS_ENV'] == 'test') }
.merge-request-tabs-container
.scrolling-tabs-container.inner-page-scroll-tabs.is-smaller
.fade-left= icon('angle-left')
.fade-right= icon('angle-right')
.nav-links.scrolling-tabs
%ul.merge-request-tabs
%li.notes-tab
= link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#notes', action: 'notes', toggle: 'tab' } do
Discussion
%span.badge= @merge_request.related_notes.user.count
- if @merge_request.source_project
%li.commits-tab
= link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#commits', action: 'commits', toggle: 'tab' } do
Commits
%span.badge= @commits_count
- if @pipelines.any?
%li.pipelines-tab
= link_to pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: '#pipelines', action: 'pipelines', toggle: 'tab' } do
Pipelines
%span.badge= @pipelines.size
%li.diffs-tab
= link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#diffs', action: 'diffs', toggle: 'tab' } do
Changes
%span.badge= @merge_request.diff_size
#resolve-count-app.line-resolve-all-container.prepend-top-10{ "v-cloak" => true }
%resolve-count{ "inline-template" => true, ":logged-out" => "#{current_user.nil?}" }
%div
.line-resolve-all{ "v-show" => "discussionCount > 0",
":class" => "{ 'has-next-btn': !loggedOut && resolvedDiscussionCount !== discussionCount }" }
%span.line-resolve-btn.is-disabled{ type: "button",
":class" => "{ 'is-active': resolvedDiscussionCount === discussionCount }" }
= render "shared/icons/icon_status_success.svg"
%span.line-resolve-text
{{ resolvedDiscussionCount }}/{{ discussionCount }} {{ resolvedCountText }} resolved
= render "discussions/new_issue_for_all_discussions", merge_request: @merge_request
= render "discussions/jump_to_next"
.tab-content#diff-notes-app
#notes.notes.tab-pane.voting_notes
.row
%section.col-md-12
.issuable-discussion
= render "projects/merge_requests/discussion"
#commits.commits.tab-pane
-# This tab is always loaded via AJAX
#pipelines.pipelines.tab-pane
- if @pipelines.any?
= render 'projects/commit/pipelines_list', disable_initialization: true, endpoint: pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)
#diffs.diffs.tab-pane
-# This tab is always loaded via AJAX
.mr-loading-status
= spinner
= render 'shared/issuable/sidebar', issuable: @merge_request
- if @merge_request.can_be_reverted?(current_user)
= render "projects/commit/change", type: 'revert', commit: @merge_request.merge_commit, title: @merge_request.title
- if @merge_request.can_be_cherry_picked?
= render "projects/commit/change", type: 'cherry-pick', commit: @merge_request.merge_commit, title: @merge_request.title
:javascript
$(function () {
window.mergeRequest = new MergeRequest({
action: "#{controller.action_name}"
});
});
...@@ -3,10 +3,10 @@ ...@@ -3,10 +3,10 @@
= page_specific_javascript_bundle_tag('common_vue') = page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('merge_conflicts') = page_specific_javascript_bundle_tag('merge_conflicts')
= page_specific_javascript_tag('lib/ace.js') = page_specific_javascript_tag('lib/ace.js')
= render "projects/merge_requests/show/mr_title" = render "projects/merge_requests/mr_title"
.merge-request-details.issuable-details .merge-request-details.issuable-details
= render "projects/merge_requests/show/mr_box" = render "projects/merge_requests/mr_box"
= render 'shared/issuable/sidebar', issuable: @merge_request = render 'shared/issuable/sidebar', issuable: @merge_request
......
- page_title "Merge Conflicts", "#{@merge_request.title} (#{@merge_request.to_reference}", "Merge Requests"
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('merge_conflicts')
= page_specific_javascript_tag('lib/ace.js')
= render "projects/merge_requests/mr_title"
.merge-request-details.issuable-details
= render "projects/merge_requests/mr_box"
= render 'shared/issuable/sidebar', issuable: @merge_request
#conflicts{ "v-cloak" => "true", data: { conflicts_path: conflicts_namespace_project_merge_request_path(@merge_request.project.namespace, @merge_request.project, @merge_request, format: :json),
resolve_conflicts_path: resolve_conflicts_namespace_project_merge_request_path(@merge_request.project.namespace, @merge_request.project, @merge_request) } }
.loading{ "v-if" => "isLoading" }
%i.fa.fa-spinner.fa-spin
.nothing-here-block{ "v-if" => "hasError" }
{{conflictsData.errorMessage}}
= render partial: "projects/merge_requests/conflicts/commit_stats"
.files-wrapper{ "v-if" => "!isLoading && !hasError" }
.files
.diff-file.file-holder.conflict{ "v-for" => "file in conflictsData.files" }
.js-file-title.file-title
%i.fa.fa-fw{ ":class" => "file.iconClass" }
%strong {{file.filePath}}
= render partial: 'projects/merge_requests/conflicts/file_actions'
.diff-content.diff-wrap-lines
.diff-wrap-lines.code.file-content.js-syntax-highlight{ "v-show" => "!isParallel && file.resolveMode === 'interactive' && file.type === 'text'" }
= render partial: "projects/merge_requests/conflicts/components/inline_conflict_lines"
.diff-wrap-lines.code.file-content.js-syntax-highlight{ "v-show" => "isParallel && file.resolveMode === 'interactive' && file.type === 'text'" }
%parallel-conflict-lines{ ":file" => "file" }
%div{ "v-show" => "file.resolveMode === 'edit' || file.type === 'text-editor'" }
= render partial: "projects/merge_requests/conflicts/components/diff_file_editor"
= render partial: "projects/merge_requests/conflicts/submit_form"
%h3.page-title %h3.page-title
New Merge Request New Merge Request
= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], url: new_namespace_project_merge_request_path(@project.namespace, @project), method: :get, html: { class: "merge-request-form form-inline js-requires-input" } do |f| = form_for [@project.namespace.becomes(Namespace), @project, @merge_request], url: namespace_project_new_merge_request_path(@project.namespace, @project), method: :get, html: { class: "merge-request-form form-inline js-requires-input" } do |f|
.hide.alert.alert-danger.mr-compare-errors .hide.alert.alert-danger.mr-compare-errors
.merge-request-branches.row .merge-request-branches.row
.col-md-6 .col-md-6
...@@ -69,7 +69,7 @@ ...@@ -69,7 +69,7 @@
:javascript :javascript
new Compare({ new Compare({
targetProjectUrl: "#{update_branches_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", targetProjectUrl: "#{namespace_project_new_merge_request_update_branches_path(@source_project.namespace, @source_project)}",
sourceBranchUrl: "#{branch_from_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", sourceBranchUrl: "#{namespace_project_new_merge_request_branch_from_path(@source_project.namespace, @source_project)}",
targetBranchUrl: "#{branch_to_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}" targetBranchUrl: "#{namespace_project_new_merge_request_branch_to_path(@source_project.namespace, @source_project)}"
}); });
...@@ -31,28 +31,27 @@ ...@@ -31,28 +31,27 @@
%span.badge= @commits.size %span.badge= @commits.size
- if @pipelines.any? - if @pipelines.any?
%li.builds-tab %li.builds-tab
= link_to url_for(params), data: {target: 'div#pipelines', action: 'pipelines', toggle: 'tab'} do = link_to url_for(params.merge(action: 'pipelines')), data: {target: 'div#pipelines', action: 'pipelines', toggle: 'tab'} do
Pipelines Pipelines
%span.badge= @pipelines.size %span.badge= @pipelines.size
%li.diffs-tab %li.diffs-tab
= link_to url_for(params.merge(action: 'new_diffs')), data: {target: 'div#diffs', action: 'new/diffs', toggle: 'tab'} do = link_to url_for(params.merge(action: 'diffs')), data: {target: 'div#diffs', action: 'diffs', toggle: 'tab'} do
Changes Changes
%span.badge= @merge_request.diff_size %span.badge= @merge_request.diff_size
.tab-content .tab-content
#commits.commits.tab-pane.active #commits.commits.tab-pane.active
= render "projects/merge_requests/show/commits" = render "projects/merge_requests/commits"
#diffs.diffs.tab-pane #diffs.diffs.tab-pane
-# This tab is always loaded via AJAX -# This tab is always loaded via AJAX
- if @pipelines.any? - if @pipelines.any?
#pipelines.pipelines.tab-pane #pipelines.pipelines.tab-pane
= render 'projects/merge_requests/show/pipelines', endpoint: url_for(params.merge(format: :json)), disable_initialization: true = render 'projects/merge_requests/pipelines', endpoint: url_for(params.merge(action: 'pipelines', format: :json)), disable_initialization: true
.mr-loading-status .mr-loading-status
= spinner = spinner
:javascript :javascript
var merge_request = new MergeRequest({ var merge_request = new MergeRequest({
action: "#{(@show_changes_tab ? 'new/diffs' : 'new')}", action: "#{j params[:tab].presence || 'new'}",
setUrl: false,
}); });
- if @merge_request_diff.collected? || @merge_request_diff.overflow? - if @merge_request_diff.collected? || @merge_request_diff.overflow?
= render 'projects/merge_requests/show/versions' = render 'projects/merge_requests/diffs/versions'
= render "projects/diffs/diffs", diffs: @diffs, environment: @environment = render "projects/diffs/diffs", diffs: @diffs, environment: @environment
- elsif @merge_request_diff.empty? - elsif @merge_request_diff.empty?
.nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch} .nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch}
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
= button_tag "Edit Merge Requests", class: "btn js-bulk-update-toggle" = button_tag "Edit Merge Requests", class: "btn js-bulk-update-toggle"
- merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project)) - merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project))
- if merge_project - if merge_project
= link_to new_namespace_project_merge_request_path(merge_project.namespace, merge_project), class: "btn btn-new", title: "New merge request" do = link_to namespace_project_new_merge_request_path(merge_project.namespace, merge_project), class: "btn btn-new", title: "New merge request" do
New merge request New merge request
= render 'shared/issuable/search_bar', type: :merge_requests = render 'shared/issuable/search_bar', type: :merge_requests
...@@ -33,4 +33,4 @@ ...@@ -33,4 +33,4 @@
.merge-requests-holder .merge-requests-holder
= render 'merge_requests' = render 'merge_requests'
- else - else
= render 'shared/empty_states/merge_requests', button_path: new_namespace_project_merge_request_path(@project.namespace, @project) = render 'shared/empty_states/merge_requests', button_path: namespace_project_new_merge_request_path(@project.namespace, @project)
- page_title "#{@merge_request.title} (#{@merge_request.to_reference}", "Merge Requests" - page_title "#{@merge_request.title} (#{@merge_request.to_reference}", "Merge Requests"
.merge-request .merge-request
= render "projects/merge_requests/show/mr_title" = render "projects/merge_requests/mr_title"
= render "projects/merge_requests/show/mr_box" = render "projects/merge_requests/mr_box"
.alert.alert-danger .alert.alert-danger
%p %p
......
= render "show" - @content_class = "limit-container-width" unless fluid_layout
- page_title "#{@merge_request.title} (#{@merge_request.to_reference})", "Merge Requests"
- page_description @merge_request.description
- page_card_attributes @merge_request.card_attributes
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('diff_notes')
.merge-request{ 'data-url' => merge_request_path(@merge_request, format: :json), 'data-project-path' => project_path(@merge_request.project) }
= render "projects/merge_requests/mr_title"
.merge-request-details.issuable-details{ data: { id: @merge_request.project.id } }
= render "projects/merge_requests/mr_box"
- if @merge_request.source_branch_exists?
= render "projects/merge_requests/how_to_merge"
:javascript
window.gl.mrWidgetData = #{serialize_issuable(@merge_request)}
#js-vue-mr-widget.mr-widget
- content_for :page_specific_javascripts do
= webpack_bundle_tag 'common_vue'
= webpack_bundle_tag 'vue_merge_request_widget'
.content-block.content-block-small.emoji-list-container
= render 'award_emoji/awards_block', awardable: @merge_request, inline: true
.merge-request-tabs-holder{ class: ("js-tabs-affix" unless ENV['RAILS_ENV'] == 'test') }
.merge-request-tabs-container
.scrolling-tabs-container.inner-page-scroll-tabs.is-smaller
.fade-left= icon('angle-left')
.fade-right= icon('angle-right')
.nav-links.scrolling-tabs
%ul.merge-request-tabs
%li.notes-tab
= link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#notes', action: 'show', toggle: 'tab' } do
Discussion
%span.badge= @merge_request.related_notes.user.count
- if @merge_request.source_project
%li.commits-tab
= link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#commits', action: 'commits', toggle: 'tab' } do
Commits
%span.badge= @commits_count
- if @pipelines.any?
%li.pipelines-tab
= link_to pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: '#pipelines', action: 'pipelines', toggle: 'tab' } do
Pipelines
%span.badge= @pipelines.size
%li.diffs-tab
= link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#diffs', action: 'diffs', toggle: 'tab' } do
Changes
%span.badge= @merge_request.diff_size
#resolve-count-app.line-resolve-all-container.prepend-top-10{ "v-cloak" => true }
%resolve-count{ "inline-template" => true, ":logged-out" => "#{current_user.nil?}" }
%div
.line-resolve-all{ "v-show" => "discussionCount > 0",
":class" => "{ 'has-next-btn': !loggedOut && resolvedDiscussionCount !== discussionCount }" }
%span.line-resolve-btn.is-disabled{ type: "button",
":class" => "{ 'is-active': resolvedDiscussionCount === discussionCount }" }
= render "shared/icons/icon_status_success.svg"
%span.line-resolve-text
{{ resolvedDiscussionCount }}/{{ discussionCount }} {{ resolvedCountText }} resolved
= render "discussions/new_issue_for_all_discussions", merge_request: @merge_request
= render "discussions/jump_to_next"
.tab-content#diff-notes-app
#notes.notes.tab-pane.voting_notes
.row
%section.col-md-12
.issuable-discussion
= render "projects/merge_requests/discussion"
#commits.commits.tab-pane
-# This tab is always loaded via AJAX
#pipelines.pipelines.tab-pane
- if @pipelines.any?
= render 'projects/commit/pipelines_list', disable_initialization: true, endpoint: pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)
#diffs.diffs.tab-pane
-# This tab is always loaded via AJAX
.mr-loading-status
= spinner
= render 'shared/issuable/sidebar', issuable: @merge_request
- if @merge_request.can_be_reverted?(current_user)
= render "projects/commit/change", type: 'revert', commit: @merge_request.merge_commit, title: @merge_request.title
- if @merge_request.can_be_cherry_picked?
= render "projects/commit/change", type: 'cherry-pick', commit: @merge_request.merge_commit, title: @merge_request.title
:javascript
$(function () {
window.mergeRequest = new MergeRequest({
action: "#{j params[:tab].presence || 'show'}",
});
});
...@@ -46,7 +46,7 @@ class ExpirePipelineCacheWorker ...@@ -46,7 +46,7 @@ class ExpirePipelineCacheWorker
end end
def new_merge_request_pipelines_path(project) def new_merge_request_pipelines_path(project)
Gitlab::Routing.url_helpers.new_namespace_project_merge_request_path( Gitlab::Routing.url_helpers.namespace_project_new_merge_request_path(
project.namespace, project.namespace,
project, project,
format: :json) format: :json)
......
...@@ -87,13 +87,8 @@ constraints(ProjectUrlConstrainer.new) do ...@@ -87,13 +87,8 @@ constraints(ProjectUrlConstrainer.new) do
resources :forks, only: [:index, :new, :create] resources :forks, only: [:index, :new, :create]
resource :import, only: [:new, :create, :show] resource :import, only: [:new, :create, :show]
resources :merge_requests, concerns: :awardable, constraints: { id: /\d+/ } do resources :merge_requests, concerns: :awardable, except: [:new, :create], constraints: { id: /\d+/ } do
member do member do
get :commits
get :diffs
get :conflicts
get :conflict_for_path
get :pipelines
get :commit_change_content get :commit_change_content
post :merge post :merge
post :cancel_merge_when_pipeline_succeeds post :cancel_merge_when_pipeline_succeeds
...@@ -101,18 +96,32 @@ constraints(ProjectUrlConstrainer.new) do ...@@ -101,18 +96,32 @@ constraints(ProjectUrlConstrainer.new) do
get :ci_environments_status get :ci_environments_status
post :toggle_subscription post :toggle_subscription
post :remove_wip post :remove_wip
get :diff_for_path
post :resolve_conflicts
post :assign_related_issues post :assign_related_issues
scope constraints: { format: nil }, action: :show do
get :commits, defaults: { tab: 'commits' }
get :pipelines, defaults: { tab: 'pipelines' }
get :diffs, defaults: { tab: 'diffs' }
end
scope constraints: { format: 'json' }, as: :json do
get :commits
get :pipelines
get :diffs, to: 'merge_requests/diffs#show'
end
get :diff_for_path, controller: 'merge_requests/diffs'
scope controller: 'merge_requests/conflicts' do
get :conflicts, action: :show
get :conflict_for_path
post :resolve_conflicts
end
end end
collection do collection do
get :branch_from
get :branch_to
get :update_branches
get :diff_for_path get :diff_for_path
post :bulk_update post :bulk_update
get :new_diffs, path: 'new/diffs'
end end
resources :discussions, only: [], constraints: { id: /\h{40}/ } do resources :discussions, only: [], constraints: { id: /\h{40}/ } do
...@@ -123,6 +132,29 @@ constraints(ProjectUrlConstrainer.new) do ...@@ -123,6 +132,29 @@ constraints(ProjectUrlConstrainer.new) do
end end
end end
controller 'merge_requests/creations', path: 'merge_requests' do
post '', action: :create, as: nil
scope path: 'new', as: :new_merge_request do
get '', action: :new
scope constraints: { format: nil }, action: :new do
get :diffs, defaults: { tab: 'diffs' }
get :pipelines, defaults: { tab: 'pipelines' }
end
scope constraints: { format: 'json' }, as: :json do
get :diffs
get :pipelines
end
get :diff_for_path
get :update_branches
get :branch_from
get :branch_to
end
end
resources :variables, only: [:index, :show, :update, :create, :destroy] resources :variables, only: [:index, :show, :update, :create, :destroy]
resources :triggers, only: [:index, :create, :edit, :update, :destroy] do resources :triggers, only: [:index, :create, :edit, :update, :destroy] do
member do member do
......
...@@ -27,7 +27,7 @@ class Spinach::Features::Dashboard < Spinach::FeatureSteps ...@@ -27,7 +27,7 @@ class Spinach::Features::Dashboard < Spinach::FeatureSteps
step 'I see prefilled new Merge Request page' do step 'I see prefilled new Merge Request page' do
expect(page).to have_selector('.merge-request-form') expect(page).to have_selector('.merge-request-form')
expect(current_path).to eq new_namespace_project_merge_request_path(@project.namespace, @project) expect(current_path).to eq namespace_project_new_merge_request_path(@project.namespace, @project)
expect(find("#merge_request_target_project_id").value).to eq @project.id.to_s expect(find("#merge_request_target_project_id").value).to eq @project.id.to_s
expect(find("input#merge_request_source_branch").value).to eq "fix" expect(find("input#merge_request_source_branch").value).to eq "fix"
expect(find("input#merge_request_target_branch").value).to eq "master" expect(find("input#merge_request_target_branch").value).to eq "master"
......
...@@ -266,12 +266,12 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps ...@@ -266,12 +266,12 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
end end
step 'I am redirected to the new merge request page' do step 'I am redirected to the new merge request page' do
expect(current_path).to eq(new_namespace_project_merge_request_path(@project.namespace, @project)) expect(current_path).to eq(namespace_project_new_merge_request_path(@project.namespace, @project))
end end
step "I am redirected to the fork's new merge request page" do step "I am redirected to the fork's new merge request page" do
fork = @user.fork_of(@project) fork = @user.fork_of(@project)
expect(current_path).to eq(new_namespace_project_merge_request_path(fork.namespace, fork)) expect(current_path).to eq(namespace_project_new_merge_request_path(fork.namespace, fork))
end end
step 'I am redirected to the root directory' do step 'I am redirected to the root directory' do
......
...@@ -235,7 +235,7 @@ describe Projects::BlobController do ...@@ -235,7 +235,7 @@ describe Projects::BlobController do
put :update, default_params put :update, default_params
expect(response).to redirect_to( expect(response).to redirect_to(
new_namespace_project_merge_request_path( namespace_project_new_merge_request_path(
forked_project.namespace, forked_project.namespace,
forked_project, forked_project,
merge_request: { merge_request: {
......
require 'spec_helper'
describe Projects::MergeRequests::ConflictsController do
let(:project) { create(:project) }
let(:user) { project.owner }
let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) }
let(:merge_request_with_conflicts) do
create(:merge_request, source_branch: 'conflict-resolvable', target_branch: 'conflict-start', source_project: project) do |mr|
mr.mark_as_unmergeable
end
end
before do
sign_in(user)
end
describe 'GET show' do
context 'when the conflicts cannot be resolved in the UI' do
before do
allow_any_instance_of(Gitlab::Conflict::Parser)
.to receive(:parse).and_raise(Gitlab::Conflict::Parser::UnmergeableFile)
get :show,
namespace_id: merge_request_with_conflicts.project.namespace.to_param,
project_id: merge_request_with_conflicts.project,
id: merge_request_with_conflicts.iid,
format: 'json'
end
it 'returns a 200 status code' do
expect(response).to have_http_status(:ok)
end
it 'returns JSON with a message' do
expect(json_response.keys).to contain_exactly('message', 'type')
end
end
context 'with valid conflicts' do
before do
get :show,
namespace_id: merge_request_with_conflicts.project.namespace.to_param,
project_id: merge_request_with_conflicts.project,
id: merge_request_with_conflicts.iid,
format: 'json'
end
it 'matches the schema' do
expect(response).to match_response_schema('conflicts')
end
it 'includes meta info about the MR' do
expect(json_response['commit_message']).to include('Merge branch')
expect(json_response['commit_sha']).to match(/\h{40}/)
expect(json_response['source_branch']).to eq(merge_request_with_conflicts.source_branch)
expect(json_response['target_branch']).to eq(merge_request_with_conflicts.target_branch)
end
it 'includes each file that has conflicts' do
filenames = json_response['files'].map { |file| file['new_path'] }
expect(filenames).to contain_exactly('files/ruby/popen.rb', 'files/ruby/regex.rb')
end
it 'splits files into sections with lines' do
json_response['files'].each do |file|
file['sections'].each do |section|
expect(section).to include('conflict', 'lines')
section['lines'].each do |line|
if section['conflict']
expect(line['type']).to be_in(%w(old new))
expect(line.values_at('old_line', 'new_line')).to contain_exactly(nil, a_kind_of(Integer))
else
if line['type'].nil?
expect(line['old_line']).not_to eq(nil)
expect(line['new_line']).not_to eq(nil)
else
expect(line['type']).to eq('match')
expect(line['old_line']).to eq(nil)
expect(line['new_line']).to eq(nil)
end
end
end
end
end
end
it 'has unique section IDs across files' do
section_ids = json_response['files'].flat_map do |file|
file['sections'].map { |section| section['id'] }.compact
end
expect(section_ids.uniq).to eq(section_ids)
end
end
end
describe 'GET conflict_for_path' do
def conflict_for_path(path)
get :conflict_for_path,
namespace_id: merge_request_with_conflicts.project.namespace.to_param,
project_id: merge_request_with_conflicts.project,
id: merge_request_with_conflicts.iid,
old_path: path,
new_path: path,
format: 'json'
end
context 'when the conflicts cannot be resolved in the UI' do
before do
allow_any_instance_of(Gitlab::Conflict::Parser)
.to receive(:parse).and_raise(Gitlab::Conflict::Parser::UnmergeableFile)
conflict_for_path('files/ruby/regex.rb')
end
it 'returns a 404 status code' do
expect(response).to have_http_status(:not_found)
end
end
context 'when the file does not exist cannot be resolved in the UI' do
before do
conflict_for_path('files/ruby/regexp.rb')
end
it 'returns a 404 status code' do
expect(response).to have_http_status(:not_found)
end
end
context 'with an existing file' do
let(:path) { 'files/ruby/regex.rb' }
before do
conflict_for_path(path)
end
it 'returns a 200 status code' do
expect(response).to have_http_status(:ok)
end
it 'returns the file in JSON format' do
content = MergeRequests::Conflicts::ListService.new(merge_request_with_conflicts)
.file_for_path(path, path)
.content
expect(json_response).to include('old_path' => path,
'new_path' => path,
'blob_icon' => 'file-text-o',
'blob_path' => a_string_ending_with(path),
'blob_ace_mode' => 'ruby',
'content' => content)
end
end
end
context 'POST resolve_conflicts' do
let!(:original_head_sha) { merge_request_with_conflicts.diff_head_sha }
def resolve_conflicts(files)
post :resolve_conflicts,
namespace_id: merge_request_with_conflicts.project.namespace.to_param,
project_id: merge_request_with_conflicts.project,
id: merge_request_with_conflicts.iid,
format: 'json',
files: files,
commit_message: 'Commit message'
end
context 'with valid params' do
before do
resolved_files = [
{
'new_path' => 'files/ruby/popen.rb',
'old_path' => 'files/ruby/popen.rb',
'sections' => {
'2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_14' => 'head'
}
}, {
'new_path' => 'files/ruby/regex.rb',
'old_path' => 'files/ruby/regex.rb',
'sections' => {
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin'
}
}
]
resolve_conflicts(resolved_files)
end
it 'creates a new commit on the branch' do
expect(original_head_sha).not_to eq(merge_request_with_conflicts.source_branch_head.sha)
expect(merge_request_with_conflicts.source_branch_head.message).to include('Commit message')
end
it 'returns an OK response' do
expect(response).to have_http_status(:ok)
end
end
context 'when sections are missing' do
before do
resolved_files = [
{
'new_path' => 'files/ruby/popen.rb',
'old_path' => 'files/ruby/popen.rb',
'sections' => {
'2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_14' => 'head'
}
}, {
'new_path' => 'files/ruby/regex.rb',
'old_path' => 'files/ruby/regex.rb',
'sections' => {
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head'
}
}
]
resolve_conflicts(resolved_files)
end
it 'returns a 400 error' do
expect(response).to have_http_status(:bad_request)
end
it 'has a message with the name of the first missing section' do
expect(json_response['message']).to include('6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21')
end
it 'does not create a new commit' do
expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
end
end
context 'when files are missing' do
before do
resolved_files = [
{
'new_path' => 'files/ruby/regex.rb',
'old_path' => 'files/ruby/regex.rb',
'sections' => {
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin'
}
}
]
resolve_conflicts(resolved_files)
end
it 'returns a 400 error' do
expect(response).to have_http_status(:bad_request)
end
it 'has a message with the name of the missing file' do
expect(json_response['message']).to include('files/ruby/popen.rb')
end
it 'does not create a new commit' do
expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
end
end
context 'when a file has identical content to the conflict' do
before do
content = MergeRequests::Conflicts::ListService.new(merge_request_with_conflicts)
.file_for_path('files/ruby/popen.rb', 'files/ruby/popen.rb')
.content
resolved_files = [
{
'new_path' => 'files/ruby/popen.rb',
'old_path' => 'files/ruby/popen.rb',
'content' => content
}, {
'new_path' => 'files/ruby/regex.rb',
'old_path' => 'files/ruby/regex.rb',
'sections' => {
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin'
}
}
]
resolve_conflicts(resolved_files)
end
it 'returns a 400 error' do
expect(response).to have_http_status(:bad_request)
end
it 'has a message with the path of the problem file' do
expect(json_response['message']).to include('files/ruby/popen.rb')
end
it 'does not create a new commit' do
expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
end
end
end
end
require 'spec_helper'
describe Projects::MergeRequests::CreationsController do
let(:project) { create(:project) }
let(:user) { project.owner }
let(:fork_project) { create(:forked_project_with_submodules) }
before do
fork_project.team << [user, :master]
sign_in(user)
end
describe 'GET new' do
context 'merge request that removes a submodule' do
render_views
it 'renders new merge request widget template' do
get :new,
namespace_id: fork_project.namespace.to_param,
project_id: fork_project,
merge_request: {
source_branch: 'remove-submodule',
target_branch: 'master'
}
expect(response).to be_success
end
end
end
describe 'GET pipelines' do
before do
create(:ci_pipeline, sha: fork_project.commit('remove-submodule').id,
ref: 'remove-submodule',
project: fork_project)
end
it 'renders JSON including serialized pipelines' do
get :pipelines,
namespace_id: fork_project.namespace.to_param,
project_id: fork_project,
merge_request: {
source_branch: 'remove-submodule',
target_branch: 'master'
},
format: :json
expect(response).to be_ok
expect(json_response).to have_key 'pipelines'
expect(json_response['pipelines']).not_to be_empty
end
end
describe 'GET diff_for_path' do
def diff_for_path(extra_params = {})
params = {
namespace_id: project.namespace.to_param,
project_id: project,
format: 'json'
}
get :diff_for_path, params.merge(extra_params)
end
let(:existing_path) { 'files/ruby/feature.rb' }
context 'when both branches are in the same project' do
it 'disables diff notes' do
diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_branch: 'feature', target_branch: 'master' })
expect(assigns(:diff_notes_disabled)).to be_truthy
end
it 'only renders the diffs for the path given' do
expect(controller).to receive(:render_diff_for_path).and_wrap_original do |meth, diffs|
expect(diffs.diff_files.map(&:new_path)).to contain_exactly(existing_path)
meth.call(diffs)
end
diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_branch: 'feature', target_branch: 'master' })
end
end
context 'when the source branch is in a different project to the target' do
let(:other_project) { create(:project) }
before do
other_project.team << [user, :master]
end
context 'when the path exists in the diff' do
it 'disables diff notes' do
diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' })
expect(assigns(:diff_notes_disabled)).to be_truthy
end
it 'only renders the diffs for the path given' do
expect(controller).to receive(:render_diff_for_path).and_wrap_original do |meth, diffs|
expect(diffs.diff_files.map(&:new_path)).to contain_exactly(existing_path)
meth.call(diffs)
end
diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' })
end
end
context 'when the path does not exist in the diff' do
before do
diff_for_path(old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb', merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' })
end
it 'returns a 404' do
expect(response).to have_http_status(404)
end
end
end
end
end
require 'spec_helper'
describe Projects::MergeRequests::DiffsController do
let(:project) { create(:project) }
let(:user) { project.owner }
let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) }
before do
sign_in(user)
end
describe 'GET show' do
def go(extra_params = {})
params = {
namespace_id: project.namespace.to_param,
project_id: project,
id: merge_request.iid,
format: 'json'
}
get :show, params.merge(extra_params)
end
context 'with default params' do
context 'for the same project' do
before do
go
end
it 'renders the diffs template to a string' do
expect(response).to render_template('projects/merge_requests/diffs/_diffs')
expect(json_response).to have_key('html')
end
end
context 'with forked projects with submodules' do
render_views
let(:project) { create(:project) }
let(:fork_project) { create(:forked_project_with_submodules) }
let(:merge_request) { create(:merge_request_with_diffs, source_project: fork_project, source_branch: 'add-submodule-version-bump', target_branch: 'master', target_project: project) }
before do
fork_project.build_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id)
fork_project.save
merge_request.reload
go
end
it 'renders' do
expect(response).to be_success
expect(response.body).to have_content('Subproject commit')
end
end
end
context 'with ignore_whitespace_change' do
before do
go(w: 1)
end
it 'renders the diffs template to a string' do
expect(response).to render_template('projects/merge_requests/diffs/_diffs')
expect(json_response).to have_key('html')
end
end
context 'with view' do
before do
go(view: 'parallel')
end
it 'saves the preferred diff view in a cookie' do
expect(response.cookies['diff_view']).to eq('parallel')
end
end
end
describe 'GET diff_for_path' do
def diff_for_path(extra_params = {})
params = {
namespace_id: project.namespace.to_param,
project_id: project,
id: merge_request.iid,
format: 'json'
}
get :diff_for_path, params.merge(extra_params)
end
let(:existing_path) { 'files/ruby/popen.rb' }
context 'when the merge request exists' do
context 'when the user can view the merge request' do
context 'when the path exists in the diff' do
it 'enables diff notes' do
diff_for_path(old_path: existing_path, new_path: existing_path)
expect(assigns(:diff_notes_disabled)).to be_falsey
expect(assigns(:new_diff_note_attrs)).to eq(noteable_type: 'MergeRequest',
noteable_id: merge_request.id)
end
it 'only renders the diffs for the path given' do
expect(controller).to receive(:render_diff_for_path).and_wrap_original do |meth, diffs|
expect(diffs.diff_files.map(&:new_path)).to contain_exactly(existing_path)
meth.call(diffs)
end
diff_for_path(old_path: existing_path, new_path: existing_path)
end
end
context 'when the path does not exist in the diff' do
before do
diff_for_path(old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb')
end
it 'returns a 404' do
expect(response).to have_http_status(404)
end
end
end
context 'when the user cannot view the merge request' do
before do
project.team.truncate
diff_for_path(old_path: existing_path, new_path: existing_path)
end
it 'returns a 404' do
expect(response).to have_http_status(404)
end
end
end
context 'when the merge request does not exist' do
before do
diff_for_path(id: merge_request.iid.succ, old_path: existing_path, new_path: existing_path)
end
it 'returns a 404' do
expect(response).to have_http_status(404)
end
end
context 'when the merge request belongs to a different project' do
let(:other_project) { create(:empty_project) }
before do
other_project.team << [user, :master]
diff_for_path(old_path: existing_path, new_path: existing_path, project_id: other_project)
end
it 'returns a 404' do
expect(response).to have_http_status(404)
end
end
end
end
...@@ -14,53 +14,6 @@ describe Projects::MergeRequestsController do ...@@ -14,53 +14,6 @@ describe Projects::MergeRequestsController do
sign_in(user) sign_in(user)
end end
describe 'GET new' do
context 'merge request that removes a submodule' do
render_views
let(:fork_project) { create(:forked_project_with_submodules) }
before do
fork_project.team << [user, :master]
end
context 'when rendering HTML response' do
it 'renders new merge request widget template' do
submit_new_merge_request
expect(response).to be_success
end
end
context 'when rendering JSON response' do
before do
create(:ci_pipeline, sha: fork_project.commit('remove-submodule').id,
ref: 'remove-submodule',
project: fork_project)
end
it 'renders JSON including serialized pipelines' do
submit_new_merge_request(format: :json)
expect(response).to be_ok
expect(json_response).to have_key 'pipelines'
expect(json_response['pipelines']).not_to be_empty
end
end
end
def submit_new_merge_request(format: :html)
get :new,
namespace_id: fork_project.namespace.to_param,
project_id: fork_project,
merge_request: {
source_branch: 'remove-submodule',
target_branch: 'master'
},
format: format
end
end
describe 'GET commit_change_content' do describe 'GET commit_change_content' do
it 'renders commit_change_content template' do it 'renders commit_change_content template' do
get :commit_change_content, get :commit_change_content,
...@@ -497,234 +450,6 @@ describe Projects::MergeRequestsController do ...@@ -497,234 +450,6 @@ describe Projects::MergeRequestsController do
end end
end end
describe 'GET diffs' do
def go(extra_params = {})
params = {
namespace_id: project.namespace.to_param,
project_id: project,
id: merge_request.iid
}
get :diffs, params.merge(extra_params)
end
it_behaves_like "loads labels", :diffs
context 'with default params' do
context 'as html' do
before do
go(format: 'html')
end
it 'renders the diff template' do
expect(response).to render_template('diffs')
end
end
context 'as json' do
before do
go(format: 'json')
end
it 'renders the diffs template to a string' do
expect(response).to render_template('projects/merge_requests/show/_diffs')
expect(json_response).to have_key('html')
end
end
context 'with forked projects with submodules' do
render_views
let(:project) { create(:project) }
let(:fork_project) { create(:forked_project_with_submodules) }
let(:merge_request) { create(:merge_request_with_diffs, source_project: fork_project, source_branch: 'add-submodule-version-bump', target_branch: 'master', target_project: project) }
before do
fork_project.build_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id)
fork_project.save
merge_request.reload
go(format: 'json')
end
it 'renders' do
expect(response).to be_success
expect(response.body).to have_content('Subproject commit')
end
end
end
context 'with ignore_whitespace_change' do
context 'as html' do
before do
go(format: 'html', w: 1)
end
it 'renders the diff template' do
expect(response).to render_template('diffs')
end
end
context 'as json' do
before do
go(format: 'json', w: 1)
end
it 'renders the diffs template to a string' do
expect(response).to render_template('projects/merge_requests/show/_diffs')
expect(json_response).to have_key('html')
end
end
end
context 'with view' do
before do
go(view: 'parallel')
end
it 'saves the preferred diff view in a cookie' do
expect(response.cookies['diff_view']).to eq('parallel')
end
end
end
describe 'GET diff_for_path' do
def diff_for_path(extra_params = {})
params = {
namespace_id: project.namespace.to_param,
project_id: project
}
get :diff_for_path, params.merge(extra_params)
end
context 'when an ID param is passed' do
let(:existing_path) { 'files/ruby/popen.rb' }
context 'when the merge request exists' do
context 'when the user can view the merge request' do
context 'when the path exists in the diff' do
it 'enables diff notes' do
diff_for_path(id: merge_request.iid, old_path: existing_path, new_path: existing_path)
expect(assigns(:diff_notes_disabled)).to be_falsey
expect(assigns(:new_diff_note_attrs)).to eq(noteable_type: 'MergeRequest',
noteable_id: merge_request.id)
end
it 'only renders the diffs for the path given' do
expect(controller).to receive(:render_diff_for_path).and_wrap_original do |meth, diffs|
expect(diffs.diff_files.map(&:new_path)).to contain_exactly(existing_path)
meth.call(diffs)
end
diff_for_path(id: merge_request.iid, old_path: existing_path, new_path: existing_path)
end
end
context 'when the path does not exist in the diff' do
before do
diff_for_path(id: merge_request.iid, old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb')
end
it 'returns a 404' do
expect(response).to have_http_status(404)
end
end
end
context 'when the user cannot view the merge request' do
before do
project.team.truncate
diff_for_path(id: merge_request.iid, old_path: existing_path, new_path: existing_path)
end
it 'returns a 404' do
expect(response).to have_http_status(404)
end
end
end
context 'when the merge request does not exist' do
before do
diff_for_path(id: merge_request.iid.succ, old_path: existing_path, new_path: existing_path)
end
it 'returns a 404' do
expect(response).to have_http_status(404)
end
end
context 'when the merge request belongs to a different project' do
let(:other_project) { create(:empty_project) }
before do
other_project.team << [user, :master]
diff_for_path(id: merge_request.iid, old_path: existing_path, new_path: existing_path, project_id: other_project)
end
it 'returns a 404' do
expect(response).to have_http_status(404)
end
end
end
context 'when source and target params are passed' do
let(:existing_path) { 'files/ruby/feature.rb' }
context 'when both branches are in the same project' do
it 'disables diff notes' do
diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_branch: 'feature', target_branch: 'master' })
expect(assigns(:diff_notes_disabled)).to be_truthy
end
it 'only renders the diffs for the path given' do
expect(controller).to receive(:render_diff_for_path).and_wrap_original do |meth, diffs|
expect(diffs.diff_files.map(&:new_path)).to contain_exactly(existing_path)
meth.call(diffs)
end
diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_branch: 'feature', target_branch: 'master' })
end
end
context 'when the source branch is in a different project to the target' do
let(:other_project) { create(:project) }
before do
other_project.team << [user, :master]
end
context 'when the path exists in the diff' do
it 'disables diff notes' do
diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' })
expect(assigns(:diff_notes_disabled)).to be_truthy
end
it 'only renders the diffs for the path given' do
expect(controller).to receive(:render_diff_for_path).and_wrap_original do |meth, diffs|
expect(diffs.diff_files.map(&:new_path)).to contain_exactly(existing_path)
meth.call(diffs)
end
diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' })
end
end
context 'when the path does not exist in the diff' do
before do
diff_for_path(old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb', merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' })
end
it 'returns a 404' do
expect(response).to have_http_status(404)
end
end
end
end
end
describe 'GET commits' do describe 'GET commits' do
def go(format: 'html') def go(format: 'html')
get :commits, get :commits,
...@@ -734,39 +459,20 @@ describe Projects::MergeRequestsController do ...@@ -734,39 +459,20 @@ describe Projects::MergeRequestsController do
format: format format: format
end end
it_behaves_like "loads labels", :commits
context 'as html' do
it 'renders the show template' do
go
expect(response).to render_template('show')
end
end
context 'as json' do
it 'renders the commits template to a string' do it 'renders the commits template to a string' do
go format: 'json' go format: 'json'
expect(response).to render_template('projects/merge_requests/show/_commits') expect(response).to render_template('projects/merge_requests/_commits')
expect(json_response).to have_key('html') expect(json_response).to have_key('html')
end end
end end
end
describe 'GET pipelines' do describe 'GET pipelines' do
before do before do
create(:ci_pipeline, project: merge_request.source_project, create(:ci_pipeline, project: merge_request.source_project,
ref: merge_request.source_branch, ref: merge_request.source_branch,
sha: merge_request.diff_head_sha) sha: merge_request.diff_head_sha)
end
context 'when using HTML format' do
it_behaves_like "loads labels", :pipelines
end
context 'when using JSON format' do
before do
get :pipelines, get :pipelines,
namespace_id: project.namespace.to_param, namespace_id: project.namespace.to_param,
project_id: project, project_id: project,
...@@ -778,89 +484,6 @@ describe Projects::MergeRequestsController do ...@@ -778,89 +484,6 @@ describe Projects::MergeRequestsController do
expect(json_response).not_to be_empty expect(json_response).not_to be_empty
end end
end end
end
describe 'GET conflicts' do
context 'when the conflicts cannot be resolved in the UI' do
before do
allow_any_instance_of(Gitlab::Conflict::Parser)
.to receive(:parse).and_raise(Gitlab::Conflict::Parser::UnmergeableFile)
get :conflicts,
namespace_id: merge_request_with_conflicts.project.namespace.to_param,
project_id: merge_request_with_conflicts.project,
id: merge_request_with_conflicts.iid,
format: 'json'
end
it 'returns a 200 status code' do
expect(response).to have_http_status(:ok)
end
it 'returns JSON with a message' do
expect(json_response.keys).to contain_exactly('message', 'type')
end
end
context 'with valid conflicts' do
before do
get :conflicts,
namespace_id: merge_request_with_conflicts.project.namespace.to_param,
project_id: merge_request_with_conflicts.project,
id: merge_request_with_conflicts.iid,
format: 'json'
end
it 'matches the schema' do
expect(response).to match_response_schema('conflicts')
end
it 'includes meta info about the MR' do
expect(json_response['commit_message']).to include('Merge branch')
expect(json_response['commit_sha']).to match(/\h{40}/)
expect(json_response['source_branch']).to eq(merge_request_with_conflicts.source_branch)
expect(json_response['target_branch']).to eq(merge_request_with_conflicts.target_branch)
end
it 'includes each file that has conflicts' do
filenames = json_response['files'].map { |file| file['new_path'] }
expect(filenames).to contain_exactly('files/ruby/popen.rb', 'files/ruby/regex.rb')
end
it 'splits files into sections with lines' do
json_response['files'].each do |file|
file['sections'].each do |section|
expect(section).to include('conflict', 'lines')
section['lines'].each do |line|
if section['conflict']
expect(line['type']).to be_in(%w(old new))
expect(line.values_at('old_line', 'new_line')).to contain_exactly(nil, a_kind_of(Integer))
else
if line['type'].nil?
expect(line['old_line']).not_to eq(nil)
expect(line['new_line']).not_to eq(nil)
else
expect(line['type']).to eq('match')
expect(line['old_line']).to eq(nil)
expect(line['new_line']).to eq(nil)
end
end
end
end
end
end
it 'has unique section IDs across files' do
section_ids = json_response['files'].flat_map do |file|
file['sections'].map { |section| section['id'] }.compact
end
expect(section_ids.uniq).to eq(section_ids)
end
end
end
describe 'POST remove_wip' do describe 'POST remove_wip' do
before do before do
...@@ -913,215 +536,6 @@ describe Projects::MergeRequestsController do ...@@ -913,215 +536,6 @@ describe Projects::MergeRequestsController do
end end
end end
describe 'GET conflict_for_path' do
def conflict_for_path(path)
get :conflict_for_path,
namespace_id: merge_request_with_conflicts.project.namespace.to_param,
project_id: merge_request_with_conflicts.project,
id: merge_request_with_conflicts.iid,
old_path: path,
new_path: path,
format: 'json'
end
context 'when the conflicts cannot be resolved in the UI' do
before do
allow_any_instance_of(Gitlab::Conflict::Parser)
.to receive(:parse).and_raise(Gitlab::Conflict::Parser::UnmergeableFile)
conflict_for_path('files/ruby/regex.rb')
end
it 'returns a 404 status code' do
expect(response).to have_http_status(:not_found)
end
end
context 'when the file does not exist cannot be resolved in the UI' do
before do
conflict_for_path('files/ruby/regexp.rb')
end
it 'returns a 404 status code' do
expect(response).to have_http_status(:not_found)
end
end
context 'with an existing file' do
let(:path) { 'files/ruby/regex.rb' }
before do
conflict_for_path(path)
end
it 'returns a 200 status code' do
expect(response).to have_http_status(:ok)
end
it 'returns the file in JSON format' do
content = MergeRequests::Conflicts::ListService.new(merge_request_with_conflicts)
.file_for_path(path, path)
.content
expect(json_response).to include('old_path' => path,
'new_path' => path,
'blob_icon' => 'file-text-o',
'blob_path' => a_string_ending_with(path),
'blob_ace_mode' => 'ruby',
'content' => content)
end
end
end
context 'POST resolve_conflicts' do
let!(:original_head_sha) { merge_request_with_conflicts.diff_head_sha }
def resolve_conflicts(files)
post :resolve_conflicts,
namespace_id: merge_request_with_conflicts.project.namespace.to_param,
project_id: merge_request_with_conflicts.project,
id: merge_request_with_conflicts.iid,
format: 'json',
files: files,
commit_message: 'Commit message'
end
context 'with valid params' do
before do
resolved_files = [
{
'new_path' => 'files/ruby/popen.rb',
'old_path' => 'files/ruby/popen.rb',
'sections' => {
'2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_14' => 'head'
}
}, {
'new_path' => 'files/ruby/regex.rb',
'old_path' => 'files/ruby/regex.rb',
'sections' => {
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin'
}
}
]
resolve_conflicts(resolved_files)
end
it 'creates a new commit on the branch' do
expect(original_head_sha).not_to eq(merge_request_with_conflicts.source_branch_head.sha)
expect(merge_request_with_conflicts.source_branch_head.message).to include('Commit message')
end
it 'returns an OK response' do
expect(response).to have_http_status(:ok)
end
end
context 'when sections are missing' do
before do
resolved_files = [
{
'new_path' => 'files/ruby/popen.rb',
'old_path' => 'files/ruby/popen.rb',
'sections' => {
'2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_14' => 'head'
}
}, {
'new_path' => 'files/ruby/regex.rb',
'old_path' => 'files/ruby/regex.rb',
'sections' => {
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head'
}
}
]
resolve_conflicts(resolved_files)
end
it 'returns a 400 error' do
expect(response).to have_http_status(:bad_request)
end
it 'has a message with the name of the first missing section' do
expect(json_response['message']).to include('6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21')
end
it 'does not create a new commit' do
expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
end
end
context 'when files are missing' do
before do
resolved_files = [
{
'new_path' => 'files/ruby/regex.rb',
'old_path' => 'files/ruby/regex.rb',
'sections' => {
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin'
}
}
]
resolve_conflicts(resolved_files)
end
it 'returns a 400 error' do
expect(response).to have_http_status(:bad_request)
end
it 'has a message with the name of the missing file' do
expect(json_response['message']).to include('files/ruby/popen.rb')
end
it 'does not create a new commit' do
expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
end
end
context 'when a file has identical content to the conflict' do
before do
content = MergeRequests::Conflicts::ListService.new(merge_request_with_conflicts)
.file_for_path('files/ruby/popen.rb', 'files/ruby/popen.rb')
.content
resolved_files = [
{
'new_path' => 'files/ruby/popen.rb',
'old_path' => 'files/ruby/popen.rb',
'content' => content
}, {
'new_path' => 'files/ruby/regex.rb',
'old_path' => 'files/ruby/regex.rb',
'sections' => {
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin'
}
}
]
resolve_conflicts(resolved_files)
end
it 'returns a 400 error' do
expect(response).to have_http_status(:bad_request)
end
it 'has a message with the path of the problem file' do
expect(json_response['message']).to include('files/ruby/popen.rb')
end
it 'does not create a new commit' do
expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
end
end
end
describe 'POST assign_related_issues' do describe 'POST assign_related_issues' do
let(:issue1) { create(:issue, project: project) } let(:issue1) { create(:issue, project: project) }
let(:issue2) { create(:issue, project: project) } let(:issue2) { create(:issue, project: project) }
......
...@@ -65,7 +65,7 @@ feature 'Create New Merge Request', feature: true, js: true do ...@@ -65,7 +65,7 @@ feature 'Create New Merge Request', feature: true, js: true do
it 'does not leak the private project name & namespace' do it 'does not leak the private project name & namespace' do
private_project = create(:project, :private) private_project = create(:project, :private)
visit new_namespace_project_merge_request_path(project.namespace, project, merge_request: { target_project_id: private_project.id }) visit namespace_project_new_merge_request_path(project.namespace, project, merge_request: { target_project_id: private_project.id })
expect(page).not_to have_content private_project.path_with_namespace expect(page).not_to have_content private_project.path_with_namespace
expect(page).to have_content project.path_with_namespace expect(page).to have_content project.path_with_namespace
...@@ -76,7 +76,7 @@ feature 'Create New Merge Request', feature: true, js: true do ...@@ -76,7 +76,7 @@ feature 'Create New Merge Request', feature: true, js: true do
it 'does not leak the private project name & namespace' do it 'does not leak the private project name & namespace' do
private_project = create(:project, :private) private_project = create(:project, :private)
visit new_namespace_project_merge_request_path(project.namespace, project, merge_request: { source_project_id: private_project.id }) visit namespace_project_new_merge_request_path(project.namespace, project, merge_request: { source_project_id: private_project.id })
expect(page).not_to have_content private_project.path_with_namespace expect(page).not_to have_content private_project.path_with_namespace
expect(page).to have_content project.path_with_namespace expect(page).to have_content project.path_with_namespace
...@@ -84,13 +84,13 @@ feature 'Create New Merge Request', feature: true, js: true do ...@@ -84,13 +84,13 @@ feature 'Create New Merge Request', feature: true, js: true do
end end
it 'populates source branch button' do it 'populates source branch button' do
visit new_namespace_project_merge_request_path(project.namespace, project, change_branches: true, merge_request: { target_branch: 'master', source_branch: 'fix' }) visit namespace_project_new_merge_request_path(project.namespace, project, change_branches: true, merge_request: { target_branch: 'master', source_branch: 'fix' })
expect(find('.js-source-branch')).to have_content('fix') expect(find('.js-source-branch')).to have_content('fix')
end end
it 'allows to change the diff view' do it 'allows to change the diff view' do
visit new_namespace_project_merge_request_path(project.namespace, project, merge_request: { target_branch: 'master', source_branch: 'fix' }) visit namespace_project_new_merge_request_path(project.namespace, project, merge_request: { target_branch: 'master', source_branch: 'fix' })
click_link 'Changes' click_link 'Changes'
...@@ -106,7 +106,7 @@ feature 'Create New Merge Request', feature: true, js: true do ...@@ -106,7 +106,7 @@ feature 'Create New Merge Request', feature: true, js: true do
end end
it 'does not allow non-existing branches' do it 'does not allow non-existing branches' do
visit new_namespace_project_merge_request_path(project.namespace, project, merge_request: { target_branch: 'non-exist-target', source_branch: 'non-exist-source' }) visit namespace_project_new_merge_request_path(project.namespace, project, merge_request: { target_branch: 'non-exist-target', source_branch: 'non-exist-source' })
expect(page).to have_content('The form contains the following errors') expect(page).to have_content('The form contains the following errors')
expect(page).to have_content('Source branch "non-exist-source" does not exist') expect(page).to have_content('Source branch "non-exist-source" does not exist')
...@@ -115,7 +115,7 @@ feature 'Create New Merge Request', feature: true, js: true do ...@@ -115,7 +115,7 @@ feature 'Create New Merge Request', feature: true, js: true do
context 'when a branch contains commits that both delete and add the same image' do context 'when a branch contains commits that both delete and add the same image' do
it 'renders the diff successfully' do it 'renders the diff successfully' do
visit new_namespace_project_merge_request_path(project.namespace, project, merge_request: { target_branch: 'master', source_branch: 'deleted-image-test' }) visit namespace_project_new_merge_request_path(project.namespace, project, merge_request: { target_branch: 'master', source_branch: 'deleted-image-test' })
click_link "Changes" click_link "Changes"
...@@ -125,7 +125,7 @@ feature 'Create New Merge Request', feature: true, js: true do ...@@ -125,7 +125,7 @@ feature 'Create New Merge Request', feature: true, js: true do
# Isolates a regression (see #24627) # Isolates a regression (see #24627)
it 'does not show error messages on initial form' do it 'does not show error messages on initial form' do
visit new_namespace_project_merge_request_path(project.namespace, project) visit namespace_project_new_merge_request_path(project.namespace, project)
expect(page).not_to have_selector('#error_explanation') expect(page).not_to have_selector('#error_explanation')
expect(page).not_to have_content('The form contains the following error') expect(page).not_to have_content('The form contains the following error')
end end
...@@ -138,7 +138,7 @@ feature 'Create New Merge Request', feature: true, js: true do ...@@ -138,7 +138,7 @@ feature 'Create New Merge Request', feature: true, js: true do
end end
it 'shows pipelines for a new merge request' do it 'shows pipelines for a new merge request' do
visit new_namespace_project_merge_request_path( visit namespace_project_new_merge_request_path(
project.namespace, project, project.namespace, project,
merge_request: { target_branch: 'master', source_branch: 'fix' }) merge_request: { target_branch: 'master', source_branch: 'fix' })
......
...@@ -23,7 +23,7 @@ describe 'New/edit merge request', feature: true, js: true do ...@@ -23,7 +23,7 @@ describe 'New/edit merge request', feature: true, js: true do
context 'new merge request' do context 'new merge request' do
before do before do
visit new_namespace_project_merge_request_path( visit namespace_project_new_merge_request_path(
project.namespace, project.namespace,
project, project,
merge_request: { merge_request: {
...@@ -182,7 +182,7 @@ describe 'New/edit merge request', feature: true, js: true do ...@@ -182,7 +182,7 @@ describe 'New/edit merge request', feature: true, js: true do
context 'new merge request' do context 'new merge request' do
before do before do
visit new_namespace_project_merge_request_path( visit namespace_project_new_merge_request_path(
fork_project.namespace, fork_project.namespace,
fork_project, fork_project,
merge_request: { merge_request: {
......
...@@ -131,7 +131,7 @@ feature 'Merge Requests > User uses quick actions', feature: true, js: true do ...@@ -131,7 +131,7 @@ feature 'Merge Requests > User uses quick actions', feature: true, js: true do
end end
it 'changes target_branch in new merge_request' do it 'changes target_branch in new merge_request' do
visit new_namespace_project_merge_request_path(another_project.namespace, another_project, new_url_opts) visit namespace_project_new_merge_request_path(another_project.namespace, another_project, new_url_opts)
fill_in "merge_request_title", with: 'My brand new feature' fill_in "merge_request_title", with: 'My brand new feature'
fill_in "merge_request_description", with: "le feature \n/target_branch fix\nFeature description:" fill_in "merge_request_description", with: "le feature \n/target_branch fix\nFeature description:"
......
...@@ -12,7 +12,7 @@ describe 'Merge request', :feature, :js do ...@@ -12,7 +12,7 @@ describe 'Merge request', :feature, :js do
context 'new merge request' do context 'new merge request' do
before do before do
visit new_namespace_project_merge_request_path( visit namespace_project_new_merge_request_path(
project.namespace, project.namespace,
project, project,
merge_request: { merge_request: {
......
...@@ -11,7 +11,7 @@ feature 'Work In Progress help message', feature: true do ...@@ -11,7 +11,7 @@ feature 'Work In Progress help message', feature: true do
context 'with WIP commits' do context 'with WIP commits' do
it 'shows a specific WIP hint' do it 'shows a specific WIP hint' do
visit new_namespace_project_merge_request_path( visit namespace_project_new_merge_request_path(
project.namespace, project.namespace,
project, project,
merge_request: { merge_request: {
...@@ -32,7 +32,7 @@ feature 'Work In Progress help message', feature: true do ...@@ -32,7 +32,7 @@ feature 'Work In Progress help message', feature: true do
context 'without WIP commits' do context 'without WIP commits' do
it 'shows the regular WIP message' do it 'shows the regular WIP message' do
visit new_namespace_project_merge_request_path( visit namespace_project_new_merge_request_path(
project.namespace, project.namespace,
project, project,
merge_request: { merge_request: {
......
...@@ -23,7 +23,7 @@ feature 'Merge Request button', feature: true do ...@@ -23,7 +23,7 @@ feature 'Merge Request button', feature: true do
end end
it 'shows Create merge request button' do it 'shows Create merge request button' do
href = new_namespace_project_merge_request_path(project.namespace, href = namespace_project_new_merge_request_path(project.namespace,
project, project,
merge_request: { source_branch: 'feature', merge_request: { source_branch: 'feature',
target_branch: 'master' }) target_branch: 'master' })
...@@ -67,7 +67,7 @@ feature 'Merge Request button', feature: true do ...@@ -67,7 +67,7 @@ feature 'Merge Request button', feature: true do
let(:user) { forked_project.owner } let(:user) { forked_project.owner }
it 'shows Create merge request button' do it 'shows Create merge request button' do
href = new_namespace_project_merge_request_path(forked_project.namespace, href = namespace_project_new_merge_request_path(forked_project.namespace,
forked_project, forked_project,
merge_request: { source_branch: 'feature', merge_request: { source_branch: 'feature',
target_branch: 'master' }) target_branch: 'master' })
......
...@@ -27,7 +27,7 @@ feature 'Merge Requests List' do ...@@ -27,7 +27,7 @@ feature 'Merge Requests List' do
it 'empty state should have a create merge request button' do it 'empty state should have a create merge request button' do
visit namespace_project_merge_requests_path(project.namespace, project) visit namespace_project_merge_requests_path(project.namespace, project)
expect(page).to have_link 'New merge request', href: new_namespace_project_merge_request_path(project.namespace, project) expect(page).to have_link 'New merge request', href: namespace_project_new_merge_request_path(project.namespace, project)
end end
context 'if there are merge requests' do context 'if there are merge requests' do
......
...@@ -51,7 +51,7 @@ feature 'New directory creation', feature: true, js: true do ...@@ -51,7 +51,7 @@ feature 'New directory creation', feature: true, js: true do
expect(page).to have_content 'New Merge Request' expect(page).to have_content 'New Merge Request'
expect(page).to have_content "From #{new_branch_name} into master" expect(page).to have_content "From #{new_branch_name} into master"
expect(page).to have_content 'Add new directory' expect(page).to have_content 'Add new directory'
expect(current_path).to eq(new_namespace_project_merge_request_path(project.namespace, project)) expect(current_path).to eq(namespace_project_new_merge_request_path(project.namespace, project))
end end
end end
end end
...@@ -239,7 +239,7 @@ describe "Internal Project Access", feature: true do ...@@ -239,7 +239,7 @@ describe "Internal Project Access", feature: true do
end end
describe "GET /:project_path/merge_requests/new" do describe "GET /:project_path/merge_requests/new" do
subject { new_namespace_project_merge_request_path(project.namespace, project) } subject { namespace_project_new_merge_request_path(project.namespace, project) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:owner).of(project) }
......
...@@ -452,7 +452,7 @@ describe "Public Project Access", feature: true do ...@@ -452,7 +452,7 @@ describe "Public Project Access", feature: true do
end end
describe "GET /:project_path/merge_requests/new" do describe "GET /:project_path/merge_requests/new" do
subject { new_namespace_project_merge_request_path(project.namespace, project) } subject { namespace_project_new_merge_request_path(project.namespace, project) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:owner).of(project) }
......
...@@ -55,27 +55,14 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont ...@@ -55,27 +55,14 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont
render_merge_request(example.description, merge_request) render_merge_request(example.description, merge_request)
end end
it 'merge_requests/inline_changes_tab_with_comments.json' do |example|
create(:diff_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request)
create(:note_on_merge_request, author: admin, project: project, noteable: merge_request)
render_merge_request(example.description, merge_request, action: :diffs, format: :json)
end
it 'merge_requests/parallel_changes_tab_with_comments.json' do |example|
create(:diff_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request)
create(:note_on_merge_request, author: admin, project: project, noteable: merge_request)
render_merge_request(example.description, merge_request, action: :diffs, format: :json, view: 'parallel')
end
private private
def render_merge_request(fixture_file_name, merge_request, action: :show, format: :html, view: 'inline') def render_merge_request(fixture_file_name, merge_request)
get action, get :show,
namespace_id: project.namespace.to_param, namespace_id: project.namespace.to_param,
project_id: project, project_id: project,
id: merge_request.to_param, id: merge_request.to_param,
format: format, format: :html
view: view
expect(response).to be_success expect(response).to be_success
store_frontend_fixture(response, fixture_file_name) store_frontend_fixture(response, fixture_file_name)
......
require 'spec_helper'
describe Projects::MergeRequests::DiffsController, '(JavaScript fixtures)', type: :controller do
include JavaScriptFixturesHelpers
let(:admin) { create(:admin) }
let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
let(:project) { create(:project, namespace: namespace, path: 'merge-requests-project') }
let(:merge_request) { create(:merge_request, :with_diffs, source_project: project, target_project: project, description: '- [ ] Task List Item') }
let(:path) { "files/ruby/popen.rb" }
let(:position) do
Gitlab::Diff::Position.new(
old_path: path,
new_path: path,
old_line: nil,
new_line: 14,
diff_refs: merge_request.diff_refs
)
end
render_views
before(:all) do
clean_frontend_fixtures('merge_request_diffs/')
end
before(:each) do
sign_in(admin)
end
it 'merge_request_diffs/inline_changes_tab_with_comments.json' do |example|
create(:diff_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request)
create(:note_on_merge_request, author: admin, project: project, noteable: merge_request)
render_merge_request(example.description, merge_request)
end
it 'merge_request_diffs/parallel_changes_tab_with_comments.json' do |example|
create(:diff_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request)
create(:note_on_merge_request, author: admin, project: project, noteable: merge_request)
render_merge_request(example.description, merge_request, view: 'parallel')
end
private
def render_merge_request(fixture_file_name, merge_request, view: 'inline')
get :show,
namespace_id: project.namespace.to_param,
project_id: project,
id: merge_request.to_param,
format: :json,
view: view
expect(response).to be_success
store_frontend_fixture(response, fixture_file_name)
end
end
...@@ -15,7 +15,7 @@ describe('Merge request notes', () => { ...@@ -15,7 +15,7 @@ describe('Merge request notes', () => {
gl.utils = gl.utils || {}; gl.utils = gl.utils || {};
const discussionTabFixture = 'merge_requests/diff_comment.html.raw'; const discussionTabFixture = 'merge_requests/diff_comment.html.raw';
const changesTabJsonFixture = 'merge_requests/inline_changes_tab_with_comments.json'; const changesTabJsonFixture = 'merge_request_diffs/inline_changes_tab_with_comments.json';
preloadFixtures(discussionTabFixture, changesTabJsonFixture); preloadFixtures(discussionTabFixture, changesTabJsonFixture);
describe('Discussion tab with diff comments', () => { describe('Discussion tab with diff comments', () => {
......
...@@ -23,8 +23,8 @@ import 'vendor/jquery.scrollTo'; ...@@ -23,8 +23,8 @@ import 'vendor/jquery.scrollTo';
$.extend(stubLocation, defaults, stubs || {}); $.extend(stubLocation, defaults, stubs || {});
}; };
const inlineChangesTabJsonFixture = 'merge_requests/inline_changes_tab_with_comments.json'; const inlineChangesTabJsonFixture = 'merge_request_diffs/inline_changes_tab_with_comments.json';
const parallelChangesTabJsonFixture = 'merge_requests/parallel_changes_tab_with_comments.json'; const parallelChangesTabJsonFixture = 'merge_request_diffs/parallel_changes_tab_with_comments.json';
preloadFixtures( preloadFixtures(
'merge_requests/merge_request_with_task_list.html.raw', 'merge_requests/merge_request_with_task_list.html.raw',
'merge_requests/diff_comment.html.raw', 'merge_requests/diff_comment.html.raw',
...@@ -52,14 +52,10 @@ import 'vendor/jquery.scrollTo'; ...@@ -52,14 +52,10 @@ import 'vendor/jquery.scrollTo';
loadFixtures('merge_requests/merge_request_with_task_list.html.raw'); loadFixtures('merge_requests/merge_request_with_task_list.html.raw');
this.subject = this.class.activateTab; this.subject = this.class.activateTab;
}); });
it('shows the first tab when action is show', function () { it('shows the notes tab when action is show', function () {
this.subject('show'); this.subject('show');
expect($('#notes')).toHaveClass('active'); expect($('#notes')).toHaveClass('active');
}); });
it('shows the notes tab when action is notes', function () {
this.subject('notes');
expect($('#notes')).toHaveClass('active');
});
it('shows the commits tab when action is commits', function () { it('shows the commits tab when action is commits', function () {
this.subject('commits'); this.subject('commits');
expect($('#commits')).toHaveClass('active'); expect($('#commits')).toHaveClass('active');
...@@ -161,7 +157,7 @@ import 'vendor/jquery.scrollTo'; ...@@ -161,7 +157,7 @@ import 'vendor/jquery.scrollTo';
setLocation({ setLocation({
pathname: '/foo/bar/merge_requests/1/commits' pathname: '/foo/bar/merge_requests/1/commits'
}); });
expect(this.subject('notes')).toBe('/foo/bar/merge_requests/1'); expect(this.subject('show')).toBe('/foo/bar/merge_requests/1');
expect(this.subject('diffs')).toBe('/foo/bar/merge_requests/1/diffs'); expect(this.subject('diffs')).toBe('/foo/bar/merge_requests/1/diffs');
}); });
...@@ -170,7 +166,7 @@ import 'vendor/jquery.scrollTo'; ...@@ -170,7 +166,7 @@ import 'vendor/jquery.scrollTo';
pathname: '/foo/bar/merge_requests/1/diffs' pathname: '/foo/bar/merge_requests/1/diffs'
}); });
expect(this.subject('notes')).toBe('/foo/bar/merge_requests/1'); expect(this.subject('show')).toBe('/foo/bar/merge_requests/1');
expect(this.subject('commits')).toBe('/foo/bar/merge_requests/1/commits'); expect(this.subject('commits')).toBe('/foo/bar/merge_requests/1/commits');
}); });
...@@ -178,7 +174,7 @@ import 'vendor/jquery.scrollTo'; ...@@ -178,7 +174,7 @@ import 'vendor/jquery.scrollTo';
setLocation({ setLocation({
pathname: '/foo/bar/merge_requests/1/diffs.html' pathname: '/foo/bar/merge_requests/1/diffs.html'
}); });
expect(this.subject('notes')).toBe('/foo/bar/merge_requests/1'); expect(this.subject('show')).toBe('/foo/bar/merge_requests/1');
expect(this.subject('commits')).toBe('/foo/bar/merge_requests/1/commits'); expect(this.subject('commits')).toBe('/foo/bar/merge_requests/1/commits');
}); });
......
...@@ -246,28 +246,13 @@ describe 'project routing' do ...@@ -246,28 +246,13 @@ describe 'project routing' do
end end
end end
# diffs_namespace_project_merge_request GET /:namespace_id/:project_id/merge_requests/:id/diffs(.:format) projects/merge_requests#diffs
# commits_namespace_project_merge_request GET /:namespace_id/:project_id/merge_requests/:id/commits(.:format) projects/merge_requests#commits
# merge_namespace_project_merge_request POST /:namespace_id/:project_id/merge_requests/:id/merge(.:format) projects/merge_requests#merge
# ci_status_namespace_project_merge_request GET /:namespace_id/:project_id/merge_requests/:id/ci_status(.:format) projects/merge_requests#ci_status
# toggle_subscription_namespace_project_merge_request POST /:namespace_id/:project_id/merge_requests/:id/toggle_subscription(.:format) projects/merge_requests#toggle_subscription
# branch_from_namespace_project_merge_requests GET /:namespace_id/:project_id/merge_requests/branch_from(.:format) projects/merge_requests#branch_from
# branch_to_namespace_project_merge_requests GET /:namespace_id/:project_id/merge_requests/branch_to(.:format) projects/merge_requests#branch_to
# update_branches_namespace_project_merge_requests GET /:namespace_id/:project_id/merge_requests/update_branches(.:format) projects/merge_requests#update_branches
# namespace_project_merge_requests GET /:namespace_id/:project_id/merge_requests(.:format) projects/merge_requests#index
# POST /:namespace_id/:project_id/merge_requests(.:format) projects/merge_requests#create
# new_namespace_project_merge_request GET /:namespace_id/:project_id/merge_requests/new(.:format) projects/merge_requests#new
# edit_namespace_project_merge_request GET /:namespace_id/:project_id/merge_requests/:id/edit(.:format) projects/merge_requests#edit
# namespace_project_merge_request GET /:namespace_id/:project_id/merge_requests/:id(.:format) projects/merge_requests#show
# PATCH /:namespace_id/:project_id/merge_requests/:id(.:format) projects/merge_requests#update
# PUT /:namespace_id/:project_id/merge_requests/:id(.:format) projects/merge_requests#update
describe Projects::MergeRequestsController, 'routing' do describe Projects::MergeRequestsController, 'routing' do
it 'to #diffs' do it 'to #commits' do
expect(get('/gitlab/gitlabhq/merge_requests/1/diffs')).to route_to('projects/merge_requests#diffs', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') expect(get('/gitlab/gitlabhq/merge_requests/1/commits.json')).to route_to('projects/merge_requests#commits', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: 'json')
end end
it 'to #commits' do it 'to #pipelines' do
expect(get('/gitlab/gitlabhq/merge_requests/1/commits')).to route_to('projects/merge_requests#commits', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') expect(get('/gitlab/gitlabhq/merge_requests/1/pipelines.json')).to route_to('projects/merge_requests#pipelines', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: 'json')
end end
it 'to #merge' do it 'to #merge' do
...@@ -277,25 +262,59 @@ describe 'project routing' do ...@@ -277,25 +262,59 @@ describe 'project routing' do
) )
end end
it 'to #show' do
expect(get('/gitlab/gitlabhq/merge_requests/1.diff')).to route_to('projects/merge_requests#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: 'diff')
expect(get('/gitlab/gitlabhq/merge_requests/1.patch')).to route_to('projects/merge_requests#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: 'patch')
expect(get('/gitlab/gitlabhq/merge_requests/1/diffs')).to route_to('projects/merge_requests#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', tab: 'diffs')
expect(get('/gitlab/gitlabhq/merge_requests/1/commits')).to route_to('projects/merge_requests#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', tab: 'commits')
expect(get('/gitlab/gitlabhq/merge_requests/1/pipelines')).to route_to('projects/merge_requests#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', tab: 'pipelines')
end
it_behaves_like 'RESTful project resources' do
let(:controller) { 'merge_requests' }
let(:actions) { [:index, :edit, :show, :update] }
end
end
describe Projects::MergeRequests::CreationsController, 'routing' do
it 'to #new' do
expect(get('/gitlab/gitlabhq/merge_requests/new')).to route_to('projects/merge_requests/creations#new', namespace_id: 'gitlab', project_id: 'gitlabhq')
expect(get('/gitlab/gitlabhq/merge_requests/new/diffs')).to route_to('projects/merge_requests/creations#new', namespace_id: 'gitlab', project_id: 'gitlabhq', tab: 'diffs')
expect(get('/gitlab/gitlabhq/merge_requests/new/pipelines')).to route_to('projects/merge_requests/creations#new', namespace_id: 'gitlab', project_id: 'gitlabhq', tab: 'pipelines')
end
it 'to #create' do
expect(post('/gitlab/gitlabhq/merge_requests')).to route_to('projects/merge_requests/creations#create', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
it 'to #branch_from' do it 'to #branch_from' do
expect(get('/gitlab/gitlabhq/merge_requests/branch_from')).to route_to('projects/merge_requests#branch_from', namespace_id: 'gitlab', project_id: 'gitlabhq') expect(get('/gitlab/gitlabhq/merge_requests/new/branch_from')).to route_to('projects/merge_requests/creations#branch_from', namespace_id: 'gitlab', project_id: 'gitlabhq')
end end
it 'to #branch_to' do it 'to #branch_to' do
expect(get('/gitlab/gitlabhq/merge_requests/branch_to')).to route_to('projects/merge_requests#branch_to', namespace_id: 'gitlab', project_id: 'gitlabhq') expect(get('/gitlab/gitlabhq/merge_requests/new/branch_to')).to route_to('projects/merge_requests/creations#branch_to', namespace_id: 'gitlab', project_id: 'gitlabhq')
end end
it 'to #show' do it 'to #pipelines' do
expect(get('/gitlab/gitlabhq/merge_requests/1.diff')).to route_to('projects/merge_requests#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: 'diff') expect(get('/gitlab/gitlabhq/merge_requests/new/pipelines.json')).to route_to('projects/merge_requests/creations#pipelines', namespace_id: 'gitlab', project_id: 'gitlabhq', format: 'json')
expect(get('/gitlab/gitlabhq/merge_requests/1.patch')).to route_to('projects/merge_requests#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: 'patch')
end end
it_behaves_like 'RESTful project resources' do it 'to #diffs' do
let(:controller) { 'merge_requests' } expect(get('/gitlab/gitlabhq/merge_requests/new/diffs.json')).to route_to('projects/merge_requests/creations#diffs', namespace_id: 'gitlab', project_id: 'gitlabhq', format: 'json')
let(:actions) { [:index, :create, :new, :edit, :show, :update] } end
end
describe Projects::MergeRequests::DiffsController, 'routing' do
it 'to #show' do
expect(get('/gitlab/gitlabhq/merge_requests/1/diffs.json')).to route_to('projects/merge_requests/diffs#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: 'json')
end end
end end
describe Projects::MergeRequests::ConflictsController, 'routing' do
it 'to #show' do
expect(get('/gitlab/gitlabhq/merge_requests/1/conflicts')).to route_to('projects/merge_requests/conflicts#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
end
end
# raw_project_snippet GET /:project_id/snippets/:id/raw(.:format) snippets#raw # raw_project_snippet GET /:project_id/snippets/:id/raw(.:format) snippets#raw
# project_snippets GET /:project_id/snippets(.:format) snippets#index # project_snippets GET /:project_id/snippets(.:format) snippets#index
# POST /:project_id/snippets(.:format) snippets#create # POST /:project_id/snippets(.:format) snippets#create
......
...@@ -28,7 +28,12 @@ shared_examples 'issuable record that supports quick actions in its description ...@@ -28,7 +28,12 @@ shared_examples 'issuable record that supports quick actions in its description
describe "new #{issuable_type}", js: true do describe "new #{issuable_type}", js: true do
context 'with commands in the description' do context 'with commands in the description' do
it "creates the #{issuable_type} and interpret commands accordingly" do it "creates the #{issuable_type} and interpret commands accordingly" do
visit public_send("new_namespace_project_#{issuable_type}_path", project.namespace, project, new_url_opts) case issuable_type
when :merge_request
visit public_send("namespace_project_new_merge_request_path", project.namespace, project, new_url_opts)
when :issue
visit public_send("new_namespace_project_issue_path", project.namespace, project, new_url_opts)
end
fill_in "#{issuable_type}_title", with: 'bug 345' fill_in "#{issuable_type}_title", with: 'bug 345'
fill_in "#{issuable_type}_description", with: "bug description\n/label ~bug\n/milestone %\"ASAP\"" fill_in "#{issuable_type}_description", with: "bug description\n/label ~bug\n/milestone %\"ASAP\""
click_button "Submit #{issuable_type}".humanize click_button "Submit #{issuable_type}".humanize
......
require 'spec_helper' require 'spec_helper'
describe 'projects/merge_requests/show/_commits.html.haml' do describe 'projects/merge_requests/_commits.html.haml' do
include Devise::Test::ControllerHelpers include Devise::Test::ControllerHelpers
let(:user) { create(:user) } let(:user) { create(:user) }
......
require 'spec_helper' require 'spec_helper'
describe 'projects/merge_requests/_new_submit.html.haml', :view do describe 'projects/merge_requests/creations/_new_submit.html.haml', :view do
let(:merge_request) { create(:merge_request) } let(:merge_request) { create(:merge_request) }
let!(:pipeline) { create(:ci_empty_pipeline) } let!(:pipeline) { create(:ci_empty_pipeline) }
......
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