diff options
40 files changed, 569 insertions, 313 deletions
diff --git a/CHANGELOG b/CHANGELOG index 14f2f14becd..145d4c03731 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.5.0 (unreleased) + - Ensure rake tasks that don't need a DB connection can be run without one - Add "visibility" flag to GET /projects api endpoint - Ignore binary files in code search to prevent Error 500 (Stan Hu) - Upgrade gitlab_git to 7.2.23 to fix commit message mentions in first branch push @@ -14,6 +15,8 @@ v 8.5.0 (unreleased) - Track project import failure - Fix visibility level text in admin area (Zeger-Jan van de Weg) - Update the ExternalIssue regex pattern (Blake Hitchcock) + - Deprecate API "merge_request/:merge_request_id/comments". Use "merge_requests/:merge_request_id/notes" instead + - Deprecate API "merge_request/:merge_request_id/...". Use "merge_requests/:merge_request_id/..." instead v 8.4.2 - Bump required gitlab-workhorse version to bring in a fix for missing diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee index cbc70cd846c..d663e34871c 100644 --- a/app/assets/javascripts/issue.js.coffee +++ b/app/assets/javascripts/issue.js.coffee @@ -50,6 +50,7 @@ class @Issue new Flash(issueFailMessage, 'alert') success: (data, textStatus, jqXHR) -> if data.saved + $(document).trigger('issuable:change'); if isClose $('a.btn-close').addClass('hidden') $('a.btn-reopen').removeClass('hidden') diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee index 53d72be66e3..3347ab65c90 100644 --- a/app/assets/javascripts/notes.js.coffee +++ b/app/assets/javascripts/notes.js.coffee @@ -64,6 +64,9 @@ class @Notes # fetch notes when tab becomes visible $(document).on "visibilitychange", @visibilityChange + # when issue status changes, we need to refresh data + $(document).on "issuable:change", @refresh + cleanBinding: -> $(document).off "ajax:success", ".js-main-target-form" $(document).off "ajax:success", ".js-discussion-note-form" diff --git a/app/assets/javascripts/projects_list.js.coffee b/app/assets/javascripts/projects_list.js.coffee index f2887af190b..b71509dbc5a 100644 --- a/app/assets/javascripts/projects_list.js.coffee +++ b/app/assets/javascripts/projects_list.js.coffee @@ -9,11 +9,13 @@ class @ProjectsList $(".projects-list-filter").keyup -> terms = $(this).val() uiBox = $('div.projects-list-holder') + filterSelector = $(this).data('filter-selector') || 'span.filter-title' + if terms == "" || terms == undefined uiBox.find("ul.projects-list li").show() else uiBox.find("ul.projects-list li").each (index) -> - name = $(this).find("span.filter-title").text() + name = $(this).find(filterSelector).text() if name.toLowerCase().search(terms.toLowerCase()) == -1 $(this).hide() diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index 4866a17005d..8d8f41287da 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -115,7 +115,7 @@ ul, ol { padding: 0; - margin: 6px 0 6px 18px !important; + margin: 6px 0 6px 28px !important; } li { diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 003a4c22f20..e4ea47cc4a2 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -564,3 +564,53 @@ pre.light-well { color: #E62958; margin-top: 2px; } + +/* + * Forks list rendered on Project's forks page + */ + +.forks-top-block { + padding: 16px 0; +} + +.projects-search-form { + .dropdown-toggle.btn { + margin-top: -3px; + } + + &.fork-search-form { + margin: 0; + margin-top: -$gl-padding; + padding-bottom: 0; + + input { + /* Small devices (tablets, 768px and up) */ + @media (min-width: $screen-sm-min) { width: 180px; } + + /* Medium devices (desktops, 992px and up) */ + @media (min-width: $screen-md-min) { width: 350px; } + + /* Large devices (large desktops, 1200px and up) */ + @media (min-width: $screen-lg-min) { width: 400px; } + } + + .sort-forks { + width: 160px; + } + + .fork-link { + float: right; + margin-left: $gl-padding; + } + } +} + +.private-forks-notice .private-fork-icon { + i:nth-child(1) { + color: #2AA056; + } + + i:nth-child(2) { + color: #FFFFFF; + } +} diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 2d735b90597..824175c8a6c 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -298,7 +298,8 @@ class ApplicationController < ActionController::Base end def set_filters_params - params[:sort] ||= 'id_desc' + set_default_sort + params[:scope] = 'all' if params[:scope].blank? params[:state] = 'opened' if params[:state].blank? @@ -405,4 +406,24 @@ class ApplicationController < ActionController::Base current_user.nil? && root_path == request.path end + + private + + def set_default_sort + key = if is_a_listing_page_for?('issues') || is_a_listing_page_for?('merge_requests') + 'issuable_sort' + end + + cookies[key] = params[:sort] if key && params[:sort].present? + params[:sort] = cookies[key] if key + params[:sort] ||= 'id_desc' + end + + def is_a_listing_page_for?(page_type) + controller_name, action_name = params.values_at(:controller, :action) + + (controller_name == "projects/#{page_type}" && action_name == 'index') || + (controller_name == 'groups' && action_name == page_type) || + (controller_name == 'dashboard' && action_name == page_type) + end end diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb index 750181f0c19..e61e01c4a59 100644 --- a/app/controllers/projects/forks_controller.rb +++ b/app/controllers/projects/forks_controller.rb @@ -3,6 +3,15 @@ class Projects::ForksController < Projects::ApplicationController before_action :require_non_empty_project before_action :authorize_download_code! + def index + @sort = params[:sort] || 'id_desc' + @all_forks = project.forks.includes(:creator).order_by(@sort) + + @public_forks, @protected_forks = @all_forks.partition do |project| + can?(current_user, :read_project, project) + end + end + def new @namespaces = current_user.manageable_namespaces @namespaces.delete(@project.namespace) @@ -10,7 +19,7 @@ class Projects::ForksController < Projects::ApplicationController def create namespace = Namespace.find(params[:namespace_key]) - + @forked_project = namespace.projects.find_by(path: project.path) @forked_project = nil unless @forked_project && @forked_project.forked_from_project == project diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index 8b689b29a41..694c03206bd 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -36,8 +36,7 @@ module BlobHelper notice: edit_in_new_fork_notice, notice_now: edit_in_new_fork_notice_now } - fork_path = namespace_project_fork_path(project.namespace, project, namespace_key: current_user.namespace.id, - continue: continue_params) + fork_path = namespace_project_forks_path(project.namespace, project, namespace_key: current_user.namespace.id, continue: continue_params) link_to "Edit", fork_path, class: 'btn', method: :post end @@ -62,8 +61,7 @@ module BlobHelper notice: edit_in_new_fork_notice + " Try to #{action} this file again.", notice_now: edit_in_new_fork_notice_now } - fork_path = namespace_project_fork_path(project.namespace, project, namespace_key: current_user.namespace.id, - continue: continue_params) + fork_path = namespace_project_forks_path(project.namespace, project, namespace_key: current_user.namespace.id, continue: continue_params) link_to label, fork_path, class: "btn btn-#{btn_class}", method: :post end diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb index 5724d3aabec..84c6d0883b0 100644 --- a/app/helpers/icons_helper.rb +++ b/app/helpers/icons_helper.rb @@ -7,7 +7,7 @@ module IconsHelper # font-awesome-rails gem, but should we ever use a different icon pack in the # future we won't have to change hundreds of method calls. def icon(names, options = {}) - fa_icon(names, options) + options.include?(:base) ? fa_stacked_icon(names, options) : fa_icon(names, options) end def spinner(text = nil, visible = false) diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index f343d81a92a..8c8b355028c 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -116,7 +116,7 @@ module ProjectsHelper private def get_project_nav_tabs(project, current_user) - nav_tabs = [:home] + nav_tabs = [:home, :forks] if !project.empty_repo? && can?(current_user, :download_code, project) nav_tabs << [:files, :commits, :network, :graphs] diff --git a/app/models/group.rb b/app/models/group.rb index 5a31b46920c..76042b3e3fd 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -19,7 +19,7 @@ require 'file_size_validator' class Group < Namespace include Gitlab::ConfigHelper include Referable - + has_many :group_members, dependent: :destroy, as: :source, class_name: 'GroupMember' alias_method :members, :group_members has_many :users, through: :group_members diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml index 3940210e19b..118d3cfea07 100644 --- a/app/views/admin/groups/index.html.haml +++ b/app/views/admin/groups/index.html.haml @@ -17,7 +17,7 @@ .pull-right .dropdown.inline %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} - %span.light sort: + %span.light - if @sort.present? = sort_options_hash[@sort] - else diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index b96ad6e2208..d39c0f44031 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -50,7 +50,7 @@ .controls .dropdown.inline %button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'} - %span.light sort: + %span.light - if @sort.present? = sort_options_hash[@sort] - else diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index b050a4d01c3..b6b1168bd37 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -32,7 +32,7 @@ .pull-right .dropdown.inline %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} - %span.light sort: + %span.light - if @sort.present? = sort_options_hash[@sort] - else diff --git a/app/views/explore/groups/index.html.haml b/app/views/explore/groups/index.html.haml index fcb07b04083..8ffca96bb4e 100644 --- a/app/views/explore/groups/index.html.haml +++ b/app/views/explore/groups/index.html.haml @@ -18,7 +18,7 @@ .pull-right .dropdown.inline %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'} - %span.light sort: + %span.light - if @sort.present? = sort_options_hash[@sort] - else diff --git a/app/views/explore/projects/_dropdown.html.haml b/app/views/explore/projects/_dropdown.html.haml index b23a3c1e5c1..a988d4c8154 100644 --- a/app/views/explore/projects/_dropdown.html.haml +++ b/app/views/explore/projects/_dropdown.html.haml @@ -1,6 +1,6 @@ .dropdown.inline %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'} - %span.light sort: + %span.light - if @sort.present? = sort_options_hash[@sort] - elsif current_page?(trending_explore_projects_path) || current_page?(explore_root_path) @@ -24,4 +24,3 @@ = sort_title_recently_updated = link_to explore_projects_filter_path(sort: sort_value_oldest_updated) do = sort_title_oldest_updated - diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index 270ccfd387f..319974e12c5 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -98,6 +98,13 @@ %span Wiki + - if project_nav_tab? :forks + = nav_link(controller: :forks, action: :index) do + = link_to namespace_project_forks_path(@project.namespace, @project), title: 'Forks' do + = icon('code-fork fw') + %span + Forks + - if project_nav_tab? :snippets = nav_link(controller: :snippets) do = link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets' do diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml index 204def60794..7afea5a5049 100644 --- a/app/views/projects/branches/index.html.haml +++ b/app/views/projects/branches/index.html.haml @@ -10,7 +10,7 @@ .dropdown.inline %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'} - %span.light sort: + %span.light - if @sort.present? = @sort.humanize - else diff --git a/app/views/projects/buttons/_dropdown.html.haml b/app/views/projects/buttons/_dropdown.html.haml index 511863d774e..e7c85edff96 100644 --- a/app/views/projects/buttons/_dropdown.html.haml +++ b/app/views/projects/buttons/_dropdown.html.haml @@ -46,7 +46,7 @@ - continue_params = { to: namespace_project_new_blob_path(@project.namespace, @project, @project.default_branch || 'master'), notice: edit_in_new_fork_notice, notice_now: edit_in_new_fork_notice_now } - - fork_path = namespace_project_fork_path(@project.namespace, @project, namespace_key: current_user.namespace.id, + - fork_path = namespace_project_forks_path(@project.namespace, @project, namespace_key: current_user.namespace.id, continue: continue_params) = link_to fork_path, method: :post do = icon('file fw') diff --git a/app/views/projects/forks/index.html.haml b/app/views/projects/forks/index.html.haml new file mode 100644 index 00000000000..a362185210a --- /dev/null +++ b/app/views/projects/forks/index.html.haml @@ -0,0 +1,58 @@ +.gray-content-block.top-block.clearfix.white.forks-top-block + .pull-left + - public_count = @public_forks.size + - protected_count = @protected_forks.size + - full_count_title = "#{public_count} public and #{protected_count} private" + == #{pluralize(@all_forks.size, 'fork')}: #{full_count_title} + + .pull-right + .projects-search-form.fork-search-form + = search_field_tag :filter_projects, nil, placeholder: 'Search forks', class: 'projects-list-filter form-control', + spellcheck: false, data: { 'filter-selector' => 'span.namespace-name' } + + .dropdown.inline.prepend-left-10 + %button.dropdown-toggle.btn.sort-forks{type: 'button', 'data-toggle' => 'dropdown'} + %span.light sort: + - if @sort.present? + = sort_options_hash[@sort] + - else + = sort_title_recently_created + %b.caret + %ul.dropdown-menu.dropdown-menu-align-right + %li + - excluded_filters = [:state, :scope, :label_name, :milestone_id, :assignee_id, :author_id] + = link_to page_filter_path(sort: sort_value_recently_created, without: excluded_filters) do + = sort_title_recently_created + = link_to page_filter_path(sort: sort_value_oldest_created, without: excluded_filters) do + = sort_title_oldest_created + = link_to page_filter_path(sort: sort_value_recently_updated, without: excluded_filters) do + = sort_title_recently_updated + = link_to page_filter_path(sort: sort_value_oldest_updated, without: excluded_filters) do + = sort_title_oldest_updated + + .fork-link.inline + - if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2 + = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to your fork', class: 'pull-right btn btn-new' do + = icon('code-fork fw') + Fork + - else + = link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'pull-right btn btn-new' do + = icon('code-fork fw') + Fork + + +.projects-list-holder + - if @public_forks.blank? + %ul.content-list + %li + .nothing-here-block No forks to show + - else + = render 'shared/projects/list', projects: @public_forks, use_creator_avatar: true, + forks: true, show_last_commit_as_description: true + + - if protected_count > 0 + %ul.projects-list.private-forks-notice + %li.project-row + = icon('lock fw', base: 'circle', class: 'fa-lg private-fork-icon') + %strong= pluralize(protected_count, 'private fork') + %span you have no access to. diff --git a/app/views/projects/forks/new.html.haml b/app/views/projects/forks/new.html.haml index 8a2c027a455..edabc2d3b44 100644 --- a/app/views/projects/forks/new.html.haml +++ b/app/views/projects/forks/new.html.haml @@ -22,7 +22,7 @@ - else .fork-thumbnail - = link_to namespace_project_fork_path(@project.namespace, @project, namespace_key: namespace.id), title: "Fork here", method: "POST", class: 'has_tooltip' do + = link_to namespace_project_forks_path(@project.namespace, @project, namespace_key: namespace.id), title: "Fork here", method: "POST", class: 'has_tooltip' do = image_tag namespace_icon(namespace, 100) .caption %strong diff --git a/app/views/projects/tree/_tree_header.html.haml b/app/views/projects/tree/_tree_header.html.haml index 3343288ad2b..3eb626e6dca 100644 --- a/app/views/projects/tree/_tree_header.html.haml +++ b/app/views/projects/tree/_tree_header.html.haml @@ -40,7 +40,7 @@ - continue_params = { to: namespace_project_new_blob_path(@project.namespace, @project, @id), notice: edit_in_new_fork_notice, notice_now: edit_in_new_fork_notice_now } - - fork_path = namespace_project_fork_path(@project.namespace, @project, namespace_key: current_user.namespace.id, + - fork_path = namespace_project_forks_path(@project.namespace, @project, namespace_key: current_user.namespace.id, continue: continue_params) = link_to fork_path, method: :post do = icon('pencil fw') @@ -49,7 +49,7 @@ - continue_params = { to: request.fullpath, notice: edit_in_new_fork_notice + " Try to upload a file again.", notice_now: edit_in_new_fork_notice_now } - - fork_path = namespace_project_fork_path(@project.namespace, @project, namespace_key: current_user.namespace.id, + - fork_path = namespace_project_forks_path(@project.namespace, @project, namespace_key: current_user.namespace.id, continue: continue_params) = link_to fork_path, method: :post do = icon('file fw') @@ -58,7 +58,7 @@ - continue_params = { to: request.fullpath, notice: edit_in_new_fork_notice + " Try to create a new directory again.", notice_now: edit_in_new_fork_notice_now } - - fork_path = namespace_project_fork_path(@project.namespace, @project, namespace_key: current_user.namespace.id, + - fork_path = namespace_project_forks_path(@project.namespace, @project, namespace_key: current_user.namespace.id, continue: continue_params) = link_to fork_path, method: :post do = icon('folder fw') diff --git a/app/views/shared/_sort_dropdown.html.haml b/app/views/shared/_sort_dropdown.html.haml index af3d35de325..f09ab25276d 100644 --- a/app/views/shared/_sort_dropdown.html.haml +++ b/app/views/shared/_sort_dropdown.html.haml @@ -1,6 +1,6 @@ .dropdown.inline.prepend-left-10 %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'} - %span.light sort: + %span.light - if @sort.present? = sort_options_hash[@sort] - else diff --git a/app/views/shared/projects/_list.html.haml b/app/views/shared/projects/_list.html.haml index e5ffe1e29ae..b3f45373f6b 100644 --- a/app/views/shared/projects/_list.html.haml +++ b/app/views/shared/projects/_list.html.haml @@ -1,14 +1,18 @@ - projects_limit = 20 unless local_assigns[:projects_limit] - avatar = true unless local_assigns[:avatar] == false +- use_creator_avatar = false unless local_assigns[:use_creator_avatar] == true - stars = true unless local_assigns[:stars] == false +- forks = false unless local_assigns[:forks] == true - ci = false unless local_assigns[:ci] == true - skip_namespace = false unless local_assigns[:skip_namespace] == true +- show_last_commit_as_description = false unless local_assigns[:show_last_commit_as_description] == true %ul.projects-list - projects.each_with_index do |project, i| - css_class = (i >= projects_limit) ? 'hide' : nil = render "shared/projects/project", project: project, skip_namespace: skip_namespace, - avatar: avatar, stars: stars, css_class: css_class, ci: ci + avatar: avatar, stars: stars, css_class: css_class, ci: ci, use_creator_avatar: use_creator_avatar, + forks: forks, show_last_commit_as_description: show_last_commit_as_description - if projects.size > projects_limit %li.bottom.center diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml index 5db8056b77c..2aeeed63c95 100644 --- a/app/views/shared/projects/_project.html.haml +++ b/app/views/shared/projects/_project.html.haml @@ -1,9 +1,11 @@ - avatar = true unless local_assigns[:avatar] == false - stars = true unless local_assigns[:stars] == false +- forks = false unless local_assigns[:forks] == true - ci = false unless local_assigns[:ci] == true - skip_namespace = false unless local_assigns[:skip_namespace] == true - css_class = '' unless local_assigns[:css_class] -- css_class += " no-description" unless project.description.present? +- show_last_commit_as_description = false unless local_assigns[:show_last_commit_as_description] == true +- css_class += " no-description" if project.description.blank? && !show_last_commit_as_description - ci_commit = project.ci_commit(project.commit.sha) if ci && !project.empty_repo? && project.commit - cache_key = [project.namespace, project, controller.controller_name, controller.action_name, current_application_settings, 'v2.2'] - cache_key.push(ci_commit.status) if ci_commit @@ -13,7 +15,10 @@ = link_to project_path(project), class: dom_class(project) do - if avatar .dash-project-avatar - = project_icon(project, alt: '', class: 'avatar project-avatar s46') + - if use_creator_avatar + = image_tag avatar_icon(project.creator.email, 46), class: "avatar s46", alt:'' + - else + = project_icon(project, alt: '', class: 'avatar project-avatar s46') %span.project-full-name %span.namespace-name - if project.namespace && !skip_namespace @@ -26,10 +31,18 @@ - if ci_commit = render_ci_status(ci_commit) + - if forks + %span + = icon('code-fork') + = project.forks_count - if stars %span - %i.fa.fa-star + = icon('star') = project.star_count - - if project.description.present? + - if show_last_commit_as_description + .project-description + = link_to_gfm project.commit.title, namespace_project_commit_path(project.namespace, project, project.commit), + class: "commit-row-message" + - elsif project.description.present? .project-description = markdown(project.description, pipeline: :description) diff --git a/config/routes.rb b/config/routes.rb index 75418db8d25..fdfdb449085 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -554,7 +554,7 @@ Rails.application.routes.draw do end end - resource :fork, only: [:new, :create] + resources :forks, only: [:index, :new, :create] resource :import, only: [:new, :create, :show] resources :refs, only: [] do diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 8bc0a67067a..85ed31320b9 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -60,7 +60,7 @@ Parameters: Shows information about a single merge request. ``` -GET /projects/:id/merge_request/:merge_request_id +GET /projects/:id/merge_requests/:merge_request_id ``` Parameters: @@ -105,7 +105,7 @@ Parameters: Get a list of merge request commits. ``` -GET /projects/:id/merge_request/:merge_request_id/commits +GET /projects/:id/merge_requests/:merge_request_id/commits ``` Parameters: @@ -142,7 +142,7 @@ Parameters: Shows information about the merge request including its files and changes. ``` -GET /projects/:id/merge_request/:merge_request_id/changes +GET /projects/:id/merge_requests/:merge_request_id/changes ``` Parameters: @@ -264,7 +264,7 @@ If an error occurs, an error number and a message explaining the reason is retur Updates an existing merge request. You can change the target branch, title, or even close the MR. ``` -PUT /projects/:id/merge_request/:merge_request_id +PUT /projects/:id/merge_requests/:merge_request_id ``` Parameters: @@ -323,7 +323,7 @@ If merge request is already merged or closed - you get 405 and error message 'Me If you don't have permissions to accept this merge request - you'll get a 401 ``` -PUT /projects/:id/merge_request/:merge_request_id/merge +PUT /projects/:id/merge_requests/:merge_request_id/merge ``` Parameters: @@ -373,7 +373,7 @@ If the merge request is already merged or closed - you get 405 and error message In case the merge request is not set to be merged when the build succeeds, you'll also get a 406 error. ``` -PUT /projects/:id/merge_request/:merge_request_id/cancel_merge_when_build_succeeds +PUT /projects/:id/merge_requests/:merge_request_id/cancel_merge_when_build_succeeds ``` Parameters: @@ -409,66 +409,6 @@ Parameters: } ``` -## Post comment to MR - -Adds a comment to a merge request. - -``` -POST /projects/:id/merge_request/:merge_request_id/comments -``` - -Parameters: - -- `id` (required) - The ID of a project -- `merge_request_id` (required) - ID of merge request -- `note` (required) - Text of comment - -```json -{ - "note": "text1" -} -``` - -## Get the comments on a MR - -Gets all the comments associated with a merge request. - -``` -GET /projects/:id/merge_request/:merge_request_id/comments -``` - -Parameters: - -- `id` (required) - The ID of a project -- `merge_request_id` (required) - ID of merge request - -```json -[ - { - "note": "this is the 1st comment on the 2merge merge request", - "author": { - "id": 11, - "username": "admin", - "email": "admin@example.com", - "name": "Administrator", - "state": "active", - "created_at": "2014-03-06T08:17:35.000Z" - } - }, - { - "note": "Status changed to closed", - "author": { - "id": 11, - "username": "admin", - "email": "admin@example.com", - "name": "Administrator", - "state": "active", - "created_at": "2014-03-06T08:17:35.000Z" - } - } -] -``` - ## Comments on merge requets -Comments are done via the notes resource. +Comments are done via the [notes](notes.md) resource. diff --git a/features/dashboard/dashboard.feature b/features/dashboard/dashboard.feature index b667b587c5b..c3b3577c449 100644 --- a/features/dashboard/dashboard.feature +++ b/features/dashboard/dashboard.feature @@ -41,3 +41,33 @@ Feature: Dashboard And user with name "John Doe" left project "Shop" When I visit dashboard activity page Then I should see "John Doe left project Shop" event + + @javascript + Scenario: Sorting Issues + Given I visit dashboard issues page + And I sort the list by "Oldest updated" + And I visit dashboard activity page + And I visit dashboard issues page + Then The list should be sorted by "Oldest updated" + + @javascript + Scenario: Visiting Project's issues after sorting + Given I visit dashboard issues page + And I sort the list by "Oldest updated" + And I visit project "Shop" issues page + Then The list should be sorted by "Oldest updated" + + @javascript + Scenario: Sorting Merge Requests + Given I visit dashboard merge requests page + And I sort the list by "Oldest updated" + And I visit dashboard activity page + And I visit dashboard merge requests page + Then The list should be sorted by "Oldest updated" + + @javascript + Scenario: Visiting Project's merge requests after sorting + Given I visit dashboard merge requests page + And I sort the list by "Oldest updated" + And I visit project "Shop" merge requests page + Then The list should be sorted by "Oldest updated" diff --git a/features/project/fork.feature b/features/project/fork.feature index 37cd53ee977..12695204e47 100644 --- a/features/project/fork.feature +++ b/features/project/fork.feature @@ -25,3 +25,18 @@ Feature: Project Fork Then I should see "New merge request" And I click link "New merge request" Then I should see the new merge request page for my namespace + + Scenario: Viewing forks of a Project + Given I click link "Fork" + When I fork to my namespace + And I visit the forks page of the "Shop" project + Then I should see my fork on the list + + Scenario: Viewing private forks of a Project + Given There is an existent fork of the "Shop" project + And I click link "Fork" + When I fork to my namespace + And I visit the forks page of the "Shop" project + Then I should see my fork on the list + And I should not see the other fork listed + And I should see a private fork notice diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature index 1502b0952cd..0b3d03aa2a5 100644 --- a/features/project/issues/issues.feature +++ b/features/project/issues/issues.feature @@ -60,6 +60,28 @@ Feature: Project Issues Then I should see "Release 0.4" at the top @javascript + Scenario: Visiting Issues after being sorted the list + Given I visit project "Shop" issues page + And I sort the list by "Oldest updated" + And I visit my project's home page + And I visit project "Shop" issues page + Then The list should be sorted by "Oldest updated" + + @javascript + Scenario: Visiting Merge Requests after being sorted the list + Given I visit project "Shop" issues page + And I sort the list by "Oldest updated" + And I visit project "Shop" merge requests page + Then The list should be sorted by "Oldest updated" + + @javascript + Scenario: Visiting Merge Requests from a differente Project after sorting + Given I visit project "Shop" merge requests page + And I sort the list by "Oldest updated" + And I visit dashboard merge requests page + Then The list should be sorted by "Oldest updated" + + @javascript Scenario: I search issue Given I fill in issue search with "Re" Then I should see "Release 0.4" in issues diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature index 4f780aa680f..ca1ee6b3c2b 100644 --- a/features/project/merge_requests.feature +++ b/features/project/merge_requests.feature @@ -85,6 +85,28 @@ Feature: Project Merge Requests Then I should see "Bug NS-04" at the top @javascript + Scenario: Visiting Merge Requests after being sorted the list + Given I visit project "Shop" merge requests page + And I sort the list by "Oldest updated" + And I visit my project's home page + And I visit project "Shop" merge requests page + Then The list should be sorted by "Oldest updated" + + @javascript + Scenario: Visiting Issues after being sorted the list + Given I visit project "Shop" merge requests page + And I sort the list by "Oldest updated" + And I visit project "Shop" issues page + Then The list should be sorted by "Oldest updated" + + @javascript + Scenario: Visiting Merge Requests from a differente Project after sorting + Given I visit project "Shop" merge requests page + And I sort the list by "Oldest updated" + And I visit dashboard merge requests page + Then The list should be sorted by "Oldest updated" + + @javascript Scenario: Visiting Merge Requests after commenting on diffs Given project "Shop" have "Bug NS-05" open merge request with diffs inside And I visit merge request page "Bug NS-05" diff --git a/features/steps/dashboard/dashboard.rb b/features/steps/dashboard/dashboard.rb index 63f0ec2b6e8..5062e348844 100644 --- a/features/steps/dashboard/dashboard.rb +++ b/features/steps/dashboard/dashboard.rb @@ -2,6 +2,7 @@ class Spinach::Features::Dashboard < Spinach::FeatureSteps include SharedAuthentication include SharedPaths include SharedProject + include SharedIssuable step 'I should see "New Project" link' do expect(page).to have_link "New project" diff --git a/features/steps/project/fork.rb b/features/steps/project/fork.rb index e98bd51ca89..5810276ced3 100644 --- a/features/steps/project/fork.rb +++ b/features/steps/project/fork.rb @@ -49,4 +49,29 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps step 'I should see the new merge request page for my namespace' do current_path.should have_content(/#{current_user.namespace.name}/i) end + + step 'I visit the forks page of the "Shop" project' do + @project = Project.where(name: 'Shop').last + visit namespace_project_forks_path(@project.namespace, @project) + end + + step 'I should see my fork on the list' do + page.within('.projects-list-holder') do + project = @user.fork_of(@project) + expect(page).to have_content("#{project.namespace.human_name} / #{project.name}") + end + end + + step 'There is an existent fork of the "Shop" project' do + user = create(:user, name: 'Mike') + @forked_project = Projects::ForkService.new(@project, user).execute + end + + step 'I should not see the other fork listed' do + expect(page).not_to have_content("#{@forked_project.namespace.human_name} / #{@forked_project.name}") + end + + step 'I should see a private fork notice' do + expect(page).to have_content("1 private fork") + end end diff --git a/features/steps/project/forked_merge_requests.rb b/features/steps/project/forked_merge_requests.rb index cbdce78dc0c..7e4425ff662 100644 --- a/features/steps/project/forked_merge_requests.rb +++ b/features/steps/project/forked_merge_requests.rb @@ -43,7 +43,9 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps expect(page).to have_css("h3.page-title", text: "New Merge Request") - fill_in "merge_request_title", with: "Merge Request On Forked Project" + page.within 'form#new_merge_request' do + fill_in "merge_request_title", with: "Merge Request On Forked Project" + end end step 'I submit the merge request' do diff --git a/features/steps/shared/issuable.rb b/features/steps/shared/issuable.rb index 4c5f7488efb..25c2b476f43 100644 --- a/features/steps/shared/issuable.rb +++ b/features/steps/shared/issuable.rb @@ -106,6 +106,19 @@ module SharedIssuable edit_issuable end + step 'I sort the list by "Oldest updated"' do + find('button.dropdown-toggle.btn').click + page.within('ul.dropdown-menu.dropdown-menu-align-right li') do + click_link "Oldest updated" + end + end + + step 'The list should be sorted by "Oldest updated"' do + page.within('div.dropdown.inline.prepend-left-10') do + expect(page.find('button.dropdown-toggle.btn')).to have_content('Oldest updated') + end + end + def create_issuable_for_project(project_name:, title:, type: :issue) project = Project.find_by(name: project_name) diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 5c97fe1c88c..dd7f24f3279 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -59,55 +59,6 @@ module API present paginate(merge_requests), with: Entities::MergeRequest end - # Show MR - # - # Parameters: - # id (required) - The ID of a project - # merge_request_id (required) - The ID of MR - # - # Example: - # GET /projects/:id/merge_request/:merge_request_id - # - get ":id/merge_request/:merge_request_id" do - merge_request = user_project.merge_requests.find(params[:merge_request_id]) - - authorize! :read_merge_request, merge_request - - present merge_request, with: Entities::MergeRequest - end - - # Show MR commits - # - # Parameters: - # id (required) - The ID of a project - # merge_request_id (required) - The ID of MR - # - # Example: - # GET /projects/:id/merge_request/:merge_request_id/commits - # - get ':id/merge_request/:merge_request_id/commits' do - merge_request = user_project.merge_requests. - find(params[:merge_request_id]) - authorize! :read_merge_request, merge_request - present merge_request.commits, with: Entities::RepoCommit - end - - # Show MR changes - # - # Parameters: - # id (required) - The ID of a project - # merge_request_id (required) - The ID of MR - # - # Example: - # GET /projects/:id/merge_request/:merge_request_id/changes - # - get ':id/merge_request/:merge_request_id/changes' do - merge_request = user_project.merge_requests. - find(params[:merge_request_id]) - authorize! :read_merge_request, merge_request - present merge_request, with: Entities::MergeRequestChanges - end - # Create MR # # Parameters: @@ -148,146 +99,206 @@ module API end end - # Update MR + # Routing "merge_request/:merge_request_id/..." is DEPRECATED and WILL BE REMOVED in version 9.0 + # Use "merge_requests/:merge_request_id/..." instead. # - # Parameters: - # id (required) - The ID of a project - # merge_request_id (required) - ID of MR - # target_branch - The target branch - # assignee_id - Assignee user ID - # title - Title of MR - # state_event - Status of MR. (close|reopen|merge) - # description - Description of MR - # labels (optional) - Labels for a MR as a comma-separated list - # Example: - # PUT /projects/:id/merge_request/:merge_request_id - # - put ":id/merge_request/:merge_request_id" do - attrs = attributes_for_keys [:target_branch, :assignee_id, :title, :state_event, :description] - merge_request = user_project.merge_requests.find(params[:merge_request_id]) - authorize! :update_merge_request, merge_request - - # Ensure source_branch is not specified - if params[:source_branch].present? - render_api_error!('Source branch cannot be changed', 400) - end - - # Validate label names in advance - if (errors = validate_label_params(params)).any? - render_api_error!({ labels: errors }, 400) - end - - merge_request = ::MergeRequests::UpdateService.new(user_project, current_user, attrs).execute(merge_request) - - if merge_request.valid? - # Find or create labels and attach to issue - unless params[:labels].nil? - merge_request.remove_labels - merge_request.add_labels_by_names(params[:labels].split(",")) - end + [":id/merge_request/:merge_request_id", ":id/merge_requests/:merge_request_id"].each do |path| + # Show MR + # + # Parameters: + # id (required) - The ID of a project + # merge_request_id (required) - The ID of MR + # + # Example: + # GET /projects/:id/merge_requests/:merge_request_id + # + get path do + merge_request = user_project.merge_requests.find(params[:merge_request_id]) + + authorize! :read_merge_request, merge_request present merge_request, with: Entities::MergeRequest - else - handle_merge_request_errors! merge_request.errors end - end - - # Merge MR - # - # Parameters: - # id (required) - The ID of a project - # merge_request_id (required) - ID of MR - # merge_commit_message (optional) - Custom merge commit message - # should_remove_source_branch (optional) - When true, the source branch will be deleted if possible - # merge_when_build_succeeds (optional) - When true, this MR will be merged when the build succeeds - # Example: - # PUT /projects/:id/merge_request/:merge_request_id/merge - # - put ":id/merge_request/:merge_request_id/merge" do - merge_request = user_project.merge_requests.find(params[:merge_request_id]) - - # Merge request can not be merged - # because user dont have permissions to push into target branch - unauthorized! unless merge_request.can_be_merged_by?(current_user) - not_allowed! if !merge_request.open? || merge_request.work_in_progress? - merge_request.check_if_can_be_merged - - render_api_error!('Branch cannot be merged', 406) unless merge_request.can_be_merged? - - merge_params = { - commit_message: params[:merge_commit_message], - should_remove_source_branch: params[:should_remove_source_branch] - } - - if parse_boolean(params[:merge_when_build_succeeds]) && merge_request.ci_commit && merge_request.ci_commit.active? - ::MergeRequests::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user, merge_params). - execute(merge_request) - else - ::MergeRequests::MergeService.new(merge_request.target_project, current_user, merge_params). - execute(merge_request) + # Show MR commits + # + # Parameters: + # id (required) - The ID of a project + # merge_request_id (required) - The ID of MR + # + # Example: + # GET /projects/:id/merge_requests/:merge_request_id/commits + # + get "#{path}/commits" do + merge_request = user_project.merge_requests. + find(params[:merge_request_id]) + authorize! :read_merge_request, merge_request + present merge_request.commits, with: Entities::RepoCommit end - present merge_request, with: Entities::MergeRequest - end + # Show MR changes + # + # Parameters: + # id (required) - The ID of a project + # merge_request_id (required) - The ID of MR + # + # Example: + # GET /projects/:id/merge_requests/:merge_request_id/changes + # + get "#{path}/changes" do + merge_request = user_project.merge_requests. + find(params[:merge_request_id]) + authorize! :read_merge_request, merge_request + present merge_request, with: Entities::MergeRequestChanges + end - # Cancel Merge if Merge When build succeeds is enabled - # Parameters: - # id (required) - The ID of a project - # merge_request_id (required) - ID of MR - # - post ":id/merge_request/:merge_request_id/cancel_merge_when_build_succeeds" do - merge_request = user_project.merge_requests.find(params[:merge_request_id]) + # Update MR + # + # Parameters: + # id (required) - The ID of a project + # merge_request_id (required) - ID of MR + # target_branch - The target branch + # assignee_id - Assignee user ID + # title - Title of MR + # state_event - Status of MR. (close|reopen|merge) + # description - Description of MR + # labels (optional) - Labels for a MR as a comma-separated list + # Example: + # PUT /projects/:id/merge_requests/:merge_request_id + # + put path do + attrs = attributes_for_keys [:target_branch, :assignee_id, :title, :state_event, :description] + merge_request = user_project.merge_requests.find(params[:merge_request_id]) + authorize! :update_merge_request, merge_request + + # Ensure source_branch is not specified + if params[:source_branch].present? + render_api_error!('Source branch cannot be changed', 400) + end - unauthorized! unless merge_request.can_cancel_merge_when_build_succeeds?(current_user) + # Validate label names in advance + if (errors = validate_label_params(params)).any? + render_api_error!({ labels: errors }, 400) + end - ::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user).cancel(merge_request) - end + merge_request = ::MergeRequests::UpdateService.new(user_project, current_user, attrs).execute(merge_request) - # Get a merge request's comments - # - # Parameters: - # id (required) - The ID of a project - # merge_request_id (required) - ID of MR - # Examples: - # GET /projects/:id/merge_request/:merge_request_id/comments - # - get ":id/merge_request/:merge_request_id/comments" do - merge_request = user_project.merge_requests.find(params[:merge_request_id]) + if merge_request.valid? + # Find or create labels and attach to issue + unless params[:labels].nil? + merge_request.remove_labels + merge_request.add_labels_by_names(params[:labels].split(",")) + end - authorize! :read_merge_request, merge_request + present merge_request, with: Entities::MergeRequest + else + handle_merge_request_errors! merge_request.errors + end + end - present paginate(merge_request.notes.fresh), with: Entities::MRNote - end + # Merge MR + # + # Parameters: + # id (required) - The ID of a project + # merge_request_id (required) - ID of MR + # merge_commit_message (optional) - Custom merge commit message + # should_remove_source_branch (optional) - When true, the source branch will be deleted if possible + # merge_when_build_succeeds (optional) - When true, this MR will be merged when the build succeeds + # Example: + # PUT /projects/:id/merge_requests/:merge_request_id/merge + # + put "#{path}/merge" do + merge_request = user_project.merge_requests.find(params[:merge_request_id]) + + # Merge request can not be merged + # because user dont have permissions to push into target branch + unauthorized! unless merge_request.can_be_merged_by?(current_user) + not_allowed! if !merge_request.open? || merge_request.work_in_progress? + + merge_request.check_if_can_be_merged + + render_api_error!('Branch cannot be merged', 406) unless merge_request.can_be_merged? + + merge_params = { + commit_message: params[:merge_commit_message], + should_remove_source_branch: params[:should_remove_source_branch] + } + + if parse_boolean(params[:merge_when_build_succeeds]) && merge_request.ci_commit && merge_request.ci_commit.active? + ::MergeRequests::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user, merge_params). + execute(merge_request) + else + ::MergeRequests::MergeService.new(merge_request.target_project, current_user, merge_params). + execute(merge_request) + end - # Post comment to merge request - # - # Parameters: - # id (required) - The ID of a project - # merge_request_id (required) - ID of MR - # note (required) - Text of comment - # Examples: - # POST /projects/:id/merge_request/:merge_request_id/comments - # - post ":id/merge_request/:merge_request_id/comments" do - required_attributes! [:note] + present merge_request, with: Entities::MergeRequest + end - merge_request = user_project.merge_requests.find(params[:merge_request_id]) + # Cancel Merge if Merge When build succeeds is enabled + # Parameters: + # id (required) - The ID of a project + # merge_request_id (required) - ID of MR + # + post "#{path}/cancel_merge_when_build_succeeds" do + merge_request = user_project.merge_requests.find(params[:merge_request_id]) - authorize! :create_note, merge_request + unauthorized! unless merge_request.can_cancel_merge_when_build_succeeds?(current_user) - opts = { - note: params[:note], - noteable_type: 'MergeRequest', - noteable_id: merge_request.id - } + ::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user).cancel(merge_request) + end - note = ::Notes::CreateService.new(user_project, current_user, opts).execute + # Duplicate. DEPRECATED and WILL BE REMOVED in 9.0. + # Use GET "/projects/:id/merge_requests/:merge_request_id/notes" instead + # + # Get a merge request's comments + # + # Parameters: + # id (required) - The ID of a project + # merge_request_id (required) - ID of MR + # Examples: + # GET /projects/:id/merge_requests/:merge_request_id/comments + # + get "#{path}/comments" do + merge_request = user_project.merge_requests.find(params[:merge_request_id]) + + authorize! :read_merge_request, merge_request + + present paginate(merge_request.notes.fresh), with: Entities::MRNote + end - if note.save - present note, with: Entities::MRNote - else - render_api_error!("Failed to save note #{note.errors.messages}", 400) + # Duplicate. DEPRECATED and WILL BE REMOVED in 9.0. + # Use POST "/projects/:id/merge_requests/:merge_request_id/notes" instead + # + # Post comment to merge request + # + # Parameters: + # id (required) - The ID of a project + # merge_request_id (required) - ID of MR + # note (required) - Text of comment + # Examples: + # POST /projects/:id/merge_requests/:merge_request_id/comments + # + post "#{path}/comments" do + required_attributes! [:note] + + merge_request = user_project.merge_requests.find(params[:merge_request_id]) + + authorize! :create_note, merge_request + + opts = { + note: params[:note], + noteable_type: 'MergeRequest', + noteable_id: merge_request.id + } + + note = ::Notes::CreateService.new(user_project, current_user, opts).execute + + if note.save + present note, with: Entities::MRNote + else + render_api_error!("Failed to save note #{note.errors.messages}", 400) + end end end end diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb index ea054255820..a6b2f14521c 100644 --- a/lib/gitlab/current_settings.rb +++ b/lib/gitlab/current_settings.rb @@ -4,11 +4,14 @@ module Gitlab key = :current_application_settings RequestStore.store[key] ||= begin + settings = nil + if connect_to_db? - ApplicationSetting.current || ApplicationSetting.create_from_defaults - else - fake_application_settings + settings = ApplicationSetting.current + settings ||= ApplicationSetting.create_from_defaults unless ActiveRecord::Migrator.needs_migration? end + + settings || fake_application_settings end end @@ -18,28 +21,32 @@ module Gitlab default_branch_protection: Settings.gitlab['default_branch_protection'], signup_enabled: Settings.gitlab['signup_enabled'], signin_enabled: Settings.gitlab['signin_enabled'], + twitter_sharing_enabled: Settings.gitlab['twitter_sharing_enabled'], gravatar_enabled: Settings.gravatar['enabled'], sign_in_text: Settings.extra['sign_in_text'], restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'], max_attachment_size: Settings.gitlab['max_attachment_size'], session_expire_delay: Settings.gitlab['session_expire_delay'], - import_sources: Settings.gitlab['import_sources'], + default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'], + default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'], + restricted_signup_domains: Settings.gitlab['restricted_signup_domains'], + import_sources: ['github','bitbucket','gitlab','gitorious','google_code','fogbugz','git'], shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'], max_artifacts_size: Settings.artifacts['max_size'], + require_two_factor_authentication: false, + two_factor_grace_period: 48 ) end private def connect_to_db? - use_db = if ENV['USE_DB'] == "false" - false - else - true - end - - use_db && ActiveRecord::Base.connection.active? && - ActiveRecord::Base.connection.table_exists?('application_settings') + # When the DBMS is not available, an exception (e.g. PG::ConnectionBad) is raised + active_db_connection = ActiveRecord::Base.connection.active? rescue false + + ENV['USE_DB'] != 'false' && + active_db_connection && + ActiveRecord::Base.connection.table_exists?('application_settings') rescue ActiveRecord::NoDatabaseError false diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index e194eb93cf4..d7bfa17b0b1 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -109,9 +109,9 @@ describe API::API, api: true do end end - describe "GET /projects/:id/merge_request/:merge_request_id" do + describe "GET /projects/:id/merge_requests/:merge_request_id" do it "should return merge_request" do - get api("/projects/#{project.id}/merge_request/#{merge_request.id}", user) + get api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user) expect(response.status).to eq(200) expect(json_response['title']).to eq(merge_request.title) expect(json_response['iid']).to eq(merge_request.iid) @@ -126,14 +126,14 @@ describe API::API, api: true do end it "should return a 404 error if merge_request_id not found" do - get api("/projects/#{project.id}/merge_request/999", user) + get api("/projects/#{project.id}/merge_requests/999", user) expect(response.status).to eq(404) end end - describe 'GET /projects/:id/merge_request/:merge_request_id/commits' do + describe 'GET /projects/:id/merge_requests/:merge_request_id/commits' do context 'valid merge request' do - before { get api("/projects/#{project.id}/merge_request/#{merge_request.id}/commits", user) } + before { get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/commits", user) } let(:commit) { merge_request.commits.first } it { expect(response.status).to eq 200 } @@ -143,20 +143,20 @@ describe API::API, api: true do end it 'returns a 404 when merge_request_id not found' do - get api("/projects/#{project.id}/merge_request/999/commits", user) + get api("/projects/#{project.id}/merge_requests/999/commits", user) expect(response.status).to eq(404) end end - describe 'GET /projects/:id/merge_request/:merge_request_id/changes' do + describe 'GET /projects/:id/merge_requests/:merge_request_id/changes' do it 'should return the change information of the merge_request' do - get api("/projects/#{project.id}/merge_request/#{merge_request.id}/changes", user) + get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/changes", user) expect(response.status).to eq 200 expect(json_response['changes'].size).to eq(merge_request.diffs.size) end it 'returns a 404 when merge_request_id not found' do - get api("/projects/#{project.id}/merge_request/999/changes", user) + get api("/projects/#{project.id}/merge_requests/999/changes", user) expect(response.status).to eq(404) end end @@ -311,19 +311,19 @@ describe API::API, api: true do end end - describe "PUT /projects/:id/merge_request/:merge_request_id to close MR" do + describe "PUT /projects/:id/merge_requests/:merge_request_id to close MR" do it "should return merge_request" do - put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), state_event: "close" + put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), state_event: "close" expect(response.status).to eq(200) expect(json_response['state']).to eq('closed') end end - describe "PUT /projects/:id/merge_request/:merge_request_id/merge" do + describe "PUT /projects/:id/merge_requests/:merge_request_id/merge" do let(:ci_commit) { create(:ci_commit_without_jobs) } it "should return merge_request in case of success" do - put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user) + put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user) expect(response.status).to eq(200) end @@ -332,7 +332,7 @@ describe API::API, api: true do allow_any_instance_of(MergeRequest). to receive(:can_be_merged?).and_return(false) - put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user) + put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user) expect(response.status).to eq(406) expect(json_response['message']).to eq('Branch cannot be merged') @@ -340,14 +340,14 @@ describe API::API, api: true do it "should return 405 if merge_request is not open" do merge_request.close - put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user) + put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user) expect(response.status).to eq(405) expect(json_response['message']).to eq('405 Method Not Allowed') end it "should return 405 if merge_request is a work in progress" do merge_request.update_attribute(:title, "WIP: #{merge_request.title}") - put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user) + put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user) expect(response.status).to eq(405) expect(json_response['message']).to eq('405 Method Not Allowed') end @@ -355,7 +355,7 @@ describe API::API, api: true do it "should return 401 if user has no permissions to merge" do user2 = create(:user) project.team << [user2, :reporter] - put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user2) + put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user2) expect(response.status).to eq(401) expect(json_response['message']).to eq('401 Unauthorized') end @@ -364,7 +364,7 @@ describe API::API, api: true do allow_any_instance_of(MergeRequest).to receive(:ci_commit).and_return(ci_commit) allow(ci_commit).to receive(:active?).and_return(true) - put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user), merge_when_build_succeeds: true + put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user), merge_when_build_succeeds: true expect(response.status).to eq(200) expect(json_response['title']).to eq('Test') @@ -372,33 +372,33 @@ describe API::API, api: true do end end - describe "PUT /projects/:id/merge_request/:merge_request_id" do + describe "PUT /projects/:id/merge_requests/:merge_request_id" do it "should return merge_request" do - put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), title: "New title" + put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), title: "New title" expect(response.status).to eq(200) expect(json_response['title']).to eq('New title') end it "should return merge_request" do - put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), description: "New description" + put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), description: "New description" expect(response.status).to eq(200) expect(json_response['description']).to eq('New description') end it "should return 400 when source_branch is specified" do - put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), + put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), source_branch: "master", target_branch: "master" expect(response.status).to eq(400) end it "should return merge_request with renamed target_branch" do - put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), target_branch: "wiki" + put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), target_branch: "wiki" expect(response.status).to eq(200) expect(json_response['target_branch']).to eq('wiki') end it 'should return 400 on invalid label names' do - put api("/projects/#{project.id}/merge_request/#{merge_request.id}", + put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), title: 'new issue', labels: 'label, ?' @@ -407,11 +407,11 @@ describe API::API, api: true do end end - describe "POST /projects/:id/merge_request/:merge_request_id/comments" do + describe "POST /projects/:id/merge_requests/:merge_request_id/comments" do it "should return comment" do original_count = merge_request.notes.size - post api("/projects/#{project.id}/merge_request/#{merge_request.id}/comments", user), note: "My comment" + post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/comments", user), note: "My comment" expect(response.status).to eq(201) expect(json_response['note']).to eq('My comment') expect(json_response['author']['name']).to eq(user.name) @@ -420,20 +420,20 @@ describe API::API, api: true do end it "should return 400 if note is missing" do - post api("/projects/#{project.id}/merge_request/#{merge_request.id}/comments", user) + post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/comments", user) expect(response.status).to eq(400) end it "should return 404 if note is attached to non existent merge request" do - post api("/projects/#{project.id}/merge_request/404/comments", user), + post api("/projects/#{project.id}/merge_requests/404/comments", user), note: 'My comment' expect(response.status).to eq(404) end end - describe "GET :id/merge_request/:merge_request_id/comments" do + describe "GET :id/merge_requests/:merge_request_id/comments" do it "should return merge_request comments ordered by created_at" do - get api("/projects/#{project.id}/merge_request/#{merge_request.id}/comments", user) + get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/comments", user) expect(response.status).to eq(200) expect(json_response).to be_an Array expect(json_response.length).to eq(2) @@ -443,7 +443,7 @@ describe API::API, api: true do end it "should return a 404 error if merge_request_id not found" do - get api("/projects/#{project.id}/merge_request/999/comments", user) + get api("/projects/#{project.id}/merge_requests/999/comments", user) expect(response.status).to eq(404) end end diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 22ba25217f0..22937226fce 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -496,11 +496,11 @@ end describe Projects::ForksController, 'routing' do it 'to #new' do - expect(get('/gitlab/gitlabhq/fork/new')).to route_to('projects/forks#new', namespace_id: 'gitlab', project_id: 'gitlabhq') + expect(get('/gitlab/gitlabhq/forks/new')).to route_to('projects/forks#new', namespace_id: 'gitlab', project_id: 'gitlabhq') end it 'to #create' do - expect(post('/gitlab/gitlabhq/fork')).to route_to('projects/forks#create', namespace_id: 'gitlab', project_id: 'gitlabhq') + expect(post('/gitlab/gitlabhq/forks')).to route_to('projects/forks#create', namespace_id: 'gitlab', project_id: 'gitlabhq') end end |