diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index b3a82135fb26e487b8c3042e667cbf9f9cb35e39..85e44fbdbc0f515fa9153f6e95c28c9c329ab79e 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -27113,6 +27113,19 @@ Represents generic policy violation information. | <a id="previewbillableuserchangeseatsinsubscription"></a>`seatsInSubscription` | [`Int`](#int) | Number of seats in subscription. | | <a id="previewbillableuserchangewillincreaseoverage"></a>`willIncreaseOverage` | [`Boolean`](#boolean) | If the group will have an increased overage after change. | +### `ProductAnalyticsProjectSettings` + +Project-level settings for product analytics provider. + +#### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| <a id="productanalyticsprojectsettingscubeapibaseurl"></a>`cubeApiBaseUrl` | [`String`](#string) | Base URL for the Cube API. | +| <a id="productanalyticsprojectsettingscubeapikey"></a>`cubeApiKey` | [`String`](#string) | API key for the Cube API. | +| <a id="productanalyticsprojectsettingsproductanalyticsconfiguratorconnectionstring"></a>`productAnalyticsConfiguratorConnectionString` | [`String`](#string) | Connection string for the product analytics configurator. | +| <a id="productanalyticsprojectsettingsproductanalyticsdatacollectorhost"></a>`productAnalyticsDataCollectorHost` | [`String`](#string) | Host for the product analytics data collector. | + ### `Project` #### Fields @@ -27200,6 +27213,7 @@ Represents generic policy violation information. | <a id="projectpreventmergewithoutjiraissueenabled"></a>`preventMergeWithoutJiraIssueEnabled` | [`Boolean!`](#boolean) | Indicates if an associated issue from Jira is required. | | <a id="projectprintingmergerequestlinkenabled"></a>`printingMergeRequestLinkEnabled` | [`Boolean`](#boolean) | Indicates if a link to create or view a merge request should display after a push to Git repositories of the project from the command line. | | <a id="projectproductanalyticsinstrumentationkey"></a>`productAnalyticsInstrumentationKey` **{warning-solid}** | [`String`](#string) | **Introduced** in GitLab 16.0. **Status**: Experiment. Product Analytics instrumentation key assigned to the project. | +| <a id="projectproductanalyticssettings"></a>`productAnalyticsSettings` | [`ProductAnalyticsProjectSettings`](#productanalyticsprojectsettings) | Project-level settings for product analytics. | | <a id="projectproductanalyticsstate"></a>`productAnalyticsState` **{warning-solid}** | [`ProductAnalyticsState`](#productanalyticsstate) | **Introduced** in GitLab 15.10. **Status**: Experiment. Current state of the product analytics stack for this project.Can only be called for one project in a single request. | | <a id="projectprojectplanlimits"></a>`projectPlanLimits` **{warning-solid}** | [`ProjectPlanLimits`](#projectplanlimits) | **Introduced** in GitLab 16.9. **Status**: Experiment. Plan limits for the current project. | | <a id="projectprotectablebranches"></a>`protectableBranches` **{warning-solid}** | [`[String!]`](#string) | **Introduced** in GitLab 16.9. **Status**: Experiment. List of unprotected branches, ignoring any wildcard branch rules. | diff --git a/ee/app/assets/javascripts/product_analytics/graphql/queries/get_product_analytics_project_settings.query.graphql b/ee/app/assets/javascripts/product_analytics/graphql/queries/get_product_analytics_project_settings.query.graphql new file mode 100644 index 0000000000000000000000000000000000000000..59b8ebfe375d4fb60484b1973567f331c2086660 --- /dev/null +++ b/ee/app/assets/javascripts/product_analytics/graphql/queries/get_product_analytics_project_settings.query.graphql @@ -0,0 +1,11 @@ +query getProductAnalyticsProjectSettings($projectPath: ID!) { + project(fullPath: $projectPath) { + id + productAnalyticsSettings { + productAnalyticsConfiguratorConnectionString + productAnalyticsDataCollectorHost + cubeApiBaseUrl + cubeApiKey + } + } +} diff --git a/ee/app/graphql/ee/types/project_type.rb b/ee/app/graphql/ee/types/project_type.rb index be70aa008a451ee457505edfc39c9e465c65e058..016bac45d109a9c5da3d2068871adfb93e8fa76b 100644 --- a/ee/app/graphql/ee/types/project_type.rb +++ b/ee/app/graphql/ee/types/project_type.rb @@ -289,6 +289,11 @@ module ProjectType extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1 end + field :product_analytics_settings, + description: 'Project-level settings for product analytics.', + null: true, + resolver: ::Resolvers::Analytics::ProductAnalytics::ProjectSettingsResolver + field :tracking_key, GraphQL::Types::String, null: true, description: 'Tracking key assigned to the project.', diff --git a/ee/app/graphql/resolvers/analytics/product_analytics/project_settings_resolver.rb b/ee/app/graphql/resolvers/analytics/product_analytics/project_settings_resolver.rb new file mode 100644 index 0000000000000000000000000000000000000000..8cae09f455cb802f6273464ba99243c6a50d5efd --- /dev/null +++ b/ee/app/graphql/resolvers/analytics/product_analytics/project_settings_resolver.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Resolvers + module Analytics + module ProductAnalytics + class ProjectSettingsResolver < BaseResolver + include Gitlab::Graphql::Authorize::AuthorizeResource + + authorizes_object! + authorize :maintainer_access + type ::Types::Analytics::ProductAnalytics::ProductAnalyticsProjectSettingsType, null: true + + def resolve + return unless Gitlab::CurrentSettings.product_analytics_enabled? && project.product_analytics_enabled? + + project.project_setting + end + + private + + def project + object.respond_to?(:sync) ? object.sync : object + end + end + end + end +end diff --git a/ee/app/graphql/types/analytics/product_analytics/product_analytics_project_settings_type.rb b/ee/app/graphql/types/analytics/product_analytics/product_analytics_project_settings_type.rb new file mode 100644 index 0000000000000000000000000000000000000000..3659cdc2c024a2b4dd3745bdd00d5589e94cd891 --- /dev/null +++ b/ee/app/graphql/types/analytics/product_analytics/product_analytics_project_settings_type.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +# rubocop: disable Graphql/AuthorizeTypes -- always authorized by Resolver + +module Types + module Analytics + module ProductAnalytics + class ProductAnalyticsProjectSettingsType < BaseObject + graphql_name 'ProductAnalyticsProjectSettings' + description 'Project-level settings for product analytics provider.' + + field :product_analytics_configurator_connection_string, GraphQL::Types::String, null: true, + description: 'Connection string for the product analytics configurator.' + + field :cube_api_base_url, GraphQL::Types::String, null: true, + description: 'Base URL for the Cube API.' + + # rubocop:disable GraphQL/ExtractType -- keep property names matching everywhere else in the codebase + field :product_analytics_data_collector_host, GraphQL::Types::String, null: true, + description: 'Host for the product analytics data collector.' + + field :cube_api_key, GraphQL::Types::String, null: true, + description: 'API key for the Cube API.' + # rubocop:enable GraphQL/ExtractType + end + end + end +end +# rubocop: enable Graphql/AuthorizeTypes diff --git a/ee/spec/graphql/resolvers/analytics/product_analytics/project_settings_resolver_spec.rb b/ee/spec/graphql/resolvers/analytics/product_analytics/project_settings_resolver_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..3e7d97962f8c2ceaa7b7f4afdbee258c354f292e --- /dev/null +++ b/ee/spec/graphql/resolvers/analytics/product_analytics/project_settings_resolver_spec.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Resolvers::Analytics::ProductAnalytics::ProjectSettingsResolver, feature_category: :product_analytics_data_management do + include GraphqlHelpers + + describe '#resolve' do + subject(:result) { resolve(described_class, obj: project, ctx: { current_user: user }) } + + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project) } + + before do + allow(Gitlab::CurrentSettings).to receive(:product_analytics_enabled?).and_return(true) + stub_licensed_features(product_analytics: true) + end + + context 'when user has guest access' do + before_all do + project.add_guest(user) + end + + it { is_expected.to be_nil } + end + + context 'when user has developer access' do + before_all do + project.add_developer(user) + end + + it { is_expected.to be_nil } + end + + context 'when user has maintainer access' do + before_all do + project.add_maintainer(user) + end + + context 'when product analytics is not enabled for the project' do + before do + allow(project).to receive(:product_analytics_enabled).and_return(false) + end + + it { is_expected.to be_nil } + end + + context 'when product analytics is enabled for the project' do + before do + allow(project).to receive(:product_analytics_enabled?).and_return(true) + + project.project_setting.update!( + product_analytics_configurator_connection_string: 'https://test:test@configurator.example.com', + product_analytics_data_collector_host: 'https://collector.example.com', + cube_api_base_url: 'https://cube.example.com', + cube_api_key: '123-cube-api-key' + ) + end + + it 'returns the project settings' do + expect(result).to have_attributes( + product_analytics_configurator_connection_string: 'https://test:test@configurator.example.com', + product_analytics_data_collector_host: 'https://collector.example.com', + cube_api_base_url: 'https://cube.example.com', + cube_api_key: '123-cube-api-key' + ) + end + end + end + end +end diff --git a/ee/spec/graphql/types/analytics/product_analytics/product_analytics_project_settings_type_spec.rb b/ee/spec/graphql/types/analytics/product_analytics/product_analytics_project_settings_type_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..424222db1d7d69c2ee96b84c5c1de0dbd8cb58a0 --- /dev/null +++ b/ee/spec/graphql/types/analytics/product_analytics/product_analytics_project_settings_type_spec.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['ProductAnalyticsProjectSettings'], feature_category: :product_analytics_data_management do + let(:expected_fields) do + %i[product_analytics_configurator_connection_string + product_analytics_data_collector_host cube_api_base_url cube_api_key] + end + + subject { described_class } + + it { is_expected.to have_graphql_fields(expected_fields) } +end