Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-03-02 00:13:45 +00:00
parent 70fe7ce74b
commit 90c386a7b0
52 changed files with 645 additions and 361 deletions

View File

@ -57,7 +57,7 @@ If you include multiple screenshots it can be helpful to hide all but the first
/label ~Quality ~QA ~test
<!-- Test failure type label, please use just one.-->
/label ~"failure::broken-test" ~"failure::flaky-test" ~"failure::stale-test" ~"failure::test-environment" ~"failure::investigating"
/label ~"failure::broken-test" ~"failure::flaky-test" ~"failure::stale-test" ~"failure::test-environment" ~"failure::investigating" ~"failure::new"
<!--
Choose the stage that appears in the test path, e.g. ~"devops::create" for

View File

@ -68,7 +68,7 @@ export default {
:href="newReleasePath"
:aria-describedby="shouldRenderEmptyState && 'releases-description'"
category="primary"
variant="success"
variant="confirm"
data-testid="new-release-button"
>
{{ __('New release') }}

View File

@ -9,6 +9,7 @@ module Types
present_using ::AlertManagement::AlertPresenter
implements(Types::Notes::NoteableInterface)
implements(Types::TodoableInterface)
authorize :read_alert_management_alert
@ -127,6 +128,12 @@ module Types
null: true,
description: 'Alert condition for Prometheus.'
field :web_url,
GraphQL::Types::String,
method: :details_url,
null: false,
description: 'URL of the alert.'
def notes
object.ordered_notes
end

View File

@ -8,6 +8,8 @@ module Types
present_using CommitPresenter
implements(Types::TodoableInterface)
field :id, type: GraphQL::Types::ID, null: false,
description: 'ID (global ID) of the commit.'

View File

@ -13,6 +13,12 @@ module Types
implements(Types::Notes::NoteableInterface)
implements(Types::DesignManagement::DesignFields)
implements(Types::CurrentUserTodos)
implements(Types::TodoableInterface)
field :web_url,
GraphQL::Types::String,
null: false,
description: 'URL of the design.'
field :versions,
Types::DesignManagement::VersionType.connection_type,
@ -40,6 +46,10 @@ module Types
def request_cache_base_key
self.class.name
end
def web_url
Gitlab::UrlBuilder.build(object)
end
end
end
end

View File

@ -8,6 +8,7 @@ module Types
implements(Types::Notes::NoteableInterface)
implements(Types::CurrentUserTodos)
implements(Types::TodoableInterface)
authorize :read_issue

View File

@ -8,6 +8,7 @@ module Types
implements(Types::Notes::NoteableInterface)
implements(Types::CurrentUserTodos)
implements(Types::TodoableInterface)
authorize :read_merge_request

View File

@ -31,6 +31,11 @@ module Types
description: 'Action of the to-do item.',
null: false
field :target, Types::TodoableInterface,
description: 'Target of the to-do item.',
calls_gitaly: true,
null: false
field :target_type, Types::TodoTargetEnum,
description: 'Target type of the to-do item.',
null: false
@ -59,5 +64,28 @@ module Types
def author
Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.author_id).find
end
def target
if object.for_commit?
Gitlab::Graphql::Loaders::BatchCommitLoader.new(
container_class: Project,
container_id: object.project_id,
oid: object.commit_id
).find
else
Gitlab::Graphql::Loaders::BatchModelLoader.new(target_type_class, object.target_id).find
end
end
private
def target_type_class
klass = object.target_type.safe_constantize
raise "Invalid target type \"#{object.target_type}\"" unless klass < Todoable
klass
end
end
end
Types::TodoType.prepend_mod

View File

@ -0,0 +1,30 @@
# frozen_string_literal: true
module Types
module TodoableInterface
include Types::BaseInterface
graphql_name 'Todoable'
field :web_url, GraphQL::Types::String, null: true, description: 'URL of this object.'
def self.resolve_type(object, context)
case object
when Issue
Types::IssueType
when MergeRequest
Types::MergeRequestType
when ::DesignManagement::Design
Types::DesignManagement::DesignType
when ::AlertManagement::Alert
Types::AlertManagement::AlertType
when Commit
Types::CommitType
else
raise "Unknown GraphQL type for #{object}"
end
end
end
end
Types::TodoableInterface.prepend_mod

View File

@ -65,22 +65,19 @@ module Spam
# ask the SpamVerdictService what to do with the target.
spam_verdict_service.execute.tap do |result|
case result
when CONDITIONAL_ALLOW
# at the moment, this means "ask for reCAPTCHA"
create_spam_log
break if target.allow_possible_spam?
target.needs_recaptcha!
when DISALLOW
# TODO: remove `unless target.allow_possible_spam?` once this flag has been passed to `SpamVerdictService`
# https://gitlab.com/gitlab-org/gitlab/-/issues/214739
target.spam! unless target.allow_possible_spam?
create_spam_log
when BLOCK_USER
# TODO: improve BLOCK_USER handling, non-existent until now
# https://gitlab.com/gitlab-org/gitlab/-/issues/329666
target.spam! unless target.allow_possible_spam?
target.spam!
create_spam_log
when DISALLOW
target.spam!
create_spam_log
when CONDITIONAL_ALLOW
# This means "require a CAPTCHA to be solved"
target.needs_recaptcha!
create_spam_log
when OVERRIDE_VIA_ALLOW_POSSIBLE_SPAM
create_spam_log
when ALLOW
target.clear_spam_flags!

View File

