Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-12-20 06:20:24 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-12-20 06:20:24 +0300
commitd99f2ee027ec0f098207ce7df55feac0021a36c1 (patch)
tree10229774f2d7f11d3bd1981b8999e4be41b42114
parent27272e0696cedeed1f55f3ce09983fe8e849f7ba (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/finders/projects_finder.rb11
-rw-r--r--app/graphql/mutations/branch_rules/create.rb56
-rw-r--r--app/graphql/resolvers/organizations/projects_resolver.rb19
-rw-r--r--app/graphql/types/mutation_type.rb1
-rw-r--r--app/graphql/types/organizations/organization_type.rb4
-rw-r--r--app/models/integrations/squash_tm.rb2
-rw-r--r--doc/administration/gitaly/troubleshooting.md17
-rw-r--r--doc/api/graphql/reference/index.md25
-rw-r--r--doc/api/integrations.md2
-rw-r--r--doc/development/documentation/styleguide/word_list.md33
-rw-r--r--doc/user/packages/container_registry/authenticate_with_container_registry.md6
-rw-r--r--doc/user/project/repository/code_suggestions/index.md10
-rw-r--r--doc/user/project/wiki/index.md25
-rw-r--r--lib/api/helpers/integrations_helpers.rb15
-rw-r--r--lib/gitlab/application_setting_fetcher.rb33
-rw-r--r--lib/gitlab/current_settings.rb14
-rw-r--r--locale/gitlab.pot6
-rw-r--r--spec/finders/projects_finder_spec.rb4
-rw-r--r--spec/graphql/types/organizations/organization_type_spec.rb4
-rw-r--r--spec/lib/gitlab/application_setting_fetcher_spec.rb66
-rw-r--r--spec/lib/gitlab/current_settings_spec.rb19
-rw-r--r--spec/requests/api/graphql/mutations/branch_rules/create_spec.rb68
-rw-r--r--spec/requests/api/graphql/organizations/organization_query_spec.rb189
-rw-r--r--spec/spec_helper.rb1
-rw-r--r--spec/support/migration.rb1
25 files changed, 490 insertions, 141 deletions
diff --git a/app/finders/projects_finder.rb b/app/finders/projects_finder.rb
index 2a781c037f6..57eea577419 100644
--- a/app/finders/projects_finder.rb
+++ b/app/finders/projects_finder.rb
@@ -29,7 +29,7 @@
# repository_storage: string
# not_aimed_for_deletion: boolean
# full_paths: string[]
-# organization_id: int
+# organization: Scope the groups to the Organizations::Organization
#
class ProjectsFinder < UnionFinder
include CustomAttributesFilter
@@ -96,7 +96,7 @@ class ProjectsFinder < UnionFinder
collection = by_language(collection)
collection = by_feature_availability(collection)
collection = by_updated_at(collection)
- collection = by_organization_id(collection)
+ collection = by_organization(collection)
by_repository_storage(collection)
end
@@ -295,8 +295,11 @@ class ProjectsFinder < UnionFinder
items
end
- def by_organization_id(items)
- params[:organization_id].present? ? items.in_organization(params[:organization_id]) : items
+ def by_organization(items)
+ organization = params[:organization]
+ return items unless organization
+
+ items.in_organization(organization)
end
def finder_params
diff --git a/app/graphql/mutations/branch_rules/create.rb b/app/graphql/mutations/branch_rules/create.rb
new file mode 100644
index 00000000000..c478d981c33
--- /dev/null
+++ b/app/graphql/mutations/branch_rules/create.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+module Mutations
+ module BranchRules
+ class Create < BaseMutation
+ graphql_name 'BranchRuleCreate'
+
+ argument :project_path, GraphQL::Types::ID,
+ required: true,
+ description: 'Full path to the project that the branch is associated with.'
+
+ argument :name, GraphQL::Types::String,
+ required: true,
+ description: 'Branch name, with wildcards, for the branch rules.'
+
+ field :branch_rule,
+ Types::Projects::BranchRuleType,
+ null: true,
+ description: 'Branch rule after mutation.'
+
+ def resolve(project_path:, name:)
+ project = Project.find_by_full_path(project_path)
+
+ service_params = protected_branch_params(name)
+ protected_branch = ::ProtectedBranches::CreateService.new(project, current_user, service_params).execute
+
+ if protected_branch.persisted?
+ {
+ branch_rule: ::Projects::BranchRule.new(project, protected_branch),
+ errors: []
+ }
+ else
+ { errors: errors_on_object(protected_branch) }
+ end
+ rescue Gitlab::Access::AccessDeniedError
+ raise_resource_not_available_error!
+ end
+
+ def protected_branch_params(name)
+ {
+ name: name,
+ push_access_levels_attributes: access_level_attributes(:push),
+ merge_access_levels_attributes: access_level_attributes(:merge)
+ }
+ end
+
+ def access_level_attributes(type)
+ ::ProtectedRefs::AccessLevelParams.new(
+ type,
+ {},
+ with_defaults: true
+ ).access_levels
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/organizations/projects_resolver.rb b/app/graphql/resolvers/organizations/projects_resolver.rb
new file mode 100644
index 00000000000..836fe0ae059
--- /dev/null
+++ b/app/graphql/resolvers/organizations/projects_resolver.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Organizations
+ class ProjectsResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ type Types::ProjectType, null: true
+
+ authorize :read_project
+
+ alias_method :organization, :object
+
+ def resolve
+ ::ProjectsFinder.new(current_user: current_user, params: { organization: organization }).execute
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index 590bc0ed282..4c987c657ef 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -111,6 +111,7 @@ module Types
mount_mutation Mutations::Projects::SyncFork, calls_gitaly: true, alpha: { milestone: '15.9' }
mount_mutation Mutations::Projects::Star, alpha: { milestone: '16.7' }
mount_mutation Mutations::BranchRules::Update, alpha: { milestone: '16.7' }
+ mount_mutation Mutations::BranchRules::Create, alpha: { milestone: '16.7' }
mount_mutation Mutations::Releases::Create
mount_mutation Mutations::Releases::Update
mount_mutation Mutations::Releases::Delete
diff --git a/app/graphql/types/organizations/organization_type.rb b/app/graphql/types/organizations/organization_type.rb
index 379bf9956a3..d36c92541ef 100644
--- a/app/graphql/types/organizations/organization_type.rb
+++ b/app/graphql/types/organizations/organization_type.rb
@@ -43,6 +43,10 @@ module Types
null: false,
description: 'Path of the organization.',
alpha: { milestone: '16.4' }
+ field :projects, Types::ProjectType.connection_type, null: false,
+ description: 'Projects within this organization that the user has access to.',
+ alpha: { milestone: '16.8' },
+ resolver: ::Resolvers::Organizations::ProjectsResolver
field :web_url,
GraphQL::Types::String,
null: false,
diff --git a/app/models/integrations/squash_tm.rb b/app/models/integrations/squash_tm.rb
index 1b4ab152b1d..7aaef0c22cc 100644
--- a/app/models/integrations/squash_tm.rb
+++ b/app/models/integrations/squash_tm.rb
@@ -7,12 +7,14 @@ module Integrations
field :url,
placeholder: 'https://your-instance.squashcloud.io/squash/plugin/xsquash4gitlab/webhook/issue',
title: -> { s_('SquashTmIntegration|Squash TM webhook URL') },
+ description: -> { s_('URL of the Squash TM webhook.') },
exposes_secrets: true,
required: true
field :token,
type: :password,
title: -> { s_('SquashTmIntegration|Secret token (optional)') },
+ description: -> { s_('Secret token.') },
non_empty_password_title: -> { s_('ProjectService|Enter new token') },
non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') },
required: false
diff --git a/doc/administration/gitaly/troubleshooting.md b/doc/administration/gitaly/troubleshooting.md
index 7d0255a3efb..211b5d67ef4 100644
--- a/doc/administration/gitaly/troubleshooting.md
+++ b/doc/administration/gitaly/troubleshooting.md
@@ -441,6 +441,23 @@ To resolve this, remove the `noexec` option from the file system mount. An alter
Because Gitaly commit signing is headless and not associated with a specific user, the GPG signing key must be created without a passphrase, or the passphrase must be removed before export.
+### Gitaly logs show errors in `info` messages
+
+Because of a bug [introduced](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/6201) in GitLab 16.3, additional entries were written to the
+[Gitaly logs](../logs/index.md#gitaly-logs). These log entries contained `"level":"info"` but the `msg` string appeared to contain an error.
+
+For example:
+
+```json
+{"level":"info","msg":"[core] [Server #3] grpc: Server.Serve failed to create ServerTransport: connection error: desc = \"ServerHandshake(\\\"x.x.x.x:x\\\") failed: wrapped server handshake: EOF\"","pid":6145,"system":"system","time":"2023-12-14T21:20:39.999Z"}
+```
+
+The reason for this log entry is that the underlying gRPC library sometimes output verbose transportation logs. These log entries appear to be errors but are, in general,
+safe to ignore.
+
+This bug was [fixed](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/6513/) in GitLab 16.4.5, 16.5.5, and 16.6.0, which prevents these types of messages from
+being written to the Gitaly logs.
+
## Troubleshoot Praefect (Gitaly Cluster)
The following sections provide possible solutions to Gitaly Cluster errors.
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index ee44d76a773..7f5b6cf52c9 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -1945,6 +1945,30 @@ Input type: `BoardListUpdateLimitMetricsInput`
| <a id="mutationboardlistupdatelimitmetricserrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationboardlistupdatelimitmetricslist"></a>`list` | [`BoardList`](#boardlist) | Updated list. |
+### `Mutation.branchRuleCreate`
+
+WARNING:
+**Introduced** in 16.7.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Input type: `BranchRuleCreateInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationbranchrulecreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationbranchrulecreatename"></a>`name` | [`String!`](#string) | Branch name, with wildcards, for the branch rules. |
+| <a id="mutationbranchrulecreateprojectpath"></a>`projectPath` | [`ID!`](#id) | Full path to the project that the branch is associated with. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationbranchrulecreatebranchrule"></a>`branchRule` | [`BranchRule`](#branchrule) | Branch rule after mutation. |
+| <a id="mutationbranchrulecreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationbranchrulecreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+
### `Mutation.branchRuleUpdate`
WARNING:
@@ -23335,6 +23359,7 @@ Active period time range for on-call rotation.
| <a id="organizationname"></a>`name` **{warning-solid}** | [`String!`](#string) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Name of the organization. |
| <a id="organizationorganizationusers"></a>`organizationUsers` **{warning-solid}** | [`OrganizationUserConnection!`](#organizationuserconnection) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Users with access to the organization. |
| <a id="organizationpath"></a>`path` **{warning-solid}** | [`String!`](#string) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Path of the organization. |
+| <a id="organizationprojects"></a>`projects` **{warning-solid}** | [`ProjectConnection!`](#projectconnection) | **Introduced** in 16.8. This feature is an Experiment. It can be changed or removed at any time. Projects within this organization that the user has access to. |
| <a id="organizationweburl"></a>`webUrl` **{warning-solid}** | [`String!`](#string) | **Introduced** in 16.6. This feature is an Experiment. It can be changed or removed at any time. Web URL of the organization. |
#### Fields with arguments
diff --git a/doc/api/integrations.md b/doc/api/integrations.md
index f713d845762..ab0337e25c8 100644
--- a/doc/api/integrations.md
+++ b/doc/api/integrations.md
@@ -1423,7 +1423,7 @@ Parameters:
| Parameter | Type | Required | Description |
|-------------------------|--------|----------|-------------------------------|
| `url` | string | yes | URL of the Squash TM webhook. |
-| `token` | string | no | Optional token. |
+| `token` | string | no | Secret token. |
### Disable Squash TM
diff --git a/doc/development/documentation/styleguide/word_list.md b/doc/development/documentation/styleguide/word_list.md
index 9d0d59e27c5..1f34ab3fb1e 100644
--- a/doc/development/documentation/styleguide/word_list.md
+++ b/doc/development/documentation/styleguide/word_list.md
@@ -239,6 +239,22 @@ Use **text box** to refer to the UI field. Do not use **field** or **box**. For
- In the **Variable name** text box, enter a value.
+## branch
+
+Use **branch** by itself to describe a branch. For specific branches, use these terms only:
+
+- **default branch**: The primary branch in the repository. Users can use the UI to set the default
+ branch. For examples that use the default branch, use `main` instead of [`master`](#master).
+- **source branch**: The branch you're merging from.
+- **target branch**: The branch you're merging to.
+- **current branch**: The branch you have checked out.
+ This branch might be the default branch, a branch you've created, a source branch, or some other branch.
+
+Do not use the terms **feature branch** or **merge request branch**. Be as specific as possible. For example:
+
+- The branch you have checked out...
+- The branch you added commits to...
+
## bullet
Don't refer to individual items in an ordered or unordered list as **bullets**. Use **list item** instead. If you need to be less ambiguous, you can use:
@@ -428,13 +444,6 @@ Instead of:
- Data are collected.
- The data show a performance increase.
-## default branch
-
-Use **default branch** to refer generically to the primary branch in the repository.
-Users can set the default branch by using a UI setting.
-
-For examples that use the default branch, use `main` instead of [`master`](#master).
-
## delete
Use **delete** when an object is completely deleted. **Delete** is the opposite of **create**.
@@ -661,6 +670,10 @@ Instead of:
- Use the merge request feature to incorporate changes into the target branch.
+## feature branch
+
+Do not use **feature branch**. See [branch](#branch).
+
## field
Use **text box** instead of **field** or **box**.
@@ -1083,7 +1096,7 @@ Do not use **manpower**. Use words like **workforce** or **GitLab team members**
## master
-Do not use `master`. Use `main` when you need a sample [default branch name](#default-branch).
+Do not use **master**. Use **main** when you need a sample [default branch name](#branch).
([Vale](../testing.md#vale) rule: [`InclusionCultural.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/InclusionCultural.yml))
## may, might
@@ -1115,6 +1128,10 @@ For **MB** and **GB**, follow the [Microsoft guidance](https://learn.microsoft.c
When you add a [user account](#user-account) to a group or project,
the user account becomes a **member**.
+## merge request branch
+
+Do not use **merge request branch**. See [branch](#branch).
+
## merge requests
Use lowercase for **merge requests**. If you use **MR** as the acronym, spell it out on first use.
diff --git a/doc/user/packages/container_registry/authenticate_with_container_registry.md b/doc/user/packages/container_registry/authenticate_with_container_registry.md
index ae19a891fc9..6e1c0ded758 100644
--- a/doc/user/packages/container_registry/authenticate_with_container_registry.md
+++ b/doc/user/packages/container_registry/authenticate_with_container_registry.md
@@ -20,9 +20,9 @@ All of these authentication methods require the minimum scope:
To authenticate, run the `docker login` command. For example:
- ```shell
- docker login registry.example.com -u <username> -p <token>
- ```
+```shell
+docker login registry.example.com -u <username> -p <token>
+```
## Use GitLab CI/CD to authenticate
diff --git a/doc/user/project/repository/code_suggestions/index.md b/doc/user/project/repository/code_suggestions/index.md
index cc036ae00d8..875b72354e4 100644
--- a/doc/user/project/repository/code_suggestions/index.md
+++ b/doc/user/project/repository/code_suggestions/index.md
@@ -18,8 +18,10 @@ Write code more efficiently by using generative AI to suggest code while you're
With Code Suggestions, you get:
-- Code Completion, which suggests completions the current line you are typing. These suggestions are usually low latency.
-- Code Generation, which generates code based on a natural language code comment block. Responses for code generation are streamed in VS Code to begin giving results quickly. In other IDEs, response time can exceed multiple seconds.
+- Code Completion, which suggests completions to the current line you are typing. These suggestions are usually low latency.
+- Code Generation, which generates code based on a natural language code comment block.
+ - Algorithms or large code blocks may take more than 10 seconds to generate.
+ - Streaming of code generation responses is supported in VS Code, leading to faster average response times. Other supported IDEs offer slower response times and will return the generated code in a single block.
## Start using Code Suggestions
@@ -30,10 +32,10 @@ GitLab Duo Code Suggestions are available:
- In the GitLab Web IDE.
<div class="video-fallback">
- <a href="https://youtu.be/wAYiy05fjF0">View how to setup and use GitLab Duo Code Suggestions</a>.
+ <a href="https://youtu.be/xQUlrbIWo8o">View how to setup and use GitLab Duo Code Suggestions</a>.
</div>
<figure class="video-container">
- <iframe src="https://www.youtube-nocookie.com/embed/wAYiy05fjF0" frameborder="0" allowfullscreen> </iframe>
+ <iframe src="https://www.youtube-nocookie.com/embed/xQUlrbIWo8o" frameborder="0" allowfullscreen> </iframe>
</figure>
During Beta, usage of Code Suggestions is governed by the [GitLab Testing Agreement](https://about.gitlab.com/handbook/legal/testing-agreement/).
diff --git a/doc/user/project/wiki/index.md b/doc/user/project/wiki/index.md
index f4946230360..07c5ce73470 100644
--- a/doc/user/project/wiki/index.md
+++ b/doc/user/project/wiki/index.md
@@ -94,8 +94,12 @@ Users with at least the Developer role can create new wiki pages:
Wikis are based on Git repositories, so you can clone them locally and edit
them like you would do with every other Git repository. To clone a wiki repository
-locally, select **Clone repository** from the right-hand sidebar of any wiki page,
-and follow the on-screen instructions.
+locally:
+
+1. On the left sidebar, select **Search or go to** and find your project or group.
+1. Select **Plan > Wiki**.
+1. On the right sidebar, select **Clone repository**.
+1. Follow the on-screen instructions.
Files you add to your wiki locally must use one of the following
supported extensions, depending on the markup language you wish to use.
@@ -155,7 +159,9 @@ For an example, read [Table of contents](../../markdown.md#table-of-contents).
## Delete a wiki page
-You need at least the Developer role to delete a wiki page:
+Prerequisites:
+
+- You must have at least the Developer role.
1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Plan > Wiki**.
@@ -166,7 +172,9 @@ You need at least the Developer role to delete a wiki page:
## Move a wiki page
-You need at least the Developer role to move a wiki page:
+Prerequisites:
+
+- You must have at least the Developer role.
1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Plan > Wiki**.
@@ -245,8 +253,11 @@ Commits to wikis are not counted in [repository analytics](../../analytics/repos
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23109) in GitLab 13.8, the sidebar can be customized by selecting the **Edit sidebar** button.
-You need at least the Developer role to customize the wiki
-navigation sidebar. This process creates a wiki page named `_sidebar` which fully
+Prerequisites:
+
+- You must have at least the Developer role.
+
+This process creates a wiki page named `_sidebar` which fully
replaces the default sidebar navigation:
1. On the left sidebar, select **Search or go to** and find your project or group.
@@ -312,7 +323,7 @@ To disable a project's internal wiki:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Visibility, project features, permissions**.
-1. Scroll down to find **Wiki** and toggle it off (in gray).
+1. Scroll down to find and turn off the **Wiki** toggle (in gray).
1. Select **Save changes**.
The internal wiki is now disabled, and users and project members:
diff --git a/lib/api/helpers/integrations_helpers.rb b/lib/api/helpers/integrations_helpers.rb
index dd3009ff1d7..bc4c07442eb 100644
--- a/lib/api/helpers/integrations_helpers.rb
+++ b/lib/api/helpers/integrations_helpers.rb
@@ -879,20 +879,7 @@ module API
desc: 'The product ID of ZenTao project'
}
],
- 'squash-tm' => [
- {
- required: true,
- name: :url,
- type: String,
- desc: 'The Squash TM webhook URL'
- },
- {
- required: false,
- name: :token,
- type: String,
- desc: 'The secret token'
- }
- ]
+ 'squash-tm' => ::Integrations::SquashTm.api_fields
}
end
diff --git a/lib/gitlab/application_setting_fetcher.rb b/lib/gitlab/application_setting_fetcher.rb
new file mode 100644
index 00000000000..ec33a36f028
--- /dev/null
+++ b/lib/gitlab/application_setting_fetcher.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module ApplicationSettingFetcher
+ class << self
+ def clear_in_memory_application_settings!
+ @in_memory_application_settings = nil
+ end
+
+ def current_application_settings
+ cached_application_settings
+ end
+
+ private
+
+ def cached_application_settings
+ return in_memory_application_settings if ENV['IN_MEMORY_APPLICATION_SETTINGS'] == 'true'
+
+ begin
+ ::ApplicationSetting.cached
+ rescue StandardError
+ # In case Redis isn't running
+ # or the Redis UNIX socket file is not available
+ # or the DB is not running (we use migrations in the cache key)
+ end
+ end
+
+ def in_memory_application_settings
+ @in_memory_application_settings ||= ::ApplicationSetting.build_from_defaults
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb
index 5c4899da11f..9b8d9880434 100644
--- a/lib/gitlab/current_settings.rb
+++ b/lib/gitlab/current_settings.rb
@@ -39,19 +39,7 @@ module Gitlab
private
def ensure_application_settings!
- cached_application_settings || uncached_application_settings
- end
-
- def cached_application_settings
- return in_memory_application_settings if ENV['IN_MEMORY_APPLICATION_SETTINGS'] == 'true'
-
- begin
- ::ApplicationSetting.cached
- rescue StandardError
- # In case Redis isn't running
- # or the Redis UNIX socket file is not available
- # or the DB is not running (we use migrations in the cache key)
- end
+ Gitlab::ApplicationSettingFetcher.current_application_settings || uncached_application_settings
end
def uncached_application_settings
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 172d1f3d9aa..c0b0c156308 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -43091,6 +43091,9 @@ msgstr ""
msgid "Secret token"
msgstr ""
+msgid "Secret token."
+msgstr ""
+
msgid "SecretDetection|This comment appears to have a token in it. Are you sure you want to add it?"
msgstr ""
@@ -51611,6 +51614,9 @@ msgstr ""
msgid "URL of the Grafana instance to link to from the Metrics Dashboard menu item."
msgstr ""
+msgid "URL of the Squash TM webhook."
+msgstr ""
+
msgid "URL of the external Spam Check endpoint"
msgstr ""
diff --git a/spec/finders/projects_finder_spec.rb b/spec/finders/projects_finder_spec.rb
index e570b49e1da..f991ecd369c 100644
--- a/spec/finders/projects_finder_spec.rb
+++ b/spec/finders/projects_finder_spec.rb
@@ -482,11 +482,11 @@ RSpec.describe ProjectsFinder, feature_category: :groups_and_projects do
it { is_expected.to match_array([internal_project]) }
end
- describe 'filter by organization_id' do
+ describe 'filter by organization' do
let_it_be(:organization) { create(:organization) }
let_it_be(:organization_project) { create(:project, organization: organization) }
- let(:params) { { organization_id: organization.id } }
+ let(:params) { { organization: organization } }
before do
organization_project.add_maintainer(current_user)
diff --git a/spec/graphql/types/organizations/organization_type_spec.rb b/spec/graphql/types/organizations/organization_type_spec.rb
index 6bc4bac6ba2..33d0376e418 100644
--- a/spec/graphql/types/organizations/organization_type_spec.rb
+++ b/spec/graphql/types/organizations/organization_type_spec.rb
@@ -3,7 +3,9 @@
require 'spec_helper'
RSpec.describe GitlabSchema.types['Organization'], feature_category: :cell do
- let(:expected_fields) { %w[avatar_url description description_html groups id name organization_users path web_url] }
+ let(:expected_fields) do
+ %w[avatar_url description description_html groups id name organization_users path projects web_url]
+ end
specify { expect(described_class.graphql_name).to eq('Organization') }
specify { expect(described_class).to require_graphql_authorizations(:read_organization) }
diff --git a/spec/lib/gitlab/application_setting_fetcher_spec.rb b/spec/lib/gitlab/application_setting_fetcher_spec.rb
new file mode 100644
index 00000000000..0cfb4eea2a3
--- /dev/null
+++ b/spec/lib/gitlab/application_setting_fetcher_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::ApplicationSettingFetcher, feature_category: :cell do
+ before do
+ stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
+
+ described_class.clear_in_memory_application_settings!
+ end
+
+ describe '.clear_in_memory_application_settings!' do
+ subject(:clear_in_memory_application_settings!) { described_class.clear_in_memory_application_settings! }
+
+ before do
+ stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'true')
+
+ described_class.current_application_settings
+ end
+
+ it 'will re-initialize settings' do
+ expect(ApplicationSetting).to receive(:build_from_defaults).and_call_original
+
+ clear_in_memory_application_settings!
+ described_class.current_application_settings
+ end
+ end
+
+ describe '.current_application_settings' do
+ subject(:current_application_settings) { described_class.current_application_settings }
+
+ context 'when ENV["IN_MEMORY_APPLICATION_SETTINGS"] is true' do
+ before do
+ stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'true')
+ end
+
+ it 'returns an in-memory ApplicationSetting object' do
+ expect(ApplicationSetting).not_to receive(:current)
+ expect(ApplicationSetting).to receive(:build_from_defaults).and_call_original
+
+ expect(current_application_settings).to be_a(ApplicationSetting)
+ expect(current_application_settings).not_to be_persisted
+ end
+ end
+
+ context 'when ENV["IN_MEMORY_APPLICATION_SETTINGS"] is false' do
+ context 'and an error is raised' do
+ before do
+ allow(ApplicationSetting).to receive(:cached).and_raise(StandardError)
+ end
+
+ it 'returns nil' do
+ expect(current_application_settings).to be_nil
+ end
+ end
+
+ context 'and settings in cache' do
+ it 'fetches the settings from cache' do
+ expect(::ApplicationSetting).to receive(:cached).and_call_original
+
+ expect(ActiveRecord::QueryRecorder.new { described_class.current_application_settings }.count).to eq(0)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/current_settings_spec.rb b/spec/lib/gitlab/current_settings_spec.rb
index df1b12e479f..9f666669c91 100644
--- a/spec/lib/gitlab/current_settings_spec.rb
+++ b/spec/lib/gitlab/current_settings_spec.rb
@@ -97,32 +97,23 @@ RSpec.describe Gitlab::CurrentSettings, feature_category: :shared do
expect(described_class.metrics_sample_interval).to be(15)
end
- context 'when ENV["IN_MEMORY_APPLICATION_SETTINGS"] is true' do
- before do
- stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'true')
- end
-
- it 'returns an in-memory ApplicationSetting object' do
- expect(ApplicationSetting).not_to receive(:current)
+ it 'retrieves settings using ApplicationSettingFetcher' do
+ expect(Gitlab::ApplicationSettingFetcher).to receive(:current_application_settings).and_call_original
- expect(described_class.current_application_settings).to be_a(ApplicationSetting)
- expect(described_class.current_application_settings).not_to be_persisted
- end
+ described_class.home_page_url
end
context 'in a Rake task with DB unavailable' do
before do
allow(Gitlab::Runtime).to receive(:rake?).and_return(true)
+ allow(Gitlab::ApplicationSettingFetcher).to receive(:current_application_settings).and_return(nil)
+
# For some reason, `allow(described_class).to receive(:connect_to_db?).and_return(false)` causes issues
# during the initialization phase of the test suite, so instead let's mock the internals of it
allow(ApplicationSetting.connection).to receive(:active?).and_return(false)
end
context 'and no settings in cache' do
- before do
- expect(ApplicationSetting).not_to receive(:current)
- end
-
it 'returns a FakeApplicationSettings object' do
expect(described_class.current_application_settings).to be_a(Gitlab::FakeApplicationSettings)
end
diff --git a/spec/requests/api/graphql/mutations/branch_rules/create_spec.rb b/spec/requests/api/graphql/mutations/branch_rules/create_spec.rb
new file mode 100644
index 00000000000..85ba3d58ee5
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/branch_rules/create_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'BranchRuleCreate', feature_category: :source_code_management do
+ include GraphqlHelpers
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:current_user, reload: true) { create(:user) }
+
+ let(:params) do
+ {
+ project_path: project.full_path,
+ name: branch_name
+ }
+ end
+
+ let(:branch_name) { 'branch_name/*' }
+ let(:mutation) { graphql_mutation(:branch_rule_create, params) }
+ let(:mutation_response) { graphql_mutation_response(:branch_rule_create) }
+ let(:mutation_errors) { mutation_response['errors'] }
+
+ subject(:post_mutation) { post_graphql_mutation(mutation, current_user: current_user) }
+
+ context 'when the user does not have permission' do
+ before_all do
+ project.add_developer(current_user)
+ end
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+
+ it 'does not create the board' do
+ expect { post_mutation }.not_to change { ProtectedBranch.count }
+ end
+ end
+
+ context 'when the user can create a branch rules' do
+ before_all do
+ project.add_maintainer(current_user)
+ end
+
+ it 'creates the protected branch' do
+ expect { post_mutation }.to change { ProtectedBranch.count }.by(1)
+ end
+
+ it 'returns the created branch rule' do
+ post_mutation
+
+ expect(mutation_response).to have_key('branchRule')
+ expect(mutation_response['branchRule']['name']).to eq(branch_name)
+ expect(mutation_errors).to be_empty
+ end
+
+ context 'when the branch rule already exist' do
+ let!(:existing_rule) { create :protected_branch, name: branch_name, project: project }
+
+ it 'does not create the protected branch' do
+ expect { post_mutation }.not_to change { ProtectedBranch.count }
+ end
+
+ it 'return an error message' do
+ post_mutation
+
+ expect(mutation_errors).to include 'Name has already been taken'
+ expect(mutation_response['branchRule']).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/organizations/organization_query_spec.rb b/spec/requests/api/graphql/organizations/organization_query_spec.rb
index c485e3b170d..73bcfe81d76 100644
--- a/spec/requests/api/graphql/organizations/organization_query_spec.rb
+++ b/spec/requests/api/graphql/organizations/organization_query_spec.rb
@@ -7,7 +7,6 @@ RSpec.describe 'getting organization information', feature_category: :cell do
let(:query) { graphql_query_for(:organization, { id: organization.to_global_id }, organization_fields) }
let(:current_user) { user }
- let(:groups) { graphql_data_at(:organization, :groups, :nodes) }
let(:organization_fields) do
<<~FIELDS
id
@@ -23,24 +22,9 @@ RSpec.describe 'getting organization information', feature_category: :cell do
let_it_be(:organization_user) { create(:organization_user) }
let_it_be(:organization) { organization_user.organization }
let_it_be(:user) { organization_user.user }
- let_it_be(:parent_group) { create(:group, name: 'parent-group', organization: organization) }
- let_it_be(:public_group) { create(:group, name: 'public-group', parent: parent_group, organization: organization) }
- let_it_be(:other_group) { create(:group, name: 'other-group', organization: organization) }
- let_it_be(:outside_organization_group) { create(:group) }
-
- let_it_be(:private_group) do
- create(:group, :private, name: 'private-group', organization: organization)
- end
-
- let_it_be(:no_access_group_in_org) do
- create(:group, :private, name: 'no-access', organization: organization)
- end
-
- before_all do
- private_group.add_developer(user)
- public_group.add_developer(user)
- other_group.add_developer(user)
- outside_organization_group.add_developer(user)
+ let_it_be(:project) { create(:project, organization: organization) { |p| p.add_developer(user) } }
+ let_it_be(:other_group) do
+ create(:group, name: 'other-group', organization: organization) { |g| g.add_developer(user) }
end
subject(:request_organization) { post_graphql(query, current_user: current_user) }
@@ -62,25 +46,6 @@ RSpec.describe 'getting organization information', feature_category: :cell do
end
end
- context 'when resolve_organization_groups feature flag is disabled' do
- before do
- stub_feature_flags(resolve_organization_groups: false)
- end
-
- it 'returns no groups' do
- request_organization
-
- expect(graphql_data_at(:organization)).not_to be_nil
- expect(graphql_data_at(:organization, :groups, :nodes)).to be_empty
- end
- end
-
- it 'does not return ancestors of authorized groups' do
- request_organization
-
- expect(groups.pluck('id')).not_to include(parent_group.to_global_id.to_s)
- end
-
context 'when requesting organization user' do
let(:organization_fields) do
<<~FIELDS
@@ -116,6 +81,8 @@ RSpec.describe 'getting organization information', feature_category: :cell do
organization_user_2 = create(:organization_user, organization: organization)
other_group.add_developer(organization_user_2.user)
+ organization_user_from_project = create(:organization_user, organization: organization)
+ project.add_developer(organization_user_from_project.user)
expect { run_query }.not_to exceed_query_limit(base_query_count)
end
@@ -127,62 +94,144 @@ RSpec.describe 'getting organization information', feature_category: :cell do
end
end
- context 'with `search` argument' do
- let(:search) { 'oth' }
- let(:organization_fields) do
- <<~FIELDS
- id
- path
- groups(search: "#{search}") {
- nodes {
- id
- name
- }
- }
- FIELDS
+ context 'when requesting groups' do
+ let(:groups) { graphql_data_at(:organization, :groups, :nodes) }
+ let_it_be(:parent_group) { create(:group, name: 'parent-group', organization: organization) }
+ let_it_be(:public_group) do
+ create(:group, name: 'public-group', parent: parent_group, organization: organization)
end
- it 'filters groups by name' do
- request_organization
+ let_it_be(:private_group) do
+ create(:group, :private, name: 'private-group', organization: organization)
+ end
- expect(groups).to contain_exactly(a_graphql_entity_for(other_group))
+ before_all do
+ create(:group, :private, name: 'no-access', organization: organization)
+ private_group.add_developer(user)
+ public_group.add_developer(user)
+ create(:group) { |g| g.add_developer(user) } # outside organization
end
- end
- context 'with `sort` argument' do
- using RSpec::Parameterized::TableSyntax
+ context 'when resolve_organization_groups feature flag is disabled' do
+ before do
+ stub_feature_flags(resolve_organization_groups: false)
+ end
+
+ it 'returns no groups' do
+ request_organization
+
+ expect(graphql_data_at(:organization)).not_to be_nil
+ expect(graphql_data_at(:organization, :groups, :nodes)).to be_empty
+ end
+ end
- let(:authorized_groups) { [public_group, private_group, other_group] }
+ it 'does not return ancestors of authorized groups' do
+ request_organization
- where(:field, :direction, :sorted_groups) do
- 'id' | 'asc' | lazy { authorized_groups.sort_by(&:id) }
- 'id' | 'desc' | lazy { authorized_groups.sort_by(&:id).reverse }
- 'name' | 'asc' | lazy { authorized_groups.sort_by(&:name) }
- 'name' | 'desc' | lazy { authorized_groups.sort_by(&:name).reverse }
- 'path' | 'asc' | lazy { authorized_groups.sort_by(&:path) }
- 'path' | 'desc' | lazy { authorized_groups.sort_by(&:path).reverse }
+ expect(groups.pluck('id')).not_to include(parent_group.to_global_id.to_s)
end
- with_them do
- let(:sort) { "#{field}_#{direction}".upcase }
+ context 'with `search` argument' do
+ let(:search) { 'oth' }
let(:organization_fields) do
<<~FIELDS
id
path
- groups(sort: #{sort}) {
+ groups(search: "#{search}") {
nodes {
id
+ name
}
}
FIELDS
end
- it 'sorts the groups' do
+ it 'filters groups by name' do
request_organization
- expect(groups.pluck('id')).to eq(sorted_groups.map(&:to_global_id).map(&:to_s))
+ expect(groups).to contain_exactly(a_graphql_entity_for(other_group))
end
end
+
+ context 'with `sort` argument' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:authorized_groups) { [public_group, private_group, other_group] }
+
+ where(:field, :direction, :sorted_groups) do
+ 'id' | 'asc' | lazy { authorized_groups.sort_by(&:id) }
+ 'id' | 'desc' | lazy { authorized_groups.sort_by(&:id).reverse }
+ 'name' | 'asc' | lazy { authorized_groups.sort_by(&:name) }
+ 'name' | 'desc' | lazy { authorized_groups.sort_by(&:name).reverse }
+ 'path' | 'asc' | lazy { authorized_groups.sort_by(&:path) }
+ 'path' | 'desc' | lazy { authorized_groups.sort_by(&:path).reverse }
+ end
+
+ with_them do
+ let(:sort) { "#{field}_#{direction}".upcase }
+ let(:organization_fields) do
+ <<~FIELDS
+ id
+ path
+ groups(sort: #{sort}) {
+ nodes {
+ id
+ }
+ }
+ FIELDS
+ end
+
+ it 'sorts the groups' do
+ request_organization
+
+ expect(groups.pluck('id')).to eq(sorted_groups.map(&:to_global_id).map(&:to_s))
+ end
+ end
+ end
+ end
+
+ context 'when requesting projects' do
+ let(:projects) { graphql_data_at(:organization, :projects, :nodes) }
+ let(:organization_fields) do
+ <<~FIELDS
+ projects {
+ nodes {
+ id
+ }
+ }
+ FIELDS
+ end
+
+ before_all do
+ create(:project) { |p| p.add_developer(user) } # some other project that shouldn't show up in our results
+ end
+
+ before do
+ request_organization
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns projects' do
+ expect(projects).to contain_exactly(a_graphql_entity_for(project))
+ end
+
+ it_behaves_like 'sorted paginated query' do
+ include_context 'no sort argument'
+
+ let_it_be(:another_project) { create(:project, organization: organization) { |p| p.add_developer(user) } }
+ let_it_be(:another_project2) { create(:project, organization: organization) { |p| p.add_developer(user) } }
+ let(:first_param) { 2 }
+ let(:data_path) { [:organization, :projects] }
+ let(:all_records) { [another_project2, another_project, project].map { |p| global_id_of(p).to_s } }
+ end
+
+ def pagination_query(params)
+ graphql_query_for(
+ :organization, { id: organization.to_global_id },
+ query_nodes(:projects, :id, include_pagination_info: true, args: params)
+ )
+ end
end
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 7317b512ae4..816dec08b53 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -424,6 +424,7 @@ RSpec.configure do |config|
config.after do
Fog.unmock! if Fog.mock?
Gitlab::CurrentSettings.clear_in_memory_application_settings!
+ Gitlab::ApplicationSettingFetcher.clear_in_memory_application_settings!
# Reset all feature flag stubs to default for testing
stub_all_feature_flags
diff --git a/spec/support/migration.rb b/spec/support/migration.rb
index fc8a4bb12fb..d9db7ae52fe 100644
--- a/spec/support/migration.rb
+++ b/spec/support/migration.rb
@@ -18,6 +18,7 @@ RSpec.configure do |config|
config.after(:context, :migration) do
Gitlab::CurrentSettings.clear_in_memory_application_settings!
+ Gitlab::ApplicationSettingFetcher.clear_in_memory_application_settings!
end
config.append_after(:context, :migration) do