diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2024-01-03 00:12:50 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2024-01-03 00:12:50 +0300 |
commit | 3a72ac775065b61bbdb285a8f4f6f152ccb4db49 (patch) | |
tree | 3e03be3d792b6693a57f7ef3da8b228c694fb45a | |
parent | 0cea0a8f44d2cef1d4d132c72a07f8995962115c (diff) |
Add latest changes from gitlab-org/gitlab@master
41 files changed, 453 insertions, 248 deletions
diff --git a/.gitlab/ci/as-if-foss.gitlab-ci.yml b/.gitlab/ci/as-if-foss.gitlab-ci.yml index c1ba9d01c77..0c496ebacd8 100644 --- a/.gitlab/ci/as-if-foss.gitlab-ci.yml +++ b/.gitlab/ci/as-if-foss.gitlab-ci.yml @@ -64,6 +64,7 @@ start-as-if-foss: ENABLE_RSPEC_MIGRATION: $ENABLE_RSPEC_MIGRATION ENABLE_RSPEC_BACKGROUND_MIGRATION: $ENABLE_RSPEC_BACKGROUND_MIGRATION ENABLE_RSPEC_SYSTEM: $ENABLE_RSPEC_SYSTEM + ENABLE_JEST: $ENABLE_JEST trigger: project: gitlab-org/gitlab-foss branch: as-if-foss/${CI_COMMIT_REF_NAME} diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index 8817f8707e9..104c972f894 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -21,7 +21,7 @@ if: '$FORCE_GITLAB_CI' .if-default-refs: &if-default-refs - if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_COMMIT_REF_NAME =~ "^ruby\d+(_\d)*$" || ($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") || $CI_COMMIT_TAG || $FORCE_GITLAB_CI' + if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_COMMIT_REF_NAME =~ /^ruby\d+(_\d)*$/ || ($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") || $CI_COMMIT_TAG || $FORCE_GITLAB_CI' .if-default-branch-refs: &if-default-branch-refs if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $CI_MERGE_REQUEST_IID == null' @@ -1250,6 +1250,7 @@ rules: - <<: *if-merge-request-labels-pipeline-expedite when: never + - if: '$ENABLE_JEST == "true"' - <<: *if-merge-request-labels-run-all-rspec - <<: *if-merge-request-labels-frontend-and-feature-flag - <<: *if-default-refs @@ -1300,6 +1301,7 @@ when: never - <<: *if-fork-merge-request when: never + - if: '$ENABLE_JEST == "true"' - <<: *if-merge-request-labels-run-all-jest - <<: *if-merge-request-labels-frontend-and-feature-flag - <<: *if-merge-request diff --git a/.rubocop_todo/layout/space_in_lambda_literal.yml b/.rubocop_todo/layout/space_in_lambda_literal.yml index e0113d2628d..bd901e40016 100644 --- a/.rubocop_todo/layout/space_in_lambda_literal.yml +++ b/.rubocop_todo/layout/space_in_lambda_literal.yml @@ -358,7 +358,7 @@ Layout/SpaceInLambdaLiteral: - 'lib/gitlab/metrics/exporter/base_exporter.rb' - 'lib/gitlab/visibility_level.rb' - 'spec/deprecation_toolkit_env.rb' - - 'spec/features/admin/users/user_spec.rb' + - 'spec/features/admin/users/admin_sees_unconfirmed_user_spec.rb' - 'spec/helpers/namespaces_helper_spec.rb' - 'spec/lib/backup/gitaly_backup_spec.rb' - 'spec/lib/container_registry/client_spec.rb' diff --git a/.rubocop_todo/rspec/before_all_role_assignment.yml b/.rubocop_todo/rspec/before_all_role_assignment.yml index 3436cffc2ff..22eebde9389 100644 --- a/.rubocop_todo/rspec/before_all_role_assignment.yml +++ b/.rubocop_todo/rspec/before_all_role_assignment.yml @@ -800,7 +800,7 @@ RSpec/BeforeAllRoleAssignment: - 'spec/controllers/projects_controller_spec.rb' - 'spec/controllers/repositories/lfs_storage_controller_spec.rb' - 'spec/features/admin/admin_projects_spec.rb' - - 'spec/features/admin/users/user_spec.rb' + - 'spec/features/admin/users/admin_sees_user_spec.rb' - 'spec/features/admin/users/users_spec.rb' - 'spec/features/boards/board_filters_spec.rb' - 'spec/features/boards/new_issue_spec.rb' diff --git a/.rubocop_todo/rspec/context_wording.yml b/.rubocop_todo/rspec/context_wording.yml index 0a50fc4485d..fe7e9f045e7 100644 --- a/.rubocop_todo/rspec/context_wording.yml +++ b/.rubocop_todo/rspec/context_wording.yml @@ -1040,8 +1040,7 @@ RSpec/ContextWording: - 'spec/features/admin/admin_mode_spec.rb' - 'spec/features/admin/admin_settings_spec.rb' - 'spec/features/admin/dashboard_spec.rb' - - 'spec/features/admin/users/user_impersonation_spec.rb' - - 'spec/features/admin/users/user_spec.rb' + - 'spec/features/admin/users/admin_impersonates_user_spec.rb' - 'spec/features/admin/users/users_spec.rb' - 'spec/features/atom/dashboard_issues_spec.rb' - 'spec/features/atom/dashboard_spec.rb' diff --git a/.rubocop_todo/rspec/named_subject.yml b/.rubocop_todo/rspec/named_subject.yml index 885fd554ad6..b1835f31c63 100644 --- a/.rubocop_todo/rspec/named_subject.yml +++ b/.rubocop_todo/rspec/named_subject.yml @@ -1414,8 +1414,7 @@ RSpec/NamedSubject: - 'spec/controllers/users/callouts_controller_spec.rb' - 'spec/experiments/application_experiment_spec.rb' - 'spec/experiments/in_product_guidance_environments_webide_experiment_spec.rb' - - 'spec/features/admin/users/user_impersonation_spec.rb' - - 'spec/features/admin/users/user_spec.rb' + - 'spec/features/admin/users/admin_impersonates_user_spec.rb' - 'spec/features/groups/clusters/user_spec.rb' - 'spec/features/merge_request/user_sees_merge_widget_spec.rb' - 'spec/features/user_settings/password_spec.rb' diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue index 485d85b8872..85b981d9370 100644 --- a/app/assets/javascripts/work_items/components/work_item_detail.vue +++ b/app/assets/javascripts/work_items/components/work_item_detail.vue @@ -449,6 +449,7 @@ export default { class="gl-mt-3 gl-sm-display-block!" :is-editing="editMode" :title="workItem.title" + @updateWorkItem="updateWorkItem" @updateDraft="updateDraft('title', $event)" /> <work-item-title @@ -518,6 +519,7 @@ export default { :is-editing="editMode" :class="titleClassComponent" :title="workItem.title" + @updateWorkItem="updateWorkItem" @updateDraft="updateDraft('title', $event)" /> <work-item-title diff --git a/app/assets/javascripts/work_items/components/work_item_title_with_edit.vue b/app/assets/javascripts/work_items/components/work_item_title_with_edit.vue index 02ed25f98e4..6af564a6a91 100644 --- a/app/assets/javascripts/work_items/components/work_item_title_with_edit.vue +++ b/app/assets/javascripts/work_items/components/work_item_title_with_edit.vue @@ -27,10 +27,12 @@ export default { <template> <gl-form-group v-if="isEditing" :label="$options.i18n.titleLabel" label-for="work-item-title"> <gl-form-input - id="work-item-title" class="gl-w-full" :value="title" - @change="$emit('updateDraft', $event)" + data-testid="work-item-title-with-edit" + @keydown.meta.enter="$emit('updateWorkItem')" + @keydown.ctrl.enter="$emit('updateWorkItem')" + @input="$emit('updateDraft', $event)" /> </gl-form-group> <h1 diff --git a/app/controllers/ldap/omniauth_callbacks_controller.rb b/app/controllers/ldap/omniauth_callbacks_controller.rb index 955dfe58449..1c79bd3a668 100644 --- a/app/controllers/ldap/omniauth_callbacks_controller.rb +++ b/app/controllers/ldap/omniauth_callbacks_controller.rb @@ -28,7 +28,7 @@ class Ldap::OmniauthCallbacksController < OmniauthCallbacksController define_providers! override :set_remember_me - def set_remember_me(user) + def set_remember_me(user, _auth_user) user.remember_me = params[:remember_me] if user.persisted? end diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index 907ece1a06e..0701b1ee977 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -139,9 +139,11 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController identity_linker ||= auth_module::IdentityLinker.new(current_user, oauth, session) link_identity(identity_linker) - set_remember_me(current_user) - store_idp_two_factor_status(build_auth_user(auth_module::User).bypass_two_factor?) + current_auth_user = build_auth_user(auth_module::User) + set_remember_me(current_user, current_auth_user) + + store_idp_two_factor_status(current_auth_user.bypass_two_factor?) if identity_linker.changed? redirect_identity_linked @@ -193,7 +195,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController track_event(@user, oauth['provider'], 'succeeded') Gitlab::Tracking.event(self.class.name, "#{oauth['provider']}_sso", user: @user) if new_user - set_remember_me(@user) + set_remember_me(@user, auth_user) set_session_active_since(oauth['provider']) if ::AuthHelper.saml_providers.include?(oauth['provider'].to_sym) if @user.two_factor_enabled? && !auth_user.bypass_two_factor? @@ -278,10 +280,10 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController .for_authentication.security_event end - def set_remember_me(user) + def set_remember_me(user, auth_user) return unless remember_me? - if user.two_factor_enabled? + if user.two_factor_enabled? && !auth_user.bypass_two_factor? params[:remember_me] = '1' else remember_me(user) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index f863c1e5093..aa8bea1bd83 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -1712,8 +1712,6 @@ class MergeRequest < ApplicationRecord actual_head_pipeline&.complete_and_has_reports?(Ci::JobArtifact.of_report_type(:test)) end - # rubocop: disable Metrics/AbcSize - # Delete a rubocop annotation once FF truncate_ci_merge_request_description is cleaned up def predefined_variables Gitlab::Ci::Variables::Collection.new.tap do |variables| variables.append(key: 'CI_MERGE_REQUEST_ID', value: id.to_s) @@ -1726,14 +1724,9 @@ class MergeRequest < ApplicationRecord variables.append(key: 'CI_MERGE_REQUEST_TARGET_BRANCH_PROTECTED', value: ProtectedBranch.protected?(target_project, target_branch).to_s) variables.append(key: 'CI_MERGE_REQUEST_TITLE', value: title) - if ::Feature.enabled?(:truncate_ci_merge_request_description) - mr_description, mr_description_truncated = truncate_mr_description - variables.append(key: 'CI_MERGE_REQUEST_DESCRIPTION', value: mr_description) - variables.append(key: 'CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED', value: mr_description_truncated) - else - variables.append(key: 'CI_MERGE_REQUEST_DESCRIPTION', value: description) - end - + mr_description, mr_description_truncated = truncate_mr_description + variables.append(key: 'CI_MERGE_REQUEST_DESCRIPTION', value: mr_description) + variables.append(key: 'CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED', value: mr_description_truncated) variables.append(key: 'CI_MERGE_REQUEST_ASSIGNEES', value: assignee_username_list) if assignees.present? variables.append(key: 'CI_MERGE_REQUEST_MILESTONE', value: milestone.title) if milestone variables.append(key: 'CI_MERGE_REQUEST_LABELS', value: label_names.join(',')) if labels.present? @@ -1741,8 +1734,6 @@ class MergeRequest < ApplicationRecord variables.concat(source_project_variables) end end - # rubocop: enable Metrics/AbcSize - # Delete a rubocop annotation once FF truncate_ci_merge_request_description is cleaned up def compare_test_reports unless has_test_reports? diff --git a/app/models/organizations/organization.rb b/app/models/organizations/organization.rb index 4a30cfc8f0e..be96939daa8 100644 --- a/app/models/organizations/organization.rb +++ b/app/models/organizations/organization.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Organizations - class Organization < ApplicationRecord + class Organization < MainClusterwide::ApplicationRecord DEFAULT_ORGANIZATION_ID = 1 scope :without_default, -> { where.not(id: DEFAULT_ORGANIZATION_ID) } diff --git a/app/views/devise/shared/_omniauth_box.html.haml b/app/views/devise/shared/_omniauth_box.html.haml index 5ba58ecb974..be559b30ce9 100644 --- a/app/views/devise/shared/_omniauth_box.html.haml +++ b/app/views/devise/shared/_omniauth_box.html.haml @@ -4,14 +4,14 @@ .omniauth-divider.gl-display-flex.gl-align-items-center = _("or sign in with") -.gl-mt-5.gl-px-5.omniauth-container.gl-text-center.gl-ml-auto.gl-mr-auto +.gl-mt-5.gl-px-5.omniauth-container.gl-text-center.gl-display-flex.gl-flex-direction-column.gl-gap-3 - enabled_button_based_providers.each do |provider| - - has_icon = provider_has_icon?(provider) - = button_to omniauth_authorize_path(:user, provider), id: "oauth-login-#{provider}", data: { testid: "#{test_id_for_provider(provider)}" }, class: "btn gl-button btn-default gl-mb-2 js-oauth-login gl-w-full", form: { class: 'gl-mb-3' } do - - if has_icon - = provider_image_tag(provider) - %span.gl-button-text - = label_for_provider(provider) + = render 'devise/shared/omniauth_provider_button', + href: omniauth_authorize_path(:user, provider), + provider: provider, + classes: 'js-oauth-login', + data: { testid: test_id_for_provider(provider) }, + id: "oauth-login-#{provider}" - if render_remember_me = render Pajamas::CheckboxTagComponent.new(name: 'remember_me_omniauth', value: nil) do |c| - c.with_label do diff --git a/app/views/devise/shared/_omniauth_provider_button.haml b/app/views/devise/shared/_omniauth_provider_button.haml new file mode 100644 index 00000000000..e92b41a6254 --- /dev/null +++ b/app/views/devise/shared/_omniauth_provider_button.haml @@ -0,0 +1,7 @@ +- button_options = { class: classes, data: data, id: id } + += render Pajamas::ButtonComponent.new(href: href, method: :post, form: true, block: true, button_options: button_options) do + - if provider_has_icon?(provider) + = provider_image_tag(provider) + %span.gl-button-text + = label_for_provider(provider) diff --git a/app/views/devise/shared/_signup_omniauth_provider_button.haml b/app/views/devise/shared/_signup_omniauth_provider_button.haml index e280259ca49..9870e90cfff 100644 --- a/app/views/devise/shared/_signup_omniauth_provider_button.haml +++ b/app/views/devise/shared/_signup_omniauth_provider_button.haml @@ -1,8 +1,6 @@ -- data = { provider: provider, track_action: "#{provider}_sso", track_label: tracking_label } -- button_options = { class: 'js-track-omni-auth', data: data, id: "oauth-login-#{provider}" } - -= render Pajamas::ButtonComponent.new(href: href, method: :post, form: true, block: true, button_options: button_options) do - - if provider_has_icon?(provider) - = provider_image_tag(provider) - %span.gl-button-text - = label_for_provider(provider) += render 'devise/shared/omniauth_provider_button', + href: href, + provider: provider, + classes: 'js-track-omni-auth', + data: { provider: provider, track_action: "#{provider}_sso", track_label: tracking_label }, + id: "oauth-login-#{provider}" diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml index 6dcd661ecdb..3f18a7bbda6 100644 --- a/app/views/profiles/emails/index.html.haml +++ b/app/views/profiles/emails/index.html.haml @@ -24,7 +24,7 @@ = sprite_icon('mail', css_class: 'gl-mr-2') = @emails.load.size .gl-new-card-actions - = render Pajamas::ButtonComponent.new(size: :small, button_options: { class: "js-toggle-button js-toggle-content", data: { testid: 'toggle_email_address_field' } }) do + = render Pajamas::ButtonComponent.new(size: :small, button_options: { class: "js-toggle-button js-toggle-content", data: { testid: 'toggle-email-address-field' } }) do = s_('Profiles|Add new email') - c.with_body do .gl-new-card-add-form.gl-m-3.gl-mb-4.gl-display-none.js-toggle-content @@ -33,9 +33,9 @@ = gitlab_ui_form_for 'email', url: profile_emails_path do |f| .form-group = f.label :email, s_('Profiles|Email address'), class: 'label-bold' - = f.text_field :email, class: 'form-control gl-form-input gl-form-input-xl', data: { qa_selector: 'email_address_field' } + = f.text_field :email, class: 'form-control gl-form-input gl-form-input-xl', data: { testid: 'email-address-field' } .gl-mt-3 - = f.submit s_('Profiles|Add email address'), data: { qa_selector: 'add_email_address_button' }, pajamas_button: true + = f.submit s_('Profiles|Add email address'), data: { testid: 'add-email-address-button' }, pajamas_button: true = render Pajamas::ButtonComponent.new(button_options: { type: 'reset', class: 'gl-ml-2 js-toggle-button' }) do = _('Cancel') - if @emails.any? @@ -59,7 +59,7 @@ = s_('Profiles|Default notification email') .gl-text-secondary.gl-font-sm= notification_message.html_safe - @emails.reject(&:user_primary_email?).each do |email| - %li{ class: 'gl-px-5!', data: { qa_selector: 'email_row_content' } } + %li{ class: 'gl-px-5!', data: { testid: 'email-row-content' } } .gl-display-flex.gl-justify-content-space-between.gl-flex-wrap.gl-gap-3 %div = render partial: 'shared/email_with_badge', locals: { email: email.email, verified: email.confirmed? } @@ -81,4 +81,4 @@ - confirm_title = "#{email.confirmation_sent_at ? s_('Profiles|Resend confirmation email') : s_('Profiles|Send confirmation email')}" = link_button_to confirm_title, resend_confirmation_instructions_profile_email_path(email), method: :put, size: :small - = link_button_to nil, profile_email_path(email), data: { confirm: _('Are you sure?'), confirm_btn_variant: 'danger', qa_selector: 'delete_email_link'}, method: :delete, size: :small, icon: 'remove', 'aria-label': _('Remove') + = link_button_to nil, profile_email_path(email), data: { confirm: _('Are you sure?'), confirm_btn_variant: 'danger', testid: 'delete-email-link'}, method: :delete, size: :small, icon: 'remove', 'aria-label': _('Remove') diff --git a/app/views/profiles/gpg_keys/_key_table.html.haml b/app/views/profiles/gpg_keys/_key_table.html.haml index 0a50ce55b50..ea7068e0484 100644 --- a/app/views/profiles/gpg_keys/_key_table.html.haml +++ b/app/views/profiles/gpg_keys/_key_table.html.haml @@ -3,7 +3,7 @@ - if @gpg_keys.any? .table-holder - %table.table.b-table.gl-table.b-table-stacked-md.gl-mt-n1.gl-mb-n2.ssh-keys-list{ data: { qa_selector: 'ssh_keys_list' } } + %table.table.b-table.gl-table.b-table-stacked-md.gl-mt-n1.gl-mb-n2.ssh-keys-list %thead.d-none.d-md-table-header-group %tr %th= s_('Profiles|Key') diff --git a/app/views/user_settings/passwords/edit.html.haml b/app/views/user_settings/passwords/edit.html.haml index afe6ee2c0b3..179f54ac45e 100644 --- a/app/views/user_settings/passwords/edit.html.haml +++ b/app/views/user_settings/passwords/edit.html.haml @@ -18,18 +18,18 @@ - unless @user.password_automatically_set? .form-group = f.label :password, _('Current password'), class: 'label-bold' - = f.password_field :password, required: true, autocomplete: 'current-password', class: 'form-control gl-form-input gl-max-w-80', data: { qa_selector: 'current_password_field' } + = f.password_field :password, required: true, autocomplete: 'current-password', class: 'form-control gl-form-input gl-max-w-80', data: { testid: 'current-password-field' } %p.form-text.text-muted = _('You must provide your current password in order to change it.') .form-group = f.label :new_password, _('New password'), class: 'label-bold' - = f.password_field :new_password, required: true, autocomplete: 'new-password', class: 'form-control gl-form-input js-password-complexity-validation gl-max-w-80', data: { qa_selector: 'new_password_field' } + = f.password_field :new_password, required: true, autocomplete: 'new-password', class: 'form-control gl-form-input js-password-complexity-validation gl-max-w-80', data: { testid: 'new-password-field' } = render_if_exists 'shared/password_requirements_list' .form-group = f.label :password_confirmation, _('Password confirmation'), class: 'label-bold' - = f.password_field :password_confirmation, required: true, autocomplete: 'new-password', class: 'form-control gl-form-input gl-max-w-80', data: { qa_selector: 'confirm_password_field' } + = f.password_field :password_confirmation, required: true, autocomplete: 'new-password', class: 'form-control gl-form-input gl-max-w-80', data: { testid: 'confirm-password-field' } .gl-mt-3.gl-mb-3 - = f.submit _('Save password'), class: "gl-mr-3", data: { qa_selector: 'save_password_button' }, pajamas_button: true + = f.submit _('Save password'), class: "gl-mr-3", data: { testid: 'save-password-button' }, pajamas_button: true - unless @user.password_automatically_set? = render Pajamas::ButtonComponent.new(href: reset_user_settings_password_path, variant: :link, method: :put) do = _('I forgot my password') diff --git a/app/views/user_settings/passwords/new.html.haml b/app/views/user_settings/passwords/new.html.haml index 3616c9ec252..4b47dfa3e83 100644 --- a/app/views/user_settings/passwords/new.html.haml +++ b/app/views/user_settings/passwords/new.html.haml @@ -16,17 +16,17 @@ .col-sm-2.col-form-label = f.label :password, _('Current password') .col-sm-10 - = f.password_field :password, required: true, autocomplete: 'current-password', class: 'form-control gl-form-input', data: { qa_selector: 'current_password_field' } + = f.password_field :password, required: true, autocomplete: 'current-password', class: 'form-control gl-form-input', data: { testid: 'current-password-field' } .form-group.row .col-sm-2.col-form-label = f.label :new_password, _('New password') .col-sm-10 - = f.password_field :new_password, required: true, autocomplete: 'new-password', class: 'form-control gl-form-input js-password-complexity-validation', data: { qa_selector: 'new_password_field' } + = f.password_field :new_password, required: true, autocomplete: 'new-password', class: 'form-control gl-form-input js-password-complexity-validation', data: { testid: 'new-password-field' } = render_if_exists 'shared/password_requirements_list' .form-group.row .col-sm-2.col-form-label = f.label :password_confirmation, _('Password confirmation') .col-sm-10 - = f.password_field :password_confirmation, required: true, autocomplete: 'new-password', class: 'form-control gl-form-input', data: { qa_selector: 'confirm_password_field' } + = f.password_field :password_confirmation, required: true, autocomplete: 'new-password', class: 'form-control gl-form-input', data: { testid: 'confirm-password-field' } .form-actions - = f.submit _('Set new password'), data: { qa_selector: 'set_new_password_button' }, pajamas_button: true + = f.submit _('Set new password'), data: { testid: 'set-new-password-button' }, pajamas_button: true diff --git a/config/feature_flags/development/truncate_ci_merge_request_description.yml b/config/feature_flags/development/truncate_ci_merge_request_description.yml deleted file mode 100644 index 816632f0da2..00000000000 --- a/config/feature_flags/development/truncate_ci_merge_request_description.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: truncate_ci_merge_request_description -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139605 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/435099 -milestone: '16.7' -type: development -group: group::pipeline security -default_enabled: false
\ No newline at end of file diff --git a/db/docs/batched_background_migrations/backfill_vs_code_settings_uuid.yml b/db/docs/batched_background_migrations/backfill_vs_code_settings_uuid.yml index 022752a06a7..fc793594203 100644 --- a/db/docs/batched_background_migrations/backfill_vs_code_settings_uuid.yml +++ b/db/docs/batched_background_migrations/backfill_vs_code_settings_uuid.yml @@ -5,5 +5,5 @@ feature_category: web_ide introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/138355 milestone: '16.7' queued_migration_version: 20231130140901 -finalize_after: '2023-12-17' +finalize_after: '2023-01-31' finalized_by: # version of the migration that finalized this BBM diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 56fd41b43fc..57a33473b19 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -24256,8 +24256,8 @@ Represents vulnerability finding of a security report on the pipeline. | <a id="projectcicdsettings"></a>`ciCdSettings` | [`ProjectCiCdSetting`](#projectcicdsetting) | CI/CD settings for the project. | | <a id="projectciconfigpathordefault"></a>`ciConfigPathOrDefault` | [`String!`](#string) | Path of the CI configuration file. | | <a id="projectcijobtokenscope"></a>`ciJobTokenScope` | [`CiJobTokenScopeType`](#cijobtokenscopetype) | The CI Job Tokens scope of access. | -| <a id="projectcisubscribedprojects"></a>`ciSubscribedProjects` | [`CiSubscriptionsProjectConnection`](#cisubscriptionsprojectconnection) | Triggers a new pipeline in the downstream project when a pipeline successfullycompletes on the(upstream) project. (see [Connections](#connections)) | -| <a id="projectcisubscriptionsprojects"></a>`ciSubscriptionsProjects` | [`CiSubscriptionsProjectConnection`](#cisubscriptionsprojectconnection) | Triggers a new pipeline in the(downstream) project when a pipeline successfullycompletes on the upstream project. (see [Connections](#connections)) | +| <a id="projectcisubscribedprojects"></a>`ciSubscribedProjects` | [`CiSubscriptionsProjectConnection`](#cisubscriptionsprojectconnection) | Pipeline subscriptions for projects subscribed to the project. (see [Connections](#connections)) | +| <a id="projectcisubscriptionsprojects"></a>`ciSubscriptionsProjects` | [`CiSubscriptionsProjectConnection`](#cisubscriptionsprojectconnection) | Pipeline subscriptions for the project. (see [Connections](#connections)) | | <a id="projectcodecoveragesummary"></a>`codeCoverageSummary` | [`CodeCoverageSummary`](#codecoveragesummary) | Code coverage summary associated with the project. | | <a id="projectcomplianceframeworks"></a>`complianceFrameworks` | [`ComplianceFrameworkConnection`](#complianceframeworkconnection) | Compliance frameworks associated with the project. (see [Connections](#connections)) | | <a id="projectcontainerexpirationpolicy"></a>`containerExpirationPolicy` | [`ContainerExpirationPolicy`](#containerexpirationpolicy) | Container expiration policy of the project. | diff --git a/doc/ci/variables/predefined_variables.md b/doc/ci/variables/predefined_variables.md index e8ed47cedd0..7c62e133958 100644 --- a/doc/ci/variables/predefined_variables.md +++ b/doc/ci/variables/predefined_variables.md @@ -165,7 +165,8 @@ These variables are available when: | `CI_MERGE_REQUEST_DIFF_ID` | 13.7 | all | The version of the merge request diff. | | `CI_MERGE_REQUEST_EVENT_TYPE` | 12.3 | all | The event type of the merge request. Can be `detached`, `merged_result` or `merge_train`. | | `CI_MERGE_REQUEST_ID` | 11.6 | all | The instance-level ID of the merge request. This is a unique ID across all projects on the GitLab instance. | -| `CI_MERGE_REQUEST_DESCRIPTION` | 16.7 | all | The description of the merge request. | +| `CI_MERGE_REQUEST_DESCRIPTION` | 16.7 | all | The description of the merge request. If the description is more than 2700 characters long, only the first 2700 characters are stored in the variable. | +| `CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED` | 16.8 | all | `true` if `CI_MERGE_REQUEST_DESCRIPTION` is truncated down to 2700 characters because the description of the merge request is too long. | | `CI_MERGE_REQUEST_IID` | 11.6 | all | The project-level IID (internal ID) of the merge request. This ID is unique for the current project, and is the number used in the merge request URL, page title, and other visible locations. | | `CI_MERGE_REQUEST_LABELS` | 11.9 | all | Comma-separated label names of the merge request. | | `CI_MERGE_REQUEST_MILESTONE` | 11.9 | all | The milestone title of the merge request. | diff --git a/doc/user/project/requirements/index.md b/doc/user/project/requirements/index.md index 0594f3fe2ee..e489f19585c 100644 --- a/doc/user/project/requirements/index.md +++ b/doc/user/project/requirements/index.md @@ -50,7 +50,7 @@ To create a requirement: 1. In a project, go to **Plan > Requirements**. 1. Select **New requirement**. -1. Enter a title and description and select **Create requirement**. +1. Enter a title and description and select **New requirement**. ![requirement create view](img/requirement_create_v13_5.png) @@ -240,7 +240,8 @@ To import requirements: 1. In a project, go to **Plan > Requirements**. - For a project with requirements, in the - upper-right corner, select the import icon (**{import}**). + upper-right corner, select the vertical ellipsis (**{ellipsis_v}**), + then select **Import requirements** (**{import}**). - For a project without requirements, in the middle of the page, select **Import CSV**. 1. Select the file and select **Import requirements**. @@ -300,7 +301,8 @@ Prerequisites: To export requirements: 1. In a project, go to **Plan > Requirements**. -1. In the upper-right corner, select **Export as CSV** (**{export}**). +1. In the upper-right corner, select the vertical ellipsis (**{ellipsis_v}**), + then select **Export as CSV** (**{export}**). A confirmation modal appears. diff --git a/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml index dd0802c14f6..467d4629010 100644 --- a/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml @@ -1,5 +1,5 @@ variables: - DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.72.0' + DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.76.0' .dast-auto-deploy: image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${DAST_AUTO_DEPLOY_IMAGE_VERSION}" diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml index 37e77c3ed25..0744a5a6321 100644 --- a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml @@ -1,5 +1,5 @@ variables: - AUTO_DEPLOY_IMAGE_VERSION: 'v2.72.0' + AUTO_DEPLOY_IMAGE_VERSION: 'v2.76.0' .auto-deploy: image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}" diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml index 813a94dde08..b3e44dbf4be 100644 --- a/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml @@ -1,5 +1,5 @@ variables: - AUTO_DEPLOY_IMAGE_VERSION: 'v2.72.0' + AUTO_DEPLOY_IMAGE_VERSION: 'v2.76.0' .auto-deploy: image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}" diff --git a/qa/gdk/Dockerfile.gdk b/qa/gdk/Dockerfile.gdk index b3443049875..f55b10e62d9 100644 --- a/qa/gdk/Dockerfile.gdk +++ b/qa/gdk/Dockerfile.gdk @@ -5,7 +5,7 @@ ENV GITLAB_LICENSE_MODE=test \ # Clone GDK at specific sha and bootstrap packages # -ARG GDK_SHA=221d3cc81d3ffc17beb178fd5021cd0d93ca55b6 +ARG GDK_SHA=88c3231079278a49ba59d37362357e5908fb7179 RUN set -eux; \ git clone --depth 1 https://gitlab.com/gitlab-org/gitlab-development-kit.git && cd gitlab-development-kit; \ git fetch --depth 1 origin ${GDK_SHA} && git -c advice.detachedHead=false checkout ${GDK_SHA}; \ diff --git a/qa/qa/page/profile/emails.rb b/qa/qa/page/profile/emails.rb index 1e6b7518e55..f9340445276 100644 --- a/qa/qa/page/profile/emails.rb +++ b/qa/qa/page/profile/emails.rb @@ -7,27 +7,27 @@ module QA include QA::Page::Component::ConfirmModal view 'app/views/profiles/emails/index.html.haml' do - element :email_address_field - element :add_email_address_button - element :email_row_content - element :delete_email_link - element :toggle_email_address_field + element 'email-address-field' + element 'add-email-address-button' + element 'email-row-content' + element 'delete-email-link' + element 'toggle-email-address-field' end def expand_email_input - click_element(:toggle_email_address_field) if has_no_element?(:email_address_field) - has_element?(:email_address_field) + click_element('toggle-email-address-field') if has_no_element?('email-address-field') + has_element?('email-address-field') end def add_email_address(email_address) expand_email_input - find_element(:email_address_field).set email_address - click_element(:add_email_address_button) + find_element('email-address-field').set email_address + click_element('add-email-address-button') end def delete_email_address(email_address) - within_element(:email_row_content, text: email_address) do - click_element(:delete_email_link) + within_element('email-row-content', text: email_address) do + click_element('delete-email-link') end click_confirmation_ok_button end diff --git a/qa/qa/page/profile/password.rb b/qa/qa/page/profile/password.rb index 5f07cdb6f25..d70dcbabd49 100644 --- a/qa/qa/page/profile/password.rb +++ b/qa/qa/page/profile/password.rb @@ -5,31 +5,31 @@ module QA module Profile class Password < Page::Base view 'app/views/user_settings/passwords/edit.html.haml' do - element :current_password_field - element :new_password_field - element :confirm_password_field - element :save_password_button + element 'current-password-field' + element 'new-password-field' + element 'confirm-password-field' + element 'save-password-button' end view 'app/views/user_settings/passwords/new.html.haml' do - element :current_password_field - element :new_password_field - element :confirm_password_field - element :set_new_password_button + element 'current-password-field' + element 'new-password-field' + element 'confirm-password-field' + element 'set-new-password-button' end def update_password(new_password, current_password) - find_element(:current_password_field).set current_password - find_element(:new_password_field).set new_password - find_element(:confirm_password_field).set new_password - click_element(:save_password_button) + find_element('current-password-field').set current_password + find_element('new-password-field').set new_password + find_element('confirm-password-field').set new_password + click_element('save-password-button') end def set_new_password(new_password, current_password) - fill_element :current_password_field, current_password - fill_element :new_password_field, new_password - fill_element :confirm_password_field, new_password - click_element :set_new_password_button + fill_element('current-password-field', current_password) + fill_element('new-password-field', new_password) + fill_element('confirm-password-field', new_password) + click_element('set-new-password-button') end end end diff --git a/scripts/setup/generate-as-if-foss-env.rb b/scripts/setup/generate-as-if-foss-env.rb index 68b869287a6..ee688e4f1d0 100755 --- a/scripts/setup/generate-as-if-foss-env.rb +++ b/scripts/setup/generate-as-if-foss-env.rb @@ -1,22 +1,79 @@ #!/usr/bin/env ruby # frozen_string_literal: true -require 'gitlab' +# In spec/scripts/setup/generate_as_if_foss_env_spec.rb we completely stub it +require 'gitlab' unless Object.const_defined?(:Gitlab) require 'set' -client = Gitlab.client(endpoint: ENV['CI_API_V4_URL'], private_token: '') +class GenerateAsIfFossEnv + def initialize + @client = Gitlab.client(endpoint: ENV['CI_API_V4_URL'], private_token: '') + @rspec_jobs = Set.new + @jest_jobs = Set.new + end -rspec_jobs = Set.new + def variables + @variables ||= generate_variables + end -client.pipeline_jobs(ENV['CI_PROJECT_ID'], ENV['CI_PIPELINE_ID']).auto_paginate do |job| - rspec_type = job.name[/^rspec ([\w\-]+)/, 1] + def display + variables.each do |key, value| + puts "#{key}=#{value}" + end + end - rspec_jobs << rspec_type if rspec_type -end + private + + attr_reader :client, :rspec_jobs, :jest_jobs + + def generate_variables + scan_jobs + + { + START_AS_IF_FOSS: 'true', + RUBY_VERSION: ENV['RUBY_VERSION'] + }.merge(rspec_variables).merge(jest_variables) + end + + def scan_jobs + each_job do |job| + detect_rspec(job) || detect_jest(job) + end + end + + def each_job + client.pipeline_jobs(ENV['CI_PROJECT_ID'], ENV['CI_PIPELINE_ID']).auto_paginate do |job| + yield(job) + end + end + + def detect_rspec(job) + rspec_type = job.name[/^rspec ([\w\-]+)/, 1] -puts 'START_AS_IF_FOSS=true', "RUBY_VERSION=#{ENV['RUBY_VERSION']}" -puts 'ENABLE_RSPEC=true' if rspec_jobs.any? + rspec_jobs << rspec_type if rspec_type + end -rspec_jobs.each do |rspec| - puts "ENABLE_RSPEC_#{rspec.upcase.tr('-', '_')}=true" + def detect_jest(job) + jest_type = job.name[/^jest([\w\-]*)/, 1] + + jest_jobs << jest_type if jest_type + end + + def rspec_variables + return {} if rspec_jobs.empty? + + rspec_jobs.inject({ ENABLE_RSPEC: 'true' }) do |result, rspec| + result.merge("ENABLE_RSPEC_#{rspec.upcase.tr('-', '_')}": 'true') + end + end + + def jest_variables + return {} if jest_jobs.empty? + + jest_jobs.inject({ ENABLE_JEST: 'true' }) do |result, jest| + result.merge("ENABLE_JEST#{jest.upcase.tr('-', '_')}": 'true') + end + end end + +GenerateAsIfFossEnv.new.display if $PROGRAM_NAME == __FILE__ diff --git a/spec/controllers/omniauth_callbacks_controller_spec.rb b/spec/controllers/omniauth_callbacks_controller_spec.rb index 5b1fdd6388a..e99d9e949a8 100644 --- a/spec/controllers/omniauth_callbacks_controller_spec.rb +++ b/spec/controllers/omniauth_callbacks_controller_spec.rb @@ -31,6 +31,67 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category: end end + shared_examples 'omniauth sign in that remembers user' do + before do + stub_omniauth_setting(allow_bypass_two_factor: allow_bypass_two_factor) + (request.env['omniauth.params'] ||= {}).deep_merge!('remember_me' => omniauth_params_remember_me) + end + + if params[:call_remember_me] + it 'calls devise method remember_me' do + expect(controller).to receive(:remember_me).with(user).and_call_original + + post_action + end + else + it 'does not calls devise method remember_me' do + expect(controller).not_to receive(:remember_me) + + post_action + end + end + end + + shared_examples 'omniauth sign in that remembers user with two factor enabled' do + using RSpec::Parameterized::TableSyntax + + subject(:post_action) { post provider } + + where(:allow_bypass_two_factor, :omniauth_params_remember_me, :call_remember_me) do + true | '1' | true + true | '0' | false + true | nil | false + false | '1' | false + false | '0' | false + false | nil | false + end + + with_them do + it_behaves_like 'omniauth sign in that remembers user' + end + end + + shared_examples 'omniauth sign in that remembers user with two factor disabled' do + context "when user selects remember me for omniauth sign in flow" do + using RSpec::Parameterized::TableSyntax + + subject(:post_action) { post provider } + + where(:allow_bypass_two_factor, :omniauth_params_remember_me, :call_remember_me) do + true | '1' | true + true | '0' | false + true | nil | false + false | '1' | true + false | '0' | false + false | nil | false + end + + with_them do + it_behaves_like 'omniauth sign in that remembers user' + end + end + end + describe 'omniauth' do let(:user) { create(:omniauth_user, extern_uid: extern_uid, provider: provider) } let(:additional_info) { {} } @@ -190,6 +251,8 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category: request.env['omniauth.params'] = { 'redirect_fragment' => 'L101' } end + it_behaves_like 'omniauth sign in that remembers user with two factor disabled' + context 'when a redirect url is stored' do it 'redirects with fragment' do post provider, session: { user_return_to: '/fake/url' } @@ -214,6 +277,12 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category: expect(response.location).not_to include('#L101') end end + + context 'when a user has 2FA enabled' do + let(:user) { create(:omniauth_user, :two_factor, extern_uid: extern_uid, provider: provider) } + + it_behaves_like 'omniauth sign in that remembers user with two factor enabled' + end end context 'with strategies' do @@ -271,6 +340,8 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category: end end + it_behaves_like 'omniauth sign in that remembers user with two factor disabled' + context 'when a user has 2FA enabled' do render_views @@ -296,6 +367,8 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category: expect(response).to have_gitlab_http_status(:ok) end end + + it_behaves_like 'omniauth sign in that remembers user with two factor enabled' end context 'for sign up' do @@ -357,6 +430,10 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category: let(:extern_uid) { '' } let(:provider) { :auth0 } + it_behaves_like 'omniauth sign in that remembers user with two factor disabled' do + let(:extern_uid) { 'my-uid' } + end + it 'does not allow sign in without extern_uid' do post 'auth0' @@ -364,6 +441,14 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category: expect(response).to have_gitlab_http_status(:found) expect(controller).to set_flash[:alert].to('Wrong extern UID provided. Make sure Auth0 is configured correctly.') end + + context 'when a user has 2FA enabled' do + let(:user) { create(:omniauth_user, :two_factor, extern_uid: extern_uid, provider: provider) } + + it_behaves_like 'omniauth sign in that remembers user with two factor enabled' do + let(:extern_uid) { 'my-uid' } + end + end end context 'for atlassian_oauth2' do @@ -373,6 +458,8 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category: context 'when the user and identity already exist' do let(:user) { create(:atlassian_user, extern_uid: extern_uid) } + it_behaves_like 'omniauth sign in that remembers user with two factor disabled' + it 'allows sign-in' do post :atlassian_oauth2 @@ -391,6 +478,12 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category: post :atlassian_oauth2 end + + context 'when a user has 2FA enabled' do + let(:user) { create(:atlassian_user, :two_factor, extern_uid: extern_uid) } + + it_behaves_like 'omniauth sign in that remembers user with two factor enabled' + end end context 'for a new user' do @@ -443,11 +536,21 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category: include_context 'with sign_up' let(:additional_info) { { extra: { email_verified: true } } } + it_behaves_like 'omniauth sign in that remembers user with two factor disabled' do + let(:user) { create(:omniauth_user, extern_uid: extern_uid, provider: provider) } + end + it 'allows sign in' do post 'salesforce' expect(request.env['warden']).to be_authenticated end + + context 'when a user has 2FA enabled' do + let(:user) { create(:omniauth_user, :two_factor, extern_uid: extern_uid, provider: provider) } + + it_behaves_like 'omniauth sign in that remembers user with two factor enabled' + end end end end @@ -497,11 +600,19 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category: let(:post_action) { post provider } end + it_behaves_like 'omniauth sign in that remembers user with two factor disabled' + it 'allows sign in' do post provider expect(request.env['warden']).to be_authenticated end + + context 'when a user has 2FA enabled' do + let(:user) { create(:omniauth_user, :two_factor, extern_uid: extern_uid, provider: provider) } + + it_behaves_like 'omniauth sign in that remembers user with two factor enabled' + end end describe '#saml' do diff --git a/spec/features/admin/users/user_impersonation_spec.rb b/spec/features/admin/users/admin_impersonates_user_spec.rb index 215afc40d80..44b67abcc80 100644 --- a/spec/features/admin/users/user_impersonation_spec.rb +++ b/spec/features/admin/users/admin_impersonates_user_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Admin::Users::UserImpersonation', feature_category: :user_management do +RSpec.describe 'Admin impersonates user', feature_category: :user_management do let_it_be(:user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') } let_it_be(:current_user) { create(:admin) } diff --git a/spec/features/admin/users/user_identities_spec.rb b/spec/features/admin/users/admin_manages_user_identities_spec.rb index 6db94750761..42d0c2e9ab8 100644 --- a/spec/features/admin/users/user_identities_spec.rb +++ b/spec/features/admin/users/admin_manages_user_identities_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Admin::Users::UserIdentities', feature_category: :user_management do +RSpec.describe 'Admin manages user identities', feature_category: :user_management do let_it_be(:user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') } let_it_be(:current_user) { create(:admin) } diff --git a/spec/features/admin/users/admin_sees_unconfirmed_user_spec.rb b/spec/features/admin/users/admin_sees_unconfirmed_user_spec.rb new file mode 100644 index 00000000000..7b45e5b5cde --- /dev/null +++ b/spec/features/admin/users/admin_sees_unconfirmed_user_spec.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Admin sees unconfirmed user', feature_category: :user_management do + include Spec::Support::Helpers::ModalHelpers + + let_it_be(:user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') } + let_it_be(:current_user) { create(:admin) } + + before do + sign_in(current_user) + enable_admin_mode!(current_user, use_ui: true) + end + + context 'when user has an unconfirmed email', :js do + # Email address contains HTML to ensure email address is displayed in an HTML safe way. + let_it_be(:unconfirmed_email) { "#{generate(:email)}<h2>testing<img/src=http://localhost:8000/test.png>" } + let_it_be(:unconfirmed_user) { create(:user, :unconfirmed, unconfirmed_email: unconfirmed_email) } + + where(:path_helper) do + [ + [-> (user) { admin_user_path(user) }], + [-> (user) { projects_admin_user_path(user) }], + [-> (user) { keys_admin_user_path(user) }], + [-> (user) { admin_user_identities_path(user) }], + [-> (user) { admin_user_impersonation_tokens_path(user) }] + ] + end + + with_them do + it "allows an admin to force confirmation of the user's email", :aggregate_failures do + visit path_helper.call(unconfirmed_user) + + click_button 'Confirm user' + + within_modal do + expect(page).to have_content("Confirm user #{unconfirmed_user.name}?") + expect(page).to( + have_content( + "This user has an unconfirmed email address (#{unconfirmed_email}). You may force a confirmation.") + ) + + click_button 'Confirm user' + end + + expect(page).to have_content('Successfully confirmed') + expect(page).not_to have_button('Confirm user') + end + end + end +end diff --git a/spec/features/admin/users/user_spec.rb b/spec/features/admin/users/admin_sees_user_spec.rb index b7e7a037ffc..d8c142d402f 100644 --- a/spec/features/admin/users/user_spec.rb +++ b/spec/features/admin/users/admin_sees_user_spec.rb @@ -193,34 +193,6 @@ RSpec.describe 'Admin::Users::User', feature_category: :user_management do end end - describe 'show user identities' do - it 'shows user identities', :aggregate_failures do - visit admin_user_identities_path(user) - - expect(page).to have_content(user.name) - expect(page).to have_content('twitter') - end - end - - describe 'update user identities' do - before do - allow(Gitlab::Auth::OAuth::Provider).to receive(:providers).and_return([:twitter, :twitter_updated]) - end - - it 'modifies twitter identity', :aggregate_failures do - visit admin_user_identities_path(user) - - find('.table').find(:link, 'Edit').click - fill_in 'identity_extern_uid', with: '654321' - select 'twitter_updated', from: 'identity_provider' - click_button 'Save changes' - - expect(page).to have_content(user.name) - expect(page).to have_content('twitter_updated') - expect(page).to have_content('654321') - end - end - describe 'remove users secondary email', :js do let_it_be(:secondary_email) do create :email, email: 'secondary@example.com', user: user @@ -237,17 +209,6 @@ RSpec.describe 'Admin::Users::User', feature_category: :user_management do end end - describe 'remove user with identities' do - it 'removes user with twitter identity', :aggregate_failures do - visit admin_user_identities_path(user) - - click_link 'Delete' - - expect(page).to have_content(user.name) - expect(page).not_to have_content('twitter') - end - end - describe 'show user keys', :js do it do key1 = create(:key, user: user, title: 'ssh-rsa Key1') @@ -284,40 +245,4 @@ RSpec.describe 'Admin::Users::User', feature_category: :user_management do end end end - - context 'when user has an unconfirmed email', :js do - # Email address contains HTML to ensure email address is displayed in an HTML safe way. - let_it_be(:unconfirmed_email) { "#{generate(:email)}<h2>testing<img/src=http://localhost:8000/test.png>" } - let_it_be(:unconfirmed_user) { create(:user, :unconfirmed, unconfirmed_email: unconfirmed_email) } - - where(:path_helper) do - [ - [-> (user) { admin_user_path(user) }], - [-> (user) { projects_admin_user_path(user) }], - [-> (user) { keys_admin_user_path(user) }], - [-> (user) { admin_user_identities_path(user) }], - [-> (user) { admin_user_impersonation_tokens_path(user) }] - ] - end - - with_them do - it "allows an admin to force confirmation of the user's email", :aggregate_failures do - visit path_helper.call(unconfirmed_user) - - click_button 'Confirm user' - - within_modal do - expect(page).to have_content("Confirm user #{unconfirmed_user.name}?") - expect(page).to have_content( - "This user has an unconfirmed email address (#{unconfirmed_email}). You may force a confirmation." - ) - - click_button 'Confirm user' - end - - expect(page).to have_content('Successfully confirmed') - expect(page).not_to have_button('Confirm user') - end - end - end end diff --git a/spec/features/projects/members/manage_members_spec.rb b/spec/features/projects/members/manage_members_spec.rb index 2ab0e63d840..8bd97566acf 100644 --- a/spec/features/projects/members/manage_members_spec.rb +++ b/spec/features/projects/members/manage_members_spec.rb @@ -118,7 +118,7 @@ RSpec.describe 'Projects > Members > Manage members', :js, feature_category: :on context 'when maintainer' do let(:current_user) { project_maintainer } - it 'does not show the Owner option' do + it 'does not show the Owner option', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/436958' do within_modal do toggle_listbox expect_listbox_items(%w[Guest Reporter Developer Maintainer]) diff --git a/spec/frontend/work_items/components/work_item_with_title_edit_spec.js b/spec/frontend/work_items/components/work_item_title_with_edit_spec.js index db9551b6ec3..7868e241821 100644 --- a/spec/frontend/work_items/components/work_item_with_title_edit_spec.js +++ b/spec/frontend/work_items/components/work_item_title_with_edit_spec.js @@ -51,7 +51,7 @@ describe('Work Item title with edit', () => { }); it('emits `updateDraft` event on change of the input', () => { - findEditableTitleInput().vm.$emit('change', 'updated title'); + findEditableTitleInput().vm.$emit('input', 'updated title'); expect(wrapper.emitted('updateDraft')).toEqual([['updated title']]); }); diff --git a/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb b/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb index f8d67a6f0b4..18ad723b75c 100644 --- a/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb +++ b/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb @@ -152,51 +152,6 @@ RSpec.describe Gitlab::Ci::Variables::Builder::Pipeline, feature_category: :secr end end - context 'when truncate_ci_merge_request_description feature flag is disabled' do - before do - stub_feature_flags(truncate_ci_merge_request_description: false) - end - - context 'when merge request description hits the limit' do - let(:merge_request_description) { 'a' * (MergeRequest::CI_MERGE_REQUEST_DESCRIPTION_MAX_LENGTH + 1) } - - it 'does not truncate the exposed description' do - expect(subject.to_hash) - .to include( - 'CI_MERGE_REQUEST_DESCRIPTION' => merge_request.description - ) - expect(subject.to_hash) - .not_to have_key('CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED') - end - end - - context 'when merge request description fits the length limit' do - let(:merge_request_description) { 'a' * (MergeRequest::CI_MERGE_REQUEST_DESCRIPTION_MAX_LENGTH - 1) } - - it 'does not truncate the exposed description' do - expect(subject.to_hash) - .to include( - 'CI_MERGE_REQUEST_DESCRIPTION' => merge_request.description - ) - expect(subject.to_hash) - .not_to have_key('CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED') - end - end - - context 'when merge request description does not exist' do - let(:merge_request_description) { nil } - - it 'does not truncate the exposed description' do - expect(subject.to_hash) - .to include( - 'CI_MERGE_REQUEST_DESCRIPTION' => merge_request.description - ) - expect(subject.to_hash) - .not_to have_key('CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED') - end - end - end - it 'exposes diff variables' do expect(subject.to_hash) .to include( diff --git a/spec/scripts/setup/generate_as_if_foss_env_spec.rb b/spec/scripts/setup/generate_as_if_foss_env_spec.rb new file mode 100644 index 00000000000..bd4c741ffad --- /dev/null +++ b/spec/scripts/setup/generate_as_if_foss_env_spec.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require 'gitlab/rspec/stub_env' + +# NOTE: Under the context of fast_spec_helper, when we `require 'gitlab'` +# we do not load the Gitlab client, but our own Gitlab module. +# Keep this in mind and just stub anything which might touch it! +require_relative '../../../scripts/setup/generate-as-if-foss-env' + +RSpec.describe GenerateAsIfFossEnv, feature_category: :tooling do + include StubENV + + subject(:generate) { described_class.new } + + before do + stub_env(RUBY_VERSION: '3.1') + end + + shared_context 'when there are all jobs' do + let(:jobs) do + [ + 'rspec fast_spec_helper', + 'rspec unit', + 'rspec integration', + 'rspec system', + 'rspec migration', + 'rspec background-migration', + 'jest', + 'jest-integration' + ] + end + + before do + messages = receive_message_chain(:client, :pipeline_jobs, :auto_paginate) + + yield_jobs = jobs.inject(messages) do |stub, job| + stub.and_yield(double(name: job)) # rubocop:disable RSpec/VerifiedDoubles -- As explained at the top of this file, we do not load the Gitlab client + end + + allow(Gitlab).to yield_jobs + end + end + + describe '#variables' do + include_context 'when there are all jobs' + + it 'returns correct variables' do + expect(generate.variables).to eq({ + START_AS_IF_FOSS: 'true', + RUBY_VERSION: ENV['RUBY_VERSION'], + ENABLE_RSPEC: 'true', + ENABLE_RSPEC_FAST_SPEC_HELPER: 'true', + ENABLE_RSPEC_UNIT: 'true', + ENABLE_RSPEC_INTEGRATION: 'true', + ENABLE_RSPEC_SYSTEM: 'true', + ENABLE_RSPEC_MIGRATION: 'true', + ENABLE_RSPEC_BACKGROUND_MIGRATION: 'true', + ENABLE_JEST: 'true', + ENABLE_JEST_INTEGRATION: 'true' + }) + end + end + + describe '#display' do + include_context 'when there are all jobs' + + it 'puts correct variables' do + expect { generate.display }.to output(<<~ENV).to_stdout + START_AS_IF_FOSS=true + RUBY_VERSION=#{ENV['RUBY_VERSION']} + ENABLE_RSPEC=true + ENABLE_RSPEC_FAST_SPEC_HELPER=true + ENABLE_RSPEC_UNIT=true + ENABLE_RSPEC_INTEGRATION=true + ENABLE_RSPEC_SYSTEM=true + ENABLE_RSPEC_MIGRATION=true + ENABLE_RSPEC_BACKGROUND_MIGRATION=true + ENABLE_JEST=true + ENABLE_JEST_INTEGRATION=true + ENV + end + end +end diff --git a/spec/support/shared_examples/features/work_items_shared_examples.rb b/spec/support/shared_examples/features/work_items_shared_examples.rb index a5b467da45d..049809f5edd 100644 --- a/spec/support/shared_examples/features/work_items_shared_examples.rb +++ b/spec/support/shared_examples/features/work_items_shared_examples.rb @@ -2,22 +2,45 @@ RSpec.shared_examples 'work items title' do let(:title_selector) { '[data-testid="work-item-title"]' } + let(:title_with_edit_selector) { '[data-testid="work-item-title-with-edit"]' } - before do - stub_feature_flags(work_items_mvc_2: false) + context 'when the work_items_mvc_2 FF is disabled' do + before do + stub_feature_flags(work_items_mvc_2: false) - page.refresh - wait_for_all_requests + page.refresh + wait_for_all_requests + end + + it 'successfully shows and changes the title of the work item' do + expect(work_item.reload.title).to eq work_item.title + + find(title_selector).set("Work item title") + find(title_selector).native.send_keys(:return) + wait_for_requests + + expect(work_item.reload.title).to eq 'Work item title' + end end - it 'successfully shows and changes the title of the work item' do - expect(work_item.reload.title).to eq work_item.title + context 'when the work_items_mvc_2 FF is enabled' do + before do + stub_feature_flags(work_items_mvc_2: true) - find(title_selector).set("Work item title") - find(title_selector).native.send_keys(:return) - wait_for_requests + page.refresh + wait_for_all_requests + end - expect(work_item.reload.title).to eq 'Work item title' + it 'successfully shows and changes the title of the work item' do + expect(work_item.reload.title).to eq work_item.title + + click_button 'Edit' + find(title_with_edit_selector).set("Work item title") + send_keys([:command, :enter]) + wait_for_requests + + expect(work_item.reload.title).to eq 'Work item title' + end end end |