2018-11-18 11:00:15 +05:30
# frozen_string_literal: true
2014-09-02 18:07:02 +05:30
module Projects
class UpdateService < BaseService
2018-03-17 18:26:18 +05:30
include UpdateVisibilityLevel
2019-07-07 11:18:12 +05:30
include ValidatesClassificationLabel
2018-03-17 18:26:18 +05:30
2018-11-18 11:00:15 +05:30
ValidationError = Class . new ( StandardError )
2016-08-24 12:49:21 +05:30
2018-11-18 11:00:15 +05:30
def execute
2021-09-04 01:27:46 +05:30
build_topics
2019-10-12 21:52:04 +05:30
remove_unallowed_params
2023-05-27 22:25:52 +05:30
add_pages_unique_domain
2018-11-18 11:00:15 +05:30
validate!
2014-09-02 18:07:02 +05:30
2018-03-27 19:54:05 +05:30
ensure_wiki_exists if enabling_wiki?
2020-06-23 00:09:42 +05:30
if changing_repository_storage?
storage_move = project . repository_storage_moves . build (
source_storage_name : project . repository_storage ,
destination_storage_name : params . delete ( :repository_storage )
)
storage_move . schedule
2020-04-08 14:13:33 +05:30
end
2018-10-15 14:42:47 +05:30
yield if block_given?
2019-07-07 11:18:12 +05:30
validate_classification_label ( project , :external_authorization_classification_label )
2018-10-15 14:42:47 +05:30
# If the block added errors, don't try to save the project
2018-11-18 11:00:15 +05:30
return update_failed! if project . errors . any?
2017-08-17 22:00:37 +05:30
2018-11-18 11:00:15 +05:30
if project . update ( params . except ( :default_branch ) )
after_update
2018-05-09 12:01:36 +05:30
2017-08-17 22:00:37 +05:30
success
else
2018-11-18 11:00:15 +05:30
update_failed!
2014-09-02 18:07:02 +05:30
end
2018-11-18 11:00:15 +05:30
rescue ValidationError = > e
error ( e . message )
2014-09-02 18:07:02 +05:30
end
2017-09-10 17:25:29 +05:30
2018-03-17 18:26:18 +05:30
def run_auto_devops_pipeline?
2018-11-08 19:23:39 +05:30
return false if project . repository . gitlab_ci_yml || ! project . auto_devops & . previous_changes & . include? ( 'enabled' )
2017-09-10 17:25:29 +05:30
2018-11-20 20:47:30 +05:30
project . auto_devops_enabled?
2017-09-10 17:25:29 +05:30
end
2018-03-17 18:26:18 +05:30
private
2023-05-27 22:25:52 +05:30
def add_pages_unique_domain
2023-06-20 00:43:36 +05:30
if Feature . disabled? ( :pages_unique_domain , project )
2023-05-27 22:25:52 +05:30
params [ :project_setting_attributes ] & . delete ( :pages_unique_domain_enabled )
return
end
return unless params . dig ( :project_setting_attributes , :pages_unique_domain_enabled )
# If the project used a unique domain once, it'll always use the same
return if project . project_setting . pages_unique_domain_in_database . present?
params [ :project_setting_attributes ] [ :pages_unique_domain ] = Gitlab :: Pages :: RandomDomain . generate (
project_path : project . path ,
namespace_path : project . parent . full_path
)
end
2018-11-18 11:00:15 +05:30
def validate!
2021-10-29 20:43:33 +05:30
unless valid_visibility_level_change? ( project , project . visibility_attribute_value ( params ) )
2021-06-08 01:23:25 +05:30
raise ValidationError , s_ ( 'UpdateProject|New visibility level not allowed!' )
2018-11-18 11:00:15 +05:30
end
if renaming_project_with_container_registry_tags?
2021-06-08 01:23:25 +05:30
raise ValidationError , s_ ( 'UpdateProject|Cannot rename project because it contains container registry tags!' )
2018-11-18 11:00:15 +05:30
end
2021-03-11 19:13:27 +05:30
validate_default_branch_change
end
def validate_default_branch_change
return unless changing_default_branch?
previous_default_branch = project . default_branch
2023-03-04 22:38:38 +05:30
new_default_branch = params [ :default_branch ]
2021-03-11 19:13:27 +05:30
2023-03-04 22:38:38 +05:30
if project . change_head ( new_default_branch )
2021-09-30 23:02:18 +05:30
params [ :previous_default_branch ] = previous_default_branch
2023-03-04 22:38:38 +05:30
if ! project . root_ref? ( new_default_branch ) && has_custom_head_branch?
raise ValidationError ,
format (
s_ ( " UpdateProject|Could not set the default branch. Do you have a branch named 'HEAD' in your repository? (%{linkStart}How do I fix this?%{linkEnd}) " ) ,
linkStart : ambiguous_head_documentation_link , linkEnd : '</a>'
) . html_safe
end
2021-03-11 19:13:27 +05:30
after_default_branch_change ( previous_default_branch )
else
2021-06-08 01:23:25 +05:30
raise ValidationError , s_ ( " UpdateProject|Could not set the default branch " )
2018-11-18 11:00:15 +05:30
end
end
2023-03-04 22:38:38 +05:30
def ambiguous_head_documentation_link
url = Rails . application . routes . url_helpers . help_page_path ( 'user/project/repository/branches/index.md' , anchor : 'error-ambiguous-head-branch-exists' )
format ( '<a href="%{url}" target="_blank" rel="noopener noreferrer">' , url : url )
end
# See issue: https://gitlab.com/gitlab-org/gitlab/-/issues/381731
def has_custom_head_branch?
project . repository . branch_names . any? { | name | name . casecmp ( 'head' ) == 0 }
end
2021-03-11 19:13:27 +05:30
def after_default_branch_change ( previous_default_branch )
# overridden by EE module
end
2019-10-12 21:52:04 +05:30
def remove_unallowed_params
params . delete ( :emails_disabled ) unless can? ( current_user , :set_emails_disabled , project )
2023-06-20 00:43:36 +05:30
params . delete ( :runner_registration_enabled ) if Gitlab :: CurrentSettings . valid_runner_registrars . exclude? ( 'project' )
2019-10-12 21:52:04 +05:30
end
2018-11-18 11:00:15 +05:30
def after_update
todos_features_changes = %w(
issues_access_level
merge_requests_access_level
repository_access_level
)
project_changed_feature_keys = project . project_feature . previous_changes . keys
2020-01-01 13:55:28 +05:30
if project . visibility_level_previous_changes && project . private?
2018-11-18 11:00:15 +05:30
# don't enqueue immediately to prevent todos removal in case of a mistake
2019-09-04 21:01:54 +05:30
TodosDestroyer :: ConfidentialIssueWorker . perform_in ( Todo :: WAIT_FOR_DELETE , nil , project . id )
2019-01-03 12:48:30 +05:30
TodosDestroyer :: ProjectPrivateWorker . perform_in ( Todo :: WAIT_FOR_DELETE , project . id )
2018-11-18 11:00:15 +05:30
elsif ( project_changed_feature_keys & todos_features_changes ) . present?
2019-01-03 12:48:30 +05:30
TodosDestroyer :: PrivateFeaturesWorker . perform_in ( Todo :: WAIT_FOR_DELETE , project . id )
2018-11-18 11:00:15 +05:30
end
if project . previous_changes . include? ( 'path' )
2019-03-02 22:35:43 +05:30
after_rename_service ( project ) . execute
2018-11-18 11:00:15 +05:30
else
system_hook_service . execute_hooks_for ( project , :update )
end
2021-11-18 22:05:49 +05:30
update_pending_builds if runners_settings_toggled?
2022-08-27 11:52:29 +05:30
2022-11-25 23:54:43 +05:30
publish_events
2018-12-05 23:21:45 +05:30
end
2019-03-02 22:35:43 +05:30
def after_rename_service ( project )
2019-07-31 22:56:46 +05:30
AfterRenameService . new ( project , path_before : project . path_before_last_save , full_path_before : project . full_path_before_last_save )
2019-03-02 22:35:43 +05:30
end
2018-11-18 11:00:15 +05:30
def update_failed!
2018-10-15 14:42:47 +05:30
model_errors = project . errors . full_messages . to_sentence
2019-07-31 22:56:46 +05:30
error_message = model_errors . presence || s_ ( 'UpdateProject|Project could not be updated!' )
2018-10-15 14:42:47 +05:30
error ( error_message )
end
2017-09-10 17:25:29 +05:30
def renaming_project_with_container_registry_tags?
new_path = params [ :path ]
new_path && new_path != project . path &&
project . has_container_registry_tags?
end
def changing_default_branch?
new_branch = params [ :default_branch ]
2018-11-08 19:23:39 +05:30
new_branch && project . repository . exists? &&
new_branch != project . default_branch
2017-09-10 17:25:29 +05:30
end
2018-03-27 19:54:05 +05:30
def enabling_wiki?
2018-11-18 11:00:15 +05:30
return false if project . wiki_enabled?
2018-03-27 19:54:05 +05:30
params . dig ( :project_feature_attributes , :wiki_access_level ) . to_i > ProjectFeature :: DISABLED
end
def ensure_wiki_exists
2020-11-24 15:15:51 +05:30
return if project . create_wiki
2018-03-27 19:54:05 +05:30
log_error ( " Could not create wiki for #{ project . full_name } " )
2019-10-12 21:52:04 +05:30
Gitlab :: Metrics . counter ( :wiki_can_not_be_created_total , 'Counts the times we failed to create a wiki' ) . increment
2018-03-27 19:54:05 +05:30
end
2018-05-09 12:01:36 +05:30
2020-06-23 00:09:42 +05:30
def changing_repository_storage?
2020-04-08 14:13:33 +05:30
new_repository_storage = params [ :repository_storage ]
new_repository_storage && project . repository . exists? &&
2020-06-23 00:09:42 +05:30
project . repository_storage != new_repository_storage &&
2020-04-08 14:13:33 +05:30
can? ( current_user , :change_repository_storage , project )
end
2021-09-04 01:27:46 +05:30
def build_topics
topics = params . delete ( :topics )
tag_list = params . delete ( :tag_list )
topic_list = topics || tag_list
params [ :topic_list ] || = topic_list if topic_list
end
2021-11-11 11:23:49 +05:30
def update_pending_builds
2021-11-18 22:05:49 +05:30
update_params = {
instance_runners_enabled : project . shared_runners_enabled? ,
namespace_traversal_ids : group_runner_traversal_ids
}
2021-11-11 11:23:49 +05:30
2021-11-18 22:05:49 +05:30
:: Ci :: UpdatePendingBuildService
. new ( project , update_params )
. execute
2021-11-11 11:23:49 +05:30
end
2021-11-18 22:05:49 +05:30
def shared_runners_settings_toggled?
project . previous_changes . include? ( :shared_runners_enabled )
end
def group_runners_settings_toggled?
return false unless project . ci_cd_settings . present?
project . ci_cd_settings . previous_changes . include? ( :group_runners_enabled )
end
def runners_settings_toggled?
shared_runners_settings_toggled? || group_runners_settings_toggled?
end
def group_runner_traversal_ids
if project . group_runners_enabled?
project . namespace . traversal_ids
else
[ ]
end
2021-11-11 11:23:49 +05:30
end
2022-08-27 11:52:29 +05:30
2022-11-25 23:54:43 +05:30
def publish_events
publish_project_archived_event
publish_project_attributed_changed_event
publish_project_features_changed_event
end
def publish_project_archived_event
2022-08-27 11:52:29 +05:30
return unless project . archived_previously_changed?
event = Projects :: ProjectArchivedEvent . new ( data : {
project_id : @project . id ,
namespace_id : @project . namespace_id ,
root_namespace_id : @project . root_namespace . id
} )
Gitlab :: EventStore . publish ( event )
end
2022-11-25 23:54:43 +05:30
def publish_project_attributed_changed_event
changes = @project . previous_changes
return if changes . blank?
event = Projects :: ProjectAttributesChangedEvent . new ( data : {
project_id : @project . id ,
namespace_id : @project . namespace_id ,
root_namespace_id : @project . root_namespace . id ,
attributes : changes . keys
} )
Gitlab :: EventStore . publish ( event )
end
def publish_project_features_changed_event
changes = @project . project_feature . previous_changes
return if changes . blank?
event = Projects :: ProjectFeaturesChangedEvent . new ( data : {
project_id : @project . id ,
namespace_id : @project . namespace_id ,
root_namespace_id : @project . root_namespace . id ,
features : changes . keys
} )
Gitlab :: EventStore . publish ( event )
end
2014-09-02 18:07:02 +05:30
end
end
2019-12-04 20:38:33 +05:30
2021-06-08 01:23:25 +05:30
Projects :: UpdateService . prepend_mod_with ( 'Projects::UpdateService' )