diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-08-20 18:42:06 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-08-20 18:42:06 +0000 |
commit | 6e4e1050d9dba2b7b2523fdd1768823ab85feef4 (patch) | |
tree | 78be5963ec075d80116a932011d695dd33910b4e /app/services/projects | |
parent | 1ce776de4ae122aba3f349c02c17cebeaa8ecf07 (diff) | |
download | gitlab-ce-6e4e1050d9dba2b7b2523fdd1768823ab85feef4.tar.gz |
Add latest changes from gitlab-org/gitlab@13-3-stable-ee
Diffstat (limited to 'app/services/projects')
18 files changed, 180 insertions, 140 deletions
diff --git a/app/services/projects/alerting/notify_service.rb b/app/services/projects/alerting/notify_service.rb index e08bc8efb15..f883c8c7bd8 100644 --- a/app/services/projects/alerting/notify_service.rb +++ b/app/services/projects/alerting/notify_service.rb @@ -58,10 +58,6 @@ module Projects AlertManagement::Alert.not_resolved.for_fingerprint(project, fingerprint).first end - def send_email? - incident_management_setting.send_email? - end - def process_incident_issues(alert) return if alert.issue diff --git a/app/services/projects/auto_devops/disable_service.rb b/app/services/projects/auto_devops/disable_service.rb index c90510c581d..e10668ac9bd 100644 --- a/app/services/projects/auto_devops/disable_service.rb +++ b/app/services/projects/auto_devops/disable_service.rb @@ -23,7 +23,7 @@ module Projects # for more context. # rubocop: disable CodeReuse/ActiveRecord def first_pipeline_failure? - auto_devops_pipelines.success.limit(1).count.zero? && + auto_devops_pipelines.success.limit(1).count == 0 && auto_devops_pipelines.failed.limit(1).count.nonzero? end # rubocop: enable CodeReuse/ActiveRecord diff --git a/app/services/projects/cleanup_service.rb b/app/services/projects/cleanup_service.rb index 04624b96bf0..4ced9feff00 100644 --- a/app/services/projects/cleanup_service.rb +++ b/app/services/projects/cleanup_service.rb @@ -22,7 +22,7 @@ module Projects apply_bfg_object_map! # Remove older objects that are no longer referenced - GitGarbageCollectWorker.new.perform(project.id, :gc) + GitGarbageCollectWorker.new.perform(project.id, :gc, "project_cleanup:gc:#{project.id}") # The cache may now be inaccurate, and holding onto it could prevent # bugs assuming the presence of some object from manifesting for some diff --git a/app/services/projects/container_repository/cleanup_tags_service.rb b/app/services/projects/container_repository/cleanup_tags_service.rb index c5809c11ea9..204a54ff23a 100644 --- a/app/services/projects/container_repository/cleanup_tags_service.rb +++ b/app/services/projects/container_repository/cleanup_tags_service.rb @@ -39,11 +39,8 @@ module Projects end def filter_by_name(tags) - # Technical Debt: https://gitlab.com/gitlab-org/gitlab/issues/207267 - # name_regex to be removed when container_expiration_policies is updated - # to have both regex columns - regex_delete = Gitlab::UntrustedRegexp.new("\\A#{params['name_regex_delete'] || params['name_regex']}\\z") - regex_retain = Gitlab::UntrustedRegexp.new("\\A#{params['name_regex_keep']}\\z") + regex_delete = ::Gitlab::UntrustedRegexp.new("\\A#{params['name_regex_delete'] || params['name_regex']}\\z") + regex_retain = ::Gitlab::UntrustedRegexp.new("\\A#{params['name_regex_keep']}\\z") tags.select do |tag| # regex_retain will override any overlapping matches by regex_delete @@ -81,11 +78,11 @@ module Projects def valid_regex? %w(name_regex_delete name_regex name_regex_keep).each do |param_name| regex = params[param_name] - Gitlab::UntrustedRegexp.new(regex) unless regex.blank? + ::Gitlab::UntrustedRegexp.new(regex) unless regex.blank? end true rescue RegexpError => e - Gitlab::ErrorTracking.log_exception(e, project_id: project.id) + ::Gitlab::ErrorTracking.log_exception(e, project_id: project.id) false end end diff --git a/app/services/projects/container_repository/delete_tags_service.rb b/app/services/projects/container_repository/delete_tags_service.rb index 5d4059710bb..a23a6a369b2 100644 --- a/app/services/projects/container_repository/delete_tags_service.rb +++ b/app/services/projects/container_repository/delete_tags_service.rb @@ -6,65 +6,35 @@ module Projects LOG_DATA_BASE = { service_class: self.to_s }.freeze def execute(container_repository) + @container_repository = container_repository return error('access denied') unless can?(current_user, :destroy_container_image, project) - tag_names = params[:tags] - return error('not tags specified') if tag_names.blank? + @tag_names = params[:tags] + return error('not tags specified') if @tag_names.blank? - smart_delete(container_repository, tag_names) + delete_tags end private - # Delete tags by name with a single DELETE request. This is only supported - # by the GitLab Container Registry fork. See - # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23325 for details. - def fast_delete(container_repository, tag_names) - deleted_tags = tag_names.select do |name| - container_repository.delete_tag_by_name(name) - end - - deleted_tags.any? ? success(deleted: deleted_tags) : error('could not delete tags') + def delete_tags + delete_service.execute + .tap(&method(:log_response)) end - # Replace a tag on the registry with a dummy tag. - # This is a hack as the registry doesn't support deleting individual - # tags. This code effectively pushes a dummy image and assigns the tag to it. - # This way when the tag is deleted only the dummy image is affected. - # This is used to preverse compatibility with third-party registries that - # don't support fast delete. - # See https://gitlab.com/gitlab-org/gitlab/issues/15737 for a discussion - def slow_delete(container_repository, tag_names) - # generates the blobs for the dummy image - dummy_manifest = container_repository.client.generate_empty_manifest(container_repository.path) - return error('could not generate manifest') if dummy_manifest.nil? - - deleted_tags = replace_tag_manifests(container_repository, dummy_manifest, tag_names) + def delete_service + fast_delete_enabled = Feature.enabled?(:container_registry_fast_tag_delete, default_enabled: true) - # Deletes the dummy image - # All created tag digests are the same since they all have the same dummy image. - # a single delete is sufficient to remove all tags with it - if deleted_tags.any? && container_repository.delete_tag_by_digest(deleted_tags.each_value.first) - success(deleted: deleted_tags.keys) + if fast_delete_enabled && @container_repository.client.supports_tag_delete? + ::Projects::ContainerRepository::Gitlab::DeleteTagsService.new(@container_repository, @tag_names) else - error('could not delete tags') + ::Projects::ContainerRepository::ThirdParty::DeleteTagsService.new(@container_repository, @tag_names) end end - def smart_delete(container_repository, tag_names) - fast_delete_enabled = Feature.enabled?(:container_registry_fast_tag_delete, default_enabled: true) - response = if fast_delete_enabled && container_repository.client.supports_tag_delete? - fast_delete(container_repository, tag_names) - else - slow_delete(container_repository, tag_names) - end - - response.tap { |r| log_response(r, container_repository) } - end - - def log_response(response, container_repository) + def log_response(response) log_data = LOG_DATA_BASE.merge( - container_repository_id: container_repository.id, + container_repository_id: @container_repository.id, message: 'deleted tags' ) @@ -76,26 +46,6 @@ module Projects log_error(log_data) end end - - # update the manifests of the tags with the new dummy image - def replace_tag_manifests(container_repository, dummy_manifest, tag_names) - deleted_tags = {} - - tag_names.each do |name| - digest = container_repository.client.put_tag(container_repository.path, name, dummy_manifest) - next unless digest - - deleted_tags[name] = digest - end - - # make sure the digests are the same (it should always be) - digests = deleted_tags.values.uniq - - # rubocop: disable CodeReuse/ActiveRecord - Gitlab::ErrorTracking.track_and_raise_for_dev_exception(ArgumentError.new('multiple tag digests')) if digests.many? - - deleted_tags - end end end end diff --git a/app/services/projects/container_repository/gitlab/delete_tags_service.rb b/app/services/projects/container_repository/gitlab/delete_tags_service.rb new file mode 100644 index 00000000000..18049648e26 --- /dev/null +++ b/app/services/projects/container_repository/gitlab/delete_tags_service.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Projects + module ContainerRepository + module Gitlab + class DeleteTagsService + include BaseServiceUtility + + def initialize(container_repository, tag_names) + @container_repository = container_repository + @tag_names = tag_names + end + + # Delete tags by name with a single DELETE request. This is only supported + # by the GitLab Container Registry fork. See + # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23325 for details. + def execute + return success(deleted: []) if @tag_names.empty? + + deleted_tags = @tag_names.select do |name| + @container_repository.delete_tag_by_name(name) + end + + deleted_tags.any? ? success(deleted: deleted_tags) : error('could not delete tags') + end + end + end + end +end diff --git a/app/services/projects/container_repository/third_party/delete_tags_service.rb b/app/services/projects/container_repository/third_party/delete_tags_service.rb new file mode 100644 index 00000000000..6504172109e --- /dev/null +++ b/app/services/projects/container_repository/third_party/delete_tags_service.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module Projects + module ContainerRepository + module ThirdParty + class DeleteTagsService + include BaseServiceUtility + + def initialize(container_repository, tag_names) + @container_repository = container_repository + @tag_names = tag_names + end + + # Replace a tag on the registry with a dummy tag. + # This is a hack as the registry doesn't support deleting individual + # tags. This code effectively pushes a dummy image and assigns the tag to it. + # This way when the tag is deleted only the dummy image is affected. + # This is used to preverse compatibility with third-party registries that + # don't support fast delete. + # See https://gitlab.com/gitlab-org/gitlab/issues/15737 for a discussion + def execute + return success(deleted: []) if @tag_names.empty? + + # generates the blobs for the dummy image + dummy_manifest = @container_repository.client.generate_empty_manifest(@container_repository.path) + return error('could not generate manifest') if dummy_manifest.nil? + + deleted_tags = replace_tag_manifests(dummy_manifest) + + # Deletes the dummy image + # All created tag digests are the same since they all have the same dummy image. + # a single delete is sufficient to remove all tags with it + if deleted_tags.any? && @container_repository.delete_tag_by_digest(deleted_tags.each_value.first) + success(deleted: deleted_tags.keys) + else + error('could not delete tags') + end + end + + private + + # update the manifests of the tags with the new dummy image + def replace_tag_manifests(dummy_manifest) + deleted_tags = {} + + @tag_names.each do |name| + digest = @container_repository.client.put_tag(@container_repository.path, name, dummy_manifest) + next unless digest + + deleted_tags[name] = digest + end + + # make sure the digests are the same (it should always be) + digests = deleted_tags.values.uniq + + # rubocop: disable CodeReuse/ActiveRecord + Gitlab::ErrorTracking.track_and_raise_for_dev_exception(ArgumentError.new('multiple tag digests')) if digests.many? + + deleted_tags + end + end + end + end +end diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index 6569277ad9d..33ed1151407 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -55,9 +55,11 @@ module Projects save_project_and_import_data - after_create_actions if @project.persisted? + Gitlab::ApplicationContext.with_context(related_class: "Projects::CreateService", project: @project) do + after_create_actions if @project.persisted? - import_schedule + import_schedule + end @project rescue ActiveRecord::RecordInvalid => e diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index 2e949f2fc55..37487261f2c 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -31,7 +31,7 @@ module Projects attempt_destroy_transaction(project) system_hook_service.execute_hooks_for(project, :destroy) - log_info("Project \"#{project.full_path}\" was removed") + log_info("Project \"#{project.full_path}\" was deleted") current_user.invalidate_personal_projects_count diff --git a/app/services/projects/fork_service.rb b/app/services/projects/fork_service.rb index 6ac53b15ef9..bb660d47887 100644 --- a/app/services/projects/fork_service.rb +++ b/app/services/projects/fork_service.rb @@ -14,10 +14,10 @@ module Projects @valid_fork_targets ||= ForkTargetsFinder.new(@project, current_user).execute end - def valid_fork_target? + def valid_fork_target?(namespace = target_namespace) return true if current_user.admin? - valid_fork_targets.include?(target_namespace) + valid_fork_targets.include?(namespace) end private diff --git a/app/services/projects/prometheus/alerts/notify_service.rb b/app/services/projects/prometheus/alerts/notify_service.rb index ea557ebe20f..d32ead76d00 100644 --- a/app/services/projects/prometheus/alerts/notify_service.rb +++ b/app/services/projects/prometheus/alerts/notify_service.rb @@ -42,10 +42,6 @@ module Projects Gitlab::Utils::DeepSize.new(params).valid? end - def send_email? - incident_management_setting.send_email && firings.any? - end - def firings @firings ||= alerts_by_status('firing') end @@ -125,6 +121,8 @@ module Projects end def send_alert_email + return unless firings.any? + notification_service .async .prometheus_alerts_fired(project, firings) diff --git a/app/services/projects/propagate_service_template.rb b/app/services/projects/propagate_service_template.rb index b6465810fde..54d09b354a1 100644 --- a/app/services/projects/propagate_service_template.rb +++ b/app/services/projects/propagate_service_template.rb @@ -66,7 +66,7 @@ module Projects # rubocop: disable CodeReuse/ActiveRecord def run_callbacks(batch) - if active_external_issue_tracker? + if template.issue_tracker? Project.where(id: batch).update_all(has_external_issue_tracker: true) end @@ -76,10 +76,6 @@ module Projects end # rubocop: enable CodeReuse/ActiveRecord - def active_external_issue_tracker? - template.issue_tracker? && !template.default - end - def active_external_wiki? template.type == 'ExternalWikiService' end diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index 60e5b7e2639..0fb70feec86 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -55,10 +55,18 @@ module Projects raise TransferError.new(s_('TransferProject|Project cannot be transferred, because tags are present in its container registry')) end + if project.has_packages?(:npm) && !new_namespace_has_same_root?(project) + raise TransferError.new(s_("TransferProject|Root namespace can't be updated if project has NPM packages")) + end + attempt_transfer_transaction end # rubocop: enable CodeReuse/ActiveRecord + def new_namespace_has_same_root?(project) + new_namespace.root_ancestor == project.namespace.root_ancestor + end + def attempt_transfer_transaction Project.transaction do project.expire_caches_before_rename(@old_path) diff --git a/app/services/projects/update_pages_configuration_service.rb b/app/services/projects/update_pages_configuration_service.rb index 674071ad92a..88c17d502df 100644 --- a/app/services/projects/update_pages_configuration_service.rb +++ b/app/services/projects/update_pages_configuration_service.rb @@ -11,15 +11,20 @@ module Projects end def execute - if file_equals?(pages_config_file, pages_config_json) - return success(reload: false) + # If the pages were never deployed, we can't write out the config, as the + # directory would not exist. + # https://gitlab.com/gitlab-org/gitlab/-/issues/235139 + return success unless project.pages_deployed? + + unless file_equals?(pages_config_file, pages_config_json) + update_file(pages_config_file, pages_config_json) + reload_daemon end - update_file(pages_config_file, pages_config_json) - reload_daemon - success(reload: true) + success rescue => e - error(e.message) + Gitlab::ErrorTracking.track_exception(e) + error(e.message, pass_back: { exception: e }) end private diff --git a/app/services/projects/update_pages_service.rb b/app/services/projects/update_pages_service.rb index 59389a0fa65..334f5993d15 100644 --- a/app/services/projects/update_pages_service.rb +++ b/app/services/projects/update_pages_service.rb @@ -136,7 +136,7 @@ module Projects def max_size max_pages_size = max_size_from_settings - return ::Gitlab::Pages::MAX_SIZE if max_pages_size.zero? + return ::Gitlab::Pages::MAX_SIZE if max_pages_size == 0 max_pages_size end diff --git a/app/services/projects/update_remote_mirror_service.rb b/app/services/projects/update_remote_mirror_service.rb index d6c0d647468..fe2610f89fb 100644 --- a/app/services/projects/update_remote_mirror_service.rb +++ b/app/services/projects/update_remote_mirror_service.rb @@ -25,14 +25,8 @@ module Projects def update_mirror(remote_mirror) remote_mirror.update_start! - remote_mirror.ensure_remote! - # https://gitlab.com/gitlab-org/gitaly/-/issues/2670 - if Feature.disabled?(:gitaly_ruby_remote_branches_ls_remote, default_enabled: true) - repository.fetch_remote(remote_mirror.remote_name, ssh_auth: remote_mirror, no_tags: true) - end - response = remote_mirror.update_repository if response.divergent_refs.any? diff --git a/app/services/projects/update_repository_storage_service.rb b/app/services/projects/update_repository_storage_service.rb index 7b346c09635..a479d53a43a 100644 --- a/app/services/projects/update_repository_storage_service.rb +++ b/app/services/projects/update_repository_storage_service.rb @@ -6,8 +6,7 @@ module Projects SameFilesystemError = Class.new(Error) attr_reader :repository_storage_move - delegate :project, :destination_storage_name, to: :repository_storage_move - delegate :repository, to: :project + delegate :project, :source_storage_name, :destination_storage_name, to: :repository_storage_move def initialize(repository_storage_move) @repository_storage_move = repository_storage_move @@ -20,21 +19,22 @@ module Projects repository_storage_move.start! end - raise SameFilesystemError if same_filesystem?(repository.storage, destination_storage_name) + raise SameFilesystemError if same_filesystem?(source_storage_name, destination_storage_name) mirror_repositories - project.transaction do - mark_old_paths_for_archive - - repository_storage_move.finish! + repository_storage_move.transaction do + repository_storage_move.finish_replication! project.leave_pool_repository project.track_project_repository end + remove_old_paths enqueue_housekeeping + repository_storage_move.finish_cleanup! + ServiceResponse.success rescue StandardError => e @@ -91,36 +91,31 @@ module Projects end end - def mark_old_paths_for_archive - old_repository_storage = project.repository_storage - new_project_path = moved_path(project.disk_path) - - # Notice that the block passed to `run_after_commit` will run with `repository_storage_move` - # as its context - repository_storage_move.run_after_commit do - GitlabShellWorker.perform_async(:mv_repository, - old_repository_storage, - project.disk_path, - new_project_path) - - if project.wiki.repository_exists? - GitlabShellWorker.perform_async(:mv_repository, - old_repository_storage, - project.wiki.disk_path, - "#{new_project_path}.wiki") - end - - if project.design_repository.exists? - GitlabShellWorker.perform_async(:mv_repository, - old_repository_storage, - project.design_repository.disk_path, - "#{new_project_path}.design") - end + def remove_old_paths + Gitlab::Git::Repository.new( + source_storage_name, + "#{project.disk_path}.git", + nil, + nil + ).remove + + if project.wiki.repository_exists? + Gitlab::Git::Repository.new( + source_storage_name, + "#{project.wiki.disk_path}.git", + nil, + nil + ).remove end - end - def moved_path(path) - "#{path}+#{project.id}+moved+#{Time.current.to_i}" + if project.design_repository.exists? + Gitlab::Git::Repository.new( + source_storage_name, + "#{project.design_repository.disk_path}.git", + nil, + nil + ).remove + end end # The underlying FetchInternalRemote call uses a `git fetch` to move data diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb index 58c9bce963b..c9ba7cde199 100644 --- a/app/services/projects/update_service.rb +++ b/app/services/projects/update_service.rb @@ -142,7 +142,13 @@ module Projects end def update_pages_config - Projects::UpdatePagesConfigurationService.new(project).execute + return unless project.pages_deployed? + + if Feature.enabled?(:async_update_pages_config, project) + PagesUpdateConfigurationWorker.perform_async(project.id) + else + Projects::UpdatePagesConfigurationService.new(project).execute + end end def changing_pages_https_only? |