diff options
55 files changed, 452 insertions, 316 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 40f554db58e..fc9822ad023 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -448304d500ab91dca193a21094319d38e22f60a7 +6bb5f6969910ce5010f1c894ee671a86e656e6da diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json index 846475bc1a2..6c805f7b4ea 100644 --- a/app/assets/javascripts/editor/schema/ci.json +++ b/app/assets/javascripts/editor/schema/ci.json @@ -292,7 +292,7 @@ "project": { "description": "Path to the project, e.g. `group/project`, or `group/sub-group/project`.", "type": "string", - "pattern": "\\S/\\S" + "pattern": "\\S/\\S|\\$(\\S+)" }, "ref": { "description": "Branch/Tag/Commit-hash for the target project.", diff --git a/app/assets/javascripts/filtered_search/add_extra_tokens_for_merge_requests.js b/app/assets/javascripts/filtered_search/add_extra_tokens_for_merge_requests.js index d00e6e59cf5..d9c627f5c93 100644 --- a/app/assets/javascripts/filtered_search/add_extra_tokens_for_merge_requests.js +++ b/app/assets/javascripts/filtered_search/add_extra_tokens_for_merge_requests.js @@ -1,8 +1,8 @@ -import { __ } from '~/locale'; +import { __, s__ } from '~/locale'; export default (IssuableTokenKeys, disableTargetBranchFilter = false) => { const reviewerToken = { - formattedKey: __('Reviewer'), + formattedKey: s__('SearchToken|Reviewer'), key: 'reviewer', type: 'string', param: 'username', diff --git a/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js b/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js index 2c58506985a..acb7449f830 100644 --- a/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js +++ b/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js @@ -1,5 +1,5 @@ import { flattenDeep } from 'lodash'; -import { __ } from '~/locale'; +import { __, s__ } from '~/locale'; import FilteredSearchTokenKeys from './filtered_search_token_keys'; export const tokenKeys = [ @@ -13,7 +13,7 @@ export const tokenKeys = [ tag: '@author', }, { - formattedKey: __('Assignee'), + formattedKey: s__('SearchToken|Assignee'), key: 'assignee', type: 'string', param: 'username', diff --git a/app/assets/javascripts/pages/projects/ci/secure_files/show/index.js b/app/assets/javascripts/pages/projects/ci/secure_files/show/index.js deleted file mode 100644 index 61486606665..00000000000 --- a/app/assets/javascripts/pages/projects/ci/secure_files/show/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import { initCiSecureFiles } from '~/ci_secure_files'; - -initCiSecureFiles(); diff --git a/app/assets/javascripts/vue_merge_request_widget/components/widget/app.vue b/app/assets/javascripts/vue_merge_request_widget/components/widget/app.vue new file mode 100644 index 00000000000..f1c1bde256f --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/components/widget/app.vue @@ -0,0 +1,27 @@ +<script> +export default { + props: { + mr: { + type: Object, + required: true, + }, + }, + computed: { + widgets() { + return [].filter((w) => w); + }, + }, +}; +</script> + +<template> + <section role="region" :aria-label="__('Merge request reports')" data-testid="mr-widget-app"> + <component + :is="widget" + v-for="(widget, index) in widgets" + :key="widget.name || index" + :mr="mr" + :class="{ 'mr-widget-border-top': index === 0 }" + /> + </section> +</template> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue new file mode 100644 index 00000000000..3af4023d8e4 --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue @@ -0,0 +1,148 @@ +<script> +import * as Sentry from '@sentry/browser'; +import { normalizeHeaders } from '~/lib/utils/common_utils'; +import { __ } from '~/locale'; +import Poll from '~/lib/utils/poll'; + +const FETCH_TYPE_COLLAPSED = 'collapsed'; +// const FETCH_TYPE_EXPANDED = 'expanded'; + +export default { + props: { + /** + * @param {value.collapsed} Object + * @param {value.extended} Object + */ + value: { + type: Object, + required: true, + }, + loadingText: { + type: String, + required: true, + }, + errorText: { + type: String, + required: false, + default: __('Failed to load'), + }, + fetchCollapsedData: { + type: Function, + required: true, + }, + fetchExtendedData: { + type: Function, + required: false, + default: undefined, + }, + // If the summary slot is not used, this value will be used as a fallback. + summary: { + type: String, + required: false, + default: undefined, + }, + // If the content slot is not used, this value will be used as a fallback. + content: { + type: Object, + required: false, + default: undefined, + }, + multiPolling: { + type: Boolean, + required: false, + default: false, + }, + }, + data() { + return { + loading: false, + statusIcon: null, + error: null, + }; + }, + async mounted() { + this.loading = true; + + try { + await this.fetch(this.fetchCollapsedData, FETCH_TYPE_COLLAPSED); + } catch { + this.error = this.errorText; + } + + this.loading = false; + }, + methods: { + fetch(handler, dataType) { + const requests = this.multiPolling ? handler() : [handler]; + const allData = []; + + const promises = requests.map((request) => { + return new Promise((resolve, reject) => { + const setData = (data) => { + this.$emit('input', { ...this.value, [dataType]: data }); + resolve(data); + }; + + const poll = new Poll({ + resource: { + fetchData: () => request(), + }, + method: 'fetchData', + successCallback: (response) => { + const headers = normalizeHeaders(response.headers); + + if (headers['POLL-INTERVAL']) { + return; + } + + if (this.multiPolling) { + allData.push(response.data); + + if (allData.length === requests.length) { + setData(allData); + } + + return; + } + + setData(response.data); + }, + errorCallback: (e) => { + Sentry.captureException(e); + reject(e); + }, + }); + + poll.makeRequest(); + }); + }); + + return Promise.all(promises); + }, + }, +}; +</script> + +<template> + <section class="media-section" data-testid="widget-extension"> + <div class="media gl-p-5"> + <!-- status icon will go here --> + <div + class="media-body gl-display-flex gl-flex-direction-row! gl-align-self-center" + data-testid="widget-extension-top-level" + > + <div class="gl-flex-grow-1" data-testid="widget-extension-top-level-summary"> + <slot name="summary">{{ summary }}</slot> + </div> + <!-- actions will go here --> + <!-- toggle button will go here --> + </div> + </div> + <div + class="mr-widget-grouped-section gl-relative" + data-testid="widget-extension-collapsed-section" + > + <slot name="content">{{ content }}</slot> + </div> + </section> +</template> diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue index 0edd44d835e..1e25143e15c 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue +++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue @@ -1,7 +1,6 @@ <script> import { GlSafeHtmlDirective } from '@gitlab/ui'; import { isEmpty } from 'lodash'; -import securityReportExtension from 'ee_else_ce/vue_merge_request_widget/extensions/security_reports'; import { registerExtension } from '~/vue_merge_request_widget/components/extensions'; import MrWidgetApprovals from 'ee_else_ce/vue_merge_request_widget/components/approvals/approvals.vue'; import MRWidgetService from 'ee_else_ce/vue_merge_request_widget/services/mr_widget_service'; @@ -39,6 +38,7 @@ import ShaMismatch from './components/states/sha_mismatch.vue'; import UnresolvedDiscussionsState from './components/states/unresolved_discussions.vue'; import WorkInProgressState from './components/states/work_in_progress.vue'; import ExtensionsContainer from './components/extensions/container'; +import WidgetContainer from './components/widget/app.vue'; import { STATE_MACHINE, stateToComponentMap } from './constants'; import eventHub from './event_hub'; import mergeRequestQueryVariablesMixin from './mixins/merge_request_query_variables'; @@ -58,6 +58,7 @@ export default { components: { Loading, ExtensionsContainer, + WidgetContainer, 'mr-widget-suggest-pipeline': WidgetSuggestPipeline, MrWidgetPipelineContainer, MrWidgetAlertMessage, @@ -262,11 +263,6 @@ export default { this.registerTestReportExtension(); } }, - shouldRenderSecurityReport(newVal) { - if (newVal) { - this.registerSecurityReportExtension(); - } - }, }, mounted() { MRWidgetService.fetchInitialData() @@ -522,11 +518,6 @@ export default { registerExtension(testReportExtension); } }, - registerSecurityReportExtension() { - if (this.shouldRenderSecurityReport && this.shouldShowSecurityExtension) { - registerExtension(securityReportExtension); - } - }, }, }; </script> @@ -587,7 +578,11 @@ export default { </template> </mr-widget-alert-message> </div> + <extensions-container :mr="mr" /> + + <widget-container v-if="mr" :mr="mr" /> + <grouped-codequality-reports-app v-if="shouldRenderCodeQuality && !shouldShowCodeQualityExtension" :head-blob-path="mr.headBlobPath" diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js index 03c9a01cc7a..146cf7e11a7 100644 --- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js +++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js @@ -33,7 +33,6 @@ export default class MergeRequestStore { this.setData(data); this.initCodeQualityReport(data); - this.initSecurityReport(data); this.setGitpodData(data); } @@ -42,19 +41,6 @@ export default class MergeRequestStore { this.codeQuality = data.codequality_reports_path; } - initSecurityReport(data) { - // TODO: check if gl.mrWidgetData can be safely removed after we migrate to the - // widget extension. - this.securityReportPaths = { - apiFuzzingReportPath: data.api_fuzzing_comparison_path, - coverageFuzzingReportPath: data.coverage_fuzzing_comparison_path, - sastReportPath: data.sast_comparison_path, - dastReportPath: data.dast_comparison_path, - secretDetectionReportPath: data.secret_detection_comparison_path, - dependencyScanningReportPath: data.dependency_scanning_comparison_path, - }; - } - setData(data, isRebased) { this.initApprovals(); diff --git a/app/controllers/projects/ci/secure_files_controller.rb b/app/controllers/projects/ci/secure_files_controller.rb deleted file mode 100644 index 59ddca19081..00000000000 --- a/app/controllers/projects/ci/secure_files_controller.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -class Projects::Ci::SecureFilesController < Projects::ApplicationController - before_action :authorize_read_secure_files! - - feature_category :pipeline_authoring - - def show - render_404 unless Feature.enabled?(:ci_secure_files, project) - end -end diff --git a/app/graphql/mutations/ci/runner/bulk_delete.rb b/app/graphql/mutations/ci/runner/bulk_delete.rb index 09aeee37317..4c1c2967799 100644 --- a/app/graphql/mutations/ci/runner/bulk_delete.rb +++ b/app/graphql/mutations/ci/runner/bulk_delete.rb @@ -31,7 +31,7 @@ module Mutations runners = find_all_runners_by_ids(model_ids_of(ids)) result = ::Ci::Runners::BulkDeleteRunnersService.new(runners: runners).execute - result.slice(:deleted_count, :deleted_ids).merge(errors: []) + result.payload.slice(:deleted_count, :deleted_ids).merge(errors: []) else { errors: [] } end diff --git a/app/services/ci/runners/bulk_delete_runners_service.rb b/app/services/ci/runners/bulk_delete_runners_service.rb index 7af8994c83d..ce07aa541c2 100644 --- a/app/services/ci/runners/bulk_delete_runners_service.rb +++ b/app/services/ci/runners/bulk_delete_runners_service.rb @@ -15,10 +15,10 @@ module Ci def execute if @runners # Delete a few runners immediately - return delete_runners + return ServiceResponse.success(payload: delete_runners) end - { deleted_count: 0, deleted_ids: [] } + ServiceResponse.success(payload: { deleted_count: 0, deleted_ids: [] }) end private diff --git a/app/views/projects/ci/secure_files/show.html.haml b/app/views/projects/ci/secure_files/show.html.haml deleted file mode 100644 index 1a87ccd753c..00000000000 --- a/app/views/projects/ci/secure_files/show.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -- page_title s_('Secure Files') - -#js-ci-secure-files{ data: { project_id: @project.id, admin: can?(current_user, :admin_secure_files, @project).to_s, file_size_limit: Ci::SecureFile::FILE_SIZE_LIMIT.to_mb } } diff --git a/config/feature_flags/development/highlight_diffs_optimize_memory_usage.yml b/config/feature_flags/development/highlight_diffs_optimize_memory_usage.yml deleted file mode 100644 index fb480d2fc93..00000000000 --- a/config/feature_flags/development/highlight_diffs_optimize_memory_usage.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: highlight_diffs_optimize_memory_usage -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92456 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/367890 -milestone: '15.3' -type: development -group: group::source code -default_enabled: false diff --git a/config/routes/project.rb b/config/routes/project.rb index 628fa3ad37b..d22029b6055 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -96,7 +96,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do namespace :ci do resource :lint, only: [:show, :create] resource :pipeline_editor, only: [:show], controller: :pipeline_editor, path: 'editor' - resource :secure_files, only: [:show], controller: :secure_files, path: 'secure_files' resources :daily_build_group_report_results, only: [:index], constraints: { format: /(csv|json)/ } namespace :prometheus_metrics do resources :histograms, only: [:create], constraints: { format: 'json' } diff --git a/doc/.vale/gitlab/HeadingDepth.yml b/doc/.vale/gitlab/HeadingDepth.yml new file mode 100644 index 00000000000..d96d59b0e35 --- /dev/null +++ b/doc/.vale/gitlab/HeadingDepth.yml @@ -0,0 +1,13 @@ +--- +# Error: gitlab.HeadingDepth +# +# Checks that there are no headings greater than 3 levels +# +# For a list of all options, see https://vale.sh/docs/topics/styles/ +extends: existence +message: 'The subheading "%s" is nested too deeply. Headings deeper than H5 suggest the section or page should be refactored.' +link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#headings-in-markdown +level: warning +scope: raw +raw: + - '(?<=\n)#{5,}\s.*' diff --git a/doc/administration/packages/container_registry.md b/doc/administration/packages/container_registry.md index cc3d3abe2cf..8b115ca1af4 100644 --- a/doc/administration/packages/container_registry.md +++ b/doc/administration/packages/container_registry.md @@ -1202,8 +1202,8 @@ Before diving in to the following sections, here's some basic troubleshooting: been synchronized (for example, via NTP). 1. If you are using an S3-backed Registry, double check that the IAM - permissions and the S3 credentials (including region) are correct. See [the - sample IAM policy](https://docs.docker.com/registry/storage-drivers/s3/) + permissions and the S3 credentials (including region) are correct. See + [the sample IAM policy](https://docs.docker.com/registry/storage-drivers/s3/) for more details. 1. Check the Registry logs (for example `/var/log/gitlab/registry/current`) and the GitLab production logs @@ -1631,8 +1631,8 @@ wrong. However, since all communications between Docker clients and servers are done over HTTPS, it's a bit difficult to decrypt the traffic quickly even if you know the private key. What can we do instead? -One way would be to disable HTTPS by setting up an [insecure -Registry](https://docs.docker.com/registry/insecure/). This could introduce a +One way would be to disable HTTPS by setting up an +[insecure Registry](https://docs.docker.com/registry/insecure/). This could introduce a security hole and is only recommended for local testing. If you have a production system and can't or don't want to do this, there is another way: use mitmproxy, which stands for Man-in-the-Middle Proxy. diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md index a1c5a232067..4d92a3a45c7 100644 --- a/doc/administration/pages/index.md +++ b/doc/administration/pages/index.md @@ -933,8 +933,8 @@ The following settings are: | `connection` | Various connection options described below. | | NOTE: -If you want to stop using and disconnect the NFS server, you need to [explicitly disable -local storage](#disable-pages-local-storage), and it's only possible after upgrading to GitLab 13.11. +If you want to stop using and disconnect the NFS server, you need to +[explicitly disable local storage](#disable-pages-local-storage), and it's only possible after upgrading to GitLab 13.11. #### S3-compatible connection settings diff --git a/doc/api/jobs.md b/doc/api/jobs.md index f399f581c40..647f8eafa62 100644 --- a/doc/api/jobs.md +++ b/doc/api/jobs.md @@ -19,7 +19,7 @@ GET /projects/:id/jobs | Attribute | Type | Required | Description | |-----------|--------------------------------|------------------------|-------------| | `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. | -| `scope` | string **or** array of strings | **{dotted-circle}** No | Scope of jobs to show. Either one of or an array of the following: `created`, `pending`, `running`, `failed`, `success`, `canceled`, `skipped`, or `manual`. All jobs are returned if `scope` is not provided. | +| `scope` | string **or** array of strings | **{dotted-circle}** No | Scope of jobs to show. Either one of or an array of the following: `created`, `pending`, `running`, `failed`, `success`, `canceled`, `skipped`, `waiting_for_resource`, or `manual`. All jobs are returned if `scope` is not provided. | ```shell curl --globoff --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs?scope[]=pending&scope[]=running" @@ -167,7 +167,7 @@ GET /projects/:id/pipelines/:pipeline_id/jobs |-------------------|--------------------------------|------------------------|-------------| | `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. | | `pipeline_id` | integer | **{check-circle}** Yes | ID of a pipeline. Can also be obtained in CI jobs via the [predefined CI variable](../ci/variables/predefined_variables.md) `CI_PIPELINE_ID`. | -| `scope` | string **or** array of strings | **{dotted-circle}** No | Scope of jobs to show. Either one of or an array of the following: `created`, `pending`, `running`, `failed`, `success`, `canceled`, `skipped`, or `manual`. All jobs are returned if `scope` is not provided. | +| `scope` | string **or** array of strings | **{dotted-circle}** No | Scope of jobs to show. Either one of or an array of the following: `created`, `pending`, `running`, `failed`, `success`, `canceled`, `skipped`, `waiting_for_resource`, or `manual`. All jobs are returned if `scope` is not provided. | | `include_retried` | boolean | **{dotted-circle}** No | Include retried jobs in the response. Defaults to `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/272627) in GitLab 13.9. | ```shell @@ -324,7 +324,7 @@ GET /projects/:id/pipelines/:pipeline_id/bridges |---------------|--------------------------------|------------------------|-------------| | `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. | | `pipeline_id` | integer | **{check-circle}** Yes | ID of a pipeline. | -| `scope` | string **or** array of strings | **{dotted-circle}** No | Scope of jobs to show. Either one of or an array of the following: `created`, `pending`, `running`, `failed`, `success`, `canceled`, `skipped`, or `manual`. All jobs are returned if `scope` is not provided. | +| `scope` | string **or** array of strings | **{dotted-circle}** No | Scope of jobs to show. Either one of or an array of the following: `created`, `pending`, `running`, `failed`, `success`, `canceled`, `skipped`, `waiting_for_resource`, or `manual`. All jobs are returned if `scope` is not provided. | ```shell curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/pipelines/6/bridges?scope[]=pending&scope[]=running" diff --git a/doc/api/notes.md b/doc/api/notes.md index f7caae59b4d..759bef8fea2 100644 --- a/doc/api/notes.md +++ b/doc/api/notes.md @@ -11,7 +11,7 @@ Notes are comments on: - Snippets - Issues - Merge requests -- Epics **(PREMIUM)** +- [Epics](../user/group/epics/index.md) This includes system notes, which are notes about changes to the object (for example, when an assignee changes, GitLab posts a system note). @@ -447,7 +447,7 @@ Parameters: curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/merge_requests/7/notes/1602" ``` -## Epics **(ULTIMATE)** +## Epics **(PREMIUM)** ### List all epic notes diff --git a/doc/api/packages/conan.md b/doc/api/packages/conan.md index 1590893d006..3ac2eeb40b1 100644 --- a/doc/api/packages/conan.md +++ b/doc/api/packages/conan.md @@ -38,8 +38,8 @@ The examples in this document all use the instance-level prefix. /packages/conan/v1 ``` -When using the instance-level routes, be aware that there is a [naming -restriction](../../user/packages/conan_repository/index.md#package-recipe-naming-convention-for-instance-remotes) +When using the instance-level routes, be aware that there is a +[naming restriction](../../user/packages/conan_repository/index.md#package-recipe-naming-convention-for-instance-remotes) for Conan recipes. ### Project-level diff --git a/doc/api/repositories.md b/doc/api/repositories.md index ce9781241ed..bf2ead43519 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -342,9 +342,8 @@ tags using these formats: - `vX.Y.Z` - `X.Y.Z` -Where `X.Y.Z` is a version that follows [semantic -versioning](https://semver.org/). For example, consider a project with the -following tags: +Where `X.Y.Z` is a version that follows [semantic versioning](https://semver.org/). +For example, consider a project with the following tags: - v1.0.0-pre1 - v1.0.0 diff --git a/doc/api/wikis.md b/doc/api/wikis.md index ebdaa700aa7..68db784e8f4 100644 --- a/doc/api/wikis.md +++ b/doc/api/wikis.md @@ -32,6 +32,8 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a Example response: +<!-- vale gitlab.MultiLineLinks = NO --> + ```json [ { @@ -57,6 +59,8 @@ Example response: ] ``` +<!-- vale gitlab.MultiLineLinks = YES --> + ## Get a wiki page Get a wiki page for a given project. diff --git a/doc/development/code_intelligence/index.md b/doc/development/code_intelligence/index.md index 3a8845084c3..a89730383e4 100644 --- a/doc/development/code_intelligence/index.md +++ b/doc/development/code_intelligence/index.md @@ -35,8 +35,8 @@ sequenceDiagram Workhorse-->>-Runner: request results ``` -1. The CI/CD job generates a document in an LSIF format (usually `dump.lsif`) using [an - indexer](https://lsif.dev) for the language of a project. The format +1. The CI/CD job generates a document in an LSIF format (usually `dump.lsif`) using + [an indexer](https://lsif.dev) for the language of a project. The format [describes](https://github.com/sourcegraph/sourcegraph/blob/main/doc/code_intelligence/explanations/writing_an_indexer.md) interactions between a method or function and its definitions or references. The document is marked to be stored as an LSIF report artifact. diff --git a/doc/development/database/client_side_connection_pool.md b/doc/development/database/client_side_connection_pool.md index dc52a551407..3cd0e836a8d 100644 --- a/doc/development/database/client_side_connection_pool.md +++ b/doc/development/database/client_side_connection_pool.md @@ -10,8 +10,8 @@ Ruby processes accessing the database through ActiveRecord, automatically calculate the connection-pool size for the process based on the concurrency. -Because of the way [Ruby on Rails manages database -connections](#connection-lifecycle), it is important that we have at +Because of the way [Ruby on Rails manages database connections](#connection-lifecycle), +it is important that we have at least as many connections as we have threads. While there is a 'pool' setting in [`database.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/database.yml.postgresql), it is not very practical because you need to maintain it in tandem with the number of application threads. For this @@ -28,9 +28,8 @@ because connections are instantiated lazily. ## Troubleshooting connection-pool issues -The connection-pool usage can be seen per environment in the [connection-pool -saturation -dashboard](https://dashboards.gitlab.net/d/alerts-sat_rails_db_connection_pool/alerts-rails_db_connection_pool-saturation-detail?orgId=1). +The connection-pool usage can be seen per environment in the +[connection-pool saturation dashboard](https://dashboards.gitlab.net/d/alerts-sat_rails_db_connection_pool/alerts-rails_db_connection_pool-saturation-detail?orgId=1). If the connection-pool is too small, this would manifest in `ActiveRecord::ConnectionTimeoutError`s from the application. Because we alert @@ -41,8 +40,8 @@ hardcoded value (10). At this point, we need to investigate what is using more connections than we anticipated. To do that, we can use the -`gitlab_ruby_threads_running_threads` metric. For example, [this -graph](https://thanos.gitlab.net/graph?g0.range_input=1h&g0.max_source_resolution=0s&g0.expr=sum%20by%20(thread_name)%20(%20gitlab_ruby_threads_running_threads%7Buses_db_connection%3D%22yes%22%7D%20)&g0.tab=0) +`gitlab_ruby_threads_running_threads` metric. For example, +[this graph](https://thanos.gitlab.net/graph?g0.range_input=1h&g0.max_source_resolution=0s&g0.expr=sum%20by%20(thread_name)%20(%20gitlab_ruby_threads_running_threads%7Buses_db_connection%3D%22yes%22%7D%20)&g0.tab=0) shows all running threads that connect to the database by their name. Threads labeled `puma worker` or `sidekiq_worker_thread` are the threads that define `Gitlab::Runtime.max_threads` so those are diff --git a/doc/development/database/loose_foreign_keys.md b/doc/development/database/loose_foreign_keys.md index e28237ca5fc..8dbccf048d7 100644 --- a/doc/development/database/loose_foreign_keys.md +++ b/doc/development/database/loose_foreign_keys.md @@ -221,8 +221,8 @@ ON DELETE CASCADE; ``` The migration must run after the `DELETE` trigger is installed and the loose -foreign key definition is deployed. As such, it must be a [post-deployment -migration](post_deployment_migrations.md) dated after the migration for the +foreign key definition is deployed. As such, it must be a +[post-deployment migration](post_deployment_migrations.md) dated after the migration for the trigger. If the foreign key is deleted earlier, there is a good chance of introducing data inconsistency which needs manual cleanup: diff --git a/doc/development/database/rename_database_tables.md b/doc/development/database/rename_database_tables.md index cbcbd507204..4a3b9df0c33 100644 --- a/doc/development/database/rename_database_tables.md +++ b/doc/development/database/rename_database_tables.md @@ -81,8 +81,8 @@ Execute a standard migration (not a post-migration): when naming indexes, so there is a possibility that not all indexes are properly renamed. After running the migration locally, check if there are inconsistently named indexes (`db/structure.sql`). Those can be renamed manually in a separate migration, which can be also part of the release M.N+1. -- Foreign key columns might still contain the old table name. For smaller tables, follow our [standard column -rename process](avoiding_downtime_in_migrations.md#renaming-columns) +- Foreign key columns might still contain the old table name. For smaller tables, follow our + [standard column rename process](avoiding_downtime_in_migrations.md#renaming-columns) - Avoid renaming database tables which are using with triggers. - Table modifications (add or remove columns) are not allowed during the rename process, please make sure that all changes to the table happen before the rename migration is started (or in the next release). - As the index names might change, verify that the model does not use bulk insert diff --git a/doc/development/database/strings_and_the_text_data_type.md b/doc/development/database/strings_and_the_text_data_type.md index 73e023f8d45..ee74e57ed32 100644 --- a/doc/development/database/strings_and_the_text_data_type.md +++ b/doc/development/database/strings_and_the_text_data_type.md @@ -148,8 +148,9 @@ to update the `title_html` with a title that has more than 1024 characters, the a database error. Adding or removing a constraint to an existing attribute requires that any application changes are -deployed _first_, [otherwise servers still in the old version of the application may try to update the -attribute with invalid values](../multi_version_compatibility.md#ci-artifact-uploads-were-failing). +deployed _first_, +otherwise servers still in the old version of the application +[may try to update the attribute with invalid values](../multi_version_compatibility.md#ci-artifact-uploads-were-failing). For these reasons, `add_text_limit` should run in a post-deployment migration. Still in our example, for the 13.0 milestone (current), consider that the following validation diff --git a/doc/development/database/understanding_explain_plans.md b/doc/development/database/understanding_explain_plans.md index 49babde737a..446a84d5232 100644 --- a/doc/development/database/understanding_explain_plans.md +++ b/doc/development/database/understanding_explain_plans.md @@ -252,8 +252,8 @@ A scan on an index that required retrieving some data from the table. Bitmap scans fall between sequential scans and index scans. These are typically used when we would read too much data from an index scan, but too little to -perform a sequential scan. A bitmap scan uses what is known as a [bitmap -index](https://en.wikipedia.org/wiki/Bitmap_index) to perform its work. +perform a sequential scan. A bitmap scan uses what is known as a +[bitmap index](https://en.wikipedia.org/wiki/Bitmap_index) to perform its work. The [source code of PostgreSQL](https://gitlab.com/postgres/postgres/blob/REL_11_STABLE/src/include/nodes/plannodes.h#L441) states the following on bitmap scans: @@ -794,8 +794,8 @@ Execution time: 0.113 ms ### ChatOps -[GitLab team members can also use our ChatOps solution, available in Slack using the -`/chatops` slash command](../chatops_on_gitlabcom.md). +GitLab team members can also use our ChatOps solution, available in Slack +using the [`/chatops` slash command](../chatops_on_gitlabcom.md). NOTE: While ChatOps is still available, the recommended way to generate execution plans is to use [Database Lab Engine](#database-lab-engine). diff --git a/doc/development/internal_api/index.md b/doc/development/internal_api/index.md index 327e750145c..c3703417f39 100644 --- a/doc/development/internal_api/index.md +++ b/doc/development/internal_api/index.md @@ -148,8 +148,8 @@ curl --request POST --header "Gitlab-Shared-Secret: <Base64 encoded token>" \ ## Authorized Keys Check This endpoint is called by the GitLab Shell authorized keys -check. Which is called by OpenSSH for [fast SSH key -lookup](../../administration/operations/fast_ssh_key_lookup.md). +check. Which is called by OpenSSH for +[fast SSH key lookup](../../administration/operations/fast_ssh_key_lookup.md). | Attribute | Type | Required | Description | |:----------|:-------|:---------|:------------| diff --git a/doc/development/issue_types.md b/doc/development/issue_types.md index e6047c62827..820c37aeb14 100644 --- a/doc/development/issue_types.md +++ b/doc/development/issue_types.md @@ -13,10 +13,8 @@ Sometimes when a new resource type is added it's not clear if it should be only "extension" of Issue (Issue Type) or if it should be a new first-class resource type (similar to issue, epic, merge request, snippet). -The idea of Issue Types was first proposed in [this -issue](https://gitlab.com/gitlab-org/gitlab/-/issues/8767) and its usage was -discussed few times since then, for example in [incident -management](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/55532). +The idea of Issue Types was first proposed in [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/8767) and its usage was +discussed few times since then, for example in [incident management](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/55532). ## What is an Issue Type diff --git a/doc/development/lfs.md b/doc/development/lfs.md index 9b78c8869b1..5900eb68294 100644 --- a/doc/development/lfs.md +++ b/doc/development/lfs.md @@ -76,14 +76,13 @@ process, which writes the contents to the standard output. 1. The archive data is sent back to the client. In step 7, the `gitaly-lfs-smudge` filter must talk to Workhorse, not to -Rails, or an invalid LFS blob is saved. To support this, GitLab -13.5 [changed the default Omnibus configuration to have Gitaly talk to -the Workhorse](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/4592) +Rails, or an invalid LFS blob is saved. To support this, GitLab 13.5 +[changed the default Omnibus configuration to have Gitaly talk to the Workhorse](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/4592) instead of Rails. One side effect of this change: the correlation ID of the original request is not preserved for the internal API requests made by Gitaly (or `gitaly-lfs-smudge`), such as the one made in step 8. The -correlation IDs for those API requests are random values until [this -Workhorse issue](https://gitlab.com/gitlab-org/gitlab-workhorse/-/issues/309) is +correlation IDs for those API requests are random values until +[this Workhorse issue](https://gitlab.com/gitlab-org/gitlab-workhorse/-/issues/309) is resolved. diff --git a/doc/development/real_time.md b/doc/development/real_time.md index df725a36a93..21f3ee1f3b2 100644 --- a/doc/development/real_time.md +++ b/doc/development/real_time.md @@ -60,8 +60,8 @@ downstream services. To mitigate this, ensure that the code establishing the new WebSocket connection is feature flagged and defaulted to `off`. A careful, percentage-based roll-out -of the feature flag ensures that effects can be observed on the [WebSocket -dashboard](https://dashboards.gitlab.net/d/websockets-main/websockets-overview?orgId=1) +of the feature flag ensures that effects can be observed on the +[WebSocket dashboard](https://dashboards.gitlab.net/d/websockets-main/websockets-overview?orgId=1) 1. Create a [feature flag roll-out](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/issue_templates/Feature%20Flag%20Roll%20Out.md) diff --git a/doc/development/service_ping/index.md b/doc/development/service_ping/index.md index 821f44f0d8a..4481fe33bda 100644 --- a/doc/development/service_ping/index.md +++ b/doc/development/service_ping/index.md @@ -111,7 +111,7 @@ sequenceDiagram 1. Finally, the timing metadata information that is used for diagnostic purposes is submitted to the Versions application. It consists of a list of metric identifiers and the time it took to calculate the metrics: - > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37911) in GitLab 15.0 [with a flag(../../user/feature_flags.md), enabled by default. + > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37911) in GitLab 15.0 [with a flag](../../user/feature_flags.md), enabled by default. > - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/295289) in GitLab 15.2. [Feature flag `measure_service_ping_metric_collection`](https://gitlab.com/gitlab-org/gitlab/-/issues/358128) removed. ```ruby diff --git a/doc/development/sql.md b/doc/development/sql.md index 8553e2a5500..7101bf7fb4b 100644 --- a/doc/development/sql.md +++ b/doc/development/sql.md @@ -79,8 +79,9 @@ ON table_name USING GIN(column_name gin_trgm_ops); ``` -The key here is the `GIN(column_name gin_trgm_ops)` part. This creates a [GIN -index](https://www.postgresql.org/docs/current/gin.html) with the operator class set to `gin_trgm_ops`. These indexes +The key here is the `GIN(column_name gin_trgm_ops)` part. This creates a +[GIN index](https://www.postgresql.org/docs/current/gin.html) +with the operator class set to `gin_trgm_ops`. These indexes _can_ be used by `ILIKE` / `LIKE` and can lead to greatly improved performance. One downside of these indexes is that they can easily get quite large (depending on the amount of data indexed). diff --git a/doc/development/workhorse/index.md b/doc/development/workhorse/index.md index de3636fa112..962124248ef 100644 --- a/doc/development/workhorse/index.md +++ b/doc/development/workhorse/index.md @@ -10,8 +10,8 @@ GitLab Workhorse is a smart reverse proxy for GitLab. It handles "large" HTTP requests such as file downloads, file uploads, Git push/pull and Git archive downloads. -Workhorse itself is not a feature, but there are [several features in -GitLab](gitlab_features.md) that would not work efficiently without Workhorse. +Workhorse itself is not a feature, but there are +[several features in GitLab](gitlab_features.md) that would not work efficiently without Workhorse. The canonical source for Workhorse is [`gitlab-org/gitlab/workhorse`](https://gitlab.com/gitlab-org/gitlab/tree/master/workhorse). diff --git a/doc/topics/git/lfs/index.md b/doc/topics/git/lfs/index.md index 3d52d5446b9..6fd7f4a5207 100644 --- a/doc/topics/git/lfs/index.md +++ b/doc/topics/git/lfs/index.md @@ -115,8 +115,7 @@ See the documentation on [File Locking](../../../user/project/file_lock.md). > - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46572) in GitLab 13.6. > - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62539) in GitLab 14.0. Feature flag `include_lfs_blobs_in_archive` removed. -Prior to GitLab 13.5, [project source -downloads](../../../user/project/repository/index.md) would include Git +Prior to GitLab 13.5, [project source downloads](../../../user/project/repository/index.md) would include Git LFS pointers instead of the actual objects. For example, LFS pointers look like the following: diff --git a/doc/user/analytics/index.md b/doc/user/analytics/index.md index f7578ed4554..3c06fcce2e2 100644 --- a/doc/user/analytics/index.md +++ b/doc/user/analytics/index.md @@ -8,8 +8,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w ## Instance-level analytics -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12077) in GitLab 12.2. - Instance-level analytics make it possible to aggregate analytics across GitLab, so that users can view information across multiple projects and groups in one place. @@ -18,8 +16,7 @@ in one place. ## Group-level analytics -> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/195979) in GitLab 12.8. -> - Moved to GitLab Premium in 13.9. +> Moved to GitLab Premium in 13.9. GitLab provides several analytics features at the group level. Some of these features require you to use a higher tier than GitLab Free. diff --git a/doc/user/analytics/merge_request_analytics.md b/doc/user/analytics/merge_request_analytics.md index 29f2ec79800..038b2f0c97e 100644 --- a/doc/user/analytics/merge_request_analytics.md +++ b/doc/user/analytics/merge_request_analytics.md @@ -31,12 +31,12 @@ To view merge request analytics: 1. On the top bar, select **Menu > Projects** and find your project. 1. On the left sidebar, select **Analytics > Merge request**. -## View merge requests merged per month +## View the number of merge requests in a date range > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/232651) in GitLab 13.3. > - Filtering [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229266) in GitLab 13.4 -To view the number of merge requests merged per month: +To view the number of merge requests merged during a specific date range: 1. On the top bar, select **Menu > Projects** and find your project. 1. On the left sidebar, select **Analytics > Merge request**. diff --git a/doc/user/crm/index.md b/doc/user/crm/index.md index a2cfdf61a8d..e71a983ccfd 100644 --- a/doc/user/crm/index.md +++ b/doc/user/crm/index.md @@ -169,7 +169,7 @@ You can also add, remove, or replace issue contacts using the [GraphQL](../../api/graphql/reference/index.md#mutationissuesetcrmcontacts) API. -## Autocomplete contacts **(FREE SELF)** +## Autocomplete contacts > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/2256) in GitLab 14.8 [with a flag](../../administration/feature_flags.md) named `contacts_autocomplete`. Disabled by default. > - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/352123) in GitLab 15.0. diff --git a/doc/user/project/git_attributes.md b/doc/user/project/git_attributes.md index 11d1db195e1..90f64b7262c 100644 --- a/doc/user/project/git_attributes.md +++ b/doc/user/project/git_attributes.md @@ -23,5 +23,5 @@ ignored. ## Syntax Highlighting The `.gitattributes` file can be used to define which language to use when -syntax highlighting files and diffs. See ["Syntax -Highlighting"](highlighting.md) for more information. +syntax highlighting files and diffs. See +["Syntax Highlighting"](highlighting.md) for more information. diff --git a/doc/user/project/pages/getting_started/pages_from_scratch.md b/doc/user/project/pages/getting_started/pages_from_scratch.md index 5fd17b5c07e..68a2a6a80ad 100644 --- a/doc/user/project/pages/getting_started/pages_from_scratch.md +++ b/doc/user/project/pages/getting_started/pages_from_scratch.md @@ -420,10 +420,10 @@ Now GitLab CI/CD not only builds the website, but also: For more information, see the following blog posts. -- [Use GitLab CI/CD `environments` to deploy your - web app to staging and production](https://about.gitlab.com/blog/2021/02/05/ci-deployment-and-environments/). -- Learn [how to run jobs sequentially, - in parallel, or build a custom pipeline](https://about.gitlab.com/blog/2016/07/29/the-basics-of-gitlab-ci/). +- Use GitLab CI/CD `environments` to + [deploy your web app to staging and production](https://about.gitlab.com/blog/2021/02/05/ci-deployment-and-environments/). +- Learn how to run jobs + [sequentially, in parallel, or build a custom pipeline](https://about.gitlab.com/blog/2016/07/29/the-basics-of-gitlab-ci/). - Learn [how to pull specific directories from different projects](https://about.gitlab.com/blog/2016/12/07/building-a-new-gitlab-docs-site-with-nanoc-gitlab-ci-and-gitlab-pages/) to deploy this website, <https://docs.gitlab.com>. - Learn [how to use GitLab Pages to produce a code coverage report](https://about.gitlab.com/blog/2016/11/03/publish-code-coverage-report-with-gitlab-pages/). diff --git a/doc/user/project/push_options.md b/doc/user/project/push_options.md index 6ef8477b6b6..d02609cbdc7 100644 --- a/doc/user/project/push_options.md +++ b/doc/user/project/push_options.md @@ -95,15 +95,15 @@ git push -o merge_request.create -o merge_request.target=my-target-branch -o mer ## Useful Git aliases As shown above, Git push options can cause Git commands to grow very long. If -you use the same push options frequently, it's useful to create [Git -aliases](https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases). Git aliases +you use the same push options frequently, it's useful to create +[Git aliases](https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases). Git aliases are command line shortcuts for Git which can significantly simplify the use of long Git commands. ### Merge when pipeline succeeds alias -To set up a Git alias for the [merge when pipeline succeeds Git push -option](#push-options-for-merge-requests): +To set up a Git alias for the +[merge when pipeline succeeds Git push option](#push-options-for-merge-requests): ```shell git config --global alias.mwps "push -o merge_request.create -o merge_request.target=master -o merge_request.merge_when_pipeline_succeeds" diff --git a/lib/gitlab/diff/highlight_cache.rb b/lib/gitlab/diff/highlight_cache.rb index 88f396fa7b9..7cfe0086f57 100644 --- a/lib/gitlab/diff/highlight_cache.rb +++ b/lib/gitlab/diff/highlight_cache.rb @@ -7,7 +7,6 @@ module Gitlab include Gitlab::Utils::StrongMemoize EXPIRATION = 1.day - PREVIOUS_EXPIRATION_PERIOD = 7.days VERSION = 2 delegate :diffable, to: :@diff_collection @@ -75,28 +74,14 @@ module Gitlab Feature.enabled?(:use_marker_ranges, diffable.project), Feature.enabled?(:diff_line_syntax_highlighting, diffable.project) ] + options_for_key = OpenSSL::Digest::SHA256.hexdigest(options.join) - options_for_key = - if Feature.enabled?(:highlight_diffs_optimize_memory_usage, diffable.project) - [OpenSSL::Digest::SHA256.hexdigest(options.join)] - else - options - end - - ['highlighted-diff-files', diffable.cache_key, VERSION, *options_for_key].join(":") + ['highlighted-diff-files', diffable.cache_key, VERSION, options_for_key].join(":") end end private - def expiration_period - if Feature.enabled?(:highlight_diffs_optimize_memory_usage, diffable.project) - EXPIRATION - else - PREVIOUS_EXPIRATION_PERIOD - end - end - def set_highlighted_diff_lines(diff_file, content) diff_file.highlighted_diff_lines = content.map do |line| Gitlab::Diff::Line.safe_init_from_hash(line) @@ -153,7 +138,7 @@ module Gitlab # HSETs have to have their expiration date manually updated # - redis.expire(key, expiration_period) + redis.expire(key, EXPIRATION) end record_memory_usage(fetch_memory_usage(redis, key)) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index ac4c288db72..ca4949b0166 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -34571,6 +34571,12 @@ msgid_plural "SearchResults|wiki results" msgstr[0] "" msgstr[1] "" +msgid "SearchToken|Assignee" +msgstr "" + +msgid "SearchToken|Reviewer" +msgstr "" + msgid "Searching by both author and message is currently not supported." msgstr "" @@ -45727,9 +45733,15 @@ msgstr "" msgid "ciReport|%{sameNum} same" msgstr "" +msgid "ciReport|%{scanner} detected %{boldStart}%{number}%{boldEnd} new potential %{vulnStr}" +msgstr "" + msgid "ciReport|%{scanner} detected %{strong_start}%{number}%{strong_end} new potential %{vulnStr}" msgstr "" +msgid "ciReport|%{scanner} detected no %{boldStart}new%{boldEnd} potential vulnerabilities" +msgstr "" + msgid "ciReport|%{scanner} detected no %{strong_start}new%{strong_end} %{vulnStr}" msgstr "" diff --git a/spec/controllers/projects/ci/secure_files_controller_spec.rb b/spec/controllers/projects/ci/secure_files_controller_spec.rb deleted file mode 100644 index 200997e31b9..00000000000 --- a/spec/controllers/projects/ci/secure_files_controller_spec.rb +++ /dev/null @@ -1,67 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Projects::Ci::SecureFilesController do - let_it_be(:project) { create(:project) } - let_it_be(:user) { create(:user) } - - subject(:show_request) { get :show, params: { namespace_id: project.namespace, project_id: project } } - - describe 'GET #show' do - context 'when the :ci_secure_files feature flag is enabled' do - context 'with enough privileges' do - before do - stub_feature_flags(ci_secure_files: true) - sign_in(user) - project.add_developer(user) - show_request - end - - it { expect(response).to have_gitlab_http_status(:ok) } - - it 'renders show page' do - expect(response).to render_template :show - end - end - end - - context 'when the :ci_secure_files feature flag is disabled' do - context 'with enough privileges' do - before do - stub_feature_flags(ci_secure_files: false) - sign_in(user) - project.add_developer(user) - show_request - end - - it 'responds with 404' do - expect(response).to have_gitlab_http_status(:not_found) - end - end - end - - context 'without enough privileges' do - before do - sign_in(user) - project.add_reporter(user) - show_request - end - - it 'responds with 404' do - expect(response).to have_gitlab_http_status(:not_found) - end - end - - context 'an unauthenticated user' do - before do - show_request - end - - it 'redirects to sign in' do - expect(response).to have_gitlab_http_status(:found) - expect(response).to redirect_to('/users/sign_in') - end - end - end -end diff --git a/spec/features/projects/ci/secure_files_spec.rb b/spec/features/projects/ci/secure_files_spec.rb deleted file mode 100644 index 412330eb5d6..00000000000 --- a/spec/features/projects/ci/secure_files_spec.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Secure Files', :js do - let(:project) { create(:project) } - let(:user) { create(:user) } - - before do - stub_feature_flags(ci_secure_files_read_only: false) - project.add_maintainer(user) - sign_in(user) - end - - it 'user sees the Secure Files list component' do - visit project_ci_secure_files_path(project) - expect(page).to have_content('There are no secure files yet.') - end - - it 'prompts the user to confirm before deleting a file' do - file = create(:ci_secure_file, project: project) - - visit project_ci_secure_files_path(project) - - expect(page).to have_content(file.name) - - find('button.btn-danger').click - - expect(page).to have_content("Delete #{file.name}?") - - click_on('Delete secure file') - - visit project_ci_secure_files_path(project) - - expect(page).not_to have_content(file.name) - end - - it 'displays an uploaded file in the file list' do - visit project_ci_secure_files_path(project) - expect(page).to have_content('There are no secure files yet.') - - page.attach_file('spec/fixtures/ci_secure_files/upload-keystore.jks') do - click_button 'Upload File' - end - - expect(page).to have_content('upload-keystore.jks') - end - - it 'displays an error when a duplicate file upload is attempted' do - create(:ci_secure_file, project: project, name: 'upload-keystore.jks') - visit project_ci_secure_files_path(project) - - expect(page).to have_content('upload-keystore.jks') - - page.attach_file('spec/fixtures/ci_secure_files/upload-keystore.jks') do - click_button 'Upload File' - end - - expect(page).to have_content('A file with this name already exists.') - end -end diff --git a/spec/frontend/behaviors/gl_emoji_spec.js b/spec/frontend/behaviors/gl_emoji_spec.js index 8842ad636ec..722327e94ba 100644 --- a/spec/frontend/behaviors/gl_emoji_spec.js +++ b/spec/frontend/behaviors/gl_emoji_spec.js @@ -121,7 +121,7 @@ describe('gl_emoji', () => { window.gon.emoji_sprites_css_path = testPath; expect(document.head.querySelector(`link[href="${testPath}"]`)).toBe(null); - expect(window.gon.emoji_sprites_css_added).toBeFalsy(); + expect(window.gon.emoji_sprites_css_added).toBe(undefined); markupToDomElement( '<gl-emoji data-fallback-sprite-class="emoji-bomb" data-name="bomb"></gl-emoji>', diff --git a/spec/frontend/security_configuration/components/training_provider_list_spec.js b/spec/frontend/security_configuration/components/training_provider_list_spec.js index 184c16fda6e..b6451af57d7 100644 --- a/spec/frontend/security_configuration/components/training_provider_list_spec.js +++ b/spec/frontend/security_configuration/components/training_provider_list_spec.js @@ -402,7 +402,7 @@ describe('TrainingProviderList component', () => { it('has disabled state for radio', () => { findPrimaryProviderRadios().wrappers.forEach((radio) => { - expect(radio.attributes('disabled')).toBeTruthy(); + expect(radio.attributes('disabled')).toBe('true'); }); }); diff --git a/spec/frontend/vue_merge_request_widget/components/widget/app_spec.js b/spec/frontend/vue_merge_request_widget/components/widget/app_spec.js new file mode 100644 index 00000000000..6bb718082a4 --- /dev/null +++ b/spec/frontend/vue_merge_request_widget/components/widget/app_spec.js @@ -0,0 +1,19 @@ +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import App from '~/vue_merge_request_widget/components/widget/app.vue'; + +describe('MR Widget App', () => { + let wrapper; + + const createComponent = () => { + wrapper = shallowMountExtended(App, { + propsData: { + mr: {}, + }, + }); + }; + + it('mounts the component', () => { + createComponent(); + expect(wrapper.findByTestId('mr-widget-app').exists()).toBe(true); + }); +}); diff --git a/spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js b/spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js new file mode 100644 index 00000000000..6ef151e93e9 --- /dev/null +++ b/spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js @@ -0,0 +1,134 @@ +import * as Sentry from '@sentry/browser'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import waitForPromises from 'helpers/wait_for_promises'; +import Widget from '~/vue_merge_request_widget/components/widget/widget.vue'; + +describe('MR Widget', () => { + let wrapper; + + const createComponent = ({ propsData, slots } = {}) => { + wrapper = shallowMountExtended(Widget, { + propsData: { + loadingText: 'Loading widget', + value: { + collapsed: null, + expanded: null, + }, + ...propsData, + }, + slots, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + describe('on mount', () => { + it('fetches collapsed', async () => { + const fetchCollapsedData = jest + .fn() + .mockReturnValue(Promise.resolve({ headers: {}, status: 200, data: {} })); + + createComponent({ propsData: { fetchCollapsedData } }); + await waitForPromises(); + expect(fetchCollapsedData).toHaveBeenCalled(); + expect(wrapper.vm.error).toBe(null); + }); + + it('sets the error text when fetch method fails', async () => { + const fetchCollapsedData = jest.fn().mockReturnValue(() => Promise.reject()); + createComponent({ propsData: { fetchCollapsedData } }); + await waitForPromises(); + expect(wrapper.vm.error).toBe('Failed to load'); + }); + }); + + describe('fetch', () => { + it('sets the data.collapsed property after a successfull call - multiPolling: false', async () => { + const mockData = { headers: {}, status: 200, data: { vulnerabilities: [] } }; + createComponent({ propsData: { fetchCollapsedData: async () => mockData } }); + await waitForPromises(); + expect(wrapper.emitted('input')[0][0]).toEqual({ collapsed: mockData.data, expanded: null }); + }); + + it('sets the data.collapsed property after a successfull call - multiPolling: true', async () => { + const mockData1 = { headers: {}, status: 200, data: { vulnerabilities: [{ vuln: 1 }] } }; + const mockData2 = { headers: {}, status: 200, data: { vulnerabilities: [{ vuln: 2 }] } }; + + createComponent({ + propsData: { + multiPolling: true, + fetchCollapsedData: () => [ + () => Promise.resolve(mockData1), + () => Promise.resolve(mockData2), + ], + }, + }); + await waitForPromises(); + await waitForPromises(); + expect(wrapper.emitted('input')[0][0]).toEqual({ + collapsed: [mockData1.data, mockData2.data], + expanded: null, + }); + }); + + it('calls sentry when failed', async () => { + const error = new Error('Something went wrong'); + jest.spyOn(Sentry, 'captureException').mockImplementation(); + createComponent({ + propsData: { + fetchCollapsedData: async () => Promise.reject(error), + }, + }); + await waitForPromises(); + expect(wrapper.emitted('input')).toBeUndefined(); + expect(Sentry.captureException).toHaveBeenCalledWith(error); + }); + }); + + describe('content', () => { + it('displays summary property when summary slot is not provided', () => { + createComponent({ + propsData: { + summary: 'Hello world', + fetchCollapsedData: async () => Promise.resolve(), + }, + }); + + expect(wrapper.findByTestId('widget-extension-top-level-summary').text()).toBe('Hello world'); + }); + + it.todo('displays content property when content slot is not provided'); + + it('displays the summary slot when provided', () => { + createComponent({ + propsData: { + fetchCollapsedData: async () => Promise.resolve(), + }, + slots: { + summary: '<b>More complex summary</b>', + }, + }); + + expect(wrapper.findByTestId('widget-extension-top-level-summary').text()).toBe( + 'More complex summary', + ); + }); + + it('displays the content slot when provided', () => { + createComponent({ + propsData: { + fetchCollapsedData: async () => Promise.resolve(), + }, + slots: { + content: '<b>More complex content</b>', + }, + }); + + expect(wrapper.findByTestId('widget-extension-collapsed-section').text()).toBe( + 'More complex content', + ); + }); + }); +}); diff --git a/spec/frontend/vue_shared/components/dismissible_alert_spec.js b/spec/frontend/vue_shared/components/dismissible_alert_spec.js index 5eb6e3166c6..8b1189f25d5 100644 --- a/spec/frontend/vue_shared/components/dismissible_alert_spec.js +++ b/spec/frontend/vue_shared/components/dismissible_alert_spec.js @@ -45,7 +45,7 @@ describe('vue_shared/components/dismissible_alert', () => { }); it('emmits alertDismissed', () => { - expect(wrapper.emitted('alertDismissed')).toBeTruthy(); + expect(wrapper.emitted()).toHaveProperty('alertDismissed'); }); }); }); diff --git a/spec/lib/gitlab/diff/highlight_cache_spec.rb b/spec/lib/gitlab/diff/highlight_cache_spec.rb index 4a8b338506d..1d1ffc8c275 100644 --- a/spec/lib/gitlab/diff/highlight_cache_spec.rb +++ b/spec/lib/gitlab/diff/highlight_cache_spec.rb @@ -127,20 +127,6 @@ RSpec.describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache do cache.write_if_empty end - - context 'when highlight_diffs_optimize_memory_usage is disabled' do - before do - stub_feature_flags(highlight_diffs_optimize_memory_usage: false) - end - - it 'sets the previous expiration period' do - Gitlab::Redis::Cache.with do |redis| - expect(redis).to receive(:expire).with(cache.key, described_class::PREVIOUS_EXPIRATION_PERIOD) - end - - cache.write_if_empty - end - end end describe '#write_if_empty' do @@ -304,15 +290,5 @@ RSpec.describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache do is_expected.to eq("highlighted-diff-files:#{cache.diffable.cache_key}:2:#{options_hash([cache.diff_options, true, false])}") end end - - context 'when highlight_diffs_optimize_memory_usage is disabled' do - before do - stub_feature_flags(highlight_diffs_optimize_memory_usage: false) - end - - it 'uses the options hash as a part of the cache key' do - is_expected.to eq("highlighted-diff-files:#{cache.diffable.cache_key}:2:#{cache.diff_options}:true:true") - end - end end end diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 1d58a31bd6e..5d560620b85 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -953,12 +953,6 @@ RSpec.describe 'project routing' do end end - describe Projects::Ci::SecureFilesController, 'routing' do - it 'to #show' do - expect(get('/gitlab/gitlabhq/-/ci/secure_files')).to route_to('projects/ci/secure_files#show', namespace_id: 'gitlab', project_id: 'gitlabhq') - end - end - context 'with a non-existent project' do it 'routes to 404 with get request' do expect(get: "/gitlab/not_exist").to route_to( diff --git a/spec/services/ci/runners/bulk_delete_runners_service_spec.rb b/spec/services/ci/runners/bulk_delete_runners_service_spec.rb index 3122e861bea..2fc13831c31 100644 --- a/spec/services/ci/runners/bulk_delete_runners_service_spec.rb +++ b/spec/services/ci/runners/bulk_delete_runners_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe ::Ci::Runners::BulkDeleteRunnersService, '#execute' do - subject { described_class.new(**service_args).execute } + subject(:execute) { described_class.new(**service_args).execute } let(:service_args) { { runners: runners_arg } } let(:runners_arg) { } @@ -17,7 +17,8 @@ RSpec.describe ::Ci::Runners::BulkDeleteRunnersService, '#execute' do it 'destroys runners', :aggregate_failures do expect { subject }.to change { Ci::Runner.count }.by(-2) - is_expected.to eq({ deleted_count: 2, deleted_ids: [instance_runner.id, project_runner.id] }) + is_expected.to be_success + expect(execute.payload).to eq({ deleted_count: 2, deleted_ids: [instance_runner.id, project_runner.id] }) expect(instance_runner[:errors]).to be_nil expect(project_runner[:errors]).to be_nil expect { project_runner.runner_projects.first.reload }.to raise_error(ActiveRecord::RecordNotFound) @@ -36,7 +37,8 @@ RSpec.describe ::Ci::Runners::BulkDeleteRunnersService, '#execute' do it 'destroys runners and returns only deleted runners', :aggregate_failures do expect { subject }.to change { Ci::Runner.count }.by(-1) - is_expected.to eq({ deleted_count: 1, deleted_ids: [project_runner.id] }) + is_expected.to be_success + expect(execute.payload).to eq({ deleted_count: 1, deleted_ids: [project_runner.id] }) expect(instance_runner[:errors]).to be_nil expect(project_runner[:errors]).to be_nil expect { project_runner.reload }.to raise_error(ActiveRecord::RecordNotFound) @@ -51,7 +53,8 @@ RSpec.describe ::Ci::Runners::BulkDeleteRunnersService, '#execute' do it 'deletes only first RUNNER_LIMIT runners' do expect { subject }.to change { Ci::Runner.count }.by(-1) - is_expected.to eq({ deleted_count: 1, deleted_ids: [instance_runner.id] }) + is_expected.to be_success + expect(execute.payload).to eq({ deleted_count: 1, deleted_ids: [instance_runner.id] }) end end end @@ -72,7 +75,8 @@ RSpec.describe ::Ci::Runners::BulkDeleteRunnersService, '#execute' do let(:runners_arg) { nil } it 'returns 0 deleted runners' do - is_expected.to eq({ deleted_count: 0, deleted_ids: [] }) + is_expected.to be_success + expect(execute.payload).to eq({ deleted_count: 0, deleted_ids: [] }) end end end |