diff options
53 files changed, 718 insertions, 277 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 9efa167e504..096a598100e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. +## 13.11.1 (2021-04-22) + +### Changed (1 change) + +- Change unsubscribe language for email campaign on self managed. !59121 + +### Added (1 change) + +- Add documentation about Pages deployment migration. !59475 + + ## 13.11.0 (2021-04-22) ### Security (3 changes) diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component.vue b/app/assets/javascripts/pipelines/components/graph/graph_component.vue index a3440d612ca..71ec81b8969 100644 --- a/app/assets/javascripts/pipelines/components/graph/graph_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/graph_component.vue @@ -165,7 +165,7 @@ export default { <div class="js-pipeline-graph"> <div ref="mainPipelineContainer" - class="gl-display-flex gl-position-relative gl-bg-gray-10 gl-white-space-nowrap" + class="gl-display-flex gl-position-relative gl-bg-gray-10 gl-white-space-nowrap gl-border-t-solid gl-border-t-1 gl-border-gray-100" :class="{ 'gl-pipeline-min-h gl-py-5 gl-overflow-auto': !isLinkedPipeline }" > <linked-graph-wrapper> diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component_wrapper.vue b/app/assets/javascripts/pipelines/components/graph/graph_component_wrapper.vue index 11d5e386af9..0355e510f73 100644 --- a/app/assets/javascripts/pipelines/components/graph/graph_component_wrapper.vue +++ b/app/assets/javascripts/pipelines/components/graph/graph_component_wrapper.vue @@ -5,6 +5,8 @@ import { __ } from '~/locale'; import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { DEFAULT, DRAW_FAILURE, LOAD_FAILURE } from '../../constants'; +import DismissPipelineGraphCallout from '../../graphql/mutations/dismiss_pipeline_notification.graphql'; +import getUserCallouts from '../../graphql/queries/get_user_callouts.query.graphql'; import { reportToSentry } from '../../utils'; import { listByLayers } from '../parsing_utils'; import { IID_FAILURE, LAYER_VIEW, STAGE_VIEW, VIEW_TYPE_KEY } from './constants'; @@ -17,6 +19,9 @@ import { unwrapPipelineData, } from './utils'; +const featureName = 'pipeline_needs_hover_tip'; +const enumFeatureName = featureName.toUpperCase(); + export default { name: 'PipelineGraphWrapper', components: { @@ -44,6 +49,7 @@ export default { data() { return { alertType: null, + callouts: [], currentViewType: STAGE_VIEW, pipeline: null, pipelineLayers: null, @@ -60,6 +66,18 @@ export default { [DEFAULT]: __('An unknown error occurred while loading this graph.'), }, apollo: { + callouts: { + query: getUserCallouts, + update(data) { + return data?.currentUser?.callouts?.nodes.map((callout) => callout.featureName); + }, + error(err) { + reportToSentry( + this.$options.name, + `type: callout_load_failure, info: ${serializeLoadErrors(err)}`, + ); + }, + }, pipeline: { context() { return getQueryHeaders(this.graphqlResourceEtag); @@ -142,6 +160,9 @@ export default { /* This prevents reading view type off the localStorage value if it does not apply. */ return this.showGraphViewSelector ? this.currentViewType : STAGE_VIEW; }, + hoverTipPreviouslyDismissed() { + return this.callouts.includes(enumFeatureName); + }, showLoadingIcon() { /* Shows the icon only when the graph is empty, not when it is is @@ -171,6 +192,18 @@ export default { return this.pipelineLayers; }, + handleTipDismissal() { + try { + this.$apollo.mutate({ + mutation: DismissPipelineGraphCallout, + variables: { + featureName, + }, + }); + } catch (err) { + reportToSentry(this.$options.name, `type: callout_dismiss_failure, info: ${err}`); + } + }, hideAlert() { this.showAlert = false; this.alertType = null; @@ -211,6 +244,8 @@ export default { v-if="showGraphViewSelector" :type="graphViewType" :show-links="showLinks" + :tip-previously-dismissed="hoverTipPreviouslyDismissed" + @dismissHoverTip="handleTipDismissal" @updateViewType="updateViewType" @updateShowLinksState="updateShowLinksState" /> diff --git a/app/assets/javascripts/pipelines/components/graph/graph_view_selector.vue b/app/assets/javascripts/pipelines/components/graph/graph_view_selector.vue index bc038dde21c..1435276edd3 100644 --- a/app/assets/javascripts/pipelines/components/graph/graph_view_selector.vue +++ b/app/assets/javascripts/pipelines/components/graph/graph_view_selector.vue @@ -1,11 +1,12 @@ <script> -import { GlLoadingIcon, GlSegmentedControl, GlToggle } from '@gitlab/ui'; +import { GlAlert, GlLoadingIcon, GlSegmentedControl, GlToggle } from '@gitlab/ui'; import { __ } from '~/locale'; import { STAGE_VIEW, LAYER_VIEW } from './constants'; export default { name: 'GraphViewSelector', components: { + GlAlert, GlLoadingIcon, GlSegmentedControl, GlToggle, @@ -15,6 +16,10 @@ export default { type: Boolean, required: true, }, + tipPreviouslyDismissed: { + type: Boolean, + required: true, + }, type: { type: String, required: true, @@ -22,15 +27,17 @@ export default { }, data() { return { - currentViewType: this.type, - showLinksActive: false, + hoverTipDismissed: false, isToggleLoading: false, isSwitcherLoading: false, + segmentSelectedType: this.type, + showLinksActive: false, }; }, i18n: { - viewLabelText: __('Group jobs by'), + hoverTipText: __('Tip: Hover over a job to see the jobs it depends on to run.'), linksLabelText: __('Show dependencies'), + viewLabelText: __('Group jobs by'), }, views: { [STAGE_VIEW]: { @@ -48,7 +55,15 @@ export default { }, computed: { showLinksToggle() { - return this.currentViewType === LAYER_VIEW; + return this.segmentSelectedType === LAYER_VIEW; + }, + showTip() { + return ( + this.showLinks && + this.showLinksActive && + !this.tipPreviouslyDismissed && + !this.hoverTipDismissed + ); }, viewTypesList() { return Object.keys(this.$options.views).map((key) => { @@ -77,6 +92,10 @@ export default { }, }, methods: { + dismissTip() { + this.hoverTipDismissed = true; + this.$emit('dismissHoverTip'); + }, /* In both toggle methods, we use setTimeout so that the loading indicator displays, then the work is done to update the DOM. The process is: @@ -108,33 +127,38 @@ export default { </script> <template> - <div class="gl-relative gl-display-flex gl-align-items-center gl-w-max-content gl-my-4"> - <gl-loading-icon - v-if="isSwitcherLoading" - data-testid="switcher-loading-state" - class="gl-absolute gl-w-full gl-bg-white gl-opacity-5 gl-z-index-2" - size="lg" - /> - <span class="gl-font-weight-bold">{{ $options.i18n.viewLabelText }}</span> - <gl-segmented-control - v-model="currentViewType" - :options="viewTypesList" - :disabled="isSwitcherLoading" - data-testid="pipeline-view-selector" - class="gl-mx-4" - @input="toggleView" - /> - - <div v-if="showLinksToggle"> - <gl-toggle - v-model="showLinksActive" - data-testid="show-links-toggle" + <div> + <div class="gl-relative gl-display-flex gl-align-items-center gl-w-max-content gl-my-4"> + <gl-loading-icon + v-if="isSwitcherLoading" + data-testid="switcher-loading-state" + class="gl-absolute gl-w-full gl-bg-white gl-opacity-5 gl-z-index-2" + size="lg" + /> + <span class="gl-font-weight-bold">{{ $options.i18n.viewLabelText }}</span> + <gl-segmented-control + v-model="segmentSelectedType" + :options="viewTypesList" + :disabled="isSwitcherLoading" + data-testid="pipeline-view-selector" class="gl-mx-4" - :label="$options.i18n.linksLabelText" - :is-loading="isToggleLoading" - label-position="left" - @change="toggleShowLinksActive" + @input="toggleView" /> + + <div v-if="showLinksToggle" class="gl-display-flex gl-align-items-center"> + <gl-toggle + v-model="showLinksActive" + data-testid="show-links-toggle" + class="gl-mx-4" + :label="$options.i18n.linksLabelText" + :is-loading="isToggleLoading" + label-position="left" + @change="toggleShowLinksActive" + /> + </div> </div> + <gl-alert v-if="showTip" class="gl-my-5" variant="tip" @dismiss="dismissTip"> + {{ $options.i18n.hoverTipText }} + </gl-alert> </div> </template> diff --git a/app/assets/javascripts/pipelines/components/notification/pipeline_notification.vue b/app/assets/javascripts/pipelines/components/notification/pipeline_notification.vue index 6982586ab12..6dff3828a34 100644 --- a/app/assets/javascripts/pipelines/components/notification/pipeline_notification.vue +++ b/app/assets/javascripts/pipelines/components/notification/pipeline_notification.vue @@ -2,7 +2,7 @@ import { GlBanner, GlLink, GlSprintf } from '@gitlab/ui'; import createFlash from '~/flash'; import { __ } from '~/locale'; -import DismissPipelineNotification from '../../graphql/mutations/dismiss_pipeline_notification.graphql'; +import DismissPipelineGraphCallout from '../../graphql/mutations/dismiss_pipeline_notification.graphql'; import getUserCallouts from '../../graphql/queries/get_user_callouts.query.graphql'; const featureName = 'pipeline_needs_banner'; @@ -55,7 +55,7 @@ export default { this.dismissedAlert = true; try { this.$apollo.mutate({ - mutation: DismissPipelineNotification, + mutation: DismissPipelineGraphCallout, variables: { featureName, }, diff --git a/app/assets/javascripts/pipelines/graphql/mutations/dismiss_pipeline_notification.graphql b/app/assets/javascripts/pipelines/graphql/mutations/dismiss_pipeline_notification.graphql index e4fd55a28be..e8af1db9592 100644 --- a/app/assets/javascripts/pipelines/graphql/mutations/dismiss_pipeline_notification.graphql +++ b/app/assets/javascripts/pipelines/graphql/mutations/dismiss_pipeline_notification.graphql @@ -1,4 +1,4 @@ -mutation DismissPipelineNotification($featureName: String!) { +mutation DismissPipelineGraphCallout($featureName: String!) { userCalloutCreate(input: { featureName: $featureName }) { errors } diff --git a/app/views/admin/appearances/preview_sign_in.html.haml b/app/views/admin/appearances/preview_sign_in.html.haml index f972b3b5cbf..a317611862c 100644 --- a/app/views/admin/appearances/preview_sign_in.html.haml +++ b/app/views/admin/appearances/preview_sign_in.html.haml @@ -1,12 +1,12 @@ -= render 'devise/shared/tab_single', tab_title: 'Sign in preview' += render 'devise/shared/tab_single', tab_title: _('Sign in preview') .login-box %form.gl-show-field-errors .form-group = label_tag :login - = text_field_tag :login, nil, class: "form-control gl-form-input top", title: 'Please provide your username or email address.' + = text_field_tag :login, nil, class: "form-control gl-form-input top", title: _('Please provide your username or email address.') .form-group = label_tag :password - = password_field_tag :password, nil, class: "form-control gl-form-input bottom", title: 'This field is required.' + = password_field_tag :password, nil, class: "form-control gl-form-input bottom", title: _('This field is required.') .form-group - = button_tag "Sign in", class: "btn gl-button btn-confirm" + = button_tag _("Sign in"), class: "btn gl-button btn-confirm" diff --git a/app/views/admin/application_settings/_spam.html.haml b/app/views/admin/application_settings/_spam.html.haml index 2086fbc9d32..6d8f96c505f 100644 --- a/app/views/admin/application_settings/_spam.html.haml +++ b/app/views/admin/application_settings/_spam.html.haml @@ -6,25 +6,25 @@ .form-check = f.check_box :recaptcha_enabled, class: 'form-check-input' = f.label :recaptcha_enabled, class: 'form-check-label' do - Enable reCAPTCHA + = _("Enable reCAPTCHA") %span.form-text.text-muted#recaptcha_help_block = _('Helps prevent bots from creating accounts.') .form-group .form-check = f.check_box :login_recaptcha_protection_enabled, class: 'form-check-input' = f.label :login_recaptcha_protection_enabled, class: 'form-check-label' do - Enable reCAPTCHA for login + = _("Enable reCAPTCHA for login") %span.form-text.text-muted#recaptcha_help_block = _('Helps prevent bots from brute-force attacks.') .form-group - = f.label :recaptcha_site_key, 'reCAPTCHA Site Key', class: 'label-bold' + = f.label :recaptcha_site_key, _('reCAPTCHA Site Key'), class: 'label-bold' = f.text_field :recaptcha_site_key, class: 'form-control gl-form-input' .form-text.text-muted - Generate site and private keys at + = _("Generate site and private keys at") %a{ href: 'http://www.google.com/recaptcha', target: 'blank' } http://www.google.com/recaptcha .form-group - = f.label :recaptcha_private_key, 'reCAPTCHA Private Key', class: 'label-bold' + = f.label :recaptcha_private_key, _('reCAPTCHA Private Key'), class: 'label-bold' .form-group = f.text_field :recaptcha_private_key, class: 'form-control gl-form-input' @@ -41,10 +41,10 @@ = f.check_box :akismet_enabled, class: 'form-check-input' = f.label :akismet_enabled, class: 'form-check-label' do Enable Akismet - %span.form-text.text-muted#akismet_help_block Helps prevent bots from creating issues + %span.form-text.text-muted#akismet_help_block= _("Helps prevent bots from creating issues") .form-group - = f.label :akismet_api_key, 'Akismet API Key', class: 'label-bold' + = f.label :akismet_api_key, _('Akismet API Key'), class: 'label-bold' = f.text_field :akismet_api_key, class: 'form-control gl-form-input' .form-text.text-muted Generate API key at @@ -54,21 +54,21 @@ .form-check = f.check_box :unique_ips_limit_enabled, class: 'form-check-input' = f.label :unique_ips_limit_enabled, class: 'form-check-label' do - Limit sign in from multiple ips + = _("Limit sign in from multiple ips") %span.form-text.text-muted#unique_ip_help_block - Helps prevent malicious users hide their activity + = _("Helps prevent malicious users hide their activity") .form-group - = f.label :unique_ips_limit_per_user, 'IPs per user', class: 'label-bold' + = f.label :unique_ips_limit_per_user, _('IPs per user'), class: 'label-bold' = f.number_field :unique_ips_limit_per_user, class: 'form-control gl-form-input' .form-text.text-muted - Maximum number of unique IPs per user + = _("Maximum number of unique IPs per user") .form-group - = f.label :unique_ips_limit_time_window, 'IP expiration time', class: 'label-bold' + = f.label :unique_ips_limit_time_window, _('IP expiration time'), class: 'label-bold' = f.number_field :unique_ips_limit_time_window, class: 'form-control gl-form-input' .form-text.text-muted - How many seconds an IP will be counted towards the limit + = _("How many seconds an IP will be counted towards the limit") .form-group .form-check @@ -79,4 +79,4 @@ = f.label :spam_check_endpoint_url, _('URL of the external Spam Check endpoint'), class: 'label-bold' = f.text_field :spam_check_endpoint_url, class: 'form-control gl-form-input' - = f.submit 'Save changes', class: "gl-button btn btn-confirm" + = f.submit _('Save changes'), class: "gl-button btn btn-confirm" diff --git a/changelogs/unreleased/239179-new-model-for-finding-evidences-request.yml b/changelogs/unreleased/239179-new-model-for-finding-evidences-request.yml new file mode 100644 index 00000000000..43db7ae3dc7 --- /dev/null +++ b/changelogs/unreleased/239179-new-model-for-finding-evidences-request.yml @@ -0,0 +1,5 @@ +--- +title: Add VulnerabiltyFindingEvidenceRequest model +merge_request: 59539 +author: +type: changed diff --git a/changelogs/unreleased/321054-remove-feature-flag-code-quick-actions.yml b/changelogs/unreleased/321054-remove-feature-flag-code-quick-actions.yml new file mode 100644 index 00000000000..b0e5cbd6c24 --- /dev/null +++ b/changelogs/unreleased/321054-remove-feature-flag-code-quick-actions.yml @@ -0,0 +1,5 @@ +--- +title: Remove usage_data_track_quickactions feature flag +merge_request: 59914 +author: +type: other diff --git a/changelogs/unreleased/322743-destroy-cadence-mutation.yml b/changelogs/unreleased/322743-destroy-cadence-mutation.yml new file mode 100644 index 00000000000..a9cac647db7 --- /dev/null +++ b/changelogs/unreleased/322743-destroy-cadence-mutation.yml @@ -0,0 +1,5 @@ +--- +title: Add support to destroy iteration cadences in GraphQL +merge_request: 59060 +author: +type: added diff --git a/changelogs/unreleased/326840-make-migration-pause-time-configurable.yml b/changelogs/unreleased/326840-make-migration-pause-time-configurable.yml new file mode 100644 index 00000000000..ca615a1502f --- /dev/null +++ b/changelogs/unreleased/326840-make-migration-pause-time-configurable.yml @@ -0,0 +1,5 @@ +--- +title: Add pause_ms column to batched_background_migrations and batched_background_migration_jobs +merge_request: 58583 +author: +type: changed diff --git a/changelogs/unreleased/328435-convert-ci-sources-pipelines-to-bigint.yml b/changelogs/unreleased/328435-convert-ci-sources-pipelines-to-bigint.yml new file mode 100644 index 00000000000..151442bcefc --- /dev/null +++ b/changelogs/unreleased/328435-convert-ci-sources-pipelines-to-bigint.yml @@ -0,0 +1,5 @@ +--- +title: Initialize conversion of ci_sources_pipelines.source_job_id to bigint +merge_request: 59951 +author: +type: other diff --git a/changelogs/unreleased/Externalize-strings-in-_spam-html-haml.yml b/changelogs/unreleased/Externalize-strings-in-_spam-html-haml.yml new file mode 100644 index 00000000000..2f242e09571 --- /dev/null +++ b/changelogs/unreleased/Externalize-strings-in-_spam-html-haml.yml @@ -0,0 +1,5 @@ +--- +title: Externalize strings in application_settings/_spam.html.haml +merge_request: 58076 +author: nuwe1 +type: other diff --git a/changelogs/unreleased/Externalize-strings-in-appearances-preview_sign_in-html-haml.yml b/changelogs/unreleased/Externalize-strings-in-appearances-preview_sign_in-html-haml.yml new file mode 100644 index 00000000000..fac49cb477f --- /dev/null +++ b/changelogs/unreleased/Externalize-strings-in-appearances-preview_sign_in-html-haml.yml @@ -0,0 +1,5 @@ +--- +title: Externalise strings in appearances/preview_sign_in.html.haml +merge_request: 58138 +author: nuwe1 +type: other diff --git a/changelogs/unreleased/nicolasdular-update-email-language-for-self-managed.yml b/changelogs/unreleased/nicolasdular-update-email-language-for-self-managed.yml deleted file mode 100644 index 7bfe58aa1dd..00000000000 --- a/changelogs/unreleased/nicolasdular-update-email-language-for-self-managed.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Change unsubscribe language for email campaign on self managed -merge_request: 59121 -author: -type: changed diff --git a/changelogs/unreleased/sh-workhorse-default-region.yml b/changelogs/unreleased/sh-workhorse-default-region.yml new file mode 100644 index 00000000000..1de978bea74 --- /dev/null +++ b/changelogs/unreleased/sh-workhorse-default-region.yml @@ -0,0 +1,5 @@ +--- +title: Set a default region to Workhorse S3 client +merge_request: 59932 +author: +type: fixed diff --git a/config/feature_flags/development/usage_data_track_quickactions.yml b/config/feature_flags/development/usage_data_track_quickactions.yml deleted file mode 100644 index 3e2a2fe8927..00000000000 --- a/config/feature_flags/development/usage_data_track_quickactions.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: usage_data_track_quickactions -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52398 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/321054 -milestone: '13.9' -type: development -group: group::project management -default_enabled: true diff --git a/config/webpack.config.js b/config/webpack.config.js index 11694e4aa1f..6880c67dff5 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -451,12 +451,14 @@ module.exports = { }), dll && - new CopyWebpackPlugin([ - { - from: dll.cacheFrom, - to: dll.cacheTo, - }, - ]), + new CopyWebpackPlugin({ + patterns: [ + { + from: dll.cacheFrom, + to: dll.cacheTo, + }, + ], + }), !IS_EE && new webpack.NormalModuleReplacementPlugin(/^ee_component\/(.*)\.vue/, (resource) => { @@ -467,24 +469,28 @@ module.exports = { ); }), - new CopyWebpackPlugin([ - { - from: path.join(ROOT_PATH, 'node_modules/pdfjs-dist/cmaps/'), - to: path.join(WEBPACK_OUTPUT_PATH, 'cmaps/'), - }, - { - from: path.join(ROOT_PATH, 'node_modules', SOURCEGRAPH_PACKAGE, '/'), - to: SOURCEGRAPH_OUTPUT_PATH, - ignore: ['package.json'], - }, - { - from: path.join( - ROOT_PATH, - 'node_modules/@gitlab/visual-review-tools/dist/visual_review_toolbar.js', - ), - to: WEBPACK_OUTPUT_PATH, - }, - ]), + new CopyWebpackPlugin({ + patterns: [ + { + from: path.join(ROOT_PATH, 'node_modules/pdfjs-dist/cmaps/'), + to: path.join(WEBPACK_OUTPUT_PATH, 'cmaps/'), + }, + { + from: path.join(ROOT_PATH, 'node_modules', SOURCEGRAPH_PACKAGE, '/'), + to: SOURCEGRAPH_OUTPUT_PATH, + globOptions: { + ignore: ['package.json'], + }, + }, + { + from: path.join( + ROOT_PATH, + 'node_modules/@gitlab/visual-review-tools/dist/visual_review_toolbar.js', + ), + to: WEBPACK_OUTPUT_PATH, + }, + ], + }), // compression can require a lot of compute time and is disabled in CI IS_PRODUCTION && !NO_COMPRESSION && new CompressionPlugin(), diff --git a/db/migrate/20210413155324_add_pause_seconds_to_batched_background_migrations.rb b/db/migrate/20210413155324_add_pause_seconds_to_batched_background_migrations.rb new file mode 100644 index 00000000000..ca73c85963e --- /dev/null +++ b/db/migrate/20210413155324_add_pause_seconds_to_batched_background_migrations.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddPauseSecondsToBatchedBackgroundMigrations < ActiveRecord::Migration[6.0] + def change + add_column :batched_background_migrations, :pause_ms, :integer, null: false, default: 100 + end +end diff --git a/db/migrate/20210414045322_add_pause_seconds_to_batched_background_migration_jobs.rb b/db/migrate/20210414045322_add_pause_seconds_to_batched_background_migration_jobs.rb new file mode 100644 index 00000000000..d232f9c0305 --- /dev/null +++ b/db/migrate/20210414045322_add_pause_seconds_to_batched_background_migration_jobs.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddPauseSecondsToBatchedBackgroundMigrationJobs < ActiveRecord::Migration[6.0] + def change + add_column :batched_background_migration_jobs, :pause_ms, :integer, null: false, default: 100 + end +end diff --git a/db/migrate/20210415172516_create_vulnerability_finding_evidence_requests.rb b/db/migrate/20210415172516_create_vulnerability_finding_evidence_requests.rb new file mode 100644 index 00000000000..2fe33ff23ba --- /dev/null +++ b/db/migrate/20210415172516_create_vulnerability_finding_evidence_requests.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class CreateVulnerabilityFindingEvidenceRequests < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + create_table_with_constraints :vulnerability_finding_evidence_requests do |t| + t.timestamps_with_timezone null: false + + t.references :vulnerability_finding_evidence, index: { name: 'finding_evidence_requests_on_finding_evidence_id' }, null: false, foreign_key: { on_delete: :cascade } + t.text :method + t.text :url + + t.text_limit :method, 32 + t.text_limit :url, 2048 + end + end + + def down + with_lock_retries do + drop_table :vulnerability_finding_evidence_requests + end + end +end diff --git a/db/migrate/20210419224834_update_issues_iteration_foreign_key.rb b/db/migrate/20210419224834_update_issues_iteration_foreign_key.rb new file mode 100644 index 00000000000..d071ac8d1d4 --- /dev/null +++ b/db/migrate/20210419224834_update_issues_iteration_foreign_key.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +class UpdateIssuesIterationForeignKey < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + disable_ddl_transaction! + + def up + with_lock_retries do + remove_foreign_key_if_exists(:issues, column: :sprint_id) + end + + add_concurrent_foreign_key(:issues, :sprints, column: :sprint_id, on_delete: :nullify) + end + + def down + with_lock_retries do + remove_foreign_key_if_exists(:issues, column: :sprint_id) + end + + add_concurrent_foreign_key(:issues, :sprints, column: :sprint_id, on_delete: :cascade) + end +end diff --git a/db/migrate/20210420221106_update_merge_requests_iteration_foreign_key.rb b/db/migrate/20210420221106_update_merge_requests_iteration_foreign_key.rb new file mode 100644 index 00000000000..64786f0b20c --- /dev/null +++ b/db/migrate/20210420221106_update_merge_requests_iteration_foreign_key.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +class UpdateMergeRequestsIterationForeignKey < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + disable_ddl_transaction! + + def up + with_lock_retries do + remove_foreign_key_if_exists(:merge_requests, column: :sprint_id) + end + + add_concurrent_foreign_key(:merge_requests, :sprints, column: :sprint_id, on_delete: :nullify) + end + + def down + with_lock_retries do + remove_foreign_key_if_exists(:merge_requests, column: :sprint_id) + end + + add_concurrent_foreign_key(:merge_requests, :sprints, column: :sprint_id, on_delete: :cascade) + end +end diff --git a/db/migrate/20210422022825_initialize_conversion_of_ci_sources_pipelines_source_job_id_to_bigint.rb b/db/migrate/20210422022825_initialize_conversion_of_ci_sources_pipelines_source_job_id_to_bigint.rb new file mode 100644 index 00000000000..e6808f7e376 --- /dev/null +++ b/db/migrate/20210422022825_initialize_conversion_of_ci_sources_pipelines_source_job_id_to_bigint.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class InitializeConversionOfCiSourcesPipelinesSourceJobIdToBigint < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + def up + # Foreign key that references ci_builds.id + initialize_conversion_of_integer_to_bigint :ci_sources_pipelines, :source_job_id + end + + def down + trigger_name = rename_trigger_name(:ci_sources_pipelines, :source_job_id, :source_job_id_convert_to_bigint) + + remove_rename_triggers_for_postgresql :ci_sources_pipelines, trigger_name + + remove_column :ci_sources_pipelines, :source_job_id_convert_to_bigint + end +end diff --git a/db/post_migrate/20210422023046_backfill_ci_sources_pipelines_source_job_id_for_bigint_conversion.rb b/db/post_migrate/20210422023046_backfill_ci_sources_pipelines_source_job_id_for_bigint_conversion.rb new file mode 100644 index 00000000000..d760e7b64f8 --- /dev/null +++ b/db/post_migrate/20210422023046_backfill_ci_sources_pipelines_source_job_id_for_bigint_conversion.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class BackfillCiSourcesPipelinesSourceJobIdForBigintConversion < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + def up + return unless should_run? + + backfill_conversion_of_integer_to_bigint :ci_sources_pipelines, :source_job_id, + batch_size: 15000, sub_batch_size: 100 + end + + def down + return unless should_run? + + Gitlab::Database::BackgroundMigration::BatchedMigration + .where(job_class_name: 'CopyColumnUsingBackgroundMigrationJob') + .where(table_name: 'ci_sources_pipelines', column_name: 'id') + .where('job_arguments = ?', [%w[source_job_id], %w[source_job_id_convert_to_bigint]].to_json) + .delete_all + end + + private + + def should_run? + Gitlab.dev_or_test_env? || Gitlab.com? + end +end diff --git a/db/schema_migrations/20210413155324 b/db/schema_migrations/20210413155324 new file mode 100644 index 00000000000..ab7e4256fdb --- /dev/null +++ b/db/schema_migrations/20210413155324 @@ -0,0 +1 @@ +7bb8be1616a61b12392bc5ff4d716123bc605d9753744c04a23f9258bab25af6
\ No newline at end of file diff --git a/db/schema_migrations/20210414045322 b/db/schema_migrations/20210414045322 new file mode 100644 index 00000000000..f95da121569 --- /dev/null +++ b/db/schema_migrations/20210414045322 @@ -0,0 +1 @@ +197930adaf08e3d22d54309d1cc0605bc4d6843409a38f8e0cc9ce9842ec1816
\ No newline at end of file diff --git a/db/schema_migrations/20210415172516 b/db/schema_migrations/20210415172516 new file mode 100644 index 00000000000..ad129261acf --- /dev/null +++ b/db/schema_migrations/20210415172516 @@ -0,0 +1 @@ +06d33e4eb99e46cb6caf71916e5c93c4b7eb9fe73152841c7c41d5e157ec339e
\ No newline at end of file diff --git a/db/schema_migrations/20210419224834 b/db/schema_migrations/20210419224834 new file mode 100644 index 00000000000..61926cfb1df --- /dev/null +++ b/db/schema_migrations/20210419224834 @@ -0,0 +1 @@ +145782c0cb0d24617e0e43c43f49a0f1d4033df3f303e4d4085e586c48e2408e
\ No newline at end of file diff --git a/db/schema_migrations/20210420221106 b/db/schema_migrations/20210420221106 new file mode 100644 index 00000000000..cfe3e6e5406 --- /dev/null +++ b/db/schema_migrations/20210420221106 @@ -0,0 +1 @@ +62842b9e9753b7880e980b0a16335e7d00bdce8b7b42d94b1ba26828724c01dd
\ No newline at end of file diff --git a/db/schema_migrations/20210422022825 b/db/schema_migrations/20210422022825 new file mode 100644 index 00000000000..4f1313658ac --- /dev/null +++ b/db/schema_migrations/20210422022825 @@ -0,0 +1 @@ +d0119a45e6ab08afa6ed73a248b81cae4a4de63d46fda25968444256355d208f
\ No newline at end of file diff --git a/db/schema_migrations/20210422023046 b/db/schema_migrations/20210422023046 new file mode 100644 index 00000000000..520db7527d3 --- /dev/null +++ b/db/schema_migrations/20210422023046 @@ -0,0 +1 @@ +e588b2e6c612e4a25615d9c5179100af20d3507e0eec8feba52bc6b45d9befea
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 90e69f4518c..331684d4246 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -115,6 +115,15 @@ BEGIN END; $$; +CREATE FUNCTION trigger_8485e97c00e3() RETURNS trigger + LANGUAGE plpgsql + AS $$ +BEGIN + NEW."source_job_id_convert_to_bigint" := NEW."source_job_id"; + RETURN NEW; +END; +$$; + CREATE FUNCTION trigger_be1804f21693() RETURNS trigger LANGUAGE plpgsql AS $$ @@ -9824,7 +9833,8 @@ CREATE TABLE batched_background_migration_jobs ( sub_batch_size integer NOT NULL, status smallint DEFAULT 0 NOT NULL, attempts smallint DEFAULT 0 NOT NULL, - metrics jsonb DEFAULT '{}'::jsonb NOT NULL + metrics jsonb DEFAULT '{}'::jsonb NOT NULL, + pause_ms integer DEFAULT 100 NOT NULL ); CREATE SEQUENCE batched_background_migration_jobs_id_seq @@ -9852,6 +9862,7 @@ CREATE TABLE batched_background_migrations ( column_name text NOT NULL, job_arguments jsonb DEFAULT '"[]"'::jsonb NOT NULL, total_tuple_count bigint, + pause_ms integer DEFAULT 100 NOT NULL, CONSTRAINT check_5bb0382d6f CHECK ((char_length(column_name) <= 63)), CONSTRAINT check_6b6a06254a CHECK ((char_length(table_name) <= 63)), CONSTRAINT check_batch_size_in_range CHECK ((batch_size >= sub_batch_size)), @@ -10977,7 +10988,8 @@ CREATE TABLE ci_sources_pipelines ( pipeline_id integer, source_project_id integer, source_job_id integer, - source_pipeline_id integer + source_pipeline_id integer, + source_job_id_convert_to_bigint bigint ); CREATE SEQUENCE ci_sources_pipelines_id_seq @@ -18559,6 +18571,26 @@ CREATE SEQUENCE vulnerability_feedback_id_seq ALTER SEQUENCE vulnerability_feedback_id_seq OWNED BY vulnerability_feedback.id; +CREATE TABLE vulnerability_finding_evidence_requests ( + id bigint NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + vulnerability_finding_evidence_id bigint NOT NULL, + method text, + url text, + CONSTRAINT check_8152fbb236 CHECK ((char_length(url) <= 2048)), + CONSTRAINT check_d9d11300f4 CHECK ((char_length(method) <= 32)) +); + +CREATE SEQUENCE vulnerability_finding_evidence_requests_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE vulnerability_finding_evidence_requests_id_seq OWNED BY vulnerability_finding_evidence_requests.id; + CREATE TABLE vulnerability_finding_evidences ( id bigint NOT NULL, created_at timestamp with time zone NOT NULL, @@ -19864,6 +19896,8 @@ ALTER TABLE ONLY vulnerability_external_issue_links ALTER COLUMN id SET DEFAULT ALTER TABLE ONLY vulnerability_feedback ALTER COLUMN id SET DEFAULT nextval('vulnerability_feedback_id_seq'::regclass); +ALTER TABLE ONLY vulnerability_finding_evidence_requests ALTER COLUMN id SET DEFAULT nextval('vulnerability_finding_evidence_requests_id_seq'::regclass); + ALTER TABLE ONLY vulnerability_finding_evidences ALTER COLUMN id SET DEFAULT nextval('vulnerability_finding_evidences_id_seq'::regclass); ALTER TABLE ONLY vulnerability_finding_links ALTER COLUMN id SET DEFAULT nextval('vulnerability_finding_links_id_seq'::regclass); @@ -21494,6 +21528,9 @@ ALTER TABLE ONLY vulnerability_external_issue_links ALTER TABLE ONLY vulnerability_feedback ADD CONSTRAINT vulnerability_feedback_pkey PRIMARY KEY (id); +ALTER TABLE ONLY vulnerability_finding_evidence_requests + ADD CONSTRAINT vulnerability_finding_evidence_requests_pkey PRIMARY KEY (id); + ALTER TABLE ONLY vulnerability_finding_evidences ADD CONSTRAINT vulnerability_finding_evidences_pkey PRIMARY KEY (id); @@ -21730,6 +21767,8 @@ CREATE UNIQUE INDEX epic_user_mentions_on_epic_id_index ON epic_user_mentions US CREATE INDEX expired_artifacts_temp_index ON ci_job_artifacts USING btree (id, created_at) WHERE ((expire_at IS NULL) AND (date(timezone('UTC'::text, created_at)) < '2020-06-22'::date)); +CREATE INDEX finding_evidence_requests_on_finding_evidence_id ON vulnerability_finding_evidence_requests USING btree (vulnerability_finding_evidence_id); + CREATE INDEX finding_evidences_on_vulnerability_occurrence_id ON vulnerability_finding_evidences USING btree (vulnerability_occurrence_id); CREATE INDEX finding_links_on_vulnerability_occurrence_id ON vulnerability_finding_links USING btree (vulnerability_occurrence_id); @@ -24676,6 +24715,8 @@ CREATE TRIGGER trigger_07c94931164e BEFORE INSERT OR UPDATE ON push_event_payloa CREATE TRIGGER trigger_69523443cc10 BEFORE INSERT OR UPDATE ON events FOR EACH ROW EXECUTE PROCEDURE trigger_69523443cc10(); +CREATE TRIGGER trigger_8485e97c00e3 BEFORE INSERT OR UPDATE ON ci_sources_pipelines FOR EACH ROW EXECUTE PROCEDURE trigger_8485e97c00e3(); + CREATE TRIGGER trigger_be1804f21693 BEFORE INSERT OR UPDATE ON ci_job_artifacts FOR EACH ROW EXECUTE PROCEDURE trigger_be1804f21693(); CREATE TRIGGER trigger_has_external_issue_tracker_on_delete AFTER DELETE ON services FOR EACH ROW WHEN ((((old.category)::text = 'issue_tracker'::text) AND (old.active = true) AND (old.project_id IS NOT NULL))) EXECUTE PROCEDURE set_has_external_issue_tracker(); @@ -24853,7 +24894,7 @@ ALTER TABLE ONLY ci_builds ADD CONSTRAINT fk_3a9eaa254d FOREIGN KEY (stage_id) REFERENCES ci_stages(id) ON DELETE CASCADE; ALTER TABLE ONLY issues - ADD CONSTRAINT fk_3b8c72ea56 FOREIGN KEY (sprint_id) REFERENCES sprints(id) ON DELETE CASCADE; + ADD CONSTRAINT fk_3b8c72ea56 FOREIGN KEY (sprint_id) REFERENCES sprints(id) ON DELETE SET NULL; ALTER TABLE ONLY epics ADD CONSTRAINT fk_3c1fd1cccc FOREIGN KEY (due_date_sourcing_milestone_id) REFERENCES milestones(id) ON DELETE SET NULL; @@ -24997,7 +25038,7 @@ ALTER TABLE ONLY labels ADD CONSTRAINT fk_7de4989a69 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; ALTER TABLE ONLY merge_requests - ADD CONSTRAINT fk_7e85395a64 FOREIGN KEY (sprint_id) REFERENCES sprints(id) ON DELETE CASCADE; + ADD CONSTRAINT fk_7e85395a64 FOREIGN KEY (sprint_id) REFERENCES sprints(id) ON DELETE SET NULL; ALTER TABLE ONLY merge_request_metrics ADD CONSTRAINT fk_7f28d925f3 FOREIGN KEY (merged_by_id) REFERENCES users(id) ON DELETE SET NULL; @@ -26118,6 +26159,9 @@ ALTER TABLE ONLY dast_scanner_profiles ALTER TABLE ONLY vulnerability_historical_statistics ADD CONSTRAINT fk_rails_72b73ed023 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; +ALTER TABLE ONLY vulnerability_finding_evidence_requests + ADD CONSTRAINT fk_rails_72c87c8eb6 FOREIGN KEY (vulnerability_finding_evidence_id) REFERENCES vulnerability_finding_evidences(id) ON DELETE CASCADE; + ALTER TABLE ONLY slack_integrations ADD CONSTRAINT fk_rails_73db19721a FOREIGN KEY (service_id) REFERENCES services(id) ON DELETE CASCADE; diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 726c9bba0a3..6156526772a 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -2437,6 +2437,25 @@ Input type: `IterationCadenceCreateInput` | <a id="mutationiterationcadencecreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | | <a id="mutationiterationcadencecreateiterationcadence"></a>`iterationCadence` | [`IterationCadence`](#iterationcadence) | The created iteration cadence. | +### `Mutation.iterationCadenceDestroy` + +Input type: `IterationCadenceDestroyInput` + +#### Arguments + +| Name | Type | Description | +| ---- | ---- | ----------- | +| <a id="mutationiterationcadencedestroyclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | +| <a id="mutationiterationcadencedestroyid"></a>`id` | [`IterationsCadenceID!`](#iterationscadenceid) | Global ID of the iteration cadence. | + +#### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| <a id="mutationiterationcadencedestroyclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | +| <a id="mutationiterationcadencedestroyerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | +| <a id="mutationiterationcadencedestroygroup"></a>`group` | [`Group!`](#group) | Group the iteration cadence belongs to. | + ### `Mutation.iterationCadenceUpdate` Input type: `IterationCadenceUpdateInput` diff --git a/lib/gitlab/background_migration/copy_column_using_background_migration_job.rb b/lib/gitlab/background_migration/copy_column_using_background_migration_job.rb index c7226b41bab..529b8cdf8d4 100644 --- a/lib/gitlab/background_migration/copy_column_using_background_migration_job.rb +++ b/lib/gitlab/background_migration/copy_column_using_background_migration_job.rb @@ -16,8 +16,6 @@ module Gitlab class CopyColumnUsingBackgroundMigrationJob include Gitlab::Database::DynamicModelHelpers - PAUSE_SECONDS = 0.1 - # start_id - The start ID of the range of rows to update. # end_id - The end ID of the range of rows to update. # batch_table - The name of the table that contains the columns. @@ -25,9 +23,10 @@ module Gitlab # sub_batch_size - We don't want updates to take more than ~100ms # This allows us to run multiple smaller batches during # the minimum 2.minute interval that we can schedule jobs + # pause_ms - The number of milliseconds to sleep between each subbatch execution. # copy_from - List of columns containing the data to copy. # copy_to - List of columns to copy the data to. Order must match the order in `copy_from`. - def perform(start_id, end_id, batch_table, batch_column, sub_batch_size, copy_from, copy_to) + def perform(start_id, end_id, batch_table, batch_column, sub_batch_size, pause_ms, copy_from, copy_to) copy_from = Array.wrap(copy_from) copy_to = Array.wrap(copy_to) @@ -42,7 +41,8 @@ module Gitlab sub_batch.update_all(assignment_clauses) end - sleep(PAUSE_SECONDS) + pause_ms = 0 if pause_ms < 0 + sleep(pause_ms * 0.001) end end diff --git a/lib/gitlab/database/background_migration/batched_migration.rb b/lib/gitlab/database/background_migration/batched_migration.rb index 4aa33ed7946..aa03305ae58 100644 --- a/lib/gitlab/database/background_migration/batched_migration.rb +++ b/lib/gitlab/database/background_migration/batched_migration.rb @@ -35,7 +35,13 @@ module Gitlab end def create_batched_job!(min, max) - batched_jobs.create!(min_value: min, max_value: max, batch_size: batch_size, sub_batch_size: sub_batch_size) + batched_jobs.create!( + min_value: min, + max_value: max, + batch_size: batch_size, + sub_batch_size: sub_batch_size, + pause_ms: pause_ms + ) end def next_min_value diff --git a/lib/gitlab/database/background_migration/batched_migration_wrapper.rb b/lib/gitlab/database/background_migration/batched_migration_wrapper.rb index 110c00e284e..a0b661119ed 100644 --- a/lib/gitlab/database/background_migration/batched_migration_wrapper.rb +++ b/lib/gitlab/database/background_migration/batched_migration_wrapper.rb @@ -43,6 +43,7 @@ module Gitlab tracking_record.migration_table_name, tracking_record.migration_column_name, tracking_record.sub_batch_size, + tracking_record.pause_ms, *tracking_record.migration_job_arguments) if job_instance.respond_to?(:batch_metrics) diff --git a/lib/gitlab/usage_data_counters/known_events/quickactions.yml b/lib/gitlab/usage_data_counters/known_events/quickactions.yml index 0fe65afb237..c1eabb352f7 100644 --- a/lib/gitlab/usage_data_counters/known_events/quickactions.yml +++ b/lib/gitlab/usage_data_counters/known_events/quickactions.yml @@ -3,334 +3,267 @@ category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_assign_single category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_assign_multiple category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_assign_self category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_assign_reviewer category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_award category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_board_move category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_child_epic category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_clear_weight category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_clone category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_close category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_confidential category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_copy_metadata_merge_request category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_copy_metadata_issue category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_create_merge_request category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_done category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_draft category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_due category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_duplicate category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_epic category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_estimate category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_iteration category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_label category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_lock category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_merge category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_milestone category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_move category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_parent_epic category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_promote category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_publish category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_reassign category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_reassign_reviewer category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_rebase category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_relabel category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_relate category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_remove_child_epic category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_remove_due_date category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_remove_epic category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_remove_estimate category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_remove_iteration category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_remove_milestone category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_remove_parent_epic category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_remove_time_spent category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_remove_zoom category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_reopen category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_shrug category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_spend_subtract category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_spend_add category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_submit_review category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_subscribe category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_tableflip category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_tag category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_target_branch category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_title category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_todo category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_unassign_specific category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_unassign_all category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_unassign_reviewer category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_unlabel_specific category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_unlabel_all category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_unlock category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_unsubscribe category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_weight category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_wip category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_zoom category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_invite_email_single category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions - name: i_quickactions_invite_email_multiple category: quickactions redis_slot: quickactions aggregation: weekly - feature_flag: usage_data_track_quickactions diff --git a/lib/gitlab/usage_data_counters/quick_action_activity_unique_counter.rb b/lib/gitlab/usage_data_counters/quick_action_activity_unique_counter.rb index ed3df7dcf75..557179ad57a 100644 --- a/lib/gitlab/usage_data_counters/quick_action_activity_unique_counter.rb +++ b/lib/gitlab/usage_data_counters/quick_action_activity_unique_counter.rb @@ -7,7 +7,6 @@ module Gitlab # Tracks the quick action with name `name`. # `args` is expected to be a single string, will be split internally when necessary. def track_unique_action(name, args:, user:) - return unless Feature.enabled?(:usage_data_track_quickactions, default_enabled: :yaml) return unless user args ||= '' diff --git a/lib/object_storage/direct_upload.rb b/lib/object_storage/direct_upload.rb index 7f1c30e574d..7fbf01f3768 100644 --- a/lib/object_storage/direct_upload.rb +++ b/lib/object_storage/direct_upload.rb @@ -79,7 +79,7 @@ module ObjectStorage Provider: 'AWS', S3Config: { Bucket: bucket_name, - Region: credentials[:region], + Region: credentials[:region] || ::Fog::AWS::Storage::DEFAULT_REGION, Endpoint: credentials[:endpoint], PathStyle: config.use_path_style?, UseIamProfile: config.use_iam_profile?, diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 880cb5beba7..f9cfaef76a6 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -2783,6 +2783,9 @@ msgstr "" msgid "After you've reviewed these contribution guidelines, you'll be all set to" msgstr "" +msgid "Akismet API Key" +msgstr "" + msgid "Alert" msgid_plural "Alerts" msgstr[0] "" @@ -12071,6 +12074,12 @@ msgstr "" msgid "Enable proxy" msgstr "" +msgid "Enable reCAPTCHA" +msgstr "" + +msgid "Enable reCAPTCHA for login" +msgstr "" + msgid "Enable reCAPTCHA, Invisible Captcha, Akismet and set IP limits. For reCAPTCHA, we currently only support %{recaptcha_v2_link_start}v2%{recaptcha_v2_link_end}" msgstr "" @@ -14188,6 +14197,9 @@ msgstr "" msgid "Generate new token" msgstr "" +msgid "Generate site and private keys at" +msgstr "" + msgid "Generic package file size in bytes" msgstr "" @@ -15970,6 +15982,12 @@ msgstr "" msgid "Helps prevent bots from creating accounts." msgstr "" +msgid "Helps prevent bots from creating issues" +msgstr "" + +msgid "Helps prevent malicious users hide their activity" +msgstr "" + msgid "Helps reduce alert volume (e.g. if creating too many issues)" msgstr "" @@ -16121,6 +16139,9 @@ msgstr "" msgid "How many replicas each Elasticsearch shard has." msgstr "" +msgid "How many seconds an IP will be counted towards the limit" +msgstr "" + msgid "How many shards to split the Elasticsearch index over." msgstr "" @@ -16205,9 +16226,15 @@ msgstr "" msgid "IP Address" msgstr "" +msgid "IP expiration time" +msgstr "" + msgid "IP subnet restriction only allowed for top-level groups" msgstr "" +msgid "IPs per user" +msgstr "" + msgid "Identifier" msgstr "" @@ -19173,6 +19200,9 @@ msgstr "" msgid "Limit namespaces and projects that can be indexed" msgstr "" +msgid "Limit sign in from multiple ips" +msgstr "" + msgid "Limit the number of concurrent operations this secondary node can run in the background." msgstr "" @@ -19760,6 +19790,9 @@ msgstr "" msgid "Maximum number of projects." msgstr "" +msgid "Maximum number of unique IPs per user" +msgstr "" + msgid "Maximum page reached" msgstr "" @@ -23894,6 +23927,9 @@ msgstr "" msgid "Please provide attributes to update" msgstr "" +msgid "Please provide your username or email address." +msgstr "" + msgid "Please reach out if you have any questions and we'll be happy to assist." msgstr "" @@ -29304,6 +29340,9 @@ msgstr "" msgid "Sign in / Register" msgstr "" +msgid "Sign in preview" +msgstr "" + msgid "Sign in to \"%{group_name}\"" msgstr "" @@ -32983,6 +33022,9 @@ msgstr "" msgid "Tip:" msgstr "" +msgid "Tip: Hover over a job to see the jobs it depends on to run." +msgstr "" + msgid "Tip: add a" msgstr "" @@ -38081,6 +38123,12 @@ msgstr "" msgid "quick actions" msgstr "" +msgid "reCAPTCHA Private Key" +msgstr "" + +msgid "reCAPTCHA Site Key" +msgstr "" + msgid "recent activity" msgstr "" diff --git a/package.json b/package.json index 5c86a0c7839..04212e374b8 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "codemirror": "^5.48.4", "codesandbox-api": "0.0.23", "compression-webpack-plugin": "^5.0.2", - "copy-webpack-plugin": "^5.1.2", + "copy-webpack-plugin": "^6.4.1", "core-js": "^3.11.0", "cron-validator": "^1.1.1", "cropper": "^2.3.0", diff --git a/spec/factories/gitlab/database/background_migration/batched_jobs.rb b/spec/factories/gitlab/database/background_migration/batched_jobs.rb index 52bc04447da..cec20616f7f 100644 --- a/spec/factories/gitlab/database/background_migration/batched_jobs.rb +++ b/spec/factories/gitlab/database/background_migration/batched_jobs.rb @@ -8,5 +8,6 @@ FactoryBot.define do max_value { 10 } batch_size { 5 } sub_batch_size { 1 } + pause_ms { 100 } end end diff --git a/spec/factories/gitlab/database/background_migration/batched_migrations.rb b/spec/factories/gitlab/database/background_migration/batched_migrations.rb index 49cbdc5a8fb..c03841d8c02 100644 --- a/spec/factories/gitlab/database/background_migration/batched_migrations.rb +++ b/spec/factories/gitlab/database/background_migration/batched_migrations.rb @@ -10,5 +10,6 @@ FactoryBot.define do table_name { :events } column_name { :id } total_tuple_count { 10_000 } + pause_ms { 100 } end end diff --git a/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js b/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js index 28f43476dc8..4914a9a1ced 100644 --- a/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js +++ b/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js @@ -17,7 +17,8 @@ import GraphViewSelector from '~/pipelines/components/graph/graph_view_selector. import StageColumnComponent from '~/pipelines/components/graph/stage_column_component.vue'; import LinksLayer from '~/pipelines/components/graph_shared/links_layer.vue'; import * as parsingUtils from '~/pipelines/components/parsing_utils'; -import { mockPipelineResponse } from './mock_data'; +import getUserCallouts from '~/pipelines/graphql/queries/get_user_callouts.query.graphql'; +import { mapCallouts, mockCalloutsResponse, mockPipelineResponse } from './mock_data'; const defaultProvide = { graphqlResourceEtag: 'frog/amphibirama/etag/', @@ -31,15 +32,16 @@ describe('Pipeline graph wrapper', () => { useLocalStorageSpy(); let wrapper; - const getAlert = () => wrapper.find(GlAlert); + const getAlert = () => wrapper.findComponent(GlAlert); const getDependenciesToggle = () => wrapper.find('[data-testid="show-links-toggle"]'); - const getLoadingIcon = () => wrapper.find(GlLoadingIcon); + const getLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); const getLinksLayer = () => wrapper.findComponent(LinksLayer); const getGraph = () => wrapper.find(PipelineGraph); const getStageColumnTitle = () => wrapper.find('[data-testid="stage-column-title"]'); const getAllStageColumnGroupsInColumn = () => wrapper.find(StageColumnComponent).findAll('[data-testid="stage-column-group"]'); const getViewSelector = () => wrapper.find(GraphViewSelector); + const getViewSelectorTrip = () => getViewSelector().findComponent(GlAlert); const createComponent = ({ apolloProvider, @@ -62,12 +64,19 @@ describe('Pipeline graph wrapper', () => { }; const createComponentWithApollo = ({ + calloutsList = [], data = {}, getPipelineDetailsHandler = jest.fn().mockResolvedValue(mockPipelineResponse), mountFn = shallowMount, provide = {}, } = {}) => { - const requestHandlers = [[getPipelineDetails, getPipelineDetailsHandler]]; + const callouts = mapCallouts(calloutsList); + const getUserCalloutsHandler = jest.fn().mockResolvedValue(mockCalloutsResponse(callouts)); + + const requestHandlers = [ + [getPipelineDetails, getPipelineDetailsHandler], + [getUserCallouts, getUserCalloutsHandler], + ]; const apolloProvider = createMockApollo(requestHandlers); createComponent({ apolloProvider, data, provide, mountFn }); @@ -325,6 +334,57 @@ describe('Pipeline graph wrapper', () => { }); }); + describe('when pipelineGraphLayersView feature flag is on, layers view is selected, and links are active', () => { + beforeEach(async () => { + createComponentWithApollo({ + provide: { + glFeatures: { + pipelineGraphLayersView: true, + }, + }, + data: { + currentViewType: LAYER_VIEW, + showLinks: true, + }, + mountFn: mount, + }); + + jest.runOnlyPendingTimers(); + await wrapper.vm.$nextTick(); + }); + + it('shows the hover tip in the view selector', async () => { + await getViewSelector().setData({ showLinksActive: true }); + expect(getViewSelectorTrip().exists()).toBe(true); + }); + }); + + describe('when hover tip would otherwise show, but it has been previously dismissed', () => { + beforeEach(async () => { + createComponentWithApollo({ + provide: { + glFeatures: { + pipelineGraphLayersView: true, + }, + }, + data: { + currentViewType: LAYER_VIEW, + showLinks: true, + }, + mountFn: mount, + calloutsList: ['pipeline_needs_hover_tip'.toUpperCase()], + }); + + jest.runOnlyPendingTimers(); + await wrapper.vm.$nextTick(); + }); + + it('does not show the hover tip', async () => { + await getViewSelector().setData({ showLinksActive: true }); + expect(getViewSelectorTrip().exists()).toBe(false); + }); + }); + describe('when feature flag is on and local storage is set', () => { beforeEach(async () => { localStorage.setItem(VIEW_TYPE_KEY, LAYER_VIEW); diff --git a/spec/frontend/pipelines/graph/graph_view_selector_spec.js b/spec/frontend/pipelines/graph/graph_view_selector_spec.js index abf25a84634..5b2a29de443 100644 --- a/spec/frontend/pipelines/graph/graph_view_selector_spec.js +++ b/spec/frontend/pipelines/graph/graph_view_selector_spec.js @@ -1,4 +1,4 @@ -import { GlLoadingIcon, GlSegmentedControl } from '@gitlab/ui'; +import { GlAlert, GlLoadingIcon, GlSegmentedControl } from '@gitlab/ui'; import { mount, shallowMount } from '@vue/test-utils'; import { LAYER_VIEW, STAGE_VIEW } from '~/pipelines/components/graph/constants'; import GraphViewSelector from '~/pipelines/components/graph/graph_view_selector.vue'; @@ -12,16 +12,19 @@ describe('the graph view selector component', () => { const findLayersViewLabel = () => findViewTypeSelector().findAll('label').at(1); const findSwitcherLoader = () => wrapper.find('[data-testid="switcher-loading-state"]'); const findToggleLoader = () => findDependenciesToggle().find(GlLoadingIcon); + const findHoverTip = () => wrapper.findComponent(GlAlert); const defaultProps = { showLinks: false, + tipPreviouslyDismissed: false, type: STAGE_VIEW, }; const defaultData = { - showLinksActive: false, + hoverTipDismissed: false, isToggleLoading: false, isSwitcherLoading: false, + showLinksActive: false, }; const createComponent = ({ data = {}, mountFn = shallowMount, props = {} } = {}) => { @@ -121,4 +124,66 @@ describe('the graph view selector component', () => { expect(wrapper.emitted().updateShowLinksState).toEqual([[true]]); }); }); + + describe('hover tip callout', () => { + describe('when links are live and it has not been previously dismissed', () => { + beforeEach(() => { + createComponent({ + props: { + showLinks: true, + }, + data: { + showLinksActive: true, + }, + mountFn: mount, + }); + }); + + it('is displayed', () => { + expect(findHoverTip().exists()).toBe(true); + expect(findHoverTip().text()).toBe(wrapper.vm.$options.i18n.hoverTipText); + }); + + it('emits dismissHoverTip event when the tip is dismissed', async () => { + expect(wrapper.emitted().dismissHoverTip).toBeUndefined(); + await findHoverTip().find('button').trigger('click'); + expect(wrapper.emitted().dismissHoverTip).toHaveLength(1); + }); + }); + + describe('when links are live and it has been previously dismissed', () => { + beforeEach(() => { + createComponent({ + props: { + showLinks: true, + tipPreviouslyDismissed: true, + }, + data: { + showLinksActive: true, + }, + }); + }); + + it('is not displayed', () => { + expect(findHoverTip().exists()).toBe(false); + }); + }); + + describe('when links are not live', () => { + beforeEach(() => { + createComponent({ + props: { + showLinks: true, + }, + data: { + showLinksActive: false, + }, + }); + }); + + it('is not displayed', () => { + expect(findHoverTip().exists()).toBe(false); + }); + }); + }); }); diff --git a/spec/frontend/pipelines/graph/mock_data.js b/spec/frontend/pipelines/graph/mock_data.js index cf420f68f37..472f2a8b211 100644 --- a/spec/frontend/pipelines/graph/mock_data.js +++ b/spec/frontend/pipelines/graph/mock_data.js @@ -669,3 +669,22 @@ export const pipelineWithUpstreamDownstream = (base) => { return generateResponse(pip, 'root/abcd-dag'); }; + +export const mapCallouts = (callouts) => + callouts.map((callout) => { + return { featureName: callout, __typename: 'UserCallout' }; + }); + +export const mockCalloutsResponse = (mappedCallouts) => ({ + data: { + currentUser: { + id: 45, + __typename: 'User', + callouts: { + id: 5, + __typename: 'UserCalloutConnection', + nodes: mappedCallouts, + }, + }, + }, +}); diff --git a/spec/lib/gitlab/background_migration/copy_column_using_background_migration_job_spec.rb b/spec/lib/gitlab/background_migration/copy_column_using_background_migration_job_spec.rb index 40f480d6dc9..68367eb67b8 100644 --- a/spec/lib/gitlab/background_migration/copy_column_using_background_migration_job_spec.rb +++ b/spec/lib/gitlab/background_migration/copy_column_using_background_migration_job_spec.rb @@ -6,6 +6,7 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo let(:table_name) { :copy_primary_key_test } let(:test_table) { table(table_name) } let(:sub_batch_size) { 1000 } + let(:pause_ms) { 0 } before do ActiveRecord::Base.connection.execute(<<~SQL) @@ -34,13 +35,13 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo SQL end - subject { described_class.new } + subject(:copy_columns) { described_class.new } describe '#perform' do let(:migration_class) { described_class.name } it 'copies all primary keys in range' do - subject.perform(12, 15, table_name, 'id', sub_batch_size, 'id', 'id_convert_to_bigint') + copy_columns.perform(12, 15, table_name, 'id', sub_batch_size, pause_ms, 'id', 'id_convert_to_bigint') expect(test_table.where('id = id_convert_to_bigint').pluck(:id)).to contain_exactly(12, 15) expect(test_table.where(id_convert_to_bigint: 0).pluck(:id)).to contain_exactly(11, 19) @@ -48,7 +49,7 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo end it 'copies all foreign keys in range' do - subject.perform(10, 14, table_name, 'id', sub_batch_size, 'fk', 'fk_convert_to_bigint') + copy_columns.perform(10, 14, table_name, 'id', sub_batch_size, pause_ms, 'fk', 'fk_convert_to_bigint') expect(test_table.where('fk = fk_convert_to_bigint').pluck(:id)).to contain_exactly(11, 12) expect(test_table.where(fk_convert_to_bigint: 0).pluck(:id)).to contain_exactly(15, 19) @@ -58,7 +59,7 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo it 'copies columns with NULLs' do expect(test_table.where("name_convert_to_text = 'no name'").count).to eq(4) - subject.perform(10, 20, table_name, 'id', sub_batch_size, 'name', 'name_convert_to_text') + copy_columns.perform(10, 20, table_name, 'id', sub_batch_size, pause_ms, 'name', 'name_convert_to_text') expect(test_table.where('name = name_convert_to_text').pluck(:id)).to contain_exactly(11, 12, 19) expect(test_table.where('name is NULL and name_convert_to_text is NULL').pluck(:id)).to contain_exactly(15) @@ -69,7 +70,7 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo columns_to_copy_from = %w[id fk] columns_to_copy_to = %w[id_convert_to_bigint fk_convert_to_bigint] - subject.perform(10, 15, table_name, 'id', sub_batch_size, columns_to_copy_from, columns_to_copy_to) + subject.perform(10, 15, table_name, 'id', sub_batch_size, pause_ms, columns_to_copy_from, columns_to_copy_to) expect(test_table.where('id = id_convert_to_bigint AND fk = fk_convert_to_bigint').pluck(:id)).to contain_exactly(11, 12, 15) expect(test_table.where(id_convert_to_bigint: 0).where(fk_convert_to_bigint: 0).pluck(:id)).to contain_exactly(19) @@ -81,16 +82,34 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo columns_to_copy_to = %w[id_convert_to_bigint] expect do - subject.perform(10, 15, table_name, 'id', sub_batch_size, columns_to_copy_from, columns_to_copy_to) + subject.perform(10, 15, table_name, 'id', sub_batch_size, pause_ms, columns_to_copy_from, columns_to_copy_to) end.to raise_error(ArgumentError, 'number of source and destination columns must match') end it 'tracks timings of queries' do - expect(subject.batch_metrics.timings).to be_empty + expect(copy_columns.batch_metrics.timings).to be_empty - subject.perform(10, 20, table_name, 'id', sub_batch_size, 'name', 'name_convert_to_text') + copy_columns.perform(10, 20, table_name, 'id', sub_batch_size, pause_ms, 'name', 'name_convert_to_text') - expect(subject.batch_metrics.timings[:update_all]).not_to be_empty + expect(copy_columns.batch_metrics.timings[:update_all]).not_to be_empty + end + + context 'pause interval between sub-batches' do + it 'sleeps for the specified time between sub-batches' do + sub_batch_size = 2 + + expect(copy_columns).to receive(:sleep).with(0.005) + + copy_columns.perform(10, 12, table_name, 'id', sub_batch_size, 5, 'name', 'name_convert_to_text') + end + + it 'treats negative values as 0' do + sub_batch_size = 2 + + expect(copy_columns).to receive(:sleep).with(0) + + copy_columns.perform(10, 12, table_name, 'id', sub_batch_size, -5, 'name', 'name_convert_to_text') + end end end end diff --git a/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb b/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb index 261e23d0745..ef50347de5d 100644 --- a/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb +++ b/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb @@ -119,7 +119,13 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :m end describe '#create_batched_job!' do - let(:batched_migration) { create(:batched_background_migration) } + let(:batched_migration) do + create(:batched_background_migration, + batch_size: 999, + sub_batch_size: 99, + pause_ms: 250 + ) + end it 'creates a batched_job with the correct batch configuration' do batched_job = batched_migration.create_batched_job!(1, 5) @@ -128,7 +134,9 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :m min_value: 1, max_value: 5, batch_size: batched_migration.batch_size, - sub_batch_size: batched_migration.sub_batch_size) + sub_batch_size: batched_migration.sub_batch_size, + pause_ms: 250 + ) end end diff --git a/spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb b/spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb index b8b91cc61f2..39a37234822 100644 --- a/spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb +++ b/spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb @@ -7,9 +7,16 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigrationWrapper, ' let(:job_class) { Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJob } + let_it_be(:pause_ms) { 250 } let_it_be(:active_migration) { create(:batched_background_migration, :active, job_arguments: [:id, :other_id]) } - let!(:job_record) { create(:batched_background_migration_job, batched_migration: active_migration) } + let!(:job_record) do + create(:batched_background_migration_job, + batched_migration: active_migration, + pause_ms: pause_ms + ) + end + let(:job_instance) { double('job instance', batch_metrics: {}) } before do @@ -17,7 +24,7 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigrationWrapper, ' end it 'runs the migration job' do - expect(job_instance).to receive(:perform).with(1, 10, 'events', 'id', 1, 'id', 'other_id') + expect(job_instance).to receive(:perform).with(1, 10, 'events', 'id', 1, pause_ms, 'id', 'other_id') subject end @@ -98,7 +105,7 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigrationWrapper, ' context 'when the migration job does not raise an error' do it 'marks the tracking record as succeeded' do - expect(job_instance).to receive(:perform).with(1, 10, 'events', 'id', 1, 'id', 'other_id') + expect(job_instance).to receive(:perform).with(1, 10, 'events', 'id', 1, pause_ms, 'id', 'other_id') freeze_time do subject @@ -115,7 +122,7 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigrationWrapper, ' shared_examples 'an error is raised' do |error_class| it 'marks the tracking record as failed' do expect(job_instance).to receive(:perform) - .with(1, 10, 'events', 'id', 1, 'id', 'other_id') + .with(1, 10, 'events', 'id', 1, pause_ms, 'id', 'other_id') .and_raise(error_class) freeze_time do diff --git a/spec/lib/object_storage/direct_upload_spec.rb b/spec/lib/object_storage/direct_upload_spec.rb index 12c6cbe03b3..4b374452c0a 100644 --- a/spec/lib/object_storage/direct_upload_spec.rb +++ b/spec/lib/object_storage/direct_upload_spec.rb @@ -126,6 +126,16 @@ RSpec.describe ObjectStorage::DirectUpload do expect(s3_config.keys).not_to include(%i(ServerSideEncryption SSEKMSKeyID)) end + context 'when no region is specified' do + before do + raw_config.delete(:region) + end + + it 'defaults to us-east-1' do + expect(subject[:ObjectStorage][:S3Config][:Region]).to eq('us-east-1') + end + end + context 'when feature flag is disabled' do before do stub_feature_flags(use_workhorse_s3_client: false) diff --git a/yarn.lock b/yarn.lock index a8e560490a4..37569da1136 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2671,7 +2671,7 @@ bytes@3.1.0: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== -cacache@^12.0.2, cacache@^12.0.3: +cacache@^12.0.2: version "12.0.3" resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.3.tgz#be99abba4e1bf5df461cd5a2c1071fc432573390" integrity sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw== @@ -3356,23 +3356,22 @@ copy-to-clipboard@^3.0.8: dependencies: toggle-selection "^1.0.6" -copy-webpack-plugin@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.1.2.tgz#8a889e1dcafa6c91c6cd4be1ad158f1d3823bae2" - integrity sha512-Uh7crJAco3AjBvgAy9Z75CjK8IG+gxaErro71THQ+vv/bl4HaQcpkexAY8KVW/T6D2W2IRr+couF/knIRkZMIQ== +copy-webpack-plugin@^6.4.1: + version "6.4.1" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-6.4.1.tgz#138cd9b436dbca0a6d071720d5414848992ec47e" + integrity sha512-MXyPCjdPVx5iiWyl40Va3JGh27bKzOTNY3NjUTrosD2q7dR/cLD0013uqJ3BpFbUjyONINjb6qI7nDIJujrMbA== dependencies: - cacache "^12.0.3" - find-cache-dir "^2.1.0" - glob-parent "^3.1.0" - globby "^7.1.1" - is-glob "^4.0.1" - loader-utils "^1.2.3" - minimatch "^3.0.4" + cacache "^15.0.5" + fast-glob "^3.2.4" + find-cache-dir "^3.3.1" + glob-parent "^5.1.1" + globby "^11.0.1" + loader-utils "^2.0.0" normalize-path "^3.0.0" - p-limit "^2.2.1" - schema-utils "^1.0.0" - serialize-javascript "^4.0.0" - webpack-log "^2.0.0" + p-limit "^3.0.2" + schema-utils "^3.0.0" + serialize-javascript "^5.0.1" + webpack-sources "^1.4.3" core-js-compat@^3.6.2: version "3.6.4" @@ -4152,13 +4151,6 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" -dir-glob@^2.0.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" - integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== - dependencies: - path-type "^3.0.0" - dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -5070,7 +5062,7 @@ fast-deep-equal@^3.1.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.1.1, fast-glob@^3.2.5: +fast-glob@^3.1.1, fast-glob@^3.2.4, fast-glob@^3.2.5: version "3.2.5" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661" integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg== @@ -5516,18 +5508,10 @@ gettext-extractor@^3.5.3: pofile "1.0.x" typescript "2 - 4" -glob-parent@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= - dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" - -glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@~5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" - integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== +glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@^5.1.1, glob-parent@~5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" @@ -5618,10 +5602,10 @@ globals@^13.6.0: dependencies: type-fest "^0.20.2" -globby@^11.0.2: - version "11.0.2" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.2.tgz#1af538b766a3b540ebfb58a32b2e2d5897321d83" - integrity sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og== +globby@^11.0.1, globby@^11.0.2: + version "11.0.3" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.3.tgz#9b1f0cb523e171dd1ad8c7b2a9fb4b644b9593cb" + integrity sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg== dependencies: array-union "^2.1.0" dir-glob "^3.0.1" @@ -5641,18 +5625,6 @@ globby@^6.1.0: pify "^2.0.0" pinkie-promise "^2.0.0" -globby@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/globby/-/globby-7.1.1.tgz#fb2ccff9401f8600945dfada97440cca972b8680" - integrity sha1-+yzP+UAfhgCUXfral0QMypcrhoA= - dependencies: - array-union "^1.0.1" - dir-glob "^2.0.0" - glob "^7.1.2" - ignore "^3.3.5" - pify "^3.0.0" - slash "^1.0.0" - globjoin@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" @@ -6100,11 +6072,6 @@ ignore-by-default@^1.0.1: resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk= -ignore@^3.3.5: - version "3.3.10" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" - integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== - ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" @@ -6394,7 +6361,7 @@ is-extendable@^1.0.1: dependencies: is-plain-object "^2.0.4" -is-extglob@^2.1.0, is-extglob@^2.1.1: +is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= @@ -6426,13 +6393,6 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-glob@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= - dependencies: - is-extglob "^2.1.0" - is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" @@ -9020,13 +8980,20 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" -p-limit@^2.0.0, p-limit@^2.2.0, p-limit@^2.2.1: +p-limit@^2.0.0, p-limit@^2.2.0: version "2.2.2" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ== dependencies: p-try "^2.0.0" +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -9201,11 +9168,6 @@ path-browserify@0.0.1: resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== -path-dirname@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= - path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" @@ -9269,13 +9231,6 @@ path-type@^2.0.0: dependencies: pify "^2.0.0" -path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -9315,11 +9270,6 @@ pify@^2.0.0: resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - pify@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" @@ -10558,6 +10508,13 @@ serialize-javascript@^4.0.0: dependencies: randombytes "^2.1.0" +serialize-javascript@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" + integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== + dependencies: + randombytes "^2.1.0" + serve-index@^1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" @@ -10686,11 +10643,6 @@ sisteransi@^1.0.4: resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== -slash@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= - slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -12883,6 +12835,11 @@ yeast@0.1.2: resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + zen-observable-ts@^0.8.21: version "0.8.21" resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.21.tgz#85d0031fbbde1eba3cd07d3ba90da241215f421d" |