@ -2,11 +2,12 @@
module Spam
module SpamConstants
CONDITIONAL_ALLOW = "conditional_allow"
DISALLOW = "disallow"
ALLOW = "allow"
BLOCK_USER = "block"
NOOP = "noop"
BLOCK_USER = 'block'
DISALLOW = 'disallow'
CONDITIONAL_ALLOW = 'conditional_allow'
OVERRIDE_VIA_ALLOW_POSSIBLE_SPAM = 'override_via_allow_possible_spam'
ALLOW = 'allow'
NOOP = 'noop'
SUPPORTED_VERDICTS = {
BLOCK_USER => {
@ -18,11 +19,14 @@ module Spam
CONDITIONAL_ALLOW => {
priority: 3
},
ALLOW => {
OVERRIDE_VIA_ALLOW_POSSIBLE_SPAM => {
priority: 4
},
NOOP => {
ALLOW => {
priority: 5
},
NOOP => {
priority: 6
}
}.freeze
end

View File

@ -39,21 +39,24 @@ module Spam
return ALLOW unless valid_results.any?
# Favour the most restrictive result.
final_verdict = valid_results.min_by { |v| SUPPORTED_VERDICTS[v][:priority] }
verdict = valid_results.min_by { |v| SUPPORTED_VERDICTS[v][:priority] }
# The target can override the verdict via the `allow_possible_spam` feature flag
verdict = OVERRIDE_VIA_ALLOW_POSSIBLE_SPAM if override_via_allow_possible_spam?(verdict: verdict)
logger.info(class: self.class.name,
akismet_verdict: akismet_verdict,
spam_check_verdict: original_spamcheck_result,
extra_attributes: spamcheck_attribs,
spam_check_rtt: external_spam_check_round_trip_time.real,
final_verdict: final_verdict,
final_verdict: verdict,
username: user.username,
user_id: user.id,
target_type: target.class.to_s,
project_id: target.project_id
)
final_verdict
verdict
end
private
@ -87,6 +90,14 @@ module Spam
end
end
def override_via_allow_possible_spam?(verdict:)
# If the verdict is already going to allow (because current verdict's priority value is greater
# than the override verdict's priority value), then we don't need to override it.
return false if SUPPORTED_VERDICTS[verdict][:priority] > SUPPORTED_VERDICTS[OVERRIDE_VIA_ALLOW_POSSIBLE_SPAM][:priority]
target.allow_possible_spam?
end
def spamcheck_client
@spamcheck_client ||= Gitlab::Spamcheck::Client.new
end

View File

@ -16,7 +16,7 @@
= image_tag @appearance.header_logo_path, class: 'appearance-light-logo-preview'
- if @appearance.persisted?
%br
= link_to _('Remove header logo'), header_logos_admin_application_settings_appearances_path, data: { confirm: _("Header logo will be removed. Are you sure?") }, method: :delete, class: "btn gl-button btn-danger btn-danger-secondary btn-sm"
= link_to _('Remove header logo'), header_logos_admin_application_settings_appearances_path, data: { confirm: _("Header logo will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove header logo') }, method: :delete, class: "btn gl-button btn-danger btn-danger-secondary btn-sm"
%hr
= f.hidden_field :header_logo_cache
= f.file_field :header_logo, class: "", accept: 'image/*'
@ -35,7 +35,7 @@
= image_tag @appearance.favicon_path, class: 'appearance-light-logo-preview'
- if @appearance.persisted?
%br
= link_to _('Remove favicon'), favicon_admin_application_settings_appearances_path, data: { confirm: _("Favicon will be removed. Are you sure?") }, method: :delete, class: "btn gl-button btn-danger btn-danger-secondary btn-sm"
= link_to _('Remove favicon'), favicon_admin_application_settings_appearances_path, data: { confirm: _("Favicon will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove favicon') }, method: :delete, class: "btn gl-button btn-danger btn-danger-secondary btn-sm"
%hr
= f.hidden_field :favicon_cache
= f.file_field :favicon, class: '', accept: 'image/*'
@ -67,7 +67,7 @@
= image_tag @appearance.logo_path, class: 'appearance-logo-preview'
- if @appearance.persisted?
%br
= link_to _('Remove logo'), logo_admin_application_settings_appearances_path, data: { confirm: _("Logo will be removed. Are you sure?") }, method: :delete, class: "btn gl-button btn-danger btn-danger-secondary btn-sm remove-logo"
= link_to _('Remove logo'), logo_admin_application_settings_appearances_path, data: { confirm: _("Logo will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove logo') }, method: :delete, class: "btn gl-button btn-danger btn-danger-secondary btn-sm remove-logo"
%hr
= f.hidden_field :logo_cache
= f.file_field :logo, class: "", accept: 'image/*'

View File

@ -78,9 +78,6 @@ ci_pipelines:
- table: merge_requests
column: merge_request_id
on_delete: async_delete
- table: external_pull_requests
column: external_pull_request_id
on_delete: async_nullify
- table: users
column: user_id
on_delete: async_nullify

View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
class RemovePackageFilesLimitFromApplicationSettings < Gitlab::Database::Migration[1.0]
disable_ddl_transaction!
def up
return unless column_exists?(:application_settings, :max_package_files_for_package_destruction)
remove_column :application_settings, :max_package_files_for_package_destruction, :smallint
end
def down
add_column :application_settings, :max_package_files_for_package_destruction, :smallint, default: 100, null: false
add_check_constraint :application_settings,
'max_package_files_for_package_destruction > 0',
'app_settings_max_package_files_for_package_destruction_positive'
end
end

View File

@ -0,0 +1 @@
481bc7b167ddf46bd11322e4458e48de10483bf34d0e393f7e76a3572c28e09f

View File

@ -11243,7 +11243,6 @@ CREATE TABLE application_settings (
container_registry_import_max_step_duration integer DEFAULT 300 NOT NULL,
container_registry_import_target_plan text DEFAULT 'free'::text NOT NULL,
container_registry_import_created_before timestamp with time zone DEFAULT '2022-01-23 00:00:00+00'::timestamp with time zone NOT NULL,
max_package_files_for_package_destruction smallint DEFAULT 100 NOT NULL,
runner_token_expiration_interval integer,
group_runner_token_expiration_interval integer,
project_runner_token_expiration_interval integer,
@ -11254,7 +11253,6 @@ CREATE TABLE application_settings (
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)),
CONSTRAINT app_settings_max_package_files_for_package_destruction_positive CHECK ((max_package_files_for_package_destruction > 0)),
CONSTRAINT app_settings_p_cleanup_package_file_worker_capacity_positive CHECK ((packages_cleanup_package_file_worker_capacity >= 0)),
CONSTRAINT app_settings_registry_exp_policies_worker_capacity_positive CHECK ((container_registry_expiration_policies_worker_capacity >= 0)),
CONSTRAINT app_settings_yaml_max_depth_positive CHECK ((max_yaml_depth > 0)),

View File

@ -8595,6 +8595,7 @@ Describes an alert from the project's Alert Management.
| <a id="alertmanagementalertstatus"></a>`status` | [`AlertManagementStatus`](#alertmanagementstatus) | Status of the alert. |
| <a id="alertmanagementalerttitle"></a>`title` | [`String`](#string) | Title of the alert. |
| <a id="alertmanagementalertupdatedat"></a>`updatedAt` | [`Time`](#time) | Timestamp the alert was last updated. |
| <a id="alertmanagementalertweburl"></a>`webUrl` | [`String!`](#string) | URL of the alert. |
#### Fields with arguments
@ -9991,6 +9992,7 @@ A single design.
| <a id="designnotes"></a>`notes` | [`NoteConnection!`](#noteconnection) | All notes on this noteable. (see [Connections](#connections)) |
| <a id="designnotescount"></a>`notesCount` | [`Int!`](#int) | Total count of user-created notes for this design. |
| <a id="designproject"></a>`project` | [`Project!`](#project) | Project the design belongs to. |
| <a id="designweburl"></a>`webUrl` | [`String!`](#string) | URL of the design. |
#### Fields with arguments
@ -15901,6 +15903,7 @@ Representing a to-do entry.
| <a id="todoid"></a>`id` | [`ID!`](#id) | ID of the to-do item. |
| <a id="todoproject"></a>`project` | [`Project`](#project) | Project this to-do item is associated with. |
| <a id="todostate"></a>`state` | [`TodoStateEnum!`](#todostateenum) | State of the to-do item. |
| <a id="todotarget"></a>`target` | [`Todoable!`](#todoable) | Target of the to-do item. |
| <a id="todotargettype"></a>`targetType` | [`TodoTargetEnum!`](#todotargetenum) | Target type of the to-do item. |
### `Topic`
@ -19414,6 +19417,25 @@ Returns [`TimeboxReport`](#timeboxreport).
| ---- | ---- | ----------- |
| <a id="timeboxreportinterfacereportfullpath"></a>`fullPath` | [`String`](#string) | Full path of the project or group used as a scope for report. For example, `gitlab-org` or `gitlab-org/gitlab`. |
#### `Todoable`
Implementations:
- [`AlertManagementAlert`](#alertmanagementalert)
- [`BoardEpic`](#boardepic)
- [`Commit`](#commit)
- [`Design`](#design)
- [`Epic`](#epic)
- [`EpicIssue`](#epicissue)
- [`Issue`](#issue)
- [`MergeRequest`](#mergerequest)
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="todoableweburl"></a>`webUrl` | [`String`](#string) | URL of this object. |
#### `User`
Representation of a GitLab user.

View File

@ -55,7 +55,7 @@ You can view and modify existing policies from the [policies](#policies) tab.
## License expressions
GitLab has limited support for [composite licenses](https://spdx.github.io/spdx-spec/appendix-IV-SPDX-license-expressions/).
GitLab has limited support for [composite licenses](https://spdx.github.io/spdx-spec/SPDX-license-expressions/).
License compliance can read multiple licenses, but always considers them combined using the `AND` operator. For example,
if a dependency has two licenses, and one of them is allowed and the other is denied by the project [policy](#policies),
GitLab evaluates the composite license as _denied_, as this is the safer option.
@ -90,7 +90,7 @@ The reported licenses might be incomplete or inaccurate.
| Objective-C, Swift | [Carthage](https://github.com/Carthage/Carthage), [CocoaPods](https://cocoapods.org/) v0.39 and below |
| Elixir | [Mix](https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html) |
| C++/C | [Conan](https://conan.io/) |
| Rust | [Cargo](https://crates.io) |
| Rust | [Cargo](https://crates.io/) |
| PHP | [Composer](https://getcomposer.org/) |
## Enable License Compliance
@ -219,7 +219,7 @@ license_scanning:
MAVEN_CLI_OPTS: --debug
```
`mvn install` runs through all of the [build life cycle](http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html)
`mvn install` runs through all of the [build life cycle](https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html)
stages prior to `install`, including `test`. Running unit tests is not directly
necessary for the license scanning purposes and consumes time, so it's skipped
by having the default value of `MAVEN_CLI_OPTS` as `-DskipTests`. If you want
@ -249,7 +249,7 @@ license_scanning:
Alternatively, you can use a Java key store to verify the TLS connection. For instructions on how to
generate a key store file, see the
[Maven Guide to Remote repository access through authenticated HTTPS](http://maven.apache.org/guides/mini/guide-repository-ssl.html).
[Maven Guide to Remote repository access through authenticated HTTPS](https://maven.apache.org/guides/mini/guide-repository-ssl.html).
### Selecting the version of Java

View File

@ -191,7 +191,7 @@ GitLab.com uses the IP ranges `34.74.90.64/28` and `34.74.226.0/24` for traffic
fleet. This whole range is solely allocated to GitLab. You can expect connections from webhooks or repository mirroring to come
from those IPs and allow them.
GitLab.com is fronted by Cloudflare. For incoming connections to GitLab.com, you might need to allow CIDR blocks of Cloudflare ([IPv4](https://www.cloudflare.com/ips-v4) and [IPv6](https://www.cloudflare.com/ips-v6)).
GitLab.com is fronted by Cloudflare. For incoming connections to GitLab.com, you might need to allow CIDR blocks of Cloudflare ([IPv4](https://www.cloudflare.com/ips-v4/) and [IPv6](https://www.cloudflare.com/ips-v6/)).
For outgoing connections from CI/CD runners, we are not providing static IP
addresses. All GitLab.com shared runners are deployed into Google Cloud Platform (GCP). Any

View File

@ -176,7 +176,7 @@ See the [troubleshooting page](../../../administration/troubleshooting/group_sam
### Okta setup notes
Please follow the Okta documentation on [setting up a SAML application in Okta](https://developer.okta.com/docs/guides/build-sso-integration/saml2/overview/) with the notes below for consideration.
Please follow the Okta documentation on [setting up a SAML application in Okta](https://developer.okta.com/docs/guides/build-sso-integration/saml2/main/) with the notes below for consideration.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For a demo of the Okta SAML setup including SCIM, see [Demo: Okta Group SAML & SCIM setup](https://youtu.be/0ES9HsZq0AQ).

View File

@ -101,7 +101,7 @@ Once synchronized, changing the field mapped to `id` and `externalId` may cause
### Okta configuration steps
Before you start this section, complete the [GitLab configuration](#gitlab-configuration) process.
Make sure that you've also set up a SAML application for [Okta](https://developer.okta.com/docs/guides/build-sso-integration/saml2/overview/),
Make sure that you've also set up a SAML application for [Okta](https://developer.okta.com/docs/guides/build-sso-integration/saml2/main/),
as described in the [Okta setup notes](index.md#okta-setup-notes)
Make sure that the Okta setup matches our documentation exactly, especially the NameID

View File

@ -24,6 +24,7 @@ Value stream analytics is also available for [projects](../../analytics/value_st
> - Date range filter [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13216) in GitLab 12.4
> - Filtering [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13216) in GitLab 13.3
> - Horizontal stage path [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12196) in 13.0 and [feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/323982) in 13.12
You must have at least the Reporter role to view value stream analytics for groups.
@ -45,6 +46,9 @@ To view value stream analytics for your group:
header. The header name differs based on the stage you select.
- To sort by most or least amount of time spent in each stage, select the **Time** header.
A badge next to the workflow items table header shows the number of workflow items that
completed during the selected stage.
The table shows a list of related workflow items for the selected stage. Based on the stage you select, this can be:
- CI/CD jobs
@ -52,9 +56,6 @@ The table shows a list of related workflow items for the selected stage. Based o
- Merge requests
- Pipelines
A badge next to the workflow items table header shows the number of workflow items that
completed the selected stage.
## View metrics for each development stage
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/210315) in GitLab 13.0.
@ -244,7 +245,8 @@ You can change the name of a project environment in your GitLab CI/CD configurat
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12196) in GitLab 12.9.
Use custom value streams to create custom stages that align with your own development processes,
and hide default stages.
and hide default stages. The dashboard depicts stages as a horizontal process
flow.
### Create a value stream
@ -263,12 +265,12 @@ To create a value stream:
1. On the left sidebar, select **Analytics > Value Stream**.
1. In the top right, select the dropdown list and then **Create new Value Stream**.
1. Enter a name for the new Value Stream.
- You can [customize the stages](#creating-a-value-stream-with-stages).
- You can [customize the stages](#create-a-value-stream-with-stages).
1. Select **Create Value Stream**.
![New value stream](img/new_value_stream_v13_12.png "Creating a new value stream")
### Creating a value stream with stages
### Create a value stream with stages
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50229) in GitLab 13.7.
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55572) in GitLab 13.10.
@ -320,7 +322,7 @@ After you create a value stream, you can customize it to suit your purposes. To
1. On the top bar, select **Menu > Groups** and find your group.
1. On the left sidebar, select **Analytics > Value Stream**.
1. In the top right, select the dropdown list and then select the relevant value stream.
1. Next to the value stream dropdown, select **Edit**.
1. Next to the value stream dropdown list, select **Edit**.
The edit form is populated with the value stream details.
1. Optional:
- Rename the value stream.
@ -345,20 +347,27 @@ To delete a custom value stream:
![Delete value stream](img/delete_value_stream_v13_12.png "Deleting a custom value stream")
## Total time chart
## View number of days for a cycle to complete
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21631) in GitLab 12.6.
> - Chart median line [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/235455) in GitLab 13.4.
> - Totals [replaced](https://gitlab.com/gitlab-org/gitlab/-/issues/262070) with averages in GitLab 13.12.
This chart visually depicts the average number of days it takes for cycles to be completed.
The **Total time chart** shows the average number of days it takes for development cycles to complete.
The chart shows data for the last 500 workflow items.
This chart uses the global page filters for displaying data based on the selected
group, projects, and time frame.
When a stage is selected the chart only displays data relevant to the selected stage. On the overview the chart displays a sum of the times for all stages in the value stream.
The chart data is limited to the last 500 items.
1. On the top bar, select **Menu > Groups** and find your group.
1. On the left sidebar, select **Analytics > Value stream**.
1. Above the **Filter results** box, select a stage:
- To view a summary of the cycle time for all stages, select **Overview**.
- To view the cycle time for specific stage, select a stage.
1. Optional. Filter the results:
1. Select the **Filter results** text box.
1. Select a parameter.
1. Select a value or enter text to refine the results.
1. To adjust the date range:
- In the **From** field, select a start date.
- In the **To** field, select an end date.
## Type of work - Tasks by type chart

View File

@ -60,9 +60,9 @@ This video from January 2021 walks you through all the GitLab Terraform integrat
## GitLab-managed Terraform state
[Terraform remote backends](https://www.terraform.io/docs/language/settings/backends/index.html)
[Terraform remote backends](https://www.terraform.io/language/settings/backends)
enable you to store the state file in a remote, shared store. GitLab uses the
[Terraform HTTP backend](https://www.terraform.io/docs/language/settings/backends/http.html)
[Terraform HTTP backend](https://www.terraform.io/language/settings/backends/http)
to securely store the state files in local storage (the default) or
[the remote store of your choice](../../../administration/terraform_state.md).

View File

@ -8,9 +8,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2673) in GitLab 13.0.
[Terraform remote backends](https://www.terraform.io/docs/language/settings/backends/index.html)
[Terraform remote backends](https://www.terraform.io/language/settings/backends)
enable you to store the state file in a remote, shared store. GitLab uses the
[Terraform HTTP backend](https://www.terraform.io/docs/language/settings/backends/http.html)
[Terraform HTTP backend](https://www.terraform.io/language/settings/backends/http)
to securely store the state files in local storage (the default) or
[the remote store of your choice](../../../administration/terraform_state.md).
@ -222,9 +222,9 @@ See [this reference project](https://gitlab.com/gitlab-org/configure/examples/gi
## Using a GitLab-managed Terraform state backend as a remote data source
You can use a GitLab-managed Terraform state as a
[Terraform data source](https://www.terraform.io/docs/language/state/remote-state-data.html).
[Terraform data source](https://www.terraform.io/language/state/remote-state-data).
To use your existing Terraform state backend as a data source, provide the following details
as [Terraform input variables](https://www.terraform.io/docs/language/values/variables.html):
as [Terraform input variables](https://www.terraform.io/language/values/variables):
- **address**: The URL of the remote state backend you want to use as a data source.
For example, `https://gitlab.com/api/v4/projects/<TARGET-PROJECT-ID>/terraform/state/<TARGET-STATE-NAME>`.

View File

@ -30,7 +30,7 @@ and the [main GitLab website](https://about.gitlab.com) use [Kramdown](https://k
You should not view this page in the documentation, but instead [view these styles as they appear on GitLab](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/user/markdown.md).
GitLab Flavored Markdown extends the [CommonMark specification](https://spec.commonmark.org/current/).
It was inspired by [GitHub Flavored Markdown](https://docs.github.com/en/github/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax).
It was inspired by [GitHub Flavored Markdown](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax).
## Where you can use GitLab Flavored Markdown

View File

@ -51,4 +51,4 @@ are some useful links to get you started:
- [ClearCase to Git](https://therub.org/2013/07/19/clearcase-to-git/)
- [Dual syncing ClearCase to Git](https://therub.org/2013/10/22/dual-syncing-clearcase-and-git/)
- [Moving to Git from ClearCase](https://sateeshkumarb.wordpress.com/2011/01/15/moving-to-git-from-clearcase/)
- [ClearCase to Git webinar](https://www.brighttalk.com/webcast/11817/162473/clearcase-to-git)
- [ClearCase to Git webinar](https://www.brighttalk.com/webcast/11817/162473)

View File

@ -71,6 +71,6 @@ Here's a few links to get you started with the migration:
- [Migrate using the `cvs-fast-export` tool](https://gitlab.com/esr/cvs-fast-export)
- [Stack Overflow post on importing the CVS repository](https://stackoverflow.com/a/11490134/974710)
- [Convert a CVS repository to Git](https://www.techrepublic.com/blog/linux-and-open-source/convert-cvs-repositories-to-git/)
- [Convert a CVS repository to Git](http://www.techrepublic.com/article/convert-cvs-repositories-to-git/)
- [Man page of the `git-cvsimport` tool](https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-cvsimport.html)
- [Migrate using `reposurgeon`](http://www.catb.org/~esr/reposurgeon/repository-editing.html#conversion)

View File

@ -165,4 +165,4 @@ different types of notifications. All events are sent to the specified channel.
## Further reading
- [Mattermost slash commands documentation](https://docs.mattermost.com/developer/slash-commands.html)
- [Omnibus GitLab Mattermost](https://docs.gitlab.com/omnibus/gitlab-mattermost/)
- [Omnibus GitLab Mattermost](../../../integration/mattermost/)

View File

@ -37,7 +37,7 @@ for the most popular hosting services:
- [Cloudflare](https://support.cloudflare.com/hc/en-us/articles/201720164-Creating-a-Cloudflare-account-and-adding-a-website)
- [cPanel](https://documentation.cpanel.net/display/84Docs/Edit+DNS+Zone)
- [DigitalOcean](https://docs.digitalocean.com/products/networking/dns/how-to/manage-records/)
- [DreamHost](https://help.dreamhost.com/hc/en-us/articles/215414867-How-do-I-add-custom-DNS-records-)
- [DreamHost](https://help.dreamhost.com/hc/en-us/articles/360035516812)
- [Gandi](https://docs.gandi.net/en/domain_names/faq/dns_records.html)
- [Go Daddy](https://www.godaddy.com/help/add-an-a-record-19238)
- [Hostgator](https://www.hostgator.com/help/article/changing-dns-records)

View File

@ -315,7 +315,7 @@ To enable this setting:
1. Tick the checkbox **Force HTTPS (requires valid certificates)**.
If you use Cloudflare CDN in front of GitLab Pages, make sure to set the SSL connection setting to
`full` instead of `flexible`. For more details, see the [Cloudflare CDN directions](https://support.cloudflare.com/hc/en-us/articles/200170416-End-to-end-HTTPS-with-Cloudflare-Part-3-SSL-options#h_4e0d1a7c-eb71-4204-9e22-9d3ef9ef7fef).
`full` instead of `flexible`. For more details, see the [Cloudflare CDN directions](https://developers.cloudflare.com/ssl/origin-configuration/ssl-modes#h_4e0d1a7c-eb71-4204-9e22-9d3ef9ef7fef).
<!-- ## Troubleshooting

View File

@ -42,7 +42,7 @@ To view a list of releases:
- On the left sidebar, select **Deployments > Releases**, or
- On the project's overview page, if at least one release exists, click the number of releases.
- On the project's overview page, if at least one release exists, select the number of releases.
![Number of Releases](img/releases_count_v13_2.png "Incremental counter of Releases")
@ -52,10 +52,10 @@ To view a list of releases:
### Sort releases
To sort releases by **Released date** or **Created date**, select from the sort order dropdown. To
To sort releases by **Released date** or **Created date**, select from the sort order dropdown list. To
switch between ascending or descending order, select **Sort order**.
![Sort releases dropdown button](img/releases_sort_v13_6.png)
![Sort releases dropdown list options](img/releases_sort_v13_6.png)
## Create a release
@ -307,9 +307,9 @@ Read more about [Release permissions](#release-permissions).
To edit the details of a release:
1. On the left sidebar, select **Deployments > Releases**.
1. In the top-right corner of the release you want to modify, click **Edit this release** (the pencil icon).
1. In the top-right corner of the release you want to modify, select **Edit this release** (the pencil icon).
1. On the **Edit Release** page, change the release's details.
1. Click **Save changes**.
1. Select **Save changes**.
You can edit the release title, notes, associated milestones, and asset links.
To change the release date use the
@ -330,16 +330,16 @@ the [Releases API](../../../api/releases/index.md#create-a-release).
In the user interface, to associate milestones to a release:
1. On the left sidebar, select **Deployments > Releases**.
1. In the top-right corner of the release you want to modify, click **Edit this release** (the pencil icon).
1. In the top-right corner of the release you want to modify, select **Edit this release** (the pencil icon).
1. From the **Milestones** list, select each milestone you want to associate. You can select multiple milestones.
1. Click **Save changes**.
1. Select **Save changes**.
On the **Deployments > Releases** page, the **Milestone** is listed in the top
section, along with statistics about the issues in the milestones.
![A Release with one associated milestone](img/release_with_milestone_v12_9.png)
Releases are also visible on the **Issues > Milestones** page, and when you click a milestone
Releases are also visible on the **Issues > Milestones** page, and when you select a milestone
on this page.
Here is an example of milestones with no releases, one release, and two releases, respectively.
@ -360,8 +360,8 @@ You can be notified by email when a new release is created for your project.
To subscribe to notifications for releases:
1. On the left sidebar, select **Project information**.
1. Click **Notification setting** (the bell icon).
1. In the list, click **Custom**.
1. Select **Notification setting** (the bell icon).
1. In the list, select **Custom**.
1. Select the **New release** checkbox.
1. Close the dialog box to save.
@ -395,12 +395,12 @@ To set a deploy freeze window in the UI, complete these steps:
1. Sign in to GitLab as a user with the Maintainer role.
1. On the left sidebar, select **Project information**.
1. In the left navigation menu, navigate to **Settings > CI/CD**.
1. In the left navigation menu, go to **Settings > CI/CD**.
1. Scroll to **Deploy freezes**.
1. Click **Expand** to see the deploy freeze table.
1. Click **Add deploy freeze** to open the deploy freeze modal.
1. Select **Expand** to see the deploy freeze table.
1. Select **Add deploy freeze** to open the deploy freeze modal.
1. Enter the start time, end time, and time zone of the desired deploy freeze period.
1. Click **Add deploy freeze** in the modal.
1. Select **Add deploy freeze** in the modal.
1. After the deploy freeze is saved, you can edit it by selecting the edit button (**{pencil}**) and remove it by selecting the delete button (**{remove}**).
![Deploy freeze modal for setting a deploy freeze period](img/deploy_freeze_v14_3.png)
@ -611,7 +611,7 @@ On [GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/releases), you can view t
![Feature count](img/feature_count_v14_6.png "Number of features in a release")
The totals are displayed on [shields](https://shields.io/) and are generated per release by
[a Rake task in the `www-gitlab-com` repo](https://gitlab.com/gitlab-com/www-gitlab-com/-/blob/master/lib/tasks/update_gitlab_project_releases_page.rake).
[a Rake task in the `www-gitlab-com` repository](https://gitlab.com/gitlab-com/www-gitlab-com/-/blob/master/lib/tasks/update_gitlab_project_releases_page.rake).
| Item | Formula |
| ------ | ------ |
@ -634,7 +634,7 @@ This data is saved in a JSON file and called *release evidence*. The feature
includes test artifacts and linked milestones to facilitate
internal processes, like external audits.
To access the release evidence, on the Releases page, click the link to the JSON file that's listed
To access the release evidence, on the Releases page, select the link to the JSON file that's listed
under the **Evidence collection** heading.
You can also [use the API](../../../api/releases/index.md#collect-release-evidence) to
@ -720,7 +720,7 @@ When you create a release, if [job artifacts](../../../ci/yaml/index.md#artifact
Although job artifacts normally expire, artifacts included in release evidence do not expire.
To enable job artifact collection you need to specify both:
To enable job artifact collection you must specify both:
1. [`artifacts:paths`](../../../ci/yaml/index.md#artifactspaths)
1. [`artifacts:reports`](../../../ci/yaml/index.md#artifactsreports)

View File

@ -76,7 +76,7 @@ through the [remote mirrors API](../../../../api/remote_mirrors.md).
To configure a mirror from GitLab to GitHub:
1. Create a [GitHub personal access token](https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token)
1. Create a [GitHub personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)
with `public_repo` selected.
1. Enter a **Git repository URL** with this format:
`https://<your_access_token>@github.com/<github_group>/<github_project>.git`.

View File

@ -24,11 +24,11 @@ The main difference is the way GitLab determines whether or not the developer's
to their account.
GitLab uses its own certificate store and therefore defines the
[trust chain](https://www.ssl.com/faqs/what-is-a-chain-of-trust/).
[trust chain](https://www.ssl.com/faqs/what-is-a-certificate-authority/).
For a commit or tag to be *verified* by GitLab:
- The signing certificate email must match a verified email address in GitLab.
- The GitLab instance must be able to establish a full [trust chain](https://www.ssl.com/faqs/what-is-a-chain-of-trust/)
- The GitLab instance must be able to establish a full trust chain
from the certificate in the signature to a trusted certificate in the GitLab certificate store.
This chain may include intermediate certificates supplied in the signature. You may
need to add certificates, such as Certificate Authority root certificates,

View File

@ -37,10 +37,12 @@ module Gitlab
next unless dependencies.present?
next unless needs_value.present?
missing_needs = dependencies - needs_value[:job].pluck(:name) # rubocop:disable CodeReuse/ActiveRecord (Array#pluck)
if needs_value[:job].nil? && needs_value[:cross_dependency].present?
errors.add(:needs, "corresponding to dependencies must be from the same pipeline")
else
missing_needs = dependencies - needs_value[:job].pluck(:name) # rubocop:disable CodeReuse/ActiveRecord (Array#pluck)
if missing_needs.any?
errors.add(:dependencies, "the #{missing_needs.join(", ")} should be part of needs")
errors.add(:dependencies, "the #{missing_needs.join(", ")} should be part of needs") if missing_needs.any?
end
end
end

View File

@ -0,0 +1,40 @@
# frozen_string_literal: true
module Gitlab
module Graphql
module Loaders
class BatchCommitLoader
def initialize(container_class:, container_id:, oid:)
@container_class = container_class
@container_id = container_id
@oid = oid
end
def find
Gitlab::Graphql::Lazy.with_value(find_containers) do |container|
BatchLoader::GraphQL.for(oid).batch(key: container) do |oids, loader, args|
container = args[:key]
container.repository.commits_by(oids: oids).each do |commit|
loader.call(commit.id, commit) if commit
end
end
end
end
private
def find_containers
BatchLoader::GraphQL.for(container_id.to_i).batch(key: container_class) do |ids, loader, args|
model = args[:key]
results = model.includes(:route).id_in(ids) # rubocop: disable CodeReuse/ActiveRecord
results.each { |record| loader.call(record.id, record) }
end
end
attr_reader :container_class, :container_id, :oid
end
end
end
end

View File

@ -619,11 +619,11 @@ RSpec.describe Projects::IssuesController do
end
end
context 'when the SpamVerdictService disallows' do
context 'when an issue is identified as spam' do
before do
stub_application_setting(recaptcha_enabled: true)
expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service|
expect(verdict_service).to receive(:execute).and_return(CONDITIONAL_ALLOW)
allow_next_instance_of(Spam::AkismetService) do |akismet_service|
allow(akismet_service).to receive(:spam?).and_return(true)
end
end
@ -940,8 +940,8 @@ RSpec.describe Projects::IssuesController do
context 'when an issue is identified as spam' do
context 'when recaptcha is not verified' do
before do
expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service|
expect(verdict_service).to receive(:execute).and_return(CONDITIONAL_ALLOW)
allow_next_instance_of(Spam::AkismetService) do |akismet_service|
allow(akismet_service).to receive(:spam?).and_return(true)
end
end
@ -1274,11 +1274,11 @@ RSpec.describe Projects::IssuesController do
end
end
context 'when SpamVerdictService requires recaptcha' do
context 'when an issue is identified as spam and requires recaptcha' do
context 'when captcha is not verified' do
before do
expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service|
expect(verdict_service).to receive(:execute).and_return(CONDITIONAL_ALLOW)
allow_next_instance_of(Spam::AkismetService) do |akismet_service|
allow(akismet_service).to receive(:spam?).and_return(true)
end
end

View File

@ -0,0 +1,178 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Spam detection on issue creation', :js do
include StubENV
let(:project) { create(:project, :public) }
let(:user) { create(:user) }
include_context 'includes Spam constants'
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
Gitlab::CurrentSettings.update!(
akismet_enabled: true,
akismet_api_key: 'testkey',
spam_check_api_key: 'testkey',
recaptcha_enabled: true,
recaptcha_site_key: 'test site key',
recaptcha_private_key: 'test private key'
)
project.add_maintainer(user)
sign_in(user)
visit new_project_issue_path(project)
fill_in 'issue_title', with: 'issue title'
fill_in 'issue_description', with: 'issue description'
end
shared_examples 'disallows issue creation' do
it 'disallows issue creation' do
click_button 'Create issue'
expect(page).to have_content('discarded')
expect(page).not_to have_css('.recaptcha')
expect(page).not_to have_content('issue title')
end
end
shared_examples 'allows issue creation with CAPTCHA' do
it 'allows issue creation' do
click_button 'Create issue'
# it is impossible to test reCAPTCHA automatically and there is no possibility to fill in recaptcha
# reCAPTCHA verification is skipped in test environment and it always returns true
expect(page).not_to have_content('issue title')
expect(page).to have_css('.recaptcha')
click_button 'Create issue'
expect(page.find('.issue-details h1.title')).to have_content('issue title')
expect(page.find('.issue-details .description')).to have_content('issue description')
end
end
shared_examples 'allows issue creation without CAPTCHA' do
it 'allows issue creation without need to solve CAPTCHA' do
click_button 'Create issue'
expect(page).not_to have_css('.recaptcha')
expect(page.find('.issue-details h1.title')).to have_content('issue title')
expect(page.find('.issue-details .description')).to have_content('issue description')
end
end
shared_examples 'creates a spam_log record' do
it 'creates a spam_log record' do
expect { click_button 'Create issue' }
.to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue')
end
end
shared_examples 'does not create a spam_log record' do
it 'does not creates a spam_log record' do
expect { click_button 'Create issue' }
.not_to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue')
end
end
shared_context 'when spammable is identified as possible spam' do
before do
allow_next_instance_of(Spam::AkismetService) do |akismet_service|
allow(akismet_service).to receive(:spam?).and_return(true)
end
end
end
shared_context 'when spammable is not identified as possible spam' do
before do
allow_next_instance_of(Spam::AkismetService) do |akismet_service|
allow(akismet_service).to receive(:spam?).and_return(false)
end
end
end
shared_context 'when CAPTCHA is enabled' do
before do
stub_application_setting(recaptcha_enabled: true)
end
end
shared_context 'when CAPTCHA is not enabled' do
before do
stub_application_setting(recaptcha_enabled: false)
end
end
shared_context 'when allow_possible_spam feature flag is true' do
before do
stub_feature_flags(allow_possible_spam: true)
end
end
shared_context 'when allow_possible_spam feature flag is false' do
before do
stub_feature_flags(allow_possible_spam: false)
end
end
describe 'spam handling' do
# verdict, spam_flagged, captcha_enabled, allow_possible_spam_flag, creates_spam_log
# TODO: Add example for BLOCK_USER verdict when we add support for testing SpamCheck - see https://gitlab.com/groups/gitlab-org/-/epics/5527#lacking-coverage-for-spamcheck-vs-akismet
# DISALLOW, true, false, false, true
# CONDITIONAL_ALLOW, true, true, false, true
# OVERRIDE_VIA_ALLOW_POSSIBLE_SPAM, true, true, true, true
# OVERRIDE_VIA_ALLOW_POSSIBLE_SPAM, true, false, true, true
# ALLOW, false, true, false, false
# TODO: Add example for NOOP verdict when we add support for testing SpamCheck - see https://gitlab.com/groups/gitlab-org/-/epics/5527#lacking-coverage-for-spamcheck-vs-akismet
context 'DISALLOW: spam_flagged=true, captcha_enabled=true, allow_possible_spam=true' do
include_context 'when spammable is identified as possible spam'
include_context 'when CAPTCHA is enabled'
include_context 'when allow_possible_spam feature flag is true'
it_behaves_like 'allows issue creation without CAPTCHA'
it_behaves_like 'creates a spam_log record'
end
context 'CONDITIONAL_ALLOW: spam_flagged=true, captcha_enabled=true, allow_possible_spam=false' do
include_context 'when spammable is identified as possible spam'
include_context 'when CAPTCHA is enabled'
include_context 'when allow_possible_spam feature flag is false'
it_behaves_like 'allows issue creation with CAPTCHA'
it_behaves_like 'creates a spam_log record'
end
context 'OVERRIDE_VIA_ALLOW_POSSIBLE_SPAM: spam_flagged=true, captcha_enabled=true, allow_possible_spam=true' do
include_context 'when spammable is identified as possible spam'
include_context 'when CAPTCHA is enabled'
include_context 'when allow_possible_spam feature flag is true'
it_behaves_like 'allows issue creation without CAPTCHA'
it_behaves_like 'creates a spam_log record'
end
context 'OVERRIDE_VIA_ALLOW_POSSIBLE_SPAM: spam_flagged=true, captcha_enabled=false, allow_possible_spam=true' do
include_context 'when spammable is identified as possible spam'
include_context 'when CAPTCHA is not enabled'
include_context 'when allow_possible_spam feature flag is true'
it_behaves_like 'allows issue creation without CAPTCHA'
it_behaves_like 'creates a spam_log record'
end
context 'ALLOW: spam_flagged=false, captcha_enabled=true, allow_possible_spam=false' do
include_context 'when spammable is not identified as possible spam'
include_context 'when CAPTCHA is not enabled'
include_context 'when allow_possible_spam feature flag is false'
it_behaves_like 'allows issue creation without CAPTCHA'
it_behaves_like 'does not create a spam_log record'
end
end
end

View File

@ -1,188 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'New issue', :js do
include StubENV
let(:project) { create(:project, :public) }
let(:user) { create(:user)}
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
Gitlab::CurrentSettings.update!(
akismet_enabled: true,
akismet_api_key: 'testkey',
spam_check_api_key: 'testkey',
recaptcha_enabled: true,
recaptcha_site_key: 'test site key',
recaptcha_private_key: 'test private key'
)
project.add_maintainer(user)
sign_in(user)
end
context 'when SpamVerdictService disallows' do
include_context 'includes Spam constants'
before do
allow_next_instance_of(Spam::SpamVerdictService) do |verdict_service|
allow(verdict_service).to receive(:execute).and_return(DISALLOW)
end
visit new_project_issue_path(project)
end
context 'when allow_possible_spam feature flag is false' do
before do
stub_feature_flags(allow_possible_spam: false)
fill_in 'issue_title', with: 'issue title'
fill_in 'issue_description', with: 'issue description'
end
it 'rejects issue creation' do
click_button 'Create issue'
expect(page).to have_content('discarded')
expect(page).not_to have_content('potential spam')
expect(page).not_to have_content('issue title')
end
it 'creates a spam log record' do
expect { click_button 'Create issue' }
.to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue')
end
end
context 'when allow_possible_spam feature flag is true' do
before do
fill_in 'issue_title', with: 'issue title'
fill_in 'issue_description', with: 'issue description'
end
it 'allows issue creation' do
click_button 'Create issue'
expect(page.find('.issue-details h1.title')).to have_content('issue title')
expect(page.find('.issue-details .description')).to have_content('issue description')
end
it 'creates a spam log record' do
expect { click_button 'Create issue' }
.to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue')
end
end
end
context 'when SpamVerdictService requires recaptcha' do
include_context 'includes Spam constants'
before do
allow_next_instance_of(Spam::SpamVerdictService) do |verdict_service|
allow(verdict_service).to receive(:execute).and_return(CONDITIONAL_ALLOW)
end
visit new_project_issue_path(project)
end
context 'when recaptcha is enabled' do
before do
stub_application_setting(recaptcha_enabled: true)
end
context 'when allow_possible_spam feature flag is false' do
before do
stub_feature_flags(allow_possible_spam: false)
end
it 'creates an issue after solving reCaptcha' do
fill_in 'issue_title', with: 'issue title'
fill_in 'issue_description', with: 'issue description'
click_button 'Create issue'
# it is impossible to test reCAPTCHA automatically and there is no possibility to fill in recaptcha
# reCAPTCHA verification is skipped in test environment and it always returns true
expect(page).not_to have_content('issue title')
expect(page).to have_css('.recaptcha')
click_button 'Create issue'
expect(page.find('.issue-details h1.title')).to have_content('issue title')
expect(page.find('.issue-details .description')).to have_content('issue description')
end
end
context 'when allow_possible_spam feature flag is true' do
before do
fill_in 'issue_title', with: 'issue title'
fill_in 'issue_description', with: 'issue description'
end
it 'creates an issue without a need to solve reCAPTCHA' do
click_button 'Create issue'
expect(page).not_to have_css('.recaptcha')
expect(page.find('.issue-details h1.title')).to have_content('issue title')
expect(page.find('.issue-details .description')).to have_content('issue description')
end
it 'creates a spam log record' do
expect { click_button 'Create issue' }
.to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue')
end
end
end
context 'when reCAPTCHA is not enabled' do
before do
stub_application_setting(recaptcha_enabled: false)
end
context 'when allow_possible_spam feature flag is true' do
before do
fill_in 'issue_title', with: 'issue title'
fill_in 'issue_description', with: 'issue description'
end
it 'creates an issue without a need to solve reCaptcha' do
click_button 'Create issue'
expect(page).not_to have_css('.recaptcha')
expect(page.find('.issue-details h1.title')).to have_content('issue title')
expect(page.find('.issue-details .description')).to have_content('issue description')
end
it 'creates a spam log record' do
expect { click_button 'Create issue' }
.to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue')
end
end
end
end
context 'when the SpamVerdictService allows' do
include_context 'includes Spam constants'
before do
allow_next_instance_of(Spam::SpamVerdictService) do |verdict_service|
allow(verdict_service).to receive(:execute).and_return(ALLOW)
end
visit new_project_issue_path(project)
end
it 'creates an issue' do
fill_in 'issue_title', with: 'issue title'
fill_in 'issue_description', with: 'issue description'
click_button 'Create issue'
expect(page.find('.issue-details h1.title')).to have_content('issue title')
expect(page.find('.issue-details .description')).to have_content('issue description')
end
end
end

View File

@ -7,6 +7,8 @@ RSpec.describe GitlabSchema.types['AlertManagementAlert'] do
specify { expect(described_class).to require_graphql_authorizations(:read_alert_management_alert) }
specify { expect(described_class.interfaces).to include(Types::TodoableInterface) }
it 'exposes the expected fields' do
expected_fields = %i[
iid
@ -34,6 +36,7 @@ RSpec.describe GitlabSchema.types['AlertManagementAlert'] do
details_url
prometheus_alert
environment
web_url
]
expect(described_class).to have_graphql_fields(*expected_fields)

View File

@ -7,6 +7,8 @@ RSpec.describe GitlabSchema.types['Commit'] do
specify { expect(described_class).to require_graphql_authorizations(:download_code) }
specify { expect(described_class).to include(Types::TodoableInterface) }
it 'contains attributes related to commit' do
expect(described_class).to have_graphql_fields(
:id, :sha, :short_id, :title, :full_title, :full_title_html, :description, :description_html, :message, :title_html, :authored_date,

View File

@ -5,8 +5,10 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['Design'] do
specify { expect(described_class.interfaces).to include(Types::CurrentUserTodos) }
specify { expect(described_class.interfaces).to include(Types::TodoableInterface) }
it_behaves_like 'a GraphQL type with design fields' do
let(:extra_design_fields) { %i[notes current_user_todos discussions versions] }
let(:extra_design_fields) { %i[notes current_user_todos discussions versions web_url] }
let_it_be(:design) { create(:design, :with_versions) }
let(:object_id) { GitlabSchema.id_from_object(design) }
let_it_be(:object_id_b) { GitlabSchema.id_from_object(create(:design, :with_versions)) }

View File

@ -13,6 +13,8 @@ RSpec.describe GitlabSchema.types['MergeRequest'] do
specify { expect(described_class.interfaces).to include(Types::CurrentUserTodos) }
specify { expect(described_class.interfaces).to include(Types::TodoableInterface) }
it 'has the expected fields' do
expected_fields = %w[
notes discussions user_permissions id iid title title_html description

View File

@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['Todo'] do
it 'has the correct fields' do
expected_fields = [:id, :project, :group, :author, :action, :target_type, :body, :state, :created_at]
expected_fields = [:id, :project, :group, :author, :action, :target, :target_type, :body, :state, :created_at]
expect(described_class).to have_graphql_fields(*expected_fields)
end

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Types::TodoableInterface do
it 'exposes the expected fields' do
expected_fields = %i[
web_url
]
expect(described_class).to have_graphql_fields(*expected_fields)
end
describe ".resolve_type" do
it 'knows the correct type for objects' do
expect(described_class.resolve_type(build(:issue), {})).to eq(Types::IssueType)
expect(described_class.resolve_type(build(:merge_request), {})).to eq(Types::MergeRequestType)
expect(described_class.resolve_type(build(:design), {})).to eq(Types::DesignManagement::DesignType)
expect(described_class.resolve_type(build(:alert_management_alert), {})).to eq(Types::AlertManagement::AlertType)
expect(described_class.resolve_type(build(:commit), {})).to eq(Types::CommitType)
end
it 'raises an error for an unknown type' do
project = build(:project)
expect { described_class.resolve_type(project, {}) }.to raise_error("Unknown GraphQL type for #{project}")
end
end
end

View File

@ -420,7 +420,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do
end
end
context 'when has dependencies' do
context 'when it has dependencies' do
context 'that are not a array of strings' do
let(:config) do
{ script: 'echo', dependencies: 'build-job' }
@ -433,8 +433,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do
end
end
context 'when has needs' do
context 'when have dependencies that are not subset of needs' do
context 'when the job has needs' do
context 'and there are dependencies that are not included in needs' do
let(:config) do
{
stage: 'test',
@ -448,6 +448,24 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do
expect(entry).not_to be_valid
expect(entry.errors).to include 'job dependencies the another-job should be part of needs'
end
context 'and they are only cross pipeline needs' do
let(:config) do
{
script: 'echo',
dependencies: ['rspec'],
needs: [{
job: 'rspec',
pipeline: 'other'
}]
}
end
it 'adds an error for dependency keyword usage' do
expect(entry).not_to be_valid
expect(entry.errors).to include 'job needs corresponding to dependencies must be from the same pipeline'
end
end
end
end

View File

@ -0,0 +1,54 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Graphql::Loaders::BatchCommitLoader do
include RepoHelpers
describe '#find' do
let_it_be(:first_project) { create(:project, :repository) }
let_it_be(:second_project) { create(:project, :repository) }
let_it_be(:first_commit) { first_project.commit(sample_commit.id) }
let_it_be(:second_commit) { first_project.commit(another_sample_commit.id) }
let_it_be(:third_commit) { second_project.commit(sample_big_commit.id) }
it 'finds a commit by id' do
result = described_class.new(
container_class: Project,
container_id: first_project.id,
oid: first_commit.id
).find
expect(result.force).to eq(first_commit)
end
before do
ActiveSupport::Notifications.subscribe('sql.active_record') do |event|
raise "no!" if event.payload[:sql].include?('SELECT "namespaces".')
end
end
it 'only queries once' do
expect do
[
described_class.new(
container_class: Project,
container_id: first_project.id,
oid: first_commit.id
).find,
described_class.new(
container_class: Project,
container_id: first_project.id,
oid: second_commit.id
).find,
described_class.new(
container_class: Project,
container_id: second_project.id,
oid: third_commit.id
).find
].map(&:force)
end.not_to exceed_query_limit(2)
end
end
end

View File

@ -233,10 +233,6 @@ RSpec.describe ExternalPullRequest do
end
end
it_behaves_like 'it has loose foreign keys' do
let(:factory_name) { :external_pull_request }
end
context 'loose foreign key on external_pull_requests.project_id' do
it_behaves_like 'cleanup by a loose foreign key' do
let!(:parent) { create(:project) }

View File

@ -199,8 +199,8 @@ RSpec.describe API::Issues do
expect(spam_service).to receive_messages(check_for_spam?: true)
end
expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service|
expect(verdict_service).to receive(:execute).and_return(DISALLOW)
allow_next_instance_of(Spam::AkismetService) do |akismet_service|
allow(akismet_service).to receive(:spam?).and_return(true)
end
end

View File

@ -170,26 +170,13 @@ RSpec.describe Spam::SpamActionService do
allow(fake_verdict_service).to receive(:execute).and_return(DISALLOW)
end
context 'when allow_possible_spam feature flag is false' do
before do
stub_feature_flags(allow_possible_spam: false)
end
it_behaves_like 'creates a spam log'
it 'marks as spam' do
response = subject
it 'marks as spam' do
response = subject
expect(response.message).to match(expected_service_check_response_message)
expect(issue).to be_spam
end
end
context 'when allow_possible_spam feature flag is true' do
it 'does not mark as spam' do
response = subject
expect(response.message).to match(expected_service_check_response_message)
expect(issue).not_to be_spam
end
expect(response.message).to match(expected_service_check_response_message)
expect(issue).to be_spam
end
end
@ -198,26 +185,13 @@ RSpec.describe Spam::SpamActionService do
allow(fake_verdict_service).to receive(:execute).and_return(BLOCK_USER)
end
context 'when allow_possible_spam feature flag is false' do
before do
stub_feature_flags(allow_possible_spam: false)
end
it_behaves_like 'creates a spam log'
it 'marks as spam' do
response = subject
it 'marks as spam' do
response = subject
expect(response.message).to match(expected_service_check_response_message)
expect(issue).to be_spam
end
end
context 'when allow_possible_spam feature flag is true' do
it 'does not mark as spam' do
response = subject
expect(response.message).to match(expected_service_check_response_message)
expect(issue).not_to be_spam
end
expect(response.message).to match(expected_service_check_response_message)
expect(issue).to be_spam
end
end
@ -226,37 +200,42 @@ RSpec.describe Spam::SpamActionService do
allow(fake_verdict_service).to receive(:execute).and_return(CONDITIONAL_ALLOW)
end
context 'when allow_possible_spam feature flag is false' do
before do
stub_feature_flags(allow_possible_spam: false)
end
it_behaves_like 'creates a spam log'
it_behaves_like 'creates a spam log'
it 'does not mark as spam' do
response = subject
it 'does not mark as spam' do
response = subject
expect(response.message).to match(expected_service_check_response_message)
expect(issue).not_to be_spam
end
it 'marks as needing reCAPTCHA' do
response = subject
expect(response.message).to match(expected_service_check_response_message)
expect(issue).to be_needs_recaptcha
end
expect(response.message).to match(expected_service_check_response_message)
expect(issue).not_to be_spam
end
context 'when allow_possible_spam feature flag is true' do
it_behaves_like 'creates a spam log'
it 'marks as needing reCAPTCHA' do
response = subject
it 'does not mark as needing reCAPTCHA' do
response = subject
expect(response.message).to match(expected_service_check_response_message)
expect(issue).to be_needs_recaptcha
end
end
expect(response.message).to match(expected_service_check_response_message)
expect(issue.needs_recaptcha).to be_falsey
end
context 'when spam verdict service returns OVERRIDE_VIA_ALLOW_POSSIBLE_SPAM' do
before do
allow(fake_verdict_service).to receive(:execute).and_return(OVERRIDE_VIA_ALLOW_POSSIBLE_SPAM)
end
it_behaves_like 'creates a spam log'
it 'does not mark as spam' do
response = subject
expect(response.message).to match(expected_service_check_response_message)
expect(issue).not_to be_spam
end
it 'does not mark as needing CAPTCHA' do
response = subject
expect(response.message).to match(expected_service_check_response_message)
expect(issue).not_to be_needs_recaptcha
end
end

View File

@ -27,6 +27,10 @@ RSpec.describe Spam::SpamVerdictService do
extra_attributes
end
before do
stub_feature_flags(allow_possible_spam: false)
end
describe '#execute' do
subject { service.execute }
@ -114,6 +118,32 @@ RSpec.describe Spam::SpamVerdictService do
end
end
context 'if allow_possible_spam flag is true' do
before do
stub_feature_flags(allow_possible_spam: true)
end
context 'and a service returns a verdict that should be overridden' do
before do
allow(service).to receive(:spamcheck_verdict).and_return([BLOCK_USER, attribs])
end
it 'overrides and renders the override verdict' do
expect(subject).to eq OVERRIDE_VIA_ALLOW_POSSIBLE_SPAM
end
end
context 'and a service returns a verdict that does not need to be overridden' do
before do
allow(service).to receive(:spamcheck_verdict).and_return([ALLOW, attribs])
end
it 'does not override and renders the original verdict' do
expect(subject).to eq ALLOW
end
end
end
context 'records metrics' do
let(:histogram) { instance_double(Prometheus::Client::Histogram) }

View File

@ -2,10 +2,11 @@
RSpec.shared_context 'includes Spam constants' do
before do
stub_const('CONDITIONAL_ALLOW', Spam::SpamConstants::CONDITIONAL_ALLOW)
stub_const('DISALLOW', Spam::SpamConstants::DISALLOW)
stub_const('ALLOW', Spam::SpamConstants::ALLOW)
stub_const('BLOCK_USER', Spam::SpamConstants::BLOCK_USER)
stub_const('DISALLOW', Spam::SpamConstants::DISALLOW)
stub_const('CONDITIONAL_ALLOW', Spam::SpamConstants::CONDITIONAL_ALLOW)
stub_const('OVERRIDE_VIA_ALLOW_POSSIBLE_SPAM', Spam::SpamConstants::OVERRIDE_VIA_ALLOW_POSSIBLE_SPAM)
stub_const('ALLOW', Spam::SpamConstants::ALLOW)
stub_const('NOOP', Spam::SpamConstants::NOOP)
end
end