Commit c3fc527c authored by Jan Provaznik's avatar Jan Provaznik

Merge branch '5164-epic-counts-graphql-only' into 'master'

Add GraphQL structure for DescendantWeightSum

See merge request gitlab-org/gitlab!25980
parents 604809ec 1a0bf10c
......@@ -1862,6 +1862,12 @@ type Epic implements Noteable {
"""
descendantCounts: EpicDescendantCount
"""
Total weight of open and closed descendant epic's issues. Available only when
feature flag unfiltered_epic_aggregates is enabled.
"""
descendantWeightSum: EpicDescendantWeights
"""
Description of the epic
"""
......@@ -2178,6 +2184,21 @@ type EpicDescendantCount {
openedIssues: Int
}
"""
Total weight of open and closed descendant issues
"""
type EpicDescendantWeights {
"""
Total weight of completed (closed) issues in this epic, including epic descendants
"""
closedIssues: Int
"""
Total weight of opened issues in this epic, including epic descendants
"""
openedIssues: Int
}
"""
An edge in a connection.
"""
......
......@@ -297,6 +297,7 @@ Represents an epic.
| `closedAt` | Time | Timestamp of the epic's closure |
| `createdAt` | Time | Timestamp of the epic's creation |
| `descendantCounts` | EpicDescendantCount | Number of open and closed descendant epics and issues |
| `descendantWeightSum` | EpicDescendantWeights | Total weight of open and closed descendant epic's issues. Available only when feature flag unfiltered_epic_aggregates is enabled. |
| `description` | String | Description of the epic |
| `downvotes` | Int! | Number of downvotes the epic has received |
| `dueDate` | Time | Due date of the epic |
......@@ -337,6 +338,15 @@ Counts of descendent epics.
| `openedEpics` | Int | Number of opened sub-epics |
| `openedIssues` | Int | Number of opened epic issues |
## EpicDescendantWeights
Total weight of open and closed descendant issues
| Name | Type | Description |
| --- | ---- | ---------- |
| `closedIssues` | Int | Total weight of completed (closed) issues in this epic, including epic descendants |
| `openedIssues` | Int | Total weight of opened issues in this epic, including epic descendants |
## EpicIssue
Relationship between an epic and an issue
......
# frozen_string_literal: true
module Types
# rubocop: disable Graphql/AuthorizeTypes
class EpicDescendantWeightSumType < BaseObject
graphql_name 'EpicDescendantWeights'
description 'Total weight of open and closed descendant issues'
field :opened_issues, GraphQL::INT_TYPE, null: true,
description: 'Total weight of opened issues in this epic, including epic descendants'
field :closed_issues, GraphQL::INT_TYPE, null: true,
description: 'Total weight of completed (closed) issues in this epic, including epic descendants'
end
# rubocop: enable Graphql/AuthorizeTypes
end
......@@ -126,6 +126,18 @@ module Types
Epics::DescendantCountService.new(epic, ctx[:current_user])
end
field :descendant_weight_sum, Types::EpicDescendantWeightSumType, null: true, complexity: 10,
description: "Total weight of open and closed descendant epic's issues",
feature_flag: :unfiltered_epic_aggregates
def descendant_weight_sum
OpenStruct.new(
# We shouldn't stop the whole query, so returning -1 for a semi-noisy error
opened_issues: -1,
closed_issues: -1
)
end
field :health_status,
::Types::HealthStatusEnum,
null: true,
......
# frozen_string_literal: true
require 'spec_helper'
describe GitlabSchema.types['EpicDescendantWeights'] do
it { expect(described_class.graphql_name).to eq('EpicDescendantWeights') }
it 'has specific fields' do
%i[opened_issues closed_issues].each do |field_name|
expect(described_class).to have_graphql_field(field_name)
end
end
end
......@@ -11,7 +11,7 @@ describe GitlabSchema.types['Epic'] do
closed_at created_at updated_at children has_children has_issues
web_path web_url relation_path reference issues user_permissions
notes discussions relative_position subscribed participants
descendant_counts upvotes downvotes health_status
descendant_counts descendant_weight_sum upvotes downvotes health_status
]
end
......
# frozen_string_literal: true
require 'spec_helper'
describe 'Epic aggregates (count and weight)' do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
let_it_be(:group) { create(:group, :public) }
let_it_be(:parent_epic) { create(:epic, id: 1, group: group, title: 'parent epic') }
let(:query) do
graphql_query_for('group', { fullPath: group.full_path }, query_graphql_field('epics', { iid: parent_epic.iid }, epic_aggregates_query))
end
let(:epic_aggregates_query) do
<<~QUERY
nodes {
descendantWeightSum {
openedIssues
closedIssues
}
descendantCounts {
openedEpics
closedEpics
openedIssues
closedIssues
}
}
QUERY
end
before do
stub_licensed_features(epics: true)
end
context 'with feature flag enabled' do
before do
stub_feature_flags(unfiltered_epic_aggregates: true)
end
it 'returns a placeholder with -1 weights and does not error' do
post_graphql(query, current_user: current_user)
actual_result = graphql_data.dig('group', 'epics', 'nodes').first
expected_result = {
"descendantWeightSum" => {
"openedIssues" => -1,
"closedIssues" => -1
}
}
expect(actual_result).to include expected_result
end
end
context 'with feature flag disabled' do
before do
stub_feature_flags(unfiltered_epic_aggregates: false)
end
context 'when requesting counts' do
let(:epic_aggregates_query) do
<<~QUERY
nodes {
descendantCounts {
openedEpics
closedEpics
openedIssues
closedIssues
}
}
QUERY
end
it 'uses the DescendantCountService' do
expect(Epics::DescendantCountService).to receive(:new)
post_graphql(query, current_user: current_user)
end
end
context 'when requesting weights' do
let(:epic_aggregates_query) do
<<~QUERY
nodes {
descendantWeightSum {
openedIssues
closedIssues
}
}
QUERY
end
it 'returns an error' do
post_graphql(query, current_user: current_user)
expect_graphql_errors_to_include /Field 'descendantWeightSum' doesn't exist on type 'Epic/
end
end
end
end
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