Commit 60e3a879 authored by Pavel Shutsin's avatar Pavel Shutsin

Rename DevOpsAdoptionSegment

Refactors API and other code to use
`EnabledNamespace` term instead of segment

Changelog: other
MR: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62834
EE: true
parent ec2587c6
...@@ -83,9 +83,9 @@ Fields related to design management. ...@@ -83,9 +83,9 @@ Fields related to design management.
Returns [`DesignManagement!`](#designmanagement). Returns [`DesignManagement!`](#designmanagement).
### `Query.devopsAdoptionSegments` ### `Query.devopsAdoptionEnabledNamespaces`
Get configured DevOps adoption segments on the instance. **BETA** This endpoint is subject to change without notice. Get configured DevOps adoption namespaces. **BETA** This endpoint is subject to change without notice.
Returns [`DevopsAdoptionSegmentConnection`](#devopsadoptionsegmentconnection). Returns [`DevopsAdoptionSegmentConnection`](#devopsadoptionsegmentconnection).
...@@ -97,7 +97,7 @@ four standard [pagination arguments](#connection-pagination-arguments): ...@@ -97,7 +97,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description | | Name | Type | Description |
| ---- | ---- | ----------- | | ---- | ---- | ----------- |
| <a id="querydevopsadoptionsegmentsdisplaynamespaceid"></a>`displayNamespaceId` | [`NamespaceID`](#namespaceid) | Filter by display namespace. | | <a id="querydevopsadoptionenablednamespacesdisplaynamespaceid"></a>`displayNamespaceId` | [`NamespaceID`](#namespaceid) | Filter by display namespace. |
### `Query.echo` ### `Query.echo`
...@@ -758,27 +758,27 @@ Input type: `BoardListUpdateLimitMetricsInput` ...@@ -758,27 +758,27 @@ Input type: `BoardListUpdateLimitMetricsInput`
| <a id="mutationboardlistupdatelimitmetricserrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | | <a id="mutationboardlistupdatelimitmetricserrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationboardlistupdatelimitmetricslist"></a>`list` | [`BoardList`](#boardlist) | The updated list. | | <a id="mutationboardlistupdatelimitmetricslist"></a>`list` | [`BoardList`](#boardlist) | The updated list. |
### `Mutation.bulkFindOrCreateDevopsAdoptionSegments` ### `Mutation.bulkEnableDevopsAdoptionNamespaces`
**BETA** This endpoint is subject to change without notice. **BETA** This endpoint is subject to change without notice.
Input type: `BulkFindOrCreateDevopsAdoptionSegmentsInput` Input type: `BulkEnableDevopsAdoptionNamespacesInput`
#### Arguments #### Arguments
| Name | Type | Description | | Name | Type | Description |
| ---- | ---- | ----------- | | ---- | ---- | ----------- |
| <a id="mutationbulkfindorcreatedevopsadoptionsegmentsclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | <a id="mutationbulkenabledevopsadoptionnamespacesclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationbulkfindorcreatedevopsadoptionsegmentsdisplaynamespaceid"></a>`displayNamespaceId` | [`NamespaceID`](#namespaceid) | Display namespace ID. | | <a id="mutationbulkenabledevopsadoptionnamespacesdisplaynamespaceid"></a>`displayNamespaceId` | [`NamespaceID`](#namespaceid) | Display namespace ID. |
| <a id="mutationbulkfindorcreatedevopsadoptionsegmentsnamespaceids"></a>`namespaceIds` | [`[NamespaceID!]!`](#namespaceid) | List of Namespace IDs for the segments. | | <a id="mutationbulkenabledevopsadoptionnamespacesnamespaceids"></a>`namespaceIds` | [`[NamespaceID!]!`](#namespaceid) | List of Namespace IDs. |
#### Fields #### Fields
| Name | Type | Description | | Name | Type | Description |
| ---- | ---- | ----------- | | ---- | ---- | ----------- |
| <a id="mutationbulkfindorcreatedevopsadoptionsegmentsclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | <a id="mutationbulkenabledevopsadoptionnamespacesclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationbulkfindorcreatedevopsadoptionsegmentserrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | | <a id="mutationbulkenabledevopsadoptionnamespacesenablednamespaces"></a>`enabledNamespaces` | [`[DevopsAdoptionSegment!]`](#devopsadoptionsegment) | Enabled namespaces after mutation. |
| <a id="mutationbulkfindorcreatedevopsadoptionsegmentssegments"></a>`segments` | [`[DevopsAdoptionSegment!]`](#devopsadoptionsegment) | Created segments after mutation. | | <a id="mutationbulkenabledevopsadoptionnamespaceserrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
### `Mutation.ciCdSettingsUpdate` ### `Mutation.ciCdSettingsUpdate`
...@@ -1094,28 +1094,6 @@ Input type: `CreateCustomEmojiInput` ...@@ -1094,28 +1094,6 @@ Input type: `CreateCustomEmojiInput`
| <a id="mutationcreatecustomemojicustomemoji"></a>`customEmoji` | [`CustomEmoji`](#customemoji) | The new custom emoji. | | <a id="mutationcreatecustomemojicustomemoji"></a>`customEmoji` | [`CustomEmoji`](#customemoji) | The new custom emoji. |
| <a id="mutationcreatecustomemojierrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | | <a id="mutationcreatecustomemojierrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
### `Mutation.createDevopsAdoptionSegment`
**BETA** This endpoint is subject to change without notice.
Input type: `CreateDevopsAdoptionSegmentInput`
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationcreatedevopsadoptionsegmentclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationcreatedevopsadoptionsegmentdisplaynamespaceid"></a>`displayNamespaceId` | [`NamespaceID`](#namespaceid) | Display namespace ID. |
| <a id="mutationcreatedevopsadoptionsegmentnamespaceid"></a>`namespaceId` | [`NamespaceID!`](#namespaceid) | Namespace ID to set for the segment. |
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationcreatedevopsadoptionsegmentclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationcreatedevopsadoptionsegmenterrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationcreatedevopsadoptionsegmentsegment"></a>`segment` | [`DevopsAdoptionSegment`](#devopsadoptionsegment) | The segment after mutation. |
### `Mutation.createDiffNote` ### `Mutation.createDiffNote`
Input type: `CreateDiffNoteInput` Input type: `CreateDiffNoteInput`
...@@ -1678,26 +1656,6 @@ Input type: `DeleteAnnotationInput` ...@@ -1678,26 +1656,6 @@ Input type: `DeleteAnnotationInput`
| <a id="mutationdeleteannotationclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | <a id="mutationdeleteannotationclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationdeleteannotationerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | | <a id="mutationdeleteannotationerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
### `Mutation.deleteDevopsAdoptionSegment`
**BETA** This endpoint is subject to change without notice.
Input type: `DeleteDevopsAdoptionSegmentInput`
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationdeletedevopsadoptionsegmentclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationdeletedevopsadoptionsegmentid"></a>`id` | [`[AnalyticsDevopsAdoptionSegmentID!]!`](#analyticsdevopsadoptionsegmentid) | One or many IDs of the segments to delete. |
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationdeletedevopsadoptionsegmentclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationdeletedevopsadoptionsegmenterrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
### `Mutation.designManagementDelete` ### `Mutation.designManagementDelete`
Input type: `DesignManagementDeleteInput` Input type: `DesignManagementDeleteInput`
...@@ -1914,6 +1872,26 @@ Input type: `DestroySnippetInput` ...@@ -1914,6 +1872,26 @@ Input type: `DestroySnippetInput`
| <a id="mutationdestroysnippeterrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | | <a id="mutationdestroysnippeterrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationdestroysnippetsnippet"></a>`snippet` | [`Snippet`](#snippet) | The snippet after mutation. | | <a id="mutationdestroysnippetsnippet"></a>`snippet` | [`Snippet`](#snippet) | The snippet after mutation. |
### `Mutation.disableDevopsAdoptionNamespace`
**BETA** This endpoint is subject to change without notice.
Input type: `DisableDevopsAdoptionNamespaceInput`
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationdisabledevopsadoptionnamespaceclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationdisabledevopsadoptionnamespaceid"></a>`id` | [`[AnalyticsDevopsAdoptionEnabledNamespaceID!]!`](#analyticsdevopsadoptionenablednamespaceid) | One or many IDs of the enabled namespaces to disable. |
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationdisabledevopsadoptionnamespaceclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationdisabledevopsadoptionnamespaceerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
### `Mutation.discussionToggleResolve` ### `Mutation.discussionToggleResolve`
Toggles the resolved state of a discussion. Toggles the resolved state of a discussion.
...@@ -1961,6 +1939,28 @@ Input type: `DismissVulnerabilityInput` ...@@ -1961,6 +1939,28 @@ Input type: `DismissVulnerabilityInput`
| <a id="mutationdismissvulnerabilityerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | | <a id="mutationdismissvulnerabilityerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationdismissvulnerabilityvulnerability"></a>`vulnerability` | [`Vulnerability`](#vulnerability) | The vulnerability after dismissal. | | <a id="mutationdismissvulnerabilityvulnerability"></a>`vulnerability` | [`Vulnerability`](#vulnerability) | The vulnerability after dismissal. |
### `Mutation.enableDevopsAdoptionNamespace`
**BETA** This endpoint is subject to change without notice.
Input type: `EnableDevopsAdoptionNamespaceInput`
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationenabledevopsadoptionnamespaceclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationenabledevopsadoptionnamespacedisplaynamespaceid"></a>`displayNamespaceId` | [`NamespaceID`](#namespaceid) | Display namespace ID. |
| <a id="mutationenabledevopsadoptionnamespacenamespaceid"></a>`namespaceId` | [`NamespaceID!`](#namespaceid) | Namespace ID. |
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationenabledevopsadoptionnamespaceclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationenabledevopsadoptionnamespaceenablednamespace"></a>`enabledNamespace` | [`DevopsAdoptionSegment`](#devopsadoptionsegment) | Enabled namespace after mutation. |
| <a id="mutationenabledevopsadoptionnamespaceerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
### `Mutation.environmentsCanaryIngressUpdate` ### `Mutation.environmentsCanaryIngressUpdate`
Input type: `EnvironmentsCanaryIngressUpdateInput` Input type: `EnvironmentsCanaryIngressUpdateInput`
...@@ -8271,15 +8271,15 @@ four standard [pagination arguments](#connection-pagination-arguments): ...@@ -8271,15 +8271,15 @@ four standard [pagination arguments](#connection-pagination-arguments):
### `DevopsAdoptionSegment` ### `DevopsAdoptionSegment`
Segment. Enabled namespace for DevopsAdoption.
#### Fields #### Fields
| Name | Type | Description | | Name | Type | Description |
| ---- | ---- | ----------- | | ---- | ---- | ----------- |
| <a id="devopsadoptionsegmentdisplaynamespace"></a>`displayNamespace` | [`Namespace`](#namespace) | Namespace where data should be displayed. | | <a id="devopsadoptionsegmentdisplaynamespace"></a>`displayNamespace` | [`Namespace`](#namespace) | Namespace where data should be displayed. |
| <a id="devopsadoptionsegmentid"></a>`id` | [`ID!`](#id) | ID of the segment. | | <a id="devopsadoptionsegmentid"></a>`id` | [`ID!`](#id) | ID of the enabled namespace. |
| <a id="devopsadoptionsegmentlatestsnapshot"></a>`latestSnapshot` | [`DevopsAdoptionSnapshot`](#devopsadoptionsnapshot) | The latest adoption metrics for the segment. | | <a id="devopsadoptionsegmentlatestsnapshot"></a>`latestSnapshot` | [`DevopsAdoptionSnapshot`](#devopsadoptionsnapshot) | The latest adoption metrics for the enabled namespace. |
| <a id="devopsadoptionsegmentnamespace"></a>`namespace` | [`Namespace`](#namespace) | Namespace which should be calculated. | | <a id="devopsadoptionsegmentnamespace"></a>`namespace` | [`Namespace`](#namespace) | Namespace which should be calculated. |
### `DevopsAdoptionSnapshot` ### `DevopsAdoptionSnapshot`
...@@ -14997,11 +14997,11 @@ A `AlertManagementHttpIntegrationID` is a global ID. It is encoded as a string. ...@@ -14997,11 +14997,11 @@ A `AlertManagementHttpIntegrationID` is a global ID. It is encoded as a string.
An example `AlertManagementHttpIntegrationID` is: `"gid://gitlab/AlertManagement::HttpIntegration/1"`. An example `AlertManagementHttpIntegrationID` is: `"gid://gitlab/AlertManagement::HttpIntegration/1"`.
### `AnalyticsDevopsAdoptionSegmentID` ### `AnalyticsDevopsAdoptionEnabledNamespaceID`
A `AnalyticsDevopsAdoptionSegmentID` is a global ID. It is encoded as a string. A `AnalyticsDevopsAdoptionEnabledNamespaceID` is a global ID. It is encoded as a string.
An example `AnalyticsDevopsAdoptionSegmentID` is: `"gid://gitlab/Analytics::DevopsAdoption::Segment/1"`. An example `AnalyticsDevopsAdoptionEnabledNamespaceID` is: `"gid://gitlab/Analytics::DevopsAdoption::EnabledNamespace/1"`.
### `AwardableID` ### `AwardableID`
......
...@@ -13,7 +13,7 @@ module EE ...@@ -13,7 +13,7 @@ module EE
end end
def show_adoption? def show_adoption?
feature_already_in_use = ::Analytics::DevopsAdoption::Segment.any? feature_already_in_use = ::Analytics::DevopsAdoption::EnabledNamespace.any?
::License.feature_available?(:devops_adoption) && ::License.feature_available?(:devops_adoption) &&
(feature_already_in_use || ::Feature.enabled?(:devops_adoption_feature, default_enabled: :yaml)) (feature_already_in_use || ::Feature.enabled?(:devops_adoption_feature, default_enabled: :yaml))
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
module Analytics module Analytics
module DevopsAdoption module DevopsAdoption
class SegmentsFinder class EnabledNamespacesFinder
attr_reader :params, :current_user attr_reader :params, :current_user
def initialize(current_user, params:) def initialize(current_user, params:)
...@@ -11,7 +11,7 @@ module Analytics ...@@ -11,7 +11,7 @@ module Analytics
end end
def execute def execute
scope = ::Analytics::DevopsAdoption::Segment.ordered_by_name scope = ::Analytics::DevopsAdoption::EnabledNamespace.ordered_by_name
by_display_namespace(scope) by_display_namespace(scope)
end end
......
...@@ -66,9 +66,9 @@ module EE ...@@ -66,9 +66,9 @@ module EE
mount_mutation ::Mutations::DastSiteTokens::Create mount_mutation ::Mutations::DastSiteTokens::Create
mount_mutation ::Mutations::Namespaces::IncreaseStorageTemporarily mount_mutation ::Mutations::Namespaces::IncreaseStorageTemporarily
mount_mutation ::Mutations::QualityManagement::TestCases::Create mount_mutation ::Mutations::QualityManagement::TestCases::Create
mount_mutation ::Mutations::Analytics::DevopsAdoption::Segments::Create mount_mutation ::Mutations::Analytics::DevopsAdoption::EnabledNamespaces::Enable
mount_mutation ::Mutations::Analytics::DevopsAdoption::Segments::BulkFindOrCreate mount_mutation ::Mutations::Analytics::DevopsAdoption::EnabledNamespaces::BulkEnable
mount_mutation ::Mutations::Analytics::DevopsAdoption::Segments::Delete mount_mutation ::Mutations::Analytics::DevopsAdoption::EnabledNamespaces::Disable
mount_mutation ::Mutations::IncidentManagement::OncallSchedule::Create mount_mutation ::Mutations::IncidentManagement::OncallSchedule::Create
mount_mutation ::Mutations::IncidentManagement::OncallSchedule::Update mount_mutation ::Mutations::IncidentManagement::OncallSchedule::Update
mount_mutation ::Mutations::IncidentManagement::OncallSchedule::Destroy mount_mutation ::Mutations::IncidentManagement::OncallSchedule::Destroy
......
...@@ -57,10 +57,10 @@ module EE ...@@ -57,10 +57,10 @@ module EE
resolver: ::Resolvers::InstanceSecurityDashboardResolver, resolver: ::Resolvers::InstanceSecurityDashboardResolver,
description: 'Fields related to Instance Security Dashboard.' description: 'Fields related to Instance Security Dashboard.'
field :devops_adoption_segments, ::Types::Admin::Analytics::DevopsAdoption::SegmentType.connection_type, field :devops_adoption_enabled_namespaces, ::Types::Analytics::DevopsAdoption::EnabledNamespaceType.connection_type,
null: true, null: true,
description: 'Get configured DevOps adoption segments on the instance. **BETA** This endpoint is subject to change without notice.', description: 'Get configured DevOps adoption namespaces. **BETA** This endpoint is subject to change without notice.',
resolver: ::Resolvers::Admin::Analytics::DevopsAdoption::SegmentsResolver resolver: ::Resolvers::Analytics::DevopsAdoption::EnabledNamespacesResolver
field :current_license, ::Types::Admin::CloudLicenses::CurrentLicenseType, field :current_license, ::Types::Admin::CloudLicenses::CurrentLicenseType,
null: true, null: true,
......
...@@ -3,40 +3,40 @@ ...@@ -3,40 +3,40 @@
module Mutations module Mutations
module Analytics module Analytics
module DevopsAdoption module DevopsAdoption
module Segments module EnabledNamespaces
class BulkFindOrCreate < BaseMutation class BulkEnable < BaseMutation
include Mixins::CommonMethods include Mixins::CommonMethods
graphql_name 'BulkFindOrCreateDevopsAdoptionSegments' graphql_name 'BulkEnableDevopsAdoptionNamespaces'
description '**BETA** This endpoint is subject to change without notice.' description '**BETA** This endpoint is subject to change without notice.'
argument :namespace_ids, [::Types::GlobalIDType[::Namespace]], argument :namespace_ids, [::Types::GlobalIDType[::Namespace]],
required: true, required: true,
description: 'List of Namespace IDs for the segments.' description: 'List of Namespace IDs.'
argument :display_namespace_id, ::Types::GlobalIDType[::Namespace], argument :display_namespace_id, ::Types::GlobalIDType[::Namespace],
required: false, required: false,
description: 'Display namespace ID.' description: 'Display namespace ID.'
field :segments, field :enabled_namespaces,
[::Types::Admin::Analytics::DevopsAdoption::SegmentType], [::Types::Analytics::DevopsAdoption::EnabledNamespaceType],
null: true, null: true,
description: 'Created segments after mutation.' description: 'Enabled namespaces after mutation.'
def resolve(namespace_ids:, display_namespace_id: nil, **) def resolve(namespace_ids:, display_namespace_id: nil, **)
namespaces = GlobalID::Locator.locate_many(namespace_ids) namespaces = GlobalID::Locator.locate_many(namespace_ids)
display_namespace = Gitlab::Graphql::Lazy.force(GitlabSchema.find_by_gid(display_namespace_id)) display_namespace = Gitlab::Graphql::Lazy.force(GitlabSchema.find_by_gid(display_namespace_id))
with_authorization_handler do with_authorization_handler do
service = ::Analytics::DevopsAdoption::Segments::BulkFindOrCreateService service = ::Analytics::DevopsAdoption::EnabledNamespaces::BulkFindOrCreateService
.new(current_user: current_user, params: { namespaces: namespaces, display_namespace: display_namespace }) .new(current_user: current_user, params: { namespaces: namespaces, display_namespace: display_namespace })
segments = service.execute.payload.fetch(:segments) enabled_namespaces = service.execute.payload.fetch(:enabled_namespaces)
{ {
segments: segments.select(&:persisted?), enabled_namespaces: enabled_namespaces.select(&:persisted?),
errors: segments.sum { |segment| errors_on_object(segment) } errors: enabled_namespaces.sum { |ns| errors_on_object(ns) }
} }
end end
end end
......
...@@ -3,28 +3,28 @@ ...@@ -3,28 +3,28 @@
module Mutations module Mutations
module Analytics module Analytics
module DevopsAdoption module DevopsAdoption
module Segments module EnabledNamespaces
class Delete < BaseMutation class Disable < BaseMutation
include Mixins::CommonMethods include Mixins::CommonMethods
graphql_name 'DeleteDevopsAdoptionSegment' graphql_name 'DisableDevopsAdoptionNamespace'
description '**BETA** This endpoint is subject to change without notice.' description '**BETA** This endpoint is subject to change without notice.'
argument :id, [::Types::GlobalIDType[::Analytics::DevopsAdoption::Segment]], argument :id, [::Types::GlobalIDType[::Analytics::DevopsAdoption::EnabledNamespace]],
required: true, required: true,
description: 'One or many IDs of the segments to delete.' description: 'One or many IDs of the enabled namespaces to disable.'
def resolve(id:, **) def resolve(id:, **)
segments = GlobalID::Locator.locate_many(id) enabled_namespaces = GlobalID::Locator.locate_many(id)
with_authorization_handler do with_authorization_handler do
service = ::Analytics::DevopsAdoption::Segments::BulkDeleteService service = ::Analytics::DevopsAdoption::EnabledNamespaces::BulkDeleteService
.new(segments: segments, current_user: current_user) .new(enabled_namespaces: enabled_namespaces, current_user: current_user)
response = service.execute response = service.execute
errors = response.payload[:segments].sum { |segment| errors_on_object(segment) } errors = response.payload[:enabled_namespaces].sum { |ns| errors_on_object(ns) }
{ errors: errors } { errors: errors }
end end
......
...@@ -3,38 +3,38 @@ ...@@ -3,38 +3,38 @@
module Mutations module Mutations
module Analytics module Analytics
module DevopsAdoption module DevopsAdoption
module Segments module EnabledNamespaces
class Create < BaseMutation class Enable < BaseMutation
include Mixins::CommonMethods include Mixins::CommonMethods
graphql_name 'CreateDevopsAdoptionSegment' graphql_name 'EnableDevopsAdoptionNamespace'
description '**BETA** This endpoint is subject to change without notice.' description '**BETA** This endpoint is subject to change without notice.'
argument :namespace_id, ::Types::GlobalIDType[::Namespace], argument :namespace_id, ::Types::GlobalIDType[::Namespace],
required: true, required: true,
description: 'Namespace ID to set for the segment.' description: 'Namespace ID.'
argument :display_namespace_id, ::Types::GlobalIDType[::Namespace], argument :display_namespace_id, ::Types::GlobalIDType[::Namespace],
required: false, required: false,
description: 'Display namespace ID.' description: 'Display namespace ID.'
field :segment, field :enabled_namespace,
Types::Admin::Analytics::DevopsAdoption::SegmentType, Types::Analytics::DevopsAdoption::EnabledNamespaceType,
null: true, null: true,
description: 'The segment after mutation.' description: 'Enabled namespace after mutation.'
def resolve(namespace_id:, display_namespace_id: nil, **) def resolve(namespace_id:, display_namespace_id: nil, **)
namespace = Gitlab::Graphql::Lazy.force(GitlabSchema.find_by_gid(namespace_id)) namespace = Gitlab::Graphql::Lazy.force(GitlabSchema.find_by_gid(namespace_id))
display_namespace = Gitlab::Graphql::Lazy.force(GitlabSchema.find_by_gid(display_namespace_id)) display_namespace = Gitlab::Graphql::Lazy.force(GitlabSchema.find_by_gid(display_namespace_id))
with_authorization_handler do with_authorization_handler do
service = ::Analytics::DevopsAdoption::Segments::CreateService service = ::Analytics::DevopsAdoption::EnabledNamespaces::CreateService
.new(current_user: current_user, params: { namespace: namespace, display_namespace: display_namespace }) .new(current_user: current_user, params: { namespace: namespace, display_namespace: display_namespace })
response = service.execute response = service.execute
resolve_segment(response) resolve_enabled_namespace(response)
end end
end end
end end
......
...@@ -3,23 +3,23 @@ ...@@ -3,23 +3,23 @@
module Mutations module Mutations
module Analytics module Analytics
module DevopsAdoption module DevopsAdoption
module Segments module EnabledNamespaces
module Mixins module Mixins
module CommonMethods module CommonMethods
private private
def resolve_segment(response) def resolve_enabled_namespace(response)
segment = response.payload.fetch(:segment) enabled_namespace = response.payload.fetch(:enabled_namespace)
{ {
segment: response.success? ? response.payload.fetch(:segment) : nil, enabled_namespace: response.success? ? enabled_namespace : nil,
errors: errors_on_object(segment) errors: errors_on_object(enabled_namespace)
} }
end end
def with_authorization_handler def with_authorization_handler
yield yield
rescue ::Analytics::DevopsAdoption::Segments::AuthorizationError => e rescue ::Analytics::DevopsAdoption::EnabledNamespaces::AuthorizationError => e
handle_unauthorized!(e) handle_unauthorized!(e)
end end
......
# frozen_string_literal: true
module Resolvers
module Admin
module Analytics
module DevopsAdoption
class SegmentsResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource
include Gitlab::Allowable
type Types::Admin::Analytics::DevopsAdoption::SegmentType, null: true
argument :display_namespace_id, ::Types::GlobalIDType[::Namespace],
required: false,
description: 'Filter by display namespace.'
def resolve(display_namespace_id: nil, **)
display_namespace_id = GlobalID.parse(display_namespace_id)
display_namespace = Gitlab::Graphql::Lazy.force(GitlabSchema.find_by_gid(display_namespace_id))
authorize!(display_namespace)
::Analytics::DevopsAdoption::SegmentsFinder.new(current_user, params: {
display_namespace: display_namespace
}).execute
end
private
def authorize!(display_namespace)
display_namespace ? authorize_with_namespace!(display_namespace) : authorize_global!
end
def authorize_global!
unless can?(current_user, :view_instance_devops_adoption)
raise_resource_not_available_error!
end
end
def authorize_with_namespace!(display_namespace)
unless can?(current_user, :view_group_devops_adoption, display_namespace)
raise_resource_not_available_error!
end
end
end
end
end
end
end
# frozen_string_literal: true
module Resolvers
module Analytics
module DevopsAdoption
class EnabledNamespacesResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource
include Gitlab::Allowable
type Types::Analytics::DevopsAdoption::EnabledNamespaceType, null: true
argument :display_namespace_id, ::Types::GlobalIDType[::Namespace],
required: false,
description: 'Filter by display namespace.'
def resolve(display_namespace_id: nil, **)
display_namespace_id = GlobalID.parse(display_namespace_id)
display_namespace = Gitlab::Graphql::Lazy.force(GitlabSchema.find_by_gid(display_namespace_id))
authorize!(display_namespace)
::Analytics::DevopsAdoption::EnabledNamespacesFinder.new(current_user, params: {
display_namespace: display_namespace
}).execute
end
private
def authorize!(display_namespace)
display_namespace ? authorize_with_namespace!(display_namespace) : authorize_global!
end
def authorize_global!
unless can?(current_user, :view_instance_devops_adoption)
raise_resource_not_available_error!
end
end
def authorize_with_namespace!(display_namespace)
unless can?(current_user, :view_group_devops_adoption, display_namespace)
raise_resource_not_available_error!
end
end
end
end
end
end
# frozen_string_literal: true
# rubocop:disable Graphql/AuthorizeTypes
module Types
module Admin
module Analytics
module DevopsAdoption
class SegmentType < BaseObject
graphql_name 'DevopsAdoptionSegment'
description 'Segment'
field :id, GraphQL::ID_TYPE, null: false,
description: "ID of the segment."
field :namespace, Types::NamespaceType, null: true,
description: 'Namespace which should be calculated.'
field :display_namespace, Types::NamespaceType, null: true,
description: 'Namespace where data should be displayed.'
field :latest_snapshot, SnapshotType, null: true,
description: 'The latest adoption metrics for the segment.'
def latest_snapshot
BatchLoader::GraphQL.for(object.namespace_id).batch(key: :devops_adoption_latest_snapshots) do |ids, loader, args|
snapshots = ::Analytics::DevopsAdoption::Snapshot
.latest_snapshot_for_namespace_ids(ids)
.index_by(&:namespace_id)
ids.each do |id|
loader.call(id, snapshots[id])
end
end
end
end
end
end
end
end
# frozen_string_literal: true
# rubocop:disable Graphql/AuthorizeTypes
module Types
module Admin
module Analytics
module DevopsAdoption
class SnapshotType < BaseObject
graphql_name 'DevopsAdoptionSnapshot'
description 'Snapshot'
field :issue_opened, GraphQL::BOOLEAN_TYPE, null: false,
description: 'At least one issue was opened.'
field :merge_request_opened, GraphQL::BOOLEAN_TYPE, null: false,
description: 'At least one merge request was opened.'
field :merge_request_approved, GraphQL::BOOLEAN_TYPE, null: false,
description: 'At least one merge request was approved.'
field :runner_configured, GraphQL::BOOLEAN_TYPE, null: false,
description: 'At least one runner was used.'
field :pipeline_succeeded, GraphQL::BOOLEAN_TYPE, null: false,
description: 'At least one pipeline succeeded.'
field :deploy_succeeded, GraphQL::BOOLEAN_TYPE, null: false,
description: 'At least one deployment succeeded.'
field :security_scan_succeeded, GraphQL::BOOLEAN_TYPE, null: false,
description: 'At least one security scan succeeded.'
field :code_owners_used_count, GraphQL::INT_TYPE, null: true,
description: 'Total number of projects with existing CODEOWNERS file.'
field :total_projects_count, GraphQL::INT_TYPE, null: true,
description: 'Total number of projects.'
field :recorded_at, Types::TimeType, null: false,
description: 'The time the snapshot was recorded.'
field :start_time, Types::TimeType, null: false,
description: 'The start time for the snapshot where the data points were collected.'
field :end_time, Types::TimeType, null: false,
description: 'The end time for the snapshot where the data points were collected.'
end
end
end
end
end
# frozen_string_literal: true
# rubocop:disable Graphql/AuthorizeTypes
module Types
module Analytics
module DevopsAdoption
class EnabledNamespaceType < BaseObject
graphql_name 'DevopsAdoptionSegment'
description 'Enabled namespace for DevopsAdoption'
field :id, GraphQL::ID_TYPE, null: false,
description: "ID of the enabled namespace."
field :namespace, Types::NamespaceType, null: true,
description: 'Namespace which should be calculated.'
field :display_namespace, Types::NamespaceType, null: true,
description: 'Namespace where data should be displayed.'
field :latest_snapshot, SnapshotType, null: true,
description: 'The latest adoption metrics for the enabled namespace.'
def latest_snapshot
BatchLoader::GraphQL.for(object.namespace_id).batch(key: :devops_adoption_latest_snapshots) do |ids, loader, args|
snapshots = ::Analytics::DevopsAdoption::Snapshot
.latest_snapshot_for_namespace_ids(ids)
.index_by(&:namespace_id)
ids.each do |id|
loader.call(id, snapshots[id])
end
end
end
end
end
end
end
# frozen_string_literal: true
# rubocop:disable Graphql/AuthorizeTypes
module Types
module Analytics
module DevopsAdoption
class SnapshotType < BaseObject
graphql_name 'DevopsAdoptionSnapshot'
description 'Snapshot'
field :issue_opened, GraphQL::BOOLEAN_TYPE, null: false,
description: 'At least one issue was opened.'
field :merge_request_opened, GraphQL::BOOLEAN_TYPE, null: false,
description: 'At least one merge request was opened.'
field :merge_request_approved, GraphQL::BOOLEAN_TYPE, null: false,
description: 'At least one merge request was approved.'
field :runner_configured, GraphQL::BOOLEAN_TYPE, null: false,
description: 'At least one runner was used.'
field :pipeline_succeeded, GraphQL::BOOLEAN_TYPE, null: false,
description: 'At least one pipeline succeeded.'
field :deploy_succeeded, GraphQL::BOOLEAN_TYPE, null: false,
description: 'At least one deployment succeeded.'
field :security_scan_succeeded, GraphQL::BOOLEAN_TYPE, null: false,
description: 'At least one security scan succeeded.'
field :code_owners_used_count, GraphQL::INT_TYPE, null: true,
description: 'Total number of projects with existing CODEOWNERS file.'
field :total_projects_count, GraphQL::INT_TYPE, null: true,
description: 'Total number of projects.'
field :recorded_at, Types::TimeType, null: false,
description: 'The time the snapshot was recorded.'
field :start_time, Types::TimeType, null: false,
description: 'The start time for the snapshot where the data points were collected.'
field :end_time, Types::TimeType, null: false,
description: 'The end time for the snapshot where the data points were collected.'
end
end
end
end
# frozen_string_literal: true # frozen_string_literal: true
class Analytics::DevopsAdoption::Segment < ApplicationRecord class Analytics::DevopsAdoption::EnabledNamespace < ApplicationRecord
self.table_name = 'analytics_devops_adoption_segments'
include IgnorableColumns include IgnorableColumns
belongs_to :namespace belongs_to :namespace
......
...@@ -5,7 +5,7 @@ class Analytics::DevopsAdoption::Snapshot < ApplicationRecord ...@@ -5,7 +5,7 @@ class Analytics::DevopsAdoption::Snapshot < ApplicationRecord
belongs_to :namespace belongs_to :namespace
has_many :segments, foreign_key: :namespace_id, primary_key: :namespace_id has_many :enabled_namespaces, foreign_key: :namespace_id, primary_key: :namespace_id
validates :namespace, presence: true validates :namespace, presence: true
validates :recorded_at, presence: true validates :recorded_at, presence: true
......
...@@ -36,7 +36,7 @@ module EE ...@@ -36,7 +36,7 @@ module EE
rule { ~anonymous & operations_dashboard_available }.enable :read_operations_dashboard rule { ~anonymous & operations_dashboard_available }.enable :read_operations_dashboard
rule { admin & instance_devops_adoption_available }.policy do rule { admin & instance_devops_adoption_available }.policy do
enable :manage_devops_adoption_segments enable :manage_devops_adoption_namespaces
enable :view_instance_devops_adoption enable :view_instance_devops_adoption
end end
......
...@@ -186,12 +186,12 @@ module EE ...@@ -186,12 +186,12 @@ module EE
end end
rule { reporter & group_devops_adoption_enabled & group_devops_adoption_available }.policy do rule { reporter & group_devops_adoption_enabled & group_devops_adoption_available }.policy do
enable :manage_devops_adoption_segments enable :manage_devops_adoption_namespaces
enable :view_group_devops_adoption enable :view_group_devops_adoption
end end
rule { admin & group_devops_adoption_enabled }.policy do rule { admin & group_devops_adoption_enabled }.policy do
enable :manage_devops_adoption_segments enable :manage_devops_adoption_namespaces
end end
rule { owner & ~has_parent & prevent_group_forking_available }.policy do rule { owner & ~has_parent & prevent_group_forking_available }.policy do
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
module Analytics module Analytics
module DevopsAdoption module DevopsAdoption
module Segments module EnabledNamespaces
class AuthorizationError < StandardError class AuthorizationError < StandardError
attr_reader :service attr_reader :service
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
module Analytics module Analytics
module DevopsAdoption module DevopsAdoption
module Segments module EnabledNamespaces
class BulkDeleteService class BulkDeleteService
def initialize(segments:, current_user:) def initialize(enabled_namespaces:, current_user:)
@segments = segments @enabled_namespaces = enabled_namespaces
@current_user = current_user @current_user = current_user
end end
...@@ -32,15 +32,15 @@ module Analytics ...@@ -32,15 +32,15 @@ module Analytics
private private
attr_reader :segments, :current_user attr_reader :enabled_namespaces, :current_user
def response_payload def response_payload
{ segments: segments } { enabled_namespaces: enabled_namespaces }
end end
def deletion_services def deletion_services
@deletion_services ||= segments.map do |segment| @deletion_services ||= enabled_namespaces.map do |ns|
DeleteService.new(current_user: current_user, segment: segment) DeleteService.new(current_user: current_user, enabled_namespace: ns)
end end
end end
end end
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
module Analytics module Analytics
module DevopsAdoption module DevopsAdoption
module Segments module EnabledNamespaces
class BulkFindOrCreateService class BulkFindOrCreateService
def initialize(params: {}, current_user:) def initialize(params: {}, current_user:)
@params = params @params = params
...@@ -12,11 +12,11 @@ module Analytics ...@@ -12,11 +12,11 @@ module Analytics
def execute def execute
authorize! authorize!
segments = services.map do |service| enabled_namespaces = services.map do |service|
service.execute.payload[:segment] service.execute.payload[:enabled_namespace]
end end
ServiceResponse.success(payload: { segments: segments }) ServiceResponse.success(payload: { enabled_namespaces: enabled_namespaces })
end end
def authorize! def authorize!
......
...@@ -2,16 +2,16 @@ ...@@ -2,16 +2,16 @@
module Analytics module Analytics
module DevopsAdoption module DevopsAdoption
module Segments module EnabledNamespaces
module CommonMethods module CommonMethods
include Gitlab::Allowable include Gitlab::Allowable
def authorize! def authorize!
unless can?(current_user, :manage_devops_adoption_segments, namespace) unless can?(current_user, :manage_devops_adoption_namespaces, namespace)
raise AuthorizationError.new(self, 'Forbidden') raise AuthorizationError.new(self, 'Forbidden')
end end
unless can?(current_user, :manage_devops_adoption_segments, display_namespace || :global) unless can?(current_user, :manage_devops_adoption_namespaces, display_namespace || :global)
raise AuthorizationError.new(self, 'Forbidden') raise AuthorizationError.new(self, 'Forbidden')
end end
end end
......
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
module Analytics module Analytics
module DevopsAdoption module DevopsAdoption
module Segments module EnabledNamespaces
class CreateService class CreateService
include CommonMethods include CommonMethods
def initialize(segment: Analytics::DevopsAdoption::Segment.new, params: {}, current_user:) def initialize(enabled_namespace: Analytics::DevopsAdoption::EnabledNamespace.new, params: {}, current_user:)
@segment = segment @enabled_namespace = enabled_namespace
@params = params @params = params
@current_user = current_user @current_user = current_user
end end
...@@ -15,10 +15,10 @@ module Analytics ...@@ -15,10 +15,10 @@ module Analytics
def execute def execute
authorize! authorize!
segment.assign_attributes(namespace: namespace, display_namespace: display_namespace) enabled_namespace.assign_attributes(namespace: namespace, display_namespace: display_namespace)
if segment.save if enabled_namespace.save
Analytics::DevopsAdoption::CreateSnapshotWorker.perform_async(segment.id) Analytics::DevopsAdoption::CreateSnapshotWorker.perform_async(enabled_namespace.id)
ServiceResponse.success(payload: response_payload) ServiceResponse.success(payload: response_payload)
else else
...@@ -28,10 +28,10 @@ module Analytics ...@@ -28,10 +28,10 @@ module Analytics
private private
attr_reader :segment attr_reader :enabled_namespace
def response_payload def response_payload
{ segment: segment } { enabled_namespace: enabled_namespace }
end end
end end
end end
......
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
module Analytics module Analytics
module DevopsAdoption module DevopsAdoption
module Segments module EnabledNamespaces
class DeleteService class DeleteService
include CommonMethods include CommonMethods
def initialize(segment:, current_user:) def initialize(enabled_namespace:, current_user:)
@segment = segment @enabled_namespace = enabled_namespace
@current_user = current_user @current_user = current_user
end end
...@@ -15,22 +15,22 @@ module Analytics ...@@ -15,22 +15,22 @@ module Analytics
authorize! authorize!
begin begin
segment.destroy! enabled_namespace.destroy!
ServiceResponse.success(payload: response_payload) ServiceResponse.success(payload: response_payload)
rescue ActiveRecord::RecordNotDestroyed rescue ActiveRecord::RecordNotDestroyed
ServiceResponse.error(message: 'DevOps Adoption Segment deletion error', payload: response_payload) ServiceResponse.error(message: 'DevOps Adoption EnabledNamespace deletion error', payload: response_payload)
end end
end end
private private
attr_reader :segment attr_reader :enabled_namespace
delegate :namespace, :display_namespace, to: :segment delegate :namespace, :display_namespace, to: :enabled_namespace
def response_payload def response_payload
{ segment: segment } { enabled_namespace: enabled_namespace }
end end
end end
end end
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
module Analytics module Analytics
module DevopsAdoption module DevopsAdoption
module Segments module EnabledNamespaces
class FindOrCreateService class FindOrCreateService
include CommonMethods include CommonMethods
...@@ -17,10 +17,10 @@ module Analytics ...@@ -17,10 +17,10 @@ module Analytics
def execute def execute
authorize! authorize!
segment = Analytics::DevopsAdoption::Segment.find_by(namespace_id: namespace.id, display_namespace_id: display_namespace&.id) enabled_namespace = Analytics::DevopsAdoption::EnabledNamespace.find_by(namespace_id: namespace.id, display_namespace_id: display_namespace&.id)
if segment if enabled_namespace
ServiceResponse.success(payload: { segment: segment }) ServiceResponse.success(payload: { enabled_namespace: enabled_namespace })
else else
create_service.execute create_service.execute
end end
......
...@@ -4,10 +4,10 @@ module Analytics ...@@ -4,10 +4,10 @@ module Analytics
module DevopsAdoption module DevopsAdoption
module Snapshots module Snapshots
class CalculateAndSaveService class CalculateAndSaveService
attr_reader :segment, :range_end attr_reader :enabled_namespace, :range_end
def initialize(segment:, range_end:) def initialize(enabled_namespace:, range_end:)
@segment = segment @enabled_namespace = enabled_namespace
@range_end = range_end @range_end = range_end
end end
...@@ -20,11 +20,11 @@ module Analytics ...@@ -20,11 +20,11 @@ module Analytics
end end
def snapshot def snapshot
@snapshot ||= segment.snapshots.for_month(range_end).first @snapshot ||= enabled_namespace.snapshots.for_month(range_end).first
end end
def calculated_data def calculated_data
@calculated_data ||= SnapshotCalculator.new(segment: segment, range_end: range_end, snapshot: snapshot).calculate @calculated_data ||= SnapshotCalculator.new(enabled_namespace: enabled_namespace, range_end: range_end, snapshot: snapshot).calculate
end end
end end
end end
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
module Analytics module Analytics
module DevopsAdoption module DevopsAdoption
# Schedules update of snapshots for all segments # Schedules update of snapshots for all enabled_namespaces
class CreateAllSnapshotsWorker class CreateAllSnapshotsWorker
include ApplicationWorker include ApplicationWorker
...@@ -18,8 +18,8 @@ module Analytics ...@@ -18,8 +18,8 @@ module Analytics
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def perform def perform
::Analytics::DevopsAdoption::Segment.all.pluck(:id).each.with_index do |segment_id, i| ::Analytics::DevopsAdoption::EnabledNamespace.all.pluck(:id).each.with_index do |enabled_namespace_id, i|
CreateSnapshotWorker.perform_in(i * WORKERS_GAP, segment_id) CreateSnapshotWorker.perform_in(i * WORKERS_GAP, enabled_namespace_id)
end end
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
module Analytics module Analytics
module DevopsAdoption module DevopsAdoption
# Updates all pending snapshots for given segment (from previous month) # Updates all pending snapshots for given enabled_namespace (from previous month)
# and creates or update snapshot for current month # and creates or update snapshot for current month
class CreateSnapshotWorker class CreateSnapshotWorker
include ApplicationWorker include ApplicationWorker
...@@ -13,21 +13,19 @@ module Analytics ...@@ -13,21 +13,19 @@ module Analytics
idempotent! idempotent!
tags :exclude_from_kubernetes tags :exclude_from_kubernetes
# range_end was deprecated and must be removed in 14.0 def perform(enabled_namespace_id)
# enabled_namespace = EnabledNamespace.find(enabled_namespace_id)
def perform(segment_id, _deprecated_range_end = nil)
segment = Segment.find(segment_id)
pending_ranges(segment).each do |range_end| pending_ranges(enabled_namespace).each do |range_end|
Snapshots::CalculateAndSaveService.new(segment: segment, range_end: range_end).execute Snapshots::CalculateAndSaveService.new(enabled_namespace: enabled_namespace, range_end: range_end).execute
end end
end end
private private
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def pending_ranges(segment) def pending_ranges(enabled_namespace)
end_times = segment.snapshots.not_finalized.pluck(:end_time) end_times = enabled_namespace.snapshots.not_finalized.pluck(:end_time)
now = Time.zone.now now = Time.zone.now
......
...@@ -8,14 +8,14 @@ Gitlab::Seeder.quiet do ...@@ -8,14 +8,14 @@ Gitlab::Seeder.quiet do
groups = groups.sample(2) groups = groups.sample(2)
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
segments = [ enabled_namespaces = [
Analytics::DevopsAdoption::Segment.create(namespace: groups.first, display_namespace: groups.first), Analytics::DevopsAdoption::EnabledNamespace.create(namespace: groups.first, display_namespace: groups.first),
Analytics::DevopsAdoption::Segment.create(namespace: groups.last, display_namespace: groups.last) Analytics::DevopsAdoption::EnabledNamespace.create(namespace: groups.last, display_namespace: groups.last)
] ]
if segments.any?(&:invalid?) if enabled_namespaces.any?(&:invalid?)
puts "Error creating segments" puts "Error creating enabled_namespaces"
puts "#{segments.map(&:errors)}" puts "#{enabled_namespaces.map(&:errors)}"
next next
end end
...@@ -25,9 +25,9 @@ Gitlab::Seeder.quiet do ...@@ -25,9 +25,9 @@ Gitlab::Seeder.quiet do
4.downto(0).each do |index| 4.downto(0).each do |index|
end_time = index.months.ago.at_end_of_month end_time = index.months.ago.at_end_of_month
segments.each do |segment| enabled_namespaces.each do |enabled_namespace|
calculated_data = { calculated_data = {
namespace: segment.namespace, namespace: enabled_namespace.namespace,
issue_opened: booleans.sample, issue_opened: booleans.sample,
merge_request_opened: booleans.sample, merge_request_opened: booleans.sample,
merge_request_approved: booleans.sample, merge_request_approved: booleans.sample,
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
module Analytics module Analytics
module DevopsAdoption module DevopsAdoption
class SnapshotCalculator class SnapshotCalculator
attr_reader :segment, :range_end, :range_start, :snapshot attr_reader :enabled_namespace, :range_end, :range_start, :snapshot
BOOLEAN_METRICS = [ BOOLEAN_METRICS = [
:issue_opened, :issue_opened,
...@@ -22,15 +22,15 @@ module Analytics ...@@ -22,15 +22,15 @@ module Analytics
ADOPTION_METRICS = BOOLEAN_METRICS + NUMERIC_METRICS ADOPTION_METRICS = BOOLEAN_METRICS + NUMERIC_METRICS
def initialize(segment:, range_end:, snapshot: nil) def initialize(enabled_namespace:, range_end:, snapshot: nil)
@segment = segment @enabled_namespace = enabled_namespace
@range_end = range_end @range_end = range_end
@range_start = Snapshot.new(end_time: range_end).start_time @range_start = Snapshot.new(end_time: range_end).start_time
@snapshot = snapshot @snapshot = snapshot
end end
def calculate def calculate
params = { recorded_at: Time.zone.now, end_time: range_end, namespace: segment.namespace } params = { recorded_at: Time.zone.now, end_time: range_end, namespace: enabled_namespace.namespace }
BOOLEAN_METRICS.each do |metric| BOOLEAN_METRICS.each do |metric|
params[metric] = snapshot&.public_send(metric) || send(metric) # rubocop:disable GitlabSecurity/PublicSend params[metric] = snapshot&.public_send(metric) || send(metric) # rubocop:disable GitlabSecurity/PublicSend
...@@ -46,7 +46,7 @@ module Analytics ...@@ -46,7 +46,7 @@ module Analytics
private private
def snapshot_groups def snapshot_groups
@snapshot_groups ||= segment.namespace.self_and_descendants @snapshot_groups ||= enabled_namespace.namespace.self_and_descendants
end end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
...@@ -105,7 +105,7 @@ module Analytics ...@@ -105,7 +105,7 @@ module Analytics
end end
def code_owners_used_count def code_owners_used_count
return unless Feature.enabled?(:analytics_devops_adoption_codeowners, segment.namespace, default_enabled: :yaml) return unless Feature.enabled?(:analytics_devops_adoption_codeowners, enabled_namespace.namespace, default_enabled: :yaml)
snapshot_projects.count do |project| snapshot_projects.count do |project|
!Gitlab::CodeOwners::Loader.new(project, project.default_branch || 'HEAD').empty_code_owners? !Gitlab::CodeOwners::Loader.new(project, project.default_branch || 'HEAD').empty_code_owners?
......
...@@ -13,8 +13,8 @@ RSpec.describe Admin::DevOpsReportController do ...@@ -13,8 +13,8 @@ RSpec.describe Admin::DevOpsReportController do
stub_licensed_features(devops_adoption: true) stub_licensed_features(devops_adoption: true)
end end
it 'is true if there are any segments' do it 'is true if there are any enabled_namespaces' do
create(:devops_adoption_segment) create(:devops_adoption_enabled_namespace)
expect(controller.show_adoption?).to be true expect(controller.show_adoption?).to be true
end end
......
# frozen_string_literal: true # frozen_string_literal: true
FactoryBot.define do FactoryBot.define do
factory :devops_adoption_segment, class: 'Analytics::DevopsAdoption::Segment' do factory :devops_adoption_enabled_namespace, class: 'Analytics::DevopsAdoption::EnabledNamespace' do
association :namespace, factory: :group association :namespace, factory: :group
association :display_namespace, factory: :group association :display_namespace, factory: :group
end end
......
...@@ -2,19 +2,19 @@ ...@@ -2,19 +2,19 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Analytics::DevopsAdoption::SegmentsFinder do RSpec.describe Analytics::DevopsAdoption::EnabledNamespacesFinder do
let_it_be(:admin_user) { create(:user, :admin) } let_it_be(:admin_user) { create(:user, :admin) }
subject(:finder_segments) { described_class.new(admin_user, params: params).execute } subject(:finder) { described_class.new(admin_user, params: params).execute }
let(:params) { {} } let(:params) { {} }
describe '#execute' do describe '#execute' do
let_it_be(:root_group_1) { create(:group, name: 'bbb') } let_it_be(:root_group_1) { create(:group, name: 'bbb') }
let_it_be(:segment_1) { create(:devops_adoption_segment, namespace: root_group_1, display_namespace: nil) } let_it_be(:enabled_namespace_1) { create(:devops_adoption_enabled_namespace, namespace: root_group_1, display_namespace: nil) }
let_it_be(:segment_2) { create(:devops_adoption_segment, namespace: root_group_1, display_namespace: root_group_1) } let_it_be(:enabled_namespace_2) { create(:devops_adoption_enabled_namespace, namespace: root_group_1, display_namespace: root_group_1) }
let_it_be(:segment_3) { create(:devops_adoption_segment) } let_it_be(:enabled_namespace_3) { create(:devops_adoption_enabled_namespace) }
before do before do
stub_licensed_features(instance_level_devops_adoption: true) stub_licensed_features(instance_level_devops_adoption: true)
...@@ -24,14 +24,14 @@ RSpec.describe Analytics::DevopsAdoption::SegmentsFinder do ...@@ -24,14 +24,14 @@ RSpec.describe Analytics::DevopsAdoption::SegmentsFinder do
context 'with display_namespace provided' do context 'with display_namespace provided' do
let(:params) { super().merge(display_namespace: root_group_1) } let(:params) { super().merge(display_namespace: root_group_1) }
it 'returns segments with given display namespace' do it 'returns enabled_namespaces with given display namespace' do
expect(finder_segments).to eq([segment_2]) expect(finder).to eq([enabled_namespace_2])
end end
end end
context 'without display_namespace provided' do context 'without display_namespace provided' do
it 'returns all namespace without display_namespace' do it 'returns all namespace without display_namespace' do
expect(finder_segments).to eq([segment_1]) expect(finder).to eq([enabled_namespace_1])
end end
end end
end end
......
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Resolvers::Admin::Analytics::DevopsAdoption::SegmentsResolver do RSpec.describe Resolvers::Analytics::DevopsAdoption::EnabledNamespacesResolver do
include GraphqlHelpers include GraphqlHelpers
let_it_be(:admin_user) { create(:user, :admin) } let_it_be(:admin_user) { create(:user, :admin) }
def resolve_segments(args = {}, context = {}) def resolve_enabled_namespaces(args = {}, context = {})
resolve(described_class, args: args, ctx: context) resolve(described_class, args: args, ctx: context)
end end
...@@ -19,12 +19,12 @@ RSpec.describe Resolvers::Admin::Analytics::DevopsAdoption::SegmentsResolver do ...@@ -19,12 +19,12 @@ RSpec.describe Resolvers::Admin::Analytics::DevopsAdoption::SegmentsResolver do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:root_group_1) { create(:group, name: 'bbb') } let_it_be(:root_group_1) { create(:group, name: 'bbb') }
let_it_be(:root_group_2) { create(:group, name: 'aaa') } let_it_be(:root_group_2) { create(:group, name: 'aaa') }
let_it_be(:segment_1) { create(:devops_adoption_segment, namespace: root_group_1, display_namespace: root_group_1) } let_it_be(:enabled_namespace_1) { create(:devops_adoption_enabled_namespace, namespace: root_group_1, display_namespace: root_group_1) }
let_it_be(:segment_2) { create(:devops_adoption_segment, namespace: root_group_1, display_namespace: nil) } let_it_be(:enabled_namespace_2) { create(:devops_adoption_enabled_namespace, namespace: root_group_1, display_namespace: nil) }
let_it_be(:segment_3) { create(:devops_adoption_segment, namespace: root_group_2, display_namespace: root_group_2) } let_it_be(:enabled_namespace_3) { create(:devops_adoption_enabled_namespace, namespace: root_group_2, display_namespace: root_group_2) }
let_it_be(:segment_4) { create(:devops_adoption_segment, namespace: root_group_2, display_namespace: nil) } let_it_be(:enabled_namespace_4) { create(:devops_adoption_enabled_namespace, namespace: root_group_2, display_namespace: nil) }
subject(:resolved_segments) { resolve_segments(params, { current_user: current_user }) } subject(:resolved_enabled_namespaces) { resolve_enabled_namespaces(params, { current_user: current_user }) }
let(:params) { {} } let(:params) { {} }
...@@ -32,8 +32,8 @@ RSpec.describe Resolvers::Admin::Analytics::DevopsAdoption::SegmentsResolver do ...@@ -32,8 +32,8 @@ RSpec.describe Resolvers::Admin::Analytics::DevopsAdoption::SegmentsResolver do
let(:current_user) { admin_user } let(:current_user) { admin_user }
context 'as an admin user' do context 'as an admin user' do
it 'returns segments for all groups without display_namespace' do it 'returns enabled_namespaces for all groups without display_namespace' do
expect(resolved_segments).to match_array([segment_2, segment_4]) expect(resolved_enabled_namespaces).to match_array([enabled_namespace_2, enabled_namespace_4])
end end
end end
...@@ -41,7 +41,7 @@ RSpec.describe Resolvers::Admin::Analytics::DevopsAdoption::SegmentsResolver do ...@@ -41,7 +41,7 @@ RSpec.describe Resolvers::Admin::Analytics::DevopsAdoption::SegmentsResolver do
let(:current_user) { user } let(:current_user) { user }
it 'raises ResourceNotAvailable error' do it 'raises ResourceNotAvailable error' do
expect { resolved_segments }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) expect { resolved_enabled_namespaces }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end end
end end
...@@ -51,7 +51,7 @@ RSpec.describe Resolvers::Admin::Analytics::DevopsAdoption::SegmentsResolver do ...@@ -51,7 +51,7 @@ RSpec.describe Resolvers::Admin::Analytics::DevopsAdoption::SegmentsResolver do
end end
it 'raises ResourceNotAvailable error' do it 'raises ResourceNotAvailable error' do
expect { resolved_segments }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) expect { resolved_enabled_namespaces }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end end
end end
end end
...@@ -65,8 +65,8 @@ RSpec.describe Resolvers::Admin::Analytics::DevopsAdoption::SegmentsResolver do ...@@ -65,8 +65,8 @@ RSpec.describe Resolvers::Admin::Analytics::DevopsAdoption::SegmentsResolver do
root_group_1.add_reporter(user) root_group_1.add_reporter(user)
end end
it 'returns segments for given parent group and its descendants' do it 'returns enabled_namespaces for given parent group and its descendants' do
expect(resolved_segments).to eq([segment_1]) expect(resolved_enabled_namespaces).to eq([enabled_namespace_1])
end end
end end
...@@ -76,7 +76,7 @@ RSpec.describe Resolvers::Admin::Analytics::DevopsAdoption::SegmentsResolver do ...@@ -76,7 +76,7 @@ RSpec.describe Resolvers::Admin::Analytics::DevopsAdoption::SegmentsResolver do
end end
it 'raises ResourceNotAvailable error' do it 'raises ResourceNotAvailable error' do
expect { resolved_segments }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) expect { resolved_enabled_namespaces }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end end
end end
...@@ -86,7 +86,7 @@ RSpec.describe Resolvers::Admin::Analytics::DevopsAdoption::SegmentsResolver do ...@@ -86,7 +86,7 @@ RSpec.describe Resolvers::Admin::Analytics::DevopsAdoption::SegmentsResolver do
end end
it 'raises ResourceNotAvailable error' do it 'raises ResourceNotAvailable error' do
expect { resolved_segments }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) expect { resolved_enabled_namespaces }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end end
end end
end end
......
...@@ -4,13 +4,13 @@ require 'spec_helper' ...@@ -4,13 +4,13 @@ require 'spec_helper'
RSpec.describe Analytics::DevopsAdoption::SnapshotCalculator do RSpec.describe Analytics::DevopsAdoption::SnapshotCalculator do
let_it_be(:group1) { create(:group) } let_it_be(:group1) { create(:group) }
let_it_be(:segment) { create(:devops_adoption_segment, namespace: group1) } let_it_be(:enabled_namespace) { create(:devops_adoption_enabled_namespace, namespace: group1) }
let_it_be(:subgroup) { create(:group, parent: group1) } let_it_be(:subgroup) { create(:group, parent: group1) }
let_it_be(:project) { create(:project, group: group1) } let_it_be(:project) { create(:project, group: group1) }
let_it_be(:subproject) { create(:project, group: subgroup) } let_it_be(:subproject) { create(:project, group: subgroup) }
let_it_be(:range_end) { Time.zone.parse('2020-12-01').end_of_month } let_it_be(:range_end) { Time.zone.parse('2020-12-01').end_of_month }
subject(:data) { described_class.new(segment: segment, range_end: range_end).calculate } subject(:data) { described_class.new(enabled_namespace: enabled_namespace, range_end: range_end).calculate }
describe 'end_time' do describe 'end_time' do
it 'equals to range_end' do it 'equals to range_end' do
...@@ -98,7 +98,7 @@ RSpec.describe Analytics::DevopsAdoption::SnapshotCalculator do ...@@ -98,7 +98,7 @@ RSpec.describe Analytics::DevopsAdoption::SnapshotCalculator do
let!(:deployment) { create(:deployment, :success, updated_at: deployed_at) } let!(:deployment) { create(:deployment, :success, updated_at: deployed_at) }
let(:deployed_at) { 100.days.ago(range_end) } let(:deployed_at) { 100.days.ago(range_end) }
let(:segment) { create(:devops_adoption_segment, namespace: group) } let(:enabled_namespace) { create(:devops_adoption_enabled_namespace, namespace: group) }
let!(:group) do let!(:group) do
create(:group).tap do |g| create(:group).tap do |g|
g.projects << deployment.project g.projects << deployment.project
...@@ -167,9 +167,9 @@ RSpec.describe Analytics::DevopsAdoption::SnapshotCalculator do ...@@ -167,9 +167,9 @@ RSpec.describe Analytics::DevopsAdoption::SnapshotCalculator do
end end
context 'when snapshot already exists' do context 'when snapshot already exists' do
subject(:data) { described_class.new(segment: segment, range_end: range_end, snapshot: snapshot).calculate } subject(:data) { described_class.new(enabled_namespace: enabled_namespace, range_end: range_end, snapshot: snapshot).calculate }
let(:snapshot) { create :devops_adoption_snapshot, namespace: segment.namespace, issue_opened: true, merge_request_opened: false, total_projects_count: 1 } let(:snapshot) { create :devops_adoption_snapshot, namespace: enabled_namespace.namespace, issue_opened: true, merge_request_opened: false, total_projects_count: 1 }
context 'for boolean metrics' do context 'for boolean metrics' do
let!(:fresh_merge_request) { create(:merge_request, source_project: project, created_at: 3.weeks.ago(range_end)) } let!(:fresh_merge_request) { create(:merge_request, source_project: project, created_at: 3.weeks.ago(range_end)) }
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Analytics::DevopsAdoption::EnabledNamespace, type: :model do
describe 'associations' do
subject { build(:devops_adoption_enabled_namespace) }
it { is_expected.to have_many(:snapshots) }
it { is_expected.to belong_to(:namespace) }
it { is_expected.to belong_to(:display_namespace) }
end
describe 'validation' do
subject { build(:devops_adoption_enabled_namespace) }
it { is_expected.to validate_presence_of(:namespace) }
it { is_expected.to validate_uniqueness_of(:namespace).scoped_to(:display_namespace_id) }
end
describe '.ordered_by_name' do
subject(:enabled_namespaces) { described_class.ordered_by_name }
it 'orders enabled_namespaces by namespace name' do
enabled_namespace_1 = create(:devops_adoption_enabled_namespace, namespace: create(:group, name: 'bbb'))
enabled_namespace_2 = create(:devops_adoption_enabled_namespace, namespace: create(:group, name: 'aaa'))
expect(enabled_namespaces).to eq([enabled_namespace_2, enabled_namespace_1])
end
end
describe '.for_namespaces' do
subject(:enabled_namespaces) { described_class.for_namespaces(namespaces) }
let_it_be(:enabled_namespace1) { create(:devops_adoption_enabled_namespace) }
let_it_be(:enabled_namespace2) { create(:devops_adoption_enabled_namespace) }
let_it_be(:enabled_namespace3) { create(:devops_adoption_enabled_namespace) }
let_it_be(:namespaces) { [enabled_namespace1.namespace, enabled_namespace2.namespace]}
it 'selects enabled_namespaces for given namespaces only' do
expect(enabled_namespaces).to match_array([enabled_namespace1, enabled_namespace2])
end
end
describe '.for_display_namespaces' do
subject(:enabled_namespaces) { described_class.for_display_namespaces(namespaces) }
let_it_be(:enabled_namespace1) { create(:devops_adoption_enabled_namespace) }
let_it_be(:enabled_namespace2) { create(:devops_adoption_enabled_namespace) }
let_it_be(:enabled_namespace3) { create(:devops_adoption_enabled_namespace) }
let_it_be(:namespaces) { [enabled_namespace1.display_namespace, enabled_namespace2.display_namespace]}
it 'selects enabled_namespaces for given namespaces only' do
expect(enabled_namespaces).to match_array([enabled_namespace1, enabled_namespace2])
end
end
describe '.for_parent' do
let_it_be(:group) { create :group }
let_it_be(:subgroup) { create :group, parent: group }
let_it_be(:group2) { create :group }
let_it_be(:enabled_namespace1) { create(:devops_adoption_enabled_namespace, namespace: group) }
let_it_be(:enabled_namespace2) { create(:devops_adoption_enabled_namespace, namespace: subgroup) }
let_it_be(:enabled_namespace3) { create(:devops_adoption_enabled_namespace, namespace: group2) }
subject(:enabled_namespaces) { described_class.for_parent(group) }
it 'selects enabled_namespaces for given namespace only' do
expect(enabled_namespaces).to match_array([enabled_namespace1, enabled_namespace2])
end
end
describe '.latest_snapshot' do
it 'loads the latest snapshot' do
enabled_namespace = create(:devops_adoption_enabled_namespace)
latest_snapshot = create(:devops_adoption_snapshot, namespace: enabled_namespace.namespace, end_time: 2.days.ago)
create(:devops_adoption_snapshot, namespace: enabled_namespace.namespace, end_time: 5.days.ago)
create(:devops_adoption_snapshot, end_time: 1.hour.ago)
expect(enabled_namespace.latest_snapshot).to eq(latest_snapshot)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Analytics::DevopsAdoption::Segment, type: :model do
describe 'associations' do
subject { build(:devops_adoption_segment) }
it { is_expected.to have_many(:snapshots) }
it { is_expected.to belong_to(:namespace) }
it { is_expected.to belong_to(:display_namespace) }
end
describe 'validation' do
subject { build(:devops_adoption_segment) }
it { is_expected.to validate_presence_of(:namespace) }
it { is_expected.to validate_uniqueness_of(:namespace).scoped_to(:display_namespace_id) }
end
describe '.ordered_by_name' do
subject(:segments) { described_class.ordered_by_name }
it 'orders segments by namespace name' do
segment_1 = create(:devops_adoption_segment, namespace: create(:group, name: 'bbb'))
segment_2 = create(:devops_adoption_segment, namespace: create(:group, name: 'aaa'))
expect(segments).to eq([segment_2, segment_1])
end
end
describe '.for_namespaces' do
subject(:segments) { described_class.for_namespaces(namespaces) }
let_it_be(:segment1) { create(:devops_adoption_segment) }
let_it_be(:segment2) { create(:devops_adoption_segment) }
let_it_be(:segment3) { create(:devops_adoption_segment) }
let_it_be(:namespaces) { [segment1.namespace, segment2.namespace]}
it 'selects segments for given namespaces only' do
expect(segments).to match_array([segment1, segment2])
end
end
describe '.for_display_namespaces' do
subject(:segments) { described_class.for_display_namespaces(namespaces) }
let_it_be(:segment1) { create(:devops_adoption_segment) }
let_it_be(:segment2) { create(:devops_adoption_segment) }
let_it_be(:segment3) { create(:devops_adoption_segment) }
let_it_be(:namespaces) { [segment1.display_namespace, segment2.display_namespace]}
it 'selects segments for given namespaces only' do
expect(segments).to match_array([segment1, segment2])
end
end
describe '.for_parent' do
let_it_be(:group) { create :group }
let_it_be(:subgroup) { create :group, parent: group }
let_it_be(:group2) { create :group }
let_it_be(:segment1) { create(:devops_adoption_segment, namespace: group) }
let_it_be(:segment2) { create(:devops_adoption_segment, namespace: subgroup) }
let_it_be(:segment3) { create(:devops_adoption_segment, namespace: group2) }
subject(:segments) { described_class.for_parent(group) }
it 'selects segments for given namespace only' do
expect(segments).to match_array([segment1, segment2])
end
end
describe '.latest_snapshot' do
it 'loads the latest snapshot' do
segment = create(:devops_adoption_segment)
latest_snapshot = create(:devops_adoption_snapshot, namespace: segment.namespace, end_time: 2.days.ago)
create(:devops_adoption_snapshot, namespace: segment.namespace, end_time: 5.days.ago)
create(:devops_adoption_snapshot, end_time: 1.hour.ago)
expect(segment.latest_snapshot).to eq(latest_snapshot)
end
end
end
...@@ -311,7 +311,7 @@ RSpec.describe GlobalPolicy do ...@@ -311,7 +311,7 @@ RSpec.describe GlobalPolicy do
end end
end end
describe ':view_instance_devops_adoption & :manage_devops_adoption_segments', :enable_admin_mode do describe ':view_instance_devops_adoption & :manage_devops_adoption_namespaces', :enable_admin_mode do
let(:current_user) { admin } let(:current_user) { admin }
context 'when license does not include the feature' do context 'when license does not include the feature' do
...@@ -319,7 +319,7 @@ RSpec.describe GlobalPolicy do ...@@ -319,7 +319,7 @@ RSpec.describe GlobalPolicy do
stub_licensed_features(instance_level_devops_adoption: false) stub_licensed_features(instance_level_devops_adoption: false)
end end
it { is_expected.to be_disallowed(:view_instance_devops_adoption, :manage_devops_adoption_segments) } it { is_expected.to be_disallowed(:view_instance_devops_adoption, :manage_devops_adoption_namespaces) }
end end
context 'when feature is enabled and license include the feature' do context 'when feature is enabled and license include the feature' do
...@@ -327,12 +327,12 @@ RSpec.describe GlobalPolicy do ...@@ -327,12 +327,12 @@ RSpec.describe GlobalPolicy do
stub_licensed_features(instance_level_devops_adoption: true) stub_licensed_features(instance_level_devops_adoption: true)
end end
it { is_expected.to be_allowed(:view_instance_devops_adoption, :manage_devops_adoption_segments) } it { is_expected.to be_allowed(:view_instance_devops_adoption, :manage_devops_adoption_namespaces) }
context 'for non-admins' do context 'for non-admins' do
let(:current_user) { user } let(:current_user) { user }
it { is_expected.to be_disallowed(:view_instance_devops_adoption, :manage_devops_adoption_segments) } it { is_expected.to be_disallowed(:view_instance_devops_adoption, :manage_devops_adoption_namespaces) }
end end
end end
end end
......
...@@ -1613,9 +1613,9 @@ RSpec.describe GroupPolicy do ...@@ -1613,9 +1613,9 @@ RSpec.describe GroupPolicy do
end end
end end
describe 'manage_devops_adoption_segments' do describe 'manage_devops_adoption_namespaces' do
let(:current_user) { owner } let(:current_user) { owner }
let(:policy) { :manage_devops_adoption_segments } let(:policy) { :manage_devops_adoption_namespaces }
context 'when feature is disabled' do context 'when feature is disabled' do
before do before do
......
...@@ -2,14 +2,14 @@ ...@@ -2,14 +2,14 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe 'DevopsAdoptionSegments' do RSpec.describe 'devopsAdoptionEnabledNamespaces' do
include GraphqlHelpers include GraphqlHelpers
let_it_be(:current_user) { create(:user, :admin) } let_it_be(:current_user) { create(:user, :admin) }
let_it_be(:group) { create(:group, name: 'my-group') } let_it_be(:group) { create(:group, name: 'my-group') }
let_it_be(:segment) do let_it_be(:enabled_namespace) do
create(:devops_adoption_segment, namespace: group, display_namespace: group) create(:devops_adoption_enabled_namespace, namespace: group, display_namespace: group)
end end
let_it_be(:snapshot) do let_it_be(:snapshot) do
...@@ -17,7 +17,7 @@ RSpec.describe 'DevopsAdoptionSegments' do ...@@ -17,7 +17,7 @@ RSpec.describe 'DevopsAdoptionSegments' do
end end
let(:query) do let(:query) do
graphql_query_for(:devopsAdoptionSegments, { display_namespace_id: group.to_gid.to_s }, %( graphql_query_for(:devopsAdoptionEnabledNamespaces, { display_namespace_id: group.to_gid.to_s }, %(
nodes { nodes {
id id
namespace { namespace {
...@@ -41,9 +41,9 @@ RSpec.describe 'DevopsAdoptionSegments' do ...@@ -41,9 +41,9 @@ RSpec.describe 'DevopsAdoptionSegments' do
end end
it 'returns measurement objects' do it 'returns measurement objects' do
expect(graphql_data['devopsAdoptionSegments']['nodes']).to eq([ expect(graphql_data['devopsAdoptionEnabledNamespaces']['nodes']).to eq([
{ {
'id' => segment.to_gid.to_s, 'id' => enabled_namespace.to_gid.to_s,
'namespace' => { 'name' => group.name }, 'namespace' => { 'name' => group.name },
'displayNamespace' => { 'name' => group.name }, 'displayNamespace' => { 'name' => group.name },
'latestSnapshot' => { 'latestSnapshot' => {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::BulkFindOrCreate do RSpec.describe Mutations::Analytics::DevopsAdoption::EnabledNamespaces::BulkEnable do
include GraphqlHelpers include GraphqlHelpers
let_it_be(:display_group) { create(:group, name: 'dddd') } let_it_be(:display_group) { create(:group, name: 'dddd') }
...@@ -19,18 +19,18 @@ RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::BulkFindOrCreate ...@@ -19,18 +19,18 @@ RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::BulkFindOrCreate
end end
end end
let_it_be(:existing_segment) { create :devops_adoption_segment, namespace: group3, display_namespace: display_group } let_it_be(:existing_enabled_namespace) { create :devops_adoption_enabled_namespace, namespace: group3, display_namespace: display_group }
let(:current_user) { reporter } let(:current_user) { reporter }
let(:variables) { { namespace_ids: [group.to_gid.to_s, group2.to_gid.to_s, group3.to_gid.to_s], display_namespace_id: display_group.to_gid.to_s } } let(:variables) { { namespace_ids: [group.to_gid.to_s, group2.to_gid.to_s, group3.to_gid.to_s], display_namespace_id: display_group.to_gid.to_s } }
let(:mutation) do let(:mutation) do
graphql_mutation(:bulk_find_or_create_devops_adoption_segments, variables) do graphql_mutation(:bulk_enable_devops_adoption_namespaces, variables) do
<<-QL.strip_heredoc <<-QL.strip_heredoc
clientMutationId clientMutationId
errors errors
segments { enabledNamespaces {
id id
namespace { namespace {
name name
...@@ -44,14 +44,14 @@ RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::BulkFindOrCreate ...@@ -44,14 +44,14 @@ RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::BulkFindOrCreate
end end
def mutation_response def mutation_response
graphql_mutation_response(:bulk_find_or_create_devops_adoption_segments) graphql_mutation_response(:bulk_enable_devops_adoption_namespaces)
end end
before do before do
stub_licensed_features(group_level_devops_adoption: true) stub_licensed_features(group_level_devops_adoption: true)
end end
context 'when the user cannot manage segments at least for one namespace' do context 'when the user cannot manage enabled_namespaces at least for one namespace' do
let(:current_user) { create(:user).tap { |u| group.add_reporter(u) } } let(:current_user) { create(:user).tap { |u| group.add_reporter(u) } }
it_behaves_like 'a mutation that returns a top-level access error' it_behaves_like 'a mutation that returns a top-level access error'
...@@ -65,16 +65,16 @@ RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::BulkFindOrCreate ...@@ -65,16 +65,16 @@ RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::BulkFindOrCreate
it_behaves_like 'a mutation that returns a top-level access error' it_behaves_like 'a mutation that returns a top-level access error'
end end
it 'creates the segment for each passed namespace or returns existing segment' do it 'creates the enabled_namespace for each passed namespace or returns existing enabled_namespace' do
post_graphql_mutation(mutation, current_user: current_user) post_graphql_mutation(mutation, current_user: current_user)
expect(mutation_response['errors']).to be_empty expect(mutation_response['errors']).to be_empty
segments = mutation_response['segments'] enabled_namespaces = mutation_response['enabledNamespaces']
expect(segments.map { |s| s['namespace']['name'] }).to match_array(%w[aaaa bbbb cccc]) expect(enabled_namespaces.map { |s| s['namespace']['name'] }).to match_array(%w[aaaa bbbb cccc])
expect(segments.map { |s| s['displayNamespace']['name'] }).to match_array(%w[dddd dddd dddd]) expect(enabled_namespaces.map { |s| s['displayNamespace']['name'] }).to match_array(%w[dddd dddd dddd])
expect(segments.map { |s| s['id'] }).to include(existing_segment.to_gid.to_s) expect(enabled_namespaces.map { |s| s['id'] }).to include(existing_enabled_namespace.to_gid.to_s)
expect(::Analytics::DevopsAdoption::Segment.joins(:namespace) expect(::Analytics::DevopsAdoption::EnabledNamespace.joins(:namespace)
.where(namespaces: { name: %w[aaaa bbbb cccc] }).count).to eq(3) .where(namespaces: { name: %w[aaaa bbbb cccc] }).count).to eq(3)
end end
end end
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::Delete do RSpec.describe Mutations::Analytics::DevopsAdoption::EnabledNamespaces::Disable do
include GraphqlHelpers include GraphqlHelpers
let_it_be(:display_group) { create :group } let_it_be(:display_group) { create :group }
...@@ -15,12 +15,12 @@ RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::Delete do ...@@ -15,12 +15,12 @@ RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::Delete do
end end
let(:current_user) { reporter } let(:current_user) { reporter }
let!(:segment) { create(:devops_adoption_segment, namespace: group, display_namespace: display_group) } let!(:enabled_namespace) { create(:devops_adoption_enabled_namespace, namespace: group, display_namespace: display_group) }
let(:variables) { { id: segment.to_gid.to_s } } let(:variables) { { id: enabled_namespace.to_gid.to_s } }
let(:mutation) do let(:mutation) do
graphql_mutation(:delete_devops_adoption_segment, variables) do graphql_mutation(:disable_devops_adoption_namespace, variables) do
<<~QL <<~QL
clientMutationId clientMutationId
errors errors
...@@ -33,10 +33,10 @@ RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::Delete do ...@@ -33,10 +33,10 @@ RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::Delete do
end end
def mutation_response def mutation_response
graphql_mutation_response(:delete_devops_adoption_segment) graphql_mutation_response(:disable_devops_adoption_namespace)
end end
context 'when the user cannot manage segments' do context 'when the user cannot manage enabled_namespaces' do
let(:current_user) { create(:user) } let(:current_user) { create(:user) }
it_behaves_like 'a mutation that returns a top-level access error' it_behaves_like 'a mutation that returns a top-level access error'
...@@ -50,32 +50,32 @@ RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::Delete do ...@@ -50,32 +50,32 @@ RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::Delete do
it_behaves_like 'a mutation that returns a top-level access error' it_behaves_like 'a mutation that returns a top-level access error'
end end
it 'deletes the segment' do it 'deletes the enabled_namespace' do
post_graphql_mutation(mutation, current_user: current_user) post_graphql_mutation(mutation, current_user: current_user)
expect(mutation_response['errors']).to be_empty expect(mutation_response['errors']).to be_empty
expect(::Analytics::DevopsAdoption::Segment.find_by_id(segment.id)).to eq(nil) expect(::Analytics::DevopsAdoption::EnabledNamespace.find_by_id(enabled_namespace.id)).to eq(nil)
end end
context 'with bulk ids' do context 'with bulk ids' do
let!(:segment2) { create(:devops_adoption_segment) } let!(:enabled_namespace2) { create(:devops_adoption_enabled_namespace) }
let!(:segment3) { create(:devops_adoption_segment) } let!(:enabled_namespace3) { create(:devops_adoption_enabled_namespace) }
let(:variables) { { id: [segment.to_gid.to_s, segment2.to_gid.to_s] } } let(:variables) { { id: [enabled_namespace.to_gid.to_s, enabled_namespace2.to_gid.to_s] } }
before do before do
segment2.namespace.add_reporter(current_user) enabled_namespace2.namespace.add_reporter(current_user)
segment2.display_namespace.add_reporter(current_user) enabled_namespace2.display_namespace.add_reporter(current_user)
segment3.namespace.add_reporter(current_user) enabled_namespace3.namespace.add_reporter(current_user)
segment3.display_namespace.add_reporter(current_user) enabled_namespace3.display_namespace.add_reporter(current_user)
end end
it 'deletes the segments specified for deletion' do it 'deletes the enabled_namespaces specified for deletion' do
post_graphql_mutation(mutation, current_user: current_user) post_graphql_mutation(mutation, current_user: current_user)
expect(mutation_response['errors']).to be_empty expect(mutation_response['errors']).to be_empty
expect(::Analytics::DevopsAdoption::Segment.where(id: [segment.id, segment2.id, segment3.id])) expect(::Analytics::DevopsAdoption::EnabledNamespace.where(id: [enabled_namespace.id, enabled_namespace2.id, enabled_namespace3.id]))
.to match_array([segment3]) .to match_array([enabled_namespace3])
end end
end end
end end
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::Create do RSpec.describe Mutations::Analytics::DevopsAdoption::EnabledNamespaces::Enable do
include GraphqlHelpers include GraphqlHelpers
let_it_be(:display_group) { create(:group, name: 'aaaa') } let_it_be(:display_group) { create(:group, name: 'aaaa') }
...@@ -20,11 +20,11 @@ RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::Create do ...@@ -20,11 +20,11 @@ RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::Create do
let(:variables) { { namespace_id: group.to_gid.to_s, display_namespace_id: display_group.to_gid.to_s } } let(:variables) { { namespace_id: group.to_gid.to_s, display_namespace_id: display_group.to_gid.to_s } }
let(:mutation) do let(:mutation) do
graphql_mutation(:create_devops_adoption_segment, variables) do graphql_mutation(:enable_devops_adoption_namespace, variables) do
<<-QL.strip_heredoc <<-QL.strip_heredoc
clientMutationId clientMutationId
errors errors
segment { enabledNamespace {
id id
namespace { namespace {
name name
...@@ -38,14 +38,14 @@ RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::Create do ...@@ -38,14 +38,14 @@ RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::Create do
end end
def mutation_response def mutation_response
graphql_mutation_response(:create_devops_adoption_segment) graphql_mutation_response(:enable_devops_adoption_namespace)
end end
before do before do
stub_licensed_features(group_level_devops_adoption: true) stub_licensed_features(group_level_devops_adoption: true)
end end
context 'when the user cannot manage segments' do context 'when the user cannot manage enabled_namespaces' do
let(:current_user) { create(:user) } let(:current_user) { create(:user) }
it_behaves_like 'a mutation that returns a top-level access error' it_behaves_like 'a mutation that returns a top-level access error'
...@@ -59,14 +59,14 @@ RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::Create do ...@@ -59,14 +59,14 @@ RSpec.describe Mutations::Analytics::DevopsAdoption::Segments::Create do
it_behaves_like 'a mutation that returns a top-level access error' it_behaves_like 'a mutation that returns a top-level access error'
end end
it 'creates the segment with the group', :aggregate_failures do it 'creates the enabled_namespace with the group', :aggregate_failures do
post_graphql_mutation(mutation, current_user: current_user) post_graphql_mutation(mutation, current_user: current_user)
expect(mutation_response['errors']).to be_empty expect(mutation_response['errors']).to be_empty
segment = mutation_response['segment'] enabled_namespace = mutation_response['enabledNamespace']
expect(segment['namespace']['name']).to eq('bbbb') expect(enabled_namespace['namespace']['name']).to eq('bbbb')
expect(segment['displayNamespace']['name']).to eq('aaaa') expect(enabled_namespace['displayNamespace']['name']).to eq('aaaa')
expect(::Analytics::DevopsAdoption::Segment.joins(:namespace).where(namespaces: { name: 'bbbb' }).count).to eq(1) expect(::Analytics::DevopsAdoption::EnabledNamespace.joins(:namespace).where(namespaces: { name: 'bbbb' }).count).to eq(1)
end end
end end
...@@ -2,55 +2,55 @@ ...@@ -2,55 +2,55 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Analytics::DevopsAdoption::Segments::BulkDeleteService do RSpec.describe Analytics::DevopsAdoption::EnabledNamespaces::BulkDeleteService do
include AdminModeHelper include AdminModeHelper
let_it_be(:group) { create(:group) } let_it_be(:group) { create(:group) }
let_it_be(:admin) { create(:user, :admin) } let_it_be(:admin) { create(:user, :admin) }
let(:segment) { create(:devops_adoption_segment, namespace: group) } let(:enabled_namespace) { create(:devops_adoption_enabled_namespace, namespace: group) }
let(:segment2) { create(:devops_adoption_segment) } let(:enabled_namespace2) { create(:devops_adoption_enabled_namespace) }
let(:current_user) { admin } let(:current_user) { admin }
subject(:response) { described_class.new(segments: [segment, segment2], current_user: current_user).execute } subject(:response) { described_class.new(enabled_namespaces: [enabled_namespace, enabled_namespace2], current_user: current_user).execute }
before do before do
enable_admin_mode!(admin) enable_admin_mode!(admin)
stub_licensed_features(group_level_devops_adoption: true, instance_level_devops_adoption: true) stub_licensed_features(group_level_devops_adoption: true, instance_level_devops_adoption: true)
end end
it 'deletes the segments' do it 'deletes the enabled_namespaces' do
expect(response).to be_success expect(response).to be_success
expect(segment).not_to be_persisted expect(enabled_namespace).not_to be_persisted
expect(segment2).not_to be_persisted expect(enabled_namespace2).not_to be_persisted
end end
context 'when deletion fails' do context 'when deletion fails' do
it 'keeps records and returns error response' do it 'keeps records and returns error response' do
expect(segment).to receive(:destroy).and_raise(ActiveRecord::RecordNotDestroyed) expect(enabled_namespace).to receive(:destroy).and_raise(ActiveRecord::RecordNotDestroyed)
expect(response).to be_error expect(response).to be_error
expect(response.message).to eq('DevOps Adoption Segment deletion error') expect(response.message).to eq('DevOps Adoption EnabledNamespace deletion error')
expect(segment).to be_persisted expect(enabled_namespace).to be_persisted
expect(segment2).to be_persisted expect(enabled_namespace2).to be_persisted
end end
end end
it 'authorizes for manage_devops_adoption' do it 'authorizes for manage_devops_adoption' do
expect(::Ability).to receive(:allowed?) expect(::Ability).to receive(:allowed?)
.with(current_user, :manage_devops_adoption_segments, group) .with(current_user, :manage_devops_adoption_namespaces, group)
.at_least(1) .at_least(1)
.and_return(true) .and_return(true)
expect(::Ability).to receive(:allowed?) expect(::Ability).to receive(:allowed?)
.with(current_user, :manage_devops_adoption_segments, segment.display_namespace) .with(current_user, :manage_devops_adoption_namespaces, enabled_namespace.display_namespace)
.at_least(1) .at_least(1)
.and_return(true) .and_return(true)
expect(::Ability).to receive(:allowed?) expect(::Ability).to receive(:allowed?)
.with(current_user, :manage_devops_adoption_segments, segment2.namespace) .with(current_user, :manage_devops_adoption_namespaces, enabled_namespace2.namespace)
.at_least(1) .at_least(1)
.and_return(true) .and_return(true)
expect(::Ability).to receive(:allowed?) expect(::Ability).to receive(:allowed?)
.with(current_user, :manage_devops_adoption_segments, segment2.display_namespace) .with(current_user, :manage_devops_adoption_namespaces, enabled_namespace2.display_namespace)
.at_least(1) .at_least(1)
.and_return(true) .and_return(true)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Analytics::DevopsAdoption::Segments::BulkFindOrCreateService do RSpec.describe Analytics::DevopsAdoption::EnabledNamespaces::BulkFindOrCreateService do
let_it_be(:group) { create(:group) } let_it_be(:group) { create(:group) }
let_it_be(:group2) { create(:group) } let_it_be(:group2) { create(:group) }
let_it_be(:display_group) { create(:group) } let_it_be(:display_group) { create(:group) }
...@@ -15,7 +15,7 @@ RSpec.describe Analytics::DevopsAdoption::Segments::BulkFindOrCreateService do ...@@ -15,7 +15,7 @@ RSpec.describe Analytics::DevopsAdoption::Segments::BulkFindOrCreateService do
end end
end end
let_it_be(:segment) { create :devops_adoption_segment, namespace: group, display_namespace: display_group } let_it_be(:enabled_namespace) { create :devops_adoption_enabled_namespace, namespace: group, display_namespace: display_group }
let(:current_user) { reporter } let(:current_user) { reporter }
let(:params) { { namespaces: [group, group2], display_namespace: display_group } } let(:params) { { namespaces: [group, group2], display_namespace: display_group } }
...@@ -28,31 +28,31 @@ RSpec.describe Analytics::DevopsAdoption::Segments::BulkFindOrCreateService do ...@@ -28,31 +28,31 @@ RSpec.describe Analytics::DevopsAdoption::Segments::BulkFindOrCreateService do
it 'authorizes for manage_devops_adoption', :aggregate_failures do it 'authorizes for manage_devops_adoption', :aggregate_failures do
expect(::Ability).to receive(:allowed?) expect(::Ability).to receive(:allowed?)
.with(current_user, :manage_devops_adoption_segments, group) .with(current_user, :manage_devops_adoption_namespaces, group)
.at_least(1) .at_least(1)
.and_return(true) .and_return(true)
expect(::Ability).to receive(:allowed?) expect(::Ability).to receive(:allowed?)
.with(current_user, :manage_devops_adoption_segments, group2) .with(current_user, :manage_devops_adoption_namespaces, group2)
.at_least(1) .at_least(1)
.and_return(true) .and_return(true)
expect(::Ability).to receive(:allowed?) expect(::Ability).to receive(:allowed?)
.with(current_user, :manage_devops_adoption_segments, display_group) .with(current_user, :manage_devops_adoption_namespaces, display_group)
.at_least(2) .at_least(2)
.and_return(true) .and_return(true)
response response
end end
context 'when the user cannot manage segments at least for one namespace' do context 'when the user cannot manage enabled_namespaces at least for one namespace' do
let(:current_user) { create(:user).tap { |u| group.add_reporter(u) } } let(:current_user) { create(:user).tap { |u| group.add_reporter(u) } }
it 'returns forbidden error' do it 'returns forbidden error' do
expect { response }.to raise_error(Analytics::DevopsAdoption::Segments::AuthorizationError) expect { response }.to raise_error(Analytics::DevopsAdoption::EnabledNamespaces::AuthorizationError)
end end
end end
it 'returns existing segments for namespaces and creates new one if none exists' do it 'returns existing enabled_namespaces for namespaces and creates new one if none exists' do
expect { response }.to change { ::Analytics::DevopsAdoption::Segment.count }.by(1) expect { response }.to change { ::Analytics::DevopsAdoption::EnabledNamespace.count }.by(1)
expect(response.payload.fetch(:segments)).to include(segment) expect(response.payload.fetch(:enabled_namespaces)).to include(enabled_namespace)
end end
end end
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Analytics::DevopsAdoption::Segments::CreateService do RSpec.describe Analytics::DevopsAdoption::EnabledNamespaces::CreateService do
let_it_be(:group) { create(:group) } let_it_be(:group) { create(:group) }
let_it_be(:display_group) { create(:group) } let_it_be(:display_group) { create(:group) }
...@@ -16,7 +16,7 @@ RSpec.describe Analytics::DevopsAdoption::Segments::CreateService do ...@@ -16,7 +16,7 @@ RSpec.describe Analytics::DevopsAdoption::Segments::CreateService do
let(:current_user) { reporter } let(:current_user) { reporter }
let(:params) { { namespace: group, display_namespace: display_group } } let(:params) { { namespace: group, display_namespace: display_group } }
let(:segment) { subject.payload[:segment] } let(:enabled_namespace) { subject.payload[:enabled_namespace] }
subject(:response) { described_class.new(params: params, current_user: current_user).execute } subject(:response) { described_class.new(params: params, current_user: current_user).execute }
...@@ -24,10 +24,10 @@ RSpec.describe Analytics::DevopsAdoption::Segments::CreateService do ...@@ -24,10 +24,10 @@ RSpec.describe Analytics::DevopsAdoption::Segments::CreateService do
stub_licensed_features(group_level_devops_adoption: true, instance_level_devops_adoption: true) stub_licensed_features(group_level_devops_adoption: true, instance_level_devops_adoption: true)
end end
it 'persists the segment', :aggregate_failures do it 'persists the enabled_namespace', :aggregate_failures do
expect(response).to be_success expect(response).to be_success
expect(segment.namespace).to eq(group) expect(enabled_namespace.namespace).to eq(group)
expect(segment.display_namespace).to eq(display_group) expect(enabled_namespace.display_namespace).to eq(display_group)
end end
it 'schedules for snapshot creation' do it 'schedules for snapshot creation' do
...@@ -35,12 +35,12 @@ RSpec.describe Analytics::DevopsAdoption::Segments::CreateService do ...@@ -35,12 +35,12 @@ RSpec.describe Analytics::DevopsAdoption::Segments::CreateService do
response response
expect(Analytics::DevopsAdoption::CreateSnapshotWorker).to have_received(:perform_async).with(Analytics::DevopsAdoption::Segment.last.id) expect(Analytics::DevopsAdoption::CreateSnapshotWorker).to have_received(:perform_async).with(Analytics::DevopsAdoption::EnabledNamespace.last.id)
end end
it 'authorizes for manage_devops_adoption', :aggregate_failures do it 'authorizes for manage_devops_adoption', :aggregate_failures do
expect(::Ability).to receive(:allowed?).with(current_user, :manage_devops_adoption_segments, group).and_return true expect(::Ability).to receive(:allowed?).with(current_user, :manage_devops_adoption_namespaces, group).and_return true
expect(::Ability).to receive(:allowed?).with(current_user, :manage_devops_adoption_segments, display_group).and_return true expect(::Ability).to receive(:allowed?).with(current_user, :manage_devops_adoption_namespaces, display_group).and_return true
response response
end end
...@@ -51,8 +51,8 @@ RSpec.describe Analytics::DevopsAdoption::Segments::CreateService do ...@@ -51,8 +51,8 @@ RSpec.describe Analytics::DevopsAdoption::Segments::CreateService do
end end
it 'authorizes for global manage_devops_adoption', :aggregate_failures do it 'authorizes for global manage_devops_adoption', :aggregate_failures do
expect(::Ability).to receive(:allowed?).with(current_user, :manage_devops_adoption_segments, group).and_return true expect(::Ability).to receive(:allowed?).with(current_user, :manage_devops_adoption_namespaces, group).and_return true
expect(::Ability).to receive(:allowed?).with(current_user, :manage_devops_adoption_segments, :global).and_return true expect(::Ability).to receive(:allowed?).with(current_user, :manage_devops_adoption_namespaces, :global).and_return true
response response
end end
...@@ -62,7 +62,7 @@ RSpec.describe Analytics::DevopsAdoption::Segments::CreateService do ...@@ -62,7 +62,7 @@ RSpec.describe Analytics::DevopsAdoption::Segments::CreateService do
let(:current_user) { create(:user) } let(:current_user) { create(:user) }
it 'returns forbidden error' do it 'returns forbidden error' do
expect { response }.to raise_error(Analytics::DevopsAdoption::Segments::AuthorizationError) expect { response }.to raise_error(Analytics::DevopsAdoption::EnabledNamespaces::AuthorizationError)
end end
end end
end end
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Analytics::DevopsAdoption::Segments::DeleteService do RSpec.describe Analytics::DevopsAdoption::EnabledNamespaces::DeleteService do
let_it_be(:group) { create(:group) } let_it_be(:group) { create(:group) }
let_it_be(:display_group) { create(:group) } let_it_be(:display_group) { create(:group) }
...@@ -13,41 +13,41 @@ RSpec.describe Analytics::DevopsAdoption::Segments::DeleteService do ...@@ -13,41 +13,41 @@ RSpec.describe Analytics::DevopsAdoption::Segments::DeleteService do
end end
end end
let(:segment) { create(:devops_adoption_segment, namespace: group, display_namespace: display_group) } let(:enabled_namespace) { create(:devops_adoption_enabled_namespace, namespace: group, display_namespace: display_group) }
let(:current_user) { reporter } let(:current_user) { reporter }
subject(:response) { described_class.new(segment: segment, current_user: current_user).execute } subject(:response) { described_class.new(enabled_namespace: enabled_namespace, current_user: current_user).execute }
before do before do
stub_licensed_features(group_level_devops_adoption: true, instance_level_devops_adoption: true) stub_licensed_features(group_level_devops_adoption: true, instance_level_devops_adoption: true)
end end
it 'deletes the segment' do it 'deletes the enabled_namespace' do
expect(response).to be_success expect(response).to be_success
expect(segment).not_to be_persisted expect(enabled_namespace).not_to be_persisted
end end
context 'when deletion fails' do context 'when deletion fails' do
it 'returns error response' do it 'returns error response' do
expect(segment).to receive(:destroy).and_raise(ActiveRecord::RecordNotDestroyed) expect(enabled_namespace).to receive(:destroy).and_raise(ActiveRecord::RecordNotDestroyed)
expect(response).to be_error expect(response).to be_error
expect(response.message).to eq('DevOps Adoption Segment deletion error') expect(response.message).to eq('DevOps Adoption EnabledNamespace deletion error')
end end
end end
it 'authorizes for manage_devops_adoption', :aggregate_failures do it 'authorizes for manage_devops_adoption', :aggregate_failures do
expect(::Ability).to receive(:allowed?).with(current_user, :manage_devops_adoption_segments, group).and_return true expect(::Ability).to receive(:allowed?).with(current_user, :manage_devops_adoption_namespaces, group).and_return true
expect(::Ability).to receive(:allowed?).with(current_user, :manage_devops_adoption_segments, display_group).and_return true expect(::Ability).to receive(:allowed?).with(current_user, :manage_devops_adoption_namespaces, display_group).and_return true
response response
end end
context 'when user cannot manage segments for the namespace' do context 'when user cannot manage enabled_namespaces for the namespace' do
let(:current_user) { create(:user) } let(:current_user) { create(:user) }
it 'returns forbidden error' do it 'returns forbidden error' do
expect { response }.to raise_error(Analytics::DevopsAdoption::Segments::AuthorizationError) expect { response }.to raise_error(Analytics::DevopsAdoption::EnabledNamespaces::AuthorizationError)
end end
end end
end end
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Analytics::DevopsAdoption::Segments::FindOrCreateService do RSpec.describe Analytics::DevopsAdoption::EnabledNamespaces::FindOrCreateService do
let_it_be(:group) { create(:group) } let_it_be(:group) { create(:group) }
let_it_be(:display_group) { create(:group) } let_it_be(:display_group) { create(:group) }
...@@ -23,22 +23,22 @@ RSpec.describe Analytics::DevopsAdoption::Segments::FindOrCreateService do ...@@ -23,22 +23,22 @@ RSpec.describe Analytics::DevopsAdoption::Segments::FindOrCreateService do
stub_licensed_features(group_level_devops_adoption: true, instance_level_devops_adoption: true) stub_licensed_features(group_level_devops_adoption: true, instance_level_devops_adoption: true)
end end
context 'when segment for given namespace & display_namespace already exists' do context 'when enabled_namespace for given namespace & display_namespace already exists' do
let!(:segment) { create :devops_adoption_segment, namespace: group, display_namespace: display_group } let!(:enabled_namespace) { create :devops_adoption_enabled_namespace, namespace: group, display_namespace: display_group }
it 'returns existing segment' do it 'returns existing enabled_namespace' do
expect { response }.not_to change { Analytics::DevopsAdoption::Segment.count } expect { response }.not_to change { Analytics::DevopsAdoption::EnabledNamespace.count }
expect(subject.payload.fetch(:segment)).to eq(segment) expect(subject.payload.fetch(:enabled_namespace)).to eq(enabled_namespace)
end end
end end
context 'when segment for given namespace does not exist' do context 'when enabled_namespace for given namespace does not exist' do
let!(:segment2) { create :devops_adoption_segment, namespace: group } let!(:enabled_namespace2) { create :devops_adoption_enabled_namespace, namespace: group }
let!(:segment3) { create :devops_adoption_segment, display_namespace: display_group } let!(:enabled_namespace3) { create :devops_adoption_enabled_namespace, display_namespace: display_group }
it 'calls for segment creation' do it 'calls for enabled_namespace creation' do
expect_next_instance_of(Analytics::DevopsAdoption::Segments::CreateService, expect_next_instance_of(Analytics::DevopsAdoption::EnabledNamespaces::CreateService,
current_user: current_user, current_user: current_user,
params: { namespace: group, display_namespace: display_group }) do |instance| params: { namespace: group, display_namespace: display_group }) do |instance|
expect(instance).to receive(:execute).and_return('create_response') expect(instance).to receive(:execute).and_return('create_response')
...@@ -50,12 +50,12 @@ RSpec.describe Analytics::DevopsAdoption::Segments::FindOrCreateService do ...@@ -50,12 +50,12 @@ RSpec.describe Analytics::DevopsAdoption::Segments::FindOrCreateService do
it 'authorizes for manage_devops_adoption' do it 'authorizes for manage_devops_adoption' do
expect(::Ability).to receive(:allowed?) expect(::Ability).to receive(:allowed?)
.with(current_user, :manage_devops_adoption_segments, group) .with(current_user, :manage_devops_adoption_namespaces, group)
.at_least(1) .at_least(1)
.and_return(true) .and_return(true)
expect(::Ability).to receive(:allowed?) expect(::Ability).to receive(:allowed?)
.with(current_user, :manage_devops_adoption_segments, display_group) .with(current_user, :manage_devops_adoption_namespaces, display_group)
.at_least(1) .at_least(1)
.and_return(true) .and_return(true)
...@@ -66,7 +66,7 @@ RSpec.describe Analytics::DevopsAdoption::Segments::FindOrCreateService do ...@@ -66,7 +66,7 @@ RSpec.describe Analytics::DevopsAdoption::Segments::FindOrCreateService do
let(:current_user) { create(:user) } let(:current_user) { create(:user) }
it 'returns forbidden error' do it 'returns forbidden error' do
expect { response }.to raise_error(Analytics::DevopsAdoption::Segments::AuthorizationError) expect { response }.to raise_error(Analytics::DevopsAdoption::EnabledNamespaces::AuthorizationError)
end end
end end
end end
...@@ -3,15 +3,15 @@ ...@@ -3,15 +3,15 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService do RSpec.describe Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService do
let_it_be(:segment) { create :devops_adoption_segment } let_it_be(:enabled_namespace) { create :devops_adoption_enabled_namespace }
subject { described_class.new(segment: segment, range_end: range_end) } subject { described_class.new(enabled_namespace: enabled_namespace, range_end: range_end) }
let(:range_end) { Time.zone.now.end_of_month } let(:range_end) { Time.zone.now.end_of_month }
let(:snapshot) { nil } let(:snapshot) { nil }
before do before do
allow_next_instance_of(Analytics::DevopsAdoption::SnapshotCalculator, segment: segment, range_end: range_end, snapshot: snapshot) do |calc| allow_next_instance_of(Analytics::DevopsAdoption::SnapshotCalculator, enabled_namespace: enabled_namespace, range_end: range_end, snapshot: snapshot) do |calc|
allow(calc).to receive(:calculate).and_return('calculated_data') allow(calc).to receive(:calculate).and_return('calculated_data')
end end
end end
...@@ -25,7 +25,7 @@ RSpec.describe Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService do ...@@ -25,7 +25,7 @@ RSpec.describe Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService do
end end
context 'when a snapshot for given range already exists' do context 'when a snapshot for given range already exists' do
let(:snapshot) { create :devops_adoption_snapshot, end_time: range_end, namespace: segment.namespace } let(:snapshot) { create :devops_adoption_snapshot, end_time: range_end, namespace: enabled_namespace.namespace }
it 'updates the snapshot with whatever snapshot calculator returns' do it 'updates the snapshot with whatever snapshot calculator returns' do
expect_next_instance_of(Analytics::DevopsAdoption::Snapshots::UpdateService, snapshot: snapshot, params: 'calculated_data') do |service| expect_next_instance_of(Analytics::DevopsAdoption::Snapshots::UpdateService, snapshot: snapshot, params: 'calculated_data') do |service|
......
...@@ -17,11 +17,11 @@ RSpec.describe Analytics::DevopsAdoption::Snapshots::CreateService do ...@@ -17,11 +17,11 @@ RSpec.describe Analytics::DevopsAdoption::Snapshots::CreateService do
params[:recorded_at] = Time.zone.now params[:recorded_at] = Time.zone.now
params[:end_time] = 1.month.ago.end_of_month params[:end_time] = 1.month.ago.end_of_month
params[:namespace] = segment.namespace params[:namespace] = enabled_namespace.namespace
params params
end end
let(:segment) { create(:devops_adoption_segment) } let(:enabled_namespace) { create(:devops_adoption_enabled_namespace) }
it 'persists the snapshot' do it 'persists the snapshot' do
expect(subject).to be_success expect(subject).to be_success
......
...@@ -6,13 +6,13 @@ RSpec.describe Analytics::DevopsAdoption::CreateAllSnapshotsWorker do ...@@ -6,13 +6,13 @@ RSpec.describe Analytics::DevopsAdoption::CreateAllSnapshotsWorker do
subject(:worker) { described_class.new } subject(:worker) { described_class.new }
describe "#perform" do describe "#perform" do
let!(:segment1) { create :devops_adoption_segment } let!(:enabled_namespace1) { create :devops_adoption_enabled_namespace }
let!(:segment2) { create :devops_adoption_segment } let!(:enabled_namespace2) { create :devops_adoption_enabled_namespace }
it 'schedules workers for each individual segment' do it 'schedules workers for each individual enabled_namespace' do
freeze_time do freeze_time do
expect(Analytics::DevopsAdoption::CreateSnapshotWorker).to receive(:perform_in).with(0, segment1.id) expect(Analytics::DevopsAdoption::CreateSnapshotWorker).to receive(:perform_in).with(0, enabled_namespace1.id)
expect(Analytics::DevopsAdoption::CreateSnapshotWorker).to receive(:perform_in).with(5, segment2.id) expect(Analytics::DevopsAdoption::CreateSnapshotWorker).to receive(:perform_in).with(5, enabled_namespace2.id)
worker.perform worker.perform
end end
......
...@@ -6,18 +6,18 @@ RSpec.describe Analytics::DevopsAdoption::CreateSnapshotWorker do ...@@ -6,18 +6,18 @@ RSpec.describe Analytics::DevopsAdoption::CreateSnapshotWorker do
subject(:worker) { described_class.new } subject(:worker) { described_class.new }
describe "#perform" do describe "#perform" do
let!(:segment) { create :devops_adoption_segment } let!(:enabled_namespace) { create :devops_adoption_enabled_namespace }
let!(:pending_snapshot) do let!(:pending_snapshot) do
create(:devops_adoption_snapshot, create(:devops_adoption_snapshot,
namespace: segment.namespace, namespace: enabled_namespace.namespace,
end_time: DateTime.parse('2020-10-01').end_of_month, end_time: DateTime.parse('2020-10-01').end_of_month,
recorded_at: DateTime.parse('2020-10-20')).reload recorded_at: DateTime.parse('2020-10-20')).reload
end end
let!(:finalized_snapshot) do let!(:finalized_snapshot) do
create(:devops_adoption_snapshot, create(:devops_adoption_snapshot,
namespace: segment.namespace, namespace: enabled_namespace.namespace,
end_time: DateTime.parse('2020-09-01').end_of_month, end_time: DateTime.parse('2020-09-01').end_of_month,
recorded_at: DateTime.parse('2020-10-20')).reload recorded_at: DateTime.parse('2020-10-20')).reload
end end
...@@ -26,31 +26,31 @@ RSpec.describe Analytics::DevopsAdoption::CreateSnapshotWorker do ...@@ -26,31 +26,31 @@ RSpec.describe Analytics::DevopsAdoption::CreateSnapshotWorker do
it 'updates metrics for all not finalized snapshots and current month' do it 'updates metrics for all not finalized snapshots and current month' do
freeze_time do freeze_time do
allow_next_instance_of(Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService, segment: segment, range_end: pending_snapshot.end_time) do |instance| allow_next_instance_of(Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService, enabled_namespace: enabled_namespace, range_end: pending_snapshot.end_time) do |instance|
expect(instance).to receive(:execute) expect(instance).to receive(:execute)
end end
allow_next_instance_of(Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService, segment: segment, range_end: finalized_snapshot.end_time) do |instance| allow_next_instance_of(Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService, enabled_namespace: enabled_namespace, range_end: finalized_snapshot.end_time) do |instance|
expect(instance).not_to receive(:execute) expect(instance).not_to receive(:execute)
end end
allow_next_instance_of(Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService, segment: segment, range_end: Time.zone.now.end_of_month) do |instance| allow_next_instance_of(Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService, enabled_namespace: enabled_namespace, range_end: Time.zone.now.end_of_month) do |instance|
expect(instance).to receive(:execute) expect(instance).to receive(:execute)
end end
worker.perform(segment.id) worker.perform(enabled_namespace.id)
end end
end end
context 'when metric for current month already exists' do context 'when metric for current month already exists' do
it 'calls for current month calculation only once' do it 'calls for current month calculation only once' do
travel_to(pending_snapshot.recorded_at + 1.day) do travel_to(pending_snapshot.recorded_at + 1.day) do
allow_next_instance_of(Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService, segment: segment, range_end: pending_snapshot.end_time) do |instance| allow_next_instance_of(Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService, enabled_namespace: enabled_namespace, range_end: pending_snapshot.end_time) do |instance|
expect(instance).to receive(:execute).once expect(instance).to receive(:execute).once
end end
allow_next_instance_of(Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService, segment: segment, range_end: finalized_snapshot.end_time) do |instance| allow_next_instance_of(Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService, enabled_namespace: enabled_namespace, range_end: finalized_snapshot.end_time) do |instance|
expect(instance).not_to receive(:execute) expect(instance).not_to receive(:execute)
end end
worker.perform(segment.id) worker.perform(enabled_namespace.id)
end end
end end
end end
...@@ -58,17 +58,17 @@ RSpec.describe Analytics::DevopsAdoption::CreateSnapshotWorker do ...@@ -58,17 +58,17 @@ RSpec.describe Analytics::DevopsAdoption::CreateSnapshotWorker do
context 'when today is first day of the month' do context 'when today is first day of the month' do
it 'doesnt update metrics for current month' do it 'doesnt update metrics for current month' do
travel_to((pending_snapshot.recorded_at + 1.month).beginning_of_month) do travel_to((pending_snapshot.recorded_at + 1.month).beginning_of_month) do
allow_next_instance_of(Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService, segment: segment, range_end: pending_snapshot.end_time) do |instance| allow_next_instance_of(Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService, enabled_namespace: enabled_namespace, range_end: pending_snapshot.end_time) do |instance|
expect(instance).to receive(:execute) expect(instance).to receive(:execute)
end end
allow_next_instance_of(Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService, segment: segment, range_end: finalized_snapshot.end_time) do |instance| allow_next_instance_of(Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService, enabled_namespace: enabled_namespace, range_end: finalized_snapshot.end_time) do |instance|
expect(instance).not_to receive(:execute) expect(instance).not_to receive(:execute)
end end
allow_next_instance_of(Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService, segment: segment, range_end: Time.zone.now.end_of_month) do |instance| allow_next_instance_of(Analytics::DevopsAdoption::Snapshots::CalculateAndSaveService, enabled_namespace: enabled_namespace, range_end: Time.zone.now.end_of_month) do |instance|
expect(instance).not_to receive(:execute) expect(instance).not_to receive(:execute)
end end
worker.perform(segment.id) worker.perform(enabled_namespace.id)
end end
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