From 41bea98c570eef817a264d41fd91809b5fb168ca Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 7 Jan 2022 06:14:36 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- app/assets/stylesheets/framework/layout.scss | 6 + .../stylesheets/framework/variables.scss | 8 ++ app/assets/stylesheets/pages/profile.scss | 12 ++ app/helpers/application_helper.rb | 11 ++ .../devise/confirmations/almost_there.haml | 2 + app/views/layouts/header/_default.html.haml | 31 ++++- .../layouts/header/_marketing_links.html.haml | 34 ++++++ .../header/_sign_in_register_button.html.haml | 6 + app/views/users/show.html.haml | 6 +- .../logged_out_marketing_header.yml | 8 ++ doc/api/project_access_tokens.md | 112 +++++++++++++++++ doc/api/resource_access_tokens.md | 113 +----------------- locale/gitlab.pot | 38 +++++- ...ck_retries_with_disable_ddl_transaction.rb | 41 +++++++ .../user_sees_marketing_header_spec.rb | 52 ++++++++ spec/helpers/application_helper_spec.rb | 34 ++++++ ...tries_with_disable_ddl_transaction_spec.rb | 58 +++++++++ 17 files changed, 454 insertions(+), 118 deletions(-) create mode 100644 app/views/layouts/header/_marketing_links.html.haml create mode 100644 app/views/layouts/header/_sign_in_register_button.html.haml create mode 100644 config/feature_flags/experiment/logged_out_marketing_header.yml create mode 100644 doc/api/project_access_tokens.md create mode 100644 rubocop/cop/migration/prevent_global_enable_lock_retries_with_disable_ddl_transaction.rb create mode 100644 spec/features/user_sees_marketing_header_spec.rb create mode 100644 spec/rubocop/cop/migration/prevent_global_enable_lock_retries_with_disable_ddl_transaction_spec.rb diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss index 69690fec208..fb05f8575ef 100644 --- a/app/assets/stylesheets/framework/layout.scss +++ b/app/assets/stylesheets/framework/layout.scss @@ -201,3 +201,9 @@ body { padding-right: 0; } } + +@include media-breakpoint-up(sm) { + .logged-out-marketing-header-candidate { + --header-height: 72px; + } +} diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 789968968a9..3e83c295491 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -610,6 +610,14 @@ $pagination-disabled-color: #cdcdcd; */ $status-icon-size: 22px; + +/* +* Social Icons +*/ +$twitter: #1d9bf0; +$skype: #0078d7; +$linkedin: #2867b2; + /* * Award emoji */ diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss index a7ed7172f5f..ccbc796913e 100644 --- a/app/assets/stylesheets/pages/profile.scss +++ b/app/assets/stylesheets/pages/profile.scss @@ -383,3 +383,15 @@ table.u2f-registrations { width: 100%; max-width: $add-to-slack-popup-max-width; } + +.skype-icon { + color: $skype; +} + +.linkedin-icon { + color: $linkedin; +} + +.twitter-icon { + color: $twitter; +} diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 02a87979f40..d7023536dec 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -285,6 +285,7 @@ module ApplicationHelper class_names << 'environment-logs-page' if current_controller?(:logs) class_names << 'with-performance-bar' if performance_bar_enabled? class_names << system_message_class + class_names << marketing_header_experiment_class class_names end @@ -420,6 +421,16 @@ module ApplicationHelper def appearance ::Appearance.current end + + def marketing_header_experiment_class + return if current_user + + experiment(:logged_out_marketing_header, actor: nil) do |e| + e.candidate { 'logged-out-marketing-header-candidate' } + e.control {} + e.run + end + end end ApplicationHelper.prepend_mod diff --git a/app/views/devise/confirmations/almost_there.haml b/app/views/devise/confirmations/almost_there.haml index 892ef730884..1d46a43e5bd 100644 --- a/app/views/devise/confirmations/almost_there.haml +++ b/app/views/devise/confirmations/almost_there.haml @@ -2,7 +2,9 @@ - request_link_start = ''.html_safe % { new_user_confirmation_path: new_user_confirmation_path } - request_link_end = ''.html_safe - content_for :page_specific_javascripts do + = render "layouts/google_tag_manager_head" = render "layouts/one_trust" += render "layouts/google_tag_manager_body" .well-confirmation.gl-text-center.gl-mb-6 %h1.gl-mt-0 diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index fc4711af71e..63297bf97d1 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -19,8 +19,16 @@ %span.gl-badge.gl-bg-green-500.gl-text-white.gl-rounded-pill.gl-font-weight-bold.gl-py-1 = _('Next') - .gl-display-none.gl-sm-display-block - = render "layouts/nav/top_nav" + - if current_user + .gl-display-none.gl-sm-display-block + = render "layouts/nav/top_nav" + - else + - experiment(:logged_out_marketing_header, actor: nil) do |e| + - e.candidate do + = render 'layouts/header/marketing_links' + - e.control do + .gl-display-none.gl-sm-display-block + = render "layouts/nav/top_nav" .navbar-collapse.collapse %ul.nav.navbar-nav @@ -104,6 +112,12 @@ = sprite_icon('chevron-down', css_class: 'caret-down') .dropdown-menu.dropdown-menu-right = render 'layouts/header/help_dropdown' + - unless current_user + - experiment(:logged_out_marketing_header, actor: nil) do |e| + - e.candidate do + %li.nav-item.gl-display-none.gl-sm-display-block + = render "layouts/nav/top_nav" + - e.control {} - if header_link?(:user_dropdown) %li.nav-item.header-user.js-nav-user-dropdown.dropdown{ data: { track_label: "profile_dropdown", track_action: "click_dropdown", track_value: "", qa_selector: 'user_menu' }, class: ('mr-0' if has_impersonation_link) } = link_to current_user, class: user_dropdown_class, data: { toggle: "dropdown" } do @@ -117,10 +131,15 @@ = link_to admin_impersonation_path, class: 'nav-link impersonation-btn', method: :delete, title: _('Stop impersonation'), aria: { label: _('Stop impersonation') }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body', qa_selector: 'stop_impersonation_link' } do = sprite_icon('incognito', size: 18) - if header_link?(:sign_in) - %li.nav-item - %div - - sign_in_text = allow_signup? ? _('Sign in / Register') : _('Sign in') - = link_to sign_in_text, new_session_path(:user, redirect_to_referer: 'yes'), class: 'gl-button btn btn-default btn-sign-in' + - experiment(:logged_out_marketing_header, actor: nil) do |e| + - e.candidate do + %li.nav-item.gl-display-none.gl-sm-display-block + = link_to _('Sign up now'), new_user_registration_path, class: 'gl-button btn btn-default btn-sign-in' + %li.nav-item.gl-display-none.gl-sm-display-block + = link_to _('Login'), new_session_path(:user, redirect_to_referer: 'yes') + = render 'layouts/header/sign_in_register_button', class: 'gl-sm-display-none' + - e.control do + = render 'layouts/header/sign_in_register_button' %button.navbar-toggler.d-block.d-sm-none{ type: 'button', class: 'gl-border-none!', data: { testid: 'top-nav-responsive-toggle', qa_selector: 'mobile_navbar_button' } } %span.sr-only= _('Toggle navigation') diff --git a/app/views/layouts/header/_marketing_links.html.haml b/app/views/layouts/header/_marketing_links.html.haml new file mode 100644 index 00000000000..24069de394d --- /dev/null +++ b/app/views/layouts/header/_marketing_links.html.haml @@ -0,0 +1,34 @@ +%ul.nav.navbar-sub-nav.gl-display-none.gl-lg-display-flex.gl-align-items-center + %li.dropdown.gl-mr-3 + %button{ type: "button", data: { toggle: "dropdown" } } + = s_('LoggedOutMarketingHeader|About GitLab') + = sprite_icon('chevron-down', css_class: 'caret-down') + .dropdown-menu + %ul + %li + = link_to 'https://about.gitlab.com/stages-devops-lifecycle/' do + = s_('LoggedOutMarketingHeader|GitLab: the DevOps platform') + %li + = link_to explore_root_path do + = s_('LoggedOutMarketingHeader|Explore GitLab') + %li + = link_to 'https://about.gitlab.com/install/' do + = s_('LoggedOutMarketingHeader|Install GitLab') + %li + = link_to 'https://about.gitlab.com/is-it-any-good/' do + = s_('LoggedOutMarketingHeader|How GitLab compares') + %li + = link_to 'https://about.gitlab.com/get-started/' do + = s_('LoggedOutMarketingHeader|Get started') + %li + = link_to 'https://docs.gitlab.com/' do + = s_('LoggedOutMarketingHeader|GitLab docs') + %li + = link_to 'https://about.gitlab.com/learn/' do + = s_('LoggedOutMarketingHeader|GitLab Learn') + %li.gl-mr-3 + = link_to 'https://about.gitlab.com/pricing/' do + = s_('LoggedOutMarketingHeader|Pricing') + %li.gl-mr-3 + = link_to 'https://about.gitlab.com/sales/' do + = s_('LoggedOutMarketingHeader|Talk to an expert') diff --git a/app/views/layouts/header/_sign_in_register_button.html.haml b/app/views/layouts/header/_sign_in_register_button.html.haml new file mode 100644 index 00000000000..992e8785251 --- /dev/null +++ b/app/views/layouts/header/_sign_in_register_button.html.haml @@ -0,0 +1,6 @@ +- top_class = local_assigns.fetch(:class, nil) + +%li.nav-item{ class: top_class } + %div + - sign_in_text = allow_signup? ? _('Sign in / Register') : _('Sign in') + = link_to sign_in_text, new_session_path(:user, redirect_to_referer: 'yes'), class: 'gl-button btn btn-default btn-sign-in' diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index ca276519758..d5a1f3884c9 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -98,15 +98,15 @@ - unless @user.skype.blank? = render 'middle_dot_divider' do = link_to "skype:#{@user.skype}", class: 'gl-hover-text-decoration-none', title: "Skype" do - = sprite_icon('skype') + = sprite_icon('skype', css_class: 'skype-icon') - unless @user.linkedin.blank? = render 'middle_dot_divider' do = link_to linkedin_url(@user), class: 'gl-hover-text-decoration-none', title: "LinkedIn", target: '_blank', rel: 'noopener noreferrer nofollow' do - = sprite_icon('linkedin') + = sprite_icon('linkedin', css_class: 'linkedin-icon') - unless @user.twitter.blank? = render 'middle_dot_divider', breakpoint: 'sm' do = link_to twitter_url(@user), class: 'gl-hover-text-decoration-none', title: "Twitter", target: '_blank', rel: 'noopener noreferrer nofollow' do - = sprite_icon('twitter') + = sprite_icon('twitter', css_class: 'twitter-icon') - unless @user.website_url.blank? = render 'middle_dot_divider', stacking: true do - if Feature.enabled?(:security_auto_fix) && @user.bot? diff --git a/config/feature_flags/experiment/logged_out_marketing_header.yml b/config/feature_flags/experiment/logged_out_marketing_header.yml new file mode 100644 index 00000000000..8bc09d59b16 --- /dev/null +++ b/config/feature_flags/experiment/logged_out_marketing_header.yml @@ -0,0 +1,8 @@ +--- +name: logged_out_marketing_header +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/76076 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/348525 +milestone: '14.7' +type: experiment +group: group::activation +default_enabled: false diff --git a/doc/api/project_access_tokens.md b/doc/api/project_access_tokens.md new file mode 100644 index 00000000000..125797a802f --- /dev/null +++ b/doc/api/project_access_tokens.md @@ -0,0 +1,112 @@ +--- +stage: Manage +group: Authentication & 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 +--- + +# Project access tokens API **(FREE)** + +You can read more about [project access tokens](../user/project/settings/project_access_tokens.md). + +## List project access tokens + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/238991) in GitLab 13.9. + +Get a list of [project access tokens](../user/project/settings/project_access_tokens.md). + +```plaintext +GET projects/:id/access_tokens +``` + +| Attribute | Type | required | Description | +|-----------|---------|----------|---------------------| +| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) | + +```shell +curl --header "PRIVATE-TOKEN: " "https://gitlab.example.com/api/v4/projects//access_tokens" +``` + +```json +[ + { + "user_id" : 141, + "scopes" : [ + "api" + ], + "name" : "token", + "expires_at" : "2021-01-31", + "id" : 42, + "active" : true, + "created_at" : "2021-01-20T22:11:48.151Z", + "revoked" : false, + "access_level": 40 + } +] +``` + +## Create a project access token + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55408) in GitLab 13.10. + +Create a [project access token](../user/project/settings/project_access_tokens.md). + +```plaintext +POST projects/:id/access_tokens +``` + +| Attribute | Type | required | Description | +|-----------|---------|----------|---------------------| +| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) | +| `name` | String | yes | The name of the project access token | +| `scopes` | `Array[String]` | yes | [List of scopes](../user/project/settings/project_access_tokens.md#scopes-for-a-project-access-token) | +| `access_level` | Integer | no | A valid access level. Default value is 40 (Maintainer). Other allowed values are 10 (Guest), 20 (Reporter), and 30 (Developer). | +| `expires_at` | Date | no | The token expires at midnight UTC on that date | + +```shell +curl --request POST --header "PRIVATE-TOKEN: " \ +--header "Content-Type:application/json" \ +--data '{ "name":"test_token", "scopes":["api", "read_repository"], "expires_at":"2021-01-31", "access_level": 30 }' \ +"https://gitlab.example.com/api/v4/projects//access_tokens" +``` + +```json +{ + "scopes" : [ + "api", + "read_repository" + ], + "active" : true, + "name" : "test", + "revoked" : false, + "created_at" : "2021-01-21T19:35:37.921Z", + "user_id" : 166, + "id" : 58, + "expires_at" : "2021-01-31", + "token" : "D4y...Wzr", + "access_level": 30 +} +``` + +## Revoke a project access token + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/238991) in GitLab 13.9. + +Revoke a [project access token](../user/project/settings/project_access_tokens.md). + +```plaintext +DELETE projects/:id/access_tokens/:token_id +``` + +| Attribute | Type | required | Description | +|-----------|---------|----------|---------------------| +| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) | +| `token_id` | integer or string | yes | The ID of the project access token | + +```shell +curl --request DELETE --header "PRIVATE-TOKEN: " "https://gitlab.example.com/api/v4/projects//access_tokens/" +``` + +### Responses + +- `204: No Content` if successfully revoked. +- `400 Bad Request` or `404 Not Found` if not revoked successfully. diff --git a/doc/api/resource_access_tokens.md b/doc/api/resource_access_tokens.md index bd0e68e8ea6..c77a8f5d0d6 100644 --- a/doc/api/resource_access_tokens.md +++ b/doc/api/resource_access_tokens.md @@ -1,112 +1,9 @@ --- -stage: Manage -group: Authentication & 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 +redirect_to: 'project_access_tokens.md' +remove_date: '2022-04-06' --- -# Project access tokens API **(FREE)** +This document was moved to [another location](project_access_tokens.md). -You can read more about [project access tokens](../user/project/settings/project_access_tokens.md). - -## List project access tokens - -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/238991) in GitLab 13.9. - -Get a list of project access tokens. - -```plaintext -GET projects/:id/access_tokens -``` - -| Attribute | Type | required | Description | -|-----------|---------|----------|---------------------| -| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) | - -```shell -curl --header "PRIVATE-TOKEN: " "https://gitlab.example.com/api/v4/projects//access_tokens" -``` - -```json -[ - { - "user_id" : 141, - "scopes" : [ - "api" - ], - "name" : "token", - "expires_at" : "2021-01-31", - "id" : 42, - "active" : true, - "created_at" : "2021-01-20T22:11:48.151Z", - "revoked" : false, - "access_level": 40 - } -] -``` - -## Create a project access token - -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55408) in GitLab 13.10. - -Create a project access token. - -```plaintext -POST projects/:id/access_tokens -``` - -| Attribute | Type | required | Description | -|-----------|---------|----------|---------------------| -| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) | -| `name` | String | yes | The name of the project access token | -| `scopes` | `Array[String]` | yes | [List of scopes](../user/project/settings/project_access_tokens.md#scopes-for-a-project-access-token) | -| `access_level` | Integer | no | A valid access level. Default value is 40 (Maintainer). Other allowed values are 10 (Guest), 20 (Reporter), and 30 (Developer). | -| `expires_at` | Date | no | The token expires at midnight UTC on that date | - -```shell -curl --request POST --header "PRIVATE-TOKEN: " \ ---header "Content-Type:application/json" \ ---data '{ "name":"test_token", "scopes":["api", "read_repository"], "expires_at":"2021-01-31", "access_level": 30 }' \ -"https://gitlab.example.com/api/v4/projects//access_tokens" -``` - -```json -{ - "scopes" : [ - "api", - "read_repository" - ], - "active" : true, - "name" : "test", - "revoked" : false, - "created_at" : "2021-01-21T19:35:37.921Z", - "user_id" : 166, - "id" : 58, - "expires_at" : "2021-01-31", - "token" : "D4y...Wzr", - "access_level": 30 -} -``` - -## Revoke a project access token - -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/238991) in GitLab 13.9. - -Revoke a project access token. - -```plaintext -DELETE projects/:id/access_tokens/:token_id -``` - -| Attribute | Type | required | Description | -|-----------|---------|----------|---------------------| -| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) | -| `token_id` | integer or string | yes | The ID of the project access token | - -```shell -curl --request DELETE --header "PRIVATE-TOKEN: " "https://gitlab.example.com/api/v4/projects//access_tokens/" -``` - -### Responses - -- `204: No Content` if successfully revoked. -- `400 Bad Request` or `404 Not Found` if not revoked successfully. + + diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 995da32e785..e2210cc0592 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -21429,6 +21429,39 @@ msgstr "" msgid "Locks the discussion." msgstr "" +msgid "LoggedOutMarketingHeader|About GitLab" +msgstr "" + +msgid "LoggedOutMarketingHeader|Explore GitLab" +msgstr "" + +msgid "LoggedOutMarketingHeader|Get started" +msgstr "" + +msgid "LoggedOutMarketingHeader|GitLab Learn" +msgstr "" + +msgid "LoggedOutMarketingHeader|GitLab docs" +msgstr "" + +msgid "LoggedOutMarketingHeader|GitLab: the DevOps platform" +msgstr "" + +msgid "LoggedOutMarketingHeader|How GitLab compares" +msgstr "" + +msgid "LoggedOutMarketingHeader|Install GitLab" +msgstr "" + +msgid "LoggedOutMarketingHeader|Pricing" +msgstr "" + +msgid "LoggedOutMarketingHeader|Talk to an expert" +msgstr "" + +msgid "Login" +msgstr "" + msgid "Login with smartcard" msgstr "" @@ -32902,6 +32935,9 @@ msgstr "" msgid "Sign up" msgstr "" +msgid "Sign up now" +msgstr "" + msgid "Sign up was successful! Please confirm your email to sign in." msgstr "" @@ -40776,7 +40812,7 @@ msgstr "" msgid "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}." msgstr "" -msgid "You have successfully purchased %{product}. You'll receive a receipt by email." +msgid "You have successfully purchased %{product}. You'll receive a receipt by email. Your purchase may take a minute to sync, so refresh the page if you don't see it yet." msgstr "" msgid "You have successfully purchased a %{plan} plan subscription for %{seats}. You’ll receive a receipt via email." diff --git a/rubocop/cop/migration/prevent_global_enable_lock_retries_with_disable_ddl_transaction.rb b/rubocop/cop/migration/prevent_global_enable_lock_retries_with_disable_ddl_transaction.rb new file mode 100644 index 00000000000..f5343f973e1 --- /dev/null +++ b/rubocop/cop/migration/prevent_global_enable_lock_retries_with_disable_ddl_transaction.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require_relative '../../migration_helpers' + +module RuboCop + module Cop + module Migration + # Cop that prevents usage of `enable_lock_retries!` within the `disable_ddl_transaction!` method. + class PreventGlobalEnableLockRetriesWithDisableDdlTransaction < RuboCop::Cop::Cop + include MigrationHelpers + + MSG = '`enable_lock_retries!` cannot be used with `disable_ddl_transaction!`. Use the `with_lock_retries` helper method to define retriable code blocks.' + + def_node_matcher :enable_lock_retries?, <<~PATTERN + (send _ :enable_lock_retries! ...) + PATTERN + + def_node_matcher :disable_ddl_transaction?, <<~PATTERN + (send _ :disable_ddl_transaction! ...) + PATTERN + + def on_begin(node) + return unless in_migration?(node) + + has_enable_lock_retries = false + has_disable_ddl_transaction = false + + node.each_descendant(:send) do |send_node| + has_enable_lock_retries = true if enable_lock_retries?(send_node) + has_disable_ddl_transaction = true if disable_ddl_transaction?(send_node) + + if has_enable_lock_retries && has_disable_ddl_transaction + add_offense(send_node, message: MSG) + break + end + end + end + end + end + end +end diff --git a/spec/features/user_sees_marketing_header_spec.rb b/spec/features/user_sees_marketing_header_spec.rb new file mode 100644 index 00000000000..d282495d6ce --- /dev/null +++ b/spec/features/user_sees_marketing_header_spec.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe 'User sees experimental lmarketing header' do + let_it_be(:project) { create(:project, :public) } + + context 'when not logged in' do + context 'when experiment candidate' do + it 'shows marketing header links', :aggregate_failures do + stub_experiments(logged_out_marketing_header: :candidate) + + visit project_path(project) + + expect(page).to have_text "About GitLab" + expect(page).to have_text "Pricing" + expect(page).to have_text "Talk to an expert" + expect(page).to have_text "Sign up now" + expect(page).to have_text "Login" + end + end + + context 'when experiment control' do + it 'does not show marketing header links', :aggregate_failures do + stub_experiments(logged_out_marketing_header: :control) + + visit project_path(project) + + expect(page).not_to have_text "About GitLab" + expect(page).not_to have_text "Pricing" + expect(page).not_to have_text "Talk to an expert" + expect(page).not_to have_text "Sign up now" + expect(page).not_to have_text "Login" + expect(page).to have_text "Sign in / Register" + end + end + end + + context 'when logged in' do + it 'does not show marketing header links', :aggregate_failures do + sign_in(create(:user)) + + stub_experiments(logged_out_marketing_header: :candidate) + + visit project_path(project) + + expect(page).not_to have_text "About GitLab" + expect(page).not_to have_text "Pricing" + expect(page).not_to have_text "Talk to an expert" + end + end +end diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 7390b9b3f58..62a409efec1 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -477,4 +477,38 @@ RSpec.describe ApplicationHelper do expect(helper).to have_received(:form_for).with(user, expected_options) end end + + describe '#page_class' do + context 'when logged_out_marketing_header experiment is enabled' do + let_it_be(:expected_class) { 'logged-out-marketing-header-candidate' } + + let(:current_user) { nil } + let(:variant) { :candidate } + + subject do + helper.page_class.flatten + end + + before do + stub_experiments(logged_out_marketing_header: variant) + allow(helper).to receive(:current_user) { current_user } + end + + context 'when candidate' do + it { is_expected.to include(expected_class) } + end + + context 'when control' do + let(:variant) { :control } + + it { is_expected.not_to include(expected_class) } + end + + context 'when a user is logged in' do + let(:current_user) { create(:user) } + + it { is_expected.not_to include(expected_class) } + end + end + end end diff --git a/spec/rubocop/cop/migration/prevent_global_enable_lock_retries_with_disable_ddl_transaction_spec.rb b/spec/rubocop/cop/migration/prevent_global_enable_lock_retries_with_disable_ddl_transaction_spec.rb new file mode 100644 index 00000000000..aa63259288d --- /dev/null +++ b/spec/rubocop/cop/migration/prevent_global_enable_lock_retries_with_disable_ddl_transaction_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require_relative '../../../../rubocop/cop/migration/prevent_global_enable_lock_retries_with_disable_ddl_transaction' + +RSpec.describe RuboCop::Cop::Migration::PreventGlobalEnableLockRetriesWithDisableDdlTransaction do + subject(:cop) { described_class.new } + + context 'when in migration' do + before do + allow(cop).to receive(:in_migration?).and_return(true) + end + + it 'registers an offense when `enable_lock_retries` and `disable_ddl_transaction` is used together' do + code = <<~RUBY + class SomeMigration < ActiveRecord::Migration[6.0] + enable_lock_retries! + disable_ddl_transaction! + end + RUBY + + expect_offense(<<~RUBY, node: code, msg: described_class::MSG) + class SomeMigration < ActiveRecord::Migration[6.0] + enable_lock_retries! + disable_ddl_transaction! + ^^^^^^^^^^^^^^^^^^^^^^^^ %{msg} + end + RUBY + end + + it 'registers no offense when `enable_lock_retries!` is used' do + expect_no_offenses(<<~RUBY) + class SomeMigration < ActiveRecord::Migration[6.0] + enable_lock_retries! + end + RUBY + end + + it 'registers no offense when `disable_ddl_transaction!` is used' do + expect_no_offenses(<<~RUBY) + class SomeMigration < ActiveRecord::Migration[6.0] + disable_ddl_transaction! + end + RUBY + end + end + + context 'when outside of migration' do + it 'registers no offense' do + expect_no_offenses(<<~RUBY) + class SomeMigration + enable_lock_retries! + disable_ddl_transaction! + end + RUBY + end + end +end