diff --git a/.eslintignore b/.eslintignore index b7769ef8970..1d069e19385 100644 --- a/.eslintignore +++ b/.eslintignore @@ -9,4 +9,3 @@ /sitespeed-result/ /fixtures/**/*.graphql spec/fixtures/**/*.graphql -**/contracts/consumer/ diff --git a/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue b/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue index 75f02af28c4..e5a8f5e79a0 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue @@ -18,6 +18,20 @@ export default { required: true, }, }, + modal: { + actionPrimary: { + text: __('Discard changes'), + attributes: { + variant: 'danger', + }, + }, + actionCancel: { + text: __('Cancel'), + attributes: { + variant: 'default', + }, + }, + }, computed: { discardModalId() { return `discard-file-${this.activeFile.path}`; @@ -66,12 +80,11 @@ export default { {{ __("You will lose all changes you've made to this file. This action cannot be undone.") }} diff --git a/app/assets/javascripts/ide/components/commit_sidebar/list.vue b/app/assets/javascripts/ide/components/commit_sidebar/list.vue index 829686ef051..86b0666e7b0 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/list.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/list.vue @@ -38,6 +38,20 @@ export default { default: __('No changes'), }, }, + modal: { + actionPrimary: { + text: __('Discard all changes'), + attributes: { + variant: 'danger', + }, + }, + actionCancel: { + text: __('Cancel'), + attributes: { + variant: 'default', + }, + }, + }, computed: { titleText() { if (!this.title) return __('Changes'); @@ -106,11 +120,11 @@ export default { {{ $options.discardModalText }} diff --git a/app/assets/javascripts/issues/show/components/description.vue b/app/assets/javascripts/issues/show/components/description.vue index d6ea06d172e..f926169549d 100644 --- a/app/assets/javascripts/issues/show/components/description.vue +++ b/app/assets/javascripts/issues/show/components/description.vue @@ -174,9 +174,7 @@ export default { this.removeAllPointerEventListeners(); - if (this.issuableType === IssuableType.Issue) { - this.renderSortableLists(); - } + this.renderSortableLists(); if (this.workItemsEnabled) { this.renderTaskActions(); @@ -184,7 +182,10 @@ export default { } }, renderSortableLists() { - const lists = document.querySelectorAll('.description ul, .description ol'); + // We exclude GLFM table of contents which have a `section-nav` class on the root `ul`. + const lists = document.querySelectorAll( + '.description .md > ul:not(.section-nav), .description .md > ul:not(.section-nav) ul, .description ol', + ); lists.forEach((list) => { if (list.children.length <= 1) { return; diff --git a/app/assets/javascripts/pages/dashboard/todos/index/todos.js b/app/assets/javascripts/pages/dashboard/todos/index/todos.js index c4bbbdcd8ec..44299d235d5 100644 --- a/app/assets/javascripts/pages/dashboard/todos/index/todos.js +++ b/app/assets/javascripts/pages/dashboard/todos/index/todos.js @@ -31,6 +31,7 @@ export default class Todos { $('.js-done-todo, .js-undo-todo, .js-add-todo').off('click', this.updateRowStateClickedWrapper); $('.js-todos-mark-all', '.js-todos-undo-all').off('click', this.updateallStateClickedWrapper); $('.todo').off('click', this.goToTodoUrl); + $('.todo').off('auxclick', this.goToTodoUrl); } bindEvents() { @@ -40,6 +41,7 @@ export default class Todos { $('.js-done-todo, .js-undo-todo, .js-add-todo').on('click', this.updateRowStateClickedWrapper); $('.js-todos-mark-all, .js-todos-undo-all').on('click', this.updateAllStateClickedWrapper); $('.todo').on('click', this.goToTodoUrl); + $('.todo').on('auxclick', this.goToTodoUrl); } initFilters() { @@ -198,11 +200,13 @@ export default class Todos { e.stopPropagation(); e.preventDefault(); + const isPrimaryClick = e.button === 0; + if (isMetaClick(e)) { const windowTarget = '_blank'; window.open(todoLink, windowTarget); - } else { + } else if (isPrimaryClick) { visitUrl(todoLink); } } diff --git a/app/assets/javascripts/security_configuration/components/app.vue b/app/assets/javascripts/security_configuration/components/app.vue index d0c4ad3646c..34910781247 100644 --- a/app/assets/javascripts/security_configuration/components/app.vue +++ b/app/assets/javascripts/security_configuration/components/app.vue @@ -4,10 +4,9 @@ import { __, s__ } from '~/locale'; import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue'; import UserCalloutDismisser from '~/vue_shared/components/user_callout_dismisser.vue'; import SectionLayout from '~/vue_shared/security_configuration/components/section_layout.vue'; -import currentLicenseQuery from '~/security_configuration/graphql/current_license.query.graphql'; import AutoDevOpsAlert from './auto_dev_ops_alert.vue'; import AutoDevOpsEnabledAlert from './auto_dev_ops_enabled_alert.vue'; -import { AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY, LICENSE_ULTIMATE } from './constants'; +import { AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY } from './constants'; import FeatureCard from './feature_card.vue'; import TrainingProviderList from './training_provider_list.vue'; import UpgradeBanner from './upgrade_banner.vue'; @@ -51,17 +50,6 @@ export default { TrainingProviderList, }, inject: ['projectFullPath', 'vulnerabilityTrainingDocsPath'], - apollo: { - currentLicensePlan: { - query: currentLicenseQuery, - update({ currentLicense }) { - return currentLicense?.plan; - }, - error() { - this.hasCurrentLicenseFetchError = true; - }, - }, - }, props: { augmentedSecurityFeatures: { type: Array, @@ -96,13 +84,15 @@ export default { required: false, default: '', }, + securityTrainingEnabled: { + type: Boolean, + required: true, + }, }, data() { return { autoDevopsEnabledAlertDismissedProjects: [], errorMessage: '', - currentLicensePlan: '', - hasCurrentLicenseFetchError: false, }; }, computed: { @@ -123,12 +113,6 @@ export default { !this.autoDevopsEnabledAlertDismissedProjects.includes(this.projectFullPath) ); }, - shouldShowVulnerabilityManagementTab() { - // if the query fails (if the plan is `null` also means an error has occurred) we still want to show the feature - const hasQueryError = this.hasCurrentLicenseFetchError || this.currentLicensePlan === null; - - return hasQueryError || this.currentLicensePlan === LICENSE_ULTIMATE; - }, }, methods: { dismissAutoDevopsEnabledAlert() { @@ -270,7 +254,7 @@ export default { { 'gitlabCiPresent', 'autoDevopsEnabled', 'canEnableAutoDevops', + 'securityTrainingEnabled', ]), }, }); diff --git a/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue b/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue index 031de669489..974ad189f32 100644 --- a/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue +++ b/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue @@ -49,14 +49,14 @@ export default { }, request() { const state = { - variant: 'default', + selected: false, icon: 'attention', direction: 'add', }; if (this.user.attention_requested) { Object.assign(state, { - variant: 'warning', + selected: true, icon: 'attention-solid', direction: 'remove', }); @@ -92,7 +92,7 @@ export default { > '.html_safe, strong_text_end: ''.html_safe} = export_information.html_safe = link_to _('Learn more.'), help_page_path('user/group/settings/import_export.md'), target: '_blank', rel: 'noopener noreferrer' - = render Pajamas::AlertComponent.new(dismissible: false, alert_class: 'gl-mb-5') do |c| + = render Pajamas::AlertComponent.new(dismissible: false, alert_options: { class: 'gl-mb-5' }) do |c| = c.body do %p.gl-mb-0 %p= _('The following items will be exported:') diff --git a/app/views/groups/settings/_remove_button.html.haml b/app/views/groups/settings/_remove_button.html.haml index e765638953a..df978f3cb96 100644 --- a/app/views/groups/settings/_remove_button.html.haml +++ b/app/views/groups/settings/_remove_button.html.haml @@ -1,7 +1,7 @@ - remove_form_id = local_assigns.fetch(:remove_form_id, nil) - if group.paid? - = render Pajamas::AlertComponent.new(dismissible: false, alert_class: 'gl-mb-5', alert_data: { testid: 'group-has-linked-subscription-alert' }) do |c| + = render Pajamas::AlertComponent.new(dismissible: false, alert_options: { class: 'gl-mb-5', data: { testid: 'group-has-linked-subscription-alert' }}) do |c| = c.body do = html_escape(_("This group can't be removed because it is linked to a subscription. To remove this group, %{linkStart}link the subscription%{linkEnd} with a different group.")) % { linkStart: "".html_safe, linkEnd: ''.html_safe } diff --git a/app/views/groups/settings/_transfer.html.haml b/app/views/groups/settings/_transfer.html.haml index e65c3cd13f6..e6c88977cb1 100644 --- a/app/views/groups/settings/_transfer.html.haml +++ b/app/views/groups/settings/_transfer.html.haml @@ -13,7 +13,7 @@ %li= s_('GroupSettings|You will need to update your local repositories to point to the new location.') %li= s_("GroupSettings|If the parent group's visibility is lower than the group's current visibility, visibility levels for subgroups and projects will be changed to match the new parent group's visibility.") - if group.paid? - = render Pajamas::AlertComponent.new(dismissible: false, alert_class: 'gl-mb-5') do |c| + = render Pajamas::AlertComponent.new(dismissible: false, alert_options: { class: 'gl-mb-5' }) do |c| = c.body do = html_escape(_("This group can't be transferred because it is linked to a subscription. To transfer this group, %{linkStart}link the subscription%{linkEnd} with a different group.")) % { linkStart: "".html_safe, linkEnd: ''.html_safe } .js-transfer-group-form{ data: initial_data } diff --git a/app/views/import/shared/_errors.html.haml b/app/views/import/shared/_errors.html.haml index ae54d0544f3..2dbb54a9a0e 100644 --- a/app/views/import/shared/_errors.html.haml +++ b/app/views/import/shared/_errors.html.haml @@ -1,7 +1,7 @@ - if @errors.present? = render Pajamas::AlertComponent.new(variant: :danger, dismissible: false, - alert_class: 'gl-mb-5') do |c| + alert_options: { class: 'gl-mb-5' }) do |c| = c.body do - @errors.each do |error| = error diff --git a/app/views/layouts/header/_registration_enabled_callout.html.haml b/app/views/layouts/header/_registration_enabled_callout.html.haml index 03e961bda8f..dd3d14a5678 100644 --- a/app/views/layouts/header/_registration_enabled_callout.html.haml +++ b/app/views/layouts/header/_registration_enabled_callout.html.haml @@ -2,10 +2,10 @@ = render Pajamas::AlertComponent.new(title: _('Anyone can register for an account.'), variant: :warning, - alert_class: 'js-registration-enabled-callout', - alert_data: { feature_id: Users::CalloutsHelper::REGISTRATION_ENABLED_CALLOUT, - dismiss_endpoint: callouts_path }, - close_button_data: { testid: 'close-registration-enabled-callout' }) do |c| + alert_options: { class: 'js-registration-enabled-callout', + data: { feature_id: Users::CalloutsHelper::REGISTRATION_ENABLED_CALLOUT, + dismiss_endpoint: callouts_path }}, + close_button_options: { data: { testid: 'close-registration-enabled-callout' }}) do |c| = c.body do = _('Only allow anyone to register for accounts on GitLab instances that you intend to be used by anyone. Allowing anyone to register makes GitLab instances more vulnerable.') = c.actions do diff --git a/app/views/layouts/header/_storage_enforcement_banner.html.haml b/app/views/layouts/header/_storage_enforcement_banner.html.haml index 6613130fdf3..c117f22a402 100644 --- a/app/views/layouts/header/_storage_enforcement_banner.html.haml +++ b/app/views/layouts/header/_storage_enforcement_banner.html.haml @@ -4,11 +4,11 @@ - return unless banner_info.present? = render Pajamas::AlertComponent.new(variant: :warning, - alert_class: 'js-storage-enforcement-banner', - alert_data: { feature_id: banner_info[:callouts_feature_name], - dismiss_endpoint: banner_info[:callouts_path], - group_id: namespace.id, - defer_links: "true" }) do |c| + alert_options: { class: 'js-storage-enforcement-banner', + data: { feature_id: banner_info[:callouts_feature_name], + dismiss_endpoint: banner_info[:callouts_path], + group_id: namespace.id, + defer_links: "true" }}) do |c| = c.body do = banner_info[:text] = banner_info[:learn_more_link] diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml index 4f2cba747c7..745d3c62c5d 100644 --- a/app/views/profiles/accounts/show.html.haml +++ b/app/views/profiles/accounts/show.html.haml @@ -2,15 +2,15 @@ - @content_class = "limit-container-width" unless fluid_layout - if current_user.ldap_user? - = render Pajamas::AlertComponent.new(alert_class: 'gl-my-5', + = render Pajamas::AlertComponent.new(alert_options: { class: 'gl-my-5' }, dismissible: false) do |c| = c.body do = s_('Profiles|Some options are unavailable for LDAP accounts') - if params[:two_factor_auth_enabled_successfully] = render Pajamas::AlertComponent.new(variant: :success, - alert_class: 'gl-my-5', - close_button_class: 'js-close-2fa-enabled-success-alert') do |c| + alert_options: { class: 'gl-my-5' }, + close_button_options: { class: 'js-close-2fa-enabled-success-alert' }) do |c| = c.body do = html_escape(_('You have set up 2FA for your account! If you lose access to your 2FA device, you can use your recovery codes to access your account. Alternatively, if you upload an SSH key, you can %{anchorOpen}use that key to generate additional recovery codes%{anchorClose}.')) % { anchorOpen: ''.html_safe % { href: help_page_path('user/profile/account/two_factor_authentication', anchor: 'generate-new-recovery-codes-using-ssh') }, anchorClose: ''.html_safe } diff --git a/app/views/projects/_deletion_failed.html.haml b/app/views/projects/_deletion_failed.html.haml index 85a7b9eb22b..489d303c5b9 100644 --- a/app/views/projects/_deletion_failed.html.haml +++ b/app/views/projects/_deletion_failed.html.haml @@ -3,7 +3,7 @@ = render Pajamas::AlertComponent.new(variant: :warning, dismissible: false, - alert_class: 'project-deletion-failed-message') do |c| + alert_options: { class: 'project-deletion-failed-message' }) do |c| = c.body do This project was scheduled for deletion, but failed with the following message: = project.delete_error diff --git a/app/views/projects/_last_push.html.haml b/app/views/projects/_last_push.html.haml index 5a2add9de1e..9845de17a11 100644 --- a/app/views/projects/_last_push.html.haml +++ b/app/views/projects/_last_push.html.haml @@ -1,8 +1,8 @@ - event = last_push_event - if event && show_last_push_widget?(event) = render Pajamas::AlertComponent.new(variant: :success, - alert_class: 'gl-mt-3', - close_button_class: 'js-close-banner') do |c| + alert_options: { class: 'gl-mt-3' }, + close_button_options: { class: 'js-close-banner' }) do |c| = c.body do %span= s_("LastPushEvent|You pushed to") %strong.gl-display-inline-flex.gl-max-w-50p{ data: { toggle: 'tooltip' }, title: event.ref_name } diff --git a/app/views/projects/_new_project_fields.html.haml b/app/views/projects/_new_project_fields.html.haml index 66fa1a69ef9..2cbb9758703 100644 --- a/app/views/projects/_new_project_fields.html.haml +++ b/app/views/projects/_new_project_fields.html.haml @@ -37,7 +37,7 @@ - link_start_group_path = '' % { path: new_group_path } - project_tip = s_('ProjectsNew|Want to house several dependent projects under the same namespace? %{link_start}Create a group.%{link_end}') % { link_start: link_start_group_path, link_end: '' } = project_tip.html_safe -= render Pajamas::AlertComponent.new(alert_class: "gl-mb-4 gl-display-none js-user-readme-repo", += render Pajamas::AlertComponent.new(alert_options: { class: "gl-mb-4 gl-display-none js-user-readme-repo" }, dismissible: false, variant: :success) do |c| = c.body do diff --git a/app/views/projects/blob/_upload.html.haml b/app/views/projects/blob/_upload.html.haml index 7251349c0e3..70c02ed4e99 100644 --- a/app/views/projects/blob/_upload.html.haml +++ b/app/views/projects/blob/_upload.html.haml @@ -16,7 +16,7 @@ %br = render Pajamas::AlertComponent.new(variant: :danger, - alert_class: 'dropzone-alerts gl-alert gl-alert-danger gl-mb-5 data gl-display-none', + alert_options: { class: 'dropzone-alerts gl-alert gl-alert-danger gl-mb-5 data gl-display-none' }, dismissible: false) = render 'shared/new_commit_form', placeholder: placeholder, ref: local_assigns[:ref] diff --git a/app/views/projects/blob/edit.html.haml b/app/views/projects/blob/edit.html.haml index 9b628e7ec43..220319d31b5 100644 --- a/app/views/projects/blob/edit.html.haml +++ b/app/views/projects/blob/edit.html.haml @@ -4,7 +4,7 @@ - webpack_preload_asset_tag('monaco') - if @conflict - = render Pajamas::AlertComponent.new(alert_class: 'gl-mb-5 gl-mt-5', + = render Pajamas::AlertComponent.new(alert_options: { class: 'gl-mb-5 gl-mt-5' }, variant: :danger, dismissible: false) do |c| - blob_url = project_blob_path(@project, @id) diff --git a/app/views/projects/forks/error.html.haml b/app/views/projects/forks/error.html.haml index 13fd4cee0cc..022a96b15a7 100644 --- a/app/views/projects/forks/error.html.haml +++ b/app/views/projects/forks/error.html.haml @@ -2,7 +2,7 @@ - if @forked_project && !@forked_project.saved? = render Pajamas::AlertComponent.new(title: _('Fork Error!'), variant: :danger, - alert_class: 'gl-mt-5', + alert_options: { class: 'gl-mt-5' }, dismissible: false) do |c| = c.body do %p diff --git a/app/views/projects/issues/_alert_moved_from_service_desk.html.haml b/app/views/projects/issues/_alert_moved_from_service_desk.html.haml index 291edf014c3..cc8d5bdaeec 100644 --- a/app/views/projects/issues/_alert_moved_from_service_desk.html.haml +++ b/app/views/projects/issues/_alert_moved_from_service_desk.html.haml @@ -3,6 +3,6 @@ - service_desk_link_start = ''.html_safe % { url: service_desk_link_url } = render Pajamas::AlertComponent.new(variant: :warning, - alert_class: 'hide js-alert-moved-from-service-desk-warning gl-mt-5') do |c| + alert_options: { class: 'hide js-alert-moved-from-service-desk-warning gl-mt-5' }) do |c| = c.body do = s_('This project does not have %{service_desk_link_start}Service Desk%{service_desk_link_end} enabled, so the user who created the issue will no longer receive email notifications about new activity.').html_safe % { service_desk_link_start: service_desk_link_start, service_desk_link_end: ''.html_safe } diff --git a/app/views/projects/merge_requests/_mr_title.html.haml b/app/views/projects/merge_requests/_mr_title.html.haml index c1734b9c521..4f4acb6103f 100644 --- a/app/views/projects/merge_requests/_mr_title.html.haml +++ b/app/views/projects/merge_requests/_mr_title.html.haml @@ -7,7 +7,7 @@ = cache(cache_key, expires_in: 1.day) do - if @merge_request.closed_or_merged_without_fork? - = render Pajamas::AlertComponent.new(alert_class: 'gl-mb-5', + = render Pajamas::AlertComponent.new(alert_options: { class: 'gl-mb-5' }, variant: :danger, dismissible: false) do |c| = c.body do diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml index 4ec72176202..8ff7fe6da71 100644 --- a/app/views/projects/milestones/show.html.haml +++ b/app/views/projects/milestones/show.html.haml @@ -13,8 +13,8 @@ - if can?(current_user, :read_issue, @project) && @milestone.total_issues_count == 0 = render Pajamas::AlertComponent.new(dismissible: false, - alert_data: { testid: 'no-issues-alert' }, - alert_class: 'gl-mt-3 gl-mb-5') do |c| + alert_options: { class: 'gl-mt-3 gl-mb-5', + data: { testid: 'no-issues-alert' }}) do |c| = c.body do = _('Assign some issues to this milestone.') - else diff --git a/app/views/projects/tags/new.html.haml b/app/views/projects/tags/new.html.haml index 549e5e91488..2960b236264 100644 --- a/app/views/projects/tags/new.html.haml +++ b/app/views/projects/tags/new.html.haml @@ -2,7 +2,7 @@ - default_ref = params[:ref] || @project.default_branch - if @error - = render Pajamas::AlertComponent.new(variant: :danger, dismissible: true, close_button_class: 'gl-alert-dismiss') do |c| + = render Pajamas::AlertComponent.new(variant: :danger, dismissible: true, close_button_options: { class: 'gl-alert-dismiss' }) do |c| = c.body do = @error diff --git a/app/views/projects/usage_quotas/index.html.haml b/app/views/projects/usage_quotas/index.html.haml index 40b952d4ae9..b2c2394235a 100644 --- a/app/views/projects/usage_quotas/index.html.haml +++ b/app/views/projects/usage_quotas/index.html.haml @@ -2,7 +2,7 @@ = render Pajamas::AlertComponent.new(title: _('Repository usage recalculation started'), variant: :info, - alert_class: 'js-recalculation-started-alert gl-mt-4 gl-mb-5 gl-display-none') do |c| + alert_options: { class: 'js-recalculation-started-alert gl-mt-4 gl-mb-5 gl-display-none' }) do |c| = c.body do = _('To view usage, refresh this page in a few minutes.') diff --git a/app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml b/app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml index d69f54608e9..1f37e33a037 100644 --- a/app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml +++ b/app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml @@ -1,7 +1,7 @@ - if show_auto_devops_implicitly_enabled_banner?(project, current_user) - = render Pajamas::AlertComponent.new(alert_class: 'qa-auto-devops-banner auto-devops-implicitly-enabled-banner', - close_button_class: 'hide-auto-devops-implicitly-enabled-banner', - close_button_data: { project_id: project.id }) do |c| + = render Pajamas::AlertComponent.new(alert_options: { class: 'qa-auto-devops-banner auto-devops-implicitly-enabled-banner' }, + close_button_options: { class: 'hide-auto-devops-implicitly-enabled-banner', + data: { project_id: project.id }}) do |c| = c.body do = s_("AutoDevOps|The Auto DevOps pipeline has been enabled and will be used if no alternative CI configuration file is found.") - unless Gitlab.config.registry.enabled diff --git a/app/views/shared/_import_form.html.haml b/app/views/shared/_import_form.html.haml index 7248403d6c9..d10f514dc58 100644 --- a/app/views/shared/_import_form.html.haml +++ b/app/views/shared/_import_form.html.haml @@ -22,9 +22,9 @@ = f.text_field :import_url, value: import_url.sanitized_url, autocomplete: 'off', class: 'form-control gl-form-input', placeholder: 'https://gitlab.company.com/group/project.git', required: true = render Pajamas::AlertComponent.new(variant: :danger, - alert_class: 'gl-mt-3 js-import-url-error hide', + alert_options: { class: 'gl-mt-3 js-import-url-error hide' }, dismissible: false, - close_button_class: 'js-close-2fa-enabled-success-alert') do |c| + close_button_options: { class: 'js-close-2fa-enabled-success-alert' }) do |c| = c.body do = s_('Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials.') = render_if_exists 'shared/ee/import_form', f: f, ci_cd_only: ci_cd_only diff --git a/app/views/shared/_no_password.html.haml b/app/views/shared/_no_password.html.haml index 91cd91ec38b..76830230cf6 100644 --- a/app/views/shared/_no_password.html.haml +++ b/app/views/shared/_no_password.html.haml @@ -1,7 +1,7 @@ - if show_no_password_message? = render Pajamas::AlertComponent.new(variant: :warning, - alert_class: 'js-no-password-message', - close_button_class: 'js-hide-no-password-message') do |c| + alert_options: { class: 'js-no-password-message' }, + close_button_options: { class: 'js-hide-no-password-message' }) do |c| = c.body do = no_password_message = c.actions do diff --git a/app/views/shared/_no_ssh.html.haml b/app/views/shared/_no_ssh.html.haml index c4d8cb092dc..be1df54a432 100644 --- a/app/views/shared/_no_ssh.html.haml +++ b/app/views/shared/_no_ssh.html.haml @@ -1,7 +1,7 @@ - if show_no_ssh_key_message? = render Pajamas::AlertComponent.new(variant: :warning, - alert_class: 'js-no-ssh-message', - close_button_class: 'js-hide-no-ssh-message') do |c| + alert_options: { class: 'js-no-ssh-message' }, + close_button_options: { class: 'js-hide-no-ssh-message'}) do |c| = c.body do = s_("MissingSSHKeyWarningLink|You can't push or pull repositories using SSH until you add an SSH key to your profile.") = c.actions do diff --git a/app/views/shared/_project_limit.html.haml b/app/views/shared/_project_limit.html.haml index b630c829c76..60be03c6631 100644 --- a/app/views/shared/_project_limit.html.haml +++ b/app/views/shared/_project_limit.html.haml @@ -1,7 +1,7 @@ - if cookies[:hide_project_limit_message].blank? && !current_user.hide_project_limit && !current_user.can_create_project? && current_user.projects_limit > 0 = render Pajamas::AlertComponent.new(variant: :warning, dismissible: false, - alert_class: 'project-limit-message') do |c| + alert_options: { class: 'project-limit-message' }) do |c| = c.body do = _("You won't be able to create new projects because you have reached your project limit.") = c.actions do diff --git a/app/views/shared/_service_ping_consent.html.haml b/app/views/shared/_service_ping_consent.html.haml index d9954d39dc6..700ffa7aa12 100644 --- a/app/views/shared/_service_ping_consent.html.haml +++ b/app/views/shared/_service_ping_consent.html.haml @@ -1,5 +1,5 @@ - if session[:ask_for_usage_stats_consent] - = render Pajamas::AlertComponent.new(alert_class: 'service-ping-consent-message') do |c| + = render Pajamas::AlertComponent.new(alert_options: { class: 'service-ping-consent-message' }) do |c| = c.body do - docs_link = link_to _('collect usage information'), help_page_path('user/admin_area/settings/usage_statistics.md'), class: 'gl-link' - settings_link = link_to _('your settings'), metrics_and_profiling_admin_application_settings_path(anchor: 'js-usage-settings'), class: 'gl-link' diff --git a/app/views/shared/_two_factor_auth_recovery_settings_check.html.haml b/app/views/shared/_two_factor_auth_recovery_settings_check.html.haml index 0899756d088..ff4b2de2286 100644 --- a/app/views/shared/_two_factor_auth_recovery_settings_check.html.haml +++ b/app/views/shared/_two_factor_auth_recovery_settings_check.html.haml @@ -1,9 +1,9 @@ = render Pajamas::AlertComponent.new(variant: :warning, - alert_class: 'js-recovery-settings-callout gl-mt-5', - alert_data: { feature_id: Users::CalloutsHelper::TWO_FACTOR_AUTH_RECOVERY_SETTINGS_CHECK, - dismiss_endpoint: callouts_path, - defer_links: 'true' }, - close_button_data: { testid: 'close-account-recovery-regular-check-callout' }) do |c| + alert_options: { class: 'js-recovery-settings-callout gl-mt-5', + data: { feature_id: Users::CalloutsHelper::TWO_FACTOR_AUTH_RECOVERY_SETTINGS_CHECK, + dismiss_endpoint: callouts_path, + defer_links: 'true' }}, + close_button_options: { data: { testid: 'close-account-recovery-regular-check-callout' }}) do |c| = c.body do = s_('Profiles|Ensure you have two-factor authentication recovery codes stored in a safe place.') = link_to _('Learn more.'), help_page_path('user/profile/account/two_factor_authentication', anchor: 'recovery-codes'), target: '_blank', rel: 'noopener noreferrer' diff --git a/app/views/shared/errors/_gitaly_unavailable.html.haml b/app/views/shared/errors/_gitaly_unavailable.html.haml index c9d7920b9c2..ba3293a3f75 100644 --- a/app/views/shared/errors/_gitaly_unavailable.html.haml +++ b/app/views/shared/errors/_gitaly_unavailable.html.haml @@ -1,4 +1,4 @@ -= render Pajamas::AlertComponent.new(alert_class: 'gl-my-5', += render Pajamas::AlertComponent.new(alert_options: { class: 'gl-my-5' }, variant: :danger, dismissible: false, title: reason) do |c| diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index 6109061869a..da49a301087 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -8,7 +8,7 @@ - if @conflict = render Pajamas::AlertComponent.new(variant: :danger, dismissible: false, - alert_class: 'gl-mb-5') do |c| + alert_options: { class: 'gl-mb-5' }) do |c| = c.body do Someone edited the #{issuable.class.model_name.human.downcase} the same time you did. Please check out diff --git a/app/views/shared/issuable/_label_page_create.html.haml b/app/views/shared/issuable/_label_page_create.html.haml index 7ab82362e85..ec78b3f7ce3 100644 --- a/app/views/shared/issuable/_label_page_create.html.haml +++ b/app/views/shared/issuable/_label_page_create.html.haml @@ -6,7 +6,7 @@ .dropdown-page-two.dropdown-new-label = dropdown_title(create_label_title(subject), options: { back: true, close: show_close }) = dropdown_content do - = render Pajamas::AlertComponent.new(variant: :danger, alert_class: 'js-label-error gl-mb-3', dismissible: false) + = render Pajamas::AlertComponent.new(variant: :danger, alert_options: { class: 'js-label-error gl-mb-3' }, dismissible: false) %input#new_label_name.default-dropdown-input{ type: "text", placeholder: _('Name new label') } .suggest-colors.suggest-colors-dropdown = render_suggested_colors diff --git a/app/views/shared/issuable/form/_branch_chooser.html.haml b/app/views/shared/issuable/form/_branch_chooser.html.haml index 8a06b40fde5..8ab002f755f 100644 --- a/app/views/shared/issuable/form/_branch_chooser.html.haml +++ b/app/views/shared/issuable/form/_branch_chooser.html.haml @@ -37,7 +37,7 @@ data: { placeholder: _('Select branch'), endpoint: refs_project_path(@project, sort: 'updated_desc', find: 'branches') }}) - if source_level < target_level - = render Pajamas::AlertComponent.new(variant: :warning, dismissible: false, alert_class: 'gl-mb-4') do |c| + = render Pajamas::AlertComponent.new(variant: :warning, dismissible: false, alert_options: { class: 'gl-mb-4' }) do |c| = c.body do = visibilityMismatchString %br diff --git a/app/views/shared/milestones/_milestone_complete_alert.html.haml b/app/views/shared/milestones/_milestone_complete_alert.html.haml index 86f9193cc7a..bde8a0b91b0 100644 --- a/app/views/shared/milestones/_milestone_complete_alert.html.haml +++ b/app/views/shared/milestones/_milestone_complete_alert.html.haml @@ -2,7 +2,7 @@ - if milestone.complete? && milestone.active? = render Pajamas::AlertComponent.new(variant: :success, - alert_data: { testid: 'all-issues-closed-alert' }, + alert_options: { data: { testid: 'all-issues-closed-alert' }}, dismissible: false) do |c| = c.body do = yield diff --git a/app/views/shared/projects/_inactive_project_deletion_alert.html.haml b/app/views/shared/projects/_inactive_project_deletion_alert.html.haml index 6b57dbd969f..0030265f007 100644 --- a/app/views/shared/projects/_inactive_project_deletion_alert.html.haml +++ b/app/views/shared/projects/_inactive_project_deletion_alert.html.haml @@ -4,4 +4,4 @@ - deletion_date = inactive_project_deletion_date(@project) - title = _('Due to inactivity, this project is scheduled to be deleted on %{deletion_date}. %{link_start}Why is this scheduled?%{link_end}').html_safe % { deletion_date: deletion_date, link_start: link_start, link_end: link_end } - = render Pajamas::AlertComponent.new(title: title, variant: :warning, alert_class: 'gl-pb-3', dismissible: false) + = render Pajamas::AlertComponent.new(title: title, variant: :warning, alert_options: { class: 'gl-pb-3' }, dismissible: false) diff --git a/app/views/shared/runners/_runner_type_alert.html.haml b/app/views/shared/runners/_runner_type_alert.html.haml index 4bf02b71109..9736780c436 100644 --- a/app/views/shared/runners/_runner_type_alert.html.haml +++ b/app/views/shared/runners/_runner_type_alert.html.haml @@ -1,14 +1,14 @@ -- alert_class = 'gl-mb-5' +- alert_options = { class: 'gl-mb-5' } - if runner.group_type? - = render Pajamas::AlertComponent.new(alert_class: alert_class, + = render Pajamas::AlertComponent.new(alert_options: alert_options, title: s_('Runners|This runner is available to all projects and subgroups in a group.'), dismissible: false) do |c| = c.body do = s_('Runners|Use Group runners when you want all projects in a group to have access to a set of runners.') = link_to _('Learn more.'), help_page_path('ci/runners/runners_scope', anchor: 'group-runners'), target: '_blank', rel: 'noopener noreferrer' - else - = render Pajamas::AlertComponent.new(alert_class: alert_class, + = render Pajamas::AlertComponent.new(alert_options: alert_options, title: s_('Runners|This runner is associated with specific projects.'), dismissible: false) do |c| = c.body do diff --git a/doc/.vale/gitlab/Uppercase.yml b/doc/.vale/gitlab/Uppercase.yml index d7f4d75a012..1616ca26639 100644 --- a/doc/.vale/gitlab/Uppercase.yml +++ b/doc/.vale/gitlab/Uppercase.yml @@ -14,6 +14,7 @@ first: '\b([A-Z]{3,5})\b' second: '(?:\b[A-Z][a-z]+ )+\(([A-Z]{3,5})\)' # ... with the exception of these: exceptions: + - ACL - AJAX - ANSI - APAC diff --git a/doc/administration/geo/disaster_recovery/bring_primary_back.md b/doc/administration/geo/disaster_recovery/bring_primary_back.md index 4c0a46b3096..833b9a877e9 100644 --- a/doc/administration/geo/disaster_recovery/bring_primary_back.md +++ b/doc/administration/geo/disaster_recovery/bring_primary_back.md @@ -18,8 +18,8 @@ If you have any doubts about the consistency of the data on this site, we recomm ## Configure the former **primary** site to be a **secondary** site -Since the former **primary** site will be out of sync with the current **primary** site, the first step is to bring the former **primary** site up to date. Note, deletion of data stored on disk like -repositories and uploads will not be replayed when bringing the former **primary** site back +Since the former **primary** site is out of sync with the current **primary** site, the first step is to bring the former **primary** site up to date. Note, deletion of data stored on disk like +repositories and uploads is not replayed when bringing the former **primary** site back into sync, which may result in increased disk usage. Alternatively, you can [set up a new **secondary** GitLab instance](../setup/index.md) to avoid this. diff --git a/doc/administration/geo/disaster_recovery/planned_failover.md b/doc/administration/geo/disaster_recovery/planned_failover.md index 711017fa4c5..7d8dd7d5d2a 100644 --- a/doc/administration/geo/disaster_recovery/planned_failover.md +++ b/doc/administration/geo/disaster_recovery/planned_failover.md @@ -143,7 +143,7 @@ If the **primary** site uses custom or self-signed TLS certificates to secure in ### Ensure Geo replication is up-to-date -The maintenance window won't end until Geo replication and verification is +The maintenance window does not end until Geo replication and verification is completely finished. To keep the window as short as possible, you should ensure these processes are close to 100% as possible during active use. @@ -201,7 +201,7 @@ be disabled on the **primary** site: ## Finish replicating and verifying all data NOTE: -GitLab 13.9 through GitLab 14.3 are affected by a bug in which the Geo secondary site statuses will appear to stop updating and become unhealthy. For more information, see [Geo Admin Area shows 'Unhealthy' after enabling Maintenance Mode](../replication/troubleshooting.md#geo-admin-area-shows-unhealthy-after-enabling-maintenance-mode). +GitLab 13.9 through GitLab 14.3 are affected by a bug in which the Geo secondary site statuses appears to stop updating and become unhealthy. For more information, see [Geo Admin Area shows 'Unhealthy' after enabling Maintenance Mode](../replication/troubleshooting.md#geo-admin-area-shows-unhealthy-after-enabling-maintenance-mode). 1. If you are manually replicating any data not managed by Geo, trigger the final replication process now. diff --git a/doc/administration/geo/replication/faq.md b/doc/administration/geo/replication/faq.md index fd29310dea0..bdf1771e8a8 100644 --- a/doc/administration/geo/replication/faq.md +++ b/doc/administration/geo/replication/faq.md @@ -32,10 +32,10 @@ To ensure that problems with pipelines (for example, syncs failing too many time the number of concurrent syncs falls below `repos_max_capacity` and there are no new projects waiting to be synced. Geo also has a checksum feature which runs a SHA256 sum across all the Git references to the SHA values. -If the refs don't match between the **primary** site and the **secondary** site, then the **secondary** site will mark that project as dirty and try to resync it. +If the refs don't match between the **primary** site and the **secondary** site, then the **secondary** site marks that project as dirty and try to resync it. So even if we have an outdated tracking database, the validation should activate and find discrepancies in the repository state and resync. -## Can I use Geo in a disaster recovery situation? +## Can you use Geo in a disaster recovery situation? Yes, but there are limitations to what we replicate (see [What data is replicated to a **secondary** site?](#what-data-is-replicated-to-a-secondary-site)). @@ -46,7 +46,7 @@ Read the documentation for [Disaster Recovery](../disaster_recovery/index.md). We currently replicate project repositories, LFS objects, generated attachments and avatars, and the whole database. This means user accounts, -issues, merge requests, groups, project data, and so on, will be available for +issues, merge requests, groups, project data, and so on, are available for query. For more details, see the [supported Geo data types](datatypes.md). @@ -69,6 +69,6 @@ That's totally fine. We use HTTP(s) to fetch repository changes from the **prima Yes. See [Docker Registry for a **secondary** site](docker_registry.md). -## Can I login to a secondary site? +## Can you login to a secondary site? Yes, but secondary sites receive all authentication data (like user accounts and logins) from the primary instance. This means you are re-directed to the primary for authentication and then routed back. diff --git a/doc/administration/geo/replication/remove_geo_site.md b/doc/administration/geo/replication/remove_geo_site.md index e25b3421f50..0d6715a93b7 100644 --- a/doc/administration/geo/replication/remove_geo_site.md +++ b/doc/administration/geo/replication/remove_geo_site.md @@ -44,7 +44,7 @@ Once GitLab has been uninstalled from each node on the **secondary** site, the r ``` NOTE: - Using `gitlab-rails dbconsole` will not work, because managing replication slots requires superuser permissions. + Using `gitlab-rails dbconsole` does not work, because managing replication slots requires superuser permissions. 1. Find the name of the relevant replication slot. This is the slot that is specified with `--slot-name` when running the replicate command: `gitlab-ctl replicate-geo-database`. diff --git a/doc/administration/geo/replication/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md index 9b53ba86951..91bd3bd0273 100644 --- a/doc/administration/geo/replication/troubleshooting.md +++ b/doc/administration/geo/replication/troubleshooting.md @@ -398,7 +398,7 @@ where some queries never complete due to being canceled on every replication. These long-running queries are [planned to be removed in the future](https://gitlab.com/gitlab-org/gitlab/-/issues/34269), but as a workaround, we recommend enabling -[hot_standby_feedback](https://www.postgresql.org/docs/10/hot-standby.html#HOT-STANDBY-CONFLICT). +[`hot_standby_feedback`](https://www.postgresql.org/docs/10/hot-standby.html#HOT-STANDBY-CONFLICT). This increases the likelihood of bloat on the **primary** node as it prevents `VACUUM` from removing recently-dead rows. However, it has been used successfully in production on GitLab.com. @@ -767,7 +767,7 @@ The appropriate action sometimes depends on the cause. For example, you can remo In some cases, a file may be determined to be of low value, and so it may be worth deleting the record. -Geo itself is an excellent mitigation for files missing on the primary. If a file disappears on the primary but it was already synced to the secondary, you can grab the secondary's file. In cases like this, the `File is not checksummable` error message will not occur on Geo secondary sites, and only the primary will log this error message. +Geo itself is an excellent mitigation for files missing on the primary. If a file disappears on the primary but it was already synced to the secondary, you can grab the secondary's file. In cases like this, the `File is not checksummable` error message does not occur on Geo secondary sites, and only the primary logs this error message. This problem is more likely to show up in Geo secondary sites which were set up long after the original GitLab site. In this case, Geo is only surfacing an existing problem. @@ -1104,9 +1104,9 @@ If using a load balancer, ensure that the load balancer's URL is set as the `ext ### Geo Admin Area shows 'Unhealthy' after enabling Maintenance Mode -In GitLab 13.9 through GitLab 14.3, when [GitLab Maintenance Mode](../../maintenance_mode/index.md) is enabled, the status of Geo secondary sites will stop getting updated. After 10 minutes, the status changes to `Unhealthy`. +In GitLab 13.9 through GitLab 14.3, when [GitLab Maintenance Mode](../../maintenance_mode/index.md) is enabled, the status of Geo secondary sites stops getting updated. After 10 minutes, the status changes to `Unhealthy`. -Geo secondary sites will continue to replicate and verify data, and the secondary sites should still be usable. You can use the [Sync status Rake task](#sync-status-rake-task) to determine the actual status of a secondary site during Maintenance Mode. +Geo secondary sites continue to replicate and verify data, and the secondary sites should still be usable. You can use the [Sync status Rake task](#sync-status-rake-task) to determine the actual status of a secondary site during Maintenance Mode. This bug was [fixed in GitLab 14.4](https://gitlab.com/gitlab-org/gitlab/-/issues/292983). diff --git a/doc/administration/geo/replication/tuning.md b/doc/administration/geo/replication/tuning.md index 4888ff0022e..670459624f3 100644 --- a/doc/administration/geo/replication/tuning.md +++ b/doc/administration/geo/replication/tuning.md @@ -25,7 +25,7 @@ On the **primary** site: - Container repositories synchronization concurrency limit - Verification concurrency limit -Increasing the concurrency values will increase the number of jobs that are scheduled. +Increasing the concurrency values increases the number of jobs that are scheduled. However, this may not lead to more downloads in parallel unless the number of available Sidekiq threads is also increased. For example, if repository synchronization concurrency is increased from 25 to 50, you may also want to increase the number diff --git a/doc/administration/geo/replication/upgrading_the_geo_sites.md b/doc/administration/geo/replication/upgrading_the_geo_sites.md index 8230ccf65f3..30961de0381 100644 --- a/doc/administration/geo/replication/upgrading_the_geo_sites.md +++ b/doc/administration/geo/replication/upgrading_the_geo_sites.md @@ -22,7 +22,7 @@ Upgrading Geo sites involves performing: NOTE: These general upgrade steps are not intended for multi-site deployments, -and will cause downtime. If you want to avoid downtime, consider using +and cause downtime. If you want to avoid downtime, consider using [zero downtime upgrades](../../../update/zero_downtime.md#multi-node--ha-deployment-with-geo). To upgrade the Geo sites when a new GitLab version is released, upgrade **primary** diff --git a/doc/administration/geo/replication/usage.md b/doc/administration/geo/replication/usage.md index 7a1cc116182..fe0e06e7ea4 100644 --- a/doc/administration/geo/replication/usage.md +++ b/doc/administration/geo/replication/usage.md @@ -11,9 +11,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w After you set up the [database replication and configure the Geo nodes](../index.md#setup-instructions), use your closest GitLab site as you would do with the primary one. You can push directly to a **secondary** site (for both HTTP, SSH including -Git LFS), and the request will be proxied to the primary site instead. +Git LFS), and the request is proxied to the primary site instead. -Example of the output you will see when pushing to a **secondary** site: +Example of the output you see when pushing to a **secondary** site: ```shell $ git push @@ -31,7 +31,7 @@ If you're using HTTPS instead of [SSH](../../../user/ssh.md) to push to the seco you can't store credentials in the URL like `user:password@URL`. Instead, you can use a [`.netrc` file](https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html) for Unix-like operating systems or `_netrc` for Windows. In that case, the credentials -will be stored as a plain text. If you're looking for a more secure way to store credentials, +are stored as a plain text. If you're looking for a more secure way to store credentials, you can use [Git Credential Storage](https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage). ## Fetch Go modules from Geo secondary sites diff --git a/doc/administration/geo/setup/external_database.md b/doc/administration/geo/setup/external_database.md index ec0c17c15df..7e8ffa829f9 100644 --- a/doc/administration/geo/setup/external_database.md +++ b/doc/administration/geo/setup/external_database.md @@ -51,7 +51,7 @@ developed and tested. We aim to be compatible with most external gitlab-ctl set-geo-primary-node ``` - This command will use your defined `external_url` in `/etc/gitlab/gitlab.rb`. + This command uses your defined `external_url` in `/etc/gitlab/gitlab.rb`. ### Configure the external database to be replicated @@ -64,7 +64,7 @@ To set up an external database, you can either: Given you have a primary node set up on AWS EC2 that uses RDS. You can now just create a read-only replica in a different region and the -replication process will be managed by AWS. Make sure you've set Network ACL, Subnet, and +replication process is managed by AWS. Make sure you've set Network ACL (Access Control List), Subnet, and Security Group according to your needs, so the secondary application node can access the database. The following instructions detail how to create a read-only replica for common diff --git a/doc/administration/geo/setup/index.md b/doc/administration/geo/setup/index.md index 59748499a7e..f4c21293782 100644 --- a/doc/administration/geo/setup/index.md +++ b/doc/administration/geo/setup/index.md @@ -19,7 +19,7 @@ The steps below should be followed in the order they appear. **Make sure the Git If you installed GitLab using the Omnibus packages (highly recommended): -1. [Install GitLab Enterprise Edition](https://about.gitlab.com/install/) on the nodes that will serve as the **secondary** site. Do not create an account or log in to the new **secondary** site. The **GitLab version must match** across primary and secondary sites. +1. [Install GitLab Enterprise Edition](https://about.gitlab.com/install/) on the nodes that serve as the **secondary** site. Do not create an account or log in to the new **secondary** site. The **GitLab version must match** across primary and secondary sites. 1. [Add the GitLab License](../../../user/admin_area/license.md) on the **primary** site to unlock Geo. The license must be for [GitLab Premium](https://about.gitlab.com/pricing/) or higher. 1. [Set up the database replication](database.md) (`primary (read-write) <-> secondary (read-only)` topology). 1. [Configure fast lookup of authorized SSH keys in the database](../../operations/fast_ssh_key_lookup.md). This step is required and needs to be done on **both** the **primary** and **secondary** sites. diff --git a/doc/administration/raketasks/geo.md b/doc/administration/raketasks/geo.md index 1d3422d0d98..5c6c99d099b 100644 --- a/doc/administration/raketasks/geo.md +++ b/doc/administration/raketasks/geo.md @@ -33,7 +33,7 @@ sudo -u git -H bundle exec rake geo:git:housekeeping:incremental_repack RAILS_EN ### Full Repack This is equivalent of running `git repack -d -A --pack-kept-objects` on a -_bare_ repository which will optionally, write a reachability bitmap index +_bare_ repository which optionally, writes a reachability bitmap index when this is enabled in GitLab. **Omnibus Installation** diff --git a/doc/api/releases/links.md b/doc/api/releases/links.md index 66808900ab6..c239d06ecfd 100644 --- a/doc/api/releases/links.md +++ b/doc/api/releases/links.md @@ -6,21 +6,13 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Release links API **(FREE)** +> Support for [GitLab CI/CD job token](../../ci/jobs/ci_job_token.md) authentication [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/250819) in GitLab 15.1. + Use this API to manipulate GitLab [Release](../../user/project/releases/index.md) links. For manipulating other Release assets, see [Release API](index.md). GitLab supports links to `http`, `https`, and `ftp` assets. -## Authentication - -For authentication, the Release Links API accepts: - -- A [Personal Access Token](../../user/profile/personal_access_tokens.md) using the - `PRIVATE-TOKEN` header. -- A [Project Access Token](../../user/project/settings/project_access_tokens.md) using the `PRIVATE-TOKEN` header. - -The [GitLab CI/CD job token](../../ci/jobs/ci_job_token.md) `$CI_JOB_TOKEN` is not supported. See [GitLab issue #50819](https://gitlab.com/gitlab-org/gitlab/-/issues/250819) for more details. - ## Get links Get assets as links from a Release. diff --git a/doc/architecture/blueprints/database_scaling/size-limits.md b/doc/architecture/blueprints/database_scaling/size-limits.md index 968059691d9..cb380d11739 100644 --- a/doc/architecture/blueprints/database_scaling/size-limits.md +++ b/doc/architecture/blueprints/database_scaling/size-limits.md @@ -1,7 +1,8 @@ --- +stage: Data Stores +group: Database comments: false description: 'Database Scalability / Limit table sizes' -group: database --- # Database Scalability: Limit on-disk table size to < 100 GB for GitLab.com diff --git a/doc/ci/jobs/ci_job_token.md b/doc/ci/jobs/ci_job_token.md index c890e8be313..9567bc9cd65 100644 --- a/doc/ci/jobs/ci_job_token.md +++ b/doc/ci/jobs/ci_job_token.md @@ -20,7 +20,7 @@ You can use a GitLab CI/CD job token to authenticate with specific API endpoints - [Get job artifacts](../../api/job_artifacts.md#get-job-artifacts). - [Get job token's job](../../api/jobs.md#get-job-tokens-job). - [Pipeline triggers](../../api/pipeline_triggers.md), using the `token=` parameter. -- [Releases](../../api/releases/index.md). +- [Releases](../../api/releases/index.md) and [Release links](../../api/releases/links.md). - [Terraform plan](../../user/infrastructure/index.md). NOTE: diff --git a/doc/development/geo.md b/doc/development/geo.md index a44d3e9c01c..18dffe42177 100644 --- a/doc/development/geo.md +++ b/doc/development/geo.md @@ -33,15 +33,15 @@ for new events and creates background jobs for each specific event type. For example when a repository is updated, the Geo **primary** site creates a Geo event with an associated repository updated event. The Geo Log Cursor daemon -picks the event up and schedules a `Geo::ProjectSyncWorker` job which will -use the `Geo::RepositorySyncService` and `Geo::WikiSyncService` classes +picks the event up and schedules a `Geo::ProjectSyncWorker` job which +uses the `Geo::RepositorySyncService` and `Geo::WikiSyncService` classes to update the repository and the wiki respectively. The Geo Log Cursor daemon can operate in High Availability mode automatically. -The daemon will try to acquire a lock from time to time and once acquired, it -will behave as the *active* daemon. +The daemon tries to acquire a lock from time to time and once acquired, it +behaves as the *active* daemon. -Any additional running daemons on the same site, will be in standby +Any additional running daemons on the same site, is in standby mode, ready to resume work if the *active* daemon releases its lock. We use the [`ExclusiveLease`](https://www.rubydoc.info/github/gitlabhq/gitlabhq/Gitlab/ExclusiveLease) lock type with a small TTL, that is renewed at every diff --git a/doc/development/geo/framework.md b/doc/development/geo/framework.md index 7738daee3bc..18774b9b3fd 100644 --- a/doc/development/geo/framework.md +++ b/doc/development/geo/framework.md @@ -59,7 +59,7 @@ naming conventions: consume) events. It takes care of the communication between the primary site (where events are produced) and the secondary site (where events are consumed). The engineer who wants to incorporate - Geo in their feature will use the API of replicators to make this + Geo in their feature uses the API of replicators to make this happen. - **Geo Domain-Specific Language**: @@ -99,7 +99,7 @@ end The class name should be unique. It also is tightly coupled to the table name for the registry, so for this example the registry table -will be `package_file_registry`. +is `package_file_registry`. For the different data types Geo supports there are different strategies to include. Pick one that fits your needs. diff --git a/doc/development/merge_request_concepts/index.md b/doc/development/merge_request_concepts/index.md index 90e8ff41368..8df0da5123e 100644 --- a/doc/development/merge_request_concepts/index.md +++ b/doc/development/merge_request_concepts/index.md @@ -1,7 +1,7 @@ --- type: reference, dev -stage: create -group: code_review +stage: Create +group: Code Review info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines" --- diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md index 5b5878f6347..d14263f660a 100644 --- a/doc/raketasks/backup_restore.md +++ b/doc/raketasks/backup_restore.md @@ -1015,9 +1015,9 @@ more of the following options: - `BACKUP=timestamp_of_backup`: Required if more than one backup exists. Read what the [backup timestamp is about](#backup-timestamp). -- `force=yes`: Doesn't ask if the authorized_keys file should get regenerated, +- `force=yes`: Doesn't ask if the `authorized_keys` file should get regenerated, and assumes 'yes' for warning about database tables being removed, - enabling the "Write to authorized_keys file" setting, and updating LDAP + enabling the `Write to authorized_keys file` setting, and updating LDAP providers. If you're restoring into directories that are mount points, you must ensure these directories are @@ -1407,7 +1407,7 @@ There is an **experimental** script that attempts to automate this process in ## Back up and restore for installations using PgBouncer -Do NOT back up or restore GitLab through a PgBouncer connection. These +Do not back up or restore GitLab through a PgBouncer connection. These tasks must [bypass PgBouncer and connect directly to the PostgreSQL primary database node](#bypassing-pgbouncer), or they cause a GitLab outage. @@ -1418,7 +1418,7 @@ following error message is shown: ActiveRecord::StatementInvalid: PG::UndefinedTable ``` -Each time the GitLab backup runs, GitLab will start generating 500 errors and errors about missing +Each time the GitLab backup runs, GitLab starts generating 500 errors and errors about missing tables will [be logged by PostgreSQL](../administration/logs.md#postgresql-logs): ```plaintext @@ -1480,7 +1480,7 @@ WARNING: Avoid uncoordinated data processing by both the new and old servers, where multiple servers could connect concurrently and process the same data. For example, when using [incoming email](../administration/incoming_email.md), if both GitLab instances are -processing email at the same time, then both instances will end up missing some data. +processing email at the same time, then both instances miss some data. This type of problem can occur with other services as well, such as a [non-packaged database](https://docs.gitlab.com/omnibus/settings/database.html#using-a-non-packaged-postgresql-database-management-server), a non-packaged Redis instance, or non-packaged Sidekiq. diff --git a/doc/user/admin_area/settings/rate_limit_on_users_api.md b/doc/user/admin_area/settings/rate_limit_on_users_api.md index 7954055f38b..5eed989f73f 100644 --- a/doc/user/admin_area/settings/rate_limit_on_users_api.md +++ b/doc/user/admin_area/settings/rate_limit_on_users_api.md @@ -1,7 +1,7 @@ --- type: reference stage: Manage -group: Authentication & Authorization +group: Authentication and Authorization info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/user/group/epics/manage_epics.md b/doc/user/group/epics/manage_epics.md index cead676f136..e0334eda875 100644 --- a/doc/user/group/epics/manage_epics.md +++ b/doc/user/group/epics/manage_epics.md @@ -87,6 +87,26 @@ To edit an epic's start date, due date, or labels: 1. Next to each section in the right sidebar, select **Edit**. 1. Select the dates or labels for your epic. +### Reorder list items in the epic description + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15260) in GitLab 15.1. + +When you view an epic that has a list in the description, you can also reorder the list items. + +Prerequisites: + +- You must have at least the Reporter role for the project, be the author of the epic, or be + assigned to the epic. +- The epic's description must have an [ordered, unordered](../../markdown.md#lists), or + [task](../../markdown.md#task-lists) list. + +To reorder list items, when viewing an epic: + +1. Hover over the list item row to make the drag icon (**{drag-vertical}**) visible. +1. Select and hold the drag icon. +1. Drag the row to the new position in the list. +1. Release the drag icon. + ## Bulk edit epics > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7250) in GitLab 12.2. diff --git a/lib/api/release/links.rb b/lib/api/release/links.rb index bc5ffe5b21f..8b9380b332e 100644 --- a/lib/api/release/links.rb +++ b/lib/api/release/links.rb @@ -29,6 +29,7 @@ module API params do use :pagination end + route_setting :authentication, job_token_allowed: true get 'links' do authorize! :read_release, release @@ -45,6 +46,7 @@ module API optional :filepath, type: String, desc: 'The filepath of the link' optional :link_type, type: String, desc: 'The link type, one of: "runbook", "image", "package" or "other"' end + route_setting :authentication, job_token_allowed: true post 'links' do authorize! :create_release, release @@ -65,6 +67,7 @@ module API detail 'This feature was introduced in GitLab 11.7.' success Entities::Releases::Link end + route_setting :authentication, job_token_allowed: true get do authorize! :read_release, release @@ -82,6 +85,7 @@ module API optional :link_type, type: String, desc: 'The link type' at_least_one_of :name, :url end + route_setting :authentication, job_token_allowed: true put do authorize! :update_release, release @@ -96,6 +100,7 @@ module API detail 'This feature was introduced in GitLab 11.7.' success Entities::Releases::Link end + route_setting :authentication, job_token_allowed: true delete do authorize! :destroy_release, release diff --git a/lib/gitlab/audit/unauthenticated_author.rb b/lib/gitlab/audit/unauthenticated_author.rb index 84c323c1950..b811f9f8ad0 100644 --- a/lib/gitlab/audit/unauthenticated_author.rb +++ b/lib/gitlab/audit/unauthenticated_author.rb @@ -12,6 +12,10 @@ module Gitlab def name @name || _('An unauthenticated user') end + + def impersonated? + false + end end end end diff --git a/lib/gitlab/diff/rendered/notebook/diff_file.rb b/lib/gitlab/diff/rendered/notebook/diff_file.rb index 68011555c3c..99631d90ce6 100644 --- a/lib/gitlab/diff/rendered/notebook/diff_file.rb +++ b/lib/gitlab/diff/rendered/notebook/diff_file.rb @@ -3,9 +3,10 @@ module Gitlab module Diff module Rendered module Notebook - include Gitlab::Utils::StrongMemoize - class DiffFile < Gitlab::Diff::File + include Gitlab::Diff::Rendered::Notebook::DiffFileHelper + include Gitlab::Utils::StrongMemoize + RENDERED_TIMEOUT_BACKGROUND = 10.seconds RENDERED_TIMEOUT_FOREGROUND = 1.5.seconds BACKGROUND_EXECUTION = 'background' @@ -14,7 +15,6 @@ module Gitlab LOG_IPYNBDIFF_TIMEOUT = 'IPYNB_DIFF_TIMEOUT' LOG_IPYNBDIFF_INVALID = 'IPYNB_DIFF_INVALID' LOG_IPYNBDIFF_TRUNCATED = 'IPYNB_DIFF_TRUNCATED' - EMBEDDED_IMAGE_PATTERN = ' ![](data:image' attr_reader :source_diff @@ -51,7 +51,8 @@ module Gitlab def highlighted_diff_lines @highlighted_diff_lines ||= begin - removal_line_maps, addition_line_maps = compute_end_start_map + removal_line_maps, addition_line_maps = map_diff_block_to_source_line( + source_diff.highlighted_diff_lines, source_diff.new_file?, source_diff.deleted_file?) Gitlab::Diff::Highlight.new(self, repository: self.repository).highlight.map do |line| mutate_line(line, addition_line_maps, removal_line_maps) end @@ -90,55 +91,6 @@ module Gitlab diff end - def strip_diff_frontmatter(diff_content) - diff_content.scan(/.*\n/)[2..]&.join('') if diff_content.present? - end - - def transformed_line_to_source(transformed_line, transformed_blocks) - transformed_blocks.empty? ? 0 : ( transformed_blocks[transformed_line - 1][:source_line] || -1 ) + 1 - end - - def mutate_line(line, addition_line_maps, removal_line_maps) - line.new_pos = transformed_line_to_source(line.new_pos, notebook_diff.to.blocks) - line.old_pos = transformed_line_to_source(line.old_pos, notebook_diff.from.blocks) - - line.old_pos = addition_line_maps[line.new_pos] if line.old_pos == 0 && line.new_pos != 0 - line.new_pos = removal_line_maps[line.old_pos] if line.new_pos == 0 && line.old_pos != 0 - - # Lines that do not appear on the original diff should not be commentable - line.type = "#{line.type || 'unchanged'}-nomappinginraw" unless addition_line_maps[line.new_pos] || removal_line_maps[line.old_pos] - - line.line_code = line_code(line) - - line.rich_text = image_as_rich_text(line) - - line - end - - def compute_end_start_map - # line_codes are used for assigning notes to diffs, and these depend on the line on the new version and the - # line that would have been that one in the previous version. However, since we do a transformation on the - # file, that map gets lost. To overcome this, we look at the original source lines and build two maps: - # - For additions, we look at the latest line change for that line and pick the old line for that id - # - For removals, we look at the first line in the old version, and pick the first line on the new version - # - # - # The caveat here is that we can't have notes on lines that are not a translation of a line in the source - # diff - # - # (gitlab/diff/file.rb:75) - - removals = {} - additions = {} - - source_diff.highlighted_diff_lines.each do |line| - removals[line.old_pos] = line.new_pos unless source_diff.new_file? - additions[line.new_pos] = line.old_pos unless source_diff.deleted_file? - end - - [removals, additions] - end - def rendered_timeout @rendered_timeout ||= Gitlab::Metrics.counter( :ipynb_semantic_diff_timeouts_total, @@ -156,16 +108,27 @@ module Gitlab nil end - def image_as_rich_text(line) - # Strip the initial +, -, or space for the diff context - line_text = line.text[1..] + def compute_line_numbers(transformed_old_pos, transformed_new_pos, addition_line_maps, removal_line_maps) + new_pos = map_transformed_line_to_source(transformed_new_pos, notebook_diff.to.blocks) + old_pos = map_transformed_line_to_source(transformed_old_pos, notebook_diff.from.blocks) - if line_text.starts_with?(EMBEDDED_IMAGE_PATTERN) - image_body = line_text.delete_prefix(EMBEDDED_IMAGE_PATTERN).delete_suffix(')') - "".html_safe - else - line.rich_text - end + old_pos = addition_line_maps[new_pos] if old_pos == 0 && new_pos != 0 + new_pos = removal_line_maps[old_pos] if new_pos == 0 && old_pos != 0 + + [old_pos, new_pos] + end + + def mutate_line(line, addition_line_maps, removal_line_maps) + line.old_pos, line.new_pos = compute_line_numbers(line.old_pos, line.new_pos, addition_line_maps, removal_line_maps) + + # Lines that do not appear on the original diff should not be commentable + line.type = "#{line.type || 'unchanged'}-nomappinginraw" unless addition_line_maps[line.new_pos] || removal_line_maps[line.old_pos] + + line.line_code = line_code(line) + + line.rich_text = image_as_rich_text(line.text) || line.rich_text + + line end end end diff --git a/lib/gitlab/diff/rendered/notebook/diff_file_helper.rb b/lib/gitlab/diff/rendered/notebook/diff_file_helper.rb new file mode 100644 index 00000000000..822b3771276 --- /dev/null +++ b/lib/gitlab/diff/rendered/notebook/diff_file_helper.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true +module Gitlab + module Diff + module Rendered + module Notebook + module DiffFileHelper + EMBEDDED_IMAGE_PATTERN = ' ![](data:image' + + def strip_diff_frontmatter(diff_content) + diff_content.scan(/.*\n/)[2..]&.join('') if diff_content.present? + end + + def map_transformed_line_to_source(transformed_line, transformed_blocks) + transformed_blocks.empty? ? 0 : ( transformed_blocks[transformed_line - 1][:source_line] || -1 ) + 1 + end + + # line_codes are used for assigning notes to diffs, and these depend on the line on the new version and the + # line that would have been that one in the previous version. However, since we do a transformation on the + # file, that mapping gets lost. To overcome this, we look at the original source lines and build two maps: + # - For additions, we look at the latest line change for that line and pick the old line for that id + # - For removals, we look at the first line in the old version, and pick the first line on the new version + # + # Note: ipynb files never change the first or last line (open and closure of the + # json object), unless the file is removed or deleted + # + # Example: Additions and removals + # Old: New: + # A A + # B D + # C E + # F F + # + # Diff: + # 1 A A 1 | line code: 1_1 + # 2 -B | line code: 2_2 -> new line is what it is after been without the removal, 2 + # 3 -C | line code: 3_2 + # + D 2 | line code: 4_2 -> old line is what would have been before the addition, 4 + # + E 3 | line code: 4_3 + # 4 F F 4 | line code: 4_4 + # + # Example: only additions + # Old: New: + # A A + # F B + # C + # F + # + # Diff: + # A A | line code: 1_1 + # + B | line code: 2_2 -> old line is the next after the additions, 2 + # + C | line code: 2_3 + # F F | line code: 2_4 + # + # Example: only removals + # Old: New: + # A A + # B F + # C + # F + # + # Diff: + # A A | line code: 1_1 + # -B | line code: 2_2 -> new line is what it is after been without the removal, 2 + # -C | line code: 3_2 + # F F | line code: 4_2 + def map_diff_block_to_source_line(lines, file_added, file_deleted) + removals = {} + additions = {} + + lines.each do |line| + removals[line.old_pos] = line.new_pos unless file_added + additions[line.new_pos] = line.old_pos unless file_deleted + end + + [removals, additions] + end + + def image_as_rich_text(line_text) + return unless line_text[1..].starts_with?(EMBEDDED_IMAGE_PATTERN) + + image_body = line_text[1..].delete_prefix(EMBEDDED_IMAGE_PATTERN).delete_suffix(')') + + "".html_safe + end + end + end + end + end +end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index a2e8a882f97..64589f872c2 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -34527,9 +34527,6 @@ msgstr "" msgid "SecurityReports|Unable to add %{invalidProjectsMessage}: %{errorMessage}" msgstr "" -msgid "SecurityReports|Unable to add %{invalidProjects}" -msgstr "" - msgid "SecurityReports|Undo dismiss" msgstr "" @@ -35923,9 +35920,6 @@ msgstr "" msgid "Something went wrong, unable to add %{project} to dashboard" msgstr "" -msgid "Something went wrong, unable to add projects to dashboard" -msgstr "" - msgid "Something went wrong, unable to delete project" msgstr "" diff --git a/spec/components/pajamas/alert_component_spec.rb b/spec/components/pajamas/alert_component_spec.rb index db425fb2dce..1e2845c44a8 100644 --- a/spec/components/pajamas/alert_component_spec.rb +++ b/spec/components/pajamas/alert_component_spec.rb @@ -50,10 +50,12 @@ RSpec.describe Pajamas::AlertComponent, :aggregate_failures, type: :component do before do render_inline described_class.new( title: '_title_', - alert_class: '_alert_class_', - alert_data: { - feature_id: '_feature_id_', - dismiss_endpoint: '_dismiss_endpoint_' + alert_options: { + class: '_alert_class_', + data: { + feature_id: '_feature_id_', + dismiss_endpoint: '_dismiss_endpoint_' + } } ) end @@ -106,9 +108,11 @@ RSpec.describe Pajamas::AlertComponent, :aggregate_failures, type: :component do context 'with dismissible content' do before do render_inline described_class.new( - close_button_class: '_close_button_class_', - close_button_data: { - testid: '_close_button_testid_' + close_button_options: { + class: '_close_button_class_', + data: { + testid: '_close_button_testid_' + } } ) end @@ -138,35 +142,5 @@ RSpec.describe Pajamas::AlertComponent, :aggregate_failures, type: :component do end end end - - context 'with alert_options' do - let(:options) { { alert_options: { id: 'test_id', class: 'baz', data: { foo: 'bar' } } } } - - before do - render_inline described_class.new(**options) - end - - it 'renders the extra options' do - expect(rendered_component).to have_css "#test_id.gl-alert.baz[data-foo='bar']" - end - - context 'with custom classes or data' do - let(:options) do - { - variant: :danger, - alert_class: 'custom', - alert_data: { foo: 'bar' }, - alert_options: { - class: 'extra special', - data: { foo: 'conflict' } - } - } - end - - it 'doesn\'t conflict with internal alert_class or alert_data' do - expect(rendered_component).to have_css ".extra.special.custom.gl-alert.gl-alert-danger[data-foo='bar']" - end - end - end end end diff --git a/spec/contracts/consumer/.eslintrc.yml b/spec/contracts/consumer/.eslintrc.yml new file mode 100644 index 00000000000..e4b380714d3 --- /dev/null +++ b/spec/contracts/consumer/.eslintrc.yml @@ -0,0 +1,7 @@ +--- +extends: + - 'plugin:@gitlab/jest' +settings: + import/core-modules: + - '@pact-foundation/pact' + - jest-pact diff --git a/spec/contracts/consumer/babel.config.json b/spec/contracts/consumer/babel.config.json new file mode 100644 index 00000000000..1320b9a3272 --- /dev/null +++ b/spec/contracts/consumer/babel.config.json @@ -0,0 +1,3 @@ +{ + "presets": ["@babel/preset-env"] +} diff --git a/spec/contracts/consumer/endpoints/merge_requests.js b/spec/contracts/consumer/endpoints/merge_requests.js index 04e66c57dc9..ae4d5544df6 100644 --- a/spec/contracts/consumer/endpoints/merge_requests.js +++ b/spec/contracts/consumer/endpoints/merge_requests.js @@ -1,42 +1,34 @@ -'use strict'; +import { request } from 'axios'; -const axios = require('axios'); +export function getMetadata(endpoint) { + const { url } = endpoint; -exports.getMetadata = (endpoint) => { - const url = endpoint.url; + return request({ + method: 'GET', + baseURL: url, + url: '/gitlab-org/gitlab-qa/-/merge_requests/1/diffs_metadata.json', + headers: { Accept: '*/*' }, + }).then((response) => response.data); +} - return axios - .request({ - method: 'GET', - baseURL: url, - url: '/gitlab-org/gitlab-qa/-/merge_requests/1/diffs_metadata.json', - headers: { Accept: '*/*' }, - }) - .then((response) => response.data); -}; +export function getDiscussions(endpoint) { + const { url } = endpoint; -exports.getDiscussions = (endpoint) => { - const url = endpoint.url; + return request({ + method: 'GET', + baseURL: url, + url: '/gitlab-org/gitlab-qa/-/merge_requests/1/discussions.json', + headers: { Accept: '*/*' }, + }).then((response) => response.data); +} - return axios - .request({ - method: 'GET', - baseURL: url, - url: '/gitlab-org/gitlab-qa/-/merge_requests/1/discussions.json', - headers: { Accept: '*/*' }, - }) - .then((response) => response.data); -}; +export function getDiffs(endpoint) { + const { url } = endpoint; -exports.getDiffs = (endpoint) => { - const url = endpoint.url; - - return axios - .request({ - method: 'GET', - baseURL: url, - url: '/gitlab-org/gitlab-qa/-/merge_requests/1/diffs_batch.json?page=0', - headers: { Accept: '*/*' }, - }) - .then((response) => response.data); -}; + return request({ + method: 'GET', + baseURL: url, + url: '/gitlab-org/gitlab-qa/-/merge_requests/1/diffs_batch.json?page=0', + headers: { Accept: '*/*' }, + }).then((response) => response.data); +} diff --git a/spec/contracts/consumer/fixtures/diffs.fixture.js b/spec/contracts/consumer/fixtures/diffs.fixture.js index 7dbe825b093..cc2c054b08f 100644 --- a/spec/contracts/consumer/fixtures/diffs.fixture.js +++ b/spec/contracts/consumer/fixtures/diffs.fixture.js @@ -1,6 +1,6 @@ -'use strict'; +/* eslint-disable @gitlab/require-i18n-strings */ -const { Matchers } = require('@pact-foundation/pact'); +import { Matchers } from '@pact-foundation/pact'; const body = { diff_files: Matchers.eachLike({ @@ -48,9 +48,9 @@ const body = { context_lines_path: Matchers.string('/gitlab-qa-bot/...'), highlighted_diff_lines: Matchers.eachLike({ // The following values can also be null which is not supported - //line_code: Matchers.string('de3150c01c3a946a6168173c4116741379fe3579_1_1'), - //old_line: Matchers.integer(1), - //new_line: Matchers.integer(1), + // line_code: Matchers.string('de3150c01c3a946a6168173c4116741379fe3579_1_1'), + // old_line: Matchers.integer(1), + // new_line: Matchers.integer(1), text: Matchers.string('source'), rich_text: Matchers.string(''), can_receive_suggestion: Matchers.boolean(true), @@ -70,7 +70,7 @@ const Diffs = { headers: { 'Content-Type': 'application/json; charset=utf-8', }, - body: body, + body, }, request: { @@ -86,4 +86,5 @@ const Diffs = { }, }; -exports.Diffs = Diffs; +export { Diffs }; +/* eslint-enable @gitlab/require-i18n-strings */ diff --git a/spec/contracts/consumer/fixtures/discussions.fixture.js b/spec/contracts/consumer/fixtures/discussions.fixture.js index c28b9bdd505..26f1d65f663 100644 --- a/spec/contracts/consumer/fixtures/discussions.fixture.js +++ b/spec/contracts/consumer/fixtures/discussions.fixture.js @@ -1,6 +1,6 @@ -'use strict'; +/* eslint-disable @gitlab/require-i18n-strings */ -const { Matchers } = require('@pact-foundation/pact'); +import { Matchers } from '@pact-foundation/pact'; const body = Matchers.eachLike({ id: Matchers.string('fd73763cbcbf7b29eb8765d969a38f7d735e222a'), @@ -67,7 +67,7 @@ const Discussions = { headers: { 'Content-Type': 'application/json; charset=utf-8', }, - body: body, + body, }, request: { @@ -82,4 +82,5 @@ const Discussions = { }, }; -exports.Discussions = Discussions; +export { Discussions }; +/* eslint-enable @gitlab/require-i18n-strings */ diff --git a/spec/contracts/consumer/fixtures/metadata.fixture.js b/spec/contracts/consumer/fixtures/metadata.fixture.js index 3fca6cf9181..c19ca2175b3 100644 --- a/spec/contracts/consumer/fixtures/metadata.fixture.js +++ b/spec/contracts/consumer/fixtures/metadata.fixture.js @@ -1,6 +1,6 @@ -'use strict'; +/* eslint-disable @gitlab/require-i18n-strings */ -const { Matchers } = require('@pact-foundation/pact'); +import { Matchers } from '@pact-foundation/pact'; const body = { real_size: Matchers.string('1'), @@ -78,7 +78,7 @@ const Metadata = { headers: { 'Content-Type': 'application/json; charset=utf-8', }, - body: body, + body, }, request: { @@ -93,4 +93,5 @@ const Metadata = { }, }; -exports.Metadata = Metadata; +export { Metadata }; +/* eslint-enable @gitlab/require-i18n-strings */ diff --git a/spec/contracts/consumer/package.json b/spec/contracts/consumer/package.json index 6a427ff8a7b..6d3feaa6d4c 100644 --- a/spec/contracts/consumer/package.json +++ b/spec/contracts/consumer/package.json @@ -13,5 +13,14 @@ }, "scripts": { "test": "jest --runInBand" + }, + "jest": { + "transform": { + "^.+\\.[t|j]sx?$": "babel-jest" + } + }, + "devDependencies": { + "@babel/preset-env": "^7.18.2", + "babel-jest": "^28.1.1" } } diff --git a/spec/contracts/consumer/specs/diffs.spec.js b/spec/contracts/consumer/specs/diffs.spec.js index b812461cb69..6b1cefdbdbc 100644 --- a/spec/contracts/consumer/specs/diffs.spec.js +++ b/spec/contracts/consumer/specs/diffs.spec.js @@ -1,9 +1,9 @@ -'use strict'; +/* eslint-disable @gitlab/require-i18n-strings */ -const { pactWith } = require('jest-pact'); +import { pactWith } from 'jest-pact'; -const { Diffs } = require('../fixtures/diffs.fixture'); -const { getDiffs } = require('../endpoints/merge_requests'); +import { Diffs } from '../fixtures/diffs.fixture'; +import { getDiffs } from '../endpoints/merge_requests'; pactWith( { @@ -34,3 +34,4 @@ pactWith( }); }, ); +/* eslint-enable @gitlab/require-i18n-strings */ diff --git a/spec/contracts/consumer/specs/discussions.spec.js b/spec/contracts/consumer/specs/discussions.spec.js index 304c240f7d3..2a5d0ba6267 100644 --- a/spec/contracts/consumer/specs/discussions.spec.js +++ b/spec/contracts/consumer/specs/discussions.spec.js @@ -1,9 +1,9 @@ -'use strict'; +/* eslint-disable @gitlab/require-i18n-strings */ -const { pactWith } = require('jest-pact'); +import { pactWith } from 'jest-pact'; -const { Discussions } = require('../fixtures/discussions.fixture'); -const { getDiscussions } = require('../endpoints/merge_requests'); +import { Discussions } from '../fixtures/discussions.fixture'; +import { getDiscussions } from '../endpoints/merge_requests'; pactWith( { @@ -34,3 +34,4 @@ pactWith( }); }, ); +/* eslint-enable @gitlab/require-i18n-strings */ diff --git a/spec/contracts/consumer/specs/metadata.spec.js b/spec/contracts/consumer/specs/metadata.spec.js index c49d4c354b1..fc082cb6a46 100644 --- a/spec/contracts/consumer/specs/metadata.spec.js +++ b/spec/contracts/consumer/specs/metadata.spec.js @@ -1,9 +1,9 @@ -'use strict'; +/* eslint-disable @gitlab/require-i18n-strings */ -const { pactWith } = require('jest-pact'); +import { pactWith } from 'jest-pact'; -const { Metadata } = require('../fixtures/metadata.fixture'); -const { getMetadata } = require('../endpoints/merge_requests'); +import { Metadata } from '../fixtures/metadata.fixture'; +import { getMetadata } from '../endpoints/merge_requests'; pactWith( { @@ -34,3 +34,4 @@ pactWith( }); }, ); +/* eslint-enable @gitlab/require-i18n-strings */ diff --git a/spec/frontend/ide/components/commit_sidebar/editor_header_spec.js b/spec/frontend/ide/components/commit_sidebar/editor_header_spec.js index 6e4c66cb780..d77e8e3d04c 100644 --- a/spec/frontend/ide/components/commit_sidebar/editor_header_spec.js +++ b/spec/frontend/ide/components/commit_sidebar/editor_header_spec.js @@ -68,7 +68,7 @@ describe('IDE commit editor header', () => { it('calls discardFileChanges if dialog result is confirmed', () => { expect(store.dispatch).not.toHaveBeenCalled(); - findDiscardModal().vm.$emit('ok'); + findDiscardModal().vm.$emit('primary'); expect(store.dispatch).toHaveBeenCalledWith('discardFileChanges', TEST_FILE_PATH); }); diff --git a/spec/frontend/security_configuration/components/app_spec.js b/spec/frontend/security_configuration/components/app_spec.js index d7d46d0d415..de91e51924d 100644 --- a/spec/frontend/security_configuration/components/app_spec.js +++ b/spec/frontend/security_configuration/components/app_spec.js @@ -2,7 +2,6 @@ import Vue, { nextTick } from 'vue'; import VueApollo from 'vue-apollo'; import { GlTab, GlTabs, GlLink } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; - import { useLocalStorageSpy } from 'helpers/local_storage_helper'; import { makeMockUserCalloutDismisser } from 'helpers/mock_user_callout_dismisser'; import stubChildren from 'helpers/stub_children'; @@ -20,22 +19,14 @@ import { LICENSE_COMPLIANCE_DESCRIPTION, LICENSE_COMPLIANCE_HELP_PATH, AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY, - LICENSE_ULTIMATE, - LICENSE_PREMIUM, - LICENSE_FREE, } from '~/security_configuration/components/constants'; import FeatureCard from '~/security_configuration/components/feature_card.vue'; import TrainingProviderList from '~/security_configuration/components/training_provider_list.vue'; -import createMockApollo from 'helpers/mock_apollo_helper'; -import currentLicenseQuery from '~/security_configuration/graphql/current_license.query.graphql'; -import waitForPromises from 'helpers/wait_for_promises'; - import UpgradeBanner from '~/security_configuration/components/upgrade_banner.vue'; import { REPORT_TYPE_LICENSE_COMPLIANCE, REPORT_TYPE_SAST, } from '~/vue_shared/security_reports/constants'; -import { getCurrentLicensePlanResponse } from '../mock_data'; const upgradePath = '/upgrade'; const autoDevopsHelpPagePath = '/autoDevopsHelpPagePath'; @@ -50,31 +41,16 @@ Vue.use(VueApollo); describe('App component', () => { let wrapper; let userCalloutDismissSpy; - let mockApollo; - const createComponent = ({ - shouldShowCallout = true, - licenseQueryResponse = LICENSE_ULTIMATE, - ...propsData - }) => { + const createComponent = ({ shouldShowCallout = true, ...propsData }) => { userCalloutDismissSpy = jest.fn(); - mockApollo = createMockApollo([ - [ - currentLicenseQuery, - jest - .fn() - .mockResolvedValue( - licenseQueryResponse instanceof Error - ? licenseQueryResponse - : getCurrentLicensePlanResponse(licenseQueryResponse), - ), - ], - ]); - wrapper = extendedWrapper( mount(SecurityConfigurationApp, { - propsData, + propsData: { + securityTrainingEnabled: true, + ...propsData, + }, provide: { upgradePath, autoDevopsHelpPagePath, @@ -82,7 +58,6 @@ describe('App component', () => { projectFullPath, vulnerabilityTrainingDocsPath, }, - apolloProvider: mockApollo, stubs: { ...stubChildren(SecurityConfigurationApp), GlLink: false, @@ -157,7 +132,6 @@ describe('App component', () => { afterEach(() => { wrapper.destroy(); - mockApollo = null; }); describe('basic structure', () => { @@ -166,7 +140,6 @@ describe('App component', () => { augmentedSecurityFeatures: securityFeaturesMock, augmentedComplianceFeatures: complianceFeaturesMock, }); - await waitForPromises(); }); it('renders main-heading with correct text', () => { @@ -469,47 +442,42 @@ describe('App component', () => { }); describe('Vulnerability management', () => { - beforeEach(async () => { + it('does not show tab if security training is disabled', () => { createComponent({ augmentedSecurityFeatures: securityFeaturesMock, augmentedComplianceFeatures: complianceFeaturesMock, + securityTrainingEnabled: false, }); - await waitForPromises(); + + expect(findVulnerabilityManagementTab().exists()).toBe(false); }); - it('renders TrainingProviderList component', () => { - expect(findTrainingProviderList().exists()).toBe(true); - }); - - it('renders security training description', () => { - expect(findVulnerabilityManagementTab().text()).toContain(i18n.securityTrainingDescription); - }); - - it('renders link to help docs', () => { - const trainingLink = findVulnerabilityManagementTab().findComponent(GlLink); - - expect(trainingLink.text()).toBe('Learn more about vulnerability training'); - expect(trainingLink.attributes('href')).toBe(vulnerabilityTrainingDocsPath); - }); - - it.each` - licenseQueryResponse | display - ${LICENSE_ULTIMATE} | ${true} - ${LICENSE_PREMIUM} | ${false} - ${LICENSE_FREE} | ${false} - ${null} | ${true} - ${new Error()} | ${true} - `( - 'displays $display for license $licenseQueryResponse', - async ({ licenseQueryResponse, display }) => { + describe('security training enabled', () => { + beforeEach(async () => { createComponent({ - licenseQueryResponse, augmentedSecurityFeatures: securityFeaturesMock, augmentedComplianceFeatures: complianceFeaturesMock, }); - await waitForPromises(); - expect(findVulnerabilityManagementTab().exists()).toBe(display); - }, - ); + }); + + it('shows the tab if security training is enabled', () => { + expect(findVulnerabilityManagementTab().exists()).toBe(true); + }); + + it('renders TrainingProviderList component', () => { + expect(findTrainingProviderList().exists()).toBe(true); + }); + + it('renders security training description', () => { + expect(findVulnerabilityManagementTab().text()).toContain(i18n.securityTrainingDescription); + }); + + it('renders link to help docs', () => { + const trainingLink = findVulnerabilityManagementTab().findComponent(GlLink); + + expect(trainingLink.text()).toBe('Learn more about vulnerability training'); + expect(trainingLink.attributes('href')).toBe(vulnerabilityTrainingDocsPath); + }); + }); }); }); diff --git a/spec/frontend/security_configuration/mock_data.js b/spec/frontend/security_configuration/mock_data.js index 94a36472a1d..18a480bf082 100644 --- a/spec/frontend/security_configuration/mock_data.js +++ b/spec/frontend/security_configuration/mock_data.js @@ -111,12 +111,3 @@ export const tempProviderLogos = { svg: `${[testProviderName[1]]}`, }, }; - -export const getCurrentLicensePlanResponse = (plan) => ({ - data: { - currentLicense: { - id: 'gid://gitlab/License/1', - plan, - }, - }, -}); diff --git a/spec/frontend/sidebar/components/attention_requested_toggle_spec.js b/spec/frontend/sidebar/components/attention_requested_toggle_spec.js index 959fa799eb7..58fa878a189 100644 --- a/spec/frontend/sidebar/components/attention_requested_toggle_spec.js +++ b/spec/frontend/sidebar/components/attention_requested_toggle_spec.js @@ -41,18 +41,18 @@ describe('Attention require toggle', () => { ); it.each` - attentionRequested | variant - ${true} | ${'warning'} - ${false} | ${'default'} + attentionRequested | selected + ${true} | ${true} + ${false} | ${false} `( - 'renders button with variant $variant when attention_requested is $attentionRequested', - ({ attentionRequested, variant }) => { + 'renders button with as selected when $selected when attention_requested is $attentionRequested', + ({ attentionRequested, selected }) => { factory({ type: 'reviewer', user: { attention_requested: attentionRequested, can_update_merge_request: true }, }); - expect(findToggle().props('variant')).toBe(variant); + expect(findToggle().props('selected')).toBe(selected); }, ); diff --git a/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js b/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js index 82526af7afa..01fbcb2154f 100644 --- a/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js +++ b/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js @@ -42,8 +42,8 @@ describe('Merge Request Collapsible Extension', () => { expect(wrapper.find('[data-testid="collapsed-header"]').text()).toBe('hello there'); }); - it('renders angle-right icon', () => { - expect(findIcon().props('name')).toBe('angle-right'); + it('renders chevron-lg-right icon', () => { + expect(findIcon().props('name')).toBe('chevron-lg-right'); }); describe('onClick', () => { @@ -60,8 +60,8 @@ describe('Merge Request Collapsible Extension', () => { expect(findTitle().text()).toBe('Collapse'); }); - it('renders angle-down icon', () => { - expect(findIcon().props('name')).toBe('angle-down'); + it('renders chevron-lg-down icon', () => { + expect(findIcon().props('name')).toBe('chevron-lg-down'); }); }); }); diff --git a/spec/helpers/form_helper_spec.rb b/spec/helpers/form_helper_spec.rb index 25dfa2251c3..c9c8c6b13b6 100644 --- a/spec/helpers/form_helper_spec.rb +++ b/spec/helpers/form_helper_spec.rb @@ -18,7 +18,7 @@ RSpec.describe FormHelper do expect(helper.form_errors(model, pajamas_alert: true)) .to include( - '