diff options
Diffstat (limited to 'app/services/issues')
-rw-r--r-- | app/services/issues/base_service.rb | 31 | ||||
-rw-r--r-- | app/services/issues/close_service.rb | 1 | ||||
-rw-r--r-- | app/services/issues/create_service.rb | 16 | ||||
-rw-r--r-- | app/services/issues/duplicate_service.rb | 9 | ||||
-rw-r--r-- | app/services/issues/move_service.rb | 14 | ||||
-rw-r--r-- | app/services/issues/related_branches_service.rb | 2 | ||||
-rw-r--r-- | app/services/issues/reopen_service.rb | 1 | ||||
-rw-r--r-- | app/services/issues/update_service.rb | 4 | ||||
-rw-r--r-- | app/services/issues/zoom_link_service.rb | 1 |
9 files changed, 68 insertions, 11 deletions
diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb index 9e72f6dad8d..0ed2b08b7b1 100644 --- a/app/services/issues/base_service.rb +++ b/app/services/issues/base_service.rb @@ -2,6 +2,8 @@ module Issues class BaseService < ::IssuableBaseService + include IncidentManagement::UsageData + def hook_data(issue, action, old_associations: {}) hook_data = issue.to_hook_data(current_user, old_associations: old_associations) hook_data[:object_attributes][:action] = action @@ -17,6 +19,19 @@ module Issues Issues::CloseService end + NO_REBALANCING_NEEDED = ((RelativePositioning::MIN_POSITION * 0.9999)..(RelativePositioning::MAX_POSITION * 0.9999)).freeze + + def rebalance_if_needed(issue) + return unless issue + return if issue.relative_position.nil? + return if NO_REBALANCING_NEEDED.cover?(issue.relative_position) + + gates = [issue.project, issue.project.group].compact + return unless gates.any? { |gate| Feature.enabled?(:rebalance_issues, gate) } + + IssueRebalancingWorker.perform_async(nil, issue.project_id) + end + private def create_assignee_note(issue, old_assignees) @@ -46,6 +61,22 @@ module Issues Milestones::IssuesCountService.new(milestone).delete_cache end + + # Applies label "incident" (creates it if missing) to incident issues. + # Please use in "after" hooks only to ensure we are not appyling + # labels prematurely. + def add_incident_label(issue) + return unless issue.incident? + + label = ::IncidentManagement::CreateIncidentLabelService + .new(project, current_user) + .execute + .payload[:label] + + return if issue.label_ids.include?(label.id) + + issue.labels << label + end end end diff --git a/app/services/issues/close_service.rb b/app/services/issues/close_service.rb index e431c766df8..c3677de015f 100644 --- a/app/services/issues/close_service.rb +++ b/app/services/issues/close_service.rb @@ -37,6 +37,7 @@ module Issues execute_hooks(issue, 'close') invalidate_cache_counts(issue, users: issue.assignees) issue.update_project_counter_caches + track_incident_action(current_user, issue, :incident_closed) store_first_mentioned_in_commit_at(issue, closed_via) if closed_via.is_a?(MergeRequest) diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb index c0194f5b847..fb7683f940d 100644 --- a/app/services/issues/create_service.rb +++ b/app/services/issues/create_service.rb @@ -5,31 +5,33 @@ module Issues include SpamCheckMethods include ResolveDiscussions - def execute + def execute(skip_system_notes: false) @issue = BuildService.new(project, current_user, params).execute filter_spam_check_params filter_resolve_discussion_params - create(@issue) + create(@issue, skip_system_notes: skip_system_notes) end def before_create(issue) spam_check(issue, current_user, action: :create) - issue.move_to_end # current_user (defined in BaseService) is not available within run_after_commit block user = current_user issue.run_after_commit do NewIssueWorker.perform_async(issue.id, user.id) + IssuePlacementWorker.perform_async(nil, issue.project_id) end end - def after_create(issuable) - todo_service.new_issue(issuable, current_user) + def after_create(issue) + add_incident_label(issue) + todo_service.new_issue(issue, current_user) user_agent_detail_service.create - resolve_discussions_with_issue(issuable) - delete_milestone_total_issue_counter_cache(issuable.milestone) + resolve_discussions_with_issue(issue) + delete_milestone_total_issue_counter_cache(issue.milestone) + track_incident_action(current_user, issue, :incident_created) super end diff --git a/app/services/issues/duplicate_service.rb b/app/services/issues/duplicate_service.rb index c936d75e277..feb496542c8 100644 --- a/app/services/issues/duplicate_service.rb +++ b/app/services/issues/duplicate_service.rb @@ -12,6 +12,8 @@ module Issues close_service.new(project, current_user, {}).execute(duplicate_issue) duplicate_issue.update(duplicated_to: canonical_issue) + + relate_two_issues(duplicate_issue, canonical_issue) end private @@ -23,7 +25,10 @@ module Issues def create_issue_canonical_note(canonical_issue, duplicate_issue) SystemNoteService.mark_canonical_issue_of_duplicate(canonical_issue, canonical_issue.project, current_user, duplicate_issue) end + + def relate_two_issues(duplicate_issue, canonical_issue) + params = { target_issuable: canonical_issue } + IssueLinks::CreateService.new(duplicate_issue, current_user, params).execute + end end end - -Issues::DuplicateService.prepend_if_ee('EE::Issues::DuplicateService') diff --git a/app/services/issues/move_service.rb b/app/services/issues/move_service.rb index ce1466307e1..60e0d1eec3d 100644 --- a/app/services/issues/move_service.rb +++ b/app/services/issues/move_service.rb @@ -38,6 +38,7 @@ module Issues def update_old_entity super + rewrite_related_issues mark_as_moved end @@ -51,13 +52,24 @@ module Issues } new_params = original_entity.serializable_hash.symbolize_keys.merge(new_params) - CreateService.new(@target_project, @current_user, new_params).execute + + # Skip creation of system notes for existing attributes of the issue. The system notes of the old + # issue are copied over so we don't want to end up with duplicate notes. + CreateService.new(@target_project, @current_user, new_params).execute(skip_system_notes: true) end def mark_as_moved original_entity.update(moved_to: new_entity) end + def rewrite_related_issues + source_issue_links = IssueLink.for_source_issue(original_entity) + source_issue_links.update_all(source_id: new_entity.id) + + target_issue_links = IssueLink.for_target_issue(original_entity) + target_issue_links.update_all(target_id: new_entity.id) + end + def notify_participants notification_service.async.issue_moved(original_entity, new_entity, @current_user) end diff --git a/app/services/issues/related_branches_service.rb b/app/services/issues/related_branches_service.rb index 46076218857..98d8412102f 100644 --- a/app/services/issues/related_branches_service.rb +++ b/app/services/issues/related_branches_service.rb @@ -24,7 +24,7 @@ module Issues return unless target - pipeline = project.pipeline_for(branch_name, target.sha) + pipeline = project.latest_pipeline(branch_name, target.sha) pipeline.detailed_status(current_user) if can?(current_user, :read_pipeline, pipeline) end diff --git a/app/services/issues/reopen_service.rb b/app/services/issues/reopen_service.rb index 0ffe33dd317..e2b1b5400c7 100644 --- a/app/services/issues/reopen_service.rb +++ b/app/services/issues/reopen_service.rb @@ -13,6 +13,7 @@ module Issues invalidate_cache_counts(issue, users: issue.assignees) issue.update_project_counter_caches delete_milestone_closed_issue_counter_cache(issue.milestone) + track_incident_action(current_user, issue, :incident_reopened) end issue diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb index ac7baba3b7c..ce21b2e0275 100644 --- a/app/services/issues/update_service.rb +++ b/app/services/issues/update_service.rb @@ -22,6 +22,7 @@ module Issues end def after_update(issue) + add_incident_label(issue) IssuesChannel.broadcast_to(issue, event: 'updated') if Gitlab::ActionCable::Config.in_app? || Feature.enabled?(:broadcast_issue_updates, issue.project) end @@ -44,12 +45,14 @@ module Issues create_assignee_note(issue, old_assignees) notification_service.async.reassigned_issue(issue, current_user, old_assignees) todo_service.reassigned_assignable(issue, current_user, old_assignees) + track_incident_action(current_user, issue, :incident_assigned) end if issue.previous_changes.include?('confidential') # don't enqueue immediately to prevent todos removal in case of a mistake TodosDestroyer::ConfidentialIssueWorker.perform_in(Todo::WAIT_FOR_DELETE, issue.id) if issue.confidential? create_confidentiality_note(issue) + track_usage_event(:incident_management_incident_change_confidential, current_user.id) end added_labels = issue.labels - old_labels @@ -83,6 +86,7 @@ module Issues raise ActiveRecord::RecordNotFound unless issue_before || issue_after issue.move_between(issue_before, issue_after) + rebalance_if_needed(issue) end # rubocop: disable CodeReuse/ActiveRecord diff --git a/app/services/issues/zoom_link_service.rb b/app/services/issues/zoom_link_service.rb index 9572cf50564..1384e2f83b2 100644 --- a/app/services/issues/zoom_link_service.rb +++ b/app/services/issues/zoom_link_service.rb @@ -60,6 +60,7 @@ module Issues if @issue.persisted? # Save the meeting directly since we only want to update one meeting, not all zoom_meeting.save + track_incident_action(current_user, issue, :incident_zoom_meeting) success(message: _('Zoom meeting added')) else success(message: _('Zoom meeting added'), payload: { zoom_meetings: [zoom_meeting] }) |