Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-11-03 03:08:56 +00:00
parent 5774fd8912
commit 3ed6401d35
49 changed files with 332 additions and 304 deletions

View File

@ -1,27 +1,6 @@
@import 'mixins_and_variables_and_functions';
.signup-page {
.page-wrap {
background-color: var(--gray-10, $gray-10);
}
.signup-box-container {
max-width: 960px;
}
.signup-box {
background-color: var(--white, $white);
box-shadow: 0 0 0 1px var(--border-color, $border-color);
border-radius: $border-radius;
}
.form-control {
&:active,
&:focus {
background-color: var(--white, $white);
}
}
.devise-errors {
h2 {
font-size: $gl-font-size;

View File

@ -14,15 +14,12 @@ class RegistrationsController < Devise::RegistrationsController
prepend_before_action :check_captcha, only: :create
before_action :whitelist_query_limiting, :ensure_destroy_prerequisites_met, only: [:destroy]
before_action :load_recaptcha, only: :new
before_action :set_invite_params, only: :new
feature_category :authentication_and_authorization
def new
if experiment_enabled?(:signup_flow)
@resource = build_resource
else
redirect_to new_user_session_path(anchor: 'register-pane')
end
@resource = build_resource
end
def create
@ -206,8 +203,8 @@ class RegistrationsController < Devise::RegistrationsController
# Part of an experiment to build a new sign up flow. Will be resolved
# with https://gitlab.com/gitlab-org/growth/engineering/issues/64
def choose_layout
if %w(welcome update_registration).include?(action_name) || experiment_enabled?(:signup_flow)
'devise_experimental_separate_sign_up_flow'
if %w(welcome update_registration).include?(action_name)
'welcome'
else
'devise'
end
@ -225,6 +222,10 @@ class RegistrationsController < Devise::RegistrationsController
resource.state = BLOCKED_PENDING_APPROVAL_STATE
end
def set_invite_params
@invite_email = ActionController::Base.helpers.sanitize(params[:invite_email])
end
end
RegistrationsController.prepend_if_ee('EE::RegistrationsController')

View File

@ -571,6 +571,7 @@ class Project < ApplicationRecord
scope :imported_from, -> (type) { where(import_type: type) }
scope :with_tracing_enabled, -> { joins(:tracing_setting) }
scope :with_enabled_error_tracking, -> { joins(:error_tracking_setting).where(project_error_tracking_settings: { enabled: true }) }
enum auto_cancel_pending_pipelines: { disabled: 0, enabled: 1 }

View File

@ -6,11 +6,11 @@ module JiraConnect
self.project = project
end
def execute(commits: nil, branches: nil, merge_requests: nil)
def execute(commits: nil, branches: nil, merge_requests: nil, update_sequence_id: nil)
JiraConnectInstallation.for_project(project).each do |installation|
client = Atlassian::JiraConnect::Client.new(installation.base_url, installation.shared_secret)
response = client.store_dev_info(project: project, commits: commits, branches: branches, merge_requests: merge_requests)
response = client.store_dev_info(project: project, commits: commits, branches: branches, merge_requests: merge_requests, update_sequence_id: update_sequence_id)
log_response(response)
end

View File

@ -1,16 +1,6 @@
- page_title _("Sign up")
- if experiment_enabled?(:signup_flow)
.row
.col-lg-7
%h1.mb-3.font-weight-bold.text-6.mt-0
= html_escape(_("Speed up your DevOps%{br_tag}with GitLab")) % { br_tag: '<br/>'.html_safe }
%p.text-3
= _("GitLab is a single application for the entire software development lifecycle. From project planning and source code management to CI/CD, monitoring, and security.")
.col-lg-5.order-12
.text-center.mb-3
%h2.font-weight-bold= _('Register for GitLab')
= render 'devise/shared/experimental_separate_sign_up_flow_box'
= render 'devise/shared/sign_in_link'
- else
- add_page_specific_style 'page_bundles/signup'
.signup-page
= render 'devise/shared/signup_box'
= render 'devise/shared/sign_in_link'

View File

@ -2,23 +2,21 @@
#signin-container
- if any_form_based_providers_enabled?
= render 'devise/shared/tabs_ldap'
- else
- unless experiment_enabled?(:signup_flow)
= render 'devise/shared/tabs_normal'
= render 'devise/shared/tabs_ldap', render_signup_link: false
.tab-content
- if password_authentication_enabled_for_web? || ldap_sign_in_enabled? || crowd_enabled?
= render 'devise/shared/signin_box'
-# Signup only makes sense if you can also sign-in
- if allow_signup?
= render 'devise/shared/signup_box'
-# Show a message if none of the mechanisms above are enabled
- if !password_authentication_enabled_for_web? && !ldap_sign_in_enabled? && !(omniauth_enabled? && devise_mapping.omniauthable?)
%div
No authentication methods configured.
- if allow_signup?
%p.gl-mt-3
= _("Don't have an account yet?")
= link_to _("Register now"), new_registration_path(:user, invite_email: @invite_email), data: { qa_selector: 'register_link' }
- if omniauth_enabled? && devise_mapping.omniauthable? && button_based_providers_enabled?
.clearfix
= render 'devise/shared/omniauth_box'

View File

@ -1,38 +0,0 @@
- max_first_name_length = max_last_name_length = 127
- max_username_length = 255
- min_username_length = 2
.signup-box.p-3.mb-2
.signup-body
= form_for(resource, as: "new_#{resource_name}", url: registration_path(resource_name), html: { class: "new_new_user gl-show-field-errors", "aria-live" => "assertive" }) do |f|
.devise-errors.mt-0
= render "devise/shared/error_messages", resource: resource
- if Feature.enabled?(:invisible_captcha)
= invisible_captcha
.name.form-row
.col.form-group
= f.label :first_name, _('First name'), for: 'new_user_first_name', class: 'label-bold'
= f.text_field :first_name, class: 'form-control top js-block-emoji js-validate-length', :data => { :max_length => max_first_name_length, :max_length_message => _("First name is too long (maximum is %{max_length} characters).") % { max_length: max_first_name_length }, :qa_selector => 'new_user_firstname_field' }, required: true, title: _("This field is required.")
.col.form-group
= f.label :last_name, _('Last name'), for: 'new_user_last_name', class: 'label-bold'
= f.text_field :last_name, class: "form-control top js-block-emoji js-validate-length", :data => { :max_length => max_last_name_length, :max_length_message => _("Last name is too long (maximum is %{max_length} characters).") % { max_length: max_last_name_length }, :qa_selector => 'new_user_lastname_field' }, required: true, title: _("This field is required.")
.username.form-group
= f.label :username, class: 'label-bold'
= f.text_field :username, class: "form-control middle js-block-emoji js-validate-length js-validate-username", :data => { :min_length => min_username_length, :min_length_message => s_("SignUp|Username is too short (minimum is %{min_length} characters).") % { min_length: min_username_length }, :max_length => max_username_length, :max_length_message => _("Username is too long (maximum is %{max_length} characters).") % { max_length: max_username_length }, :qa_selector => 'new_user_username_field' }, pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, required: true, title: _("Please create a username with only alphanumeric characters.")
%p.validation-error.gl-field-error-ignore.field-validation.mt-1.hide.cred= _('Username is already taken.')
%p.validation-success.gl-field-error-ignore.field-validation.mt-1.hide.cgreen= _('Username is available.')
%p.validation-pending.gl-field-error-ignore.field-validation.mt-1.hide= _('Checking username availability...')
.form-group
= f.label :email, class: 'label-bold'
= f.email_field :email, class: "form-control middle", data: { qa_selector: 'new_user_email_field' }, required: true, title: _("Please provide a valid email address.")
.form-group.append-bottom-20#password-strength
= f.label :password, class: 'label-bold'
= f.password_field :password, class: "form-control bottom", data: { qa_selector: 'new_user_password_field' }, required: true, pattern: ".{#{@minimum_password_length},}", title: _("Minimum length is %{minimum_password_length} characters.") % { minimum_password_length: @minimum_password_length }
%p.gl-field-hint.text-secondary= _('Minimum length is %{minimum_password_length} characters') % { minimum_password_length: @minimum_password_length }
%div
- if show_recaptcha_sign_up?
= recaptcha_tags
.submit-container.mt-3
= f.submit _("Register"), class: "btn-register gl-button btn btn-block btn-success mb-0 p-2", data: { qa_selector: 'new_user_register_button' }
= render 'devise/shared/terms_of_service_notice'
- if omniauth_enabled? && button_based_providers_enabled?
= render 'devise/shared/experimental_separate_sign_up_flow_omniauth_box'

View File

@ -22,8 +22,3 @@
.login-box.tab-pane.active{ id: 'login-pane', role: 'tabpanel' }
.login-body
= render 'devise/sessions/new_base'
- if experiment_enabled?(:signup_flow)
%p.light.mt-2
= _("Don't have an account yet?")
= link_to _("Register now"), new_registration_path(:user)

View File

@ -1,36 +1,38 @@
- max_first_name_length = max_last_name_length = 127
- max_username_length = 255
- min_username_length = 2
#register-pane.tab-pane.login-box{ role: 'tabpanel' }
.login-body
= form_for(resource, as: "new_#{resource_name}", url: registration_path(resource_name), html: { class: "new_new_user gl-show-field-errors", "aria-live" => "assertive" }) do |f|
.devise-errors
= render "devise/shared/error_messages", resource: resource
- if Feature.enabled?(:invisible_captcha)
= invisible_captcha
.name.form-row
.col.form-group
= f.label :first_name, _('First name'), for: 'new_user_first_name', class: 'label-bold'
= f.text_field :first_name, class: 'form-control top js-block-emoji js-validate-length', :data => { :max_length => max_first_name_length, :max_length_message => _("First name is too long (maximum is %{max_length} characters).") % { max_length: max_first_name_length }, :qa_selector => 'new_user_first_name_field' }, required: true, title: _("This field is required.")
.col.form-group
= f.label :last_name, _('Last name'), for: 'new_user_last_name', class: 'label-bold'
= f.text_field :last_name, class: "form-control top js-block-emoji js-validate-length", :data => { :max_length => max_last_name_length, :max_length_message => _("Last name is too long (maximum is %{max_length} characters).") % { max_length: max_last_name_length }, :qa_selector => 'new_user_last_name_field' }, required: true, title: _("This field is required.")
.username.form-group
= f.label :username, class: 'label-bold'
= f.text_field :username, class: "form-control middle js-block-emoji js-validate-length js-validate-username", :data => { :min_length => min_username_length, :min_length_message => s_("SignUp|Username is too short (minimum is %{min_length} characters).") % { min_length: min_username_length }, :max_length => max_username_length, :max_length_message => s_("SignUp|Username is too long (maximum is %{max_length} characters).") % { max_length: max_username_length }, :qa_selector => 'new_user_username_field' }, pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, required: true, title: _("Please create a username with only alphanumeric characters.")
%p.validation-error.gl-field-error-ignore.field-validation.hide= _('Username is already taken.')
%p.validation-success.gl-field-error-ignore.field-validation.hide= _('Username is available.')
%p.validation-pending.gl-field-error-ignore.field-validation.hide= _('Checking username availability...')
.form-group
= f.label :email, class: 'label-bold'
= f.email_field :email, value: @invite_email, class: "form-control middle", data: { qa_selector: 'new_user_email_field' }, required: true, title: _("Please provide a valid email address.")
.form-group.append-bottom-20#password-strength
= f.label :password, class: 'label-bold'
= f.password_field :password, class: "form-control bottom", data: { qa_selector: 'new_user_password_field' }, required: true, pattern: ".{#{@minimum_password_length},}", title: _("Minimum length is %{minimum_password_length} characters.") % { minimum_password_length: @minimum_password_length }
%p.gl-field-hint.text-secondary= _('Minimum length is %{minimum_password_length} characters') % { minimum_password_length: @minimum_password_length }
%div
- if show_recaptcha_sign_up?
= recaptcha_tags
.submit-container
= f.submit _("Register"), class: "btn-register btn", data: { qa_selector: 'new_user_register_button' }
= render 'devise/shared/terms_of_service_notice'
.gl-mb-3.gl-p-4.gl-border-gray-100.gl-border-1.gl-border-solid.gl-rounded-base
= form_for(resource, as: "new_#{resource_name}", url: registration_path(resource_name), html: { class: "new_new_user gl-show-field-errors", "aria-live" => "assertive" }) do |f|
.devise-errors
= render "devise/shared/error_messages", resource: resource
- if Feature.enabled?(:invisible_captcha)
= invisible_captcha
.name.form-row
.col.form-group
= f.label :first_name, _('First name'), for: 'new_user_first_name', class: 'label-bold'
= f.text_field :first_name, class: 'form-control top js-block-emoji js-validate-length', :data => { :max_length => max_first_name_length, :max_length_message => _("First name is too long (maximum is %{max_length} characters).") % { max_length: max_first_name_length }, :qa_selector => 'new_user_first_name_field' }, required: true, title: _("This field is required.")
.col.form-group
= f.label :last_name, _('Last name'), for: 'new_user_last_name', class: 'label-bold'
= f.text_field :last_name, class: "form-control top js-block-emoji js-validate-length", :data => { :max_length => max_last_name_length, :max_length_message => _("Last name is too long (maximum is %{max_length} characters).") % { max_length: max_last_name_length }, :qa_selector => 'new_user_last_name_field' }, required: true, title: _("This field is required.")
.username.form-group
= f.label :username, class: 'label-bold'
= f.text_field :username, class: "form-control middle js-block-emoji js-validate-length js-validate-username", :data => { :min_length => min_username_length, :min_length_message => s_("SignUp|Username is too short (minimum is %{min_length} characters).") % { min_length: min_username_length }, :max_length => max_username_length, :max_length_message => s_("SignUp|Username is too long (maximum is %{max_length} characters).") % { max_length: max_username_length }, :qa_selector => 'new_user_username_field' }, pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, required: true, title: _("Please create a username with only alphanumeric characters.")
%p.validation-error.gl-text-red-500.gl-field-error-ignore.gl-mt-2.field-validation.hide= _('Username is already taken.')
%p.validation-success.gl-text-green-600.gl-field-error-ignore.gl-mt-2.field-validation.hide= _('Username is available.')
%p.validation-pending.gl-field-error-ignore.gl-mt-2.field-validation.hide= _('Checking username availability...')
.form-group
= f.label :email, class: 'label-bold'
= f.email_field :email, value: @invite_email, class: "form-control middle", data: { qa_selector: 'new_user_email_field' }, required: true, title: _("Please provide a valid email address.")
.form-group.append-bottom-20#password-strength
= f.label :password, class: 'label-bold'
= f.password_field :password, class: "form-control bottom", data: { qa_selector: 'new_user_password_field' }, required: true, pattern: ".{#{@minimum_password_length},}", title: _("Minimum length is %{minimum_password_length} characters.") % { minimum_password_length: @minimum_password_length }
%p.gl-field-hint.text-secondary= _('Minimum length is %{minimum_password_length} characters') % { minimum_password_length: @minimum_password_length }
%div
- if show_recaptcha_sign_up?
= recaptcha_tags
.submit-container
= f.submit _("Register"), class: "btn gl-button btn-success", data: { qa_selector: 'new_user_register_button' }
= render 'devise/shared/terms_of_service_notice'
- if omniauth_enabled? && button_based_providers_enabled?
= render 'devise/shared/signup_omniauth_providers'

View File

@ -1,17 +1,4 @@
- page_description brand_title unless page_description
-# Needs a redirect on the client side since it's using an anchor to distinguish
-# between sign in and registration. We need to inline the JS to not render
-# anything from this page beforehand.
-# Part of an experiment to build a new sign up flow. Will be removed again with
-# https://gitlab.com/gitlab-org/growth/engineering/issues/64
- if experiment_enabled?(:signup_flow) && current_path?("sessions#new")
= javascript_tag nonce: true do
:plain
if (window.location.hash === '#register-pane') {
window.location.replace("/users/sign_up")
}
- site_name = "GitLab"
%head{ prefix: "og: http://ogp.me/ns#" }
%meta{ charset: "utf-8" }

View File

@ -1,6 +1,6 @@
!!! 5
%html.devise-layout-html.navless{ class: system_message_class }
- add_page_specific_style 'page_bundles/experimental_separate_sign_up'
- add_page_specific_style 'page_bundles/signup'
= render "layouts/head"
%body.ui-indigo.signup-page{ class: "#{client_class_list}", data: { page: body_data_page, qa_selector: 'signup_page' } }
= render "layouts/header/logo_with_title"

View File

@ -1,20 +0,0 @@
!!! 5
%html.devise-layout-html.navless{ class: system_message_class }
- add_page_specific_style 'page_bundles/experimental_separate_sign_up'
= render "layouts/head"
%body.ui-indigo.signup-page{ class: "#{client_class_list}", data: { page: body_data_page, qa_selector: 'signup_page' } }
= render "layouts/header/logo_with_title"
= render "layouts/init_client_detection_flags"
.page-wrap
.container.signup-box-container.navless-container
= render "layouts/broadcast"
.content
= render "layouts/flash"
= yield
%hr.footer-fixed
.footer-container
.container
.footer-links
= link_to _("Help"), help_path
= link_to _("About GitLab"), "https://about.gitlab.com/"
= footer_message

View File

@ -0,0 +1,8 @@
!!! 5
%html.subscriptions-layout-html{ lang: 'en' }
= render 'layouts/head'
%body.ui-indigo.d-flex.vh-100.gl-bg-gray-10
= render "layouts/header/logo_with_title"
= render "layouts/broadcast"
.container.d-flex.flex-grow-1.m-0
= yield

View File

@ -1,6 +1,6 @@
- page_title _('Your profile')
.row.gl-flex-grow-1.gl-bg-gray-10
.row.gl-flex-grow-1
.d-flex.gl-flex-direction-column.gl-align-items-center.gl-w-full.gl-p-5
.edit-profile.login-page.d-flex.flex-column.gl-align-items-center.pt-lg-3
= render_if_exists "registrations/welcome/progress_bar"

View File

@ -19,7 +19,7 @@
= render "shared/notes/form", view: diff_view, supports_autocomplete: autocomplete
- elsif !current_user
.disabled-comment.text-center.gl-mt-3
- link_to_register = link_to(_("register"), new_session_path(:user, redirect_to_referer: 'yes', anchor: 'register-pane'), class: 'js-register-link')
- link_to_register = link_to(_("register"), new_user_registration_path(redirect_to_referer: 'yes'), class: 'js-register-link')
- link_to_sign_in = link_to(_("sign in"), new_session_path(:user, redirect_to_referer: 'yes'), class: 'js-sign-in-link')
= _("Please %{link_to_register} or %{link_to_sign_in} to comment").html_safe % { link_to_register: link_to_register, link_to_sign_in: link_to_sign_in }
- elsif discussion_locked

View File

@ -8,7 +8,7 @@ module JiraConnect
feature_category :integrations
loggable_arguments 1, 2
def perform(project_id, branch_name, commit_shas)
def perform(project_id, branch_name, commit_shas, update_sequence_id = nil)
project = Project.find_by_id(project_id)
return unless project
@ -16,7 +16,7 @@ module JiraConnect
branches = [project.repository.find_branch(branch_name)] if branch_name.present?
commits = project.commits_by(oids: commit_shas) if commit_shas.present?
JiraConnect::SyncService.new(project).execute(commits: commits, branches: branches)
JiraConnect::SyncService.new(project).execute(commits: commits, branches: branches, update_sequence_id: update_sequence_id)
end
end
end

View File

@ -7,12 +7,12 @@ module JiraConnect
queue_namespace :jira_connect
feature_category :integrations
def perform(merge_request_id)
def perform(merge_request_id, update_sequence_id = nil)
merge_request = MergeRequest.find_by_id(merge_request_id)
return unless merge_request && merge_request.project
JiraConnect::SyncService.new(merge_request.project).execute(merge_requests: [merge_request])
JiraConnect::SyncService.new(merge_request.project).execute(merge_requests: [merge_request], update_sequence_id: update_sequence_id)
end
end
end

View File

@ -0,0 +1,5 @@
---
title: Moves projects_with_error_tracking_enabled ping usage to Core
merge_request: 46556
author:
type: changed

View File

@ -0,0 +1,5 @@
---
title: Split sign in and sign up pages
merge_request: 42592
author:
type: changed

View File

@ -183,7 +183,7 @@ module Gitlab
config.assets.precompile << "page_bundles/environments.css"
config.assets.precompile << "page_bundles/error_tracking_details.css"
config.assets.precompile << "page_bundles/error_tracking_index.css"
config.assets.precompile << "page_bundles/experimental_separate_sign_up.css"
config.assets.precompile << "page_bundles/signup.css"
config.assets.precompile << "page_bundles/ide.css"
config.assets.precompile << "page_bundles/issues_list.css"
config.assets.precompile << "page_bundles/jira_connect.css"

View File

@ -262,6 +262,7 @@ Here are the valid connection parameters for GCS:
| `google_project` | GCP project name | `gcp-project-12345` |
| `google_client_email` | The email address of the service account | `foo@gcp-project-12345.iam.gserviceaccount.com` |
| `google_json_key_location` | The JSON key path | `/path/to/gcp-project-12345-abcde.json` |
| `google_application_default` | Set to `true` to use [Google Cloud Application Default Credentials](https://cloud.google.com/docs/authentication/production#automatically) to locate service account credentials. |
NOTE: **Note:**
The service account must have permission to access the bucket.
@ -280,6 +281,33 @@ gitlab_rails['object_store']['connection'] = {
}
```
##### Google example with ADC (consolidated form)
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/275979) in GitLab 13.6.
Google Cloud Application Default Credentials (ADC) are typically
used with GitLab to use the default service account. This eliminates the
need to supply credentials for the instance. For example:
```ruby
gitlab_rails['object_store']['connection'] = {
'provider' => 'Google',
'google_project' => '<GOOGLE PROJECT>',
'google_application_default' => true
}
```
If you use ADC, be sure that:
- The service account that you use has the
[`iam.serviceAccounts.signBlob` permission](https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/signBlob).
Typically this is done by granting the `Service Account Token Creator` role to the service account.
- Your virtual machines have the [correct access scopes to access Google Cloud APIs](https://cloud.google.com/compute/docs/access/create-enable-service-accounts-for-instances#changeserviceaccountandscopes). If the machines do not have the right scope, the error logs may show:
```markdown
Google::Apis::ClientError (insufficientPermissions: Request had insufficient authentication scopes.)
```
#### Azure Blob storage
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/25877) in GitLab 13.4.

View File

@ -1,6 +1,6 @@
---
stage: none
group: unassigned
stage: Monitor
group: Health
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/#designated-technical-writers
---

View File

@ -57,7 +57,7 @@ To subscribe to GitLab.com:
- **For individuals**:
1. Create a user account for yourself using our
[sign up page](https://gitlab.com/users/sign_in#register-pane).
[sign up page](https://gitlab.com/users/sign_up).
1. Visit the [billing page](https://gitlab.com/profile/billings)
under your profile.
1. Select the **Bronze**, **Silver**, or **Gold** GitLab.com plan through the
@ -70,7 +70,7 @@ To subscribe to GitLab.com:
1. Proceed to checkout.
- **For groups**:
1. Create a user account for yourself using our
[sign up page](https://gitlab.com/users/sign_in#register-pane).
[sign up page](https://gitlab.com/users/sign_up).
1. Create a [group](../../user/group/index.md). GitLab groups help assemble related
projects together allowing you to grant members access to several projects
at once. A group is not required if you plan on having projects inside a personal

View File

@ -14,9 +14,9 @@ You can create users:
## Create users on sign in page
If you have [sign-up enabled](../../admin_area/settings/sign_up_restrictions.md), users can create their own accounts using the **Register** tab on the sign in page.
If you have [sign-up enabled](../../admin_area/settings/sign_up_restrictions.md), users can create their own accounts by selecting "Register now" on the sign-in page, or navigate to `https://gitlab.example.com/users/sign_up`.
![Register Tab](img/register_tab.png)
![Register Tab](img/register_v13_6.png)
## Create users in Admin Area

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

View File

@ -3,19 +3,24 @@
module Atlassian
module JiraConnect
class Client < Gitlab::HTTP
def self.generate_update_sequence_id
Gitlab::Metrics::System.monotonic_time.to_i
end
def initialize(base_uri, shared_secret)
@base_uri = base_uri
@shared_secret = shared_secret
end
def store_dev_info(project:, commits: nil, branches: nil, merge_requests: nil)
def store_dev_info(project:, commits: nil, branches: nil, merge_requests: nil, update_sequence_id: nil)
dev_info_json = {
repositories: [
Serializers::RepositoryEntity.represent(
project,
commits: commits,
branches: branches,
merge_requests: merge_requests
merge_requests: merge_requests,
update_sequence_id: update_sequence_id
)
]
}.to_json

View File

@ -9,12 +9,12 @@ module Atlassian
format_with(:string) { |value| value.to_s }
expose :monotonic_time, as: :updateSequenceId
expose :update_sequence_id, as: :updateSequenceId
private
def monotonic_time
Gitlab::Metrics::System.monotonic_time.to_i
def update_sequence_id
options[:update_sequence_id] || Client.generate_update_sequence_id
end
end
end

View File

@ -15,13 +15,13 @@ module Atlassian
end
expose :commits do |project, options|
JiraConnect::Serializers::CommitEntity.represent options[:commits], project: project
JiraConnect::Serializers::CommitEntity.represent options[:commits], project: project, update_sequence_id: options[:update_sequence_id]
end
expose :branches do |project, options|
JiraConnect::Serializers::BranchEntity.represent options[:branches], project: project
JiraConnect::Serializers::BranchEntity.represent options[:branches], project: project, update_sequence_id: options[:update_sequence_id]
end
expose :pullRequests do |project, options|
JiraConnect::Serializers::PullRequestEntity.represent options[:merge_requests], project: project
JiraConnect::Serializers::PullRequestEntity.represent options[:merge_requests], project: project, update_sequence_id: options[:update_sequence_id]
end
end
end

View File

@ -617,7 +617,8 @@ module Gitlab
operations_dashboard_default_dashboard: count(::User.active.with_dashboard('operations').where(time_period),
start: user_minimum_id,
finish: user_maximum_id),
projects_with_tracing_enabled: distinct_count(::Project.with_tracing_enabled.where(time_period), :creator_id)
projects_with_tracing_enabled: distinct_count(::Project.with_tracing_enabled.where(time_period), :creator_id),
projects_with_error_tracking_enabled: distinct_count(::Project.with_enabled_error_tracking.where(time_period), :creator_id)
}
end
# rubocop: enable CodeReuse/ActiveRecord

View File

@ -22016,9 +22016,6 @@ msgstr ""
msgid "Register device"
msgstr ""
msgid "Register for GitLab"
msgstr ""
msgid "Register now"
msgstr ""
@ -25305,9 +25302,6 @@ msgstr ""
msgid "Specify the following URL during the Runner setup:"
msgstr ""
msgid "Speed up your DevOps%{br_tag}with GitLab"
msgstr ""
msgid "Squash commit message"
msgstr ""
@ -29246,9 +29240,6 @@ msgstr ""
msgid "Username is available."
msgstr ""
msgid "Username is too long (maximum is %{max_length} characters)."
msgstr ""
msgid "Username or email"
msgstr ""

View File

@ -125,9 +125,9 @@ module QA
click_element :sign_in_tab
end
def switch_to_register_tab
def switch_to_register_page
set_initial_password_if_present
click_element :register_tab
click_element :register_link
end
def switch_to_ldap_tab

View File

@ -75,7 +75,7 @@ module QA
end
else
Page::Main::Login.perform do |login|
login.switch_to_register_tab
login.switch_to_register_page
end
Page::Main::SignUp.perform do |signup|
signup.sign_up!(self)

View File

@ -12,30 +12,10 @@ RSpec.describe RegistrationsController do
describe '#new' do
subject { get :new }
context 'with the experimental signup flow enabled and the user is part of the experimental group' do
before do
stub_experiment(signup_flow: true)
stub_experiment_for_user(signup_flow: true)
end
it 'renders new template and sets the resource variable' do
expect(subject).to render_template(:new)
expect(response).to have_gitlab_http_status(:ok)
expect(assigns(:resource)).to be_a(User)
end
end
context 'with the experimental signup flow enabled and the user is part of the control group' do
before do
stub_experiment(signup_flow: true)
stub_experiment_for_user(signup_flow: false)
end
it 'renders new template and sets the resource variable' do
subject
expect(response).to have_gitlab_http_status(:found)
expect(response).to redirect_to(new_user_session_path(anchor: 'register-pane'))
end
it 'renders new template and sets the resource variable' do
expect(subject).to render_template(:new)
expect(response).to have_gitlab_http_status(:ok)
expect(assigns(:resource)).to be_a(User)
end
end
@ -426,12 +406,10 @@ RSpec.describe RegistrationsController do
describe '#welcome' do
subject { get :welcome }
it 'renders the devise_experimental_separate_sign_up_flow layout' do
it 'renders the welcome layout' do
sign_in(create(:user))
expected_layout = Gitlab.ee? ? :checkout : :devise_experimental_separate_sign_up_flow
expect(subject).to render_template(expected_layout)
expect(subject).to render_template(:welcome)
end
context '2FA is required from group' do

View File

@ -58,6 +58,8 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures do
end
it 'pre-fills the Email field on the sign up box with the invite_email from the invite' do
click_link 'Register now'
expect(find_field('Email').value).to eq(group_invite.invite_email)
end
@ -92,6 +94,7 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures do
before do
stub_application_setting(send_user_confirmation_email: send_email_confirmation)
visit invite_path(group_invite.raw_invite_token)
click_link 'Register now'
end
context 'email confirmation disabled' do

View File

@ -26,7 +26,6 @@ RSpec.describe 'Login' do
user.reload
expect(user.reset_password_token).not_to be_nil
find('a[href="#login-pane"]').click
gitlab_sign_in(user)
expect(current_path).to eq root_path
@ -593,10 +592,16 @@ RSpec.describe 'Login' do
describe 'UI tabs and panes' do
context 'when no defaults are changed' do
it 'correctly renders tabs and panes' do
it 'does not render any tabs' do
visit new_user_session_path
ensure_tab_pane_correctness(['Sign in', 'Register'])
ensure_no_tabs
end
it 'renders link to sign up path' do
visit new_user_session_path
expect(page.body).to have_link('Register now', href: new_user_registration_path)
end
end
@ -607,8 +612,14 @@ RSpec.describe 'Login' do
visit new_user_session_path
end
it 'correctly renders tabs and panes' do
ensure_tab_pane_correctness(['Sign in'])
it 'does not render any tabs' do
ensure_no_tabs
end
it 'does not render link to sign up path' do
visit new_user_session_path
expect(page.body).not_to have_link('Register now', href: new_user_registration_path)
end
end
@ -644,7 +655,11 @@ RSpec.describe 'Login' do
end
it 'correctly renders tabs and panes' do
ensure_tab_pane_correctness(['Main LDAP', 'Standard', 'Register'])
ensure_tab_pane_correctness(['Main LDAP', 'Standard'])
end
it 'renders link to sign up path' do
expect(page.body).to have_link('Register now', href: new_user_registration_path)
end
end
@ -665,7 +680,7 @@ RSpec.describe 'Login' do
end
it 'correctly renders tabs and panes' do
ensure_tab_pane_correctness(%w(Crowd Standard Register))
ensure_tab_pane_correctness(%w(Crowd Standard))
end
end
end

View File

@ -2,7 +2,45 @@
require 'spec_helper'
RSpec.shared_examples 'Signup' do
RSpec.shared_examples 'Signup name validation' do |field, max_length, label|
before do
visit new_user_registration_path
end
describe "#{field} validation", :js do
it "does not show an error border if the user's fullname length is not longer than #{max_length} characters" do
fill_in field, with: 'u' * max_length
expect(find('.name')).not_to have_css '.gl-field-error-outline'
end
it 'shows an error border if the user\'s fullname contains an emoji' do
simulate_input("##{field}", 'Ehsan 🦋')
expect(find('.name')).to have_css '.gl-field-error-outline'
end
it "shows an error border if the user\'s fullname is longer than #{max_length} characters" do
fill_in field, with: 'n' * (max_length + 1)
expect(find('.name')).to have_css '.gl-field-error-outline'
end
it "shows an error message if the user\'s #{label} is longer than #{max_length} characters" do
fill_in field, with: 'n' * (max_length + 1)
expect(page).to have_content("#{label} is too long (maximum is #{max_length} characters).")
end
it 'shows an error message if the username contains emojis' do
simulate_input("##{field}", 'Ehsan 🦋')
expect(page).to have_content("Invalid input, please avoid emojis")
end
end
end
RSpec.describe 'Signup' do
include TermsHelper
let(:new_user) { build_stubbed(:user) }
@ -295,64 +333,7 @@ RSpec.shared_examples 'Signup' do
expect(created_user.setup_for_company).to be_nil
expect(page).to have_current_path(new_project_path)
end
end
RSpec.shared_examples 'Signup name validation' do |field, max_length, label|
before do
visit new_user_registration_path
end
describe "#{field} validation", :js do
it "does not show an error border if the user's fullname length is not longer than #{max_length} characters" do
fill_in field, with: 'u' * max_length
expect(find('.name')).not_to have_css '.gl-field-error-outline'
end
it 'shows an error border if the user\'s fullname contains an emoji' do
simulate_input("##{field}", 'Ehsan 🦋')
expect(find('.name')).to have_css '.gl-field-error-outline'
end
it "shows an error border if the user\'s fullname is longer than #{max_length} characters" do
fill_in field, with: 'n' * (max_length + 1)
expect(find('.name')).to have_css '.gl-field-error-outline'
end
it "shows an error message if the user\'s #{label} is longer than #{max_length} characters" do
fill_in field, with: 'n' * (max_length + 1)
expect(page).to have_content("#{label} is too long (maximum is #{max_length} characters).")
end
it 'shows an error message if the username contains emojis' do
simulate_input("##{field}", 'Ehsan 🦋')
expect(page).to have_content("Invalid input, please avoid emojis")
end
end
end
RSpec.describe 'With original flow' do
before do
stub_experiment(signup_flow: false)
stub_experiment_for_user(signup_flow: false)
end
it_behaves_like 'Signup'
it_behaves_like 'Signup name validation', 'new_user_first_name', 127, 'First name'
it_behaves_like 'Signup name validation', 'new_user_last_name', 127, 'Last name'
end
RSpec.describe 'With experimental flow' do
before do
stub_experiment(signup_flow: true)
stub_experiment_for_user(signup_flow: true)
end
it_behaves_like 'Signup'
it_behaves_like 'Signup name validation', 'new_user_first_name', 127, 'First name'
it_behaves_like 'Signup name validation', 'new_user_last_name', 127, 'Last name'
end

View File

@ -5,7 +5,4 @@
<li>
<a href="#login-pane">Standard</a>
</li>
<li>
<a href="#register-pane">Register</a>
</li>
</ul>

View File

@ -7,7 +7,7 @@ export const notesDataMock = {
newSessionPath: '/users/sign_in?redirect_to_referer=yes',
notesPath: '/gitlab-org/gitlab-foss/noteable/issue/98/notes',
quickActionsDocsPath: '/help/user/project/quick_actions',
registerPath: '/users/sign_in?redirect_to_referer=yes#register-pane',
registerPath: '/users/sign_up?redirect_to_referer=yes',
prerenderedNotesCount: 1,
closePath: '/twitter/flight/issues/9.json?issue%5Bstate_event%5D=close',
reopenPath: '/twitter/flight/issues/9.json?issue%5Bstate_event%5D=reopen',

View File

@ -14,18 +14,16 @@ describe('preserve_url_fragment', () => {
loadFixtures('sessions/new.html');
});
it('adds the url fragment to all login and sign up form actions', () => {
it('adds the url fragment to the login form actions', () => {
preserveUrlFragment('#L65');
expect($('#new_user').attr('action')).toBe('http://test.host/users/sign_in#L65');
expect($('#new_new_user').attr('action')).toBe('http://test.host/users#L65');
});
it('does not add an empty url fragment to login and sign up form actions', () => {
it('does not add an empty url fragment to the login form actions', () => {
preserveUrlFragment();
expect($('#new_user').attr('action')).toBe('http://test.host/users/sign_in');
expect($('#new_new_user').attr('action')).toBe('http://test.host/users');
});
it('does not add an empty query parameter to OmniAuth login buttons', () => {

View File

@ -11,6 +11,14 @@ RSpec.describe Atlassian::JiraConnect::Client do
Timecop.freeze { example.run }
end
describe '.generate_update_sequence_id' do
it 'returns monotonic_time converted it to integer' do
allow(Gitlab::Metrics::System).to receive(:monotonic_time).and_return(1.0)
expect(described_class.generate_update_sequence_id).to eq(1)
end
end
describe '#store_dev_info' do
it "calls the API with auth headers" do
expected_jwt = Atlassian::Jwt.encode(

View File

@ -0,0 +1,28 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Atlassian::JiraConnect::Serializers::BaseEntity do
let(:update_sequence_id) { nil }
subject do
described_class.represent(
anything,
update_sequence_id: update_sequence_id
)
end
it 'generates the update_sequence_id' do
allow(Atlassian::JiraConnect::Client).to receive(:generate_update_sequence_id).and_return(1)
expect(subject.value_for(:updateSequenceId)).to eq(1)
end
context 'with update_sequence_id option' do
let(:update_sequence_id) { 123 }
it 'uses the custom update_sequence_id' do
expect(subject.value_for(:updateSequenceId)).to eq(123)
end
end
end

View File

@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Atlassian::JiraConnect::Serializers::RepositoryEntity do
let(:update_sequence_id) { nil }
subject do
project = create(:project, :repository)
commits = [project.commit]
@ -13,9 +15,23 @@ RSpec.describe Atlassian::JiraConnect::Serializers::RepositoryEntity do
project,
commits: commits,
branches: branches,
merge_requests: merge_requests
merge_requests: merge_requests,
update_sequence_id: update_sequence_id
).to_json
end
it { is_expected.to match_schema('jira_connect/repository') }
context 'with custom update_sequence_id' do
let(:update_sequence_id) { 1.0 }
it 'passes the update_sequence_id on to the nested entities', :aggregate_failures do
parsed_subject = Gitlab::Json.parse(subject)
expect(parsed_subject['updateSequenceId']).to eq(update_sequence_id)
expect(parsed_subject['commits'].first['updateSequenceId']).to eq(update_sequence_id)
expect(parsed_subject['branches'].first['updateSequenceId']).to eq(update_sequence_id)
expect(parsed_subject['pullRequests'].first['updateSequenceId']).to eq(update_sequence_id)
end
end
end

View File

@ -294,19 +294,22 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
create(:project, creator: user)
create(:clusters_applications_prometheus, :installed, cluster: cluster)
create(:project_tracing_setting)
create(:project_error_tracking_setting)
end
expect(described_class.usage_activity_by_stage_monitor({})).to include(
clusters: 2,
clusters_applications_prometheus: 2,
operations_dashboard_default_dashboard: 2,
projects_with_tracing_enabled: 2
projects_with_tracing_enabled: 2,
projects_with_error_tracking_enabled: 2
)
expect(described_class.usage_activity_by_stage_monitor(described_class.last_28_days_time_period)).to include(
clusters: 1,
clusters_applications_prometheus: 1,
operations_dashboard_default_dashboard: 1,
projects_with_tracing_enabled: 1
projects_with_tracing_enabled: 1,
projects_with_error_tracking_enabled: 1
)
end
end

View File

@ -23,7 +23,8 @@ RSpec.describe JiraConnect::SyncService do
project: project,
commits: commits,
branches: [instance_of(Gitlab::Git::Branch)],
merge_requests: merge_requests
merge_requests: merge_requests,
update_sequence_id: anything
).and_return(return_value)
end
end

View File

@ -8,6 +8,10 @@ module UserLoginHelper
ensure_one_active_pane
end
def ensure_no_tabs
expect(page.all('[role="tab"]').size).to eq(0)
end
def ensure_tab_labels(tab_names)
tab_labels = page.all('[role="tab"]').map(&:text)

View File

@ -4,7 +4,10 @@ require 'spec_helper'
RSpec.describe JiraConnect::SyncBranchWorker do
describe '#perform' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, :repository, group: group) }
let_it_be(:subscription) { create(:jira_connect_subscription, installation: create(:jira_connect_installation), namespace: group) }
let(:project_id) { project.id }
let(:branch_name) { 'master' }
let(:commit_shas) { %w(b83d6e3 5a62481) }
@ -13,7 +16,7 @@ RSpec.describe JiraConnect::SyncBranchWorker do
def expect_jira_sync_service_execute(args)
expect_next_instance_of(JiraConnect::SyncService) do |instance|
expect(instance).to receive(:execute).with(args)
expect(instance).to receive(:execute).with(args.merge(update_sequence_id: nil))
end
end
@ -61,5 +64,31 @@ RSpec.describe JiraConnect::SyncBranchWorker do
subject
end
end
context 'with update_sequence_id' do
let(:update_sequence_id) { 1 }
let(:request_url) { 'https://sample.atlassian.net/rest/devinfo/0.10/bulk' }
let(:request_body) do
{
repositories: [
Atlassian::JiraConnect::Serializers::RepositoryEntity.represent(
project,
commits: project.commits_by(oids: commit_shas),
branches: [project.repository.find_branch(branch_name)],
update_sequence_id: update_sequence_id
)
]
}.to_json
end
subject { described_class.new.perform(project_id, branch_name, commit_shas, update_sequence_id) }
it 'sends the reqeust with custom update_sequence_id' do
expect(Atlassian::JiraConnect::Client).to receive(:post)
.with(URI(request_url), headers: anything, body: request_body)
subject
end
end
end
end

View File

@ -4,14 +4,18 @@ require 'spec_helper'
RSpec.describe JiraConnect::SyncMergeRequestWorker do
describe '#perform' do
let(:merge_request) { create(:merge_request) }
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, :repository, group: group) }
let_it_be(:subscription) { create(:jira_connect_subscription, installation: create(:jira_connect_installation), namespace: group) }
let_it_be(:merge_request) { create(:merge_request, source_project: project) }
let(:merge_request_id) { merge_request.id }
subject { described_class.new.perform(merge_request_id) }
it 'calls JiraConnect::SyncService#execute' do
expect_next_instance_of(JiraConnect::SyncService) do |service|
expect(service).to receive(:execute).with(merge_requests: [merge_request])
expect(service).to receive(:execute).with(merge_requests: [merge_request], update_sequence_id: nil)
end
subject
@ -26,5 +30,30 @@ RSpec.describe JiraConnect::SyncMergeRequestWorker do
subject
end
end
context 'with update_sequence_id' do
let(:update_sequence_id) { 1 }
let(:request_url) { 'https://sample.atlassian.net/rest/devinfo/0.10/bulk' }
let(:request_body) do
{
repositories: [
Atlassian::JiraConnect::Serializers::RepositoryEntity.represent(
project,
merge_requests: [merge_request],
update_sequence_id: update_sequence_id
)
]
}.to_json
end
subject { described_class.new.perform(merge_request_id, update_sequence_id) }
it 'sends the request with custom update_sequence_id' do
expect(Atlassian::JiraConnect::Client).to receive(:post)
.with(URI(request_url), headers: anything, body: request_body)
subject
end
end
end
end