Skip resolved-thread note when discussion already resolved

What does this MR do and why?

Calling PUT /projects/:id/merge_requests/:merge_request_iid/discussions/:discussion_id?resolved=true against a discussion that is already resolved created a new "resolved all threads" system note on the merge request, even though nothing changed on the discussion. Repeating the call produced one duplicate note per call.

Discussions::ResolveService#resolve_discussion called discussion.resolve! and then ran MergeRequests::ResolvedDiscussionNotificationService unconditionally — which posts the note whenever the MR's discussions are all resolved, with no check that this call is what resolved them. discussion.resolve! itself is a no-op when already resolved, but the notification still fired.

This MR records whether the discussion was newly resolved by the call, and only tracks the usage counter and runs the notification when it was. An already-resolved resolve is now a true no-op: no counter, no notification, no system note. Behaviour is unchanged when the call actually resolves the discussion.

Only API callers can reach this path — the UI renders "Unresolve" on an already-resolved thread — but that path is increasingly common as tooling drives the API directly.

Closes #628395.

How to validate locally

bin/rspec spec/services/discussions/resolve_service_spec.rb

The new context asserts that resolving an already-resolved discussion does not run the notification service, does not track the usage counter, and adds no new note to the merge request.

Merge request reports

Loading
Loading