Commit f1a40767 authored by Kerri Miller's avatar Kerri Miller

Merge branch 'al-325685-add-spent-time-update' into 'master'

New service to add spent time to MRs

See merge request gitlab-org/gitlab!60043
parents 937ea2f3 a30dfddc
# frozen_string_literal: true
module MergeRequests
class AddSpentTimeService < UpdateService
def execute(merge_request)
old_associations = { total_time_spent: merge_request.total_time_spent }
merge_request.spend_time(params[:spend_time])
merge_request_saved = merge_request.with_transaction_returning_status do
merge_request.save
end
if merge_request_saved
create_system_notes(merge_request)
# track usage
track_time_spend_edits(merge_request, old_associations[:total_time_spent])
execute_hooks(merge_request, 'update', old_associations: old_associations)
end
merge_request
end
private
def track_time_spend_edits(merge_request, old_total_time_spent)
if old_total_time_spent != merge_request.total_time_spent
merge_request_activity_counter.track_time_spent_changed_action(user: current_user)
end
end
end
end
......@@ -295,6 +295,8 @@ module MergeRequests
case attribute
when :assignee_ids
assignees_service.execute(merge_request)
when :spend_time
add_time_spent_service.execute(merge_request)
else
nil
end
......@@ -304,6 +306,10 @@ module MergeRequests
@assignees_service ||= ::MergeRequests::UpdateAssigneesService
.new(project, current_user, params)
end
def add_time_spent_service
@add_time_spent_service ||= ::MergeRequests::AddSpentTimeService.new(project, current_user, params)
end
end
end
......
---
title: Add new service to handle add_spent_time to MRs
merge_request: 60043
author:
type: performance
......@@ -85,10 +85,15 @@ module API
post ":id/#{issuable_collection_name}/:#{issuable_key}/add_spent_time" do
authorize! admin_issuable_key, load_issuable
update_issuable(spend_time: {
update_params = {
spend_time: {
duration: Gitlab::TimeTrackingFormatter.parse(params.delete(:duration)),
user_id: current_user.id
})
}
}
update_params[:use_specialized_service] = true if issuable_name == 'merge_request'
update_issuable(update_params)
end
desc "Reset spent time for a project #{issuable_name}"
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe MergeRequests::AddSpentTimeService do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public, :repository) }
let_it_be_with_reload(:merge_request) { create(:merge_request, :simple, :unique_branches, source_project: project) }
let(:duration) { 1500 }
let(:params) { { spend_time: { duration: duration, user_id: user.id } } }
let(:service) { described_class.new(project, user, params) }
describe '#execute' do
before do
project.add_developer(user)
end
it 'creates a new timelog with the specified duration' do
expect { service.execute(merge_request) }.to change { Timelog.count }.from(0).to(1)
timelog = merge_request.timelogs.last
expect(timelog).not_to be_nil
expect(timelog.time_spent).to eq(1500)
end
it 'creates a system note with the time added' do
expect { service.execute(merge_request) }.to change { Note.count }.from(0).to(1)
system_note = merge_request.notes.last
expect(system_note).not_to be_nil
expect(system_note.note_html).to include('added 25m of time spent')
end
it 'saves usage data' do
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
.to receive(:track_time_spent_changed_action).once.with(user: user)
service.execute(merge_request)
end
it 'is more efficient than using the full update-service' do
other_mr = create(:merge_request, :simple, :unique_branches, source_project: project)
update_service = ::MergeRequests::UpdateService.new(project, user, params)
other_mr.reload
expect { service.execute(merge_request) }
.to issue_fewer_queries_than { update_service.execute(other_mr) }
end
context 'when duration is nil' do
let(:duration) { nil }
it 'does not create a timelog with the specified duration' do
expect { service.execute(merge_request) }.not_to change { Timelog.count }
expect(merge_request).not_to be_valid
end
end
end
end
......@@ -1052,6 +1052,35 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
end
end
context 'when adding time spent' do
let(:spend_time) { { duration: 1800, user_id: user3.id } }
context ':use_specialized_service' do
context 'when true' do
it 'passes the update action to ::MergeRequests::AddSpentTimeService' do
expect(::MergeRequests::AddSpentTimeService)
.to receive(:new).and_call_original
update_merge_request(spend_time: spend_time, use_specialized_service: true)
end
end
context 'when false or nil' do
before do
expect(::MergeRequests::AddSpentTimeService).not_to receive(:new)
end
it 'does not pass the update action to ::MergeRequests::UpdateAssigneesService when false' do
update_merge_request(spend_time: spend_time, use_specialized_service: false)
end
it 'does not pass the update action to ::MergeRequests::UpdateAssigneesService when nil' do
update_merge_request(spend_time: spend_time, use_specialized_service: nil)
end
end
end
end
include_examples 'issuable update service' do
let(:open_issuable) { merge_request }
let(:closed_issuable) { create(:closed_merge_request, source_project: project) }
......
......@@ -125,6 +125,22 @@ RSpec.shared_examples 'time tracking endpoints' do |issuable_name|
expect(json_response['message']['base'].first).to eq(_('Time to subtract exceeds the total time spent'))
end
end
if issuable_name == 'merge_request'
it 'calls update service with :use_specialized_service param' do
expect(::MergeRequests::UpdateService).to receive(:new).with(project, user, hash_including(use_specialized_service: true))
post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user), params: { duration: '2h' }
end
end
if issuable_name == 'issue'
it 'calls update service without :use_specialized_service param' do
expect(::Issues::UpdateService).to receive(:new).with(project, user, hash_not_including(use_specialized_service: true))
post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user), params: { duration: '2h' }
end
end
end
describe "POST /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/reset_spent_time" do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment