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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-11-03 21:13:40 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-11-03 21:13:40 +0300
commitbbc36645d34c557df40d031a1a41fbd05e491644 (patch)
tree55529c6e93d72f7e35e78488a397f50098f137a5
parent70a50740a20ab0027e0490487f6244f5ec961eee (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/issue_templates/Feature proposal - detailed.md8
-rw-r--r--CHANGELOG.md7
-rw-r--r--app/assets/javascripts/boards/components/board_filtered_search.vue124
-rw-r--r--app/assets/javascripts/pipelines/constants.js2
-rw-r--r--app/assets/javascripts/pipelines/mixins/pipelines_mixin.js7
-rw-r--r--app/controllers/jira_connect/app_descriptor_controller.rb2
-rw-r--r--app/controllers/jira_connect/application_controller.rb4
-rw-r--r--app/controllers/jira_connect/events_controller.rb7
-rw-r--r--config/feature_flags/development/rate_limiter_safe_increment.yml (renamed from config/feature_flags/development/jira_connect_asymmetric_jwt.yml)12
-rw-r--r--config/metrics/counts_28d/20210216184822_i_package_generic_deploy_token_monthly.yml3
-rw-r--r--config/metrics/counts_28d/20210216184910_i_package_generic_user_monthly.yml3
-rw-r--r--config/metrics/counts_7d/20210216184908_i_package_generic_user_weekly.yml3
-rw-r--r--doc/api/lint.md39
-rw-r--r--doc/development/service_ping/index.md2
-rw-r--r--doc/user/admin_area/settings/index.md288
-rw-r--r--doc/user/project/integrations/microsoft_teams.md19
-rw-r--r--doc/user/project/repository/vscode.md4
-rw-r--r--lib/api/entities/ci/lint/result.rb1
-rw-r--r--lib/api/lint.rb9
-rw-r--r--lib/gitlab/application_rate_limiter.rb36
-rw-r--r--locale/gitlab.pot42
-rw-r--r--spec/controllers/jira_connect/app_descriptor_controller_spec.rb12
-rw-r--r--spec/controllers/jira_connect/events_controller_spec.rb75
-rw-r--r--spec/frontend/boards/components/board_filtered_search_spec.js33
-rw-r--r--spec/frontend/commit/pipelines/pipelines_table_spec.js14
-rw-r--r--spec/lib/gitlab/application_rate_limiter_spec.rb173
-rw-r--r--spec/requests/api/lint_spec.rb123
27 files changed, 666 insertions, 386 deletions
diff --git a/.gitlab/issue_templates/Feature proposal - detailed.md b/.gitlab/issue_templates/Feature proposal - detailed.md
index 6448553d1b0..c787fc99333 100644
--- a/.gitlab/issue_templates/Feature proposal - detailed.md
+++ b/.gitlab/issue_templates/Feature proposal - detailed.md
@@ -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?
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 83934210e78..fd895fc2220 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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.
diff --git a/app/assets/javascripts/boards/components/board_filtered_search.vue b/app/assets/javascripts/boards/components/board_filtered_search.vue
index 6352228b057..86f512a5117 100644
--- a/app/assets/javascripts/boards/components/board_filtered_search.vue
+++ b/app/assets/javascripts/boards/components/board_filtered_search.vue
@@ -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>
diff --git a/app/assets/javascripts/pipelines/constants.js b/app/assets/javascripts/pipelines/constants.js
index 5678b613ec6..d123f7a203c 100644
--- a/app/assets/javascripts/pipelines/constants.js
+++ b/app/assets/javascripts/pipelines/constants.js
@@ -49,3 +49,5 @@ export const PipelineKeyOptions = [
key: 'iid',
},
];
+
+export const TOAST_MESSAGE = s__('Pipeline|Creating pipeline.');
diff --git a/app/assets/javascripts/pipelines/mixins/pipelines_mixin.js b/app/assets/javascripts/pipelines/mixins/pipelines_mixin.js
index 082d67c938c..3201f88a9e3 100644
--- a/app/assets/javascripts/pipelines/mixins/pipelines_mixin.js
+++ b/app/assets/javascripts/pipelines/mixins/pipelines_mixin.js
@@ -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: __(
diff --git a/app/controllers/jira_connect/app_descriptor_controller.rb b/app/controllers/jira_connect/app_descriptor_controller.rb
index e96242c7052..16bd73f5ab6 100644
--- a/app/controllers/jira_connect/app_descriptor_controller.rb
+++ b/app/controllers/jira_connect/app_descriptor_controller.rb
@@ -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
}
}
diff --git a/app/controllers/jira_connect/application_controller.rb b/app/controllers/jira_connect/application_controller.rb
index 1d1575f3a05..352e78d6255 100644
--- a/app/controllers/jira_connect/application_controller.rb
+++ b/app/controllers/jira_connect/application_controller.rb
@@ -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
diff --git a/app/controllers/jira_connect/events_controller.rb b/app/controllers/jira_connect/events_controller.rb
index 76ac15f7631..1ea0a92662b 100644
--- a/app/controllers/jira_connect/events_controller.rb
+++ b/app/controllers/jira_connect/events_controller.rb
@@ -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)
diff --git a/config/feature_flags/development/jira_connect_asymmetric_jwt.yml b/config/feature_flags/development/rate_limiter_safe_increment.yml
index 48684e80d0c..16e8f2fe7c7 100644
--- a/config/feature_flags/development/jira_connect_asymmetric_jwt.yml
+++ b/config/feature_flags/development/rate_limiter_safe_increment.yml
@@ -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
diff --git a/config/metrics/counts_28d/20210216184822_i_package_generic_deploy_token_monthly.yml b/config/metrics/counts_28d/20210216184822_i_package_generic_deploy_token_monthly.yml
index 84da476edb5..a09e973206d 100644
--- a/config/metrics/counts_28d/20210216184822_i_package_generic_deploy_token_monthly.yml
+++ b/config/metrics/counts_28d/20210216184822_i_package_generic_deploy_token_monthly.yml
@@ -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
diff --git a/config/metrics/counts_28d/20210216184910_i_package_generic_user_monthly.yml b/config/metrics/counts_28d/20210216184910_i_package_generic_user_monthly.yml
index f028719bfe1..93f551178c3 100644
--- a/config/metrics/counts_28d/20210216184910_i_package_generic_user_monthly.yml
+++ b/config/metrics/counts_28d/20210216184910_i_package_generic_user_monthly.yml
@@ -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
diff --git a/config/metrics/counts_7d/20210216184908_i_package_generic_user_weekly.yml b/config/metrics/counts_7d/20210216184908_i_package_generic_user_weekly.yml
index 63278bcfbd8..d529d1c2f38 100644
--- a/config/metrics/counts_7d/20210216184908_i_package_generic_user_weekly.yml
+++ b/config/metrics/counts_7d/20210216184908_i_package_generic_user_weekly.yml
@@ -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
diff --git a/doc/api/lint.md b/doc/api/lint.md
index 9f95b9a94ae..e5b5e0e2be8 100644
--- a/doc/api/lint.md
+++ b/doc/api/lint.md
@@ -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:
diff --git a/doc/development/service_ping/index.md b/doc/development/service_ping/index.md
index cd702720319..152eec87d5d 100644
--- a/doc/development/service_ping/index.md
+++ b/doc/development/service_ping/index.md
@@ -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?
diff --git a/doc/user/admin_area/settings/index.md b/doc/user/admin_area/settings/index.md
index 5b78eecad5d..7945e5d790f 100644
--- a/doc/user/admin_area/settings/index.md
+++ b/doc/user/admin_area/settings/index.md
@@ -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**.
-
-| 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. |
-
-## Integrations
-
-| 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. |
-
-## Repository
-
-| 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). |
-
-## Templates **(PREMIUM SELF)**
-
-| 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. |
-
-## CI/CD
-
-| 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. |
-
-## Reporting
-
-| 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. |
-
-## Metrics and profiling
-
-| 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. |
-
-## Network
-
-| 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. |
-
-## Geo **(PREMIUM SELF)**
-
-| 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). |
-
-## Preferences
-
-| 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. |
-
-### Default first day of the week
+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)
+
+### General
+
+The **General** settings contain:
+
+- [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.
+
+### CI/CD
+
+The **CI/CD** settings contain:
+
+- [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.
+
+### Geo **(PREMIUM SELF)**
+
+The **Geo** setting contains:
+
+- [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).
+
+### Integrations
+
+The **Integrations** settings contain:
+
+- [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.
+
+### Metrics and profiling
+
+The **Metrics and profiling** settings contain:
+
+- [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.
+
+### Network
+
+The **Network** settings contain:
+
+- 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.
+
+### Preferences
+
+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:
diff --git a/doc/user/project/integrations/microsoft_teams.md b/doc/user/project/integrations/microsoft_teams.md
index 07a4307da43..6679bab745b 100644
--- a/doc/user/project/integrations/microsoft_teams.md
+++ b/doc/user/project/integrations/microsoft_teams.md
@@ -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**.
diff --git a/doc/user/project/repository/vscode.md b/doc/user/project/repository/vscode.md
index c021d999588..bbf14a71653 100644
--- a/doc/user/project/repository/vscode.md
+++ b/doc/user/project/repository/vscode.md
@@ -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:
diff --git a/lib/api/entities/ci/lint/result.rb b/lib/api/entities/ci/lint/result.rb
index 0e4aa238ba2..39039868bba 100644
--- a/lib/api/entities/ci/lint/result.rb
+++ b/lib/api/entities/ci/lint/result.rb
@@ -9,6 +9,7 @@ module API
expose :errors
expose :warnings
expose :merged_yaml
+ expose :jobs, if: -> (result, options) { options[:include_jobs] }
end
end
end
diff --git a/lib/api/lint.rb b/lib/api/lint.rb
index fa871b4bc57..f1e19e9c3c5 100644
--- a/lib/api/lint.rb
+++ b/lib/api/lint.rb
@@ -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
diff --git a/lib/gitlab/application_rate_limiter.rb b/lib/gitlab/application_rate_limiter.rb
index c17c452056a..ef8fd9504f7 100644
--- a/lib/gitlab/application_rate_limiter.rb
+++ b/lib/gitlab/application_rate_limiter.rb
@@ -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
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index bcb066ea996..766114b5255 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -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 ""
diff --git a/spec/controllers/jira_connect/app_descriptor_controller_spec.rb b/spec/controllers/jira_connect/app_descriptor_controller_spec.rb
index 9d890efdd33..4f8b2b90637 100644
--- a/spec/controllers/jira_connect/app_descriptor_controller_spec.rb
+++ b/spec/controllers/jira_connect/app_descriptor_controller_spec.rb
@@ -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
diff --git a/spec/controllers/jira_connect/events_controller_spec.rb b/spec/controllers/jira_connect/events_controller_spec.rb
index 78bd0dc8318..2a70a2ea683 100644
--- a/spec/controllers/jira_connect/events_controller_spec.rb
+++ b/spec/controllers/jira_connect/events_controller_spec.rb
@@ -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
diff --git a/spec/frontend/boards/components/board_filtered_search_spec.js b/spec/frontend/boards/components/board_filtered_search_spec.js
index dc93890f27a..b858d6e95a0 100644
--- a/spec/frontend/boards/components/board_filtered_search_spec.js
+++ b/spec/frontend/boards/components/board_filtered_search_spec.js
@@ -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();
diff --git a/spec/frontend/commit/pipelines/pipelines_table_spec.js b/spec/frontend/commit/pipelines/pipelines_table_spec.js
index 17f7be9d1d7..51f5538b2a0 100644
--- a/spec/frontend/commit/pipelines/pipelines_table_spec.js
+++ b/spec/frontend/commit/pipelines/pipelines_table_spec.js
@@ -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');
diff --git a/spec/lib/gitlab/application_rate_limiter_spec.rb b/spec/lib/gitlab/application_rate_limiter_spec.rb
index e13475d1108..ab6ac024af7 100644
--- a/spec/lib/gitlab/application_rate_limiter_spec.rb
+++ b/spec/lib/gitlab/application_rate_limiter_spec.rb
@@ -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
+ describe '.throttled?' do
+ let(:rate_limits) do
+ {
+ test_action: {
+ threshold: 1,
+ interval: 2.minutes
+ },
+ another_action: {
+ threshold: 2,
+ interval: 3.minutes
+ }
+ }
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
+ before do
+ allow(described_class).to receive(:rate_limits).and_return(rate_limits)
end
- end
- describe '.throttled?' do
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] }
+
+ before do
+ allow(Gitlab::Redis::RateLimiting).to receive(:with).and_yield(redis)
+
+ stub_feature_flags(rate_limiter_safe_increment: false)
+ 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
+
+ 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}"
+ let(:cache_key) do
+ "application_rate_limiter:test_action:user:#{user.id}:project:#{project.id}"
+ end
+
+ it_behaves_like 'action rate limiter'
end
- it_behaves_like 'action rate limiter'
+ 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] }
+ 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
+
+ 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)
- let(:cache_key) do
- "application_rate_limiter:test_action:project:#{project.id}:commit:#{commit.sha}:#{path}"
+ # 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
- it_behaves_like 'action rate limiter'
+ 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({
diff --git a/spec/requests/api/lint_spec.rb b/spec/requests/api/lint_spec.rb
index d7f22b9d619..ac30da99afe 100644
--- a/spec/requests/api/lint_spec.rb
+++ b/spec/requests/api/lint_spec.rb
@@ -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