diff options
Diffstat (limited to 'app/services')
27 files changed, 412 insertions, 90 deletions
diff --git a/app/services/boards/create_service.rb b/app/services/boards/create_service.rb index 1b796cef3e2..dd9358913fd 100644 --- a/app/services/boards/create_service.rb +++ b/app/services/boards/create_service.rb @@ -9,7 +9,7 @@ module Boards private def can_create_board? - parent.boards.empty? + parent.boards.empty? || parent.multiple_issue_boards_available? end def create_board! diff --git a/app/services/boards/destroy_service.rb b/app/services/boards/destroy_service.rb new file mode 100644 index 00000000000..ea0c1394aa3 --- /dev/null +++ b/app/services/boards/destroy_service.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Boards + class DestroyService < Boards::BaseService + def execute(board) + return false if parent.boards.size == 1 + + board.destroy + end + end +end diff --git a/app/services/boards/issues/move_service.rb b/app/services/boards/issues/move_service.rb index 834baeb9643..e27d34dbcab 100644 --- a/app/services/boards/issues/move_service.rb +++ b/app/services/boards/issues/move_service.rb @@ -79,9 +79,11 @@ module Boards # rubocop: enable CodeReuse/ActiveRecord def move_between_ids - return unless params[:move_after_id] || params[:move_before_id] + ids = [params[:move_after_id], params[:move_before_id]] + .map(&:to_i) + .map { |m| m.positive? ? m : nil } - [params[:move_after_id], params[:move_before_id]] + ids.any? ? ids : nil end end end diff --git a/app/services/boards/update_service.rb b/app/services/boards/update_service.rb new file mode 100644 index 00000000000..88aced01ccd --- /dev/null +++ b/app/services/boards/update_service.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Boards + class UpdateService < Boards::BaseService + def execute(board) + board.update(params) + end + end +end diff --git a/app/services/boards/visits/latest_service.rb b/app/services/boards/visits/latest_service.rb deleted file mode 100644 index d13e25b4f12..00000000000 --- a/app/services/boards/visits/latest_service.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -module Boards - module Visits - class LatestService < Boards::BaseService - def execute - return unless current_user - - recent_visit_model.latest(current_user, parent, count: params[:count]) - end - - private - - def recent_visit_model - parent.is_a?(Group) ? BoardGroupRecentVisit : BoardProjectRecentVisit - end - end - end -end diff --git a/app/services/branches/diverging_commit_counts_service.rb b/app/services/branches/diverging_commit_counts_service.rb new file mode 100644 index 00000000000..f947cec1663 --- /dev/null +++ b/app/services/branches/diverging_commit_counts_service.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module Branches + class DivergingCommitCountsService + def initialize(repository) + @repository = repository + @cache = Gitlab::RepositoryCache.new(repository) + end + + def call(branch) + if Feature.enabled?('gitaly_count_diverging_commits_no_max') + diverging_commit_counts_without_max(branch) + else + diverging_commit_counts(branch) + end + end + + private + + attr_reader :repository, :cache + + delegate :raw_repository, to: :repository + + def diverging_commit_counts(branch) + ## TODO: deprecate the below code after 12.0 + @root_ref_hash ||= raw_repository.commit(repository.root_ref).id + cache.fetch(:"diverging_commit_counts_#{branch.name}") do + number_commits_behind, number_commits_ahead = + repository.raw_repository.diverging_commit_count( + @root_ref_hash, + branch.dereferenced_target.sha, + max_count: Repository::MAX_DIVERGING_COUNT) + + if number_commits_behind + number_commits_ahead >= Repository::MAX_DIVERGING_COUNT + { distance: Repository::MAX_DIVERGING_COUNT } + else + { behind: number_commits_behind, ahead: number_commits_ahead } + end + end + end + + def diverging_commit_counts_without_max(branch) + @root_ref_hash ||= raw_repository.commit(repository.root_ref).id + cache.fetch(:"diverging_commit_counts_without_max_#{branch.name}") do + number_commits_behind, number_commits_ahead = + raw_repository.diverging_commit_count( + @root_ref_hash, + branch.dereferenced_target.sha) + + { behind: number_commits_behind, ahead: number_commits_ahead } + end + end + end +end diff --git a/app/services/ci/pipeline_schedule_service.rb b/app/services/ci/pipeline_schedule_service.rb index 5b5e9a26520..ef90d91c936 100644 --- a/app/services/ci/pipeline_schedule_service.rb +++ b/app/services/ci/pipeline_schedule_service.rb @@ -7,7 +7,18 @@ module Ci # Otherwise, multiple pipelines could be created in a short interval. schedule.schedule_next_run! - RunPipelineScheduleWorker.perform_async(schedule.id, schedule.owner&.id) + if Feature.enabled?(:ci_pipeline_schedule_async) + RunPipelineScheduleWorker.perform_async(schedule.id, schedule.owner&.id) + else + begin + RunPipelineScheduleWorker.new.perform(schedule.id, schedule.owner&.id) + ensure + ## + # This is the temporary solution for avoiding the memory bloat. + # See more https://gitlab.com/gitlab-org/gitlab-ce/issues/61955 + GC.start if Feature.enabled?(:ci_pipeline_schedule_force_gc, default_enabled: true) + end + end end end end diff --git a/app/services/clusters/gcp/finalize_creation_service.rb b/app/services/clusters/gcp/finalize_creation_service.rb index 5525c1b9b7f..2f3c1df7651 100644 --- a/app/services/clusters/gcp/finalize_creation_service.rb +++ b/app/services/clusters/gcp/finalize_creation_service.rb @@ -12,9 +12,6 @@ module Clusters create_gitlab_service_account! configure_kubernetes cluster.save! - - ClusterConfigureWorker.perform_async(cluster.id) - rescue Google::Apis::ServerError, Google::Apis::ClientError, Google::Apis::AuthorizationError => e log_service_error(e.class.name, provider.id, e.message) provider.make_errored!(s_('ClusterIntegration|Failed to request to Google Cloud Platform: %{message}') % { message: e.message }) diff --git a/app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb b/app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb index 4ad04ab801e..5d9bdc52d37 100644 --- a/app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb +++ b/app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb @@ -4,17 +4,30 @@ module Clusters module Gcp module Kubernetes class FetchKubernetesTokenService + DEFAULT_TOKEN_RETRY_DELAY = 5.seconds + TOKEN_RETRY_LIMIT = 5 + attr_reader :kubeclient, :service_account_token_name, :namespace - def initialize(kubeclient, service_account_token_name, namespace) + def initialize(kubeclient, service_account_token_name, namespace, token_retry_delay: DEFAULT_TOKEN_RETRY_DELAY) @kubeclient = kubeclient @service_account_token_name = service_account_token_name @namespace = namespace + @token_retry_delay = token_retry_delay end def execute - token_base64 = get_secret&.dig('data', 'token') - Base64.decode64(token_base64) if token_base64 + # Kubernetes will create the Secret and set the token asynchronously + # so it is necessary to retry + # https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/#token-controller + TOKEN_RETRY_LIMIT.times do + token_base64 = get_secret&.dig('data', 'token') + return Base64.decode64(token_base64) if token_base64 + + sleep @token_retry_delay + end + + nil end private diff --git a/app/services/files/create_service.rb b/app/services/files/create_service.rb index fd5442a6c28..f2cd51ef4d0 100644 --- a/app/services/files/create_service.rb +++ b/app/services/files/create_service.rb @@ -3,7 +3,7 @@ module Files class CreateService < Files::BaseService def create_commit! - transformer = Lfs::FileTransformer.new(project, @branch_name) + transformer = Lfs::FileTransformer.new(project, repository, @branch_name) result = transformer.new_file(@file_path, @file_content) diff --git a/app/services/files/multi_service.rb b/app/services/files/multi_service.rb index c1bc26c330a..d8c4e5bc5e8 100644 --- a/app/services/files/multi_service.rb +++ b/app/services/files/multi_service.rb @@ -5,7 +5,7 @@ module Files UPDATE_FILE_ACTIONS = %w(update move delete chmod).freeze def create_commit! - transformer = Lfs::FileTransformer.new(project, @branch_name) + transformer = Lfs::FileTransformer.new(project, repository, @branch_name) actions = actions_after_lfs_transformation(transformer, params[:actions]) actions = transform_move_actions(actions) diff --git a/app/services/git/branch_hooks_service.rb b/app/services/git/branch_hooks_service.rb index d21a6bb1b9a..c41f445c3c4 100644 --- a/app/services/git/branch_hooks_service.rb +++ b/app/services/git/branch_hooks_service.rb @@ -20,8 +20,7 @@ module Git strong_memoize(:commits) do if creating_default_branch? # The most recent PROCESS_COMMIT_LIMIT commits in the default branch - offset = [count_commits_in_branch - PROCESS_COMMIT_LIMIT, 0].max - project.repository.commits(params[:newrev], offset: offset, limit: PROCESS_COMMIT_LIMIT) + project.repository.commits(params[:newrev], limit: PROCESS_COMMIT_LIMIT) elsif creating_branch? # Use the pushed commits that aren't reachable by the default branch # as a heuristic. This may include more commits than are actually @@ -84,9 +83,6 @@ module Git # Schedules processing of commit messages def enqueue_process_commit_messages - # don't process commits for the initial push to the default branch - return if creating_default_branch? - limited_commits.each do |commit| next unless commit.matches_cross_reference_regex? @@ -109,8 +105,14 @@ module Git CreateGpgSignatureWorker.perform_async(signable, project.id) end + # It's not sufficient to just check for a blank SHA as it's possible for the + # branch to be pushed, but for the `post-receive` hook to never run: + # https://gitlab.com/gitlab-org/gitlab-ce/issues/59257 def creating_branch? - Gitlab::Git.blank_ref?(params[:oldrev]) + strong_memoize(:creating_branch) do + Gitlab::Git.blank_ref?(params[:oldrev]) || + !project.repository.branch_exists?(branch_name) + end end def updating_branch? diff --git a/app/services/git/wiki_push_service.rb b/app/services/git/wiki_push_service.rb new file mode 100644 index 00000000000..a053f133016 --- /dev/null +++ b/app/services/git/wiki_push_service.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Git + class WikiPushService < ::BaseService + def execute + # This is used in EE + end + end +end diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb index 26132f1824a..02de080e0ba 100644 --- a/app/services/issuable_base_service.rb +++ b/app/services/issuable_base_service.rb @@ -205,7 +205,7 @@ class IssuableBaseService < BaseService end if issuable.changed? || params.present? - issuable.assign_attributes(params.merge(updated_by: current_user)) + issuable.assign_attributes(params) if has_title_or_description_changed?(issuable) issuable.assign_attributes(last_edited_at: Time.now, last_edited_by: current_user) @@ -213,11 +213,16 @@ class IssuableBaseService < BaseService before_update(issuable) + # Do not touch when saving the issuable if only changes position within a list. We should call + # this method at this point to capture all possible changes. + should_touch = update_timestamp?(issuable) + + issuable.updated_by = current_user if should_touch # We have to perform this check before saving the issuable as Rails resets # the changed fields upon calling #save. update_project_counters = issuable.project && update_project_counter_caches?(issuable) - if issuable.with_transaction_returning_status { issuable.save } + if issuable.with_transaction_returning_status { issuable.save(touch: should_touch) } # We do not touch as it will affect a update on updated_at field ActiveRecord::Base.no_touching do Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, old_labels: old_associations[:labels]) @@ -402,4 +407,8 @@ class IssuableBaseService < BaseService def ensure_milestone_available(issuable) issuable.milestone_id = nil unless issuable.milestone_available? end + + def update_timestamp?(issuable) + issuable.changes.keys != ["relative_position"] + end end diff --git a/app/services/issues/reorder_service.rb b/app/services/issues/reorder_service.rb new file mode 100644 index 00000000000..02c18d31b5e --- /dev/null +++ b/app/services/issues/reorder_service.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module Issues + class ReorderService < Issues::BaseService + def execute(issue) + return false unless can?(current_user, :update_issue, issue) + return false if group && !can?(current_user, :read_group, group) + + attrs = issue_params(group) + return false if attrs.empty? + + update(issue, attrs) + end + + private + + def group + return unless params[:group_full_path] + + @group ||= Group.find_by_full_path(params[:group_full_path]) + end + + def update(issue, attrs) + ::Issues::UpdateService.new(project, current_user, attrs).execute(issue) + rescue ActiveRecord::RecordNotFound + false + end + + def issue_params(group) + attrs = {} + + if move_between_ids + attrs[:move_between_ids] = move_between_ids + attrs[:board_group_id] = group&.id + end + + attrs + end + + def move_between_ids + ids = [params[:move_after_id], params[:move_before_id]] + .map(&:to_i) + .map { |m| m.positive? ? m : nil } + + ids.any? ? ids : nil + end + end +end diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb index cb2337d29d4..6b9f23f24cd 100644 --- a/app/services/issues/update_service.rb +++ b/app/services/issues/update_service.rb @@ -76,6 +76,7 @@ module Issues issue_before = get_issue_if_allowed(before_id, board_group_id) issue_after = get_issue_if_allowed(after_id, board_group_id) + raise ActiveRecord::RecordNotFound unless issue_before || issue_after issue.move_between(issue_before, issue_after) end diff --git a/app/services/lfs/file_transformer.rb b/app/services/lfs/file_transformer.rb index 5239fe1b6e3..88f59b820a4 100644 --- a/app/services/lfs/file_transformer.rb +++ b/app/services/lfs/file_transformer.rb @@ -4,21 +4,29 @@ module Lfs # Usage: Calling `new_file` check to see if a file should be in LFS and # return a transformed result with `content` and `encoding` to commit. # + # The `repository` passed to the initializer can be a Repository or + # a DesignManagement::Repository (an EE-specific class that inherits + # from Repository). + # + # The `repository_type` property will be one of the types named in + # `Gitlab::GlRepository.types`, and is recorded on the `LfsObjectsProject` + # in order to identify the repository location of the blob. + # # For LFS an LfsObject linked to the project is stored and an LFS # pointer returned. If the file isn't in LFS the untransformed content # is returned to save in the commit. # - # transformer = Lfs::FileTransformer.new(project, @branch_name) + # transformer = Lfs::FileTransformer.new(project, repository, @branch_name) # content_or_lfs_pointer = transformer.new_file(file_path, content).content # create_transformed_commit(content_or_lfs_pointer) # class FileTransformer - attr_reader :project, :branch_name - - delegate :repository, to: :project + attr_reader :project, :repository, :repository_type, :branch_name - def initialize(project, branch_name) + def initialize(project, repository, branch_name) @project = project + @repository = repository + @repository_type = repository.repo_type.name @branch_name = branch_name end @@ -52,7 +60,7 @@ module Lfs end def cached_attributes - @cached_attributes ||= Gitlab::Git::AttributesAtRefParser.new(repository, branch_name) + @cached_attributes ||= repository.attributes_at(branch_name) end # rubocop: disable CodeReuse/ActiveRecord @@ -64,7 +72,11 @@ module Lfs # rubocop: enable CodeReuse/ActiveRecord def link_lfs_object!(lfs_object) - project.lfs_objects << lfs_object + LfsObjectsProject.safe_find_or_create_by!( + project: project, + lfs_object: lfs_object, + repository_type: repository_type + ) end def parse_file_content(file_content, encoding: nil) diff --git a/app/services/merge_requests/create_from_issue_service.rb b/app/services/merge_requests/create_from_issue_service.rb index e69791872cc..2a217a6f689 100644 --- a/app/services/merge_requests/create_from_issue_service.rb +++ b/app/services/merge_requests/create_from_issue_service.rb @@ -6,17 +6,20 @@ module MergeRequests # branch - the name of new branch # ref - the source of new branch. - @branch_name = params[:branch_name] - @issue_iid = params[:issue_iid] - @ref = params[:ref] + @branch_name = params[:branch_name] + @issue_iid = params[:issue_iid] + @ref = params[:ref] + @target_project_id = params[:target_project_id] super(project, user) end def execute + return error('Project not found') if target_project.blank? + return error('Not allowed to create merge request') unless can_create_merge_request? return error('Invalid issue iid') unless @issue_iid.present? && issue.present? - result = CreateBranchService.new(project, current_user).execute(branch_name, ref) + result = CreateBranchService.new(target_project, current_user).execute(branch_name, ref) return result if result[:status] == :error new_merge_request = create(merge_request) @@ -26,7 +29,7 @@ module MergeRequests success(new_merge_request) else - SystemNoteService.new_issue_branch(issue, project, current_user, branch_name) + SystemNoteService.new_issue_branch(issue, project, current_user, branch_name, branch_project: target_project) error(new_merge_request.errors) end @@ -34,6 +37,10 @@ module MergeRequests private + def can_create_merge_request? + can?(current_user, :create_merge_request_from, target_project) + end + # rubocop: disable CodeReuse/ActiveRecord def issue @issue ||= IssuesFinder.new(current_user, project_id: project.id).find_by(iid: @issue_iid) @@ -45,21 +52,21 @@ module MergeRequests end def ref - return @ref if project.repository.branch_exists?(@ref) + return @ref if target_project.repository.branch_exists?(@ref) - project.default_branch || 'master' + target_project.default_branch || 'master' end def merge_request - MergeRequests::BuildService.new(project, current_user, merge_request_params).execute + MergeRequests::BuildService.new(target_project, current_user, merge_request_params).execute end def merge_request_params { issue_iid: @issue_iid, - source_project_id: project.id, + source_project_id: target_project.id, source_branch: branch_name, - target_project_id: project.id, + target_project_id: target_project.id, target_branch: ref } end @@ -67,5 +74,14 @@ module MergeRequests def success(merge_request) super().merge(merge_request: merge_request) end + + def target_project + @target_project ||= + if @target_project_id.present? + project.forks.find_by_id(@target_project_id) + else + project + end + 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..efe4dcd6255 100644 --- a/app/services/merge_requests/merge_to_ref_service.rb +++ b/app/services/merge_requests/merge_to_ref_service.rb @@ -11,6 +11,8 @@ module MergeRequests # be executed regardless of the `target_ref` current state). # class MergeToRefService < MergeRequests::MergeBaseService + extend ::Gitlab::Utils::Override + def execute(merge_request) @merge_request = merge_request @@ -26,14 +28,18 @@ module MergeRequests success(commit_id: commit.id, target_id: target_id, source_id: source_id) - rescue MergeError => error + rescue MergeError, ArgumentError => error error(error.message) end private + override :source + def source + merge_request.diff_head_sha + end + def validate! - authorization_check! error_check! end @@ -43,21 +49,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..9fa50c9448f --- /dev/null +++ b/app/services/merge_requests/mergeability_check_service.rb @@ -0,0 +1,120 @@ +# 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. + # + # recheck - When given, it'll enforce a merge-ref refresh if the current merge_status is + # can_be_merged or cannot_be_merged and merge-ref is outdated. + # Given MergeRequests::RefreshService is called async, it might happen that the target + # branch gets updated, but the MergeRequest#merge_status lags behind. So in scenarios + # where we need the current state of the merge ref in repository, the `recheck` + # argument is required. + # + # 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(recheck: false) + return ServiceResponse.error(message: 'Invalid argument') unless merge_request + return ServiceResponse.error(message: 'Unsupported operation') if Gitlab::Database.read_only? + + recheck! if recheck + update_merge_status + + unless merge_request.can_be_merged? + return ServiceResponse.error(message: 'Merge request is not mergeable') + end + + unless merge_ref_auto_sync_enabled? + return ServiceResponse.error(message: 'Merge ref is outdated due to disabled feature') + end + + unless payload.fetch(:merge_ref_head) + return ServiceResponse.error(message: 'Merge ref cannot be updated') + 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 recheck! + if !merge_request.recheck_merge_status? && outdated_merge_ref? + merge_request.mark_as_unchecked + end + end + + # Checks if the existing merge-ref is synced with the target branch. + # + # Returns true if the merge-ref does not exists or is out of sync. + def outdated_merge_ref? + return false unless merge_ref_auto_sync_enabled? + return false unless merge_request.open? + + return true unless ref_head = merge_request.merge_ref_head + return true unless target_sha = merge_request.target_branch_sha + return true unless source_sha = merge_request.source_branch_sha + + ref_head.parent_ids != [target_sha, source_sha] + 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 + return true unless merge_ref_auto_sync_enabled? + + result = MergeRequests::MergeToRefService.new(project, merge_request.author).execute(merge_request) + result[:status] == :success + end + + def merge_ref_auto_sync_enabled? + Feature.enabled?(:merge_ref_auto_sync, project, default_enabled: true) + end + end +end diff --git a/app/services/pages_domains/obtain_lets_encrypt_certificate_service.rb b/app/services/pages_domains/obtain_lets_encrypt_certificate_service.rb index 2dfe1a3d8ca..58f795e639e 100644 --- a/app/services/pages_domains/obtain_lets_encrypt_certificate_service.rb +++ b/app/services/pages_domains/obtain_lets_encrypt_certificate_service.rb @@ -2,6 +2,14 @@ module PagesDomains class ObtainLetsEncryptCertificateService + # time for processing validation requests for acme challenges + # 5-15 seconds is usually enough + CHALLENGE_PROCESSING_DELAY = 1.minute.freeze + + # time LetsEncrypt ACME server needs to generate the certificate + # no particular SLA, usually takes 10-15 seconds + CERTIFICATE_PROCESSING_DELAY = 1.minute.freeze + attr_reader :pages_domain def initialize(pages_domain) @@ -14,6 +22,7 @@ module PagesDomains unless acme_order ::PagesDomains::CreateAcmeOrderService.new(pages_domain).execute + PagesDomainSslRenewalWorker.perform_in(CHALLENGE_PROCESSING_DELAY, pages_domain.id) return end @@ -23,6 +32,7 @@ module PagesDomains case api_order.status when 'ready' api_order.request_certificate(private_key: acme_order.private_key, domain: pages_domain.domain) + PagesDomainSslRenewalWorker.perform_in(CERTIFICATE_PROCESSING_DELAY, pages_domain.id) when 'valid' save_certificate(acme_order.private_key, api_order) acme_order.destroy! @@ -35,7 +45,7 @@ module PagesDomains def save_certificate(private_key, api_order) certificate = api_order.certificate - pages_domain.update!(key: private_key, certificate: certificate) + pages_domain.update!(gitlab_provided_key: private_key, gitlab_provided_certificate: certificate) end end end diff --git a/app/services/projects/propagate_service_template.rb b/app/services/projects/propagate_service_template.rb index a2f36d2bd1b..a25c985585b 100644 --- a/app/services/projects/propagate_service_template.rb +++ b/app/services/projects/propagate_service_template.rb @@ -24,7 +24,7 @@ module Projects def propagate_projects_with_template loop do - batch = project_ids_batch + batch = Project.uncached { project_ids_batch } bulk_create_from_template(batch) unless batch.empty? diff --git a/app/services/search_service.rb b/app/services/search_service.rb index 302510341ac..e0cbfac2420 100644 --- a/app/services/search_service.rb +++ b/app/services/search_service.rb @@ -52,10 +52,6 @@ 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/system_note_service.rb b/app/services/system_note_service.rb index 27d59279d75..237ddbcf2c2 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -404,8 +404,9 @@ module SystemNoteService # Example note text: # # "created branch `201-issue-branch-button`" - def new_issue_branch(issue, project, author, branch) - link = url_helpers.project_compare_path(project, from: project.default_branch, to: branch) + def new_issue_branch(issue, project, author, branch, branch_project: nil) + branch_project ||= project + link = url_helpers.project_compare_path(branch_project, from: branch_project.default_branch, to: branch) body = "created branch [`#{branch}`](#{link}) to address this issue" @@ -413,7 +414,7 @@ module SystemNoteService end def new_merge_request(issue, project, author, merge_request) - body = "created merge request #{merge_request.to_reference} to address this issue" + body = "created merge request #{merge_request.to_reference(project)} to address this issue" create_note(NoteSummary.new(issue, project, author, body, action: 'merge')) end diff --git a/app/services/users/build_service.rb b/app/services/users/build_service.rb index 30f7743c56e..026bcfcdaf4 100644 --- a/app/services/users/build_service.rb +++ b/app/services/users/build_service.rb @@ -5,10 +5,12 @@ module Users delegate :user_default_internal_regex_enabled?, :user_default_internal_regex_instance, to: :'Gitlab::CurrentSettings.current_application_settings' + attr_reader :identity_params def initialize(current_user, params = {}) @current_user = current_user @params = params.dup + @identity_params = params.slice(*identity_attributes) end def execute(skip_authorization: false) @@ -26,10 +28,8 @@ module Users end end - identity_attrs = params.slice(*identity_params) - - unless identity_attrs.empty? - user.identities.build(identity_attrs) + unless identity_params.empty? + user.identities.build(identity_params) end user @@ -37,7 +37,7 @@ module Users private - def identity_params + def identity_attributes [:extern_uid, :provider] end diff --git a/app/services/users/update_service.rb b/app/services/users/update_service.rb index 0b00bd135eb..8f52e9cb23f 100644 --- a/app/services/users/update_service.rb +++ b/app/services/users/update_service.rb @@ -3,11 +3,13 @@ module Users class UpdateService < BaseService include NewUserNotifier + attr_reader :user, :identity_params def initialize(current_user, params = {}) @current_user = current_user @user = params.delete(:user) @status_params = params.delete(:status) + @identity_params = params.slice(*identity_attributes) @params = params.dup end @@ -15,8 +17,8 @@ module Users yield(@user) if block_given? user_exists = @user.persisted? - assign_attributes + assign_identity if @user.save(validate: validate) && update_status notify_success(user_exists) @@ -55,7 +57,26 @@ module Users params.reject! { |key, _| read_only.include?(key.to_sym) } end - @user.assign_attributes(params) unless params.empty? + @user.assign_attributes(params.except(*identity_attributes)) unless params.empty? # rubocop: disable CodeReuse/ActiveRecord + end + + def assign_identity + return unless identity_params.present? + + identity = user.identities.find_or_create_by(provider_params) # rubocop: disable CodeReuse/ActiveRecord + identity.update(identity_params) + end + + def identity_attributes + [:provider, :extern_uid] + end + + def provider_attributes + [:provider] + end + + def provider_params + identity_params.slice(*provider_attributes) end end end |