Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-01-07 06:14:36 +00:00
parent b2eab0d28d
commit 41bea98c57
17 changed files with 454 additions and 118 deletions

View File

@ -201,3 +201,9 @@ body {
padding-right: 0;
}
}
@include media-breakpoint-up(sm) {
.logged-out-marketing-header-candidate {
--header-height: 72px;
}
}

View File

@ -610,6 +610,14 @@ $pagination-disabled-color: #cdcdcd;
*/
$status-icon-size: 22px;
/*
* Social Icons
*/
$twitter: #1d9bf0;
$skype: #0078d7;
$linkedin: #2867b2;
/*
* Award emoji
*/

View File

@ -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;
}

View File

@ -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

View File

@ -2,7 +2,9 @@
- request_link_start = '<a href="%{new_user_confirmation_path}">'.html_safe % { new_user_confirmation_path: new_user_confirmation_path }
- request_link_end = '</a>'.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

View File

@ -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')

View File

@ -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')

View File

@ -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'

View File

@ -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?

View File

@ -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

View File

@ -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: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/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: <your_access_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/<project_id>/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: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/access_tokens/<token_id>"
```
### Responses
- `204: No Content` if successfully revoked.
- `400 Bad Request` or `404 Not Found` if not revoked successfully.

View File

@ -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: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/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: <your_access_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/<project_id>/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: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/access_tokens/<token_id>"
```
### Responses
- `204: No Content` if successfully revoked.
- `400 Bad Request` or `404 Not Found` if not revoked successfully.
<!-- This redirect file can be deleted after <2022-04-06>. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->

View File

@ -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}. Youll receive a receipt via email."

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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