Draft: [skip ci] Search subgroup milestones in basic group search
What does this MR do and why?
Basic (non-Elasticsearch) group-level milestone search now returns group milestones from the searched group and its subgroups. It no longer returns group milestones from ancestor groups.
In Gitlab::GroupSearchResults#filter_milestones_by_group, group milestones now come from group.self_and_descendants instead of group.self_and_ancestors. This applies to both the archived and non-archived branches. non_archived still excludes a group when it or an ancestor is archived.
Project milestones are unchanged. They already came from projects in the group and its subgroups (Search::GroupService#projects uses for_group_and_its_subgroups).
Example: searching Group A, which has subgroup Group B and parent Group P.
| Milestones of | Before | After |
|---|---|---|
| Group A | yes | yes |
| Group B (subgroup) | no | yes |
| Group P (parent) | yes | no |
| Projects in A and B | yes | yes |
Project-level basic search is unchanged. It still includes the milestones of the project's group and ancestor groups, because a project can use those milestones.
Why change the scope
Searching a group should find what is in it. The new scope matches the rest of the product:
- The group milestones page uses
self_and_descendants(Groups::MilestonesController#group_ids). It only adds ancestors for the JSON milestone picker, where an ancestor's milestone can be assigned. - Group-level work items in basic search use
include_descendants: true, include_ancestors: false(EE::Gitlab::GroupSearchResults#work_items). - Project milestones from subgroup projects were already in the results, so group milestones from subgroups were the odd one out.
- Advanced search scopes group milestones the same way in !260603.
Impact on the MCP use case
The ancestor scope came from https://gitlab.com/gitlab-org/gitlab/-/work_items/589711 (commit d634d98e). That change was driven by the gitlab_search MCP tool and /api/v4/search?scope=milestones.
After this MR, an agent searching in a subgroup for a milestone to assign no longer gets ancestor group milestones. It needs to search the ancestor group instead.
The author of https://gitlab.com/gitlab-org/gitlab/-/work_items/589711 should confirm this is fine for the MCP use case.
Database
The group list now comes from self_and_descendants instead of self_and_ancestors. It can be larger for groups with many subgroups. A database reviewer should look at the query. Query plans will follow.
Spec
In spec/lib/gitlab/group_search_results_spec.rb, the example includes milestones from ancestor groups is replaced. The new example uses a parent / searched group / subgroup hierarchy, with projects in the searched group and in the subgroup. It expects the milestones of the searched group, the subgroup and both projects, and not the parent's. It fails on the old code (subgroup missing, parent present).
References
Screenshots or screen recordings
Not applicable. There is no UI change, only the content of the results list.
| Before | After |
|---|---|
How to set up and validate locally
This is basic search, so Advanced Search must be disabled or the search type forced to basic.
- Create the groups Group P > Group A > Group B.
- Add a milestone to each group, all named e.g.
release. - Search milestones in Group A:
/search?group_id=<A id>&scope=milestones&search=release&search_type=basic - Expect the milestones of Group A and Group B. Do not expect the milestone of Group P.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.