Skip to content
代码片段 群组 项目
未验证 提交 33f8e616 编辑于 作者: Doug Stull's avatar Doug Stull 提交者: GitLab
浏览文件

Merge branch 'acook/440485_add_duo_features_enabled_graphql' into 'master'

Add projectSettingsUpdate mutation

See merge request https://gitlab.com/gitlab-org/gitlab/-/merge_requests/143972



Merged-by: default avatarDoug Stull <dstull@gitlab.com>
Approved-by: default avatarDoug Stull <dstull@gitlab.com>
Reviewed-by: default avatarDoug Stull <dstull@gitlab.com>
Reviewed-by: default avatarJessie Young <jessieyoung@gitlab.com>
Co-authored-by: default avatarAllen Cook <acook@gitlab.com>
Co-authored-by: default avatarJessie Young <jessieyoung@gitlab.com>
No related branches found
No related tags found
无相关合并请求
......@@ -6497,6 +6497,30 @@ Input type: `ProjectSetLockedInput`
| <a id="mutationprojectsetlockederrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationprojectsetlockedproject"></a>`project` | [`Project`](#project) | Project after mutation. |
 
### `Mutation.projectSettingsUpdate`
NOTE:
**Introduced** in 16.9.
**Status**: Experiment.
Input type: `ProjectSettingsUpdateInput`
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationprojectsettingsupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationprojectsettingsupdateduofeaturesenabled"></a>`duoFeaturesEnabled` | [`Boolean!`](#boolean) | Indicates whether GitLab Duo features are enabled for the project. |
| <a id="mutationprojectsettingsupdatefullpath"></a>`fullPath` | [`ID!`](#id) | Full Path of the project the settings belong to. |
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationprojectsettingsupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationprojectsettingsupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationprojectsettingsupdateprojectsettings"></a>`projectSettings` | [`ProjectSetting!`](#projectsetting) | Project settings after mutation. |
### `Mutation.projectSubscriptionCreate`
 
Input type: `ProjectSubscriptionCreateInput`
......@@ -24600,6 +24624,7 @@ Represents vulnerability finding of a security report on the pipeline.
| <a id="projectdescriptionhtml"></a>`descriptionHtml` | [`String`](#string) | GitLab Flavored Markdown rendering of `description`. |
| <a id="projectdetailedimportstatus"></a>`detailedImportStatus` | [`DetailedImportStatus`](#detailedimportstatus) | Detailed import status of the project. |
| <a id="projectdora"></a>`dora` | [`Dora`](#dora) | Project's DORA metrics. |
| <a id="projectduofeaturesenabled"></a>`duoFeaturesEnabled` **{warning-solid}** | [`Boolean`](#boolean) | **Introduced** in 16.9. **Status**: Experiment. Indicates whether GitLab Duo features are enabled for the project. |
| <a id="projectflowmetrics"></a>`flowMetrics` **{warning-solid}** | [`ProjectValueStreamAnalyticsFlowMetrics`](#projectvaluestreamanalyticsflowmetrics) | **Introduced** in 15.10. **Status**: Experiment. Flow metrics for value stream analytics. |
| <a id="projectforkingaccesslevel"></a>`forkingAccessLevel` | [`ProjectFeatureAccess`](#projectfeatureaccess) | Access level required for forking access. |
| <a id="projectforkscount"></a>`forksCount` | [`Int!`](#int) | Number of times the project has been forked. |
......@@ -26384,6 +26409,15 @@ Represents the source of a security policy belonging to a project.
| <a id="projectsecuritytrainingname"></a>`name` | [`String!`](#string) | Name of the training provider. |
| <a id="projectsecuritytrainingurl"></a>`url` | [`String!`](#string) | URL of the provider. |
 
### `ProjectSetting`
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="projectsettingduofeaturesenabled"></a>`duoFeaturesEnabled` | [`Boolean`](#boolean) | Indicates whether GitLab Duo features are enabled for the project. |
| <a id="projectsettingproject"></a>`project` | [`Project`](#project) | Project the settings belong to. |
### `ProjectStatistics`
 
#### Fields
......@@ -97,6 +97,7 @@ module MutationType
mount_mutation ::Mutations::IncidentManagement::IssuableResourceLink::Destroy
mount_mutation ::Mutations::AppSec::Fuzzing::Coverage::Corpus::Create
mount_mutation ::Mutations::Projects::SetComplianceFramework
mount_mutation ::Mutations::Projects::ProjectSettingsUpdate, alpha: { milestone: '16.9' }
mount_mutation ::Mutations::Projects::InitializeProductAnalytics
mount_mutation ::Mutations::SecurityPolicy::CommitScanExecutionPolicy
mount_mutation ::Mutations::SecurityPolicy::AssignSecurityPolicyProject
......
......@@ -245,6 +245,11 @@ module ProjectType
description: 'Indicates that merges of merge requests should be blocked ' \
'unless all status checks have passed.'
field :duo_features_enabled, GraphQL::Types::Boolean,
null: true,
alpha: { milestone: '16.9' },
description: 'Indicates whether GitLab Duo features are enabled for the project.'
field :gitlab_subscriptions_preview_billable_user_change,
::Types::GitlabSubscriptions::PreviewBillableUserChangeType,
null: true,
......
# frozen_string_literal: true
module Mutations
module Projects
class ProjectSettingsUpdate < BaseMutation
graphql_name 'ProjectSettingsUpdate'
include FindsProject
include Gitlab::Utils::StrongMemoize
authorize :admin_project
argument :full_path,
GraphQL::Types::ID,
required: true,
description: 'Full Path of the project the settings belong to.'
argument :duo_features_enabled,
GraphQL::Types::Boolean,
required: true,
description: 'Indicates whether GitLab Duo features are enabled for the project.'
field :project_settings,
Types::Projects::SettingType,
null: false,
description: 'Project settings after mutation.'
def resolve(full_path:, **args)
raise raise_resource_not_available_error! unless allowed?
settings = authorized_find!(full_path).project_setting
settings.update(args)
{
project_settings: settings,
errors: errors_on_object(settings)
}
end
private
def allowed?
# TODO clean up via https://gitlab.com/gitlab-org/gitlab/-/issues/440546
return true if ::Gitlab::Saas.feature_available?(:duo_chat_on_saas)
return false unless ::License.feature_available?(:code_suggestions)
if ::CodeSuggestions::SelfManaged::SERVICE_START_DATE.past?
::GitlabSubscriptions::AddOnPurchase
.for_code_suggestions
.any?
else # Before service start date
# TODO: Remove this else branch after the service start date
::Gitlab::CurrentSettings.instance_level_code_suggestions_enabled
end
end
end
end
end
# frozen_string_literal: true
module Types
module Projects
# rubocop: disable Graphql/AuthorizeTypes -- parent handles auth
class SettingType < BaseObject
graphql_name 'ProjectSetting'
field :duo_features_enabled,
GraphQL::Types::Boolean,
null: true,
description: 'Indicates whether GitLab Duo features are enabled for the project.'
field :project,
Types::ProjectType,
null: true,
description: 'Project the settings belong to.'
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Mutations::Projects::ProjectSettingsUpdate, feature_category: :code_suggestions do
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
let_it_be(:user) { create(:user) }
let_it_be(:namespace) { create(:group) }
let_it_be(:add_on) { create(:gitlab_subscription_add_on, :code_suggestions) }
let_it_be(:add_on_purchase) { create(:gitlab_subscription_add_on_purchase, namespace: namespace, add_on: add_on) }
let_it_be(:project) { create(:project, namespace: namespace) }
let_it_be(:project_without_addon) { create(:project) }
describe '#resolve' do
subject(:resolve) do
mutation.resolve(
full_path: project.full_path,
duo_features_enabled: duo_features_enabled)
end
let(:duo_features_enabled) { true }
it 'raises an error if the resource is not accessible to the user' do
expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
context 'when the user can update duo features enabled' do
before_all do
project.add_owner(user)
end
context 'when duo features are not available' do
before do
stub_licensed_features(code_suggestions: false)
end
it 'raises an error' do
expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
context 'when duo addon is not available' do
before do
stub_licensed_features(code_suggestions: true)
stub_const("::CodeSuggestions::SelfManaged::SERVICE_START_DATE", Time.zone.parse('2000-02-15T00:00:00Z'))
end
it 'raises an error' do
expect do
mutation.resolve(full_path: project_without_addon.full_path,
duo_features_enabled: duo_features_enabled)
end.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
context 'when instance has it disabled' do
before do
stub_licensed_features(code_suggestions: true)
stub_const("::CodeSuggestions::SelfManaged::SERVICE_START_DATE", Time.zone.parse('3000-02-15T00:00:00Z'))
stub_application_setting(instance_level_code_suggestions_enabled: false)
end
it 'raises an error' do
expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
context 'when duo chat is enabled on saas' do
before do
stub_licensed_features(code_suggestions: false)
stub_saas_features(duo_chat_on_saas: true)
end
it 'updates the setting' do
expect(resolve[:project_settings]).to have_attributes(duo_features_enabled: duo_features_enabled)
end
end
context 'when disabling duo features' do
let(:duo_features_enabled) { false }
before do
stub_saas_features(duo_chat_on_saas: true)
end
it 'updates the setting' do
expect(resolve[:project_settings]).to have_attributes(duo_features_enabled: duo_features_enabled)
end
end
end
context 'when user cannot update duo features enabled' do
before_all do
project.add_developer(user)
end
it 'will raise an error' do
expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
end
end
......@@ -29,7 +29,7 @@
security_policy_project security_training_urls vulnerability_images only_allow_merge_if_all_status_checks_passed
security_policy_project_linked_projects security_policy_project_linked_namespaces
dependencies merge_requests_disable_committers_approval has_jira_vulnerability_issue_creation_enabled
ci_subscriptions_projects ci_subscribed_projects ai_agents
ci_subscriptions_projects ci_subscribed_projects ai_agents duo_features_enabled
]
expect(described_class).to include_graphql_fields(*expected_fields)
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe "Project settings update", feature_category: :code_suggestions do
include GraphqlHelpers
include ProjectForksHelper
include ExclusiveLeaseHelpers
let_it_be(:user) { create(:user) }
let_it_be(:namespace) { create(:group) }
let_it_be(:add_on) { create(:gitlab_subscription_add_on, :code_suggestions) }
let_it_be(:add_on_purchase) { create(:gitlab_subscription_add_on_purchase, namespace: namespace, add_on: add_on) }
let_it_be(:project) { create(:project, namespace: namespace) }
let_it_be(:duo_features_enabled) { true }
let(:mutation) do
params = { full_path: project.full_path, duo_features_enabled: duo_features_enabled }
graphql_mutation(:project_settings_update, params) do
<<-QL.strip_heredoc
projectSettings {
duoFeaturesEnabled
}
errors
QL
end
end
context 'when updating settings' do
before_all do
project.add_maintainer(user)
end
before do
stub_saas_features(duo_chat_on_saas: true)
end
it 'will update the settings' do
post_graphql_mutation(mutation, current_user: user)
expect(graphql_mutation_response('projectSettingsUpdate')['projectSettings'])
.to eq({ 'duoFeaturesEnabled' => duo_features_enabled })
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'querying duoFeaturesEnabled', feature_category: :code_suggestions do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
describe 'duoFeaturesEnabled' do
before_all do
project.add_maintainer(current_user)
end
it 'is available to query' do
result = GitlabSchema.execute(%(
query {
project(fullPath: "#{project.full_path}") {
duoFeaturesEnabled
}
}
), context: { current_user: current_user }).as_json
expect(result.dig('data', 'project', 'duoFeaturesEnabled')).to eq(project.duo_features_enabled)
end
end
end
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册