Delete each resource through the project it belongs to
What does this MR do and why?
With --source groups, a rule with delete: true on issues or merge requests sends the DELETE to the group instead of to the project each resource belongs to. Action::Delete#build_delete_url passes the --source-id value as the project, so --source groups --source-id my-group/subgroup produces DELETE /api/v4/projects/my-group%2Fsubgroup/issues/42. A group's path is never a project's path, so GitLab answers 404 and nothing is deleted, and the run reports nothing, because the REST adapter raises only on 401, 429 and 500 and the action does not look at the response. A numeric group ID is read as a project ID instead, so the DELETE goes to whichever project has that ID. --all-projects has no source ID at all, and the URL comes out as /projects//issues/42.
I made the delete action take the project from the resource's project_id, which is what the comment and update actions already use to build their URLs. Branches carry no project_id, so they keep using --source-id. The issue suggests checking the policy type first; reading resource[policy.source_id_sym] with that fallback gives the same result here, because the action only deletes branches, issues and merge requests, and it is the same lookup the other two actions make.
One change is visible with a project source: when --source-id is a path, the URL now names the project by the ID GitLab returned with the issue or merge request (/projects/123/issues/42 instead of /projects/my-group%2Fmy-project/issues/42). Both address the same project, and it is the project ID the comment action already puts in its URL for the same resource.
The second commit comes from review: the dry run now prints the URL each DELETE would request, built as the real run builds it, instead of the resource's type and iid, which printed the same line for two issues with the same iid in two projects of a group. It has its own Changelog: changed trailer, since it changes what a dry run prints.
Tests:
spec/gitlab/triage/action/delete_spec.rb: a group source for issues and for merge requests,--all-projects, and a project source given by its path. The existing examples, whose resources carry noproject_id, are unchanged and still take--source-id. A dry run over two issues with iid 1 in two projects of a group expects one URL for each project.spec/integration/delete_group_resources_spec.rb: runs the engine with--source groups --source-id my-group/subgroupagainst two issues, and then two merge requests, that share an iid in two projects of the group, and expects one DELETE in each project.
The new specs without the fix, and the checks with it
On master at deb07caa, with master's delete.rb, bundle exec rspec spec/gitlab/triage/action/delete_spec.rb spec/integration/delete_group_resources_spec.rb spec/integration/delete_issues_spec.rb on Ruby 3.2.11 (WebMock's message trimmed to the request):
Unregistered request: DELETE http://test.com/api/v4/projects/my-group%2Fsubgroup/issues/42
Unregistered request: DELETE http://test.com/api/v4/projects/my-group%2Fsubgroup/merge_requests/99
Unregistered request: DELETE http://test.com/api/v4/projects//issues/42
Unregistered request: DELETE http://test.com/api/v4/projects/my-group%2Fmy-project/issues/42
Unregistered request: DELETE https://gitlab.com/api/v4/projects/my-group%2Fsubgroup/issues/1
Unregistered request: DELETE https://gitlab.com/api/v4/projects/my-group%2Fsubgroup/merge_requests/1
13 examples, 7 failuresThe seven failures are the seven new examples: the six above, and the dry run, which printed DELETE resource with type: issues and id: 1 for both issues. The six existing ones (four in delete_spec.rb, two in delete_issues_spec.rb) pass. With the first commit's delete.rb, the dry run is the only failure.
With both commits, on the same master:
bundle exec rake spec: 1079 examples, 0 failures on Ruby 3.0.7, 3.1.7, 3.2.4, 3.2.11 and 3.3.12; the first commit on its own, 1078 examples, 0 failures on Ruby 3.2.11.bundle exec rubocop --parallel: 215 files inspected, no offenses detected (Ruby 3.2.4 and 3.2.11).
Closes #401 (closed)