Traversal ids queries
What does this MR do?
Closes #230456 (closed)
Currently to query the namespace hierarchy we must use recursive methods through Gitlab::ObjectHierarchy
. We can query the namespace hierarchy a lot faster and easier if we store the path from the root ancestor to each namespace as an attribute on the namespace. We will store this on a new traversal_id
attribute on Namespaces
.
Say we have this Namespace hierarchy...
graph TD;
gitlab-->backend;
backend-->create;
backend-->manage;
create-->source;
manage-->access;
gitlab-->frontend;
Then the path from gitlab
to access
is gitlab / backend / manage / access
. The path from gitlab
to source
is gitlab / backend / create / source
.
We can use this structure for fast queries. If the current namespace is backend
then all our descendants match the path gitlab / backend / *
, all our ancestors match the path * / backend
, and everyone in the same Namespace hierarchy matches gitlab / *
.
We store that path using an array of Namespace ids in a new column on Namespace called traversal_ids
.
The recursive Namespace query methods have been moved to a module at app/models/concerns/namespace/recursive_traversal.rb
. Feature flags have been included to toggle between using recursive and linear querying methods.
Screenshots
Does this MR meet the acceptance criteria?
Conformity
-
Changelog entry -
Documentation (if required) -
Code review guidelines -
Merge request performance guidelines -
Style guides -
Database guides -
Separation of EE specific content
Availability and Testing
-
Review and add/update tests for this feature/bug. Consider all test levels. See the Test Planning Process. -
Tested in all supported browsers -
Informed Infrastructure department of a default or new setting change, if applicable per definition of done
Security
If this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in the security review guidelines:
-
Label as security and @ mention @gitlab-com/gl-security/appsec
-
The MR includes necessary changes to maintain consistency between UI, API, email, or other methods -
Security reports checked/validated by a reviewer from the AppSec team
Merge request reports
Activity
Hi @alexpooley,
Please add labels to your merge request, this helps triage community merge requests.
Thanks for your help!
You are welcome to help improve this comment.
added auto updated label
added backend label
3 Warnings This merge request is quite big (more than 737 lines changed), please consider splitting it into multiple merge requests. This merge request does not refer to an existing milestone. This MR has a Changelog file outside ee/
, but code changes inee/
. Consider moving the Changelog file intoee/
.1 Message This merge request adds or changes files that require a review from the Database team. This merge request requires a database review. To make sure these changes are reviewed, take the following steps:
- Ensure the merge request has database and databasereview pending labels. If the merge request modifies database files, Danger will do this for you.
- Prepare your MR for database review according to the docs.
- Assign and mention the database reviewer suggested by Reviewer Roulette.
The following files require a review from the Database team:
db/migrate/20200618070630_add_namespace_traversal_ids_index.rb
db/schema_migrations/20200618070630
db/structure.sql
Reviewer roulette
Changes that require review have been detected! A merge request is normally reviewed by both a reviewer and a maintainer in its primary category (e.g. frontend or backend), and by a maintainer in all other categories.
To spread load more evenly across eligible reviewers, Danger has picked a candidate for each review slot, based on their timezone. Feel free to override these selections if you think someone else would be better-suited, or the chosen person is unavailable.
To read more on how to use the reviewer roulette, please take a look at the Engineering workflow and code review guidelines. Please consider assigning a reviewer or maintainer who is a domain expert in the area of the merge request.
Once you've decided who will review this merge request, mention them as you normally would! Danger does not automatically notify them for you.
Category Reviewer Maintainer backend Michał Zając ( @quintasan
) (UTC+2, 6 hours behind@alexpooley
)Sean McGivern ( @smcgivern
) (UTC+1, 7 hours behind@alexpooley
)database Patrick Bair ( @pbair
) (UTC-4, 12 hours behind@alexpooley
)Tiger Watson ( @tigerwnz
) (UTC+11, 3 hours ahead of@alexpooley
)If needed, you can retry the
danger-review
job that generated this comment.Generated by
DangerEdited by 🤖 GitLab Bot 🤖mentioned in merge request !35713 (merged)
added 90 commits
- 7a7c5e19 - Define a namespace traversal cache
- 6aa022b0 - Remove unused apollo configuration
- 18a41e17 - Swimlanes - Detailed popover for epics
- 0b49d1cb - Add issue column to alert list
- a254d2de - Alert list issue link - docs
- c5d26e73 - Add create project milestone spec
- 87ff317a - Use consistent spacing with yaml arrays in docs
- 0e33a34d - Provide working artifacts:expose_as examples
- da3353ab - Fix incorrect Package File progress bar total count
- e43d4923 - Update pipeline security tab filter label and docs
- 6aaf25f2 - Add link to Merge request references in emails
- d1822cb6 - Apply 1 suggestion(s) to 1 file(s)
- 2bee1e3d - Add helper method to generate reference link
- 1f13c53a - Remove service desk license checks
- c74e613e - Ignore removed queues in danger sidekiq_queues
- 4f2f2e19 - Make `gitlab:elastic:index` enable `elasticsearch_indexing`
- 9f629a39 - Add NOT param support to Merge Requests API
- a64e498f - Remove mixin from recommended approach in docs
- 3a1c8b52 - Raise error when non-dangling builds use YAML blob
- 099ddd0e - Add MergeRequests::ApprovalService to CE
- 5442ed00 - Fix missing `Rspec.describe`
- f4a31ff8 - Improve translations for Alert Management assignees
- 9bf144e5 - Rolling 28 day time period counter for deployments
- eb2a9309 - Replace create with build_stubbed in user validations
- 32b348da - Move qa selector to dropdown_class
- 8dc6f689 - Resolve timeout in admin/jobs
- 40f9d30f - Quarantine a flaky spec
- 9c1bf36b - Remove unused method UserAccess#can_read_project?
- 75f09a80 - Use S3 Workhorse client with consolidated object store settings
- ff790f40 - Return ID for newly created vulnerability issue links
- d56eb19a - Track failures in usage ping payload
- 4ba12cc7 - Minor UI fixes for Issue page in dark mode
- 603ce322 - Change alert severity sort order
- 44268f99 - Add FORCE_GITLAB_CI to default-refs
- 299423d8 - Use percentage for chart loader
- d932fd43 - Remove old feature flag for policy list
- bcf67ab7 - First pass at implementing design
- 6e926591 - Add in feature flag logic and fix alignment
- 89c90d92 - Add unit tests with feature flag for license compliance vue
- 10f4c814 - Rework feature flag logic
- 07c16c08 - Update styles, regenerate translations
- fda152c9 - Unit test feedback
- 83f57dca - Clean up unit tests
- 150b7073 - Fix typo in unit test
- aa8e0802 - Apply maintainer feedback
- 2220c6b6 - Fix usage graph not exceeding 100%
- bca89743 - Memoize the source_branch_exists method for a MR
- 85539f24 - Remove check for >9.6 for Geo
- c42b78d8 - Remove onboarding tour
- b69a5122 - Update doc to include squash commits options
- 4e8464a3 - Add version for new features
- e3241a54 - Add note about SSH key title being public information
- f20ad6b2 - Update GitLab Runner Helm Chart to 0.18.1
- 21655d06 - Add comments to public methods of ProxyVariableSubstitutionService
- ece23f43 - Replacing Font-Awesome Icons
- a38d2211 - Fix archived parameter for Group API's projects endpoint
- 02cf6c4d - Update list_item component with details slots
- c9035925 - Allow cloning of all out of the box dashboards
- 774e00be - Geo: Replicate delete event of Package Files
- 6d38bc5d - Project import rake task on Omnibus, plus errors
- 15a26c29 - Remove commit message 50 character soft limit
- 83cf86b8 - Sync translations for 06/2020
- f545bf00 - Fetch system notes when changing assignee
- 4a450592 - Remove GitLab pages custom CA workaround
- ae6074d8 - Include inapplicable_reason in API response
- 84edbd30 - Remove button row from environments empty state
- 9befdc68 - MR diff migration: perform I/O outside of database transaction
- 06cebf47 - Docs: adding a note about bypassing pgbouncer during restore
- e8899021 - Add additional changelog for ee
- 65c7afb6 - Remove tempfile from external diff creation
- 63718c10 - Replace `.html` with `.md` in `help_page_link` helpers
- 6f92eae6 - Add issues_enabled column to jira_tracker_data table
- 58c66f74 - Display commits search in mobile & adjust text
- ef9f07c2 - Prevent autosave when reply comment via cmd+enter
- a8cfaa21 - Address reviewer's comments
- 36f00614 - Use yamllint Docker image that is maintained
- a2b4fb07 - Link to documentation in Jira app
- 88669d6e - Update GitLab Elasticsearch Indexer
- 498adf97 - Database migration for caching has_confluence
- 59cd8d4c - Implement GraphQL query for SAST Config UI
- 9d573793 - Create new metrics dashboard path
- f3a27145 - Add changelog entry
- b01c1e7e - Allow dashboard paths in route
- 784c77df - Clean up specs
- 259d561c - Clean up controller
- 50f8a357 - Apply 1 suggestion(s) to 1 file(s)
- ee460b19 - Change action name and fix code styling
- 9e988a99 - Change route and add comments
- 23e861d4 - Configurable defaults for "Squash commits" option
- 65eee4e0 - wip
Toggle commit listadded database databasereview pending labels
Bundle size analysis [beta]
This compares changes in bundle size for entry points between the commits 0e335a91 and 8d5e2f73
Special assetsEntrypoint / Name Size before Size after Diff Diff in percent average 2.89 MB 2.89 MB - 0.0 % mainChunk 1.9 MB 1.9 MB - 0.0 %
Please look at the full report for more details
Read more about how this report works.
Generated by
DangerEdited by 🤖 GitLab Bot 🤖added 626 commits
-
65eee4e0...ce8dd2f5 - 625 commits from branch
traversal-hierarchy
- 78475dcf - wip
-
65eee4e0...ce8dd2f5 - 625 commits from branch
mentioned in merge request !35846 (closed)
mentioned in merge request !35833 (merged)
Could you confirm that efficient
root_ancestor
lookup is only needed for the feature flag check?On slack, I proposed a different approach which assumes that calculating
traversal_ids
on namespace update is not going to be a problem from performance POV (no need forsync_linear_group_traversal
FF).Release 1:
- Always keep traversal_ids in sync (I think this won't be too heavy since groups are not changed that often:
saved_change_to_parent
) - Kick off BG migrations to update traversal_ids for all groups
At this point we can start double checking the impact of the new column on GL.com (PRD console) and proceed with the query changes.
Release 2:
- Update the queries and keep
linear_groups
feature flag checks. - At this point getting the root namespace should be easy, since
traversal_ids
are in sync.
Note: If the Ruby based sync solution is not efficient enough, we could explore a trigger based solution later on.
- Always keep traversal_ids in sync (I think this won't be too heavy since groups are not changed that often:
- Resolved by Alex Pooley
Could you confirm that efficient
root_ancestor
lookup is only needed for the feature flag check?Yes, correct.
On slack, I proposed a different approach
Thanks, I have been pondering your Slack comment. My primary concern is what happens if we have to disable the FFs after we have enabled. Maybe we have to disable because it's slow, or we are storing invalid
traversal_ids
... I think the FF enable case as you have laid out is fine.The plan is to dogfood with gitlab-com or gitlab-data first just to be safe, so the plan will be amended slightly to what you have detailed.
I agree that the sync code impact will be minimal. I want to add some specs around what happens if we disable the
linear_groups
FF but sync continues to be sure we don't implode. Thetraversal_ids
content won't be trustworthy at this point. Provided the root ancestor doesn't change then we should be fine. I think that's a fine assumption for the lifespan of the FF.
- Resolved by Alex Pooley
added 2944 commits
-
3891c215...fa954f34 - 2944 commits from branch
traversal-hierarchy
-
3891c215...fa954f34 - 2944 commits from branch
added 289 commits
-
fa954f34...72a4673b - 288 commits from branch
master
- aee51862 - wip
-
fa954f34...72a4673b - 288 commits from branch
@ahegyi I've completely reworked the queries. I'm really happy how they look now. They are a lot cleaner and don't depend on the object's copy of the
traversal_ids
attribute.If you have the capacity can you please take a look?
I've moved the recursive
Namespace
traversal methods toapp/models/concerns/namespace/recursive_traversal.rb
which will eventually be superseded when we remove the feature flags.assigned to @ahegyi
- Resolved by Alex Pooley
Sure, I'll take a look.
Do you already have an MR for the data migration? It would be nice to see how much space the index needs and do some perf comparison.
In the meantime I'll try to migrate all namespaces in a database lab instance, it'll take a while.
CREATE OR REPLACE FUNCTION array_reverse(anyarray) RETURNS anyarray AS $$ SELECT ARRAY( SELECT $1[i] FROM generate_series( array_lower($1,1), array_upper($1,1) ) AS s(i) ORDER BY i DESC ); $$ LANGUAGE 'sql' STRICT IMMUTABLE;
WITH namespaces_with_traversal_ids AS (SELECT outer_namespaces.id, array_reverse(array_agg(all_namespaces.id)) AS traversal_ids FROM (SELECT * FROM namespaces) AS outer_namespaces INNER JOIN LATERAL (WITH RECURSIVE "base_and_ancestors" AS ( (SELECT "namespaces".* FROM "namespaces" WHERE "namespaces"."id" = outer_namespaces.id) UNION (SELECT "namespaces".* FROM "namespaces", "base_and_ancestors" WHERE "namespaces"."id" = "base_and_ancestors"."parent_id")) SELECT "namespaces".* FROM "base_and_ancestors" AS "namespaces") all_namespaces ON TRUE GROUP BY 1) UPDATE namespaces SET traversal_ids = namespaces_with_traversal_ids.traversal_ids FROM namespaces_with_traversal_ids WHERE namespaces.id = namespaces_with_traversal_ids.id
- Resolved by Alex Pooley
Test with
base_and_descendants
.Generated query
SELECT "namespaces".* FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND (traversal_ids <@ (SELECT traversal_ids AS latest_traversal_ids FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" = 9970))
Notice the bitmap index scan. The timings are unfortunately worse than our current recursive approach.
If we remove the
Group
conditions we get better execution times: https://explain.depesz.com/s/uKjsComparing it with our current recursive solution:
WITH RECURSIVE "base_and_descendants" AS ( (SELECT "namespaces".* FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" = 9970) UNION (SELECT "namespaces".* FROM "namespaces", "base_and_descendants" WHERE "namespaces"."type" = 'Group' AND "namespaces"."parent_id" = "base_and_descendants"."id")) SELECT "namespaces".* FROM "base_and_descendants" AS "namespaces"
0.5ms (new) vs 3ms (old).
Edited by Adam Hegyi
added 602 commits
-
d4937601...81fb0963 - 601 commits from branch
master
- 910b2d76 - wip
-
d4937601...81fb0963 - 601 commits from branch
mentioned in issue #233070 (closed)
- Resolved by Alex Pooley
@alexpooley, feel free to assign the MR back to me when it's ready for another review round!
unassigned @ahegyi
added 727 commits
-
cae814f1...61dbcf87 - 726 commits from branch
master
- 4c5b3e64 - wip
-
cae814f1...61dbcf87 - 726 commits from branch
mentioned in issue #233297 (closed)
mentioned in issue #233298 (closed)
There is a bug in the use of feature flags in specs. I'm working on a merge request to fix that problem, which may delay this MR. FWIW I think this one is pretty much done.
mentioned in merge request !38659 (merged)
added 1661 commits
-
f080dd19...54ce3a2e - 1660 commits from branch
master
- 6de72752 - wip
-
f080dd19...54ce3a2e - 1660 commits from branch
added featureaddition typefeature labels
mentioned in issue #235935
mentioned in issue #235936
assigned to @ahegyi
- Resolved by Adam Hegyi
- Resolved by Alex Pooley
- Resolved by Adam Hegyi
- Resolved by Adam Hegyi
added sectiondev label
added 571 commits
-
8346bcac...9e404d35 - 570 commits from branch
master
- 544ea884 - Linear Namespace querying methods
-
8346bcac...9e404d35 - 570 commits from branch
cc @jprovaznik for visibility. This MR relates to discussions we have had around performance and complexity of group queries.
added 244 commits
-
544ea884...b07a1923 - 243 commits from branch
master
- 3ac88a44 - Linear Namespace querying methods
-
544ea884...b07a1923 - 243 commits from branch
- Resolved by Alex Pooley
- Resolved by Alex Pooley
- Resolved by Alex Pooley
- Resolved by Alex Pooley
Thanks @alexpooley,
Left a question about the sorting. I'll try to set up DB lab to verify the performance again.
mentioned in epic &4257 (closed)
assigned to @morefice
- Resolved by Alex Pooley
- Resolved by Alex Pooley
- Resolved by Alex Pooley
- Resolved by Alex Pooley
- Resolved by Alex Pooley
- Resolved by Alex Pooley
unassigned @morefice
- Resolved by Alex Pooley
- Resolved by Alex Pooley
mentioned in issue #244282 (closed)
added 2609 commits
-
81844741...afec9e8d - 2608 commits from branch
master
- 3d194e3e - Linear Namespace querying methods
-
81844741...afec9e8d - 2608 commits from branch
assigned to @morefice
mentioned in issue #243753 (closed)
mentioned in issue #229918 (closed)
- app/models/concerns/namespace/traversal.rb 0 → 100644
34 # We implement this in the database using Postgresql arrays, indexed by a 35 # generalized inverted index (gin). 36 class Namespace 37 module Traversal 38 extend ActiveSupport::Concern 39 40 included do 41 after_create :init_traversal_ids, if: :sync_traversal_ids? 42 after_update :sync_traversal_ids, if: -> { sync_traversal_ids? && saved_change_to_parent? } 43 44 scope :traversal_ids_contains, ->(ids) { where("traversal_ids @> (?)", ids) } 45 scope :traversal_ids_contained_by, ->(ids) { where("traversal_ids <@ (?)", ids) } 46 end 47 48 def sync_traversal_ids? 49 return false unless self.respond_to?(:traversal_ids) Currently the MR will break this spec https://gitlab.com/gitlab-org/gitlab/-/blob/master/spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb without these lines. I'm consulting Slack for guidance.
These lines should be removed. It doesn't make sense to perform a check every single request in order to appease a spec. Hopefully we can resolve soon.
Initial Slack conversation https://gitlab.slack.com/archives/C8HG8D9MY/p1599199398124400
Follow up https://gitlab.slack.com/archives/CNZ8E900G/p1599204910016900
- app/models/concerns/namespace/traversal.rb 0 → 100644
40 included do 41 after_create :init_traversal_ids, if: :sync_traversal_ids? 42 after_update :sync_traversal_ids, if: -> { sync_traversal_ids? && saved_change_to_parent? } 43 44 scope :traversal_ids_contains, ->(ids) { where("traversal_ids @> (?)", ids) } 45 scope :traversal_ids_contained_by, ->(ids) { where("traversal_ids <@ (?)", ids) } 46 end 47 48 def sync_traversal_ids? 49 return false unless self.respond_to?(:traversal_ids) 50 51 Feature.enabled?(:sync_traversal_ids, root_ancestor, default_enabled: false) 52 end 53 54 def linear_group_traversal? 55 return false unless self.respond_to?(:traversal_ids) - app/models/concerns/namespace/traversal.rb 0 → 100644
43 44 scope :traversal_ids_contains, ->(ids) { where("traversal_ids @> (?)", ids) } 45 scope :traversal_ids_contained_by, ->(ids) { where("traversal_ids <@ (?)", ids) } 46 end 47 48 def sync_traversal_ids? 49 return false unless self.respond_to?(:traversal_ids) 50 51 Feature.enabled?(:sync_traversal_ids, root_ancestor, default_enabled: false) 52 end 53 54 def linear_group_traversal? 55 return false unless self.respond_to?(:traversal_ids) 56 return false if traversal_ids.blank? 57 58 Feature.enabled?(:linear_groups, root_ancestor, default_enabled: false) - app/models/concerns/namespace/traversal.rb 0 → 100644
127 128 skope = without_sti_condition 129 130 if top 131 skope = skope.traversal_ids_contains(latest_traversal_ids(top)) 132 end 133 134 if bottom 135 skope = skope.traversal_ids_contained_by(latest_traversal_ids(bottom)) 136 end 137 138 # The original `with_depth` attribute in ObjectHierarchy increments as you 139 # walk away from the "base" namespace. This direction changes depending on 140 # if you are walking up the ancestors or down the descendants. 141 if hierarchy_order 142 depth_sql = "ABS(array_length((#{latest_traversal_ids.to_sql}), 1) - array_length(traversal_ids, 1))" The real fix is to get rid of this way of ordering the hierarchy. I've created an issue to follow up #245094
188 end 189 177 190 it 'has the correct help text with correct ancestor links' do 191 expect(subject).to match(possible_help_texts[help_text]) 192 expect(subject).to match(possible_linked_ancestors[linked_ancestor].name) unless help_text == :default_help 178 with_them do 179 before do 180 root_group.add_owner(root_owner) 181 subgroup.add_owner(sub_owner) 182 sub_subgroup.add_owner(sub_sub_owner) 183 184 root_group.update_column(:share_with_group_lock, true) if root_share_with_group_locked 185 subgroup.update_column(:share_with_group_lock, true) if subgroup_share_with_group_locked 186 sub_subgroup.update_column(:share_with_group_lock, true) if sub_subgroup_share_with_group_locked 187 188 allow(helper).to receive(:current_user).and_return(users[current_user]) Thanks for updating the description. Left some questions let me know what you think.
I'm not feeling super confident with this MR as it does a lot of things and I'm missing some context about our
Group
architecture. I trust you folks to make the right decision hereBack to you
@morefice Thanks for your efforts. Yes, it's not the easiest MR to review :(
I've responded to all queries. A couple of queries are the same problem and I'm waiting on guidance from #g_database on how to proceed. Details are in the comment.
Maybe just respond as best you can for now while we wait for resolution on that one
@morefice, I've used postgres.ai, which is the same tech like
#database-lab
. This is the thread that contains more info: !36025 (comment 387248049)Since we have a lot's of group level (recursive) queries, we didn't identify and measure each of them. We could run a comparison benchmark against our reference architecture after this MR merged (for the test, the change needs to land on
master
).Edited by Adam Hegyi
unassigned @morefice
assigned to @morefice
added databasereviewed label and removed databasereview pending label
unassigned @morefice
This MR is currently blocked by an issue with an unrelated migration spec. Discussion of the problem and proposed resolution at https://gitlab.slack.com/archives/CNZ8E900G/p1599204910016900
@alexpooley I took the liberty to rebase this MR agains master, just to be able to rebase the fix for the above mentioned blocking issue that has an MR !41893 (merged)
I am not sure how you want to proceed with this? either merge !41893 (merged) into this MR or merge this MR to master and follow-up with the fix afterwards ?
@acroitor I'm not clear on how your fix is working. Does it protect itself against future changes to the model files you use in your migration? Or is the fix specific to this MR in some way?
Can you remove the changes in your MR to
app/models/concerns/namespace/traversal.rb
and merge to master branch? makes sense. updated !41893 (merged) MR.I'm not clear on how your fix is working. Does it protect itself against future changes to the model files you use in your migration? Or is the fix specific to this MR in some way?
right, for now I've just isolated namespace/group models so that we can unblock this MR, ideally I need to also isolate User, Project and related banzai parsing classes for mentions.
mentioned in issue #217937 (closed)
mentioned in issue #246752 (closed)
mentioned in merge request !41893 (merged)
Setting label(s) devopsmanage based on ~"group::access".
added devopsmanage label
added 3267 commits
-
3c3f83ab...3810ab0f - 3266 commits from branch
master
- 9f3d0e87 - Linear Namespace querying methods
-
3c3f83ab...3810ab0f - 3266 commits from branch
mentioned in merge request !43244 (closed)
added 4399 commits
-
9f3d0e87...0e335a91 - 4398 commits from branch
master
- 8d5e2f73 - Linear Namespace querying methods
-
9f3d0e87...0e335a91 - 4398 commits from branch
mentioned in issue #260327 (closed)
mentioned in merge request !44740 (merged)
mentioned in merge request !42423 (merged)
added 823 commits
-
8d5e2f73...9d2a9f8a - 822 commits from branch
master
- 9bf51658 - Linear Namespace querying methods
-
8d5e2f73...9d2a9f8a - 822 commits from branch
added 114 commits
-
9bf51658...a7248d86 - 113 commits from branch
master
- 4fa50afb - Linear Namespace querying methods
-
9bf51658...a7248d86 - 113 commits from branch
mentioned in issue #270040 (closed)
mentioned in issue #270126
mentioned in issue gitlab-org/quality/triage-reports#751 (closed)
@alexpooley how do we move this MR forwards?
mentioned in issue #281286
mentioned in issue #259719 (closed)
mentioned in merge request !47245 (merged)
mentioned in issue gitlab-org/quality/triage-reports#953 (closed)
mentioned in issue gitlab-org/quality/triage-reports#1133 (closed)
mentioned in issue gitlab-org/quality/triage-reports#1300 (closed)
mentioned in issue gitlab-org/quality/triage-reports#1474 (closed)
mentioned in issue gitlab-org/quality/triage-reports#1624 (closed)
mentioned in issue gitlab-org/manage/general-discussion#17306
mentioned in issue #301142 (closed)
This MR is currently being split in to smaller MRs. Closing this MR as it has been superseded by &5296 (closed)
mentioned in merge request !52999 (merged)
mentioned in merge request !52854 (merged)
mentioned in epic &5296 (closed)
mentioned in merge request !56296 (merged)
mentioned in merge request !57137 (merged)
mentioned in merge request !59632 (merged)
mentioned in merge request !61163 (merged)
mentioned in merge request !61799 (merged)
mentioned in issue #385682