From a62e9e7a14355a66367bab022ff638328d5048c8 Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Fri, 18 Aug 2017 10:09:29 +0000 Subject: [PATCH 01/49] Add example of docker login with personal access token --- doc/user/project/container_registry.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/user/project/container_registry.md b/doc/user/project/container_registry.md index 629d69d8aea..5c615daf464 100644 --- a/doc/user/project/container_registry.md +++ b/doc/user/project/container_registry.md @@ -120,6 +120,11 @@ If a project is private, credentials will need to be provided for authorization. The preferred way to do this, is by using [personal access tokens][pat]. The minimal scope needed is `read_registry`. +Example of using a personal access token: +``` +docker login registry.example.com -u -p +``` + ## Troubleshooting the GitLab Container Registry ### Basic Troubleshooting From 62c747d4ede303c8d5c9252ee473e8473c1f9dcf Mon Sep 17 00:00:00 2001 From: Johan Brandhorst Date: Mon, 21 Aug 2017 15:51:16 +0000 Subject: [PATCH 02/49] Fix incorrect reference in documentation --- doc/ci/docker/using_docker_images.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md index dc5313c5597..d6b6c18488c 100644 --- a/doc/ci/docker/using_docker_images.md +++ b/doc/ci/docker/using_docker_images.md @@ -96,7 +96,7 @@ services: - tutum/wordpress:latest ``` -If you don't [specify a service alias](#available-settings-for-services-entry), +If you don't [specify a service alias](#available-settings-for-services), when the job is run, `tutum/wordpress` will be started and you will have access to it from your build container under two hostnames to choose from: From f2a43ff5b7eec188ffc470649bf40d268cbdce2a Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Mon, 28 Aug 2017 18:56:49 -0300 Subject: [PATCH 03/49] Group boards CE backport --- .../boards/application_controller.rb | 21 +++++ app/controllers/boards/issues_controller.rb | 89 ++++++++++++++++++ app/controllers/boards/lists_controller.rb | 74 +++++++++++++++ .../projects/boards/application_controller.rb | 15 --- .../projects/boards/issues_controller.rb | 94 ------------------- .../projects/boards/lists_controller.rb | 86 ----------------- app/controllers/projects/boards_controller.rb | 25 +++-- app/helpers/boards_helper.rb | 78 +++++++++++++-- app/helpers/issuables_helper.rb | 8 ++ app/helpers/labels_helper.rb | 7 +- app/helpers/search_helper.rb | 14 +-- app/models/board.rb | 6 +- app/models/concerns/relative_positioning.rb | 14 ++- app/models/label.rb | 3 +- app/models/project.rb | 8 ++ app/services/boards/base_service.rb | 10 ++ app/services/boards/create_service.rb | 6 +- app/services/boards/issues/create_service.rb | 12 ++- app/services/boards/issues/list_service.rb | 8 +- app/services/boards/issues/move_service.rb | 20 ++-- app/services/boards/list_service.rb | 8 +- app/services/boards/lists/create_service.rb | 7 +- app/services/boards/lists/generate_service.rb | 4 +- app/services/issues/update_service.rb | 14 +-- config/routes.rb | 13 +++ config/routes/project.rb | 14 +-- 26 files changed, 379 insertions(+), 279 deletions(-) create mode 100644 app/controllers/boards/application_controller.rb create mode 100644 app/controllers/boards/issues_controller.rb create mode 100644 app/controllers/boards/lists_controller.rb delete mode 100644 app/controllers/projects/boards/application_controller.rb delete mode 100644 app/controllers/projects/boards/issues_controller.rb delete mode 100644 app/controllers/projects/boards/lists_controller.rb create mode 100644 app/services/boards/base_service.rb diff --git a/app/controllers/boards/application_controller.rb b/app/controllers/boards/application_controller.rb new file mode 100644 index 00000000000..b2675025fc0 --- /dev/null +++ b/app/controllers/boards/application_controller.rb @@ -0,0 +1,21 @@ +module Boards + class ApplicationController < ::ApplicationController + respond_to :json + + rescue_from ActiveRecord::RecordNotFound, with: :record_not_found + + private + + def board + @board ||= Board.find(params[:board_id]) + end + + def board_parent + @board_parent ||= board.parent + end + + def record_not_found(exception) + render json: { error: exception.message }, status: :not_found + end + end +end diff --git a/app/controllers/boards/issues_controller.rb b/app/controllers/boards/issues_controller.rb new file mode 100644 index 00000000000..7d776d9b591 --- /dev/null +++ b/app/controllers/boards/issues_controller.rb @@ -0,0 +1,89 @@ +module Boards + class IssuesController < Boards::ApplicationController + include BoardsResponses + + before_action :authorize_read_issue, only: [:index] + before_action :authorize_create_issue, only: [:create] + before_action :authorize_update_issue, only: [:update] + + def index + issues = Boards::Issues::ListService.new(board_parent, current_user, filter_params).execute + issues = issues.page(params[:page]).per(params[:per] || 20) + make_sure_position_is_set(issues) unless Gitlab::Geo.secondary? + + render json: { + issues: serialize_as_json(issues.preload(:project)), + size: issues.total_count + } + end + + def create + service = Boards::Issues::CreateService.new(board_parent, project, current_user, issue_params) + issue = service.execute + + if issue.valid? + render json: serialize_as_json(issue) + else + render json: issue.errors, status: :unprocessable_entity + end + end + + def update + service = Boards::Issues::MoveService.new(board_parent, current_user, move_params) + + if service.execute(issue) + head :ok + else + head :unprocessable_entity + end + end + + private + + def make_sure_position_is_set(issues) + issues.each do |issue| + issue.move_to_end && issue.save unless issue.relative_position + end + end + + def issue + @issue ||= issues_finder.execute.find(params[:id]) + end + + def filter_params + params.merge(board_id: params[:board_id], id: params[:list_id]) + .reject { |_, value| value.nil? } + end + + def issues_finder + IssuesFinder.new(current_user, project_id: board_parent.id) + end + + def project + @project ||= Project.find(issue_params[:project_id]) + end + + def move_params + params.permit(:board_id, :id, :from_list_id, :to_list_id, :move_before_id, :move_after_id) + end + + def issue_params + params.require(:issue) + .permit(:title, :milestone_id, :project_id) + .merge(board_id: params[:board_id], list_id: params[:list_id], request: request) + end + + def serialize_as_json(resource) + resource.as_json( + labels: true, + only: [:id, :iid, :project_id, :title, :confidential, :due_date, :relative_position], + include: { + project: { only: [:id, :path] }, + assignees: { only: [:id, :name, :username], methods: [:avatar_url] }, + milestone: { only: [:id, :title] } + }, + user: current_user + ) + end + end +end diff --git a/app/controllers/boards/lists_controller.rb b/app/controllers/boards/lists_controller.rb new file mode 100644 index 00000000000..a4ed37dab31 --- /dev/null +++ b/app/controllers/boards/lists_controller.rb @@ -0,0 +1,74 @@ +module Boards + class ListsController < Boards::ApplicationController + include BoardsResponses + + before_action :authorize_admin_list, only: [:create, :update, :destroy, :generate] + before_action :authorize_read_list, only: [:index] + + def index + lists = Boards::Lists::ListService.new(board.parent, current_user).execute(board) + + render json: serialize_as_json(lists) + end + + def create + list = Boards::Lists::CreateService.new(board.parent, current_user, list_params).execute(board) + + if list.valid? + render json: serialize_as_json(list) + else + render json: list.errors, status: :unprocessable_entity + end + end + + def update + list = board.lists.movable.find(params[:id]) + service = Boards::Lists::MoveService.new(board_parent, current_user, move_params) + + if service.execute(list) + head :ok + else + head :unprocessable_entity + end + end + + def destroy + list = board.lists.destroyable.find(params[:id]) + service = Boards::Lists::DestroyService.new(board_parent, current_user) + + if service.execute(list) + head :ok + else + head :unprocessable_entity + end + end + + def generate + service = Boards::Lists::GenerateService.new(board_parent, current_user) + + if service.execute(board) + render json: serialize_as_json(board.lists.movable) + else + head :unprocessable_entity + end + end + + private + + def list_params + params.require(:list).permit(:label_id) + end + + def move_params + params.require(:list).permit(:position) + end + + def serialize_as_json(resource) + resource.as_json( + only: [:id, :list_type, :position], + methods: [:title], + label: true + ) + end + end +end diff --git a/app/controllers/projects/boards/application_controller.rb b/app/controllers/projects/boards/application_controller.rb deleted file mode 100644 index dad38fff6b9..00000000000 --- a/app/controllers/projects/boards/application_controller.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Projects - module Boards - class ApplicationController < Projects::ApplicationController - respond_to :json - - rescue_from ActiveRecord::RecordNotFound, with: :record_not_found - - private - - def record_not_found(exception) - render json: { error: exception.message }, status: :not_found - end - end - end -end diff --git a/app/controllers/projects/boards/issues_controller.rb b/app/controllers/projects/boards/issues_controller.rb deleted file mode 100644 index 653e7bc7e40..00000000000 --- a/app/controllers/projects/boards/issues_controller.rb +++ /dev/null @@ -1,94 +0,0 @@ -module Projects - module Boards - class IssuesController < Boards::ApplicationController - before_action :authorize_read_issue!, only: [:index] - before_action :authorize_create_issue!, only: [:create] - before_action :authorize_update_issue!, only: [:update] - - def index - issues = ::Boards::Issues::ListService.new(project, current_user, filter_params).execute - issues = issues.page(params[:page]).per(params[:per] || 20) - make_sure_position_is_set(issues) - - render json: { - issues: serialize_as_json(issues), - size: issues.total_count - } - end - - def create - service = ::Boards::Issues::CreateService.new(project, current_user, issue_params) - issue = service.execute - - if issue.valid? - render json: serialize_as_json(issue) - else - render json: issue.errors, status: :unprocessable_entity - end - end - - def update - service = ::Boards::Issues::MoveService.new(project, current_user, move_params) - - if service.execute(issue) - head :ok - else - head :unprocessable_entity - end - end - - private - - def make_sure_position_is_set(issues) - issues.each do |issue| - issue.move_to_end && issue.save unless issue.relative_position - end - end - - def issue - @issue ||= - IssuesFinder.new(current_user, project_id: project.id) - .execute - .where(iid: params[:id]) - .first! - end - - def authorize_read_issue! - return render_403 unless can?(current_user, :read_issue, project) - end - - def authorize_create_issue! - return render_403 unless can?(current_user, :admin_issue, project) - end - - def authorize_update_issue! - return render_403 unless can?(current_user, :update_issue, issue) - end - - def filter_params - params.merge(board_id: params[:board_id], id: params[:list_id]) - .reject { |_, value| value.nil? } - end - - def move_params - params.permit(:board_id, :id, :from_list_id, :to_list_id, :move_before_iid, :move_after_iid) - end - - def issue_params - params.require(:issue).permit(:title).merge(board_id: params[:board_id], list_id: params[:list_id], request: request) - end - - def serialize_as_json(resource) - resource.as_json( - labels: true, - only: [:id, :iid, :title, :confidential, :due_date, :relative_position], - include: { - assignees: { only: [:id, :name, :username], methods: [:avatar_url] }, - milestone: { only: [:id, :title] } - }, - user: current_user - ) - end - end - end -end diff --git a/app/controllers/projects/boards/lists_controller.rb b/app/controllers/projects/boards/lists_controller.rb deleted file mode 100644 index ad53bb749a0..00000000000 --- a/app/controllers/projects/boards/lists_controller.rb +++ /dev/null @@ -1,86 +0,0 @@ -module Projects - module Boards - class ListsController < Boards::ApplicationController - before_action :authorize_admin_list!, only: [:create, :update, :destroy, :generate] - before_action :authorize_read_list!, only: [:index] - - def index - lists = ::Boards::Lists::ListService.new(project, current_user).execute(board) - - render json: serialize_as_json(lists) - end - - def create - list = ::Boards::Lists::CreateService.new(project, current_user, list_params).execute(board) - - if list.valid? - render json: serialize_as_json(list) - else - render json: list.errors, status: :unprocessable_entity - end - end - - def update - list = board.lists.movable.find(params[:id]) - service = ::Boards::Lists::MoveService.new(project, current_user, move_params) - - if service.execute(list) - head :ok - else - head :unprocessable_entity - end - end - - def destroy - list = board.lists.destroyable.find(params[:id]) - service = ::Boards::Lists::DestroyService.new(project, current_user) - - if service.execute(list) - head :ok - else - head :unprocessable_entity - end - end - - def generate - service = ::Boards::Lists::GenerateService.new(project, current_user) - - if service.execute(board) - render json: serialize_as_json(board.lists.movable) - else - head :unprocessable_entity - end - end - - private - - def authorize_admin_list! - return render_403 unless can?(current_user, :admin_list, project) - end - - def authorize_read_list! - return render_403 unless can?(current_user, :read_list, project) - end - - def board - @board ||= project.boards.find(params[:board_id]) - end - - def list_params - params.require(:list).permit(:label_id) - end - - def move_params - params.require(:list).permit(:position) - end - - def serialize_as_json(resource) - resource.as_json( - only: [:id, :list_type, :position], - methods: [:title], - label: true - ) - end - end - end -end diff --git a/app/controllers/projects/boards_controller.rb b/app/controllers/projects/boards_controller.rb index 808affa4f98..88a57749d78 100644 --- a/app/controllers/projects/boards_controller.rb +++ b/app/controllers/projects/boards_controller.rb @@ -1,32 +1,31 @@ class Projects::BoardsController < Projects::ApplicationController include IssuableCollections + include BoardsResponses before_action :authorize_read_board!, only: [:index, :show] + before_action :assign_endpoint_vars def index - @boards = ::Boards::ListService.new(project, current_user).execute + @boards = Boards::ListService.new(project, current_user).execute - respond_to do |format| - format.html - format.json do - render json: serialize_as_json(@boards) - end - end + respond_with_boards end def show @board = project.boards.find(params[:id]) - respond_to do |format| - format.html - format.json do - render json: serialize_as_json(@board) - end - end + respond_with_board end private + def assign_endpoint_vars + @boards_endpoint = project_boards_url(project) + @bulk_issues_path = bulk_update_project_issues_path(project) + @namespace_path = project.namespace.path + @labels_endpoint = project_labels_path(project) + end + def authorize_read_board! return access_denied! unless can?(current_user, :read_board, project) end diff --git a/app/helpers/boards_helper.rb b/app/helpers/boards_helper.rb index 8b33c362a9c..062c3dcf164 100644 --- a/app/helpers/boards_helper.rb +++ b/app/helpers/boards_helper.rb @@ -1,15 +1,81 @@ module BoardsHelper - def board_data - board = @board || @boards.first + def board + @board ||= @board || @boards.first + end + def board_data { - endpoint: project_boards_path(@project), + boards_endpoint: @boards_endpoint, + lists_endpoint: board_lists_url(board), board_id: board.id, - disabled: "#{!can?(current_user, :admin_list, @project)}", - issue_link_base: project_issues_path(@project), + board_milestone_title: board&.milestone&.title, + disabled: "#{!can?(current_user, :admin_list, current_board_parent)}", + issue_link_base: build_issue_link_base, root_path: root_path, - bulk_update_path: bulk_update_project_issues_path(@project), + bulk_update_path: @bulk_issues_path, default_avatar: image_path(default_avatar) } end + + def build_issue_link_base + project_issues_path(@project) + end + + def current_board_json + board = @board || @boards.first + + board.to_json( + only: [:id, :name, :milestone_id], + include: { + milestone: { only: [:title] } + } + ) + end + + def board_base_url + project_boards_path(@project) + end + + def multiple_boards_available? + current_board_parent.multiple_issue_boards_available?(current_user) + end + + def board_path(board) + @board_path ||= project_board_path(current_board_parent, board) + end + + def current_board_parent + @current_board_parent ||= @project + end + + def can_admin_issue? + can?(current_user, :admin_issue, current_board_parent) + end + + def board_list_data + { + toggle: "dropdown", + list_labels_path: labels_filter_path(true), + labels: labels_filter_path(true), + labels_endpoint: @labels_endpoint, + namespace_path: @namespace_path, + project_path: @project&.try(:path) + } + end + + def board_sidebar_user_data + dropdown_options = issue_assignees_dropdown_options + + { + toggle: 'dropdown', + field_name: 'issue[assignee_ids][]', + first_user: current_user&.username, + current_user: 'true', + project_id: @project&.try(:id), + null_user: 'true', + multi_select: 'true', + 'dropdown-header': dropdown_options[:data][:'dropdown-header'], + 'max-select': dropdown_options[:data][:'max-select'] + } + end end diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index 197c90c4081..256de454ecc 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -358,6 +358,14 @@ module IssuablesHelper end end + def labels_path + if @project + project_labels_path(@project) + elsif @group + group_labels_path(@group) + end + end + def issuable_sidebar_options(issuable, can_edit_issuable) { endpoint: "#{issuable_json_path(issuable)}?basic=true", diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index e60513b35c7..e1ba7898ee6 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -121,13 +121,14 @@ module LabelsHelper end end - def labels_filter_path - return group_labels_path(@group, :json) if @group - + def labels_filter_path(only_group_labels = false) project = @target_project || @project if project project_labels_path(project, :json) + elsif @group + options = { only_group_labels: only_group_labels } if only_group_labels + group_labels_path(@group, :json, options) else dashboard_labels_path(:json) end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index ae0e0aa3cf9..b85fd96d57a 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -127,19 +127,21 @@ module SearchHelper end def search_filter_input_options(type) - opts = { - id: "filtered-search-#{type}", - placeholder: 'Search or filter results...', - data: { - 'username-params' => @users.to_json(only: [:id, :username]) + opts = + { + id: "filtered-search-#{type}", + placeholder: 'Search or filter results...', + data: { + 'username-params' => @users.to_json(only: [:id, :username]) + } } - } if @project.present? opts[:data]['project-id'] = @project.id opts[:data]['base-endpoint'] = project_path(@project) else # Group context + opts[:data]['group-id'] = @group.id opts[:data]['base-endpoint'] = group_canonical_path(@group) end diff --git a/app/models/board.rb b/app/models/board.rb index 97d0f550925..8a6de31ea30 100644 --- a/app/models/board.rb +++ b/app/models/board.rb @@ -3,7 +3,11 @@ class Board < ActiveRecord::Base has_many :lists, -> { order(:list_type, :position) }, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent - validates :project, presence: true + validates :project, presence: true, if: :project_needed? + + def project_needed? + true + end def backlog_list lists.merge(List.backlog).take diff --git a/app/models/concerns/relative_positioning.rb b/app/models/concerns/relative_positioning.rb index 7cb9a28a284..e961c97e337 100644 --- a/app/models/concerns/relative_positioning.rb +++ b/app/models/concerns/relative_positioning.rb @@ -10,8 +10,12 @@ module RelativePositioning after_save :save_positionable_neighbours end + def project_ids + [project.id] + end + def max_relative_position - self.class.in_projects(project.id).maximum(:relative_position) + self.class.in_projects(project_ids).maximum(:relative_position) end def prev_relative_position @@ -19,7 +23,7 @@ module RelativePositioning if self.relative_position prev_pos = self.class - .in_projects(project.id) + .in_projects(project_ids) .where('relative_position < ?', self.relative_position) .maximum(:relative_position) end @@ -32,7 +36,7 @@ module RelativePositioning if self.relative_position next_pos = self.class - .in_projects(project.id) + .in_projects(project_ids) .where('relative_position > ?', self.relative_position) .minimum(:relative_position) end @@ -59,7 +63,7 @@ module RelativePositioning pos_after = before.next_relative_position if before.shift_after? - issue_to_move = self.class.in_projects(project.id).find_by!(relative_position: pos_after) + issue_to_move = self.class.in_projects(project_ids).find_by!(relative_position: pos_after) issue_to_move.move_after @positionable_neighbours = [issue_to_move] @@ -74,7 +78,7 @@ module RelativePositioning pos_before = after.prev_relative_position if after.shift_before? - issue_to_move = self.class.in_projects(project.id).find_by!(relative_position: pos_before) + issue_to_move = self.class.in_projects(project_ids).find_by!(relative_position: pos_before) issue_to_move.move_before @positionable_neighbours = [issue_to_move] diff --git a/app/models/label.rb b/app/models/label.rb index 674bb3f2720..7fb017f9b0c 100644 --- a/app/models/label.rb +++ b/app/models/label.rb @@ -34,7 +34,8 @@ class Label < ActiveRecord::Base scope :templates, -> { where(template: true) } scope :with_title, ->(title) { where(title: title) } - scope :on_project_boards, ->(project_id) { joins(lists: :board).merge(List.movable).where(boards: { project_id: project_id }) } + scope :with_lists_and_board, -> { joins(lists: :board).merge(List.movable) } + scope :on_project_boards, ->(project_id) { with_lists_and_board.where(boards: { project_id: project_id }) } def self.prioritized(project) joins(:priorities) diff --git a/app/models/project.rb b/app/models/project.rb index d5324ceac31..8ade8c3fc38 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1469,6 +1469,14 @@ class Project < ActiveRecord::Base end end + def multiple_issue_boards_available?(user) + feature_available?(:multiple_issue_boards, user) + end + + def issue_board_milestone_available?(user = nil) + feature_available?(:issue_board_milestone, user) + end + def full_path_was File.join(namespace.full_path, previous_changes['path'].first) end diff --git a/app/services/boards/base_service.rb b/app/services/boards/base_service.rb new file mode 100644 index 00000000000..72822ffffa1 --- /dev/null +++ b/app/services/boards/base_service.rb @@ -0,0 +1,10 @@ +module Boards + class BaseService < ::BaseService + # Parent can either a group or a project + attr_accessor :parent, :current_user, :params + + def initialize(parent, user, params = {}) + @parent, @current_user, @params = parent, user, params.dup + end + end +end diff --git a/app/services/boards/create_service.rb b/app/services/boards/create_service.rb index 9eedb9e65a2..bd0bb387662 100644 --- a/app/services/boards/create_service.rb +++ b/app/services/boards/create_service.rb @@ -1,5 +1,5 @@ module Boards - class CreateService < BaseService + class CreateService < Boards::BaseService def execute create_board! if can_create_board? end @@ -7,11 +7,11 @@ module Boards private def can_create_board? - project.boards.size == 0 + parent.boards.size == 0 end def create_board! - board = project.boards.create(params) + board = parent.boards.create(params) if board.persisted? board.lists.create(list_type: :backlog) diff --git a/app/services/boards/issues/create_service.rb b/app/services/boards/issues/create_service.rb index c0d7ff5b585..7c4a79f555e 100644 --- a/app/services/boards/issues/create_service.rb +++ b/app/services/boards/issues/create_service.rb @@ -1,6 +1,14 @@ module Boards module Issues - class CreateService < BaseService + class CreateService < Boards::BaseService + attr_accessor :project + + def initialize(parent, project, user, params = {}) + @project = project + + super(parent, user, params) + end + def execute create_issue(params.merge(label_ids: [list.label_id])) end @@ -8,7 +16,7 @@ module Boards private def board - @board ||= project.boards.find(params.delete(:board_id)) + @board ||= parent.boards.find(params.delete(:board_id)) end def list diff --git a/app/services/boards/issues/list_service.rb b/app/services/boards/issues/list_service.rb index eb345fead2d..a4c82817148 100644 --- a/app/services/boards/issues/list_service.rb +++ b/app/services/boards/issues/list_service.rb @@ -1,6 +1,6 @@ module Boards module Issues - class ListService < BaseService + class ListService < Boards::BaseService def execute issues = IssuesFinder.new(current_user, filter_params).execute issues = without_board_labels(issues) unless movable_list? || closed_list? @@ -11,7 +11,7 @@ module Boards private def board - @board ||= project.boards.find(params[:board_id]) + @board ||= parent.boards.find(params[:board_id]) end def list @@ -33,13 +33,13 @@ module Boards end def filter_params - set_project + set_parent set_state params end - def set_project + def set_parent params[:project_id] = project.id end diff --git a/app/services/boards/issues/move_service.rb b/app/services/boards/issues/move_service.rb index ecabb2a48e4..797d6df7c1a 100644 --- a/app/services/boards/issues/move_service.rb +++ b/app/services/boards/issues/move_service.rb @@ -1,17 +1,17 @@ module Boards module Issues - class MoveService < BaseService + class MoveService < Boards::BaseService def execute(issue) return false unless can?(current_user, :update_issue, issue) return false if issue_params.empty? - update_service.execute(issue) + update(issue) end private def board - @board ||= project.boards.find(params[:board_id]) + @board ||= parent.boards.find(params[:board_id]) end def move_between_lists? @@ -27,8 +27,8 @@ module Boards @moving_to_list ||= board.lists.find_by(id: params[:to_list_id]) end - def update_service - ::Issues::UpdateService.new(project, current_user, issue_params) + def update(issue) + ::Issues::UpdateService.new(issue.project, current_user, issue_params).execute(issue) end def issue_params @@ -42,7 +42,7 @@ module Boards ) end - attrs[:move_between_iids] = move_between_iids if move_between_iids + attrs[:move_between_ids] = move_between_ids if move_between_ids attrs end @@ -61,16 +61,16 @@ module Boards if moving_to_list.movable? moving_from_list.label_id else - Label.on_project_boards(project.id).pluck(:label_id) + Label.on_project_boards(parent.id).pluck(:label_id) end Array(label_ids).compact end - def move_between_iids - return unless params[:move_after_iid] || params[:move_before_iid] + def move_between_ids + return unless params[:move_after_id] || params[:move_before_id] - [params[:move_after_iid], params[:move_before_iid]] + [params[:move_after_id], params[:move_before_id]] end end end diff --git a/app/services/boards/list_service.rb b/app/services/boards/list_service.rb index 84f1fc3a4e2..6d0dd0a9f99 100644 --- a/app/services/boards/list_service.rb +++ b/app/services/boards/list_service.rb @@ -1,14 +1,14 @@ module Boards - class ListService < BaseService + class ListService < Boards::BaseService def execute - create_board! if project.boards.empty? - project.boards + create_board! if parent.boards.empty? + parent.boards end private def create_board! - Boards::CreateService.new(project, current_user).execute + Boards::CreateService.new(parent, current_user).execute end end end diff --git a/app/services/boards/lists/create_service.rb b/app/services/boards/lists/create_service.rb index fe0d762ccd2..dbb6c0694b9 100644 --- a/app/services/boards/lists/create_service.rb +++ b/app/services/boards/lists/create_service.rb @@ -3,17 +3,16 @@ module Boards class CreateService < BaseService def execute(board) List.transaction do - label = available_labels.find(params[:label_id]) + label = available_labels_for(board).find(params[:label_id]) position = next_position(board) - create_list(board, label, position) end end private - def available_labels - LabelsFinder.new(current_user, project_id: project.id).execute + def available_labels_for(board) + LabelsFinder.new(current_user, project_id: parent.id).execute end def next_position(board) diff --git a/app/services/boards/lists/generate_service.rb b/app/services/boards/lists/generate_service.rb index 939f9bfd068..3bf37649787 100644 --- a/app/services/boards/lists/generate_service.rb +++ b/app/services/boards/lists/generate_service.rb @@ -15,11 +15,11 @@ module Boards def create_list(board, params) label = find_or_create_label(params) - Lists::CreateService.new(project, current_user, label_id: label.id).execute(board) + Lists::CreateService.new(parent, current_user, label_id: label.id).execute(board) end def find_or_create_label(params) - ::Labels::FindOrCreateService.new(current_user, project, params).execute + ::Labels::FindOrCreateService.new(current_user, parent, params).execute end def label_params diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb index 8d918ccc635..69ccb15a0a1 100644 --- a/app/services/issues/update_service.rb +++ b/app/services/issues/update_service.rb @@ -3,7 +3,7 @@ module Issues include SpamCheckService def execute(issue) - handle_move_between_iids(issue) + handle_move_between_ids(issue) filter_spam_check_params change_issue_duplicate(issue) update(issue) @@ -55,12 +55,12 @@ module Issues end def handle_move_between_iids(issue) - return unless params[:move_between_iids] + return unless params[:move_between_ids] - after_iid, before_iid = params.delete(:move_between_iids) + after_id, before_id = params.delete(:move_between_ids) - issue_before = get_issue_if_allowed(issue.project, before_iid) if before_iid - issue_after = get_issue_if_allowed(issue.project, after_iid) if after_iid + issue_before = get_issue_if_allowed(issue.project, before_id) if before_id + issue_after = get_issue_if_allowed(issue.project, after_id) if after_id issue.move_between(issue_before, issue_after) end @@ -76,8 +76,8 @@ module Issues private - def get_issue_if_allowed(project, iid) - issue = project.issues.find_by(iid: iid) + def get_issue_if_allowed(project, id) + issue = project.issues.find(id) issue if can?(current_user, :update_issue, issue) end diff --git a/config/routes.rb b/config/routes.rb index 4fd6cb5d439..5d7166cad9a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -73,6 +73,19 @@ Rails.application.routes.draw do # Notification settings resources :notification_settings, only: [:create, :update] + # Boards resources shared between group and projects + resources :boards do + resources :lists, module: :boards, only: [:index, :create, :update, :destroy] do + collection do + post :generate + end + + resources :issues, only: [:index, :create, :update] + end + + resources :issues, module: :boards, only: [:index, :update] + end + draw :import draw :uploads draw :explore diff --git a/config/routes/project.rb b/config/routes/project.rb index 06928c7b9ce..3c7c218c356 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -341,19 +341,7 @@ constraints(ProjectUrlConstrainer.new) do get 'noteable/:target_type/:target_id/notes' => 'notes#index', as: 'noteable_notes' - resources :boards, only: [:index, :show] do - scope module: :boards do - resources :issues, only: [:index, :update] - - resources :lists, only: [:index, :create, :update, :destroy] do - collection do - post :generate - end - - resources :issues, only: [:index, :create] - end - end - end + resources :boards, only: [:index, :show, :create, :update, :destroy] resources :todos, only: [:create] From c27b1cd394c8891285577f2843f651c7d4be469e Mon Sep 17 00:00:00 2001 From: EmilienMottet Date: Fri, 25 Aug 2017 13:17:04 +0000 Subject: [PATCH 04/49] fix json response --- doc/api/namespaces.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/api/namespaces.md b/doc/api/namespaces.md index 8133251dffe..5c0bebbaeb0 100644 --- a/doc/api/namespaces.md +++ b/doc/api/namespaces.md @@ -28,12 +28,14 @@ Example response: [ { "id": 1, + "name": "user1", "path": "user1", "kind": "user", "full_path": "user1" }, { "id": 2, + "name": "group1", "path": "group1", "kind": "group", "full_path": "group1", @@ -42,6 +44,7 @@ Example response: }, { "id": 3, + "name": "bar", "path": "bar", "kind": "group", "full_path": "foo/bar", @@ -77,6 +80,7 @@ Example response: [ { "id": 4, + "name": "twitter", "path": "twitter", "kind": "group", "full_path": "twitter", From 21cf3d2c3f39de8069c404932733068c3100a279 Mon Sep 17 00:00:00 2001 From: Markus Koller Date: Tue, 29 Aug 2017 16:04:32 +0200 Subject: [PATCH 05/49] Add documentation for PlantUML in reStructuredText --- .../unreleased/feature-plantuml-restructured-text.yml | 5 +++++ doc/administration/integration/plantuml.md | 11 ++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/feature-plantuml-restructured-text.yml diff --git a/changelogs/unreleased/feature-plantuml-restructured-text.yml b/changelogs/unreleased/feature-plantuml-restructured-text.yml new file mode 100644 index 00000000000..b885029f589 --- /dev/null +++ b/changelogs/unreleased/feature-plantuml-restructured-text.yml @@ -0,0 +1,5 @@ +--- +title: Add documentation for PlantUML in reStructuredText +merge_request: 13900 +author: Markus Koller +type: other diff --git a/doc/administration/integration/plantuml.md b/doc/administration/integration/plantuml.md index b21817c1fd3..652ca9cf454 100644 --- a/doc/administration/integration/plantuml.md +++ b/doc/administration/integration/plantuml.md @@ -71,6 +71,15 @@ And in Markdown using fenced code blocks: Alice -> Bob : Go Away ``` +And in reStructuredText using a directive: + +``` +.. plantuml:: + + Bob -> Alice: hello + Alice -> Bob: Go Away +``` + The above blocks will be converted to an HTML img tag with source pointing to the PlantUML instance. If the PlantUML server is correctly configured, this should render a nice diagram instead of the block: @@ -94,4 +103,4 @@ Some parameters can be added to the AsciiDoc block definition: Markdown does not support any parameters and will always use PNG format. -[ce-8537]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8537 \ No newline at end of file +[ce-8537]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8537 From 6d2a549217f01c66fdb6724d8086707da71f2b99 Mon Sep 17 00:00:00 2001 From: Sab94 Date: Thu, 31 Aug 2017 01:04:55 +0000 Subject: [PATCH 06/49] Minor Text Fix --- doc/user/project/wiki/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user/project/wiki/index.md b/doc/user/project/wiki/index.md index e9ee1abc6c1..c0b8a87f038 100644 --- a/doc/user/project/wiki/index.md +++ b/doc/user/project/wiki/index.md @@ -4,7 +4,7 @@ A separate system for documentation called Wiki, is built right into each GitLab project. It is enabled by default on all new projects and you can find it under **Wiki** in your project. -Wikis are very convenient if you don't want to keep you documentation in your +Wikis are very convenient if you don't want to keep your documentation in your repository, but you do want to keep it in the same project where your code resides. From 8077b728bc26e9ece8055b8301033238ddbdf3f5 Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Thu, 31 Aug 2017 14:48:57 -0300 Subject: [PATCH 07/49] Continue BE backport --- app/controllers/boards/issues_controller.rb | 1 + app/controllers/boards/lists_controller.rb | 1 + app/controllers/concerns/boards_responses.rb | 42 +++++++++++++++++++ app/controllers/projects/boards_controller.rb | 2 +- app/models/label.rb | 1 + app/services/boards/lists/create_service.rb | 2 +- app/services/boards/lists/destroy_service.rb | 2 +- app/services/boards/lists/generate_service.rb | 2 +- app/services/boards/lists/list_service.rb | 2 +- app/services/boards/lists/move_service.rb | 2 +- doc/README.md | 2 +- .../boards/issues_controller_spec.rb | 0 .../boards/lists_controller_spec.rb | 0 spec/fixtures/api/schemas/issue.json | 1 + .../boards/issues/move_service_spec.rb | 2 +- spec/services/issues/update_service_spec.rb | 2 +- 16 files changed, 55 insertions(+), 9 deletions(-) create mode 100644 app/controllers/concerns/boards_responses.rb rename spec/controllers/{projects => }/boards/issues_controller_spec.rb (100%) rename spec/controllers/{projects => }/boards/lists_controller_spec.rb (100%) diff --git a/app/controllers/boards/issues_controller.rb b/app/controllers/boards/issues_controller.rb index 7d776d9b591..8ac23faa4b7 100644 --- a/app/controllers/boards/issues_controller.rb +++ b/app/controllers/boards/issues_controller.rb @@ -5,6 +5,7 @@ module Boards before_action :authorize_read_issue, only: [:index] before_action :authorize_create_issue, only: [:create] before_action :authorize_update_issue, only: [:update] + skip_before_action :authenticate_user!, only: [:index] def index issues = Boards::Issues::ListService.new(board_parent, current_user, filter_params).execute diff --git a/app/controllers/boards/lists_controller.rb b/app/controllers/boards/lists_controller.rb index a4ed37dab31..381fd4d7508 100644 --- a/app/controllers/boards/lists_controller.rb +++ b/app/controllers/boards/lists_controller.rb @@ -4,6 +4,7 @@ module Boards before_action :authorize_admin_list, only: [:create, :update, :destroy, :generate] before_action :authorize_read_list, only: [:index] + skip_before_action :authenticate_user!, only: [:index] def index lists = Boards::Lists::ListService.new(board.parent, current_user).execute(board) diff --git a/app/controllers/concerns/boards_responses.rb b/app/controllers/concerns/boards_responses.rb new file mode 100644 index 00000000000..2c9c095a5d7 --- /dev/null +++ b/app/controllers/concerns/boards_responses.rb @@ -0,0 +1,42 @@ +module BoardsResponses + def authorize_read_list + authorize_action_for!(board.parent, :read_list) + end + + def authorize_read_issue + authorize_action_for!(board.parent, :read_issue) + end + + def authorize_update_issue + authorize_action_for!(issue, :admin_issue) + end + + def authorize_create_issue + authorize_action_for!(project, :admin_issue) + end + + def authorize_admin_list + authorize_action_for!(board.parent, :admin_list) + end + + def authorize_action_for!(resource, ability) + return render_403 unless can?(current_user, ability, resource) + end + + def respond_with_boards + respond_with(@boards) + end + + def respond_with_board + respond_with(@board) + end + + def respond_with(resource) + respond_to do |format| + format.html + format.json do + render json: serialize_as_json(resource) + end + end + end +end diff --git a/app/controllers/projects/boards_controller.rb b/app/controllers/projects/boards_controller.rb index 88a57749d78..04f2f77faf2 100644 --- a/app/controllers/projects/boards_controller.rb +++ b/app/controllers/projects/boards_controller.rb @@ -1,6 +1,6 @@ class Projects::BoardsController < Projects::ApplicationController - include IssuableCollections include BoardsResponses + include IssuableCollections before_action :authorize_read_board!, only: [:index, :show] before_action :assign_endpoint_vars diff --git a/app/models/label.rb b/app/models/label.rb index 7fb017f9b0c..0298e7b417c 100644 --- a/app/models/label.rb +++ b/app/models/label.rb @@ -173,6 +173,7 @@ class Label < ActiveRecord::Base def as_json(options = {}) super(options).tap do |json| + json[:type] = self.type json[:priority] = priority(options[:project]) if options.key?(:project) end end diff --git a/app/services/boards/lists/create_service.rb b/app/services/boards/lists/create_service.rb index dbb6c0694b9..183556a1d6b 100644 --- a/app/services/boards/lists/create_service.rb +++ b/app/services/boards/lists/create_service.rb @@ -1,6 +1,6 @@ module Boards module Lists - class CreateService < BaseService + class CreateService < Boards::BaseService def execute(board) List.transaction do label = available_labels_for(board).find(params[:label_id]) diff --git a/app/services/boards/lists/destroy_service.rb b/app/services/boards/lists/destroy_service.rb index f986e05944c..d75c5fd3dc6 100644 --- a/app/services/boards/lists/destroy_service.rb +++ b/app/services/boards/lists/destroy_service.rb @@ -1,6 +1,6 @@ module Boards module Lists - class DestroyService < BaseService + class DestroyService < Boards::BaseService def execute(list) return false unless list.destroyable? diff --git a/app/services/boards/lists/generate_service.rb b/app/services/boards/lists/generate_service.rb index 3bf37649787..05d4ab5dbcc 100644 --- a/app/services/boards/lists/generate_service.rb +++ b/app/services/boards/lists/generate_service.rb @@ -1,6 +1,6 @@ module Boards module Lists - class GenerateService < BaseService + class GenerateService < Boards::BaseService def execute(board) return false unless board.lists.movable.empty? diff --git a/app/services/boards/lists/list_service.rb b/app/services/boards/lists/list_service.rb index df2a01a69e5..e57c95294af 100644 --- a/app/services/boards/lists/list_service.rb +++ b/app/services/boards/lists/list_service.rb @@ -1,6 +1,6 @@ module Boards module Lists - class ListService < BaseService + class ListService < Boards::BaseService def execute(board) board.lists.create(list_type: :backlog) unless board.lists.backlog.exists? diff --git a/app/services/boards/lists/move_service.rb b/app/services/boards/lists/move_service.rb index f2a68865f7b..7d0730e8332 100644 --- a/app/services/boards/lists/move_service.rb +++ b/app/services/boards/lists/move_service.rb @@ -1,6 +1,6 @@ module Boards module Lists - class MoveService < BaseService + class MoveService < Boards::BaseService def execute(list) @board = list.board @old_position = list.position diff --git a/doc/README.md b/doc/README.md index 76d4c3e51fe..0dc5c4dc9ff 100644 --- a/doc/README.md +++ b/doc/README.md @@ -82,7 +82,7 @@ Manage your [repositories](user/project/repository/index.md) from the UI (user i - [Discussions](user/discussions/index.md) Threads, comments, and resolvable discussions in issues, commits, and merge requests. - [Issues](user/project/issues/index.md) -- [Issue Board](user/project/issue_board.md) +- [Project issue Board](user/project/issue_board.md) - [Issues and merge requests templates](user/project/description_templates.md): Create templates for submitting new issues and merge requests. - [Labels](user/project/labels.md): Categorize your issues or merge requests based on descriptive titles. - [Merge Requests](user/project/merge_requests/index.md) diff --git a/spec/controllers/projects/boards/issues_controller_spec.rb b/spec/controllers/boards/issues_controller_spec.rb similarity index 100% rename from spec/controllers/projects/boards/issues_controller_spec.rb rename to spec/controllers/boards/issues_controller_spec.rb diff --git a/spec/controllers/projects/boards/lists_controller_spec.rb b/spec/controllers/boards/lists_controller_spec.rb similarity index 100% rename from spec/controllers/projects/boards/lists_controller_spec.rb rename to spec/controllers/boards/lists_controller_spec.rb diff --git a/spec/fixtures/api/schemas/issue.json b/spec/fixtures/api/schemas/issue.json index ff86437fdd5..b9d2d5befbb 100644 --- a/spec/fixtures/api/schemas/issue.json +++ b/spec/fixtures/api/schemas/issue.json @@ -34,6 +34,7 @@ "type": "string", "pattern": "^#[0-9A-Fa-f]{3}{1,2}+$" }, + "type": { "type": "string" }, "title": { "type": "string" }, "priority": { "type": ["integer", "null"] } }, diff --git a/spec/services/boards/issues/move_service_spec.rb b/spec/services/boards/issues/move_service_spec.rb index 63dfe80d672..464ff9f94b3 100644 --- a/spec/services/boards/issues/move_service_spec.rb +++ b/spec/services/boards/issues/move_service_spec.rb @@ -98,7 +98,7 @@ describe Boards::Issues::MoveService do issue.move_to_end && issue.save! end - params.merge!(move_after_iid: issue1.iid, move_before_iid: issue2.iid) + params.merge!(move_after_id: issue1.id, move_before_id: issue2.id) described_class.new(project, user, params).execute(issue) diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index 34fb16edc84..ccb770e01d0 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -80,7 +80,7 @@ describe Issues::UpdateService, :mailer do issue.save end - opts[:move_between_iids] = [issue1.iid, issue2.iid] + opts[:move_between_ids] = [issue1.id, issue2.id] update_issue(opts) From 02fed9a905b65fb9b2a0d61500b51d44cd24ba28 Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Thu, 31 Aug 2017 15:18:35 -0300 Subject: [PATCH 08/49] Backport specs --- .../boards/issues_controller_spec.rb | 32 +++++++++++++------ .../boards/lists_controller_spec.rb | 2 +- spec/factories/milestones.rb | 4 +++ spec/fixtures/api/schemas/issue.json | 5 +++ .../boards/issues/create_service_spec.rb | 2 +- 5 files changed, 34 insertions(+), 11 deletions(-) diff --git a/spec/controllers/boards/issues_controller_spec.rb b/spec/controllers/boards/issues_controller_spec.rb index 3f6c1092163..dfa06c78d46 100644 --- a/spec/controllers/boards/issues_controller_spec.rb +++ b/spec/controllers/boards/issues_controller_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Projects::Boards::IssuesController do +describe Boards::IssuesController do let(:project) { create(:project) } let(:board) { create(:board, project: project) } let(:user) { create(:user) } @@ -133,6 +133,22 @@ describe Projects::Boards::IssuesController do expect(response).to have_http_status(404) end end + + context 'with invalid board id' do + it 'returns a not found 404 response' do + create_issue user: user, board: 999, list: list1, title: 'New issue' + + expect(response).to have_http_status(404) + end + end + + context 'with invalid list id' do + it 'returns a not found 404 response' do + create_issue user: user, board: board, list: 999, title: 'New issue' + + expect(response).to have_http_status(404) + end + end end context 'with unauthorized user' do @@ -146,17 +162,15 @@ describe Projects::Boards::IssuesController do def create_issue(user:, board:, list:, title:) sign_in(user) - post :create, namespace_id: project.namespace.to_param, - project_id: project, - board_id: board.to_param, + post :create, board_id: board.to_param, list_id: list.to_param, - issue: { title: title }, + issue: { title: title, project_id: project.id }, format: :json end end describe 'PATCH update' do - let(:issue) { create(:labeled_issue, project: project, labels: [planning]) } + let!(:issue) { create(:labeled_issue, project: project, labels: [planning]) } context 'with valid params' do it 'returns a successful 200 response' do @@ -186,7 +200,7 @@ describe Projects::Boards::IssuesController do end it 'returns a not found 404 response for invalid issue id' do - move user: user, board: board, issue: 999, from_list_id: list1.id, to_list_id: list2.id + move user: user, board: board, issue: double(id: 999), from_list_id: list1.id, to_list_id: list2.id expect(response).to have_http_status(404) end @@ -210,9 +224,9 @@ describe Projects::Boards::IssuesController do sign_in(user) patch :update, namespace_id: project.namespace.to_param, - project_id: project, + project_id: project.id, board_id: board.to_param, - id: issue.to_param, + id: issue.id, from_list_id: from_list_id, to_list_id: to_list_id, format: :json diff --git a/spec/controllers/boards/lists_controller_spec.rb b/spec/controllers/boards/lists_controller_spec.rb index 65beec16307..b11fce0fa58 100644 --- a/spec/controllers/boards/lists_controller_spec.rb +++ b/spec/controllers/boards/lists_controller_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Projects::Boards::ListsController do +describe Boards::ListsController do let(:project) { create(:project) } let(:board) { create(:board, project: project) } let(:user) { create(:user) } diff --git a/spec/factories/milestones.rb b/spec/factories/milestones.rb index 2f75bf12cd7..b5298b2f969 100644 --- a/spec/factories/milestones.rb +++ b/spec/factories/milestones.rb @@ -7,6 +7,7 @@ FactoryGirl.define do group nil project_id nil group_id nil + parent nil end trait :active do @@ -26,6 +27,9 @@ FactoryGirl.define do milestone.project = evaluator.project elsif evaluator.project_id milestone.project_id = evaluator.project_id + elsif evaluator.parent + id = evaluator.parent.id + evaluator.parent.is_a?(Group) ? board.group_id = id : evaluator.project_id = id else milestone.project = create(:project) end diff --git a/spec/fixtures/api/schemas/issue.json b/spec/fixtures/api/schemas/issue.json index b9d2d5befbb..e1f62508933 100644 --- a/spec/fixtures/api/schemas/issue.json +++ b/spec/fixtures/api/schemas/issue.json @@ -8,10 +8,15 @@ "properties" : { "id": { "type": "integer" }, "iid": { "type": "integer" }, + "project_id": { "type": ["integer", "null"] }, "title": { "type": "string" }, "confidential": { "type": "boolean" }, "due_date": { "type": ["date", "null"] }, "relative_position": { "type": "integer" }, + "project": { + "id": { "type": "integer" }, + "path": { "type": "string" } + }, "labels": { "type": "array", "items": { diff --git a/spec/services/boards/issues/create_service_spec.rb b/spec/services/boards/issues/create_service_spec.rb index f2ddaa903da..1a56164dba4 100644 --- a/spec/services/boards/issues/create_service_spec.rb +++ b/spec/services/boards/issues/create_service_spec.rb @@ -8,7 +8,7 @@ describe Boards::Issues::CreateService do let(:label) { create(:label, project: project, name: 'in-progress') } let!(:list) { create(:list, board: board, label: label, position: 0) } - subject(:service) { described_class.new(project, user, board_id: board.id, list_id: list.id, title: 'New issue') } + subject(:service) { described_class.new(board.parent, project, user, board_id: board.id, list_id: list.id, title: 'New issue') } before do project.team << [user, :developer] From aa997e4297065cdb4a78b4b629c8820d4d6b0a8e Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Thu, 31 Aug 2017 16:34:57 -0300 Subject: [PATCH 09/49] Small fixes --- app/controllers/boards/issues_controller.rb | 2 +- app/helpers/boards_helper.rb | 1 - app/models/board.rb | 8 ++++++++ app/services/boards/issues/list_service.rb | 2 +- app/services/issues/update_service.rb | 2 +- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/controllers/boards/issues_controller.rb b/app/controllers/boards/issues_controller.rb index 8ac23faa4b7..016059b3a51 100644 --- a/app/controllers/boards/issues_controller.rb +++ b/app/controllers/boards/issues_controller.rb @@ -10,7 +10,7 @@ module Boards def index issues = Boards::Issues::ListService.new(board_parent, current_user, filter_params).execute issues = issues.page(params[:page]).per(params[:per] || 20) - make_sure_position_is_set(issues) unless Gitlab::Geo.secondary? + make_sure_position_is_set(issues) render json: { issues: serialize_as_json(issues.preload(:project)), diff --git a/app/helpers/boards_helper.rb b/app/helpers/boards_helper.rb index 062c3dcf164..3133b716345 100644 --- a/app/helpers/boards_helper.rb +++ b/app/helpers/boards_helper.rb @@ -8,7 +8,6 @@ module BoardsHelper boards_endpoint: @boards_endpoint, lists_endpoint: board_lists_url(board), board_id: board.id, - board_milestone_title: board&.milestone&.title, disabled: "#{!can?(current_user, :admin_list, current_board_parent)}", issue_link_base: build_issue_link_base, root_path: root_path, diff --git a/app/models/board.rb b/app/models/board.rb index 8a6de31ea30..5bb7d3d3722 100644 --- a/app/models/board.rb +++ b/app/models/board.rb @@ -9,6 +9,14 @@ class Board < ActiveRecord::Base true end + def parent + project + end + + def group_board? + false + end + def backlog_list lists.merge(List.backlog).take end diff --git a/app/services/boards/issues/list_service.rb b/app/services/boards/issues/list_service.rb index a4c82817148..d85d93e251b 100644 --- a/app/services/boards/issues/list_service.rb +++ b/app/services/boards/issues/list_service.rb @@ -40,7 +40,7 @@ module Boards end def set_parent - params[:project_id] = project.id + params[:project_id] = parent.id end def set_state diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb index 69ccb15a0a1..a1f31abd164 100644 --- a/app/services/issues/update_service.rb +++ b/app/services/issues/update_service.rb @@ -54,7 +54,7 @@ module Issues end end - def handle_move_between_iids(issue) + def handle_move_between_ids(issue) return unless params[:move_between_ids] after_id, before_id = params.delete(:move_between_ids) From 53c871d390a65f6e22fb83f142ea1b5aaf4a5bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 3 Sep 2017 11:22:44 +0000 Subject: [PATCH 10/49] CONTRIBUTING.md: fix CD label (it's CI/CD now) --- CONTRIBUTING.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6cc34f1de08..50c7529cdee 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ By submitting code as an individual you agree to the By submitting code as an entity you agree to the [corporate contributor license agreement](doc/legal/corporate_contributor_license_agreement.md). -_This notice should stay as the first item in the CONTRIBUTING.MD file._ +_This notice should stay as the first item in the CONTRIBUTING.md file._ --- @@ -21,7 +21,7 @@ _This notice should stay as the first item in the CONTRIBUTING.MD file._ - [Workflow labels](#workflow-labels) - [Type labels (~"feature proposal", ~bug, ~customer, etc.)](#type-labels-feature-proposal-bug-customer-etc) - [Subject labels (~wiki, ~"container registry", ~ldap, ~api, etc.)](#subject-labels-wiki-container-registry-ldap-api-etc) - - [Team labels (~CI, ~Discussion, ~Edge, ~Platform, etc.)](#team-labels-ci-discussion-edge-platform-etc) + - [Team labels (~"CI/CD", ~Discussion, ~Edge, ~Platform, etc.)](#team-labels-ci-discussion-edge-platform-etc) - [Priority labels (~Deliverable and ~Stretch)](#priority-labels-deliverable-and-stretch) - [Label for community contributors (~"Accepting Merge Requests")](#label-for-community-contributors-accepting-merge-requests) - [Implement design & UI elements](#implement-design--ui-elements) @@ -115,7 +115,7 @@ Most issues will have labels for at least one of the following: - Type: ~"feature proposal", ~bug, ~customer, etc. - Subject: ~wiki, ~"container registry", ~ldap, ~api, ~frontend, etc. -- Team: ~CI, ~Discussion, ~Edge, ~Platform, etc. +- Team: ~"CI/CD", ~Discussion, ~Edge, ~Platform, etc. - Priority: ~Deliverable, ~Stretch All labels, their meaning and priority are defined on the @@ -157,13 +157,13 @@ Examples of subject labels are ~wiki, ~"container registry", ~ldap, ~api, Subject labels are always all-lowercase. -### Team labels (~CI, ~Discussion, ~Edge, ~Platform, etc.) +### Team labels (~"CI/CD", ~Discussion, ~Edge, ~Platform, etc.) Team labels specify what team is responsible for this issue. Assigning a team label makes sure issues get the attention of the appropriate people. -The current team labels are ~Build, ~CI, ~Discussion, ~Documentation, ~Edge, +The current team labels are ~Build, ~"CI/CD", ~Discussion, ~Documentation, ~Edge, ~Geo, ~Gitaly, ~Platform, ~Prometheus, ~Release, and ~"UX". The descriptions on the [labels page][labels-page] explain what falls under the From 261ab85c2c3dfa17ed1d671f34c16226ee1af6da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 3 Sep 2017 14:32:02 +0300 Subject: [PATCH 11/49] fix one more label not expanded issue just remove the ~ in display text making it into real label link would confuse user as the label links to different filter --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 50c7529cdee..6fb2c6bd1dc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -217,11 +217,11 @@ After adding the ~"Accepting Merge Requests" label, we try to estimate the [weight](#issue-weight) of the issue. We use issue weight to let contributors know how difficult the issue is. Additionally: -- We advertise [~"Accepting Merge Requests" issues with weight < 5][up-for-grabs] +- We advertise ["Accepting Merge Requests" issues with weight < 5][up-for-grabs] as suitable for people that have never contributed to GitLab before on the [Up For Grabs campaign](http://up-for-grabs.net) - We encourage people that have never contributed to any open source project to - look for [~"Accepting Merge Requests" issues with a weight of 1][firt-timers] + look for ["Accepting Merge Requests" issues with a weight of 1][firt-timers] [up-for-grabs]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=Accepting+Merge+Requests&scope=all&sort=weight_asc&state=opened [firt-timers]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name%5B%5D=Accepting+Merge+Requests&scope=all&sort=upvotes_desc&state=opened&weight=1 From f5bb1789ee170cbdfb7580f6ec5de17ce06b6cbc Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Mon, 4 Sep 2017 16:55:29 -0300 Subject: [PATCH 12/49] Fix specs BACKPORT --- app/controllers/projects/boards_controller.rb | 2 +- lib/gitlab/path_regex.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/controllers/projects/boards_controller.rb b/app/controllers/projects/boards_controller.rb index 04f2f77faf2..d1b99ecce4a 100644 --- a/app/controllers/projects/boards_controller.rb +++ b/app/controllers/projects/boards_controller.rb @@ -22,7 +22,7 @@ class Projects::BoardsController < Projects::ApplicationController def assign_endpoint_vars @boards_endpoint = project_boards_url(project) @bulk_issues_path = bulk_update_project_issues_path(project) - @namespace_path = project.namespace.path + @namespace_path = project.namespace.full_path @labels_endpoint = project_labels_path(project) end diff --git a/lib/gitlab/path_regex.rb b/lib/gitlab/path_regex.rb index 894bd5efae5..7c02c9c5c48 100644 --- a/lib/gitlab/path_regex.rb +++ b/lib/gitlab/path_regex.rb @@ -26,6 +26,7 @@ module Gitlab apple-touch-icon.png assets autocomplete + boards ci dashboard deploy.html From 74740604211dab6632771f1bfd7dd67902fea7ef Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Mon, 4 Sep 2017 18:36:31 -0300 Subject: [PATCH 13/49] Fix route conflict --- app/helpers/boards_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/helpers/boards_helper.rb b/app/helpers/boards_helper.rb index 3133b716345..4bd61aa8f86 100644 --- a/app/helpers/boards_helper.rb +++ b/app/helpers/boards_helper.rb @@ -39,8 +39,8 @@ module BoardsHelper current_board_parent.multiple_issue_boards_available?(current_user) end - def board_path(board) - @board_path ||= project_board_path(current_board_parent, board) + def current_board_path(board) + @current_board_path ||= project_board_path(current_board_parent, board) end def current_board_parent From c28d52a3a5e745d20981151b89bfcad07c68fa9c Mon Sep 17 00:00:00 2001 From: Simon Knox Date: Wed, 6 Sep 2017 15:02:30 +1000 Subject: [PATCH 14/49] FE backport of group boards to reduce CE conflicts --- app/assets/javascripts/api.js | 14 +++-- .../javascripts/boards/boards_bundle.js | 51 ++++++++++++------- .../boards/components/board_list.js | 10 ++-- .../boards/components/board_new_issue.js | 5 +- .../boards/components/issue_card_inner.js | 7 ++- .../boards/components/modal/footer.js | 2 +- .../boards/components/new_list_dropdown.js | 2 +- .../boards/components/sidebar/remove_issue.js | 23 +++++++-- app/assets/javascripts/boards/models/issue.js | 4 +- app/assets/javascripts/boards/models/label.js | 1 + app/assets/javascripts/boards/models/list.js | 27 +++++----- spec/javascripts/api_spec.js | 23 ++++++++- 12 files changed, 116 insertions(+), 53 deletions(-) diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js index 8acddd6194c..501cc43d552 100644 --- a/app/assets/javascripts/api.js +++ b/app/assets/javascripts/api.js @@ -6,7 +6,8 @@ const Api = { namespacesPath: '/api/:version/namespaces.json', groupProjectsPath: '/api/:version/groups/:id/projects.json', projectsPath: '/api/:version/projects.json', - labelsPath: '/:namespace_path/:project_path/labels', + projectLabelsPath: '/:namespace_path/:project_path/labels', + groupLabelsPath: '/groups/:namespace_path/labels', licensePath: '/api/:version/templates/licenses/:key', gitignorePath: '/api/:version/templates/gitignores/:key', gitlabCiYmlPath: '/api/:version/templates/gitlab_ci_ymls/:key', @@ -74,9 +75,14 @@ const Api = { }, newLabel(namespacePath, projectPath, data, callback) { - const url = Api.buildUrl(Api.labelsPath) - .replace(':namespace_path', namespacePath) - .replace(':project_path', projectPath); + let url; + if (projectPath) { + url = Api.buildUrl(Api.projectLabelsPath) + .replace(':namespace_path', namespacePath) + .replace(':project_path', projectPath); + } else { + url = Api.buildUrl(Api.groupLabelsPath).replace(':namespace_path', namespacePath); + } return $.ajax({ url, type: 'POST', diff --git a/app/assets/javascripts/boards/boards_bundle.js b/app/assets/javascripts/boards/boards_bundle.js index 89c14180149..ea00efe4b46 100644 --- a/app/assets/javascripts/boards/boards_bundle.js +++ b/app/assets/javascripts/boards/boards_bundle.js @@ -53,7 +53,8 @@ $(() => { data: { state: Store.state, loading: true, - endpoint: $boardApp.dataset.endpoint, + boardsEndpoint: $boardApp.dataset.boardsEndpoint, + listsEndpoint: $boardApp.dataset.listsEndpoint, boardId: $boardApp.dataset.boardId, disabled: $boardApp.dataset.disabled === 'true', issueLinkBase: $boardApp.dataset.issueLinkBase, @@ -68,7 +69,13 @@ $(() => { }, }, created () { - gl.boardService = new BoardService(this.endpoint, this.bulkUpdatePath, this.boardId); + gl.boardService = new BoardService({ + boardsEndpoint: this.boardsEndpoint, + listsEndpoint: this.listsEndpoint, + bulkUpdatePath: this.bulkUpdatePath, + boardId: this.boardId, + }); + Store.rootPath = this.boardsEndpoint; this.filterManager = new FilteredSearchBoards(Store.filter, true); this.filterManager.setup(); @@ -112,19 +119,21 @@ $(() => { gl.IssueBoardsSearch = new Vue({ el: document.getElementById('js-add-list'), data: { - filters: Store.state.filters + filters: Store.state.filters, }, mounted () { gl.issueBoards.newListDropdownInit(); - } + }, }); gl.IssueBoardsModalAddBtn = new Vue({ mixins: [gl.issueBoards.ModalMixins], el: document.getElementById('js-add-issues-btn'), - data: { - modal: ModalStore.store, - store: Store.state, + data() { + return { + modal: ModalStore.store, + store: Store.state, + }; }, watch: { disabled() { @@ -133,6 +142,9 @@ $(() => { }, computed: { disabled() { + if (!this.store) { + return true; + } return !this.store.lists.filter(list => !list.preset).length; }, tooltipTitle() { @@ -145,7 +157,7 @@ $(() => { }, methods: { updateTooltip() { - const $tooltip = $(this.$el); + const $tooltip = $(this.$refs.addIssuesButton); this.$nextTick(() => { if (this.disabled) { @@ -165,16 +177,19 @@ $(() => { this.updateTooltip(); }, template: ` - +
+ +
`, }); }); diff --git a/app/assets/javascripts/boards/components/board_list.js b/app/assets/javascripts/boards/components/board_list.js index bebca17fb1e..6159680f1e6 100644 --- a/app/assets/javascripts/boards/components/board_list.js +++ b/app/assets/javascripts/boards/components/board_list.js @@ -77,7 +77,7 @@ export default { this.showIssueForm = !this.showIssueForm; }, onScroll() { - if ((this.scrollTop() > this.scrollHeight() - this.scrollOffset) && !this.list.loadingMore) { + if (!this.loadingMore && (this.scrollTop() > this.scrollHeight() - this.scrollOffset)) { this.loadNextPage(); } }, @@ -165,11 +165,9 @@ export default { v-if="loading"> - - - +