Commit 4496045d authored by Sean Arnold's avatar Sean Arnold Committed by Kamil Trzciński

Add alert_management_alert to issues type

Use Lookahead
parent aeac7c0e
...@@ -4,6 +4,8 @@ module IssueResolverFields ...@@ -4,6 +4,8 @@ module IssueResolverFields
extend ActiveSupport::Concern extend ActiveSupport::Concern
prepended do prepended do
include LooksAhead
argument :iid, GraphQL::STRING_TYPE, argument :iid, GraphQL::STRING_TYPE,
required: false, required: false,
description: 'IID of the issue. For example, "1"' description: 'IID of the issue. For example, "1"'
...@@ -49,7 +51,7 @@ module IssueResolverFields ...@@ -49,7 +51,7 @@ module IssueResolverFields
required: false required: false
end end
def resolve(**args) def resolve_with_lookahead(**args)
# The project could have been loaded in batch by `BatchLoader`. # The project could have been loaded in batch by `BatchLoader`.
# At this point we need the `id` of the project to query for issues, so # At this point we need the `id` of the project to query for issues, so
# make sure it's loaded and not `nil` before continuing. # make sure it's loaded and not `nil` before continuing.
......
...@@ -7,7 +7,7 @@ module Resolvers ...@@ -7,7 +7,7 @@ module Resolvers
type Types::IssueStatusCountsType, null: true type Types::IssueStatusCountsType, null: true
def continue_issue_resolve(parent, finder, **args) def continue_issue_resolve(parent, finder, **args)
Gitlab::IssuablesCountForState.new(finder, parent) apply_lookahead(Gitlab::IssuablesCountForState.new(finder, parent))
end end
end end
end end
...@@ -19,7 +19,7 @@ module Resolvers ...@@ -19,7 +19,7 @@ module Resolvers
milestone_due_asc milestone_due_desc].freeze milestone_due_asc milestone_due_desc].freeze
def continue_issue_resolve(parent, finder, **args) def continue_issue_resolve(parent, finder, **args)
issues = Gitlab::Graphql::Loaders::IssuableLoader.new(parent, finder).batching_find_all issues = apply_lookahead(Gitlab::Graphql::Loaders::IssuableLoader.new(parent, finder).batching_find_all)
if non_stable_cursor_sort?(args[:sort]) if non_stable_cursor_sort?(args[:sort])
# Certain complex sorts are not supported by the stable cursor pagination yet. # Certain complex sorts are not supported by the stable cursor pagination yet.
...@@ -30,6 +30,14 @@ module Resolvers ...@@ -30,6 +30,14 @@ module Resolvers
end end
end end
private
def preloads
{
alert_management_alert: [:alert_management_alert]
}
end
def non_stable_cursor_sort?(sort) def non_stable_cursor_sort?(sort)
NON_STABLE_CURSOR_SORTS.include?(sort) NON_STABLE_CURSOR_SORTS.include?(sort)
end end
......
...@@ -101,6 +101,11 @@ module Types ...@@ -101,6 +101,11 @@ module Types
field :type, Types::IssueTypeEnum, null: true, field :type, Types::IssueTypeEnum, null: true,
method: :issue_type, method: :issue_type,
description: 'Type of the issue' description: 'Type of the issue'
field :alert_management_alert,
Types::AlertManagement::AlertType,
null: true,
description: 'Alert associated to this issue'
end end
end end
......
...@@ -146,12 +146,14 @@ module Types ...@@ -146,12 +146,14 @@ module Types
Types::IssueType.connection_type, Types::IssueType.connection_type,
null: true, null: true,
description: 'Issues of the project', description: 'Issues of the project',
extras: [:lookahead],
resolver: Resolvers::IssuesResolver resolver: Resolvers::IssuesResolver
field :issue_status_counts, field :issue_status_counts,
Types::IssueStatusCountsType, Types::IssueStatusCountsType,
null: true, null: true,
description: 'Counts of issues by status for the project', description: 'Counts of issues by status for the project',
extras: [:lookahead],
resolver: Resolvers::IssueStatusCountsResolver resolver: Resolvers::IssueStatusCountsResolver
field :milestones, Types::MilestoneType.connection_type, null: true, field :milestones, Types::MilestoneType.connection_type, null: true,
......
---
title: Add alert to Issue type in GraphQL
merge_request: 40214
author:
type: added
...@@ -5152,6 +5152,11 @@ type EpicHealthStatus { ...@@ -5152,6 +5152,11 @@ type EpicHealthStatus {
Relationship between an epic and an issue Relationship between an epic and an issue
""" """
type EpicIssue implements Noteable { type EpicIssue implements Noteable {
"""
Alert associated to this issue
"""
alertManagementAlert: AlertManagementAlert
""" """
Assignees of the issue Assignees of the issue
""" """
...@@ -6871,6 +6876,11 @@ enum IssuableState { ...@@ -6871,6 +6876,11 @@ enum IssuableState {
} }
type Issue implements Noteable { type Issue implements Noteable {
"""
Alert associated to this issue
"""
alertManagementAlert: AlertManagementAlert
""" """
Assignees of the issue Assignees of the issue
""" """
......
...@@ -14374,6 +14374,20 @@ ...@@ -14374,6 +14374,20 @@
"name": "EpicIssue", "name": "EpicIssue",
"description": "Relationship between an epic and an issue", "description": "Relationship between an epic and an issue",
"fields": [ "fields": [
{
"name": "alertManagementAlert",
"description": "Alert associated to this issue",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "AlertManagementAlert",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{ {
"name": "assignees", "name": "assignees",
"description": "Assignees of the issue", "description": "Assignees of the issue",
...@@ -18951,6 +18965,20 @@ ...@@ -18951,6 +18965,20 @@
"name": "Issue", "name": "Issue",
"description": null, "description": null,
"fields": [ "fields": [
{
"name": "alertManagementAlert",
"description": "Alert associated to this issue",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "AlertManagementAlert",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{ {
"name": "assignees", "name": "assignees",
"description": "Assignees of the issue", "description": "Assignees of the issue",
...@@ -866,6 +866,7 @@ Relationship between an epic and an issue ...@@ -866,6 +866,7 @@ Relationship between an epic and an issue
| Name | Type | Description | | Name | Type | Description |
| --- | ---- | ---------- | | --- | ---- | ---------- |
| `alertManagementAlert` | AlertManagementAlert | Alert associated to this issue |
| `author` | User! | User that created the issue | | `author` | User! | User that created the issue |
| `blocked` | Boolean! | Indicates the issue is blocked | | `blocked` | Boolean! | Indicates the issue is blocked |
| `closedAt` | Time | Timestamp of when the issue was closed | | `closedAt` | Time | Timestamp of when the issue was closed |
...@@ -1038,6 +1039,7 @@ Represents a Group Membership ...@@ -1038,6 +1039,7 @@ Represents a Group Membership
| Name | Type | Description | | Name | Type | Description |
| --- | ---- | ---------- | | --- | ---- | ---------- |
| `alertManagementAlert` | AlertManagementAlert | Alert associated to this issue |
| `author` | User! | User that created the issue | | `author` | User! | User that created the issue |
| `blocked` | Boolean! | Indicates the issue is blocked | | `blocked` | Boolean! | Indicates the issue is blocked |
| `closedAt` | Time | Timestamp of when the issue was closed | | `closedAt` | Time | Timestamp of when the issue was closed |
......
...@@ -26,6 +26,12 @@ FactoryBot.define do ...@@ -26,6 +26,12 @@ FactoryBot.define do
closed_at { Time.now } closed_at { Time.now }
end end
trait :with_alert do
after(:create) do |issue|
create(:alert_management_alert, project: issue.project, issue: issue)
end
end
after(:build) do |issue, evaluator| after(:build) do |issue, evaluator|
issue.state_id = Issue.available_states[evaluator.state] issue.state_id = Issue.available_states[evaluator.state]
end end
......
...@@ -15,7 +15,7 @@ RSpec.describe GitlabSchema.types['Issue'] do ...@@ -15,7 +15,7 @@ RSpec.describe GitlabSchema.types['Issue'] do
fields = %i[id iid title description state reference author assignees participants labels milestone due_date fields = %i[id iid title description state reference author assignees participants labels milestone due_date
confidential discussion_locked upvotes downvotes user_notes_count web_path web_url relative_position confidential discussion_locked upvotes downvotes user_notes_count web_path web_url relative_position
subscribed time_estimate total_time_spent closed_at created_at updated_at task_completion_status subscribed time_estimate total_time_spent closed_at created_at updated_at task_completion_status
designs design_collection] designs design_collection alert_management_alert]
fields.each do |field_name| fields.each do |field_name|
expect(described_class).to have_graphql_field(field_name) expect(described_class).to have_graphql_field(field_name)
......
...@@ -10,7 +10,7 @@ RSpec.describe 'getting an issue list for a project' do ...@@ -10,7 +10,7 @@ RSpec.describe 'getting an issue list for a project' do
let(:issues_data) { graphql_data['project']['issues']['edges'] } let(:issues_data) { graphql_data['project']['issues']['edges'] }
let!(:issues) do let!(:issues) do
[create(:issue, project: project, discussion_locked: true), [create(:issue, project: project, discussion_locked: true),
create(:issue, project: project)] create(:issue, :with_alert, project: project)]
end end
let(:fields) do let(:fields) do
...@@ -256,6 +256,40 @@ RSpec.describe 'getting an issue list for a project' do ...@@ -256,6 +256,40 @@ RSpec.describe 'getting an issue list for a project' do
end end
end end
context 'fetching alert management alert' do
let(:fields) do
<<~QUERY
edges {
node {
id
alertManagementAlert {
title
}
}
}
QUERY
end
# Alerts need to reporter and above
before do
project.add_reporter(current_user)
end
it 'avoids N+1 queries' do
control = ActiveRecord::QueryRecorder.new { post_graphql(query, current_user: current_user) }
create(:alert_management_alert, :with_issue, project: project )
expect { post_graphql(query, current_user: current_user) }.not_to exceed_query_limit(control)
end
it 'returns the alert data' do
post_graphql(query, current_user: current_user)
issues_data
end
end
def grab_iids(data = issues_data) def grab_iids(data = issues_data)
data.map do |issue| data.map do |issue|
issue.dig('node', 'iid').to_i issue.dig('node', 'iid').to_i
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment