Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-11-03 18:13:40 +00:00
parent 70a50740a2
commit bbc36645d3
27 changed files with 650 additions and 370 deletions

View File

@ -31,6 +31,14 @@ Personas are described at https://about.gitlab.com/handbook/marketing/product-ma
* [Eddie (Content Editor)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#eddie-content-editor)
-->
### Metrics
<!-- How are you going to track uage of this feature? Think about user behavior and their interaction with the product. What indicates someone is getting value from it?
Create tracking issue using the Snowplow event tracking template. See https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/issue_templates/Snowplow%20event%20tracking.md
-->
### User experience goal
<!-- What is the single user experience workflow this problem addresses?

View File

@ -3064,6 +3064,13 @@ No changes.
- [Add missing metrics information](gitlab-org/gitlab@89cd7fe3b95323e635b2d73e08549b2e6153dc4d) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61772/edit))
- [Track usage of the resolve UI](gitlab-org/gitlab@35c8e30fce288cecefcf2f7c0077d4608e696519) ([merge request](gitlab-org/gitlab!61654))
## 13.12.14 (2021-11-03)
### Fixed (2 changes)
- [Allow nil for remaining ci cd settings](gitlab-org/gitlab@896fd7ecf23714fa9f710efa4af245a26c677dce) ([merge request](gitlab-org/gitlab!73522))
- [Allow nil on delegated CI/CD settings](gitlab-org/gitlab@d57a9ea79080fc473eb54c0ee696a50fd270e8a4) ([merge request](gitlab-org/gitlab!73522))
## 13.12.13 (2021-10-29)
No changes.

View File

