diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-30 21:09:38 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-30 21:09:38 +0300 |
commit | 028bb5dda7abc9ec76f21ae8e691825b4673f733 (patch) | |
tree | a41741811452f928c6f650451c69fc18e46b62a4 | |
parent | 7f305b576b51c3503970ef224cf4b31e247a322d (diff) |
Add latest changes from gitlab-org/gitlab@master
68 files changed, 389 insertions, 242 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3ba8df9b0d2..a5d5b918428 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -30,7 +30,7 @@ workflow: # merge requests used for this merge a branch release-tools/X into a stable # branch. For these merge requests we don't want to run any pipelines, as # they serve no purpose and will run anyway when the changes are merged. - - if: '$CI_COMMIT_BRANCH =~ /^release-tools\/\d+\.\d+\.\d+-rc\d+$/ && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^[\d-]+-stable(-ee)?$/ && $CI_PROJECT_PATH == "gitlab-org/gitlab"' + - if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /^release-tools\/\d+\.\d+\.\d+-rc\d+$/ && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^[\d-]+-stable(-ee)?$/ && $CI_PROJECT_PATH == "gitlab-org/gitlab"' when: never # For merge requests, create a pipeline. - if: '$CI_MERGE_REQUEST_IID' diff --git a/app/assets/javascripts/registry/settings/store/getters.js b/app/assets/javascripts/registry/settings/store/getters.js index ef4b4f0ba02..ac1a931d8e0 100644 --- a/app/assets/javascripts/registry/settings/store/getters.js +++ b/app/assets/javascripts/registry/settings/store/getters.js @@ -16,6 +16,7 @@ export const getSettings = (state, getters) => ({ older_than: getters.getOlderThan, keep_n: getters.getKeepN, name_regex: state.settings.name_regex, + name_regex_keep: state.settings.name_regex_keep, }); export const getIsEdited = state => !isEqual(state.original, state.settings); diff --git a/app/assets/javascripts/registry/shared/components/expiration_policy_fields.vue b/app/assets/javascripts/registry/shared/components/expiration_policy_fields.vue index 26dfd11b55c..04a547db07e 100644 --- a/app/assets/javascripts/registry/shared/components/expiration_policy_fields.vue +++ b/app/assets/javascripts/registry/shared/components/expiration_policy_fields.vue @@ -1,8 +1,23 @@ <script> import { uniqueId } from 'lodash'; import { GlFormGroup, GlToggle, GlFormSelect, GlFormTextarea, GlSprintf } from '@gitlab/ui'; -import { s__, __ } from '~/locale'; -import { NAME_REGEX_LENGTH } from '../constants'; +import { + NAME_REGEX_LENGTH, + ENABLED_TEXT, + DISABLED_TEXT, + TEXT_AREA_INVALID_FEEDBACK, + EXPIRATION_INTERVAL_LABEL, + EXPIRATION_SCHEDULE_LABEL, + KEEP_N_LABEL, + NAME_REGEX_LABEL, + NAME_REGEX_PLACEHOLDER, + NAME_REGEX_DESCRIPTION, + NAME_REGEX_KEEP_LABEL, + NAME_REGEX_KEEP_PLACEHOLDER, + NAME_REGEX_KEEP_DESCRIPTION, + ENABLE_TOGGLE_LABEL, + ENABLE_TOGGLE_DESCRIPTION, +} from '../constants'; import { mapComputedToEvent } from '../utils'; export default { @@ -40,42 +55,73 @@ export default { default: 'right', }, }, - nameRegexPlaceholder: '.*', + i18n: { + textAreaInvalidFeedback: TEXT_AREA_INVALID_FEEDBACK, + enableToggleLabel: ENABLE_TOGGLE_LABEL, + enableToggleDescription: ENABLE_TOGGLE_DESCRIPTION, + }, selectList: [ { name: 'expiration-policy-interval', - label: s__('ContainerRegistry|Expiration interval:'), + label: EXPIRATION_INTERVAL_LABEL, model: 'older_than', optionKey: 'olderThan', }, { name: 'expiration-policy-schedule', - label: s__('ContainerRegistry|Expiration schedule:'), + label: EXPIRATION_SCHEDULE_LABEL, model: 'cadence', optionKey: 'cadence', }, { name: 'expiration-policy-latest', - label: s__('ContainerRegistry|Number of tags to retain:'), + label: KEEP_N_LABEL, model: 'keep_n', optionKey: 'keepN', }, ], + textAreaList: [ + { + name: 'expiration-policy-name-matching', + label: NAME_REGEX_LABEL, + model: 'name_regex', + placeholder: NAME_REGEX_PLACEHOLDER, + stateVariable: 'nameRegexState', + description: NAME_REGEX_DESCRIPTION, + }, + { + name: 'expiration-policy-keep-name', + label: NAME_REGEX_KEEP_LABEL, + model: 'name_regex_keep', + placeholder: NAME_REGEX_KEEP_PLACEHOLDER, + stateVariable: 'nameKeepRegexState', + description: NAME_REGEX_KEEP_DESCRIPTION, + }, + ], data() { return { uniqueId: uniqueId(), }; }, computed: { - ...mapComputedToEvent(['enabled', 'cadence', 'older_than', 'keep_n', 'name_regex'], 'value'), + ...mapComputedToEvent( + ['enabled', 'cadence', 'older_than', 'keep_n', 'name_regex', 'name_regex_keep'], + 'value', + ), policyEnabledText() { - return this.enabled ? __('enabled') : __('disabled'); + return this.enabled ? ENABLED_TEXT : DISABLED_TEXT; }, - nameRegexState() { - return this.name_regex ? this.name_regex.length <= NAME_REGEX_LENGTH : null; + textAreaState() { + return { + nameRegexState: this.validateNameRegex(this.name_regex), + nameKeepRegexState: this.validateNameRegex(this.name_regex_keep), + }; }, fieldsValidity() { - return this.nameRegexState !== false; + return ( + this.textAreaState.nameRegexState !== false && + this.textAreaState.nameKeepRegexState !== false + ); }, isFormElementDisabled() { return !this.enabled || this.isLoading; @@ -94,6 +140,9 @@ export default { }, }, methods: { + validateNameRegex(value) { + return value ? value.length <= NAME_REGEX_LENGTH : null; + }, idGenerator(id) { return `${id}_${this.uniqueId}`; }, @@ -111,7 +160,7 @@ export default { :label-cols="labelCols" :label-align="labelAlign" :label-for="idGenerator('expiration-policy-toggle')" - :label="s__('ContainerRegistry|Expiration policy:')" + :label="$options.i18n.enableToggleLabel" > <div class="d-flex align-items-start"> <gl-toggle @@ -120,9 +169,7 @@ export default { :disabled="isLoading" /> <span class="mb-2 ml-1 lh-2"> - <gl-sprintf - :message="s__('ContainerRegistry|Docker tag expiration policy is %{toggleStatus}')" - > + <gl-sprintf :message="$options.i18n.enableToggleDescription"> <template #toggleStatus> <strong>{{ policyEnabledText }}</strong> </template> @@ -157,35 +204,34 @@ export default { </gl-form-group> <gl-form-group - :id="idGenerator('expiration-policy-name-matching-group')" + v-for="textarea in $options.textAreaList" + :id="idGenerator(`${textarea.name}-group`)" + :key="textarea.name" :label-cols="labelCols" :label-align="labelAlign" - :label-for="idGenerator('expiration-policy-name-matching')" - :label=" - s__('ContainerRegistry|Docker tags with names matching this regex pattern will expire:') - " - :state="nameRegexState" - :invalid-feedback=" - s__('ContainerRegistry|The value of this input should be less than 255 characters') - " + :label-for="idGenerator(textarea.name)" + :state="textAreaState[textarea.stateVariable]" + :invalid-feedback="$options.i18n.textAreaInvalidFeedback" > + <template #label> + <gl-sprintf :message="textarea.label"> + <template #italic="{content}"> + <i>{{ content }}</i> + </template> + </gl-sprintf> + </template> <gl-form-textarea - :id="idGenerator('expiration-policy-name-matching')" - v-model="name_regex" - :placeholder="$options.nameRegexPlaceholder" - :state="nameRegexState" + :id="idGenerator(textarea.name)" + :value="value[textarea.model]" + :placeholder="textarea.placeholder" + :state="textAreaState[textarea.stateVariable]" :disabled="isFormElementDisabled" trim + @input="updateModel($event, textarea.model)" /> <template #description> <span ref="regex-description"> - <gl-sprintf - :message=" - s__( - 'ContainerRegistry|Regular expressions such as %{codeStart}.*-test%{codeEnd} or %{codeStart}dev-.*%{codeEnd} are supported. To select all tags, use %{codeStart}.*%{codeEnd}', - ) - " - > + <gl-sprintf :message="textarea.description"> <template #code="{content}"> <code>{{ content }}</code> </template> diff --git a/app/assets/javascripts/registry/shared/constants.js b/app/assets/javascripts/registry/shared/constants.js index c0dac466b29..7a839e4a3ed 100644 --- a/app/assets/javascripts/registry/shared/constants.js +++ b/app/assets/javascripts/registry/shared/constants.js @@ -1,4 +1,4 @@ -import { s__ } from '~/locale'; +import { s__, __ } from '~/locale'; export const FETCH_SETTINGS_ERROR_MESSAGE = s__( 'ContainerRegistry|Something went wrong while fetching the expiration policy.', @@ -13,3 +13,33 @@ export const UPDATE_SETTINGS_SUCCESS_MESSAGE = s__( ); export const NAME_REGEX_LENGTH = 255; + +export const ENABLED_TEXT = __('enabled'); +export const DISABLED_TEXT = __('disabled'); + +export const ENABLE_TOGGLE_LABEL = s__('ContainerRegistry|Expiration policy:'); +export const ENABLE_TOGGLE_DESCRIPTION = s__( + 'ContainerRegistry|Docker tag expiration policy is %{toggleStatus}', +); + +export const TEXT_AREA_INVALID_FEEDBACK = s__( + 'ContainerRegistry|The value of this input should be less than 255 characters', +); + +export const EXPIRATION_INTERVAL_LABEL = s__('ContainerRegistry|Expiration interval:'); +export const EXPIRATION_SCHEDULE_LABEL = s__('ContainerRegistry|Expiration schedule:'); +export const KEEP_N_LABEL = s__('ContainerRegistry|Number of tags to retain:'); +export const NAME_REGEX_LABEL = s__( + 'ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}', +); +export const NAME_REGEX_PLACEHOLDER = '.*'; +export const NAME_REGEX_DESCRIPTION = s__( + 'ContainerRegistry|Regular expressions such as %{codeStart}.*-test%{codeEnd} or %{codeStart}dev-.*%{codeEnd} are supported. To select all tags, use %{codeStart}.*%{codeEnd}', +); +export const NAME_REGEX_KEEP_LABEL = s__( + 'ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}be preserved:%{italicEnd}', +); +export const NAME_REGEX_KEEP_PLACEHOLDER = ''; +export const NAME_REGEX_KEEP_DESCRIPTION = s__( + 'ContainerRegistry|Regular expressions such as %{codeStart}.*-test%{codeEnd} or %{codeStart}dev-.*%{codeEnd} are supported', +); diff --git a/app/assets/javascripts/static_site_editor/components/saved_changes_message.vue b/app/assets/javascripts/static_site_editor/components/saved_changes_message.vue index 41cb901720c..dd907570114 100644 --- a/app/assets/javascripts/static_site_editor/components/saved_changes_message.vue +++ b/app/assets/javascripts/static_site_editor/components/saved_changes_message.vue @@ -28,7 +28,8 @@ export default { }, returnUrl: { type: String, - required: true, + required: false, + default: '', }, }, }; @@ -46,7 +47,7 @@ export default { }} </p> <div class="d-flex justify-content-end"> - <gl-button ref="returnToSiteButton" :href="returnUrl">{{ + <gl-button v-if="returnUrl" ref="returnToSiteButton" :href="returnUrl">{{ s__('StaticSiteEditor|Return to site') }}</gl-button> <gl-button ref="mergeRequestButton" class="ml-2" :href="mergeRequest.url" variant="success"> @@ -60,7 +61,7 @@ export default { <ul> <li> {{ s__('StaticSiteEditor|You created a new branch:') }} - <span ref="branchLink">{{ branch.label }}</span> + <gl-link ref="branchLink" :href="branch.url">{{ branch.label }}</gl-link> </li> <li> {{ s__('StaticSiteEditor|You created a merge request:') }} diff --git a/app/assets/javascripts/static_site_editor/components/static_site_editor.vue b/app/assets/javascripts/static_site_editor/components/static_site_editor.vue index d45c3d08ef4..79e4b4a4581 100644 --- a/app/assets/javascripts/static_site_editor/components/static_site_editor.vue +++ b/app/assets/javascripts/static_site_editor/components/static_site_editor.vue @@ -48,6 +48,7 @@ export default { <!-- Success view --> <saved-changes-message v-if="savedContentMeta" + class="w-75" :branch="savedContentMeta.branch" :commit="savedContentMeta.commit" :merge-request="savedContentMeta.mergeRequest" diff --git a/app/assets/javascripts/static_site_editor/services/submit_content_changes.js b/app/assets/javascripts/static_site_editor/services/submit_content_changes.js index ff591e4b245..b4e4e94d4f2 100644 --- a/app/assets/javascripts/static_site_editor/services/submit_content_changes.js +++ b/app/assets/javascripts/static_site_editor/services/submit_content_changes.js @@ -56,8 +56,8 @@ const submitContentChanges = ({ username, projectId, sourcePath, content }) => { const meta = {}; return createBranch(projectId, branch) - .then(() => { - Object.assign(meta, { branch: { label: branch } }); + .then(({ data: { web_url: url } }) => { + Object.assign(meta, { branch: { label: branch, url } }); return commitContent(projectId, mergeRequestTitle, branch, sourcePath, content); }) @@ -67,7 +67,7 @@ const submitContentChanges = ({ username, projectId, sourcePath, content }) => { return createMergeRequest(projectId, mergeRequestTitle, branch); }) .then(({ data: { iid: label, web_url: url } }) => { - Object.assign(meta, { mergeRequest: { label, url } }); + Object.assign(meta, { mergeRequest: { label: label.toString(), url } }); return meta; }); diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 16254c74ba4..942bb4b6b0e 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -43,7 +43,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController def usage_data respond_to do |format| format.html do - usage_data_json = JSON.pretty_generate(Gitlab::UsageData.data) + usage_data_json = Gitlab::Json.pretty_generate(Gitlab::UsageData.data) render html: Gitlab::Highlight.highlight('payload.json', usage_data_json, language: 'json') end diff --git a/app/controllers/import/google_code_controller.rb b/app/controllers/import/google_code_controller.rb index 4dddfbcd20d..03bde0345e3 100644 --- a/app/controllers/import/google_code_controller.rb +++ b/app/controllers/import/google_code_controller.rb @@ -15,7 +15,7 @@ class Import::GoogleCodeController < Import::BaseController end begin - dump = JSON.parse(dump_file.read) + dump = Gitlab::Json.parse(dump_file.read) rescue return redirect_back_or_default(options: { alert: _("The uploaded file is not a valid Google Takeout archive.") }) end @@ -42,7 +42,7 @@ class Import::GoogleCodeController < Import::BaseController user_map_json = "{}" if user_map_json.blank? begin - user_map = JSON.parse(user_map_json) + user_map = Gitlab::Json.parse(user_map_json) rescue flash.now[:alert] = _("The entered user map is not a valid JSON user map.") diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb index 876789e0d4a..8a32d3c8a3f 100644 --- a/app/helpers/icons_helper.rb +++ b/app/helpers/icons_helper.rb @@ -158,6 +158,6 @@ module IconsHelper def known_sprites return if Rails.env.production? - @known_sprites ||= JSON.parse(File.read(Rails.root.join('node_modules/@gitlab/svgs/dist/icons.json')))['icons'] + @known_sprites ||= Gitlab::Json.parse(File.read(Rails.root.join('node_modules/@gitlab/svgs/dist/icons.json')))['icons'] end end diff --git a/app/models/blob_viewer/dependency_manager.rb b/app/models/blob_viewer/dependency_manager.rb index 711465c7c79..a851f22bfcd 100644 --- a/app/models/blob_viewer/dependency_manager.rb +++ b/app/models/blob_viewer/dependency_manager.rb @@ -32,7 +32,7 @@ module BlobViewer def json_data @json_data ||= begin prepare! - JSON.parse(blob.data) + Gitlab::Json.parse(blob.data) rescue {} end diff --git a/app/models/clusters/applications/jupyter.rb b/app/models/clusters/applications/jupyter.rb index 42fa4a6f179..056ea355de6 100644 --- a/app/models/clusters/applications/jupyter.rb +++ b/app/models/clusters/applications/jupyter.rb @@ -5,7 +5,7 @@ require 'securerandom' module Clusters module Applications class Jupyter < ApplicationRecord - VERSION = '0.9.0-beta.2' + VERSION = '0.9.0' self.table_name = 'clusters_applications_jupyter' diff --git a/app/models/concerns/diff_positionable_note.rb b/app/models/concerns/diff_positionable_note.rb index 6484a3157b1..8590bc7f4eb 100644 --- a/app/models/concerns/diff_positionable_note.rb +++ b/app/models/concerns/diff_positionable_note.rb @@ -17,7 +17,7 @@ module DiffPositionableNote %i(original_position position change_position).each do |meth| define_method "#{meth}=" do |new_position| if new_position.is_a?(String) - new_position = JSON.parse(new_position) rescue nil + new_position = Gitlab::Json.parse(new_position) rescue nil end if new_position.is_a?(Hash) diff --git a/app/models/concerns/redis_cacheable.rb b/app/models/concerns/redis_cacheable.rb index 2f23467dc78..2d4ed51ce3b 100644 --- a/app/models/concerns/redis_cacheable.rb +++ b/app/models/concerns/redis_cacheable.rb @@ -43,7 +43,7 @@ module RedisCacheable strong_memoize(:cached_attributes) do Gitlab::Redis::Cache.with do |redis| data = redis.get(cache_attribute_key) - JSON.parse(data, symbolize_names: true) if data + Gitlab::Json.parse(data, symbolize_names: true) if data end end end diff --git a/app/models/project_services/mock_monitoring_service.rb b/app/models/project_services/mock_monitoring_service.rb index bcf8f1df5da..25ae0f6b60d 100644 --- a/app/models/project_services/mock_monitoring_service.rb +++ b/app/models/project_services/mock_monitoring_service.rb @@ -14,7 +14,7 @@ class MockMonitoringService < MonitoringService end def metrics(environment) - JSON.parse(File.read(Rails.root + 'spec/fixtures/metrics.json')) + Gitlab::Json.parse(File.read(Rails.root + 'spec/fixtures/metrics.json')) end def can_test? diff --git a/app/models/sent_notification.rb b/app/models/sent_notification.rb index f3a9293376f..1bfcad02f38 100644 --- a/app/models/sent_notification.rb +++ b/app/models/sent_notification.rb @@ -76,7 +76,7 @@ class SentNotification < ApplicationRecord def position=(new_position) if new_position.is_a?(String) - new_position = JSON.parse(new_position) rescue nil + new_position = Gitlab::Json.parse(new_position) rescue nil end if new_position.is_a?(Hash) diff --git a/app/services/metrics/dashboard/grafana_metric_embed_service.rb b/app/services/metrics/dashboard/grafana_metric_embed_service.rb index 5fd1e0dda89..d9ce2c5e905 100644 --- a/app/services/metrics/dashboard/grafana_metric_embed_service.rb +++ b/app/services/metrics/dashboard/grafana_metric_embed_service.rb @@ -113,7 +113,7 @@ module Metrics end def parse_json(json) - JSON.parse(json, symbolize_names: true) + Gitlab::Json.parse(json, symbolize_names: true) rescue JSON::ParserError raise DashboardProcessingError.new('Grafana response contains invalid json') end diff --git a/app/services/metrics/dashboard/transient_embed_service.rb b/app/services/metrics/dashboard/transient_embed_service.rb index b13fc1e4fa8..cb6ca215447 100644 --- a/app/services/metrics/dashboard/transient_embed_service.rb +++ b/app/services/metrics/dashboard/transient_embed_service.rb @@ -23,7 +23,7 @@ module Metrics override :get_raw_dashboard def get_raw_dashboard - JSON.parse(params[:embed_json]) + Gitlab::Json.parse(params[:embed_json]) rescue JSON::ParserError => e invalid_embed_json!(e.message) end diff --git a/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb b/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb index 48a21bf94ba..efd410088ab 100644 --- a/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb +++ b/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb @@ -69,7 +69,7 @@ module Projects # application/vnd.git-lfs+json # (https://github.com/git-lfs/git-lfs/blob/master/docs/api/batch.md#requests), # HTTParty does not know this is actually JSON. - data = JSON.parse(response.body) + data = Gitlab::Json.parse(response.body) raise DownloadLinksError, "LFS Batch API did return any objects" unless data.is_a?(Hash) && data.key?('objects') diff --git a/app/services/projects/lsif_data_service.rb b/app/services/projects/lsif_data_service.rb index 142a5a910d4..5e7055b3309 100644 --- a/app/services/projects/lsif_data_service.rb +++ b/app/services/projects/lsif_data_service.rb @@ -42,7 +42,7 @@ module Projects file.open do |stream| Zlib::GzipReader.wrap(stream) do |gz_stream| - data = JSON.parse(gz_stream.read) + data = Gitlab::Json.parse(gz_stream.read) end end diff --git a/app/workers/irker_worker.rb b/app/workers/irker_worker.rb index 73bc050d7be..7622f40a949 100644 --- a/app/workers/irker_worker.rb +++ b/app/workers/irker_worker.rb @@ -53,7 +53,7 @@ class IrkerWorker # rubocop:disable Scalability/IdempotentWorker def sendtoirker(privmsg) to_send = { to: @channels, privmsg: privmsg } - @socket.puts JSON.dump(to_send) + @socket.puts Gitlab::Json.dump(to_send) end def close_connection diff --git a/changelogs/unreleased/207267-regex-keep-frontend.yml b/changelogs/unreleased/207267-regex-keep-frontend.yml new file mode 100644 index 00000000000..8ff20c390eb --- /dev/null +++ b/changelogs/unreleased/207267-regex-keep-frontend.yml @@ -0,0 +1,5 @@ +--- +title: Add new keep regex to expiration policy settings ui +merge_request: 29940 +author: +type: changed diff --git a/changelogs/unreleased/update-jupyter-to-0-9-0.yml b/changelogs/unreleased/update-jupyter-to-0-9-0.yml new file mode 100644 index 00000000000..2e309513b87 --- /dev/null +++ b/changelogs/unreleased/update-jupyter-to-0-9-0.yml @@ -0,0 +1,5 @@ +--- +title: Update managed jupyter chart to 0.9.0 (stable) +merge_request: 30393 +author: +type: changed diff --git a/doc/user/packages/container_registry/index.md b/doc/user/packages/container_registry/index.md index 9d50c23b780..9f4702a09e5 100644 --- a/doc/user/packages/container_registry/index.md +++ b/doc/user/packages/container_registry/index.md @@ -503,7 +503,7 @@ then goes through a process of excluding tags from it until only the ones to be 1. Evaluates the `name_regex`, excluding non-matching names from the list. 1. Excludes any tags that do not have a manifest (not part of the options). 1. Orders the remaining tags by `created_date`. -1. Excludes from the list the N tags based on the `keep_n` value (Expiration latest). +1. Excludes from the list the N tags based on the `keep_n` value (Number of tags to retain). 1. Excludes from the list the tags older than the `older_than` value (Expiration interval). 1. Finally, the remaining tags in the list are deleted from the Container Registry. @@ -518,7 +518,7 @@ The UI allows you to configure the following: - **Expiration policy:** enable or disable the expiration policy. - **Expiration interval:** how long tags are exempt from being deleted. - **Expiration schedule:** how often the cron job checking the tags should run. -- **Expiration latest:** how many tags to _always_ keep for each image. +- **Number of tags to retain:** how many tags to _always_ keep for each image. - **Docker tags with names matching this regex pattern will expire:** the regex used to determine what tags should be expired. To qualify all tags for expiration, use the default value of `.*`. ### Managing project expiration policy through the API diff --git a/doc/user/project/import/bitbucket.md b/doc/user/project/import/bitbucket.md index e7dd94d2794..56717858b53 100644 --- a/doc/user/project/import/bitbucket.md +++ b/doc/user/project/import/bitbucket.md @@ -42,7 +42,7 @@ The importer will create any new namespaces (groups) if they don't exist or in the case the namespace is taken, the repository will be imported under the user's namespace that started the import process. -## Importing your Bitbucket repositories +## Import your Bitbucket repositories 1. Sign in to GitLab and go to your dashboard. 1. Click on **New project**. @@ -60,3 +60,12 @@ namespace that started the import process. each project will be imported. ![Import projects](img/bitbucket_import_select_project_v12_3.png) + +## Troubleshooting + +If you have more than one Bitbucket account, be sure to sign in to the correct account. +If you've accidentally started the import process with the wrong account, follow these steps: + +1. Revoke GitLab access to your Bitbucket account, essentially reversing the process in the following procedure: [Import your Bitbucket repositories](#import-your-bitbucket-repositories). + +1. Sign out of the Bitbucket account. Follow the procedure linked from the previous step. diff --git a/doc/user/project/import/bitbucket_server.md b/doc/user/project/import/bitbucket_server.md index 99179c3190e..55df2d7294d 100644 --- a/doc/user/project/import/bitbucket_server.md +++ b/doc/user/project/import/bitbucket_server.md @@ -73,3 +73,7 @@ namespace that started the import process. imported. ![Import projects](img/bitbucket_server_import_select_project_v12_3.png) + +## Troubleshooting + +See the [troubleshooting](bitbucket.md#troubleshooting) section for [Bitbucket](bitbucket.md). diff --git a/doc/user/project/merge_requests/code_quality.md b/doc/user/project/merge_requests/code_quality.md index 4b3bfac6e76..beb90e30906 100644 --- a/doc/user/project/merge_requests/code_quality.md +++ b/doc/user/project/merge_requests/code_quality.md @@ -65,10 +65,10 @@ also requires the GitLab Runner 11.5 or later. For earlier versions, use the This example shows how to run Code Quality on your code by using GitLab CI/CD and Docker. -First, you need GitLab Runner with: +First, you need GitLab Runner configured: -- The [docker-in-docker executor](../../../ci/docker/using_docker_build.md#use-docker-in-docker-workflow-with-docker-executor). -- Enough disk space to handle generated Code Quality files. For example on the [GitLab project](https://gitlab.com/gitlab-org/gitlab) the files are approximately 7 GB. +- For the [docker-in-docker workflow](../../../ci/docker/using_docker_build.md#use-docker-in-docker-workflow-with-docker-executor). +- With enough disk space to handle generated Code Quality files. For example on the [GitLab project](https://gitlab.com/gitlab-org/gitlab) the files are approximately 7 GB. Once you set up the Runner, include the CodeQuality template in your CI config: diff --git a/doc/user/search/index.md b/doc/user/search/index.md index ed2a4b36372..eac3d714831 100644 --- a/doc/user/search/index.md +++ b/doc/user/search/index.md @@ -41,7 +41,10 @@ groups: - [Label](../project/labels.md) - My-reaction - Confidential - - Epic ([Introduced](https://gitlab.com/gitlab-org/gitlab/issues/195704) in GitLab 12.9) + - Epic ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/195704) in GitLab 12.9), + including [child epic](../group/epics/index.md#multi-level-child-epics-ultimate) + ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9029) in + [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.0) - Search for this text 1. Select or type the operator to use for filtering the attribute. The following operators are available: diff --git a/lib/gitlab/database/with_lock_retries.rb b/lib/gitlab/database/with_lock_retries.rb index 2f36bfa1480..bebcba6f42e 100644 --- a/lib/gitlab/database/with_lock_retries.rb +++ b/lib/gitlab/database/with_lock_retries.rb @@ -78,12 +78,18 @@ module Gitlab run_block_with_transaction rescue ActiveRecord::LockWaitTimeout if retry_with_lock_timeout? + disable_idle_in_transaction_timeout wait_until_next_retry + reset_db_settings retry else + reset_db_settings run_block_without_lock_timeout end + + ensure + reset_db_settings end end @@ -153,6 +159,14 @@ module Gitlab def current_sleep_time_in_seconds timing_configuration[current_iteration - 1][1].to_f end + + def disable_idle_in_transaction_timeout + execute("SET LOCAL idle_in_transaction_session_timeout TO '0'") + end + + def reset_db_settings + execute('RESET idle_in_transaction_session_timeout; RESET lock_timeout') + end end end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index aa22bea0367..bff051d896f 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -5606,9 +5606,6 @@ msgstr "" msgid "ContainerRegistry|Docker tag expiration policy is %{toggleStatus}" msgstr "" -msgid "ContainerRegistry|Docker tags with names matching this regex pattern will expire:" -msgstr "" - msgid "ContainerRegistry|Edit Settings" msgstr "" @@ -5654,7 +5651,10 @@ msgstr "" msgid "ContainerRegistry|Quick Start" msgstr "" -msgid "ContainerRegistry|Regular expressions such as %{codeStart}.*-test%{codeEnd} or %{codeStart}dev-.*%{codeEnd} are supported. To select all tags, use %{codeStart}.*%{codeEnd}" +msgid "ContainerRegistry|Regular expressions such as %{codeStart}.*-test%{codeEnd} or %{codeStart}dev-.*%{codeEnd} are supported" +msgstr "" + +msgid "ContainerRegistry|Regular expressions such as %{codeStart}.*-test%{codeEnd} or %{codeStart}dev-.*%{codeEnd} are supported. To select all tags, use %{codeStart}.*%{codeEnd}" msgstr "" msgid "ContainerRegistry|Remove repository" @@ -5707,6 +5707,12 @@ msgstr "" msgid "ContainerRegistry|Tags deleted successfully" msgstr "" +msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}be preserved:%{italicEnd}" +msgstr "" + +msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}" +msgstr "" + msgid "ContainerRegistry|The Container Registry tag expiration and retention policies for this project have not been enabled." msgstr "" diff --git a/spec/controllers/oauth/token_info_controller_spec.rb b/spec/controllers/oauth/token_info_controller_spec.rb index 4b3539879df..4658c2702ca 100644 --- a/spec/controllers/oauth/token_info_controller_spec.rb +++ b/spec/controllers/oauth/token_info_controller_spec.rb @@ -9,7 +9,7 @@ RSpec.describe Oauth::TokenInfoController do get :show expect(response).to have_gitlab_http_status(:unauthorized) - expect(JSON.parse(response.body)).to include('error' => 'invalid_request') + expect(Gitlab::Json.parse(response.body)).to include('error' => 'invalid_request') end end @@ -23,7 +23,7 @@ RSpec.describe Oauth::TokenInfoController do get :show, params: { access_token: access_token.token } expect(response).to have_gitlab_http_status(:ok) - expect(JSON.parse(response.body)).to eq( + expect(Gitlab::Json.parse(response.body)).to eq( 'scope' => %w[api], 'scopes' => %w[api], 'created_at' => access_token.created_at.to_i, @@ -40,7 +40,7 @@ RSpec.describe Oauth::TokenInfoController do get :show, params: { access_token: 'unknown_token' } expect(response).to have_gitlab_http_status(:unauthorized) - expect(JSON.parse(response.body)).to include('error' => 'invalid_request') + expect(Gitlab::Json.parse(response.body)).to include('error' => 'invalid_request') end end @@ -53,7 +53,7 @@ RSpec.describe Oauth::TokenInfoController do get :show, params: { access_token: access_token.token } expect(response).to have_gitlab_http_status(:unauthorized) - expect(JSON.parse(response.body)).to include('error' => 'invalid_request') + expect(Gitlab::Json.parse(response.body)).to include('error' => 'invalid_request') end end @@ -64,7 +64,7 @@ RSpec.describe Oauth::TokenInfoController do get :show, params: { access_token: access_token.token } expect(response).to have_gitlab_http_status(:unauthorized) - expect(JSON.parse(response.body)).to include('error' => 'invalid_request') + expect(Gitlab::Json.parse(response.body)).to include('error' => 'invalid_request') end end end diff --git a/spec/controllers/projects/artifacts_controller_spec.rb b/spec/controllers/projects/artifacts_controller_spec.rb index c59983d5138..aa3371f7ddf 100644 --- a/spec/controllers/projects/artifacts_controller_spec.rb +++ b/spec/controllers/projects/artifacts_controller_spec.rb @@ -334,7 +334,7 @@ describe Projects::ArtifactsController do def params @params ||= begin base64_params = send_data.sub(/\Aartifacts\-entry:/, '') - JSON.parse(Base64.urlsafe_decode64(base64_params)) + Gitlab::Json.parse(Base64.urlsafe_decode64(base64_params)) end end end diff --git a/spec/controllers/projects/cycle_analytics/events_controller_spec.rb b/spec/controllers/projects/cycle_analytics/events_controller_spec.rb index b828c678d0c..942e095d669 100644 --- a/spec/controllers/projects/cycle_analytics/events_controller_spec.rb +++ b/spec/controllers/projects/cycle_analytics/events_controller_spec.rb @@ -17,7 +17,7 @@ describe Projects::CycleAnalytics::EventsController do get_issue expect(response).to be_successful - expect(JSON.parse(response.body)['events']).to be_empty + expect(Gitlab::Json.parse(response.body)['events']).to be_empty end end @@ -38,7 +38,7 @@ describe Projects::CycleAnalytics::EventsController do it 'contains event detais' do get_issue - events = JSON.parse(response.body)['events'] + events = Gitlab::Json.parse(response.body)['events'] expect(events).not_to be_empty expect(events.first).to include('title', 'author', 'iid', 'total_time', 'created_at', 'url') @@ -51,7 +51,7 @@ describe Projects::CycleAnalytics::EventsController do expect(response).to be_successful - expect(JSON.parse(response.body)['events']).to be_empty + expect(Gitlab::Json.parse(response.body)['events']).to be_empty end end end diff --git a/spec/controllers/projects/environments/prometheus_api_controller_spec.rb b/spec/controllers/projects/environments/prometheus_api_controller_spec.rb index 793c10f0b21..fcb9293d4a9 100644 --- a/spec/controllers/projects/environments/prometheus_api_controller_spec.rb +++ b/spec/controllers/projects/environments/prometheus_api_controller_spec.rb @@ -38,7 +38,7 @@ describe Projects::Environments::PrometheusApiController do context 'with success result' do let(:service_result) { { status: :success, body: prometheus_body } } let(:prometheus_body) { '{"status":"success"}' } - let(:prometheus_json_body) { JSON.parse(prometheus_body) } + let(:prometheus_json_body) { Gitlab::Json.parse(prometheus_body) } it 'returns prometheus response' do get :proxy, params: environment_params diff --git a/spec/controllers/projects/logs_controller_spec.rb b/spec/controllers/projects/logs_controller_spec.rb index ea71dbe45aa..cc0690788c7 100644 --- a/spec/controllers/projects/logs_controller_spec.rb +++ b/spec/controllers/projects/logs_controller_spec.rb @@ -50,7 +50,7 @@ describe Projects::LogsController do container_name: container } end - let(:service_result_json) { JSON.parse(service_result.to_json) } + let(:service_result_json) { Gitlab::Json.parse(service_result.to_json) } let_it_be(:cluster) { create(:cluster, :provided_by_gcp, environment_scope: '*', projects: [project]) } diff --git a/spec/features/error_tracking/user_filters_errors_by_status_spec.rb b/spec/features/error_tracking/user_filters_errors_by_status_spec.rb index 51e29e2a5ec..4b5bc16c4db 100644 --- a/spec/features/error_tracking/user_filters_errors_by_status_spec.rb +++ b/spec/features/error_tracking/user_filters_errors_by_status_spec.rb @@ -6,7 +6,7 @@ describe 'When a user filters Sentry errors by status', :js, :use_clean_rails_me include_context 'sentry error tracking context feature' let_it_be(:issues_response_body) { fixture_file('sentry/issues_sample_response.json') } - let_it_be(:filtered_errors_by_status_response) { JSON.parse(issues_response_body).filter { |error| error['status'] == 'ignored' }.to_json } + let_it_be(:filtered_errors_by_status_response) { Gitlab::Json.parse(issues_response_body).filter { |error| error['status'] == 'ignored' }.to_json } let(:issues_api_url) { "#{sentry_api_urls.issues_url}?limit=20&query=is:unresolved" } let(:issues_api_url_filter) { "#{sentry_api_urls.issues_url}?limit=20&query=is:ignored" } let(:auth_token) {{ 'Authorization' => 'Bearer access_token_123' }} diff --git a/spec/features/error_tracking/user_sees_error_index_spec.rb b/spec/features/error_tracking/user_sees_error_index_spec.rb index 842e4a2e8b5..34a3a4b5a49 100644 --- a/spec/features/error_tracking/user_sees_error_index_spec.rb +++ b/spec/features/error_tracking/user_sees_error_index_spec.rb @@ -6,7 +6,7 @@ describe 'View error index page', :js, :use_clean_rails_memory_store_caching, :s include_context 'sentry error tracking context feature' let_it_be(:issues_response_body) { fixture_file('sentry/issues_sample_response.json') } - let_it_be(:issues_response) { JSON.parse(issues_response_body) } + let_it_be(:issues_response) { Gitlab::Json.parse(issues_response_body) } let(:issues_api_url) { "#{sentry_api_urls.issues_url}?limit=20&query=is:unresolved" } before do diff --git a/spec/features/projects/import_export/export_file_spec.rb b/spec/features/projects/import_export/export_file_spec.rb index 7ee8f42e6ef..1d6d5ae1b4d 100644 --- a/spec/features/projects/import_export/export_file_spec.rb +++ b/spec/features/projects/import_export/export_file_spec.rb @@ -52,7 +52,7 @@ describe 'Import/Export - project export integration test', :js do project_json_path = File.join(tmpdir, 'project.json') expect(File).to exist(project_json_path) - project_hash = JSON.parse(IO.read(project_json_path)) + project_hash = Gitlab::Json.parse(IO.read(project_json_path)) sensitive_words.each do |sensitive_word| found = find_sensitive_attributes(sensitive_word, project_hash) @@ -78,7 +78,7 @@ describe 'Import/Export - project export integration test', :js do expect(File).to exist(project_json_path) relations = [] - relations << JSON.parse(IO.read(project_json_path)) + relations << Gitlab::Json.parse(IO.read(project_json_path)) Dir.glob(File.join(tmpdir, 'tree/project', '*.ndjson')) do |rb_filename| File.foreach(rb_filename) do |line| json = ActiveSupport::JSON.decode(line) diff --git a/spec/features/projects/settings/operations_settings_spec.rb b/spec/features/projects/settings/operations_settings_spec.rb index 3c9102431e8..752353cf2f5 100644 --- a/spec/features/projects/settings/operations_settings_spec.rb +++ b/spec/features/projects/settings/operations_settings_spec.rb @@ -76,7 +76,7 @@ describe 'Projects > Settings > For a forked project', :js do context 'success path' do let(:projects_sample_response) do Gitlab::Utils.deep_indifferent_access( - JSON.parse(fixture_file('sentry/list_projects_sample_response.json')) + Gitlab::Json.parse(fixture_file('sentry/list_projects_sample_response.json')) ) end diff --git a/spec/features/projects/settings/registry_settings_spec.rb b/spec/features/projects/settings/registry_settings_spec.rb index 74d3544ce92..ba92e8bc516 100644 --- a/spec/features/projects/settings/registry_settings_spec.rb +++ b/spec/features/projects/settings/registry_settings_spec.rb @@ -29,7 +29,7 @@ describe 'Project > Settings > CI/CD > Container registry tag expiration policy' select('7 days until tags are automatically removed', from: 'Expiration interval:') select('Every day', from: 'Expiration schedule:') select('50 tags per image name', from: 'Number of tags to retain:') - fill_in('Docker tags with names matching this regex pattern will expire:', with: '*-production') + fill_in('Tags with names matching this regex pattern will expire:', with: '*-production') end submit_button = find('.card-footer .btn.btn-success') expect(submit_button).not_to be_disabled diff --git a/spec/javascripts/integrations/integration_settings_form_spec.js b/spec/frontend/integrations/integration_settings_form_spec.js index 72d04be822f..c117a37ff2f 100644 --- a/spec/javascripts/integrations/integration_settings_form_spec.js +++ b/spec/frontend/integrations/integration_settings_form_spec.js @@ -16,7 +16,7 @@ describe('IntegrationSettingsForm', () => { beforeEach(() => { integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form'); - spyOn(integrationSettingsForm, 'init'); + jest.spyOn(integrationSettingsForm, 'init').mockImplementation(() => {}); }); it('should initialize form element refs on class object', () => { @@ -130,7 +130,7 @@ describe('IntegrationSettingsForm', () => { beforeEach(() => { mock = new MockAdaptor(axios); - spyOn(axios, 'put').and.callThrough(); + jest.spyOn(axios, 'put'); integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form'); // eslint-disable-next-line no-jquery/no-serialize @@ -141,18 +141,13 @@ describe('IntegrationSettingsForm', () => { mock.restore(); }); - it('should make an ajax request with provided `formData`', done => { - integrationSettingsForm - .testSettings(formData) - .then(() => { - expect(axios.put).toHaveBeenCalledWith(integrationSettingsForm.testEndPoint, formData); - - done(); - }) - .catch(done.fail); + it('should make an ajax request with provided `formData`', () => { + return integrationSettingsForm.testSettings(formData).then(() => { + expect(axios.put).toHaveBeenCalledWith(integrationSettingsForm.testEndPoint, formData); + }); }); - it('should show error Flash with `Save anyway` action if ajax request responds with error in test', done => { + it('should show error Flash with `Save anyway` action if ajax request responds with error in test', () => { const errorMessage = 'Test failed.'; mock.onPut(integrationSettingsForm.testEndPoint).reply(200, { error: true, @@ -161,32 +156,27 @@ describe('IntegrationSettingsForm', () => { test_failed: true, }); - integrationSettingsForm - .testSettings(formData) - .then(() => { - const $flashContainer = $('.flash-container'); - - expect( - $flashContainer - .find('.flash-text') - .text() - .trim(), - ).toEqual('Test failed. some error'); - - expect($flashContainer.find('.flash-action')).toBeDefined(); - expect( - $flashContainer - .find('.flash-action') - .text() - .trim(), - ).toEqual('Save anyway'); - - done(); - }) - .catch(done.fail); + return integrationSettingsForm.testSettings(formData).then(() => { + const $flashContainer = $('.flash-container'); + + expect( + $flashContainer + .find('.flash-text') + .text() + .trim(), + ).toEqual('Test failed. some error'); + + expect($flashContainer.find('.flash-action')).toBeDefined(); + expect( + $flashContainer + .find('.flash-action') + .text() + .trim(), + ).toEqual('Save anyway'); + }); }); - it('should not show error Flash with `Save anyway` action if ajax request responds with error in validation', done => { + it('should not show error Flash with `Save anyway` action if ajax request responds with error in validation', () => { const errorMessage = 'Validations failed.'; mock.onPut(integrationSettingsForm.testEndPoint).reply(200, { error: true, @@ -195,50 +185,40 @@ describe('IntegrationSettingsForm', () => { test_failed: false, }); - integrationSettingsForm - .testSettings(formData) - .then(() => { - const $flashContainer = $('.flash-container'); - - expect( - $flashContainer - .find('.flash-text') - .text() - .trim(), - ).toEqual('Validations failed. some error'); - - expect($flashContainer.find('.flash-action')).toBeDefined(); - expect( - $flashContainer - .find('.flash-action') - .text() - .trim(), - ).toEqual(''); - - done(); - }) - .catch(done.fail); + return integrationSettingsForm.testSettings(formData).then(() => { + const $flashContainer = $('.flash-container'); + + expect( + $flashContainer + .find('.flash-text') + .text() + .trim(), + ).toEqual('Validations failed. some error'); + + expect($flashContainer.find('.flash-action')).toBeDefined(); + expect( + $flashContainer + .find('.flash-action') + .text() + .trim(), + ).toEqual(''); + }); }); - it('should submit form if ajax request responds without any error in test', done => { - spyOn(integrationSettingsForm.$form, 'submit'); + it('should submit form if ajax request responds without any error in test', () => { + jest.spyOn(integrationSettingsForm.$form, 'submit').mockImplementation(() => {}); mock.onPut(integrationSettingsForm.testEndPoint).reply(200, { error: false, }); - integrationSettingsForm - .testSettings(formData) - .then(() => { - expect(integrationSettingsForm.$form.submit).toHaveBeenCalled(); - - done(); - }) - .catch(done.fail); + return integrationSettingsForm.testSettings(formData).then(() => { + expect(integrationSettingsForm.$form.submit).toHaveBeenCalled(); + }); }); - it('should submit form when clicked on `Save anyway` action of error Flash', done => { - spyOn(integrationSettingsForm.$form, 'submit'); + it('should submit form when clicked on `Save anyway` action of error Flash', () => { + jest.spyOn(integrationSettingsForm.$form, 'submit').mockImplementation(() => {}); const errorMessage = 'Test failed.'; mock.onPut(integrationSettingsForm.testEndPoint).reply(200, { @@ -247,7 +227,7 @@ describe('IntegrationSettingsForm', () => { test_failed: true, }); - integrationSettingsForm + return integrationSettingsForm .testSettings(formData) .then(() => { const $flashAction = $('.flash-container .flash-action'); @@ -258,44 +238,31 @@ describe('IntegrationSettingsForm', () => { }) .then(() => { expect(integrationSettingsForm.$form.submit).toHaveBeenCalled(); - - done(); - }) - .catch(done.fail); + }); }); - it('should show error Flash if ajax request failed', done => { + it('should show error Flash if ajax request failed', () => { const errorMessage = 'Something went wrong on our end.'; mock.onPut(integrationSettingsForm.testEndPoint).networkError(); - integrationSettingsForm - .testSettings(formData) - .then(() => { - expect( - $('.flash-container .flash-text') - .text() - .trim(), - ).toEqual(errorMessage); - - done(); - }) - .catch(done.fail); + return integrationSettingsForm.testSettings(formData).then(() => { + expect( + $('.flash-container .flash-text') + .text() + .trim(), + ).toEqual(errorMessage); + }); }); - it('should always call `toggleSubmitBtnState` with `false` once request is completed', done => { + it('should always call `toggleSubmitBtnState` with `false` once request is completed', () => { mock.onPut(integrationSettingsForm.testEndPoint).networkError(); - spyOn(integrationSettingsForm, 'toggleSubmitBtnState'); + jest.spyOn(integrationSettingsForm, 'toggleSubmitBtnState').mockImplementation(() => {}); - integrationSettingsForm - .testSettings(formData) - .then(() => { - expect(integrationSettingsForm.toggleSubmitBtnState).toHaveBeenCalledWith(false); - - done(); - }) - .catch(done.fail); + return integrationSettingsForm.testSettings(formData).then(() => { + expect(integrationSettingsForm.toggleSubmitBtnState).toHaveBeenCalledWith(false); + }); }); }); }); diff --git a/spec/frontend/registry/settings/store/getters_spec.js b/spec/frontend/registry/settings/store/getters_spec.js index 944057ebc9f..b781d09466c 100644 --- a/spec/frontend/registry/settings/store/getters_spec.js +++ b/spec/frontend/registry/settings/store/getters_spec.js @@ -4,9 +4,12 @@ import { formOptions } from '../../shared/mock_data'; describe('Getters registry settings store', () => { const settings = { + enabled: true, cadence: 'foo', keep_n: 'bar', older_than: 'baz', + name_regex: 'name-foo', + name_regex_keep: 'name-keep-bar', }; describe.each` @@ -29,6 +32,17 @@ describe('Getters registry settings store', () => { }); }); + describe('getSettings', () => { + it('returns the content of settings', () => { + const computedGetters = { + getCadence: settings.cadence, + getOlderThan: settings.older_than, + getKeepN: settings.keep_n, + }; + expect(getters.getSettings({ settings }, computedGetters)).toEqual(settings); + }); + }); + describe('getIsEdited', () => { it('returns false when original is equal to settings', () => { const same = { foo: 'bar' }; diff --git a/spec/frontend/registry/shared/components/__snapshots__/expiration_policy_fields_spec.js.snap b/spec/frontend/registry/shared/components/__snapshots__/expiration_policy_fields_spec.js.snap index 6e7bc0491ce..a9034b81d2f 100644 --- a/spec/frontend/registry/shared/components/__snapshots__/expiration_policy_fields_spec.js.snap +++ b/spec/frontend/registry/shared/components/__snapshots__/expiration_policy_fields_spec.js.snap @@ -117,11 +117,11 @@ exports[`Expiration Policy Form renders 1`] = ` <gl-form-group-stub id="expiration-policy-name-matching-group" invalid-feedback="The value of this input should be less than 255 characters" - label="Docker tags with names matching this regex pattern will expire:" label-align="right" label-cols="3" label-for="expiration-policy-name-matching" > + <gl-form-textarea-stub disabled="true" id="expiration-policy-name-matching" @@ -130,5 +130,21 @@ exports[`Expiration Policy Form renders 1`] = ` value="" /> </gl-form-group-stub> + <gl-form-group-stub + id="expiration-policy-keep-name-group" + invalid-feedback="The value of this input should be less than 255 characters" + label-align="right" + label-cols="3" + label-for="expiration-policy-keep-name" + > + + <gl-form-textarea-stub + disabled="true" + id="expiration-policy-keep-name" + placeholder="" + trim="" + value="" + /> + </gl-form-group-stub> </div> `; diff --git a/spec/frontend/registry/shared/components/expiration_policy_fields_spec.js b/spec/frontend/registry/shared/components/expiration_policy_fields_spec.js index 3782bfeaac4..4825351a6d3 100644 --- a/spec/frontend/registry/shared/components/expiration_policy_fields_spec.js +++ b/spec/frontend/registry/shared/components/expiration_policy_fields_spec.js @@ -40,12 +40,13 @@ describe('Expiration Policy Form', () => { }); describe.each` - elementName | modelName | value | disabledByToggle - ${'toggle'} | ${'enabled'} | ${true} | ${'not disabled'} - ${'interval'} | ${'older_than'} | ${'foo'} | ${'disabled'} - ${'schedule'} | ${'cadence'} | ${'foo'} | ${'disabled'} - ${'latest'} | ${'keep_n'} | ${'foo'} | ${'disabled'} - ${'name-matching'} | ${'name_regex'} | ${'foo'} | ${'disabled'} + elementName | modelName | value | disabledByToggle + ${'toggle'} | ${'enabled'} | ${true} | ${'not disabled'} + ${'interval'} | ${'older_than'} | ${'foo'} | ${'disabled'} + ${'schedule'} | ${'cadence'} | ${'foo'} | ${'disabled'} + ${'latest'} | ${'keep_n'} | ${'foo'} | ${'disabled'} + ${'name-matching'} | ${'name_regex'} | ${'foo'} | ${'disabled'} + ${'keep-name'} | ${'name_regex_keep'} | ${'bar'} | ${'disabled'} `( `${FORM_ELEMENTS_ID_PREFIX}-$elementName form element`, ({ elementName, modelName, value, disabledByToggle }) => { @@ -118,21 +119,26 @@ describe('Expiration Policy Form', () => { ${'schedule'} ${'latest'} ${'name-matching'} + ${'keep-name'} `(`${FORM_ELEMENTS_ID_PREFIX}-$elementName is disabled`, ({ elementName }) => { expect(findFormElements(elementName).attributes('disabled')).toBe('true'); }); }); - describe('form validation', () => { + describe.each` + modelName | elementName | stateVariable + ${'name_regex'} | ${'name-matching'} | ${'nameRegexState'} + ${'name_regex_keep'} | ${'keep-name'} | ${'nameKeepRegexState'} + `('regex textarea validation', ({ modelName, elementName, stateVariable }) => { describe(`when name regex is longer than ${NAME_REGEX_LENGTH}`, () => { const invalidString = new Array(NAME_REGEX_LENGTH + 2).join(','); beforeEach(() => { - mountComponent({ value: { name_regex: invalidString } }); + mountComponent({ value: { [modelName]: invalidString } }); }); - it('nameRegexState is false', () => { - expect(wrapper.vm.nameRegexState).toBe(false); + it(`${stateVariable} is false`, () => { + expect(wrapper.vm.textAreaState[stateVariable]).toBe(false); }); it('emit the @invalidated event', () => { @@ -141,17 +147,20 @@ describe('Expiration Policy Form', () => { }); it('if the user did not type validation is null', () => { - mountComponent({ value: { name_regex: '' } }); + mountComponent({ value: { [modelName]: '' } }); return wrapper.vm.$nextTick().then(() => { - expect(wrapper.vm.nameRegexState).toBe(null); + expect(wrapper.vm.textAreaState[stateVariable]).toBe(null); expect(wrapper.emitted('validated')).toBeTruthy(); }); }); it(`if the user typed and is less than ${NAME_REGEX_LENGTH} state is true`, () => { - mountComponent({ value: { name_regex: 'foo' } }); + mountComponent({ value: { [modelName]: 'foo' } }); return wrapper.vm.$nextTick().then(() => { - expect(wrapper.vm.nameRegexState).toBe(true); + const formGroup = findFormGroup(elementName); + const formElement = findFormElements(elementName, formGroup); + expect(formGroup.attributes('state')).toBeTruthy(); + expect(formElement.attributes('state')).toBeTruthy(); }); }); }); diff --git a/spec/frontend/static_site_editor/components/saved_changes_message_spec.js b/spec/frontend/static_site_editor/components/saved_changes_message_spec.js index 659e9be59d2..a63c3a83395 100644 --- a/spec/frontend/static_site_editor/components/saved_changes_message_spec.js +++ b/spec/frontend/static_site_editor/components/saved_changes_message_spec.js @@ -46,14 +46,11 @@ describe('~/static_site_editor/components/saved_changes_message.vue', () => { ${'branch'} | ${findBranchLink} | ${props.branch} ${'commit'} | ${findCommitLink} | ${props.commit} ${'merge request'} | ${findMergeRequestLink} | ${props.mergeRequest} - `('renders $desc link', ({ desc, findEl, prop }) => { + `('renders $desc link', ({ findEl, prop }) => { const el = findEl(); expect(el.exists()).toBe(true); expect(el.text()).toBe(prop.label); - - if (desc !== 'branch') { - expect(el.attributes('href')).toBe(prop.url); - } + expect(el.attributes('href')).toBe(prop.url); }); }); diff --git a/spec/frontend/static_site_editor/mock_data.js b/spec/frontend/static_site_editor/mock_data.js index 962047e6dd2..c90ecc96521 100644 --- a/spec/frontend/static_site_editor/mock_data.js +++ b/spec/frontend/static_site_editor/mock_data.js @@ -34,6 +34,9 @@ export const savedContentMeta = { }; export const submitChangesError = 'Could not save changes'; +export const commitBranchResponse = { + web_url: '/tree/root-master-patch-88195', +}; export const commitMultipleResponse = { short_id: 'ed899a2f4b5', web_url: '/commit/ed899a2f4b5', diff --git a/spec/frontend/static_site_editor/services/submit_content_changes_spec.js b/spec/frontend/static_site_editor/services/submit_content_changes_spec.js index 9a0bd88b57d..962950ec96c 100644 --- a/spec/frontend/static_site_editor/services/submit_content_changes_spec.js +++ b/spec/frontend/static_site_editor/services/submit_content_changes_spec.js @@ -13,6 +13,7 @@ import submitContentChanges from '~/static_site_editor/services/submit_content_c import { username, projectId, + commitBranchResponse, commitMultipleResponse, createMergeRequestResponse, sourcePath, @@ -26,7 +27,7 @@ describe('submitContentChanges', () => { const branch = 'branch-name'; beforeEach(() => { - jest.spyOn(Api, 'createBranch').mockResolvedValue(); + jest.spyOn(Api, 'createBranch').mockResolvedValue({ data: commitBranchResponse }); jest.spyOn(Api, 'commitMultiple').mockResolvedValue({ data: commitMultipleResponse }); jest .spyOn(Api, 'createProjectMergeRequest') diff --git a/spec/helpers/todos_helper_spec.rb b/spec/helpers/todos_helper_spec.rb index 7c73b990338..69da5707b2a 100644 --- a/spec/helpers/todos_helper_spec.rb +++ b/spec/helpers/todos_helper_spec.rb @@ -32,7 +32,7 @@ describe TodosHelper do { 'id' => projects.first.id, 'text' => projects.first.full_name } ] - expect(JSON.parse(helper.todo_projects_options)).to match_array(expected_results) + expect(Gitlab::Json.parse(helper.todo_projects_options)).to match_array(expected_results) end end end diff --git a/spec/initializers/lograge_spec.rb b/spec/initializers/lograge_spec.rb index 48acdac74ac..c243217d2a2 100644 --- a/spec/initializers/lograge_spec.rb +++ b/spec/initializers/lograge_spec.rb @@ -123,7 +123,7 @@ describe 'lograge', type: :request do let(:logger) do Logger.new(log_output).tap { |logger| logger.formatter = ->(_, _, _, msg) { msg } } end - let(:log_data) { JSON.parse(log_output.string) } + let(:log_data) { Gitlab::Json.parse(log_output.string) } before do Lograge.logger = logger diff --git a/spec/lib/gitlab/database/with_lock_retries_spec.rb b/spec/lib/gitlab/database/with_lock_retries_spec.rb index b6321f2eab1..9c8c9749125 100644 --- a/spec/lib/gitlab/database/with_lock_retries_spec.rb +++ b/spec/lib/gitlab/database/with_lock_retries_spec.rb @@ -84,7 +84,7 @@ describe Gitlab::Database::WithLockRetries do subject.run do lock_attempts += 1 - if lock_attempts == retry_count # we reached the last retry iteration, if we kill the thread, the last try (no lock_timeout) will succeed) + if lock_attempts == retry_count # we reached the last retry iteration, if we kill the thread, the last try (no lock_timeout) will succeed lock_fiber.resume end @@ -106,9 +106,13 @@ describe Gitlab::Database::WithLockRetries do end context 'after the retries, without setting lock_timeout' do - let(:retry_count) { timing_configuration.size } + let(:retry_count) { timing_configuration.size + 1 } - it_behaves_like 'retriable exclusive lock on `projects`' + it_behaves_like 'retriable exclusive lock on `projects`' do + before do + expect(subject).to receive(:run_block_without_lock_timeout).and_call_original + end + end end context 'when statement timeout is reached' do @@ -129,11 +133,22 @@ describe Gitlab::Database::WithLockRetries do end end + context 'restore local database variables' do + it do + expect { subject.run {} }.not_to change { ActiveRecord::Base.connection.execute("SHOW lock_timeout").to_a } + end + + it do + expect { subject.run {} }.not_to change { ActiveRecord::Base.connection.execute("SHOW idle_in_transaction_session_timeout").to_a } + end + end + context 'casting durations correctly' do let(:timing_configuration) { [[0.015.seconds, 0.025.seconds], [0.015.seconds, 0.025.seconds]] } # 15ms, 25ms it 'executes `SET LOCAL lock_timeout` using the configured timeout value in milliseconds' do expect(ActiveRecord::Base.connection).to receive(:execute).with("SAVEPOINT active_record_1").and_call_original + expect(ActiveRecord::Base.connection).to receive(:execute).with('RESET idle_in_transaction_session_timeout; RESET lock_timeout').and_call_original expect(ActiveRecord::Base.connection).to receive(:execute).with("SET LOCAL lock_timeout TO '15ms'").and_call_original expect(ActiveRecord::Base.connection).to receive(:execute).with("RELEASE SAVEPOINT active_record_1").and_call_original diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index cae81540cd0..3df87e5d2b4 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -2351,7 +2351,7 @@ describe Ci::Pipeline, :mailer do def have_requested_pipeline_hook(status) have_requested(:post, stubbed_hostname(hook.url)).with do |req| - json_body = JSON.parse(req.body) + json_body = Gitlab::Json.parse(req.body) json_body['object_attributes']['status'] == status && json_body['builds'].length == 2 end diff --git a/spec/models/clusters/applications/jupyter_spec.rb b/spec/models/clusters/applications/jupyter_spec.rb index 3bc5088d1ab..937db9217f3 100644 --- a/spec/models/clusters/applications/jupyter_spec.rb +++ b/spec/models/clusters/applications/jupyter_spec.rb @@ -57,7 +57,7 @@ describe Clusters::Applications::Jupyter do it 'is initialized with 4 arguments' do expect(subject.name).to eq('jupyter') expect(subject.chart).to eq('jupyter/jupyterhub') - expect(subject.version).to eq('0.9.0-beta.2') + expect(subject.version).to eq('0.9.0') expect(subject).to be_rbac expect(subject.repository).to eq('https://jupyterhub.github.io/helm-chart/') @@ -76,7 +76,7 @@ describe Clusters::Applications::Jupyter do let(:jupyter) { create(:clusters_applications_jupyter, :errored, version: '0.0.1') } it 'is initialized with the locked version' do - expect(subject.version).to eq('0.9.0-beta.2') + expect(subject.version).to eq('0.9.0') end end end diff --git a/spec/models/container_repository_spec.rb b/spec/models/container_repository_spec.rb index 59bade3c841..1eecefe5d4a 100644 --- a/spec/models/container_repository_spec.rb +++ b/spec/models/container_repository_spec.rb @@ -19,7 +19,7 @@ describe ContainerRepository do .with(headers: { 'Accept' => ContainerRegistry::Client::ACCEPTED_TYPES.join(', ') }) .to_return( status: 200, - body: JSON.dump(tags: ['test_tag']), + body: Gitlab::Json.dump(tags: ['test_tag']), headers: { 'Content-Type' => 'application/json' }) end diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb index badc964db16..88a93eef214 100644 --- a/spec/models/project_services/irker_service_spec.rb +++ b/spec/models/project_services/irker_service_spec.rb @@ -65,7 +65,7 @@ describe IrkerService do conn = @irker_server.accept conn.each_line do |line| - msg = JSON.parse(line.chomp("\n")) + msg = Gitlab::Json.parse(line.chomp("\n")) expect(msg.keys).to match_array(%w(to privmsg)) expect(msg['to']).to match_array(["irc://chat.freenode.net/#commits", "irc://test.net/#test"]) diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb index 9b37a2d9ad5..12c06feacf3 100644 --- a/spec/models/snippet_spec.rb +++ b/spec/models/snippet_spec.rb @@ -529,11 +529,11 @@ describe Snippet do let(:snippet) { build(:snippet) } it 'excludes secret_token from generated json' do - expect(JSON.parse(to_json).keys).not_to include("secret_token") + expect(Gitlab::Json.parse(to_json).keys).not_to include("secret_token") end it 'does not override existing exclude option value' do - expect(JSON.parse(to_json(except: [:id])).keys).not_to include("secret_token", "id") + expect(Gitlab::Json.parse(to_json(except: [:id])).keys).not_to include("secret_token", "id") end def to_json(params = {}) diff --git a/spec/requests/api/graphql/boards/board_lists_query_spec.rb b/spec/requests/api/graphql/boards/board_lists_query_spec.rb index 3d2f6cc9046..f0927487f85 100644 --- a/spec/requests/api/graphql/boards/board_lists_query_spec.rb +++ b/spec/requests/api/graphql/boards/board_lists_query_spec.rb @@ -132,6 +132,6 @@ describe 'get board lists' do end def grab_list_data(response_body) - JSON.parse(response_body)['data'][board_parent_type]['boards']['edges'][0]['node']['lists']['edges'] + Gitlab::Json.parse(response_body)['data'][board_parent_type]['boards']['edges'][0]['node']['lists']['edges'] end end diff --git a/spec/requests/api/graphql/project/issues_spec.rb b/spec/requests/api/graphql/project/issues_spec.rb index cb751f786a8..256b45498f6 100644 --- a/spec/requests/api/graphql/project/issues_spec.rb +++ b/spec/requests/api/graphql/project/issues_spec.rb @@ -171,7 +171,7 @@ describe 'getting an issue list for a project' do cursored_query = query("sort: DUE_DATE_ASC, after: \"#{end_cursor}\"") post_graphql(cursored_query, current_user: current_user) - response_data = JSON.parse(response.body)['data']['project']['issues']['edges'] + response_data = Gitlab::Json.parse(response.body)['data']['project']['issues']['edges'] expect(grab_iids(response_data)).to eq([due_issue1.iid, due_issue4.iid, due_issue2.iid]) end @@ -193,7 +193,7 @@ describe 'getting an issue list for a project' do cursored_query = query("sort: DUE_DATE_DESC, after: \"#{end_cursor}\"") post_graphql(cursored_query, current_user: current_user) - response_data = JSON.parse(response.body)['data']['project']['issues']['edges'] + response_data = Gitlab::Json.parse(response.body)['data']['project']['issues']['edges'] expect(grab_iids(response_data)).to eq([due_issue3.iid, due_issue4.iid, due_issue2.iid]) end @@ -239,7 +239,7 @@ describe 'getting an issue list for a project' do cursored_query = query("sort: RELATIVE_POSITION_ASC, after: \"#{end_cursor}\"") post_graphql(cursored_query, current_user: current_user) - response_data = JSON.parse(response.body)['data']['project']['issues']['edges'] + response_data = Gitlab::Json.parse(response.body)['data']['project']['issues']['edges'] expect(grab_iids(response_data)).to eq([relative_issue1.iid, relative_issue4.iid, relative_issue2.iid]) end @@ -288,7 +288,7 @@ describe 'getting an issue list for a project' do cursored_query = query("sort: PRIORITY_ASC, after: \"#{end_cursor}\"") post_graphql(cursored_query, current_user: current_user) - response_data = JSON.parse(response.body)['data']['project']['issues']['edges'] + response_data = Gitlab::Json.parse(response.body)['data']['project']['issues']['edges'] expect(grab_iids(response_data)).to eq([priority_issue2.iid, priority_issue4.iid]) end @@ -310,7 +310,7 @@ describe 'getting an issue list for a project' do cursored_query = query("sort: PRIORITY_DESC, after: \"#{end_cursor}\"") post_graphql(cursored_query, current_user: current_user) - response_data = JSON.parse(response.body)['data']['project']['issues']['edges'] + response_data = Gitlab::Json.parse(response.body)['data']['project']['issues']['edges'] expect(grab_iids(response_data)).to eq([priority_issue2.iid, priority_issue4.iid]) end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 853155cea7a..f776faf6458 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -24,7 +24,7 @@ shared_examples 'languages and percentages JSON response' do get api("/projects/#{project.id}/languages", user) expect(response).to have_gitlab_http_status(:ok) - expect(JSON.parse(response.body)).to eq(expected_languages) + expect(Gitlab::Json.parse(response.body)).to eq(expected_languages) end end @@ -672,7 +672,7 @@ describe API::Projects do match[1] end - ids += JSON.parse(response.body).map { |p| p['id'] } + ids += Gitlab::Json.parse(response.body).map { |p| p['id'] } end expect(ids).to contain_exactly(*projects.map(&:id)) diff --git a/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb b/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb index 3eebbe98c9d..3547e1f0f8c 100644 --- a/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb +++ b/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb @@ -217,7 +217,7 @@ describe Metrics::Dashboard::DatasourceNameParser do include GrafanaApiHelpers let(:grafana_url) { valid_grafana_dashboard_link('https://gitlab.grafana.net') } - let(:grafana_dashboard) { JSON.parse(fixture_file('grafana/dashboard_response.json'), symbolize_names: true) } + let(:grafana_dashboard) { Gitlab::Json.parse(fixture_file('grafana/dashboard_response.json'), symbolize_names: true) } subject { described_class.new(grafana_url, grafana_dashboard).parse } diff --git a/spec/support/helpers/stub_gitlab_calls.rb b/spec/support/helpers/stub_gitlab_calls.rb index 40f4151c0fb..120d432655b 100644 --- a/spec/support/helpers/stub_gitlab_calls.rb +++ b/spec/support/helpers/stub_gitlab_calls.rb @@ -86,7 +86,7 @@ module StubGitlabCalls def stub_container_registry_tag_manifest_content fixture_path = 'spec/fixtures/container_registry/tag_manifest.json' - JSON.parse(File.read(Rails.root + fixture_path)) + Gitlab::Json.parse(File.read(Rails.root + fixture_path)) end def stub_container_registry_blob_content @@ -113,12 +113,12 @@ module StubGitlabCalls def stub_project_8 data = File.read(Rails.root.join('spec/support/gitlab_stubs/project_8.json')) - allow_any_instance_of(Network).to receive(:project).and_return(JSON.parse(data)) + allow_any_instance_of(Network).to receive(:project).and_return(Gitlab::Json.parse(data)) end def stub_project_8_hooks data = File.read(Rails.root.join('spec/support/gitlab_stubs/project_8_hooks.json')) - allow_any_instance_of(Network).to receive(:project_hooks).and_return(JSON.parse(data)) + allow_any_instance_of(Network).to receive(:project_hooks).and_return(Gitlab::Json.parse(data)) end def stub_projects @@ -143,7 +143,7 @@ module StubGitlabCalls def project_hash_array f = File.read(Rails.root.join('spec/support/gitlab_stubs/projects.json')) - JSON.parse f + Gitlab::Json.parse(f) end end diff --git a/spec/support/helpers/workhorse_helpers.rb b/spec/support/helpers/workhorse_helpers.rb index 53b36b3dd45..f16b6c1e910 100644 --- a/spec/support/helpers/workhorse_helpers.rb +++ b/spec/support/helpers/workhorse_helpers.rb @@ -11,7 +11,7 @@ module WorkhorseHelpers header = split_header.join(':') [ type, - JSON.parse(Base64.urlsafe_decode64(header)) + Gitlab::Json.parse(Base64.urlsafe_decode64(header)) ] end end diff --git a/spec/support/import_export/configuration_helper.rb b/spec/support/import_export/configuration_helper.rb index 4330c4314a8..6f67b0f3dd7 100644 --- a/spec/support/import_export/configuration_helper.rb +++ b/spec/support/import_export/configuration_helper.rb @@ -44,8 +44,8 @@ module ConfigurationHelper import_export_config = config_hash(config) excluded_attributes = import_export_config[:excluded_attributes][relation_name.to_sym] included_attributes = import_export_config[:included_attributes][relation_name.to_sym] - attributes = attributes - JSON.parse(excluded_attributes.to_json) if excluded_attributes - attributes = attributes & JSON.parse(included_attributes.to_json) if included_attributes + attributes = attributes - Gitlab::Json.parse(excluded_attributes.to_json) if excluded_attributes + attributes = attributes & Gitlab::Json.parse(included_attributes.to_json) if included_attributes attributes end diff --git a/spec/support/matchers/disallow_request_matchers.rb b/spec/support/matchers/disallow_request_matchers.rb index a161e3660cd..cb6f4bedbd5 100644 --- a/spec/support/matchers/disallow_request_matchers.rb +++ b/spec/support/matchers/disallow_request_matchers.rb @@ -11,7 +11,7 @@ end RSpec::Matchers.define :disallow_request_in_json do match do |response| - json_response = JSON.parse(response.body) + json_response = Gitlab::Json.parse(response.body) response.body.include?('You cannot perform write operations') && json_response.key?('message') end end diff --git a/spec/support/shared_contexts/features/error_tracking_shared_context.rb b/spec/support/shared_contexts/features/error_tracking_shared_context.rb index cbd33dd109b..102cf7c9b11 100644 --- a/spec/support/shared_contexts/features/error_tracking_shared_context.rb +++ b/spec/support/shared_contexts/features/error_tracking_shared_context.rb @@ -6,9 +6,9 @@ shared_context 'sentry error tracking context feature' do let_it_be(:project) { create(:project) } let_it_be(:project_error_tracking_settings) { create(:project_error_tracking_setting, project: project) } let_it_be(:issue_response_body) { fixture_file('sentry/issue_sample_response.json') } - let_it_be(:issue_response) { JSON.parse(issue_response_body) } + let_it_be(:issue_response) { Gitlab::Json.parse(issue_response_body) } let_it_be(:event_response_body) { fixture_file('sentry/issue_latest_event_sample_response.json') } - let_it_be(:event_response) { JSON.parse(event_response_body) } + let_it_be(:event_response) { Gitlab::Json.parse(event_response_body) } let(:sentry_api_urls) { Sentry::ApiUrls.new(project_error_tracking_settings.api_url) } let(:issue_id) { issue_response['id'] } let(:issue_seen) { 1.year.ago.utc } diff --git a/spec/support/shared_contexts/json_response_shared_context.rb b/spec/support/shared_contexts/json_response_shared_context.rb index 6a0734decd5..2f0a564d2bc 100644 --- a/spec/support/shared_contexts/json_response_shared_context.rb +++ b/spec/support/shared_contexts/json_response_shared_context.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true RSpec.shared_context 'JSON response' do - let(:json_response) { JSON.parse(response.body) } + let(:json_response) { Gitlab::Json.parse(response.body) } end diff --git a/spec/support/shared_examples/graphql/sorted_paginated_query_shared_examples.rb b/spec/support/shared_examples/graphql/sorted_paginated_query_shared_examples.rb index e530237b4e3..fb7e24eecf2 100644 --- a/spec/support/shared_examples/graphql/sorted_paginated_query_shared_examples.rb +++ b/spec/support/shared_examples/graphql/sorted_paginated_query_shared_examples.rb @@ -82,7 +82,7 @@ RSpec.shared_examples 'sorted paginated query' do cursored_query = pagination_query("sort: #{sort_param}, after: \"#{end_cursor}\"", page_info) post_graphql(cursored_query, current_user: current_user) - response_data = graphql_dig_at(JSON.parse(response.body), :data, *data_path, :edges) + response_data = graphql_dig_at(Gitlab::Json.parse(response.body), :data, *data_path, :edges) expect(pagination_results_data(response_data)).to eq expected_results.drop(first_param) end diff --git a/spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb index 90ac60a6fe7..feb3ba46353 100644 --- a/spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb @@ -80,7 +80,7 @@ RSpec.shared_examples 'group and project boards query' do cursored_query = query("after: \"#{end_cursor}\"") post_graphql(cursored_query, current_user: current_user) - response_data = JSON.parse(response.body)['data'][board_parent_type]['boards']['edges'] + response_data = Gitlab::Json.parse(response.body)['data'][board_parent_type]['boards']['edges'] expect(grab_names(response_data)).to eq expected_boards.drop(2).first(2).map(&:name) end diff --git a/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb b/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb index 90fcac0e55c..5dd1badbefc 100644 --- a/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb +++ b/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb @@ -23,7 +23,7 @@ RSpec.shared_examples 'valid dashboard service response for schema' do end RSpec.shared_examples 'valid dashboard service response' do - let(:dashboard_schema) { JSON.parse(fixture_file('lib/gitlab/metrics/dashboard/schemas/dashboard.json')) } + let(:dashboard_schema) { Gitlab::Json.parse(fixture_file('lib/gitlab/metrics/dashboard/schemas/dashboard.json')) } it_behaves_like 'valid dashboard service response for schema' end @@ -38,7 +38,7 @@ RSpec.shared_examples 'caches the unprocessed dashboard for subsequent calls' do end RSpec.shared_examples 'valid embedded dashboard service response' do - let(:dashboard_schema) { JSON.parse(fixture_file('lib/gitlab/metrics/dashboard/schemas/embedded_dashboard.json')) } + let(:dashboard_schema) { Gitlab::Json.parse(fixture_file('lib/gitlab/metrics/dashboard/schemas/embedded_dashboard.json')) } it_behaves_like 'valid dashboard service response for schema' end |