diff options
Diffstat (limited to 'app/services')
-rw-r--r-- | app/services/ci/pipeline_schedule_service.rb | 13 | ||||
-rw-r--r-- | app/services/clusters/applications/base_service.rb | 2 | ||||
-rw-r--r-- | app/services/issues/close_service.rb | 2 | ||||
-rw-r--r-- | app/services/merge_requests/base_service.rb | 26 | ||||
-rw-r--r-- | app/services/merge_requests/close_service.rb | 5 | ||||
-rw-r--r-- | app/services/merge_requests/create_pipeline_service.rb | 37 | ||||
-rw-r--r-- | app/services/merge_requests/merge_to_ref_service.rb | 20 | ||||
-rw-r--r-- | app/services/merge_requests/mergeability_check_service.rb | 82 | ||||
-rw-r--r-- | app/services/projects/update_service.rb | 1 | ||||
-rw-r--r-- | app/services/search_service.rb | 4 | ||||
-rw-r--r-- | app/services/service_response.rb | 15 | ||||
-rw-r--r-- | app/services/todos/destroy/base_service.rb | 2 | ||||
-rw-r--r-- | app/services/todos/destroy/confidential_issue_service.rb | 35 |
13 files changed, 184 insertions, 60 deletions
diff --git a/app/services/ci/pipeline_schedule_service.rb b/app/services/ci/pipeline_schedule_service.rb new file mode 100644 index 00000000000..387d0351490 --- /dev/null +++ b/app/services/ci/pipeline_schedule_service.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Ci + class PipelineScheduleService < BaseService + def execute(schedule) + # Ensure `next_run_at` is set properly before creating a pipeline. + # Otherwise, multiple pipelines could be created in a short interval. + schedule.schedule_next_run! + + RunPipelineScheduleWorker.perform_async(schedule.id, schedule.owner.id) + end + end +end diff --git a/app/services/clusters/applications/base_service.rb b/app/services/clusters/applications/base_service.rb index 14a45437287..a9feb60be6e 100644 --- a/app/services/clusters/applications/base_service.rb +++ b/app/services/clusters/applications/base_service.rb @@ -81,7 +81,7 @@ module Clusters oauth_application_params = { name: params[:application], redirect_uri: application.callback_url, - scopes: 'api read_user openid', + scopes: application.oauth_scopes, owner: current_user } diff --git a/app/services/issues/close_service.rb b/app/services/issues/close_service.rb index 2a19e57a94f..805721212ba 100644 --- a/app/services/issues/close_service.rb +++ b/app/services/issues/close_service.rb @@ -29,7 +29,7 @@ module Issues event_service.close_issue(issue, current_user) create_note(issue, closed_via) if system_note - closed_via = "commit #{closed_via.id}" if closed_via.is_a?(Commit) + closed_via = _("commit %{commit_id}") % { commit_id: closed_via.id } if closed_via.is_a?(Commit) notification_service.async.close_issue(issue, current_user, closed_via: closed_via) if notifications todo_service.close_issue(issue, current_user) diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb index bb9062e9b40..2cfed62ce49 100644 --- a/app/services/merge_requests/base_service.rb +++ b/app/services/merge_requests/base_service.rb @@ -60,31 +60,7 @@ module MergeRequests end def create_pipeline_for(merge_request, user) - return unless can_create_pipeline_for?(merge_request) - - create_detached_merge_request_pipeline(merge_request, user) - end - - def create_detached_merge_request_pipeline(merge_request, user) - if can_use_merge_request_ref?(merge_request) - Ci::CreatePipelineService.new(merge_request.source_project, user, - ref: merge_request.ref_path) - .execute(:merge_request_event, merge_request: merge_request) - else - Ci::CreatePipelineService.new(merge_request.source_project, user, - ref: merge_request.source_branch) - .execute(:merge_request_event, merge_request: merge_request) - end - end - - def can_create_pipeline_for?(merge_request) - ## - # UpdateMergeRequestsWorker could be retried by an exception. - # pipelines for merge request should not be recreated in such case. - return false if merge_request.find_actual_head_pipeline&.triggered_by_merge_request? - return false if merge_request.has_no_commits? - - true + MergeRequests::CreatePipelineService.new(project, user).execute(merge_request) end def can_use_merge_request_ref?(merge_request) diff --git a/app/services/merge_requests/close_service.rb b/app/services/merge_requests/close_service.rb index e77051bb1c9..b0f6166ea1c 100644 --- a/app/services/merge_requests/close_service.rb +++ b/app/services/merge_requests/close_service.rb @@ -18,6 +18,7 @@ module MergeRequests invalidate_cache_counts(merge_request, users: merge_request.assignees) merge_request.update_project_counter_caches cleanup_environments(merge_request) + cancel_auto_merge(merge_request) end merge_request @@ -33,5 +34,9 @@ module MergeRequests merge_request_metrics_service(merge_request).close(close_event) end end + + def cancel_auto_merge(merge_request) + AutoMergeService.new(project, current_user).cancel(merge_request) + end end end diff --git a/app/services/merge_requests/create_pipeline_service.rb b/app/services/merge_requests/create_pipeline_service.rb new file mode 100644 index 00000000000..03246cc1920 --- /dev/null +++ b/app/services/merge_requests/create_pipeline_service.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module MergeRequests + class CreatePipelineService < MergeRequests::BaseService + def execute(merge_request) + return unless can_create_pipeline_for?(merge_request) + + create_detached_merge_request_pipeline(merge_request) + end + + def create_detached_merge_request_pipeline(merge_request) + if can_use_merge_request_ref?(merge_request) + Ci::CreatePipelineService.new(merge_request.source_project, current_user, + ref: merge_request.ref_path) + .execute(:merge_request_event, merge_request: merge_request) + else + Ci::CreatePipelineService.new(merge_request.source_project, current_user, + ref: merge_request.source_branch) + .execute(:merge_request_event, merge_request: merge_request) + end + end + + def can_create_pipeline_for?(merge_request) + ## + # UpdateMergeRequestsWorker could be retried by an exception. + # pipelines for merge request should not be recreated in such case. + return false if !allow_duplicate && merge_request.find_actual_head_pipeline&.triggered_by_merge_request? + return false if merge_request.has_no_commits? + + true + end + + def allow_duplicate + params[:allow_duplicate] + end + end +end diff --git a/app/services/merge_requests/merge_to_ref_service.rb b/app/services/merge_requests/merge_to_ref_service.rb index 87147d90c32..8670b9ccf3d 100644 --- a/app/services/merge_requests/merge_to_ref_service.rb +++ b/app/services/merge_requests/merge_to_ref_service.rb @@ -20,20 +20,14 @@ module MergeRequests raise_error('Conflicts detected during merge') unless commit_id - commit = project.commit(commit_id) - target_id, source_id = commit.parent_ids - - success(commit_id: commit.id, - target_id: target_id, - source_id: source_id) - rescue MergeError => error + success(commit_id: commit_id) + rescue MergeError, ArgumentError => error error(error.message) end private def validate! - authorization_check! error_check! end @@ -43,21 +37,13 @@ module MergeRequests error = if !hooks_validation_pass?(merge_request) hooks_validation_error(merge_request) - elsif !@merge_request.mergeable_to_ref? - "Merge request is not mergeable to #{target_ref}" - elsif !source + elsif source.blank? 'No source for merge' end raise_error(error) if error end - def authorization_check! - unless Ability.allowed?(current_user, :admin_merge_request, project) - raise_error("You are not allowed to merge to this ref") - end - end - def target_ref merge_request.merge_ref_path end diff --git a/app/services/merge_requests/mergeability_check_service.rb b/app/services/merge_requests/mergeability_check_service.rb new file mode 100644 index 00000000000..ef833774e65 --- /dev/null +++ b/app/services/merge_requests/mergeability_check_service.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +module MergeRequests + class MergeabilityCheckService < ::BaseService + include Gitlab::Utils::StrongMemoize + + delegate :project, to: :@merge_request + delegate :repository, to: :project + + def initialize(merge_request) + @merge_request = merge_request + end + + # Updates the MR merge_status. Whenever it switches to a can_be_merged state, + # the merge-ref is refreshed. + # + # Returns a ServiceResponse indicating merge_status is/became can_be_merged + # and the merge-ref is synced. Success in case of being/becoming mergeable, + # error otherwise. + def execute + return ServiceResponse.error(message: 'Invalid argument') unless merge_request + return ServiceResponse.error(message: 'Unsupported operation') if Gitlab::Database.read_only? + + update_merge_status + + unless merge_request.can_be_merged? + return ServiceResponse.error(message: 'Merge request is not mergeable') + end + + unless payload.fetch(:merge_ref_head) + return ServiceResponse.error(message: 'Merge ref was not found') + end + + ServiceResponse.success(payload: payload) + end + + private + + attr_reader :merge_request + + def payload + strong_memoize(:payload) do + { + merge_ref_head: merge_ref_head_payload + } + end + end + + def merge_ref_head_payload + commit = merge_request.merge_ref_head + + return unless commit + + target_id, source_id = commit.parent_ids + + { + commit_id: commit.id, + source_id: source_id, + target_id: target_id + } + end + + def update_merge_status + return unless merge_request.recheck_merge_status? + + if can_git_merge? + merge_to_ref && merge_request.mark_as_mergeable + else + merge_request.mark_as_unmergeable + end + end + + def can_git_merge? + !merge_request.broken? && repository.can_be_merged?(merge_request.diff_head_sha, merge_request.target_branch) + end + + def merge_to_ref + result = MergeRequests::MergeToRefService.new(project, merge_request.author).execute(merge_request) + result[:status] == :success + end + end +end diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb index dfa7bd20254..2bc04470342 100644 --- a/app/services/projects/update_service.rb +++ b/app/services/projects/update_service.rb @@ -64,6 +64,7 @@ module Projects if project.previous_changes.include?(:visibility_level) && project.private? # don't enqueue immediately to prevent todos removal in case of a mistake + TodosDestroyer::ConfidentialIssueWorker.perform_in(Todo::WAIT_FOR_DELETE, nil, project.id) TodosDestroyer::ProjectPrivateWorker.perform_in(Todo::WAIT_FOR_DELETE, project.id) elsif (project_changed_feature_keys & todos_features_changes).present? TodosDestroyer::PrivateFeaturesWorker.perform_in(Todo::WAIT_FOR_DELETE, project.id) diff --git a/app/services/search_service.rb b/app/services/search_service.rb index e0cbfac2420..302510341ac 100644 --- a/app/services/search_service.rb +++ b/app/services/search_service.rb @@ -52,6 +52,10 @@ class SearchService @search_objects ||= search_results.objects(scope, params[:page]) end + def display_options + @display_options ||= search_results.display_options(scope) + end + private def search_service diff --git a/app/services/service_response.rb b/app/services/service_response.rb index 1de30e68d87..f3437ba16de 100644 --- a/app/services/service_response.rb +++ b/app/services/service_response.rb @@ -1,19 +1,20 @@ # frozen_string_literal: true class ServiceResponse - def self.success(message: nil) - new(status: :success, message: message) + def self.success(message: nil, payload: {}) + new(status: :success, message: message, payload: payload) end - def self.error(message:, http_status: nil) - new(status: :error, message: message, http_status: http_status) + def self.error(message:, payload: {}, http_status: nil) + new(status: :error, message: message, payload: payload, http_status: http_status) end - attr_reader :status, :message, :http_status + attr_reader :status, :message, :http_status, :payload - def initialize(status:, message: nil, http_status: nil) + def initialize(status:, message: nil, payload: {}, http_status: nil) self.status = status self.message = message + self.payload = payload self.http_status = http_status end @@ -27,5 +28,5 @@ class ServiceResponse private - attr_writer :status, :message, :http_status + attr_writer :status, :message, :http_status, :payload end diff --git a/app/services/todos/destroy/base_service.rb b/app/services/todos/destroy/base_service.rb index f3f1dbb5698..7378f10e7c4 100644 --- a/app/services/todos/destroy/base_service.rb +++ b/app/services/todos/destroy/base_service.rb @@ -13,7 +13,7 @@ module Todos # rubocop: disable CodeReuse/ActiveRecord def without_authorized(items) - items.where('user_id NOT IN (?)', authorized_users) + items.where('todos.user_id NOT IN (?)', authorized_users) end # rubocop: enable CodeReuse/ActiveRecord diff --git a/app/services/todos/destroy/confidential_issue_service.rb b/app/services/todos/destroy/confidential_issue_service.rb index 6276e332448..6cdd8c16894 100644 --- a/app/services/todos/destroy/confidential_issue_service.rb +++ b/app/services/todos/destroy/confidential_issue_service.rb @@ -2,36 +2,55 @@ module Todos module Destroy + # Service class for deleting todos that belongs to confidential issues. + # It deletes todos for users that are not at least reporters, issue author or assignee. + # + # Accepts issue_id or project_id as argument. + # When issue_id is passed it deletes matching todos for one confidential issue. + # When project_id is passed it deletes matching todos for all confidential issues of the project. class ConfidentialIssueService < ::Todos::Destroy::BaseService extend ::Gitlab::Utils::Override - attr_reader :issue + attr_reader :issues # rubocop: disable CodeReuse/ActiveRecord - def initialize(issue_id) - @issue = Issue.find_by(id: issue_id) + def initialize(issue_id: nil, project_id: nil) + @issues = + if issue_id + Issue.where(id: issue_id) + elsif project_id + project_confidential_issues(project_id) + end end # rubocop: enable CodeReuse/ActiveRecord private + def project_confidential_issues(project_id) + project = Project.find(project_id) + + project.issues.confidential_only + end + override :todos # rubocop: disable CodeReuse/ActiveRecord def todos - Todo.where(target: issue) - .where('user_id != ?', issue.author_id) - .where('user_id NOT IN (?)', issue.assignees.select(:id)) + Todo.joins_issue_and_assignees + .where(target: issues) + .where('issues.confidential = ?', true) + .where('todos.user_id != issues.author_id') + .where('todos.user_id != issue_assignees.user_id') end # rubocop: enable CodeReuse/ActiveRecord override :todos_to_remove? def todos_to_remove? - issue&.confidential? + issues&.any?(&:confidential?) end override :project_ids def project_ids - issue.project_id + issues&.distinct&.select(:project_id) end override :authorized_users |