From 18213ae6481c701ccd794f4801d19a45d2a0df9e Mon Sep 17 00:00:00 2001 From: Kerri Miller Date: Fri, 2 Dec 2022 09:41:54 -0800 Subject: [PATCH 01/14] Initial WIP commit of new doc --- doc/development/merge_request_diffs.md | 278 +++++++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 doc/development/merge_request_diffs.md diff --git a/doc/development/merge_request_diffs.md b/doc/development/merge_request_diffs.md new file mode 100644 index 00000000000000..afc092c34ec1cc --- /dev/null +++ b/doc/development/merge_request_diffs.md @@ -0,0 +1,278 @@ +--- +stage: Create +group: Code Review +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments +--- + +# Merge Request Diffs development guide **(FREE)** + +This document explains the backend design and flow of merge request diffs. + +This should help contributors to understand the code design easier and to +identify areas for improvement through contribution. + +It's intentional that it doesn't contain too many implementation details, as they +can change often. The code should explain those things better. The components +mentioned here are the major parts of the application for how merge request diffs +are generated, stored, and returned to users. + +NOTE: +This is a living document and should be updated accordingly when parts +of the codebase touched in this document are changed or removed, or when new components +are added. + +## Data Model + +```mermaid +erDiagram + MergeRequest ||--|{ MergeRequestDiff: "" + MergeRequestDiff |{--|{ MergeRequestDiffCommit: "" + MergeRequestDiff |{--|| MergeRequestDiffDetail: "" + MergeRequestDiff |{--|{ MergeRequestDiffFile: "" + MergeRequestDiffCommit |{--|| MergeRequestDiffCommitUser: "" +``` + + +### `Project` and `MergeRequest` + +`Project` and `MergeRequest` models are defined in `ee/app/models/ee/project.rb` +and `ee/app/models/ee/merge_request.rb`. They extend the non-EE versions, because +approval rules are an EE-only feature. Associations and other related stuff to +merge request approvals are defined here. + +### `ApprovalState` + +```mermaid +erDiagram + MergeRequest ||--|| ApprovalState: " " +``` + +`ApprovalState` class is defined in `ee/app/models/approval_state.rb`. It's not +an actual `ActiveRecord` model. This class encapsulates all logic related to the +state of the approvals for a certain merge request like: + +- Knowing the approval rules that are applicable to the merge request based on + its target branch. +- Knowing the approval rules that are applicable to a certain target branch. +- Checking if all rules were approved. +- Checking if approval is required. +- Knowing how many approvals were given or still required. + +It gets the approval rules data from the project (`ApprovalProjectRule`) or the +merge request (`ApprovalMergeRequestRule`) and wrap it as `ApprovalWrappedRule`. + +### `ApprovalProjectRule` + +```mermaid +erDiagram + Project ||--o{ ApprovalProjectRule: " " + ApprovalProjectRule }o--o{ User: " " + ApprovalProjectRule }o--o{ Group: " " + ApprovalProjectRule }o--o{ ProtectedBranch: " " +``` + +`ApprovalProjectRule` model is defined in `ee/app/models/approval_project_rule.rb`. + +A record is created/updated/deleted when an approval rule is added/edited/removed +via project settings or the [project level approvals API](../api/merge_request_approvals.md#project-level-mr-approvals). +The `ApprovalState` model get these records when approval rules are not +overwritten. + +The `protected_branches` attribute is set and used when a rule is scoped to +protected branches. See [Approvals for protected branches](../user/project/merge_requests/approvals/rules.md#approvals-for-protected-branches) +for more information about the feature. + +### `ApprovalMergeRequestRule` + +```mermaid +erDiagram + MergeRequest ||--o{ ApprovalMergeRequestRule: " " + ApprovalMergeRequestRule }o--o{ User: " " + ApprovalMergeRequestRule }o--o{ Group: " " + ApprovalMergeRequestRule ||--o| ApprovalProjectRule: " " +``` + +`ApprovalMergeRequestRule` model is defined in `ee/app/models/approval_merge_request_rule.rb`. + +A record is created/updated/deleted when a rule is added/edited/removed via merge +request create/edit form or the [merge request level approvals API](../api/merge_request_approvals.md#merge-request-level-mr-approvals). + +The `approval_project_rule` is set when it is based from an existing `ApprovalProjectRule`. + +An `ApprovalMergeRequestRule` doesn't have `protected_branches` as it inherits +them from the `approval_project_rule` if not overridden. + +### `ApprovalWrappedRule` + +```mermaid +erDiagram + ApprovalState ||--o{ ApprovalWrappedRule: " " +``` + +`ApprovalWrappedRule` is defined in `ee/app/modes/approval_wrapped_rule.rb` and +is not an `ActiveRecord` model. It's used to wrap an `ApprovalProjectRule` or +`ApprovalMergeRequestRule` for common interface. It also has the following sub +types: + +- `ApprovalWrappedAnyApprovalRule` - for wrapping an `any_approver` rule. +- `ApprovalWrappedCodeOwnerRule` - for wrapping a `code_owner` rule. + +This class delegates most of the responsibilities to the approval rule it wraps +but it's also responsible for: + +- Checking if the approval rule is approved. +- Knowing how many approvals were given or still required for the approval rule. + +It gets this information from the approval rule and the `Approval` records from +the merge request. + +### `Approval` + +```mermaid +erDiagram + MergeRequest ||--o{ Approval: " " +``` + +`Approval` model is defined in `ee/app/models/approval.rb`. This model is +responsible for storing information about an approval made on a merge request. +Whenever an approval is given/revoked, a record is created/deleted. + +## Controllers and Services + +The following controllers and services below are being used for the approval +rules feature to work. + +### `API::ProjectApprovalSettings` + +This private API is defined in `ee/lib/api/project_approval_settings.rb`. + +This is used for the following: + +- Listing the approval rules in project settings. +- Creating/updating/deleting rules in project settings. +- Listing the approval rules on create merge request form. + +### `Projects::MergeRequests::CreationsController` + +This controller is defined in `app/controllers/projects/merge_requests/creations_controller.rb`. + +The `create` action of this controller is used when create merge request form is +submitted. It accepts the `approval_rules_attributes` parameter for creating/updating/deleting +`ApprovalMergeRequestRule` records. It passes the parameter along when it executes +`MergeRequests::CreateService`. + +### `Projects::MergeRequestsController` + +This controller is defined in `app/controllers/projects/merge_requests_controller.rb`. + +The `update` action of this controller is used when edit merge request form is +submitted. It's like `Projects::MergeRequests::CreationsController` but it executes +`MergeRequests::UpdateService` instead. + +### `API::MergeRequestApprovals` + +This API is defined in `ee/lib/api/merge_request_approvals.rb`. + +The [Approvals API endpoint](../api/merge_request_approvals.md#get-configuration-1) +is requested when merge request page loads. + +The `/projects/:id/merge_requests/:merge_request_iid/approval_settings` is a +private API endpoint used for the following: + +- Listing the approval rules on edit merge request form. +- Listing the approval rules on the merge request page. + +When approving/unapproving MR via UI and API, the [Approve Merge Request](../api/merge_request_approvals.md#approve-merge-request) +API endpoint and the [Unapprove Merge Request](../api/merge_request_approvals.md#unapprove-merge-request) +API endpoint are requested. They execute `MergeRequests::ApprovalService` and +`MergeRequests::RemoveApprovalService` accordingly. + +### `API::ProjectApprovalRules` and `API::MergeRequestApprovalRules` + +These APIs are defined in `ee/lib/api/project_approval_rules.rb` and +`ee/lib/api/merge_request_approval_rules.rb`. + +Used to list/create/update/delete project and merge request level rules via +[Merge request approvals API](../api/merge_request_approvals.md). + +Executes `ApprovalRules::CreateService`, `ApprovalRules::UpdateService`, +`ApprovalRules::ProjectRuleDestroyService`, and `ApprovalRules::MergeRequestRuleDestroyService` +accordingly. + +### `ApprovalRules::ParamsFilteringService` + +This service is defined in `ee/app/services/approval_rules/params_filtering_service.rb`. + +It is called only when `MergeRequests::CreateService` and +`MergeRequests::UpdateService` are executed. + +It is responsible for parsing `approval_rules_attributes` parameter to: + +- Remove it when user can't update approval rules. +- Filter the user IDs whether they are members of the project or not. +- Filter the group IDs whether they are visible to user. +- Identify the `any_approver` rule. +- Append hidden groups to it when specified. +- Append user defined inapplicable (rules that does not apply to MR's target + branch) approval rules. + +## Flow + +These flowcharts should help explain the flow from the controllers down to the +models for different functionalities. + +Some CRUD API endpoints are intentionally skipped because they are pretty +straightforward. + +### Creating a merge request with approval rules via web UI + +```mermaid +graph LR + Projects::MergeRequests::CreationsController --> MergeRequests::CreateService + MergeRequests::CreateService --> ApprovalRules::ParamsFilteringService + ApprovalRules::ParamsFilteringService --> MergeRequests::CreateService + MergeRequests::CreateService --> MergeRequest + MergeRequest --> db[(Database)] + MergeRequest --> User + MergeRequest --> Group + MergeRequest --> ApprovalProjectRule + User --> db[(Database)] + Group --> db[(Database)] + ApprovalProjectRule --> db[(Database)] +``` + +When updating, same flow is followed but it starts at `Projects::MergeRequestsController` +and executes `MergeRequests::UpdateService` instead. + +### Viewing the merge request approval rules on an MR page + +```mermaid +graph LR + API::MergeRequestApprovals --> MergeRequest + MergeRequest --> ApprovalState + ApprovalState --> id1{approval rules are overridden} + id1{approval rules are overridden} --> |No| ApprovalProjectRule & ApprovalMergeRequestRule + id1{approval rules are overridden} --> |Yes| ApprovalMergeRequestRule + ApprovalState --> ApprovalWrappedRule + ApprovalWrappedRule --> Approval +``` + +This flow gets initiated by the frontend component. The data returned is +used to display information on the MR widget. + +### Approving a merge request + +```mermaid +graph LR + API::MergeRequestApprovals --> MergeRequests::ApprovalService + MergeRequests::ApprovalService --> Approval + Approval --> db[(Database)] +``` + +When unapproving, same flow is followed but the `MergeRequests::RemoveApprovalService` +is executed instead. + +## TODO + +1. Add information related to other rule types, such as `code_owner` and `report_approver`. +1. Add information about side effects of approving/unapproving merge request. -- GitLab From 023e7a44d7ac976cfd57e7b6357b1f844567c0e9 Mon Sep 17 00:00:00 2001 From: Kerri Miller Date: Fri, 2 Dec 2022 12:09:02 -0800 Subject: [PATCH 02/14] Adds data model details and removes placeholders --- doc/development/merge_request_diffs.md | 319 +++++++------------------ 1 file changed, 91 insertions(+), 228 deletions(-) diff --git a/doc/development/merge_request_diffs.md b/doc/development/merge_request_diffs.md index afc092c34ec1cc..f005cb0a56de76 100644 --- a/doc/development/merge_request_diffs.md +++ b/doc/development/merge_request_diffs.md @@ -33,246 +33,109 @@ erDiagram ``` -### `Project` and `MergeRequest` - -`Project` and `MergeRequest` models are defined in `ee/app/models/ee/project.rb` -and `ee/app/models/ee/merge_request.rb`. They extend the non-EE versions, because -approval rules are an EE-only feature. Associations and other related stuff to -merge request approvals are defined here. - -### `ApprovalState` - -```mermaid -erDiagram - MergeRequest ||--|| ApprovalState: " " -``` - -`ApprovalState` class is defined in `ee/app/models/approval_state.rb`. It's not -an actual `ActiveRecord` model. This class encapsulates all logic related to the -state of the approvals for a certain merge request like: - -- Knowing the approval rules that are applicable to the merge request based on - its target branch. -- Knowing the approval rules that are applicable to a certain target branch. -- Checking if all rules were approved. -- Checking if approval is required. -- Knowing how many approvals were given or still required. - -It gets the approval rules data from the project (`ApprovalProjectRule`) or the -merge request (`ApprovalMergeRequestRule`) and wrap it as `ApprovalWrappedRule`. - -### `ApprovalProjectRule` - -```mermaid -erDiagram - Project ||--o{ ApprovalProjectRule: " " - ApprovalProjectRule }o--o{ User: " " - ApprovalProjectRule }o--o{ Group: " " - ApprovalProjectRule }o--o{ ProtectedBranch: " " -``` - -`ApprovalProjectRule` model is defined in `ee/app/models/approval_project_rule.rb`. - -A record is created/updated/deleted when an approval rule is added/edited/removed -via project settings or the [project level approvals API](../api/merge_request_approvals.md#project-level-mr-approvals). -The `ApprovalState` model get these records when approval rules are not -overwritten. - -The `protected_branches` attribute is set and used when a rule is scoped to -protected branches. See [Approvals for protected branches](../user/project/merge_requests/approvals/rules.md#approvals-for-protected-branches) -for more information about the feature. - -### `ApprovalMergeRequestRule` - -```mermaid -erDiagram - MergeRequest ||--o{ ApprovalMergeRequestRule: " " - ApprovalMergeRequestRule }o--o{ User: " " - ApprovalMergeRequestRule }o--o{ Group: " " - ApprovalMergeRequestRule ||--o| ApprovalProjectRule: " " +### `MergeRequestDiff` +`MergeRequestDiff` is defined in `app/models/merge_request_diff.rb`. This +class holds metadata and context related to the the diff resulting from a set of +commits. It defines methods that are the primary means for interacting with diff +contents, individual commits, and the files containing changes. + +```ruby +# ``` -`ApprovalMergeRequestRule` model is defined in `ee/app/models/approval_merge_request_rule.rb`. - -A record is created/updated/deleted when a rule is added/edited/removed via merge -request create/edit form or the [merge request level approvals API](../api/merge_request_approvals.md#merge-request-level-mr-approvals). - -The `approval_project_rule` is set when it is based from an existing `ApprovalProjectRule`. - -An `ApprovalMergeRequestRule` doesn't have `protected_branches` as it inherits -them from the `approval_project_rule` if not overridden. - -### `ApprovalWrappedRule` - -```mermaid -erDiagram - ApprovalState ||--o{ ApprovalWrappedRule: " " +Diff content is usually accessed through this class, as logic is often applied +to diff, file, and commit content before it is returned to a user. + +### `MergeRequestDiffCommit` +`MergeRequestDiffCommit` is defined in `app/models/merge_request_diff_commit.rb`. +This class corresponds to a single commit contained in it's corresponding `MergeRequestDiff` +and holds header information about the commit. + +```ruby +#\n", + trailers: {}, + commit_author_id: 19, + committer_id: 19> ``` -`ApprovalWrappedRule` is defined in `ee/app/modes/approval_wrapped_rule.rb` and -is not an `ActiveRecord` model. It's used to wrap an `ApprovalProjectRule` or -`ApprovalMergeRequestRule` for common interface. It also has the following sub -types: - -- `ApprovalWrappedAnyApprovalRule` - for wrapping an `any_approver` rule. -- `ApprovalWrappedCodeOwnerRule` - for wrapping a `code_owner` rule. +Every `MergeRequestDiffCommit` has a corresponding `MergeRequest::DiffCommitUser` +record it `:belongs_to` (in ActiveRecord parlance.) These are the `:commit_author` +and the `:committer` records, as they could be distinct individuals. -This class delegates most of the responsibilities to the approval rule it wraps -but it's also responsible for: +### `MergeRequest::DiffCommitUser` +`MergeRequest::DiffCommitUser` is defined in `app/models/merge_request/diff_commit_user.rb`. +It captures the `name` and `email` of a given commit, but contains no connection +itself to any `User` records. -- Checking if the approval rule is approved. -- Knowing how many approvals were given or still required for the approval rule. - -It gets this information from the approval rule and the `Approval` records from -the merge request. - -### `Approval` - -```mermaid -erDiagram - MergeRequest ||--o{ Approval: " " +```ruby +# ``` -`Approval` model is defined in `ee/app/models/approval.rb`. This model is -responsible for storing information about an approval made on a merge request. -Whenever an approval is given/revoked, a record is created/deleted. - -## Controllers and Services - -The following controllers and services below are being used for the approval -rules feature to work. - -### `API::ProjectApprovalSettings` - -This private API is defined in `ee/lib/api/project_approval_settings.rb`. - -This is used for the following: - -- Listing the approval rules in project settings. -- Creating/updating/deleting rules in project settings. -- Listing the approval rules on create merge request form. - -### `Projects::MergeRequests::CreationsController` - -This controller is defined in `app/controllers/projects/merge_requests/creations_controller.rb`. - -The `create` action of this controller is used when create merge request form is -submitted. It accepts the `approval_rules_attributes` parameter for creating/updating/deleting -`ApprovalMergeRequestRule` records. It passes the parameter along when it executes -`MergeRequests::CreateService`. - -### `Projects::MergeRequestsController` - -This controller is defined in `app/controllers/projects/merge_requests_controller.rb`. - -The `update` action of this controller is used when edit merge request form is -submitted. It's like `Projects::MergeRequests::CreationsController` but it executes -`MergeRequests::UpdateService` instead. - -### `API::MergeRequestApprovals` - -This API is defined in `ee/lib/api/merge_request_approvals.rb`. - -The [Approvals API endpoint](../api/merge_request_approvals.md#get-configuration-1) -is requested when merge request page loads. - -The `/projects/:id/merge_requests/:merge_request_iid/approval_settings` is a -private API endpoint used for the following: - -- Listing the approval rules on edit merge request form. -- Listing the approval rules on the merge request page. - -When approving/unapproving MR via UI and API, the [Approve Merge Request](../api/merge_request_approvals.md#approve-merge-request) -API endpoint and the [Unapprove Merge Request](../api/merge_request_approvals.md#unapprove-merge-request) -API endpoint are requested. They execute `MergeRequests::ApprovalService` and -`MergeRequests::RemoveApprovalService` accordingly. - -### `API::ProjectApprovalRules` and `API::MergeRequestApprovalRules` - -These APIs are defined in `ee/lib/api/project_approval_rules.rb` and -`ee/lib/api/merge_request_approval_rules.rb`. - -Used to list/create/update/delete project and merge request level rules via -[Merge request approvals API](../api/merge_request_approvals.md). - -Executes `ApprovalRules::CreateService`, `ApprovalRules::UpdateService`, -`ApprovalRules::ProjectRuleDestroyService`, and `ApprovalRules::MergeRequestRuleDestroyService` -accordingly. - -### `ApprovalRules::ParamsFilteringService` - -This service is defined in `ee/app/services/approval_rules/params_filtering_service.rb`. - -It is called only when `MergeRequests::CreateService` and -`MergeRequests::UpdateService` are executed. - -It is responsible for parsing `approval_rules_attributes` parameter to: - -- Remove it when user can't update approval rules. -- Filter the user IDs whether they are members of the project or not. -- Filter the group IDs whether they are visible to user. -- Identify the `any_approver` rule. -- Append hidden groups to it when specified. -- Append user defined inapplicable (rules that does not apply to MR's target - branch) approval rules. +### `MergeRequestDiffFile` +`MergeRequestDiffFile` is defined in `app/models/merge_request_diff_file.rb`. +This record of this class represents the diff of a single file contained in the +`MergeRequestDiff`. It holds both meta and specific information about the file's +relationship to the change, such as whether it is added or renamed, it's ordering +within the diff, as well as the raw diff output itself. + + +### `MergeRequestDiffDetail` +`MergeRequestDiffDetail` is defined in `app/models/merge_request_diff_detail.rb`. +This class provides verification information for Geo replication, but otherwise +is not used for user-facing diffs. + +```ruby +# + ``` ## Flow These flowcharts should help explain the flow from the controllers down to the -models for different functionalities. - -Some CRUD API endpoints are intentionally skipped because they are pretty -straightforward. - -### Creating a merge request with approval rules via web UI - -```mermaid -graph LR - Projects::MergeRequests::CreationsController --> MergeRequests::CreateService - MergeRequests::CreateService --> ApprovalRules::ParamsFilteringService - ApprovalRules::ParamsFilteringService --> MergeRequests::CreateService - MergeRequests::CreateService --> MergeRequest - MergeRequest --> db[(Database)] - MergeRequest --> User - MergeRequest --> Group - MergeRequest --> ApprovalProjectRule - User --> db[(Database)] - Group --> db[(Database)] - ApprovalProjectRule --> db[(Database)] -``` - -When updating, same flow is followed but it starts at `Projects::MergeRequestsController` -and executes `MergeRequests::UpdateService` instead. - -### Viewing the merge request approval rules on an MR page - -```mermaid -graph LR - API::MergeRequestApprovals --> MergeRequest - MergeRequest --> ApprovalState - ApprovalState --> id1{approval rules are overridden} - id1{approval rules are overridden} --> |No| ApprovalProjectRule & ApprovalMergeRequestRule - id1{approval rules are overridden} --> |Yes| ApprovalMergeRequestRule - ApprovalState --> ApprovalWrappedRule - ApprovalWrappedRule --> Approval -``` - -This flow gets initiated by the frontend component. The data returned is -used to display information on the MR widget. - -### Approving a merge request - -```mermaid -graph LR - API::MergeRequestApprovals --> MergeRequests::ApprovalService - MergeRequests::ApprovalService --> Approval - Approval --> db[(Database)] -``` +models for different functionalities. This is not intended to document the entirety +of options for access and working with diffs, focusing solely on the most common. -When unapproving, same flow is followed but the `MergeRequests::RemoveApprovalService` -is executed instead. +### `batch_diffs.json` -## TODO +This -1. Add information related to other rule types, such as `code_owner` and `report_approver`. -1. Add information about side effects of approving/unapproving merge request. -- GitLab From 82b5197cfb279a32f7f2004b4f2b4e7784cc0dea Mon Sep 17 00:00:00 2001 From: Kerri Miller Date: Mon, 5 Dec 2022 14:43:50 -0800 Subject: [PATCH 03/14] Add small intro for batch_diffs.json --- doc/development/merge_request_diffs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/development/merge_request_diffs.md b/doc/development/merge_request_diffs.md index f005cb0a56de76..1a7227739ae3fa 100644 --- a/doc/development/merge_request_diffs.md +++ b/doc/development/merge_request_diffs.md @@ -137,5 +137,5 @@ of options for access and working with diffs, focusing solely on the most common ### `batch_diffs.json` -This +The most common avenue for viewing diffs is through the web UI and the "Changes" tab found in the top navigation bar of merge request pages. When selected, the diffs themselves are loaded via a paginated request to `/-/merge_requests/:id/diffs_batch.json`, which is served by [`Projects::MergeRequests::DiffsController#diffs_batch`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/controllers/projects/merge_requests/diffs_controller.rb), -- GitLab From 24baadea589aa5ccac134ec1a2f2be919f2debd0 Mon Sep 17 00:00:00 2001 From: Kerri Miller Date: Mon, 5 Dec 2022 14:47:06 -0800 Subject: [PATCH 04/14] Add blurb about data model --- doc/development/merge_request_diffs.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/development/merge_request_diffs.md b/doc/development/merge_request_diffs.md index 1a7227739ae3fa..905db7e69067b1 100644 --- a/doc/development/merge_request_diffs.md +++ b/doc/development/merge_request_diffs.md @@ -23,6 +23,13 @@ are added. ## Data Model +There are 4 main ActiveRecord models that represent what we collectively refer to +as "diffs." They are database-backed records that replicate data contained in the +project's git repository, and are in part a cache against excessive access requests +to [Gitaly](). Additionally, they provide a logical place for calculated and retrieved +metadata about the pieces of the diff, as well as general class- and instance-based +logic. + ```mermaid erDiagram MergeRequest ||--|{ MergeRequestDiff: "" -- GitLab From 4a2e595873e811cb07f5e7133713b34d11ebd272 Mon Sep 17 00:00:00 2001 From: Kerri Miller Date: Mon, 5 Dec 2022 14:47:30 -0800 Subject: [PATCH 05/14] Formatting changes --- doc/development/merge_request_diffs.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/development/merge_request_diffs.md b/doc/development/merge_request_diffs.md index 905db7e69067b1..4ab89eecc59fe7 100644 --- a/doc/development/merge_request_diffs.md +++ b/doc/development/merge_request_diffs.md @@ -144,5 +144,8 @@ of options for access and working with diffs, focusing solely on the most common ### `batch_diffs.json` -The most common avenue for viewing diffs is through the web UI and the "Changes" tab found in the top navigation bar of merge request pages. When selected, the diffs themselves are loaded via a paginated request to `/-/merge_requests/:id/diffs_batch.json`, which is served by [`Projects::MergeRequests::DiffsController#diffs_batch`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/controllers/projects/merge_requests/diffs_controller.rb), +The most common avenue for viewing diffs is through the web UI and the "Changes" +tab found in the top navigation bar of merge request pages. When selected, the +diffs themselves are loaded via a paginated request to `/-/merge_requests/:id/diffs_batch.json`, +which is served by [`Projects::MergeRequests::DiffsController#diffs_batch`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/controllers/projects/merge_requests/diffs_controller.rb), -- GitLab From df23925f5a76fa53957a9034c9d452ae7ac5d921 Mon Sep 17 00:00:00 2001 From: Kerri Miller Date: Mon, 5 Dec 2022 15:15:12 -0800 Subject: [PATCH 06/14] Markdown linting --- doc/development/merge_request_diffs.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/doc/development/merge_request_diffs.md b/doc/development/merge_request_diffs.md index 4ab89eecc59fe7..33d3d2a70f808c 100644 --- a/doc/development/merge_request_diffs.md +++ b/doc/development/merge_request_diffs.md @@ -25,8 +25,8 @@ are added. There are 4 main ActiveRecord models that represent what we collectively refer to as "diffs." They are database-backed records that replicate data contained in the -project's git repository, and are in part a cache against excessive access requests -to [Gitaly](). Additionally, they provide a logical place for calculated and retrieved +project's Git repository, and are in part a cache against excessive access requests +to [Gitaly](../). Additionally, they provide a logical place for calculated and retrieved metadata about the pieces of the diff, as well as general class- and instance-based logic. @@ -39,8 +39,8 @@ erDiagram MergeRequestDiffCommit |{--|| MergeRequestDiffCommitUser: "" ``` - ### `MergeRequestDiff` + `MergeRequestDiff` is defined in `app/models/merge_request_diff.rb`. This class holds metadata and context related to the the diff resulting from a set of commits. It defines methods that are the primary means for interacting with diff @@ -71,6 +71,7 @@ Diff content is usually accessed through this class, as logic is often applied to diff, file, and commit content before it is returned to a user. ### `MergeRequestDiffCommit` + `MergeRequestDiffCommit` is defined in `app/models/merge_request_diff_commit.rb`. This class corresponds to a single commit contained in it's corresponding `MergeRequestDiff` and holds header information about the commit. @@ -93,6 +94,7 @@ record it `:belongs_to` (in ActiveRecord parlance.) These are the `:commit_autho and the `:committer` records, as they could be distinct individuals. ### `MergeRequest::DiffCommitUser` + `MergeRequest::DiffCommitUser` is defined in `app/models/merge_request/diff_commit_user.rb`. It captures the `name` and `email` of a given commit, but contains no connection itself to any `User` records. @@ -105,14 +107,15 @@ itself to any `User` records. ``` ### `MergeRequestDiffFile` + `MergeRequestDiffFile` is defined in `app/models/merge_request_diff_file.rb`. This record of this class represents the diff of a single file contained in the `MergeRequestDiff`. It holds both meta and specific information about the file's relationship to the change, such as whether it is added or renamed, it's ordering within the diff, as well as the raw diff output itself. - ### `MergeRequestDiffDetail` + `MergeRequestDiffDetail` is defined in `app/models/merge_request_diff_detail.rb`. This class provides verification information for Geo replication, but otherwise is not used for user-facing diffs. @@ -148,4 +151,3 @@ The most common avenue for viewing diffs is through the web UI and the "Changes" tab found in the top navigation bar of merge request pages. When selected, the diffs themselves are loaded via a paginated request to `/-/merge_requests/:id/diffs_batch.json`, which is served by [`Projects::MergeRequests::DiffsController#diffs_batch`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/controllers/projects/merge_requests/diffs_controller.rb), - -- GitLab From 2c757700347150665a4ca4be973200fa53dff8cd Mon Sep 17 00:00:00 2001 From: Kerri Miller Date: Tue, 6 Dec 2022 08:59:39 -0800 Subject: [PATCH 07/14] Link to gitaly.md --- doc/development/merge_request_diffs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/development/merge_request_diffs.md b/doc/development/merge_request_diffs.md index 33d3d2a70f808c..4177ed61a192b5 100644 --- a/doc/development/merge_request_diffs.md +++ b/doc/development/merge_request_diffs.md @@ -26,7 +26,7 @@ are added. There are 4 main ActiveRecord models that represent what we collectively refer to as "diffs." They are database-backed records that replicate data contained in the project's Git repository, and are in part a cache against excessive access requests -to [Gitaly](../). Additionally, they provide a logical place for calculated and retrieved +to [Gitaly](gitaly.md). Additionally, they provide a logical place for calculated and retrieved metadata about the pieces of the diff, as well as general class- and instance-based logic. -- GitLab From 565315d9db88b60e0225456b5db28a7a4a64c805 Mon Sep 17 00:00:00 2001 From: Kerri Miller Date: Tue, 6 Dec 2022 08:59:52 -0800 Subject: [PATCH 08/14] Remove doubled word typo --- doc/development/merge_request_diffs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/development/merge_request_diffs.md b/doc/development/merge_request_diffs.md index 4177ed61a192b5..743476ca73a1d8 100644 --- a/doc/development/merge_request_diffs.md +++ b/doc/development/merge_request_diffs.md @@ -42,7 +42,7 @@ erDiagram ### `MergeRequestDiff` `MergeRequestDiff` is defined in `app/models/merge_request_diff.rb`. This -class holds metadata and context related to the the diff resulting from a set of +class holds metadata and context related to the diff resulting from a set of commits. It defines methods that are the primary means for interacting with diff contents, individual commits, and the files containing changes. -- GitLab From 1997d2bfd412571180806239095c0702232bc31d Mon Sep 17 00:00:00 2001 From: Kerri Miller Date: Mon, 12 Dec 2022 13:50:36 -0800 Subject: [PATCH 09/14] Fix typo'd reference to API endpoint --- doc/development/merge_request_diffs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/development/merge_request_diffs.md b/doc/development/merge_request_diffs.md index 743476ca73a1d8..5e1968b14ddb91 100644 --- a/doc/development/merge_request_diffs.md +++ b/doc/development/merge_request_diffs.md @@ -149,5 +149,5 @@ of options for access and working with diffs, focusing solely on the most common The most common avenue for viewing diffs is through the web UI and the "Changes" tab found in the top navigation bar of merge request pages. When selected, the -diffs themselves are loaded via a paginated request to `/-/merge_requests/:id/diffs_batch.json`, +diffs themselves are loaded via a paginated request to `/-/merge_requests/:id/batch_diffs.json`, which is served by [`Projects::MergeRequests::DiffsController#diffs_batch`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/controllers/projects/merge_requests/diffs_controller.rb), -- GitLab From 3cb22a2e760daaa74c27847c027ee3025253e28b Mon Sep 17 00:00:00 2001 From: Kerri Miller Date: Mon, 12 Dec 2022 13:50:59 -0800 Subject: [PATCH 10/14] Add begining of batch_diffs.json request sequence --- doc/development/merge_request_diffs.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/development/merge_request_diffs.md b/doc/development/merge_request_diffs.md index 5e1968b14ddb91..44a7421d845408 100644 --- a/doc/development/merge_request_diffs.md +++ b/doc/development/merge_request_diffs.md @@ -151,3 +151,16 @@ The most common avenue for viewing diffs is through the web UI and the "Changes" tab found in the top navigation bar of merge request pages. When selected, the diffs themselves are loaded via a paginated request to `/-/merge_requests/:id/batch_diffs.json`, which is served by [`Projects::MergeRequests::DiffsController#diffs_batch`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/controllers/projects/merge_requests/diffs_controller.rb), + +```mermaid +sequenceDiagram + .#diffs_batch->>+.#define_diff_vars: preload diffs + .#define_diff_vars ->>+ MergeRequestDiff: @merge_request.merge_request_diffs.viewable + Note over MergeRequestDiff,.#define_diff_vars: @merge_request_diffs + MergeRequestDiff -->>- .#define_diff_vars: An ordered collection of all diffs in MR + .#define_diff_vars ->>+ MergeRequestDiff: @merge_request.merge_request_diff + Note over MergeRequestDiff,.#define_diff_vars: @merge_request_diff + MergeRequestDiff -->>- .#define_diff_vars: The most recent MRD + .#define_diff_vars ->>+ .#define_diff_vars: @compare = param-filtered MRD + .#define_diff_vars -->>- .#diffs_batch: +``` -- GitLab From 15c95f95ae32c6b9a5399f9a9335b6a07d9da186 Mon Sep 17 00:00:00 2001 From: Kerri Miller Date: Mon, 12 Dec 2022 16:34:41 -0800 Subject: [PATCH 11/14] Adds additional sequencing for #diffs_batch --- doc/development/merge_request_diffs.md | 33 +++++++++++++++++++------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/doc/development/merge_request_diffs.md b/doc/development/merge_request_diffs.md index 44a7421d845408..09c682d0593f7e 100644 --- a/doc/development/merge_request_diffs.md +++ b/doc/development/merge_request_diffs.md @@ -154,13 +154,28 @@ which is served by [`Projects::MergeRequests::DiffsController#diffs_batch`](http ```mermaid sequenceDiagram - .#diffs_batch->>+.#define_diff_vars: preload diffs - .#define_diff_vars ->>+ MergeRequestDiff: @merge_request.merge_request_diffs.viewable - Note over MergeRequestDiff,.#define_diff_vars: @merge_request_diffs - MergeRequestDiff -->>- .#define_diff_vars: An ordered collection of all diffs in MR - .#define_diff_vars ->>+ MergeRequestDiff: @merge_request.merge_request_diff - Note over MergeRequestDiff,.#define_diff_vars: @merge_request_diff - MergeRequestDiff -->>- .#define_diff_vars: The most recent MRD - .#define_diff_vars ->>+ .#define_diff_vars: @compare = param-filtered MRD - .#define_diff_vars -->>- .#diffs_batch: + Note over .#diffs_batch: Preload diffs and ivars + .#diffs_batch->>+.#define_diff_vars: + .#define_diff_vars ->>+ @merge_request: @merge_request_diffs = + Note right of @merge_request: An ordered collection of all diffs in MR + @merge_request-->>-.#define_diff_vars: + .#define_diff_vars ->>+ @merge_request: @merge_request_diff = + Note right of @merge_request: Most recent merge_request_diff (or commit) + @merge_request-->>-.#define_diff_vars: + .#define_diff_vars ->>+ .#define_diff_vars: @compare = + Note right of .#define_diff_vars:: param-filtered merge_request_diff(s) + .#define_diff_vars -->>- .#diffs_batch: + Note over .#diffs_batch: Preloading complete + .#diffs_batch->>+@merge_request: Calculate unfoldable diff lines + Note right of @merge_request: note_positions_for_paths.unfoldable + @merge_request-->>-.#diffs_batch: + Note over .#diffs_batch: Build options hash + Note over .#diffs_batch: Build cache_context + Note over .#diffs_batch: Unfold files in diff + .#diffs_batch->>+Gitlab_Diff_FileCollection_MergeRequestDiffBase: diffs.write_diff + Gitlab_Diff_FileCollection_MergeRequestDiffBase->>+Gitlab_Diff_HighlightCache: Highlight diff + Gitlab_Diff_HighlightCache -->>-Gitlab_Diff_FileCollection_MergeRequestDiffBase: Return highlighted diff + Note over Gitlab_Diff_FileCollection_MergeRequestDiffBase: Cache diff + Gitlab_Diff_FileCollection_MergeRequestDiffBase-->>-.#diffs_batch: + Note over .#diffs_batch: render JSON ``` -- GitLab From aff04258fb28f5fe8c12850981858a4f3059e968 Mon Sep 17 00:00:00 2001 From: Amy Qualls Date: Tue, 20 Dec 2022 08:17:53 -0800 Subject: [PATCH 12/14] Cleans up warnings and suggestions from Vale Before doing any more edits, let's first take care of the simpler items that Vale flags. --- doc/development/merge_request_diffs.md | 50 ++++++++++++++------------ 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/doc/development/merge_request_diffs.md b/doc/development/merge_request_diffs.md index 09c682d0593f7e..aa0319cb436af5 100644 --- a/doc/development/merge_request_diffs.md +++ b/doc/development/merge_request_diffs.md @@ -4,7 +4,7 @@ group: Code Review info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments --- -# Merge Request Diffs development guide **(FREE)** +# Merge Request diffs development guide **(FREE)** This document explains the backend design and flow of merge request diffs. @@ -17,18 +17,19 @@ mentioned here are the major parts of the application for how merge request diff are generated, stored, and returned to users. NOTE: -This is a living document and should be updated accordingly when parts +This page is a living document. Update it accordingly when the parts of the codebase touched in this document are changed or removed, or when new components are added. ## Data Model -There are 4 main ActiveRecord models that represent what we collectively refer to -as "diffs." They are database-backed records that replicate data contained in the +Four main ActiveRecord models represent what we collectively refer to +as _diffs._ These database-backed records replicate data contained in the project's Git repository, and are in part a cache against excessive access requests -to [Gitaly](gitaly.md). Additionally, they provide a logical place for calculated and retrieved -metadata about the pieces of the diff, as well as general class- and instance-based -logic. +to [Gitaly](gitaly.md). Additionally, they provide a logical place for: + +- Calculated and retrieved metadata about the pieces of the diff. +- General class- and instance-based logic. ```mermaid erDiagram @@ -67,7 +68,7 @@ contents, individual commits, and the files containing changes. verification_checksum: nil> ``` -Diff content is usually accessed through this class, as logic is often applied +Diff content is usually accessed through this class. Logic is often applied to diff, file, and commit content before it is returned to a user. ### `MergeRequestDiffCommit` @@ -90,8 +91,8 @@ and holds header information about the commit. ``` Every `MergeRequestDiffCommit` has a corresponding `MergeRequest::DiffCommitUser` -record it `:belongs_to` (in ActiveRecord parlance.) These are the `:commit_author` -and the `:committer` records, as they could be distinct individuals. +record it `:belongs_to`, in ActiveRecord parlance. These records are `:commit_author` +and `:committer`, and could be distinct individuals. ### `MergeRequest::DiffCommitUser` @@ -111,8 +112,11 @@ itself to any `User` records. `MergeRequestDiffFile` is defined in `app/models/merge_request_diff_file.rb`. This record of this class represents the diff of a single file contained in the `MergeRequestDiff`. It holds both meta and specific information about the file's -relationship to the change, such as whether it is added or renamed, it's ordering -within the diff, as well as the raw diff output itself. +relationship to the change, such as: + +- Whether it is added or renamed. +- Its ordering in the diff. +- The raw diff output itself. ### `MergeRequestDiffDetail` @@ -142,40 +146,40 @@ is not used for user-facing diffs. ## Flow These flowcharts should help explain the flow from the controllers down to the -models for different functionalities. This is not intended to document the entirety +models for different functionalities. This page is not intended to document the entirety of options for access and working with diffs, focusing solely on the most common. ### `batch_diffs.json` -The most common avenue for viewing diffs is through the web UI and the "Changes" -tab found in the top navigation bar of merge request pages. When selected, the +The most common avenue for viewing diffs is the **Changes** +tab in the top navigation bar of merge request pages in the GitLab UI. When selected, the diffs themselves are loaded via a paginated request to `/-/merge_requests/:id/batch_diffs.json`, which is served by [`Projects::MergeRequests::DiffsController#diffs_batch`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/controllers/projects/merge_requests/diffs_controller.rb), ```mermaid sequenceDiagram Note over .#diffs_batch: Preload diffs and ivars - .#diffs_batch->>+.#define_diff_vars: + .#diffs_batch->>+.#define_diff_vars: .#define_diff_vars ->>+ @merge_request: @merge_request_diffs = Note right of @merge_request: An ordered collection of all diffs in MR - @merge_request-->>-.#define_diff_vars: + @merge_request-->>-.#define_diff_vars: .#define_diff_vars ->>+ @merge_request: @merge_request_diff = Note right of @merge_request: Most recent merge_request_diff (or commit) - @merge_request-->>-.#define_diff_vars: - .#define_diff_vars ->>+ .#define_diff_vars: @compare = + @merge_request-->>-.#define_diff_vars: + .#define_diff_vars ->>+ .#define_diff_vars: @compare = Note right of .#define_diff_vars:: param-filtered merge_request_diff(s) - .#define_diff_vars -->>- .#diffs_batch: + .#define_diff_vars -->>- .#diffs_batch: Note over .#diffs_batch: Preloading complete .#diffs_batch->>+@merge_request: Calculate unfoldable diff lines Note right of @merge_request: note_positions_for_paths.unfoldable - @merge_request-->>-.#diffs_batch: + @merge_request-->>-.#diffs_batch: Note over .#diffs_batch: Build options hash Note over .#diffs_batch: Build cache_context - Note over .#diffs_batch: Unfold files in diff + Note over .#diffs_batch: Unfold files in diff .#diffs_batch->>+Gitlab_Diff_FileCollection_MergeRequestDiffBase: diffs.write_diff Gitlab_Diff_FileCollection_MergeRequestDiffBase->>+Gitlab_Diff_HighlightCache: Highlight diff Gitlab_Diff_HighlightCache -->>-Gitlab_Diff_FileCollection_MergeRequestDiffBase: Return highlighted diff Note over Gitlab_Diff_FileCollection_MergeRequestDiffBase: Cache diff - Gitlab_Diff_FileCollection_MergeRequestDiffBase-->>-.#diffs_batch: + Gitlab_Diff_FileCollection_MergeRequestDiffBase-->>-.#diffs_batch: Note over .#diffs_batch: render JSON ``` -- GitLab From 0d94355db1953ee7bdfb0504a893bdaee25d8af8 Mon Sep 17 00:00:00 2001 From: Amy Qualls Date: Tue, 20 Dec 2022 08:36:17 -0800 Subject: [PATCH 13/14] Revisions for tone and style Revises the language of the page to bring it closer to GitLab tone and style. In several places, break apart long sentences into list items. --- doc/development/merge_request_diffs.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/doc/development/merge_request_diffs.md b/doc/development/merge_request_diffs.md index aa0319cb436af5..89a128affe8dcd 100644 --- a/doc/development/merge_request_diffs.md +++ b/doc/development/merge_request_diffs.md @@ -4,15 +4,16 @@ group: Code Review info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments --- -# Merge Request diffs development guide **(FREE)** +# Merge request diffs development guide **(FREE)** This document explains the backend design and flow of merge request diffs. +It should help contributors: -This should help contributors to understand the code design easier and to -identify areas for improvement through contribution. +- Understand the code design. +- Identify areas for improvement through contribution. It's intentional that it doesn't contain too many implementation details, as they -can change often. The code should explain those things better. The components +can change often. The code better explains these details. The components mentioned here are the major parts of the application for how merge request diffs are generated, stored, and returned to users. @@ -21,7 +22,7 @@ This page is a living document. Update it accordingly when the parts of the codebase touched in this document are changed or removed, or when new components are added. -## Data Model +## Data model Four main ActiveRecord models represent what we collectively refer to as _diffs._ These database-backed records replicate data contained in the @@ -29,7 +30,7 @@ project's Git repository, and are in part a cache against excessive access reque to [Gitaly](gitaly.md). Additionally, they provide a logical place for: - Calculated and retrieved metadata about the pieces of the diff. -- General class- and instance-based logic. +- General class- and instance- based logic. ```mermaid erDiagram @@ -74,7 +75,7 @@ to diff, file, and commit content before it is returned to a user. ### `MergeRequestDiffCommit` `MergeRequestDiffCommit` is defined in `app/models/merge_request_diff_commit.rb`. -This class corresponds to a single commit contained in it's corresponding `MergeRequestDiff` +This class corresponds to a single commit contained in its corresponding `MergeRequestDiff`, and holds header information about the commit. ```ruby @@ -146,7 +147,7 @@ is not used for user-facing diffs. ## Flow These flowcharts should help explain the flow from the controllers down to the -models for different functionalities. This page is not intended to document the entirety +models for different features. This page is not intended to document the entirety of options for access and working with diffs, focusing solely on the most common. ### `batch_diffs.json` -- GitLab From 85287e795512e75af167fb1e068ce61b59aa15d7 Mon Sep 17 00:00:00 2001 From: Amy Qualls Date: Tue, 20 Dec 2022 17:03:50 +0000 Subject: [PATCH 14/14] Cleans up indentation, Mermaid graph Fixes the indentation of a code block that caused syntax highlighting problems in the web UI. Also fixes the sequenceDiagram at the bottom of the page by adding in   characters. Why it's required, we don't know, but the graph fails to render without them. --- doc/development/merge_request_diffs.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/doc/development/merge_request_diffs.md b/doc/development/merge_request_diffs.md index 89a128affe8dcd..a3c8ada898e5ff 100644 --- a/doc/development/merge_request_diffs.md +++ b/doc/development/merge_request_diffs.md @@ -142,7 +142,7 @@ is not used for user-facing diffs. binary: false, external_diff_offset: nil, external_diff_size: nil> - ``` +``` ## Flow @@ -155,25 +155,27 @@ of options for access and working with diffs, focusing solely on the most common The most common avenue for viewing diffs is the **Changes** tab in the top navigation bar of merge request pages in the GitLab UI. When selected, the diffs themselves are loaded via a paginated request to `/-/merge_requests/:id/batch_diffs.json`, -which is served by [`Projects::MergeRequests::DiffsController#diffs_batch`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/controllers/projects/merge_requests/diffs_controller.rb), +which is served by [`Projects::MergeRequests::DiffsController#diffs_batch`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/controllers/projects/merge_requests/diffs_controller.rb): + + ```mermaid sequenceDiagram Note over .#diffs_batch: Preload diffs and ivars - .#diffs_batch->>+.#define_diff_vars: + .#diffs_batch->>+.#define_diff_vars:   .#define_diff_vars ->>+ @merge_request: @merge_request_diffs = Note right of @merge_request: An ordered collection of all diffs in MR - @merge_request-->>-.#define_diff_vars: + @merge_request-->>-.#define_diff_vars:   .#define_diff_vars ->>+ @merge_request: @merge_request_diff = Note right of @merge_request: Most recent merge_request_diff (or commit) - @merge_request-->>-.#define_diff_vars: + @merge_request-->>-.#define_diff_vars:   .#define_diff_vars ->>+ .#define_diff_vars: @compare = Note right of .#define_diff_vars:: param-filtered merge_request_diff(s) - .#define_diff_vars -->>- .#diffs_batch: + .#define_diff_vars -->>- .#diffs_batch:   Note over .#diffs_batch: Preloading complete .#diffs_batch->>+@merge_request: Calculate unfoldable diff lines Note right of @merge_request: note_positions_for_paths.unfoldable - @merge_request-->>-.#diffs_batch: + @merge_request-->>-.#diffs_batch:   Note over .#diffs_batch: Build options hash Note over .#diffs_batch: Build cache_context Note over .#diffs_batch: Unfold files in diff @@ -181,6 +183,6 @@ sequenceDiagram Gitlab_Diff_FileCollection_MergeRequestDiffBase->>+Gitlab_Diff_HighlightCache: Highlight diff Gitlab_Diff_HighlightCache -->>-Gitlab_Diff_FileCollection_MergeRequestDiffBase: Return highlighted diff Note over Gitlab_Diff_FileCollection_MergeRequestDiffBase: Cache diff - Gitlab_Diff_FileCollection_MergeRequestDiffBase-->>-.#diffs_batch: + Gitlab_Diff_FileCollection_MergeRequestDiffBase-->>-.#diffs_batch:   Note over .#diffs_batch: render JSON ``` -- GitLab