@ -1,5 +1,5 @@
<script>
import { pickBy } from 'lodash';
import { pickBy, isEmpty } from 'lodash';
import { mapActions } from 'vuex';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { updateHistory, setUrlParams } from '~/lib/utils/url_utility';
@ -20,6 +20,11 @@ export default {
type: Array,
required: true,
},
eeFilters: {
required: false,
type: Object,
default: () => ({}),
},
},
data() {
return {
@ -27,61 +32,6 @@ export default {
};
},
computed: {
urlParams() {
const {
authorUsername,
labelName,
assigneeUsername,
search,
milestoneTitle,
types,
weight,
epicId,
} = this.filterParams;
let notParams = {};
if (Object.prototype.hasOwnProperty.call(this.filterParams, 'not')) {
notParams = pickBy(
{
'not[label_name][]': this.filterParams.not.labelName,
'not[author_username]': this.filterParams.not.authorUsername,
'not[assignee_username]': this.filterParams.not.assigneeUsername,
'not[types]': this.filterParams.not.types,
'not[milestone_title]': this.filterParams.not.milestoneTitle,
'not[weight]': this.filterParams.not.weight,
'not[epic_id]': this.filterParams.not.epicId,
},
undefined,
);
}
return {
...notParams,
author_username: authorUsername,
'label_name[]': labelName,
assignee_username: assigneeUsername,
milestone_title: milestoneTitle,
search,
types,
weight,
epic_id: getIdFromGraphQLId(epicId),
};
},
},
methods: {
...mapActions(['performSearch']),
handleFilter(filters) {
this.filterParams = this.getFilterParams(filters);
updateHistory({
url: setUrlParams(this.urlParams, window.location.href, true, false, true),
title: document.title,
replace: true,
});
this.performSearch();
},
getFilteredSearchValue() {
const {
authorUsername,
@ -203,6 +153,66 @@ export default {
return filteredSearchValue;
},
urlParams() {
const {
authorUsername,
labelName,
assigneeUsername,
search,
milestoneTitle,
types,
weight,
epicId,
} = this.filterParams;
let notParams = {};
if (Object.prototype.hasOwnProperty.call(this.filterParams, 'not')) {
notParams = pickBy(
{
'not[label_name][]': this.filterParams.not.labelName,
'not[author_username]': this.filterParams.not.authorUsername,
'not[assignee_username]': this.filterParams.not.assigneeUsername,
'not[types]': this.filterParams.not.types,
'not[milestone_title]': this.filterParams.not.milestoneTitle,
'not[weight]': this.filterParams.not.weight,
'not[epic_id]': this.filterParams.not.epicId,
},
undefined,
);
}
return {
...notParams,
author_username: authorUsername,
'label_name[]': labelName,
assignee_username: assigneeUsername,
milestone_title: milestoneTitle,
search,
types,
weight,
epic_id: getIdFromGraphQLId(epicId),
};
},
},
created() {
if (!isEmpty(this.eeFilters)) {
this.filterParams = this.eeFilters;
}
},
methods: {
...mapActions(['performSearch']),
handleFilter(filters) {
this.filterParams = this.getFilterParams(filters);
updateHistory({
url: setUrlParams(this.urlParams, window.location.href, true, false, true),
title: document.title,
replace: true,
});
this.performSearch();
},
getFilterParams(filters = []) {
const notFilters = filters.filter((item) => item.value.operator === '!=');
const equalsFilters = filters.filter(
@ -266,7 +276,7 @@ export default {
namespace=""
:tokens="tokens"
:search-input-placeholder="$options.i18n.search"
:initial-filter-value="getFilteredSearchValue()"
:initial-filter-value="getFilteredSearchValue"
@onFilter="handleFilter"
/>
</template>

View File

@ -49,3 +49,5 @@ export const PipelineKeyOptions = [
key: 'iid',
},
];
export const TOAST_MESSAGE = s__('Pipeline|Creating pipeline.');

View File

@ -4,7 +4,7 @@ import { historyPushState, buildUrlWithCurrentLocation } from '~/lib/utils/commo
import Poll from '~/lib/utils/poll';
import { __ } from '~/locale';
import { validateParams } from '~/pipelines/utils';
import { CANCEL_REQUEST } from '../constants';
import { CANCEL_REQUEST, TOAST_MESSAGE } from '../constants';
import eventHub from '../event_hub';
export default {
@ -191,7 +191,10 @@ export default {
this.service
.runMRPipeline(options)
.then(() => this.updateTable())
.then(() => {
this.$toast.show(TOAST_MESSAGE);
this.updateTable();
})
.catch(() => {
createFlash({
message: __(

View File

@ -32,7 +32,7 @@ class JiraConnect::AppDescriptorController < JiraConnect::ApplicationController
apiVersion: 1,
apiMigrations: {
'context-qsh': true,
'signed-install': signed_install_active?,
'signed-install': true,
gdpr: true
}
}

View File

@ -74,8 +74,4 @@ class JiraConnect::ApplicationController < ApplicationController
params[:jwt] || request.headers['Authorization']&.split(' ', 2)&.last
end
end
def signed_install_active?
Feature.enabled?(:jira_connect_asymmetric_jwt, default_enabled: :yaml)
end
end

View File

@ -4,14 +4,9 @@ class JiraConnect::EventsController < JiraConnect::ApplicationController
# See https://developer.atlassian.com/cloud/jira/software/app-descriptor/#lifecycle
skip_before_action :verify_atlassian_jwt!
before_action :verify_asymmetric_atlassian_jwt!, if: :signed_install_active?
before_action :verify_atlassian_jwt!, only: :uninstalled, unless: :signed_install_active?
before_action :verify_qsh_claim!, only: :uninstalled, unless: :signed_install_active?
before_action :verify_asymmetric_atlassian_jwt!
def installed
return head :ok if !signed_install_active? && atlassian_jwt_valid?
return head :ok if current_jira_installation
installation = JiraConnectInstallation.new(event_params)

View File

@ -1,8 +1,8 @@
---
name: jira_connect_asymmetric_jwt
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/71080
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/342808
milestone: '14.4'
name: rate_limiter_safe_increment
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73343
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/285352
milestone: '14.5'
type: development
group: group::integrations
default_enabled: true
group: group::project management
default_enabled: false

View File

@ -8,8 +8,7 @@ product_stage: package
product_group: group::package
product_category: package registry
value_type: number
status: broken
repair_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/331455
status: active
time_frame: 28d
data_source: redis_hll
instrumentation_class: RedisHLLMetric

View File

@ -8,8 +8,7 @@ product_stage: package
product_group: group::package
product_category: package registry
value_type: number
status: broken
repair_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/331455
status: active
time_frame: 28d
data_source: redis_hll
instrumentation_class: RedisHLLMetric

View File

@ -8,8 +8,7 @@ product_stage: package
product_group: group::package
product_category: package registry
value_type: number
status: broken
repair_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/331455
status: active
time_frame: 7d
data_source: redis_hll
instrumentation_class: RedisHLLMetric

View File

@ -30,6 +30,7 @@ POST /ci/lint
| ---------- | ------- | -------- | -------- |
| `content` | string | yes | The CI/CD configuration content. |
| `include_merged_yaml` | boolean | no | If the [expanded CI/CD configuration](#yaml-expansion) should be included in the response. |
| `include_jobs` | boolean | no | If the list of jobs should be included in the response. This is false by default. |
```shell
curl --header "Content-Type: application/json" --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/ci/lint" --data '{"content": "{ \"image\": \"ruby:2.6\", \"services\": [\"postgres\"], \"before_script\": [\"bundle install\", \"bundle exec rake db:create\"], \"variables\": {\"DB_NAME\": \"postgres\"}, \"types\": [\"test\", \"deploy\", \"notify\"], \"rspec\": { \"script\": \"rake spec\", \"tags\": [\"ruby\", \"postgres\"], \"only\": [\"branches\"]}}"}'
@ -91,7 +92,7 @@ work for CI configuration added with [`include: local`](../ci/yaml/index.md#incl
or with [`extends:`](../ci/yaml/index.md#extends).
Example contents of a `.gitlab-ci.yml` passed to the CI Lint API with
`include_merged_yaml` set as true:
`include_merged_yaml` and `include_jobs` set as true:
```yaml
include:
@ -118,7 +119,39 @@ Example response:
{
"status": "valid",
"errors": [],
"merged_yaml": "---\n:another_test:\n :stage: test\n :script: echo 2\n:test:\n :stage: test\n :script: echo 1\n"
"merged_yaml": "---\n:another_test:\n :stage: test\n :script: echo 2\n:test:\n :stage: test\n :script: echo 1\n",
"jobs": [
{
"name":"test",
"stage":"test",
"before_script":[],
"script":["echo 1"],
"after_script":[],
"tag_list":[],
"environment":null,
"when":"on_success",
"allow_failure":false,
"only":{
"refs":["branches","tags"]
},
"except":null
},
{
"name":"another_test",
"stage":"test",
"before_script":[],
"script":["echo 2"],
"after_script":[],
"tag_list":[],
"environment":null,
"when":"on_success",
"allow_failure":false,
"only":{
"refs":["branches","tags"]
},
"except":null
}
]
}
```
@ -137,6 +170,7 @@ POST /projects/:id/ci/lint
| ---------- | ------- | -------- | -------- |
| `content` | string | yes | The CI/CD configuration content. |
| `dry_run` | boolean | no | Run [pipeline creation simulation](../ci/lint.md#pipeline-simulation), or only do static check. This is false by default. |
| `include_jobs` | boolean | no | If the list of jobs that would exist in a static check or pipeline simulation should be included in the response. This is false by default. |
Example request:
@ -185,6 +219,7 @@ GET /projects/:id/ci/lint
| Attribute | Type | Required | Description |
| ---------- | ------- | -------- | -------- |
| `dry_run` | boolean | no | Run pipeline creation simulation, or only do static check. |
| `include_jobs` | boolean | no | If the list of jobs that would exist in a static check or pipeline simulation should be included in the response. This is false by default. |
Example request:

View File

@ -50,6 +50,8 @@ We use the following terminology to describe the Service Ping components:
- **Metrics**: primarily made up of row counts for different tables in an instance's database. Each
metric has a corresponding [metric definition](metrics_dictionary.md#metrics-definition-and-validation)
in a YAML file.
- **MAU**: monthly active users.
- **WAU**: weekly active users.
### Why should we enable Service Ping?

View File

@ -7,124 +7,186 @@ type: index
# Admin Area settings **(FREE SELF)**
As an administrator of a GitLab self-managed instance, you can manage the behavior of your deployment. To do so, select **Admin Area > Settings**.
As an administrator of a GitLab self-managed instance, you can manage the behavior of your
deployment.
The Admin Area is not accessible on GitLab.com, and settings can only be changed by the
GitLab.com administrators. See the [GitLab.com settings](../../gitlab_com/index.md)
documentation for all current settings and limits on the GitLab.com instance.
The **Admin Area** is not accessible on GitLab.com, and settings can only be changed by the
GitLab.com administrators. For the settings and limits on the GitLab.com instance,
read [GitLab.com settings](../../gitlab_com/index.md).
## General
## Access the Admin Area
To access the default page for Admin Area settings:
To access the **Admin Area**:
1. Sign in to your GitLab instance as an administrator.
1. On the top bar, select **Menu > Admin**.
1. On the left sidebar, select **Settings > General**.
1. On the left sidebar, select **Settings**, and the group of settings to view:
- [General](#general)
- [Geo](#geo)
- [CI/CD](#cicd)
- [Integrations](#integrations)
- [Metrics and profiling](#metrics-and-profiling)
- [Network](#network)
- [Preferences](#preferences)
- [Reporting](#reporting)
- [Repository](#repository)
- [Templates](#templates)
| Option | Description |
| ------ | ----------- |
| [Visibility and access controls](visibility_and_access_controls.md) | Set default and restrict visibility levels. Configure import sources and Git access protocol. |
| [Account and limit](account_and_limit_settings.md) | Set projects and maximum size limits, session duration, user options, and check feature availability for namespace plan. |
| [Diff limits](../diff_limits.md) | Diff content limits. |
| [Sign-up restrictions](sign_up_restrictions.md) | Configure the way a user creates a new account. |
| [Sign in restrictions](sign_in_restrictions.md) | Set requirements for a user to sign in. Enable mandatory two-factor authentication. |
| [Terms of Service and Privacy Policy](terms.md) | Include a Terms of Service agreement and Privacy Policy that all users must accept. |
| [External Authentication](external_authorization.md#configuration) | External Classification Policy Authorization |
| [Web terminal](../../../administration/integration/terminal.md#limiting-websocket-connection-time) | Set max session time for web terminal. |
| [Web IDE](../../project/web_ide/index.md#enable-live-preview) | Manage Web IDE features. |
| [FLoC](floc.md) | Enable or disable [Federated Learning of Cohorts (FLoC)](https://en.wikipedia.org/wiki/Federated_Learning_of_Cohorts) tracking. |
### General
## Integrations
The **General** settings contain:
| Option | Description |
| ------ | ----------- |
| [Elasticsearch](../../../integration/elasticsearch.md#enable-advanced-search) | Elasticsearch integration. Elasticsearch AWS IAM. |
| [Kroki](../../../administration/integration/kroki.md#enable-kroki-in-gitlab) | Allow rendering of diagrams in AsciiDoc and Markdown documents using [kroki.io](https://kroki.io). |
| [Mailgun](../../../administration/integration/mailgun.md) | Enable your GitLab instance to receive invite email bounce events from Mailgun, if it is your email provider. |
| [PlantUML](../../../administration/integration/plantuml.md) | Allow rendering of PlantUML diagrams in documents. |
| [Slack application](../../../user/project/integrations/gitlab_slack_application.md#configuration) | Slack integration allows you to interact with GitLab via slash commands in a chat window. This option is only available on GitLab.com, though it may be [available for self-managed instances in the future](https://gitlab.com/gitlab-org/gitlab/-/issues/28164). |
| [Third party offers](third_party_offers.md) | Control the display of third party offers. |
| [Snowplow](../../../development/snowplow/index.md) | Configure the Snowplow integration. |
| [Google GKE](../../project/clusters/add_gke_clusters.md) | Google GKE integration allows you to provision GKE clusters from GitLab. |
| [Amazon EKS](../../project/clusters/add_eks_clusters.md) | Amazon EKS integration allows you to provision EKS clusters from GitLab. |
- [Visibility and access controls](visibility_and_access_controls.md) - Set default and
restrict visibility levels. Configure import sources and Git access protocol.
- [Account and limit](account_and_limit_settings.md) - Set projects and maximum size limits,
session duration, user options, and check feature availability for namespace plan.
- [Diff limits](../diff_limits.md) - Diff content limits.
- [Sign-up restrictions](sign_up_restrictions.md) - Configure the way a user creates a new account.
- [Sign in restrictions](sign_in_restrictions.md) - Set requirements for a user to sign in.
Enable mandatory two-factor authentication.
- [Terms of Service and Privacy Policy](terms.md) - Include a Terms of Service agreement
and Privacy Policy that all users must accept.
- [External Authentication](external_authorization.md#configuration) - External Classification Policy Authorization.
- [Web terminal](../../../administration/integration/terminal.md#limiting-websocket-connection-time) -
Set max session time for web terminal.
- [Web IDE](../../project/web_ide/index.md#enable-live-preview) - Manage Web IDE features.
- [FLoC](floc.md) - Enable or disable
[Federated Learning of Cohorts (FLoC)](https://en.wikipedia.org/wiki/Federated_Learning_of_Cohorts) tracking.
## Repository
### CI/CD
| Option | Description |
| ------ | ----------- |
| [Repository's custom initial branch name](../../project/repository/branches/default.md#instance-level-custom-initial-branch-name) | Set a custom branch name for new repositories created in your instance. |
| [Repository mirror](visibility_and_access_controls.md#enable-project-mirroring) | Configure repository mirroring. |
| [Repository storage](../../../administration/repository_storage_types.md) | Configure storage path settings. |
| Repository maintenance | ([Repository checks](../../../administration/repository_checks.md) and [Housekeeping](../../../administration/housekeeping.md)). Configure automatic Git checks and housekeeping on repositories. |
| [Repository static objects](../../../administration/static_objects_external_storage.md) | Serve repository static objects (for example, archives and blobs) from an external storage (for example, a CDN). |
The **CI/CD** settings contain:
## Templates **(PREMIUM SELF)**
- [Continuous Integration and Deployment](continuous_integration.md) -
Auto DevOps, runners and job artifacts.
- [Required pipeline configuration](continuous_integration.md#required-pipeline-configuration) -
Set an instance-wide auto included [pipeline configuration](../../../ci/yaml/index.md).
This pipeline configuration is run after the project's own configuration.
- [Package Registry](continuous_integration.md#package-registry-configuration) -
Settings related to the use and experience of using the GitLab Package Registry. Some
[risks are involved](../../packages/container_registry/index.md#use-with-external-container-registries)
in enabling some of these settings.
| Option | Description |
| ------ | ----------- |
| [Templates](instance_template_repository.md#configuration) | Set instance-wide template repository. |
| [Custom project templates](../custom_project_templates.md) | Select the custom project template source group. |
### Geo **(PREMIUM SELF)**
## CI/CD
The **Geo** setting contains:
| Option | Description |
| ------ | ----------- |
| [Continuous Integration and Deployment](continuous_integration.md) | Auto DevOps, runners and job artifacts. |
| [Required pipeline configuration](continuous_integration.md#required-pipeline-configuration) | Set an instance-wide auto included [pipeline configuration](../../../ci/yaml/index.md). This pipeline configuration is run after the project's own configuration. |
| [Package Registry](continuous_integration.md#package-registry-configuration) | Settings related to the use and experience of using the GitLab Package Registry. Note there are [risks involved](../../packages/container_registry/index.md#use-with-external-container-registries) in enabling some of these settings. |
- [Geo](../../../administration/geo/index.md) - Replicate your GitLab instance to other
geographical locations. Redirects to **Admin Area > Geo > Settings** are no
longer available at **Admin Area > Settings > Geo** in [GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/issues/36896).
## Reporting
### Integrations
| Option | Description |
| ------ | ----------- |
| [Spam and Anti-bot Protection](../../../integration/recaptcha.md) | Enable reCAPTCHA or Akismet and set IP limits. For reCAPTCHA, we currently only support [v2](https://developers.google.com/recaptcha/docs/versions). |
| [Abuse reports](../review_abuse_reports.md) | Set notification email for abuse reports. |
The **Integrations** settings contain:
## Metrics and profiling
- [Elasticsearch](../../../integration/elasticsearch.md#enable-advanced-search) -
Elasticsearch integration. Elasticsearch AWS IAM.
- [Kroki](../../../administration/integration/kroki.md#enable-kroki-in-gitlab) -
Allow rendering of diagrams in AsciiDoc and Markdown documents using [kroki.io](https://kroki.io).
- [Mailgun](../../../administration/integration/mailgun.md) - Enable your GitLab instance
to receive invite email bounce events from Mailgun, if it is your email provider.
- [PlantUML](../../../administration/integration/plantuml.md) - Allow rendering of PlantUML
diagrams in documents.
- [Slack application](../../../user/project/integrations/gitlab_slack_application.md#configuration) -
Slack integration allows you to interact with GitLab via slash commands in a chat window.
This option is only available on GitLab.com, though it may be
[available for self-managed instances in the future](https://gitlab.com/gitlab-org/gitlab/-/issues/28164).
- [Third party offers](third_party_offers.md) - Control the display of third-party offers.
- [Snowplow](../../../development/snowplow/index.md) - Configure the Snowplow integration.
- [Google GKE](../../project/clusters/add_gke_clusters.md) - Google GKE integration enables
you to provision GKE clusters from GitLab.
- [Amazon EKS](../../project/clusters/add_eks_clusters.md) - Amazon EKS integration enables
you to provision EKS clusters from GitLab.
| Option | Description |
| ------ | ----------- |
| [Metrics - Prometheus](../../../administration/monitoring/prometheus/gitlab_metrics.md) | Enable and configure Prometheus metrics. |
| [Metrics - Grafana](../../../administration/monitoring/performance/grafana_configuration.md#integration-with-gitlab-ui) | Enable and configure Grafana. |
| [Profiling - Performance bar](../../../administration/monitoring/performance/performance_bar.md#enable-the-performance-bar-for-non-administrators) | Enable access to the Performance Bar for non-administrator users in a given group. |
| [Self monitoring](../../../administration/monitoring/gitlab_self_monitoring_project/index.md#create-the-self-monitoring-project) | Enable or disable instance self monitoring. |
| [Usage statistics](usage_statistics.md) | Enable or disable version check and Service Ping. |
| [Pseudonymizer data collection](../../../administration/pseudonymizer.md) | Enable or disable the Pseudonymizer data collection. |
### Metrics and profiling
## Network
The **Metrics and profiling** settings contain:
| Option | Description |
| ------ | ----------- |
| Performance optimization | [Write to "authorized_keys" file](../../../administration/operations/fast_ssh_key_lookup.md#setting-up-fast-lookup-via-gitlab-shell) and [Push event activities limit and bulk push events](push_event_activities_limit.md). Various settings that affect GitLab performance. |
| [User and IP rate limits](user_and_ip_rate_limits.md) | Configure limits for web and API requests. |
| [Package Registry Rate Limits](package_registry_rate_limits.md) | Configure specific limits for Packages API requests that supersede the user and IP rate limits. |
| [Git LFS Rate Limits](git_lfs_rate_limits.md) | Configure specific limits for Git LFS requests that supersede the user and IP rate limits. |
| [Files API Rate Limits](files_api_rate_limits.md) | Configure specific limits for Files API requests that supersede the user and IP rate limits. |
| [Deprecated API Rate Limits](deprecated_api_rate_limits.md) | Configure specific limits for deprecated API requests that supersede the user and IP rate limits. |
| [Outbound requests](../../../security/webhooks.md) | Allow requests to the local network from hooks and services. |
| [Protected Paths](protected_paths.md) | Configure paths to be protected by Rack Attack. |
| [Incident Management](../../../operations/incident_management/index.md) Limits | Limit the number of inbound alerts that can be sent to a project. |
| [Notes creation limit](rate_limit_on_notes_creation.md)| Set a rate limit on the note creation requests. |
- [Metrics - Prometheus](../../../administration/monitoring/prometheus/gitlab_metrics.md) -
Enable and configure Prometheus metrics.
- [Metrics - Grafana](../../../administration/monitoring/performance/grafana_configuration.md#integration-with-gitlab-ui) -
Enable and configure Grafana.
- [Profiling - Performance bar](../../../administration/monitoring/performance/performance_bar.md#enable-the-performance-bar-for-non-administrators) -
Enable access to the Performance Bar for non-administrator users in a given group.
- [Self monitoring](../../../administration/monitoring/gitlab_self_monitoring_project/index.md#create-the-self-monitoring-project) -
Enable or disable instance self monitoring.
- [Usage statistics](usage_statistics.md) - Enable or disable version check and Service Ping.
- [Pseudonymizer data collection](../../../administration/pseudonymizer.md) -
Enable or disable the Pseudonymizer data collection.
## Geo **(PREMIUM SELF)**
### Network
| Option | Description |
| ------ | ----------- |
| [Geo](../../../administration/geo/index.md) | Geo allows you to replicate your GitLab instance to other geographical locations. Redirects to **Admin Area > Geo > Settings** are no longer available at **Admin Area > Settings > Geo** in [GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/issues/36896). |
The **Network** settings contain:
## Preferences
- Performance optimization - Various settings that affect GitLab performance, including:
- [Write to `authorized_keys` file](../../../administration/operations/fast_ssh_key_lookup.md#setting-up-fast-lookup-via-gitlab-shell).
- [Push event activities limit and bulk push events](push_event_activities_limit.md).
- [User and IP rate limits](user_and_ip_rate_limits.md) - Configure limits for web and API requests.
These rate limits can be overridden:
- [Package Registry Rate Limits](package_registry_rate_limits.md) - Configure specific
limits for Packages API requests that supersede the user and IP rate limits.
- [Git LFS Rate Limits](git_lfs_rate_limits.md) - Configure specific limits for
Git LFS requests that supersede the user and IP rate limits.
- [Files API Rate Limits](files_api_rate_limits.md) - Configure specific limits for
Files API requests that supersede the user and IP rate limits.
- [Deprecated API Rate Limits](deprecated_api_rate_limits.md) - Configure specific limits
for deprecated API requests that supersede the user and IP rate limits.
- [Outbound requests](../../../security/webhooks.md) - Allow requests to the local network from hooks and services.
- [Protected Paths](protected_paths.md) - Configure paths to be protected by Rack Attack.
- [Incident Management Limits](../../../operations/incident_management/index.md) - Limit the
number of inbound alerts that can be sent to a project.
- [Notes creation limit](rate_limit_on_notes_creation.md) - Set a rate limit on the note creation requests.
| Option | Description |
| ------ | ----------- |
| [Email](email.md) | Various email settings. |
| [What's new](../../../administration/whats-new.md) | Configure What's new drawer and content. |
| [Help page](help_page.md) | Help page text and support page URL. |
| [Pages](../../../administration/pages/index.md#custom-domain-verification) | Size and domain settings for static websites |
| [Polling interval multiplier](../../../administration/polling.md) | Configure how frequently the GitLab UI polls for updates. |
| [Gitaly timeouts](gitaly_timeouts.md) | Configure Gitaly timeouts. |
| Localization | [Default first day of the week](../../profile/preferences.md) and [Time tracking](../../project/time_tracking.md#limit-displayed-units-to-hours). |
| [Sidekiq Job Limits](sidekiq_job_limits.md) | Limit the size of Sidekiq jobs stored in Redis. |
### Preferences
### Default first day of the week
The **Preferences** settings contain:
- [Email](email.md) - Various email settings.
- [What's new](../../../administration/whats-new.md) - Configure **What's new** drawer and content.
- [Help page](help_page.md) - Help page text and support page URL.
- [Pages](../../../administration/pages/index.md#custom-domain-verification) -
Size and domain settings for static websites.
- [Polling interval multiplier](../../../administration/polling.md) -
Configure how frequently the GitLab UI polls for updates.
- [Gitaly timeouts](gitaly_timeouts.md) - Configure Gitaly timeouts.
- Localization:
- [Default first day of the week](../../profile/preferences.md).
- [Time tracking](../../project/time_tracking.md#limit-displayed-units-to-hours).
- [Sidekiq Job Limits](sidekiq_job_limits.md) - Limit the size of Sidekiq jobs stored in Redis.
### Reporting
The **Reporting** settings contain:
- [Spam and Anti-bot Protection](../../../integration/recaptcha.md) -
Enable anti-spam services, like reCAPTCHA or Akismet, and set IP limits.
- [Abuse reports](../review_abuse_reports.md) - Set notification email for abuse reports.
### Repository
The **Repository** settings contain:
- [Repository's custom initial branch name](../../project/repository/branches/default.md#instance-level-custom-initial-branch-name) -
Set a custom branch name for new repositories created in your instance.
- [Repository mirror](visibility_and_access_controls.md#enable-project-mirroring) -
Configure repository mirroring.
- [Repository storage](../../../administration/repository_storage_types.md) - Configure storage path settings.
- Repository maintenance:
- [Repository checks](../../../administration/repository_checks.md) - Configure
automatic Git checks on repositories.
- [Housekeeping](../../../administration/housekeeping.md)). Configure automatic
Git housekeeping on repositories.
- [Repository static objects](../../../administration/static_objects_external_storage.md) -
Serve repository static objects (for example, archives and blobs) from an external storage (for example, a CDN).
### Templates **(PREMIUM SELF)**
The **Templates** settings contain:
- [Templates](instance_template_repository.md#configuration) - Set instance-wide template repository.
- [Custom project templates](../custom_project_templates.md) - Select the custom project template source group.
## Default first day of the week
You can change the [Default first day of the week](../../profile/preferences.md)
for the entire GitLab instance:

View File

@ -18,8 +18,8 @@ in Microsoft Teams. To integrate the services, you must:
To configure Microsoft Teams to listen for notifications from GitLab:
1. In Microsoft Teams, search for "incoming webhook" in the search bar, and select the
**Incoming Webhook** item:
1. In Microsoft Teams, type `incoming webhook` in the search bar, and select
**Incoming Webhook**:
![Select Incoming Webhook](img/microsoft_teams_select_incoming_webhook.png)
@ -34,11 +34,12 @@ To configure Microsoft Teams to listen for notifications from GitLab:
After you configure Microsoft Teams to receive notifications, you must configure
GitLab to send the notifications:
1. Sign in to GitLab as a user with [Administrator](../../permissions.md) and go
to your project's page.
1. Go to **Settings > Integrations** and select **Microsoft Teams Notification**.
1. Select **Active** to enable the integration.
1. Select the checkbox next to each **Trigger** to enable:
1. Sign in to GitLab as an administrator.
1. On the top bar, select **Menu > Projects** and find your project.
1. On the left sidebar, select **Settings > Integrations**.
1. Select **Microsoft Teams notifications**.
1. To enable the integration, select **Active**.
1. In the **Trigger** section, select the checkbox next to each event to enable it:
- Push
- Issue
- Confidential issue
@ -46,11 +47,11 @@ GitLab to send the notifications:
- Note
- Confidential note
- Tag push
- Pipeline - If you enable this trigger, you can also select **Notify only broken pipelines** to be notified only about failed pipelines.
- Pipeline
- Wiki page
1. In **Webhook**, paste the URL you copied when you
[configured Microsoft Teams](#configure-microsoft-teams).
1. (Optional) If you enabled the pipeline trigger, you can select the
1. Optional. If you enable the pipeline trigger, select the
**Notify only broken pipelines** checkbox to push notifications only when pipelines break.
1. Select the branches you want to send notifications for.
1. Select **Save changes**.

View File

@ -4,9 +4,9 @@ group: Code Review
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
# GitLab Workflow VS Code extension **(FREE)**
# GitLab Workflow extension for VS Code **(FREE)**
The [GitLab VS Code Extension](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow)
The [GitLab Workflow extension](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow)
integrates GitLab with Visual Studio Code. You can decrease context switching and
do more day-to-day tasks in Visual Studio Code, such as:

View File

@ -9,6 +9,7 @@ module API
expose :errors
expose :warnings
expose :merged_yaml
expose :jobs, if: -> (result, options) { options[:include_jobs] }
end
end
end

View File

@ -9,6 +9,7 @@ module API
params do
requires :content, type: String, desc: 'Content of .gitlab-ci.yml'
optional :include_merged_yaml, type: Boolean, desc: 'Whether or not to include merged CI config yaml in the response'
optional :include_jobs, type: Boolean, desc: 'Whether or not to include CI jobs in the response'
end
post '/lint' do
unauthorized! if (Gitlab::CurrentSettings.signup_disabled? || Gitlab::CurrentSettings.signup_limited?) && current_user.nil?
@ -17,7 +18,7 @@ module API
.validate(params[:content], dry_run: false)
status 200
Entities::Ci::Lint::Result.represent(result, current_user: current_user).serializable_hash.tap do |presented_result|
Entities::Ci::Lint::Result.represent(result, current_user: current_user, include_jobs: params[:include_jobs]).serializable_hash.tap do |presented_result|
presented_result[:status] = presented_result[:valid] ? 'valid' : 'invalid'
presented_result.delete(:merged_yaml) unless params[:include_merged_yaml]
end
@ -30,6 +31,7 @@ module API
end
params do
optional :dry_run, type: Boolean, default: false, desc: 'Run pipeline creation simulation, or only do static check.'
optional :include_jobs, type: Boolean, desc: 'Whether or not to include CI jobs in the response'
end
get ':id/ci/lint' do
authorize! :download_code, user_project
@ -39,7 +41,7 @@ module API
.new(project: user_project, current_user: current_user)
.validate(content, dry_run: params[:dry_run])
present result, with: Entities::Ci::Lint::Result, current_user: current_user
present result, with: Entities::Ci::Lint::Result, current_user: current_user, include_jobs: params[:include_jobs]
end
end
@ -50,6 +52,7 @@ module API
params do
requires :content, type: String, desc: 'Content of .gitlab-ci.yml'
optional :dry_run, type: Boolean, default: false, desc: 'Run pipeline creation simulation, or only do static check.'
optional :include_jobs, type: Boolean, desc: 'Whether or not to include CI jobs in the response'
end
post ':id/ci/lint' do
authorize! :create_pipeline, user_project
@ -59,7 +62,7 @@ module API
.validate(params[:content], dry_run: params[:dry_run])
status 200
present result, with: Entities::Ci::Lint::Result, current_user: current_user
present result, with: Entities::Ci::Lint::Result, current_user: current_user, include_jobs: params[:include_jobs]
end
end
end

View File

@ -66,7 +66,6 @@ module Gitlab
# @param key [Symbol] Key attribute registered in `.rate_limits`
# @option scope [Array<ActiveRecord>] Array of ActiveRecord models to scope throttling to a specific request (e.g. per user per project)
# @option threshold [Integer] Optional threshold value to override default one registered in `.rate_limits`
# @option interval [Integer] Optional interval value to override default one registered in `.rate_limits`
# @option users_allowlist [Array<String>] Optional list of usernames to exclude from the limit. This param will only be functional if Scope includes a current user.
#
# @return [Boolean] Whether or not a request should be throttled
@ -77,7 +76,7 @@ module Gitlab
threshold_value = options[:threshold] || threshold(key)
threshold_value > 0 &&
increment(key, options[:scope], options[:interval]) > threshold_value
increment(key, options[:scope]) > threshold_value
end
# Increments the given cache key and increments the value by 1 with the
@ -85,12 +84,13 @@ module Gitlab
#
# @param key [Symbol] Key attribute registered in `.rate_limits`
# @option scope [Array<ActiveRecord>] Array of ActiveRecord models to scope throttling to a specific request (e.g. per user per project)
# @option interval [Integer] Optional interval value to override default one registered in `.rate_limits`
#
# @return [Integer] incremented value
def increment(key, scope, interval = nil)
def increment(key, scope)
return safe_increment(key, scope) if Feature.enabled?(:rate_limiter_safe_increment, default_enabled: :yaml)
value = 0
interval_value = interval || interval(key)
interval_value = interval(key)
::Gitlab::Redis::RateLimiting.with do |redis|
cache_key = action_key(key, scope)
@ -101,6 +101,32 @@ module Gitlab
value
end
# Increments a cache key that is based on the current time and interval.
# So that when time passes to the next interval, the key changes and the count starts again from 0.
#
# Based on https://github.com/rack/rack-attack/blob/886ba3a18d13c6484cd511a4dc9b76c0d14e5e96/lib/rack/attack/cache.rb#L63-L68
#
# @param key [Symbol] Key attribute registered in `.rate_limits`
# @option scope [Array<ActiveRecord>] Array of ActiveRecord models to scope throttling to a specific request (e.g. per user per project)
#
# @return [Integer] incremented value
def safe_increment(key, scope)
interval_value = interval(key)
period_key, time_elapsed_in_period = Time.now.to_i.divmod(interval_value)
cache_key = "#{action_key(key, scope)}:#{period_key}"
# We add a 1 second buffer to avoid timing issues when we're at the end of a period
expiry = interval_value - time_elapsed_in_period + 1
::Gitlab::Redis::RateLimiting.with do |redis|
redis.pipelined do
redis.incr(cache_key)
redis.expire(cache_key, expiry)
end.first
end
end
# Logs request using provided logger
#
# @param request [Http::Request] - Web request to be logged

View File

@ -8216,9 +8216,6 @@ msgstr ""
msgid "Code"
msgstr ""
msgid "Code Coverage: %{coveragePercentage}"
msgstr ""
msgid "Code Coverage: %{coveragePercentage}%{percentSymbol}"
msgstr ""
@ -14075,6 +14072,12 @@ msgstr ""
msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
msgstr ""
msgid "ExternalIssueIntegration|Not all data may be displayed here. To view more details or make changes to this issue, go to %{linkStart}%{trackerName}%{linkEnd}."
msgstr ""
msgid "ExternalIssueIntegration|This issue is synchronized with %{trackerName}"
msgstr ""
msgid "ExternalWikiService|External wiki"
msgstr ""
@ -19655,9 +19658,6 @@ msgstr ""
msgid "JiraService|No available statuses"
msgstr ""
msgid "JiraService|Not all data may be displayed here. To view more details or make changes to this issue, go to %{linkStart}Jira%{linkEnd}."
msgstr ""
msgid "JiraService|Open Jira"
msgstr ""
@ -19688,9 +19688,6 @@ msgstr ""
msgid "JiraService|This is an Ultimate feature"
msgstr ""
msgid "JiraService|This issue is synchronized with Jira"
msgstr ""
msgid "JiraService|Transition Jira issues to their final state:"
msgstr ""
@ -25534,6 +25531,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
msgid "Pipeline|Creating pipeline."
msgstr ""
msgid "Pipeline|Date"
msgstr ""
@ -29002,6 +29002,9 @@ msgstr ""
msgid "RepositoriesAnalytics|Average test coverage last 30 days"
msgstr ""
msgid "RepositoriesAnalytics|Code Coverage: %{averageCoverage}"
msgstr ""
msgid "RepositoriesAnalytics|Coverage"
msgstr ""
@ -29023,6 +29026,9 @@ msgstr ""
msgid "RepositoriesAnalytics|Jobs with Coverage"
msgstr ""
msgid "RepositoriesAnalytics|Jobs with Coverage: %{coverageCount}"
msgstr ""
msgid "RepositoriesAnalytics|Last Update"
msgstr ""
@ -29041,6 +29047,9 @@ msgstr ""
msgid "RepositoriesAnalytics|Projects with Coverage"
msgstr ""
msgid "RepositoriesAnalytics|Projects with Coverage: %{projectCount}"
msgstr ""
msgid "RepositoriesAnalytics|Test Code Coverage"
msgstr ""
@ -39914,15 +39923,9 @@ msgstr ""
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
msgid "ZenTaoIntegration|Not all data may be displayed here. To view more details or make changes to this issue, go to %{linkStart}ZenTao%{linkEnd}."
msgstr ""
msgid "ZenTaoIntegration|This is a ZenTao user."
msgstr ""
msgid "ZenTaoIntegration|This issue is synchronized with ZenTao"
msgstr ""
msgid "ZenTaoIntegration|ZenTao user"
msgstr ""
@ -40304,6 +40307,9 @@ msgstr ""
msgid "ciReport|Failed to load %{reportName} report"
msgstr ""
msgid "ciReport|Failed to load Code Quality report"
msgstr ""
msgid "ciReport|Fixed"
msgstr ""
@ -40336,6 +40342,9 @@ msgstr ""
msgid "ciReport|Loading %{reportName} report"
msgstr ""
msgid "ciReport|Loading Code Quality report"
msgstr ""
msgid "ciReport|Manage licenses"
msgstr ""
@ -40372,6 +40381,9 @@ msgstr ""
msgid "ciReport|Security scanning failed loading any results"
msgstr ""
msgid "ciReport|Showing %{fetchedItems} of %{totalItems} items"
msgstr ""
msgid "ciReport|Solution"
msgstr ""

View File

@ -90,17 +90,5 @@ RSpec.describe JiraConnect::AppDescriptorController do
)
)
end
context 'when jira_connect_asymmetric_jwt is disabled' do
before do
stub_feature_flags(jira_connect_asymmetric_jwt: false)
end
specify do
get :show
expect(json_response).to include('apiMigrations' => include('signed-install' => false))
end
end
end
end

View File

@ -77,18 +77,6 @@ RSpec.describe JiraConnect::EventsController do
expect(installation.base_url).to eq('https://test.atlassian.net')
end
context 'when jira_connect_asymmetric_jwt is disabled' do
before do
stub_feature_flags(jira_connect_asymmetric_jwt: false)
end
it 'saves the jira installation data without JWT validation' do
expect(Atlassian::JiraConnect::AsymmetricJwt).not_to receive(:new)
expect { subject }.to change { JiraConnectInstallation.count }.by(1)
end
end
context 'when it is a version update and shared_secret is not sent' do
let(:params) do
{
@ -110,22 +98,6 @@ RSpec.describe JiraConnect::EventsController do
expect { subject }.not_to change { JiraConnectInstallation.count }
expect(response).to have_gitlab_http_status(:ok)
end
context 'when jira_connect_asymmetric_jwt is disabled' do
before do
stub_feature_flags(jira_connect_asymmetric_jwt: false)
end
it 'decodes the JWT token in authorization header and returns 200 without creating a new installation' do
request.headers["Authorization"] = "Bearer #{Atlassian::Jwt.encode({ iss: client_key }, shared_secret)}"
expect(Atlassian::JiraConnect::AsymmetricJwt).not_to receive(:new)
expect { subject }.not_to change { JiraConnectInstallation.count }
expect(response).to have_gitlab_http_status(:ok)
end
end
end
end
end
@ -153,23 +125,6 @@ RSpec.describe JiraConnect::EventsController do
it 'does not delete the installation' do
expect { post_uninstalled }.not_to change { JiraConnectInstallation.count }
end
context 'when jira_connect_asymmetric_jwt is disabled' do
before do
stub_feature_flags(jira_connect_asymmetric_jwt: false)
request.headers['Authorization'] = 'JWT invalid token'
end
it 'returns 403' do
post_uninstalled
expect(response).to have_gitlab_http_status(:forbidden)
end
it 'does not delete the installation' do
expect { post_uninstalled }.not_to change { JiraConnectInstallation.count }
end
end
end
context 'when JWT is valid' do
@ -197,36 +152,6 @@ RSpec.describe JiraConnect::EventsController do
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
context 'when jira_connect_asymmetric_jwt is disabled' do
before do
stub_feature_flags(jira_connect_asymmetric_jwt: false)
request.headers['Authorization'] = "JWT #{Atlassian::Jwt.encode({ iss: installation.client_key, qsh: qsh }, installation.shared_secret)}"
end
let(:qsh) { Atlassian::Jwt.create_query_string_hash('https://gitlab.test/events/uninstalled', 'POST', 'https://gitlab.test') }
it 'calls the DestroyService and returns ok in case of success' do
expect_next_instance_of(JiraConnectInstallations::DestroyService, installation, jira_base_path, jira_event_path) do |destroy_service|
expect(destroy_service).to receive(:execute).and_return(true)
end
post_uninstalled
expect(response).to have_gitlab_http_status(:ok)
end
it 'calls the DestroyService and returns unprocessable_entity in case of failure' do
expect_next_instance_of(JiraConnectInstallations::DestroyService, installation, jira_base_path, jira_event_path) do |destroy_service|
expect(destroy_service).to receive(:execute).and_return(false)
end
post_uninstalled
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
end
end
end
end

View File

@ -7,6 +7,7 @@ import { __ } from '~/locale';
import FilteredSearchBarRoot from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue';
import { createStore } from '~/boards/stores';
Vue.use(Vuex);
@ -42,17 +43,13 @@ describe('BoardFilteredSearch', () => {
},
];
const createComponent = ({ initialFilterParams = {} } = {}) => {
store = new Vuex.Store({
actions: {
performSearch: jest.fn(),
},
});
const createComponent = ({ initialFilterParams = {}, props = {} } = {}) => {
store = createStore();
wrapper = shallowMount(BoardFilteredSearch, {
provide: { initialFilterParams, fullPath: '' },
store,
propsData: {
...props,
tokens,
},
});
@ -68,11 +65,7 @@ describe('BoardFilteredSearch', () => {
beforeEach(() => {
createComponent();
jest.spyOn(store, 'dispatch');
});
it('renders FilteredSearch', () => {
expect(findFilteredSearch().exists()).toBe(true);
jest.spyOn(store, 'dispatch').mockImplementation();
});
it('passes the correct tokens to FilteredSearch', () => {
@ -99,6 +92,22 @@ describe('BoardFilteredSearch', () => {
});
});
describe('when eeFilters is not empty', () => {
it('passes the correct initialFilterValue to FitleredSearchBarRoot', () => {
createComponent({ props: { eeFilters: { labelName: ['label'] } } });
expect(findFilteredSearch().props('initialFilterValue')).toEqual([
{ type: 'label_name', value: { data: 'label', operator: '=' } },
]);
});
});
it('renders FilteredSearch', () => {
createComponent();
expect(findFilteredSearch().exists()).toBe(true);
});
describe('when searching', () => {
beforeEach(() => {
createComponent();

View File

@ -6,8 +6,13 @@ import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import Api from '~/api';
import PipelinesTable from '~/commit/pipelines/pipelines_table.vue';
import { TOAST_MESSAGE } from '~/pipelines/constants';
import axios from '~/lib/utils/axios_utils';
const $toast = {
show: jest.fn(),
};
describe('Pipelines table in Commits and Merge requests', () => {
let wrapper;
let pipeline;
@ -30,6 +35,9 @@ describe('Pipelines table in Commits and Merge requests', () => {
errorStateSvgPath: 'foo',
...props,
},
mocks: {
$toast,
},
}),
);
};
@ -178,6 +186,12 @@ describe('Pipelines table in Commits and Merge requests', () => {
await waitForPromises();
});
it('displays a toast message during pipeline creation', async () => {
await findRunPipelineBtn().trigger('click');
expect($toast.show).toHaveBeenCalledWith(TOAST_MESSAGE);
});
it('on desktop, shows a loading button', async () => {
await findRunPipelineBtn().trigger('click');

View File

@ -3,53 +3,29 @@
require 'spec_helper'
RSpec.describe Gitlab::ApplicationRateLimiter do
let(:redis) { double('redis') }
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:rate_limits) do
{
test_action: {
threshold: 1,
interval: 2.minutes
}
}
end
let(:key) { rate_limits.keys[0] }
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
subject { described_class }
before do
allow(Gitlab::Redis::RateLimiting).to receive(:with).and_yield(redis)
allow(described_class).to receive(:rate_limits).and_return(rate_limits)
end
shared_examples 'action rate limiter' do
it 'increases the throttle count and sets the expiration time' do
expect(redis).to receive(:incr).with(cache_key).and_return(1)
expect(redis).to receive(:expire).with(cache_key, 120)
expect(subject.throttled?(key, scope: scope)).to be_falsy
end
it 'returns true if the key is throttled' do
expect(redis).to receive(:incr).with(cache_key).and_return(2)
expect(redis).not_to receive(:expire)
expect(subject.throttled?(key, scope: scope)).to be_truthy
end
context 'when throttling is disabled' do
it 'returns false and does not set expiration time' do
expect(redis).not_to receive(:incr)
expect(redis).not_to receive(:expire)
expect(subject.throttled?(key, scope: scope, threshold: 0)).to be_falsy
end
end
end
describe '.throttled?' do
let(:rate_limits) do
{
test_action: {
threshold: 1,
interval: 2.minutes
},
another_action: {
threshold: 2,
interval: 3.minutes
}
}
end
before do
allow(described_class).to receive(:rate_limits).and_return(rate_limits)
end
context 'when the key is invalid' do
context 'is provided as a Symbol' do
context 'but is not defined in the rate_limits Hash' do
@ -80,27 +56,116 @@ RSpec.describe Gitlab::ApplicationRateLimiter do
end
end
context 'when the key is an array of only ActiveRecord models' do
let(:scope) { [user, project] }
context 'when rate_limiter_safe_increment is disabled' do
let(:redis) { double('redis') }
let(:key) { rate_limits.keys[0] }
let(:cache_key) do
"application_rate_limiter:test_action:user:#{user.id}:project:#{project.id}"
before do
allow(Gitlab::Redis::RateLimiting).to receive(:with).and_yield(redis)
stub_feature_flags(rate_limiter_safe_increment: false)
end
it_behaves_like 'action rate limiter'
shared_examples 'action rate limiter' do
it 'increases the throttle count and sets the expiration time' do
expect(redis).to receive(:incr).with(cache_key).and_return(1)
expect(redis).to receive(:expire).with(cache_key, 120)
expect(subject.throttled?(key, scope: scope)).to be_falsy
end
it 'returns true if the key is throttled' do
expect(redis).to receive(:incr).with(cache_key).and_return(2)
expect(redis).not_to receive(:expire)
expect(subject.throttled?(key, scope: scope)).to be_truthy
end
context 'when throttling is disabled' do
it 'returns false and does not set expiration time' do
expect(redis).not_to receive(:incr)
expect(redis).not_to receive(:expire)
expect(subject.throttled?(key, scope: scope, threshold: 0)).to be_falsy
end
end
end
context 'when the key is an array of only ActiveRecord models' do
let(:scope) { [user, project] }
let(:cache_key) do
"application_rate_limiter:test_action:user:#{user.id}:project:#{project.id}"
end
it_behaves_like 'action rate limiter'
end
context 'when the key is a combination of ActiveRecord models and strings' do
let(:project) { create(:project, :public, :repository) }
let(:commit) { project.repository.commit }
let(:path) { 'app/controllers/groups_controller.rb' }
let(:scope) { [project, commit, path] }
let(:cache_key) do
"application_rate_limiter:test_action:project:#{project.id}:commit:#{commit.sha}:#{path}"
end
it_behaves_like 'action rate limiter'
end
end
context 'when they key a combination of ActiveRecord models and strings' do
let(:project) { create(:project, :public, :repository) }
let(:commit) { project.repository.commit }
let(:path) { 'app/controllers/groups_controller.rb' }
let(:scope) { [project, commit, path] }
let(:cache_key) do
"application_rate_limiter:test_action:project:#{project.id}:commit:#{commit.sha}:#{path}"
context 'when rate_limiter_safe_increment is enabled', :clean_gitlab_redis_rate_limiting do
before do
stub_feature_flags(rate_limiter_safe_increment: true)
end
it_behaves_like 'action rate limiter'
shared_examples 'throttles based on key and scope' do
let(:start_time) { Time.current.beginning_of_hour }
it 'returns true when threshold is exceeded' do
travel_to(start_time) do
expect(subject.throttled?(:test_action, scope: scope)).to eq(false)
end
travel_to(start_time + 1.minute) do
expect(subject.throttled?(:test_action, scope: scope)).to eq(true)
# Assert that it does not affect other actions or scope
expect(subject.throttled?(:another_action, scope: scope)).to eq(false)
expect(subject.throttled?(:test_action, scope: [user])).to eq(false)
end
end
it 'returns false when interval has elapsed' do
travel_to(start_time) do
expect(subject.throttled?(:test_action, scope: scope)).to eq(false)
# another_action has a threshold of 3 so we simulate 2 requests
expect(subject.throttled?(:another_action, scope: scope)).to eq(false)
expect(subject.throttled?(:another_action, scope: scope)).to eq(false)
end
travel_to(start_time + 2.minutes) do
expect(subject.throttled?(:test_action, scope: scope)).to eq(false)
# Assert that another_action has its own interval that hasn't elapsed
expect(subject.throttled?(:another_action, scope: scope)).to eq(true)
end
end
end
context 'when using ActiveRecord models as scope' do
let(:scope) { [user, project] }
it_behaves_like 'throttles based on key and scope'
end
context 'when using ActiveRecord models and strings as scope' do
let(:scope) { [project, 'app/controllers/groups_controller.rb'] }
it_behaves_like 'throttles based on key and scope'
end
end
end
@ -134,7 +199,7 @@ RSpec.describe Gitlab::ApplicationRateLimiter do
end
context 'with a current_user' do
let(:current_user) { create(:user) }
let(:current_user) { user }
let(:attributes) do
base_attributes.merge({

View File

@ -102,6 +102,13 @@ RSpec.describe API::Lint do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to have_key('merged_yaml')
end
it 'outputs jobs' do
post api('/ci/lint', api_user), params: { content: yaml_content, include_jobs: true }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to have_key('jobs')
end
end
context 'with valid .gitlab-ci.yaml with warnings' do
@ -136,6 +143,13 @@ RSpec.describe API::Lint do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to have_key('merged_yaml')
end
it 'outputs jobs' do
post api('/ci/lint', api_user), params: { content: yaml_content, include_jobs: true }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to have_key('jobs')
end
end
context 'with invalid configuration' do
@ -156,6 +170,13 @@ RSpec.describe API::Lint do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to have_key('merged_yaml')
end
it 'outputs jobs' do
post api('/ci/lint', api_user), params: { content: yaml_content, include_jobs: true }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to have_key('jobs')
end
end
end
@ -171,10 +192,11 @@ RSpec.describe API::Lint do
end
describe 'GET /projects/:id/ci/lint' do
subject(:ci_lint) { get api("/projects/#{project.id}/ci/lint", api_user), params: { dry_run: dry_run } }
subject(:ci_lint) { get api("/projects/#{project.id}/ci/lint", api_user), params: { dry_run: dry_run, include_jobs: include_jobs } }
let(:project) { create(:project, :repository) }
let(:dry_run) { nil }
let(:include_jobs) { nil }
RSpec.shared_examples 'valid config with warnings' do
it 'passes validation with warnings' do
@ -359,6 +381,30 @@ RSpec.describe API::Lint do
it_behaves_like 'valid config without warnings'
end
context 'when running with include jobs' do
let(:include_jobs) { true }
it_behaves_like 'valid config without warnings'
it 'returns jobs key' do
ci_lint
expect(json_response).to have_key('jobs')
end
end
context 'when running without include jobs' do
let(:include_jobs) { false }
it_behaves_like 'valid config without warnings'
it 'does not return jobs key' do
ci_lint
expect(json_response).not_to have_key('jobs')
end
end
context 'With warnings' do
let(:yaml_content) { { job: { script: 'ls', rules: [{ when: 'always' }] } }.to_yaml }
@ -386,15 +432,40 @@ RSpec.describe API::Lint do
it_behaves_like 'invalid config'
end
context 'when running with include jobs' do
let(:include_jobs) { true }
it_behaves_like 'invalid config'
it 'returns jobs key' do
ci_lint
expect(json_response).to have_key('jobs')
end
end
context 'when running without include jobs' do
let(:include_jobs) { false }
it_behaves_like 'invalid config'
it 'does not return jobs key' do
ci_lint
expect(json_response).not_to have_key('jobs')
end
end
end
end
end
describe 'POST /projects/:id/ci/lint' do
subject(:ci_lint) { post api("/projects/#{project.id}/ci/lint", api_user), params: { dry_run: dry_run, content: yaml_content } }
subject(:ci_lint) { post api("/projects/#{project.id}/ci/lint", api_user), params: { dry_run: dry_run, content: yaml_content, include_jobs: include_jobs } }
let(:project) { create(:project, :repository) }
let(:dry_run) { nil }
let(:include_jobs) { nil }
let_it_be(:api_user) { create(:user) }
@ -562,6 +633,30 @@ RSpec.describe API::Lint do
it_behaves_like 'valid project config'
end
context 'when running with include jobs param' do
let(:include_jobs) { true }
it_behaves_like 'valid project config'
it 'contains jobs key' do
ci_lint
expect(json_response).to have_key('jobs')
end
end
context 'when running without include jobs param' do
let(:include_jobs) { false }
it_behaves_like 'valid project config'
it 'does not contain jobs key' do
ci_lint
expect(json_response).not_to have_key('jobs')
end
end
end
context 'with invalid .gitlab-ci.yml content' do
@ -580,6 +675,30 @@ RSpec.describe API::Lint do
it_behaves_like 'invalid project config'
end
context 'when running with include jobs set to false' do
let(:include_jobs) { false }
it_behaves_like 'invalid project config'
it 'does not contain jobs key' do
ci_lint
expect(json_response).not_to have_key('jobs')
end
end
context 'when running with param include jobs' do
let(:include_jobs) { true }
it_behaves_like 'invalid project config'
it 'contains jobs key' do
ci_lint
expect(json_response).to have_key('jobs')
end
end
end
end
end