From e4cfc16da343c2008053ee09bb6af7145a6924cb Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Mon, 12 Sep 2022 18:10:22 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .../push_access_level_type.rb | 11 ++ .../branch_rules/branch_protection_type.rb | 5 + doc/api/graphql/reference/index.md | 35 ++++++ doc/user/usage_quotas.md | 4 +- .../types/branch_protection_type_spec.rb | 2 +- .../push_access_level_type_spec.rb | 13 +++ .../push_access_levels_spec.rb | 109 ++++++++++++++++++ 7 files changed, 176 insertions(+), 3 deletions(-) create mode 100644 app/graphql/types/branch_protections/push_access_level_type.rb create mode 100644 spec/graphql/types/branch_protections/push_access_level_type_spec.rb create mode 100644 spec/requests/api/graphql/project/branch_protections/push_access_levels_spec.rb diff --git a/app/graphql/types/branch_protections/push_access_level_type.rb b/app/graphql/types/branch_protections/push_access_level_type.rb new file mode 100644 index 00000000000..bfbdc4edbea --- /dev/null +++ b/app/graphql/types/branch_protections/push_access_level_type.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Types + module BranchProtections + class PushAccessLevelType < BaseAccessLevelType # rubocop:disable Graphql/AuthorizeTypes + graphql_name 'PushAccessLevel' + description 'Represents the push access level of a branch protection.' + accepts ::ProtectedBranch::PushAccessLevel + end + end +end diff --git a/app/graphql/types/branch_rules/branch_protection_type.rb b/app/graphql/types/branch_rules/branch_protection_type.rb index 02379dcf558..d475abb8665 100644 --- a/app/graphql/types/branch_rules/branch_protection_type.rb +++ b/app/graphql/types/branch_rules/branch_protection_type.rb @@ -13,6 +13,11 @@ module Types null: true, description: 'Details about who can merge when this branch is the source branch.' + field :push_access_levels, + type: Types::BranchProtections::PushAccessLevelType.connection_type, + null: true, + description: 'Details about who can push when this branch is the source branch.' + field :allow_force_push, type: GraphQL::Types::Boolean, null: false, diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index ebe922239c9..fd36ec083ad 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -8418,6 +8418,29 @@ The edge type for [`ProjectMember`](#projectmember). | `cursor` | [`String!`](#string) | A cursor for use in pagination. | | `node` | [`ProjectMember`](#projectmember) | The item at the end of the edge. | +#### `PushAccessLevelConnection` + +The connection type for [`PushAccessLevel`](#pushaccesslevel). + +##### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `edges` | [`[PushAccessLevelEdge]`](#pushaccessleveledge) | A list of edges. | +| `nodes` | [`[PushAccessLevel]`](#pushaccesslevel) | A list of nodes. | +| `pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. | + +#### `PushAccessLevelEdge` + +The edge type for [`PushAccessLevel`](#pushaccesslevel). + +##### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `cursor` | [`String!`](#string) | A cursor for use in pagination. | +| `node` | [`PushAccessLevel`](#pushaccesslevel) | The item at the end of the edge. | + #### `ReleaseAssetLinkConnection` The connection type for [`ReleaseAssetLink`](#releaseassetlink). @@ -10107,6 +10130,7 @@ Branch protection details for a branch rule. | ---- | ---- | ----------- | | `allowForcePush` | [`Boolean!`](#boolean) | Toggle force push to the branch for users with write access. | | `mergeAccessLevels` | [`MergeAccessLevelConnection`](#mergeaccesslevelconnection) | Details about who can merge when this branch is the source branch. (see [Connections](#connections)) | +| `pushAccessLevels` | [`PushAccessLevelConnection`](#pushaccesslevelconnection) | Details about who can push when this branch is the source branch. (see [Connections](#connections)) | ### `BranchRule` @@ -17109,6 +17133,17 @@ The alert condition for Prometheus. | `humanizedText` | [`String!`](#string) | Human-readable text of the alert condition. | | `id` | [`ID!`](#id) | ID of the alert condition. | +### `PushAccessLevel` + +Represents the push access level of a branch protection. + +#### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `accessLevel` | [`Int!`](#int) | GitLab::Access level. | +| `accessLevelDescription` | [`String!`](#string) | Human readable representation for this access level. | + ### `PushRules` Represents rules that commit pushes must follow. diff --git a/doc/user/usage_quotas.md b/doc/user/usage_quotas.md index 2ec2f0a5dc6..56220fb9906 100644 --- a/doc/user/usage_quotas.md +++ b/doc/user/usage_quotas.md @@ -57,8 +57,8 @@ you must purchase additional storage. For more details, see [Excess storage usag Prerequisites: -- To view storage usage for a project, you must be a project Maintainer or namespace Owner. -- To view storage usage for a namespace, you must be the namespace Owner. +- To view storage usage for a project, you must have at least the Maintainer role for the project or Owner role for the namespace. +- To view storage usage for a namespace, you must have the Owner role for the namespace. 1. Go to your project or namespace: - For a project, on the top bar, select **Menu > Projects** and find your project. diff --git a/spec/graphql/types/branch_protection_type_spec.rb b/spec/graphql/types/branch_protection_type_spec.rb index 5891df666c5..40f6a852813 100644 --- a/spec/graphql/types/branch_protection_type_spec.rb +++ b/spec/graphql/types/branch_protection_type_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' RSpec.describe GitlabSchema.types['BranchProtection'] do subject { described_class } - let(:fields) { %i[merge_access_levels allow_force_push] } + let(:fields) { %i[merge_access_levels push_access_levels allow_force_push] } specify { is_expected.to require_graphql_authorizations(:read_protected_branch) } diff --git a/spec/graphql/types/branch_protections/push_access_level_type_spec.rb b/spec/graphql/types/branch_protections/push_access_level_type_spec.rb new file mode 100644 index 00000000000..c78c0bda74c --- /dev/null +++ b/spec/graphql/types/branch_protections/push_access_level_type_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['PushAccessLevel'] do + subject { described_class } + + let(:fields) { %i[access_level access_level_description] } + + specify { is_expected.to require_graphql_authorizations(:read_protected_branch) } + + specify { is_expected.to have_graphql_fields(fields).at_least } +end diff --git a/spec/requests/api/graphql/project/branch_protections/push_access_levels_spec.rb b/spec/requests/api/graphql/project/branch_protections/push_access_levels_spec.rb new file mode 100644 index 00000000000..59f9c7d61cb --- /dev/null +++ b/spec/requests/api/graphql/project/branch_protections/push_access_levels_spec.rb @@ -0,0 +1,109 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'getting push access levels for a branch protection' do + include GraphqlHelpers + + let_it_be(:current_user) { create(:user) } + + let(:push_access_level_data) { push_access_levels_data[0] } + + let(:push_access_levels_data) do + graphql_data_at('project', + 'branchRules', + 'nodes', + 0, + 'branchProtection', + 'pushAccessLevels', + 'nodes') + end + + let(:project) { protected_branch.project } + + let(:push_access_levels_count) { protected_branch.push_access_levels.size } + + let(:variables) { { path: project.full_path } } + + let(:fields) { all_graphql_fields_for('PushAccessLevel'.classify) } + + let(:query) do + <<~GQL + query($path: ID!) { + project(fullPath: $path) { + branchRules(first: 1) { + nodes { + branchProtection { + pushAccessLevels { + nodes { + #{fields} + } + } + } + } + } + } + } + GQL + end + + context 'when the user does not have read_protected_branch abilities' do + let_it_be(:protected_branch) { create(:protected_branch) } + + before do + project.add_guest(current_user) + post_graphql(query, current_user: current_user, variables: variables) + end + + it_behaves_like 'a working graphql query' + + it { expect(push_access_levels_data).not_to be_present } + end + + shared_examples 'push access request' do + let(:push_access) { protected_branch.push_access_levels.first } + + before do + project.add_maintainer(current_user) + post_graphql(query, current_user: current_user, variables: variables) + end + + it_behaves_like 'a working graphql query' + + it 'returns all push access levels' do + expect(push_access_levels_data.size).to eq(push_access_levels_count) + end + + it 'includes access_level' do + expect(push_access_level_data['accessLevel']) + .to eq(push_access.access_level) + end + + it 'includes access_level_description' do + expect(push_access_level_data['accessLevelDescription']) + .to eq(push_access.humanize) + end + end + + context 'when the user does have read_protected_branch abilities' do + let(:push_access) { protected_branch.push_access_levels.first } + + context 'when no one has access' do + let_it_be(:protected_branch) { create(:protected_branch, :no_one_can_push) } + + it_behaves_like 'push access request' + end + + context 'when developers have access' do + let_it_be(:protected_branch) { create(:protected_branch, :developers_can_push) } + + it_behaves_like 'push access request' + end + + context 'when maintainers have access' do + let_it_be(:protected_branch) { create(:protected_branch, :maintainers_can_push) } + + it_behaves_like 'push access request' + end + end +end