Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
185f428fa5
commit
31040b5bfe
58 changed files with 841 additions and 143 deletions
|
@ -203,6 +203,13 @@ Please view this file on the master branch, on stable branches it's out of date.
|
||||||
- Fixes style-lint errors and warnings for EE builds.scss file.
|
- Fixes style-lint errors and warnings for EE builds.scss file.
|
||||||
|
|
||||||
|
|
||||||
|
## 12.2.8
|
||||||
|
|
||||||
|
### Fixed (1 change)
|
||||||
|
|
||||||
|
- Geo: LFS not being synced. !17633
|
||||||
|
|
||||||
|
|
||||||
## 12.2.7
|
## 12.2.7
|
||||||
|
|
||||||
### Security (1 change)
|
### Security (1 change)
|
||||||
|
@ -471,6 +478,13 @@ Please view this file on the master branch, on stable branches it's out of date.
|
||||||
- Fix alignment of activity dropdown in epic tabs; add counter to discussion tab.
|
- Fix alignment of activity dropdown in epic tabs; add counter to discussion tab.
|
||||||
|
|
||||||
|
|
||||||
|
## 12.1.14
|
||||||
|
|
||||||
|
### Fixed (1 change)
|
||||||
|
|
||||||
|
- Geo: LFS not being synced. !17633
|
||||||
|
|
||||||
|
|
||||||
## 12.1.12
|
## 12.1.12
|
||||||
|
|
||||||
### Security (4 changes)
|
### Security (4 changes)
|
||||||
|
|
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -307,6 +307,13 @@ entry.
|
||||||
- Updates tooltip of 'detached' label/state.
|
- Updates tooltip of 'detached' label/state.
|
||||||
|
|
||||||
|
|
||||||
|
## 12.2.8
|
||||||
|
|
||||||
|
### Security (1 change)
|
||||||
|
|
||||||
|
- Limit search for IID to a type to avoid leaking records with the same IID that the user does not have access to.
|
||||||
|
|
||||||
|
|
||||||
## 12.2.7
|
## 12.2.7
|
||||||
|
|
||||||
### Security (1 change)
|
### Security (1 change)
|
||||||
|
@ -649,6 +656,13 @@ entry.
|
||||||
- Update Packer.gitlab-ci.yml to use latest image. (Kelly Hair)
|
- Update Packer.gitlab-ci.yml to use latest image. (Kelly Hair)
|
||||||
|
|
||||||
|
|
||||||
|
## 12.1.14
|
||||||
|
|
||||||
|
### Security (1 change)
|
||||||
|
|
||||||
|
- Limit search for IID to a type to avoid leaking records with the same IID that the user does not have access to.
|
||||||
|
|
||||||
|
|
||||||
## 12.1.12
|
## 12.1.12
|
||||||
|
|
||||||
### Security (12 changes)
|
### Security (12 changes)
|
||||||
|
|
|
@ -561,3 +561,6 @@ export const getDateInPast = (date, daysInPast) => {
|
||||||
dateClone.setTime(dateClone.getTime() - daysInPast * 24 * 60 * 60 * 1000),
|
dateClone.setTime(dateClone.getTime() - daysInPast * 24 * 60 * 60 * 1000),
|
||||||
).toISOString();
|
).toISOString();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const beginOfDayTime = 'T00:00:00Z';
|
||||||
|
export const endOfDayTime = 'T23:59:59Z';
|
||||||
|
|
9
app/assets/javascripts/pages/registrations/new/index.js
Normal file
9
app/assets/javascripts/pages/registrations/new/index.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import LengthValidator from '~/pages/sessions/new/length_validator';
|
||||||
|
import UsernameValidator from '~/pages/sessions/new/username_validator';
|
||||||
|
import NoEmojiValidator from '~/emoji/no_emoji_validator';
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
new UsernameValidator(); // eslint-disable-line no-new
|
||||||
|
new LengthValidator(); // eslint-disable-line no-new
|
||||||
|
new NoEmojiValidator(); // eslint-disable-line no-new
|
||||||
|
});
|
|
@ -0,0 +1,51 @@
|
||||||
|
.signup-page {
|
||||||
|
.page-wrap {
|
||||||
|
background-color: $gray-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gitlab-logo {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.signup-box-container {
|
||||||
|
max-width: 900px;
|
||||||
|
|
||||||
|
&.navless-container {
|
||||||
|
// overriding .devise-layout-html.navless-container to support the sticky footer
|
||||||
|
// without having a header on size xs
|
||||||
|
@include media-breakpoint-down(xs) {
|
||||||
|
padding: 65px $gl-padding; // height of footer
|
||||||
|
padding-top: $gl-padding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.signup-heading h2 {
|
||||||
|
font-weight: $gl-font-weight-bold;
|
||||||
|
|
||||||
|
@include media-breakpoint-down(md) {
|
||||||
|
font-size: $gl-font-size-large;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.signup-box {
|
||||||
|
background-color: $white-light;
|
||||||
|
box-shadow: 0 0 0 1px $border-color;
|
||||||
|
border-radius: $border-radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control {
|
||||||
|
&:active,
|
||||||
|
&:focus {
|
||||||
|
background-color: $white-light;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.devise-errors {
|
||||||
|
h2 {
|
||||||
|
font-size: $gl-font-size;
|
||||||
|
color: $red-700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -215,6 +215,12 @@
|
||||||
body {
|
body {
|
||||||
// offset height of fixed header + 1 to avoid scroll
|
// offset height of fixed header + 1 to avoid scroll
|
||||||
height: calc(100% - 51px);
|
height: calc(100% - 51px);
|
||||||
|
|
||||||
|
// offset without the header
|
||||||
|
&.navless {
|
||||||
|
height: calc(100% - 11px);
|
||||||
|
}
|
||||||
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
|
|
|
@ -5,23 +5,21 @@ class HealthController < ActionController::Base
|
||||||
include RequiresWhitelistedMonitoringClient
|
include RequiresWhitelistedMonitoringClient
|
||||||
|
|
||||||
def readiness
|
def readiness
|
||||||
results = checks.flat_map(&:readiness)
|
render_probe(::Gitlab::HealthChecks::Probes::Readiness)
|
||||||
success = results.all?(&:success)
|
|
||||||
|
|
||||||
# disable static error pages at the gitlab-workhorse level, we want to see this error response even in production
|
|
||||||
headers["X-GitLab-Custom-Error"] = 1 unless success
|
|
||||||
|
|
||||||
response = results.map { |result| [result.name, result.payload] }.to_h
|
|
||||||
render json: response, status: success ? :ok : :service_unavailable
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def liveness
|
def liveness
|
||||||
render json: { status: 'ok' }, status: :ok
|
render_probe(::Gitlab::HealthChecks::Probes::Liveness)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def checks
|
def render_probe(probe_class)
|
||||||
::Gitlab::HealthChecks::CHECKS
|
result = probe_class.new.execute
|
||||||
|
|
||||||
|
# disable static error pages at the gitlab-workhorse level, we want to see this error response even in production
|
||||||
|
headers["X-GitLab-Custom-Error"] = 1 unless result.success?
|
||||||
|
|
||||||
|
render json: result.json, status: result.http_status
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,13 +6,19 @@ class RegistrationsController < Devise::RegistrationsController
|
||||||
include RecaptchaExperimentHelper
|
include RecaptchaExperimentHelper
|
||||||
include InvisibleCaptcha
|
include InvisibleCaptcha
|
||||||
|
|
||||||
|
layout :choose_layout
|
||||||
|
|
||||||
prepend_before_action :check_captcha, only: :create
|
prepend_before_action :check_captcha, only: :create
|
||||||
before_action :whitelist_query_limiting, only: [:destroy]
|
before_action :whitelist_query_limiting, only: [:destroy]
|
||||||
before_action :ensure_terms_accepted,
|
before_action :ensure_terms_accepted,
|
||||||
if: -> { action_name == 'create' && Gitlab::CurrentSettings.current_application_settings.enforce_terms? }
|
if: -> { action_name == 'create' && Gitlab::CurrentSettings.current_application_settings.enforce_terms? }
|
||||||
|
|
||||||
def new
|
def new
|
||||||
redirect_to(new_user_session_path)
|
if helpers.use_experimental_separate_sign_up_flow?
|
||||||
|
@resource = build_resource
|
||||||
|
else
|
||||||
|
redirect_to new_user_session_path(anchor: 'register-pane')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
@ -144,6 +150,16 @@ class RegistrationsController < Devise::RegistrationsController
|
||||||
def stored_location_or_dashboard(user)
|
def stored_location_or_dashboard(user)
|
||||||
stored_location_for(user) || dashboard_projects_path
|
stored_location_for(user) || dashboard_projects_path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# 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 helpers.use_experimental_separate_sign_up_flow?
|
||||||
|
'devise_experimental_separate_sign_up_flow'
|
||||||
|
else
|
||||||
|
'devise'
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
RegistrationsController.prepend_if_ee('EE::RegistrationsController')
|
RegistrationsController.prepend_if_ee('EE::RegistrationsController')
|
||||||
|
|
|
@ -4,4 +4,8 @@ module SessionsHelper
|
||||||
def unconfirmed_email?
|
def unconfirmed_email?
|
||||||
flash[:alert] == t(:unconfirmed, scope: [:devise, :failure])
|
flash[:alert] == t(:unconfirmed, scope: [:devise, :failure])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def use_experimental_separate_sign_up_flow?
|
||||||
|
::Gitlab.dev_env_or_com? && Feature.enabled?(:experimental_separate_sign_up_flow)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
22
app/models/concerns/group_api_compatibility.rb
Normal file
22
app/models/concerns/group_api_compatibility.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Add methods used by the groups API
|
||||||
|
module GroupAPICompatibility
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
def project_creation_level_str
|
||||||
|
::Gitlab::Access.project_creation_string_options.key(project_creation_level)
|
||||||
|
end
|
||||||
|
|
||||||
|
def project_creation_level_str=(value)
|
||||||
|
write_attribute(:project_creation_level, ::Gitlab::Access.project_creation_string_options.fetch(value))
|
||||||
|
end
|
||||||
|
|
||||||
|
def subgroup_creation_level_str
|
||||||
|
::Gitlab::Access.subgroup_creation_string_options.key(subgroup_creation_level)
|
||||||
|
end
|
||||||
|
|
||||||
|
def subgroup_creation_level_str=(value)
|
||||||
|
write_attribute(:subgroup_creation_level, ::Gitlab::Access.subgroup_creation_string_options.fetch(value))
|
||||||
|
end
|
||||||
|
end
|
|
@ -14,6 +14,7 @@ class Group < Namespace
|
||||||
include TokenAuthenticatable
|
include TokenAuthenticatable
|
||||||
include WithUploads
|
include WithUploads
|
||||||
include Gitlab::Utils::StrongMemoize
|
include Gitlab::Utils::StrongMemoize
|
||||||
|
include GroupAPICompatibility
|
||||||
|
|
||||||
ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT = 10
|
ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT = 10
|
||||||
|
|
||||||
|
|
|
@ -256,7 +256,7 @@ class Namespace < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def has_parent?
|
def has_parent?
|
||||||
parent.present?
|
parent_id.present? || parent.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def root_ancestor
|
def root_ancestor
|
||||||
|
|
|
@ -5,7 +5,7 @@ module DataFields
|
||||||
|
|
||||||
class_methods do
|
class_methods do
|
||||||
# Provide convenient accessor methods for data fields.
|
# Provide convenient accessor methods for data fields.
|
||||||
# TODO: Simplify as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084
|
# TODO: Simplify as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
|
||||||
def data_field(*args)
|
def data_field(*args)
|
||||||
args.each do |arg|
|
args.each do |arg|
|
||||||
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
||||||
|
|
|
@ -4,7 +4,7 @@ class IssueTrackerService < Service
|
||||||
validate :one_issue_tracker, if: :activated?, on: :manual_change
|
validate :one_issue_tracker, if: :activated?, on: :manual_change
|
||||||
|
|
||||||
# TODO: we can probably just delegate as part of
|
# TODO: we can probably just delegate as part of
|
||||||
# https://gitlab.com/gitlab-org/gitlab-foss/issues/63084
|
# https://gitlab.com/gitlab-org/gitlab/issues/29404
|
||||||
data_field :project_url, :issues_url, :new_issue_url
|
data_field :project_url, :issues_url, :new_issue_url
|
||||||
|
|
||||||
default_value_for :category, 'issue_tracker'
|
default_value_for :category, 'issue_tracker'
|
||||||
|
@ -25,7 +25,7 @@ class IssueTrackerService < Service
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084
|
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
|
||||||
def title
|
def title
|
||||||
if title_attribute = read_attribute(:title)
|
if title_attribute = read_attribute(:title)
|
||||||
title_attribute
|
title_attribute
|
||||||
|
@ -36,7 +36,7 @@ class IssueTrackerService < Service
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084
|
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
|
||||||
def description
|
def description
|
||||||
if description_attribute = read_attribute(:description)
|
if description_attribute = read_attribute(:description)
|
||||||
description_attribute
|
description_attribute
|
||||||
|
@ -49,7 +49,7 @@ class IssueTrackerService < Service
|
||||||
|
|
||||||
def handle_properties
|
def handle_properties
|
||||||
# this has been moved from initialize_properties and should be improved
|
# this has been moved from initialize_properties and should be improved
|
||||||
# as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084
|
# as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
|
||||||
return unless properties
|
return unless properties
|
||||||
|
|
||||||
@legacy_properties_data = properties.dup
|
@legacy_properties_data = properties.dup
|
||||||
|
|
|
@ -19,7 +19,7 @@ class JiraService < IssueTrackerService
|
||||||
# for more information check: https://gitlab.com/gitlab-org/gitlab-foss/issues/49936.
|
# for more information check: https://gitlab.com/gitlab-org/gitlab-foss/issues/49936.
|
||||||
|
|
||||||
# TODO: we can probably just delegate as part of
|
# TODO: we can probably just delegate as part of
|
||||||
# https://gitlab.com/gitlab-org/gitlab-foss/issues/63084
|
# https://gitlab.com/gitlab-org/gitlab/issues/29404
|
||||||
data_field :username, :password, :url, :api_url, :jira_issue_transition_id
|
data_field :username, :password, :url, :api_url, :jira_issue_transition_id
|
||||||
|
|
||||||
before_update :reset_password
|
before_update :reset_password
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
in running SQL queries. These settings require a
|
in running SQL queries. These settings require a
|
||||||
= link_to 'restart', help_page_path('administration/restart_gitlab')
|
= link_to 'restart', help_page_path('administration/restart_gitlab')
|
||||||
to take effect.
|
to take effect.
|
||||||
= link_to icon('question-circle'), help_page_path('administration/monitoring/performance/introduction')
|
= link_to icon('question-circle'), help_page_path('administration/monitoring/performance/index')
|
||||||
.form-group
|
.form-group
|
||||||
.form-check
|
.form-check
|
||||||
= f.check_box :metrics_enabled, class: 'form-check-input'
|
= f.check_box :metrics_enabled, class: 'form-check-input'
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
- page_title "Sign up"
|
- page_title "Sign up"
|
||||||
= render 'devise/shared/signup_box'
|
- if use_experimental_separate_sign_up_flow?
|
||||||
|
= render 'devise/shared/experimental_separate_sign_up_flow_box'
|
||||||
|
- else
|
||||||
|
= render 'devise/shared/signup_box'
|
||||||
|
|
||||||
= render 'devise/shared/sign_in_link'
|
= render 'devise/shared/sign_in_link'
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
- if form_based_providers.any?
|
- if form_based_providers.any?
|
||||||
= render 'devise/shared/tabs_ldap'
|
= render 'devise/shared/tabs_ldap'
|
||||||
- else
|
- else
|
||||||
= render 'devise/shared/tabs_normal'
|
- unless use_experimental_separate_sign_up_flow?
|
||||||
|
= render 'devise/shared/tabs_normal'
|
||||||
.tab-content
|
.tab-content
|
||||||
- if password_authentication_enabled_for_web? || ldap_enabled? || crowd_enabled?
|
- if password_authentication_enabled_for_web? || ldap_enabled? || crowd_enabled?
|
||||||
= render 'devise/shared/signin_box'
|
= render 'devise/shared/signin_box'
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
- max_name_length = 128
|
||||||
|
- max_username_length = 255
|
||||||
|
.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
|
||||||
|
= invisible_captcha
|
||||||
|
.name.form-group
|
||||||
|
= f.label :name, _('Full name'), class: 'label-bold'
|
||||||
|
= f.text_field :name, class: "form-control top js-block-emoji js-validate-length", :data => { :max_length => max_name_length, :max_length_message => s_("SignUp|Name is too long (maximum is %{max_length} characters).") % { max_length: max_name_length }, :qa_selector => 'new_user_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 => { :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.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 }
|
||||||
|
- if Gitlab::CurrentSettings.current_application_settings.enforce_terms?
|
||||||
|
.form-group
|
||||||
|
= check_box_tag :terms_opt_in, '1', false, required: true, data: { qa_selector: 'new_user_accept_terms_checkbox' }
|
||||||
|
= label_tag :terms_opt_in do
|
||||||
|
- terms_link = link_to s_("I accept the|Terms of Service and Privacy Policy"), terms_path, target: "_blank"
|
||||||
|
- accept_terms_label = _("I accept the %{terms_link}") % { terms_link: terms_link }
|
||||||
|
= accept_terms_label.html_safe
|
||||||
|
= render_if_exists 'devise/shared/email_opted_in', f: f
|
||||||
|
.submit-container.mt-3
|
||||||
|
= f.submit _("Register"), class: "btn-register btn btn-block btn-success mb-0 p-2", data: { qa_selector: 'new_user_register_button' }
|
|
@ -1,4 +1,4 @@
|
||||||
%p
|
%p.text-center
|
||||||
%span.light
|
%span.light
|
||||||
Already have login and password?
|
Already have login and password?
|
||||||
= link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes')
|
= link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes')
|
||||||
|
|
|
@ -22,3 +22,8 @@
|
||||||
.login-box.tab-pane.active{ id: 'login-pane', role: 'tabpanel' }
|
.login-box.tab-pane.active{ id: 'login-pane', role: 'tabpanel' }
|
||||||
.login-body
|
.login-body
|
||||||
= render 'devise/sessions/new_base'
|
= render 'devise/sessions/new_base'
|
||||||
|
|
||||||
|
- if use_experimental_separate_sign_up_flow?
|
||||||
|
%p.light.mt-2
|
||||||
|
= _("Don't have an account yet?")
|
||||||
|
= link_to _("Register now"), new_registration_path(:user)
|
||||||
|
|
|
@ -1,5 +1,17 @@
|
||||||
- page_description brand_title unless page_description
|
- page_description brand_title unless page_description
|
||||||
|
|
||||||
|
-# Needs a redirect on the client side since it's using an anchor to distuingish
|
||||||
|
-# 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 use_experimental_separate_sign_up_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"
|
- site_name = "GitLab"
|
||||||
%head{ prefix: "og: http://ogp.me/ns#" }
|
%head{ prefix: "og: http://ogp.me/ns#" }
|
||||||
%meta{ charset: "utf-8" }
|
%meta{ charset: "utf-8" }
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
!!! 5
|
||||||
|
%html.devise-layout-html.navless{ class: system_message_class }
|
||||||
|
= render "layouts/head"
|
||||||
|
%body.ui-indigo.signup-page.application.navless{ class: "#{client_class_list}", data: { page: body_data_page, qa_selector: 'signup_page' } }
|
||||||
|
= header_message
|
||||||
|
= render "layouts/init_client_detection_flags"
|
||||||
|
.page-wrap
|
||||||
|
.container.signup-box-container.navless-container.mt-0
|
||||||
|
= render "layouts/broadcast"
|
||||||
|
.content
|
||||||
|
= render "layouts/flash"
|
||||||
|
.row.mb-3
|
||||||
|
.col-sm-8.offset-sm-2.col-md-6.offset-md-3.new-session-forms-container
|
||||||
|
= render_if_exists 'layouts/devise_help_text'
|
||||||
|
.text-center.signup-heading.mt-3.mb-3
|
||||||
|
= image_tag(image_url('logo.svg'), class: 'gitlab-logo', alt: 'GitLab Logo')
|
||||||
|
%h2= _('Register for GitLab.com')
|
||||||
|
= yield
|
||||||
|
%hr.footer-fixed
|
||||||
|
.footer-container
|
||||||
|
.container
|
||||||
|
.footer-links
|
||||||
|
= link_to _("Help"), help_path
|
||||||
|
= link_to _("About GitLab"), "https://about.gitlab.com/"
|
||||||
|
= footer_message
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Experimental separate sign up flow
|
||||||
|
merge_request: 16482
|
||||||
|
author:
|
||||||
|
type: other
|
5
changelogs/unreleased/add-health-checks-exporter.yml
Normal file
5
changelogs/unreleased/add-health-checks-exporter.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Export liveness and readiness probes
|
||||||
|
merge_request:
|
||||||
|
author:
|
||||||
|
type: changed
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Fix moved help URL for monitoring performance
|
||||||
|
merge_request:
|
||||||
|
author:
|
||||||
|
type: fixed
|
5
changelogs/unreleased/groups_api.yml
Normal file
5
changelogs/unreleased/groups_api.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: 'API: Add missing group parameters'
|
||||||
|
merge_request: 17220
|
||||||
|
author: Mathieu Parent
|
||||||
|
type: added
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
title: Limit search for IID to a type to avoid leaking records with the same IID that
|
||||||
|
the user does not have access to
|
||||||
|
merge_request:
|
||||||
|
author:
|
||||||
|
type: security
|
|
@ -31,6 +31,13 @@ GET /groups
|
||||||
"path": "foo-bar",
|
"path": "foo-bar",
|
||||||
"description": "An interesting group",
|
"description": "An interesting group",
|
||||||
"visibility": "public",
|
"visibility": "public",
|
||||||
|
"share_with_group_lock": false,
|
||||||
|
"require_two_factor_authentication": false,
|
||||||
|
"two_factor_grace_period": 48,
|
||||||
|
"project_creation_level": "developer",
|
||||||
|
"auto_devops_enabled": null,
|
||||||
|
"subgroup_creation_level": "owner",
|
||||||
|
"emails_disabled": null,
|
||||||
"lfs_enabled": true,
|
"lfs_enabled": true,
|
||||||
"avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg",
|
"avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg",
|
||||||
"web_url": "http://localhost:3000/groups/foo-bar",
|
"web_url": "http://localhost:3000/groups/foo-bar",
|
||||||
|
@ -57,6 +64,13 @@ GET /groups?statistics=true
|
||||||
"path": "foo-bar",
|
"path": "foo-bar",
|
||||||
"description": "An interesting group",
|
"description": "An interesting group",
|
||||||
"visibility": "public",
|
"visibility": "public",
|
||||||
|
"share_with_group_lock": false,
|
||||||
|
"require_two_factor_authentication": false,
|
||||||
|
"two_factor_grace_period": 48,
|
||||||
|
"project_creation_level": "developer",
|
||||||
|
"auto_devops_enabled": null,
|
||||||
|
"subgroup_creation_level": "owner",
|
||||||
|
"emails_disabled": null,
|
||||||
"lfs_enabled": true,
|
"lfs_enabled": true,
|
||||||
"avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg",
|
"avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg",
|
||||||
"web_url": "http://localhost:3000/groups/foo-bar",
|
"web_url": "http://localhost:3000/groups/foo-bar",
|
||||||
|
@ -119,6 +133,13 @@ GET /groups/:id/subgroups
|
||||||
"path": "foo-bar",
|
"path": "foo-bar",
|
||||||
"description": "An interesting group",
|
"description": "An interesting group",
|
||||||
"visibility": "public",
|
"visibility": "public",
|
||||||
|
"share_with_group_lock": false,
|
||||||
|
"require_two_factor_authentication": false,
|
||||||
|
"two_factor_grace_period": 48,
|
||||||
|
"project_creation_level": "developer",
|
||||||
|
"auto_devops_enabled": null,
|
||||||
|
"subgroup_creation_level": "owner",
|
||||||
|
"emails_disabled": null,
|
||||||
"lfs_enabled": true,
|
"lfs_enabled": true,
|
||||||
"avatar_url": "http://gitlab.example.com/uploads/group/avatar/1/foo.jpg",
|
"avatar_url": "http://gitlab.example.com/uploads/group/avatar/1/foo.jpg",
|
||||||
"web_url": "http://gitlab.example.com/groups/foo-bar",
|
"web_url": "http://gitlab.example.com/groups/foo-bar",
|
||||||
|
@ -434,6 +455,13 @@ Parameters:
|
||||||
| `path` | string | yes | The path of the group. |
|
| `path` | string | yes | The path of the group. |
|
||||||
| `description` | string | no | The group's description. |
|
| `description` | string | no | The group's description. |
|
||||||
| `visibility` | string | no | The group's visibility. Can be `private`, `internal`, or `public`. |
|
| `visibility` | string | no | The group's visibility. Can be `private`, `internal`, or `public`. |
|
||||||
|
| `share_with_group_lock` | boolean | no | Prevent sharing a project with another group within this group. |
|
||||||
|
| `require_two_factor_authentication` | boolean | no | Require all users in this group to setup Two-factor authentication. |
|
||||||
|
| `two_factor_grace_period` | integer | no | Time before Two-factor authentication is enforced (in hours). |
|
||||||
|
| `project_creation_level` | string | no | Determine if developers can create projects in the group. Can be `noone` (No one), `maintainer` (Maintainers), or `developer` (Developers + Maintainers). |
|
||||||
|
| `auto_devops_enabled` | boolean | no | Default to Auto DevOps pipeline for all projects within this group. |
|
||||||
|
| `subgroup_creation_level` | integer | no | Allowed to create subgroups. Can be `owner` (Owners), or `maintainer` (Maintainers). |
|
||||||
|
| `emails_disabled` | boolean | no | Disable email notifications |
|
||||||
| `lfs_enabled` | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group. |
|
| `lfs_enabled` | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group. |
|
||||||
| `request_access_enabled` | boolean | no | Allow users to request member access. |
|
| `request_access_enabled` | boolean | no | Allow users to request member access. |
|
||||||
| `parent_id` | integer | no | The parent group ID for creating nested group. |
|
| `parent_id` | integer | no | The parent group ID for creating nested group. |
|
||||||
|
@ -472,6 +500,13 @@ PUT /groups/:id
|
||||||
| `membership_lock` | boolean | no | **(STARTER)** Prevent adding new members to project membership within this group. |
|
| `membership_lock` | boolean | no | **(STARTER)** Prevent adding new members to project membership within this group. |
|
||||||
| `share_with_group_lock` | boolean | no | Prevent sharing a project with another group within this group. |
|
| `share_with_group_lock` | boolean | no | Prevent sharing a project with another group within this group. |
|
||||||
| `visibility` | string | no | The visibility level of the group. Can be `private`, `internal`, or `public`. |
|
| `visibility` | string | no | The visibility level of the group. Can be `private`, `internal`, or `public`. |
|
||||||
|
| `share_with_group_lock` | boolean | no | Prevent sharing a project with another group within this group. |
|
||||||
|
| `require_two_factor_authentication` | boolean | no | Require all users in this group to setup Two-factor authentication. |
|
||||||
|
| `two_factor_grace_period` | integer | no | Time before Two-factor authentication is enforced (in hours). |
|
||||||
|
| `project_creation_level` | string | no | Determine if developers can create projects in the group. Can be `noone` (No one), `maintainer` (Maintainers), or `developer` (Developers + Maintainers). |
|
||||||
|
| `auto_devops_enabled` | boolean | no | Default to Auto DevOps pipeline for all projects within this group. |
|
||||||
|
| `subgroup_creation_level` | integer | no | Allowed to create subgroups. Can be `owner` (Owners), or `maintainer` (Maintainers). |
|
||||||
|
| `emails_disabled` | boolean | no | Disable email notifications |
|
||||||
| `lfs_enabled` (optional) | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group. |
|
| `lfs_enabled` (optional) | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group. |
|
||||||
| `request_access_enabled` | boolean | no | Allow users to request member access. |
|
| `request_access_enabled` | boolean | no | Allow users to request member access. |
|
||||||
| `file_template_project_id` | integer | no | **(PREMIUM)** The ID of a project to load custom file templates from. |
|
| `file_template_project_id` | integer | no | **(PREMIUM)** The ID of a project to load custom file templates from. |
|
||||||
|
|
|
@ -378,6 +378,13 @@ module API
|
||||||
|
|
||||||
class Group < BasicGroupDetails
|
class Group < BasicGroupDetails
|
||||||
expose :path, :description, :visibility
|
expose :path, :description, :visibility
|
||||||
|
expose :share_with_group_lock
|
||||||
|
expose :require_two_factor_authentication
|
||||||
|
expose :two_factor_grace_period
|
||||||
|
expose :project_creation_level_str, as: :project_creation_level
|
||||||
|
expose :auto_devops_enabled
|
||||||
|
expose :subgroup_creation_level_str, as: :subgroup_creation_level
|
||||||
|
expose :emails_disabled
|
||||||
expose :lfs_enabled?, as: :lfs_enabled
|
expose :lfs_enabled?, as: :lfs_enabled
|
||||||
expose :avatar_url do |group, options|
|
expose :avatar_url do |group, options|
|
||||||
group.avatar_url(only_path: false)
|
group.avatar_url(only_path: false)
|
||||||
|
|
|
@ -11,9 +11,15 @@ module API
|
||||||
optional :visibility, type: String,
|
optional :visibility, type: String,
|
||||||
values: Gitlab::VisibilityLevel.string_values,
|
values: Gitlab::VisibilityLevel.string_values,
|
||||||
desc: 'The visibility of the group'
|
desc: 'The visibility of the group'
|
||||||
|
optional :share_with_group_lock, type: Boolean, desc: 'Prevent sharing a project with another group within this group'
|
||||||
|
optional :require_two_factor_authentication, type: Boolean, desc: 'Require all users in this group to setup Two-factor authentication'
|
||||||
|
optional :two_factor_grace_period, type: Integer, desc: 'Time before Two-factor authentication is enforced'
|
||||||
|
optional :project_creation_level, type: String, values: ::Gitlab::Access.project_creation_string_values, desc: 'Determine if developers can create projects in the group', as: :project_creation_level_str
|
||||||
|
optional :auto_devops_enabled, type: Boolean, desc: 'Default to Auto DevOps pipeline for all projects within this group'
|
||||||
|
optional :subgroup_creation_level, type: String, values: ::Gitlab::Access.subgroup_creation_string_values, desc: 'Allowed to create subgroups', as: :subgroup_creation_level_str
|
||||||
|
optional :emails_disabled, type: Boolean, desc: 'Disable email notifications'
|
||||||
optional :lfs_enabled, type: Boolean, desc: 'Enable/disable LFS for the projects in this group'
|
optional :lfs_enabled, type: Boolean, desc: 'Enable/disable LFS for the projects in this group'
|
||||||
optional :request_access_enabled, type: Boolean, desc: 'Allow users to request member access'
|
optional :request_access_enabled, type: Boolean, desc: 'Allow users to request member access'
|
||||||
optional :share_with_group_lock, type: Boolean, desc: 'Prevent sharing a project with another group within this group'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
params :optional_params_ee do
|
params :optional_params_ee do
|
||||||
|
|
|
@ -103,10 +103,22 @@ module Gitlab
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def project_creation_string_options
|
||||||
|
{
|
||||||
|
'noone' => NO_ONE_PROJECT_ACCESS,
|
||||||
|
'maintainer' => MAINTAINER_PROJECT_ACCESS,
|
||||||
|
'developer' => DEVELOPER_MAINTAINER_PROJECT_ACCESS
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
def project_creation_values
|
def project_creation_values
|
||||||
project_creation_options.values
|
project_creation_options.values
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def project_creation_string_values
|
||||||
|
project_creation_string_options.keys
|
||||||
|
end
|
||||||
|
|
||||||
def project_creation_level_name(name)
|
def project_creation_level_name(name)
|
||||||
project_creation_options.key(name)
|
project_creation_options.key(name)
|
||||||
end
|
end
|
||||||
|
@ -117,6 +129,21 @@ module Gitlab
|
||||||
s_('SubgroupCreationlevel|Maintainers') => MAINTAINER_SUBGROUP_ACCESS
|
s_('SubgroupCreationlevel|Maintainers') => MAINTAINER_SUBGROUP_ACCESS
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def subgroup_creation_string_options
|
||||||
|
{
|
||||||
|
'owner' => OWNER_SUBGROUP_ACCESS,
|
||||||
|
'maintainer' => MAINTAINER_SUBGROUP_ACCESS
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def subgroup_creation_values
|
||||||
|
subgroup_creation_options.values
|
||||||
|
end
|
||||||
|
|
||||||
|
def subgroup_creation_string_values
|
||||||
|
subgroup_creation_string_options.keys
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def human_access
|
def human_access
|
||||||
|
|
13
lib/gitlab/health_checks/probes/liveness.rb
Normal file
13
lib/gitlab/health_checks/probes/liveness.rb
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Gitlab
|
||||||
|
module HealthChecks
|
||||||
|
module Probes
|
||||||
|
class Liveness
|
||||||
|
def execute
|
||||||
|
Probes::Status.new(200, status: 'ok')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
53
lib/gitlab/health_checks/probes/readiness.rb
Normal file
53
lib/gitlab/health_checks/probes/readiness.rb
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Gitlab
|
||||||
|
module HealthChecks
|
||||||
|
module Probes
|
||||||
|
class Readiness
|
||||||
|
attr_reader :checks
|
||||||
|
|
||||||
|
# This accepts an array of Proc
|
||||||
|
# that returns `::Gitlab::HealthChecks::Result`
|
||||||
|
def initialize(*additional_checks)
|
||||||
|
@checks = ::Gitlab::HealthChecks::CHECKS.map { |check| check.method(:readiness) }
|
||||||
|
@checks += additional_checks
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
readiness = probe_readiness
|
||||||
|
success = all_succeeded?(readiness)
|
||||||
|
|
||||||
|
Probes::Status.new(
|
||||||
|
success ? 200 : 503,
|
||||||
|
status(success).merge(payload(readiness))
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def all_succeeded?(readiness)
|
||||||
|
readiness.all? do |name, probes|
|
||||||
|
probes.any?(&:success)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def status(success)
|
||||||
|
{ status: success ? 'ok' : 'failed' }
|
||||||
|
end
|
||||||
|
|
||||||
|
def payload(readiness)
|
||||||
|
readiness.transform_values do |probes|
|
||||||
|
probes.map(&:payload)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def probe_readiness
|
||||||
|
checks
|
||||||
|
.flat_map(&:call)
|
||||||
|
.compact
|
||||||
|
.group_by(&:name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
14
lib/gitlab/health_checks/probes/status.rb
Normal file
14
lib/gitlab/health_checks/probes/status.rb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Gitlab
|
||||||
|
module HealthChecks
|
||||||
|
module Probes
|
||||||
|
Status = Struct.new(:http_status, :json) do
|
||||||
|
# We accept 2xx
|
||||||
|
def success?
|
||||||
|
http_status / 100 == 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -31,7 +31,15 @@ module Gitlab
|
||||||
@server = ::WEBrick::HTTPServer.new(
|
@server = ::WEBrick::HTTPServer.new(
|
||||||
Port: settings.port, BindAddress: settings.address,
|
Port: settings.port, BindAddress: settings.address,
|
||||||
Logger: logger, AccessLog: access_log)
|
Logger: logger, AccessLog: access_log)
|
||||||
server.mount "/", Rack::Handler::WEBrick, rack_app
|
server.mount_proc '/readiness' do |req, res|
|
||||||
|
render_probe(
|
||||||
|
::Gitlab::HealthChecks::Probes::Readiness.new, req, res)
|
||||||
|
end
|
||||||
|
server.mount_proc '/liveness' do |req, res|
|
||||||
|
render_probe(
|
||||||
|
::Gitlab::HealthChecks::Probes::Liveness.new, req, res)
|
||||||
|
end
|
||||||
|
server.mount '/', Rack::Handler::WEBrick, rack_app
|
||||||
server.start
|
server.start
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -51,6 +59,14 @@ module Gitlab
|
||||||
run -> (env) { [404, {}, ['']] }
|
run -> (env) { [404, {}, ['']] }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def render_probe(probe, req, res)
|
||||||
|
result = probe.execute
|
||||||
|
|
||||||
|
res.status = result.http_status
|
||||||
|
res.content_type = 'application/json; charset=utf-8'
|
||||||
|
res.body = result.json.to_json
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5472,6 +5472,9 @@ msgstr ""
|
||||||
msgid "Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled"
|
msgid "Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Don't have an account yet?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Don't paste the private part of the GPG key. Paste the public part which begins with '-----BEGIN PGP PUBLIC KEY BLOCK-----'."
|
msgid "Don't paste the private part of the GPG key. Paste the public part which begins with '-----BEGIN PGP PUBLIC KEY BLOCK-----'."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -13081,6 +13084,12 @@ msgstr ""
|
||||||
msgid "Register and see your runners for this project."
|
msgid "Register and see your runners for this project."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Register for GitLab.com"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Register now"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Register with two-factor app"
|
msgid "Register with two-factor app"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
2
qa/qa.rb
2
qa/qa.rb
|
@ -259,6 +259,7 @@ module QA
|
||||||
module Milestone
|
module Milestone
|
||||||
autoload :New, 'qa/page/project/milestone/new'
|
autoload :New, 'qa/page/project/milestone/new'
|
||||||
autoload :Index, 'qa/page/project/milestone/index'
|
autoload :Index, 'qa/page/project/milestone/index'
|
||||||
|
autoload :Show, 'qa/page/project/milestone/show'
|
||||||
end
|
end
|
||||||
|
|
||||||
module Operations
|
module Operations
|
||||||
|
@ -449,6 +450,7 @@ module QA
|
||||||
autoload :Logging, 'qa/support/page/logging'
|
autoload :Logging, 'qa/support/page/logging'
|
||||||
end
|
end
|
||||||
autoload :Api, 'qa/support/api'
|
autoload :Api, 'qa/support/api'
|
||||||
|
autoload :Dates, 'qa/support/dates'
|
||||||
autoload :Waiter, 'qa/support/waiter'
|
autoload :Waiter, 'qa/support/waiter'
|
||||||
autoload :Retrier, 'qa/support/retrier'
|
autoload :Retrier, 'qa/support/retrier'
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,5 +17,3 @@ module QA
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
QA::Page::Project::Milestone::Index.prepend_if_ee('QA::EE::Page::Project::Milestone::Index')
|
|
||||||
|
|
14
qa/qa/page/project/milestone/show.rb
Normal file
14
qa/qa/page/project/milestone/show.rb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module QA
|
||||||
|
module Page
|
||||||
|
module Project
|
||||||
|
module Milestone
|
||||||
|
class Show < Page::Base
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
QA::Page::Project::Milestone::Show.prepend_if_ee('QA::EE::Page::Project::Milestone::Show')
|
21
qa/qa/support/dates.rb
Normal file
21
qa/qa/support/dates.rb
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module QA
|
||||||
|
module Support
|
||||||
|
module Dates
|
||||||
|
def current_date_yyyy_mm_dd
|
||||||
|
current_date.strftime("%Y/%m/%d")
|
||||||
|
end
|
||||||
|
|
||||||
|
def next_month_yyyy_mm_dd
|
||||||
|
current_date.next_month.strftime("%Y/%m/%d")
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def current_date
|
||||||
|
DateTime.now
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -24,11 +24,12 @@ describe HealthController do
|
||||||
it 'responds with readiness checks data' do
|
it 'responds with readiness checks data' do
|
||||||
subject
|
subject
|
||||||
|
|
||||||
expect(json_response['db_check']['status']).to eq('ok')
|
expect(json_response['db_check']).to contain_exactly({ 'status' => 'ok' })
|
||||||
expect(json_response['cache_check']['status']).to eq('ok')
|
expect(json_response['cache_check']).to contain_exactly({ 'status' => 'ok' })
|
||||||
expect(json_response['queues_check']['status']).to eq('ok')
|
expect(json_response['queues_check']).to contain_exactly({ 'status' => 'ok' })
|
||||||
expect(json_response['shared_state_check']['status']).to eq('ok')
|
expect(json_response['shared_state_check']).to contain_exactly({ 'status' => 'ok' })
|
||||||
expect(json_response['gitaly_check']['status']).to eq('ok')
|
expect(json_response['gitaly_check']).to contain_exactly(
|
||||||
|
{ 'status' => 'ok', 'labels' => { 'shard' => 'default' } })
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'responds with readiness checks data when a failure happens' do
|
it 'responds with readiness checks data when a failure happens' do
|
||||||
|
@ -37,9 +38,9 @@ describe HealthController do
|
||||||
|
|
||||||
subject
|
subject
|
||||||
|
|
||||||
expect(json_response['redis_check']['status']).to eq('failed')
|
expect(json_response['cache_check']).to contain_exactly({ 'status' => 'ok' })
|
||||||
expect(json_response['redis_check']['message']).to eq('check error')
|
expect(json_response['redis_check']).to contain_exactly(
|
||||||
expect(json_response['cache_check']['status']).to eq('ok')
|
{ 'status' => 'failed', 'message' => 'check error' })
|
||||||
|
|
||||||
expect(response.status).to eq(503)
|
expect(response.status).to eq(503)
|
||||||
expect(response.headers['X-GitLab-Custom-Error']).to eq(1)
|
expect(response.headers['X-GitLab-Custom-Error']).to eq(1)
|
||||||
|
@ -90,7 +91,7 @@ describe HealthController do
|
||||||
it 'responds with liveness checks data' do
|
it 'responds with liveness checks data' do
|
||||||
subject
|
subject
|
||||||
|
|
||||||
expect(json_response['status']).to eq('ok')
|
expect(json_response).to eq('status' => 'ok')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe 'Signup' do
|
shared_examples 'Signup' do
|
||||||
include TermsHelper
|
include TermsHelper
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
@ -13,8 +13,7 @@ describe 'Signup' do
|
||||||
|
|
||||||
describe 'username validation', :js do
|
describe 'username validation', :js do
|
||||||
before do
|
before do
|
||||||
visit root_path
|
visit new_user_registration_path
|
||||||
click_link 'Register'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not show an error border if the username is available' do
|
it 'does not show an error border if the username is available' do
|
||||||
|
@ -130,8 +129,7 @@ describe 'Signup' do
|
||||||
|
|
||||||
describe 'user\'s full name validation', :js do
|
describe 'user\'s full name validation', :js do
|
||||||
before do
|
before do
|
||||||
visit root_path
|
visit new_user_registration_path
|
||||||
click_link 'Register'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not show an error border if the user\'s fullname length is not longer than 128 characters' do
|
it 'does not show an error border if the user\'s fullname length is not longer than 128 characters' do
|
||||||
|
@ -177,13 +175,17 @@ describe 'Signup' do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates the user account and sends a confirmation email' do
|
it 'creates the user account and sends a confirmation email' do
|
||||||
visit root_path
|
visit new_user_registration_path
|
||||||
|
|
||||||
fill_in 'new_user_name', with: new_user.name
|
fill_in 'new_user_name', with: new_user.name
|
||||||
fill_in 'new_user_username', with: new_user.username
|
fill_in 'new_user_username', with: new_user.username
|
||||||
fill_in 'new_user_email', with: new_user.email
|
fill_in 'new_user_email', with: new_user.email
|
||||||
fill_in 'new_user_email_confirmation', with: new_user.email
|
|
||||||
fill_in 'new_user_password', with: new_user.password
|
unless Feature.enabled?(:experimental_separate_sign_up_flow)
|
||||||
|
fill_in 'new_user_email_confirmation', with: new_user.email
|
||||||
|
end
|
||||||
|
|
||||||
|
fill_in 'new_user_password', with: new_user.password
|
||||||
|
|
||||||
expect { click_button 'Register' }.to change { User.count }.by(1)
|
expect { click_button 'Register' }.to change { User.count }.by(1)
|
||||||
|
|
||||||
|
@ -198,13 +200,17 @@ describe 'Signup' do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates the user account and sends a confirmation email' do
|
it 'creates the user account and sends a confirmation email' do
|
||||||
visit root_path
|
visit new_user_registration_path
|
||||||
|
|
||||||
fill_in 'new_user_name', with: new_user.name
|
fill_in 'new_user_name', with: new_user.name
|
||||||
fill_in 'new_user_username', with: new_user.username
|
fill_in 'new_user_username', with: new_user.username
|
||||||
fill_in 'new_user_email', with: new_user.email
|
fill_in 'new_user_email', with: new_user.email
|
||||||
fill_in 'new_user_email_confirmation', with: new_user.email
|
|
||||||
fill_in 'new_user_password', with: new_user.password
|
unless Feature.enabled?(:experimental_separate_sign_up_flow)
|
||||||
|
fill_in 'new_user_email_confirmation', with: new_user.email
|
||||||
|
end
|
||||||
|
|
||||||
|
fill_in 'new_user_password', with: new_user.password
|
||||||
|
|
||||||
expect { click_button 'Register' }.to change { User.count }.by(1)
|
expect { click_button 'Register' }.to change { User.count }.by(1)
|
||||||
|
|
||||||
|
@ -216,13 +222,17 @@ describe 'Signup' do
|
||||||
|
|
||||||
context "when sigining up with different cased emails" do
|
context "when sigining up with different cased emails" do
|
||||||
it "creates the user successfully" do
|
it "creates the user successfully" do
|
||||||
visit root_path
|
visit new_user_registration_path
|
||||||
|
|
||||||
fill_in 'new_user_name', with: new_user.name
|
fill_in 'new_user_name', with: new_user.name
|
||||||
fill_in 'new_user_username', with: new_user.username
|
fill_in 'new_user_username', with: new_user.username
|
||||||
fill_in 'new_user_email', with: new_user.email
|
fill_in 'new_user_email', with: new_user.email
|
||||||
fill_in 'new_user_email_confirmation', with: new_user.email.capitalize
|
|
||||||
fill_in 'new_user_password', with: new_user.password
|
unless Feature.enabled?(:experimental_separate_sign_up_flow)
|
||||||
|
fill_in 'new_user_email_confirmation', with: new_user.email.capitalize
|
||||||
|
end
|
||||||
|
|
||||||
|
fill_in 'new_user_password', with: new_user.password
|
||||||
click_button "Register"
|
click_button "Register"
|
||||||
|
|
||||||
expect(current_path).to eq dashboard_projects_path
|
expect(current_path).to eq dashboard_projects_path
|
||||||
|
@ -236,13 +246,17 @@ describe 'Signup' do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates the user account and goes to dashboard' do
|
it 'creates the user account and goes to dashboard' do
|
||||||
visit root_path
|
visit new_user_registration_path
|
||||||
|
|
||||||
fill_in 'new_user_name', with: new_user.name
|
fill_in 'new_user_name', with: new_user.name
|
||||||
fill_in 'new_user_username', with: new_user.username
|
fill_in 'new_user_username', with: new_user.username
|
||||||
fill_in 'new_user_email', with: new_user.email
|
fill_in 'new_user_email', with: new_user.email
|
||||||
fill_in 'new_user_email_confirmation', with: new_user.email
|
|
||||||
fill_in 'new_user_password', with: new_user.password
|
unless Feature.enabled?(:experimental_separate_sign_up_flow)
|
||||||
|
fill_in 'new_user_email_confirmation', with: new_user.email
|
||||||
|
end
|
||||||
|
|
||||||
|
fill_in 'new_user_password', with: new_user.password
|
||||||
click_button "Register"
|
click_button "Register"
|
||||||
|
|
||||||
expect(current_path).to eq dashboard_projects_path
|
expect(current_path).to eq dashboard_projects_path
|
||||||
|
@ -255,28 +269,34 @@ describe 'Signup' do
|
||||||
it "displays the errors" do
|
it "displays the errors" do
|
||||||
existing_user = create(:user)
|
existing_user = create(:user)
|
||||||
|
|
||||||
visit root_path
|
visit new_user_registration_path
|
||||||
|
|
||||||
fill_in 'new_user_name', with: new_user.name
|
fill_in 'new_user_name', with: new_user.name
|
||||||
fill_in 'new_user_username', with: new_user.username
|
fill_in 'new_user_username', with: new_user.username
|
||||||
fill_in 'new_user_email', with: existing_user.email
|
fill_in 'new_user_email', with: existing_user.email
|
||||||
fill_in 'new_user_password', with: new_user.password
|
fill_in 'new_user_password', with: new_user.password
|
||||||
click_button "Register"
|
click_button "Register"
|
||||||
|
|
||||||
expect(current_path).to eq user_registration_path
|
expect(current_path).to eq user_registration_path
|
||||||
expect(page).to have_content("errors prohibited this user from being saved")
|
|
||||||
expect(page).to have_content("Email has already been taken")
|
if Feature.enabled?(:experimental_separate_sign_up_flow)
|
||||||
expect(page).to have_content("Email confirmation doesn't match")
|
expect(page).to have_content("error prohibited this user from being saved")
|
||||||
|
expect(page).to have_content("Email has already been taken")
|
||||||
|
else
|
||||||
|
expect(page).to have_content("errors prohibited this user from being saved")
|
||||||
|
expect(page).to have_content("Email has already been taken")
|
||||||
|
expect(page).to have_content("Email confirmation doesn't match")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not redisplay the password' do
|
it 'does not redisplay the password' do
|
||||||
existing_user = create(:user)
|
existing_user = create(:user)
|
||||||
|
|
||||||
visit root_path
|
visit new_user_registration_path
|
||||||
|
|
||||||
fill_in 'new_user_name', with: new_user.name
|
fill_in 'new_user_name', with: new_user.name
|
||||||
fill_in 'new_user_username', with: new_user.username
|
fill_in 'new_user_username', with: new_user.username
|
||||||
fill_in 'new_user_email', with: existing_user.email
|
fill_in 'new_user_email', with: existing_user.email
|
||||||
fill_in 'new_user_password', with: new_user.password
|
fill_in 'new_user_password', with: new_user.password
|
||||||
click_button "Register"
|
click_button "Register"
|
||||||
|
|
||||||
|
@ -291,13 +311,17 @@ describe 'Signup' do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'requires the user to check the checkbox' do
|
it 'requires the user to check the checkbox' do
|
||||||
visit root_path
|
visit new_user_registration_path
|
||||||
|
|
||||||
fill_in 'new_user_name', with: new_user.name
|
fill_in 'new_user_name', with: new_user.name
|
||||||
fill_in 'new_user_username', with: new_user.username
|
fill_in 'new_user_username', with: new_user.username
|
||||||
fill_in 'new_user_email', with: new_user.email
|
fill_in 'new_user_email', with: new_user.email
|
||||||
fill_in 'new_user_email_confirmation', with: new_user.email
|
|
||||||
fill_in 'new_user_password', with: new_user.password
|
unless Feature.enabled?(:experimental_separate_sign_up_flow)
|
||||||
|
fill_in 'new_user_email_confirmation', with: new_user.email
|
||||||
|
end
|
||||||
|
|
||||||
|
fill_in 'new_user_password', with: new_user.password
|
||||||
|
|
||||||
click_button 'Register'
|
click_button 'Register'
|
||||||
|
|
||||||
|
@ -306,13 +330,17 @@ describe 'Signup' do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'asks the user to accept terms before going to the dashboard' do
|
it 'asks the user to accept terms before going to the dashboard' do
|
||||||
visit root_path
|
visit new_user_registration_path
|
||||||
|
|
||||||
fill_in 'new_user_name', with: new_user.name
|
fill_in 'new_user_name', with: new_user.name
|
||||||
fill_in 'new_user_username', with: new_user.username
|
fill_in 'new_user_username', with: new_user.username
|
||||||
fill_in 'new_user_email', with: new_user.email
|
fill_in 'new_user_email', with: new_user.email
|
||||||
fill_in 'new_user_email_confirmation', with: new_user.email
|
|
||||||
fill_in 'new_user_password', with: new_user.password
|
unless Feature.enabled?(:experimental_separate_sign_up_flow)
|
||||||
|
fill_in 'new_user_email_confirmation', with: new_user.email
|
||||||
|
end
|
||||||
|
|
||||||
|
fill_in 'new_user_password', with: new_user.password
|
||||||
check :terms_opt_in
|
check :terms_opt_in
|
||||||
|
|
||||||
click_button "Register"
|
click_button "Register"
|
||||||
|
@ -321,3 +349,20 @@ describe 'Signup' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'With original flow' do
|
||||||
|
it_behaves_like 'Signup' do
|
||||||
|
before do
|
||||||
|
stub_feature_flags(experimental_separate_sign_up_flow: false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'With experimental flow on GitLab.com' do
|
||||||
|
it_behaves_like 'Signup' do
|
||||||
|
before do
|
||||||
|
expect(Gitlab).to receive(:com?).and_return(true).at_least(:once)
|
||||||
|
stub_feature_flags(experimental_separate_sign_up_flow: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
17
spec/lib/gitlab/health_checks/probes/liveness_spec.rb
Normal file
17
spec/lib/gitlab/health_checks/probes/liveness_spec.rb
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Gitlab::HealthChecks::Probes::Liveness do
|
||||||
|
let(:liveness) { described_class.new }
|
||||||
|
|
||||||
|
describe '#call' do
|
||||||
|
subject { liveness.execute }
|
||||||
|
|
||||||
|
it 'responds with liveness checks data' do
|
||||||
|
expect(subject.http_status).to eq(200)
|
||||||
|
|
||||||
|
expect(subject.json[:status]).to eq('ok')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
39
spec/lib/gitlab/health_checks/probes/readiness_spec.rb
Normal file
39
spec/lib/gitlab/health_checks/probes/readiness_spec.rb
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Gitlab::HealthChecks::Probes::Readiness do
|
||||||
|
let(:readiness) { described_class.new }
|
||||||
|
|
||||||
|
describe '#call' do
|
||||||
|
subject { readiness.execute }
|
||||||
|
|
||||||
|
it 'responds with readiness checks data' do
|
||||||
|
expect(subject.http_status).to eq(200)
|
||||||
|
|
||||||
|
expect(subject.json[:status]).to eq('ok')
|
||||||
|
expect(subject.json['db_check']).to contain_exactly(status: 'ok')
|
||||||
|
expect(subject.json['cache_check']).to contain_exactly(status: 'ok')
|
||||||
|
expect(subject.json['queues_check']).to contain_exactly(status: 'ok')
|
||||||
|
expect(subject.json['shared_state_check']).to contain_exactly(status: 'ok')
|
||||||
|
expect(subject.json['gitaly_check']).to contain_exactly(
|
||||||
|
status: 'ok', labels: { shard: 'default' })
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when Redis fails' do
|
||||||
|
before do
|
||||||
|
allow(Gitlab::HealthChecks::Redis::RedisCheck).to receive(:readiness).and_return(
|
||||||
|
Gitlab::HealthChecks::Result.new('redis_check', false, "check error"))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'responds with failure' do
|
||||||
|
expect(subject.http_status).to eq(503)
|
||||||
|
|
||||||
|
expect(subject.json[:status]).to eq('failed')
|
||||||
|
expect(subject.json['cache_check']).to contain_exactly(status: 'ok')
|
||||||
|
expect(subject.json['redis_check']).to contain_exactly(
|
||||||
|
status: 'failed', message: 'check error')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -4,35 +4,42 @@ require 'spec_helper'
|
||||||
|
|
||||||
describe Gitlab::Metrics::Exporter::BaseExporter do
|
describe Gitlab::Metrics::Exporter::BaseExporter do
|
||||||
let(:exporter) { described_class.new }
|
let(:exporter) { described_class.new }
|
||||||
let(:server) { double('server') }
|
|
||||||
let(:socket) { double('socket') }
|
|
||||||
let(:log_filename) { File.join(Rails.root, 'log', 'sidekiq_exporter.log') }
|
let(:log_filename) { File.join(Rails.root, 'log', 'sidekiq_exporter.log') }
|
||||||
let(:settings) { double('settings') }
|
let(:settings) { double('settings') }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow(::WEBrick::HTTPServer).to receive(:new).and_return(server)
|
|
||||||
allow(server).to receive(:mount)
|
|
||||||
allow(server).to receive(:start)
|
|
||||||
allow(server).to receive(:shutdown)
|
|
||||||
allow(server).to receive(:listeners) { [socket] }
|
|
||||||
allow(socket).to receive(:close)
|
|
||||||
allow_any_instance_of(described_class).to receive(:log_filename).and_return(log_filename)
|
allow_any_instance_of(described_class).to receive(:log_filename).and_return(log_filename)
|
||||||
allow_any_instance_of(described_class).to receive(:settings).and_return(settings)
|
allow_any_instance_of(described_class).to receive(:settings).and_return(settings)
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'when exporter is enabled' do
|
describe 'when exporter is enabled' do
|
||||||
before do
|
before do
|
||||||
|
allow(::WEBrick::HTTPServer).to receive(:new).with(
|
||||||
|
Port: anything,
|
||||||
|
BindAddress: anything,
|
||||||
|
Logger: anything,
|
||||||
|
AccessLog: anything
|
||||||
|
).and_wrap_original do |m, *args|
|
||||||
|
m.call(DoNotListen: true, Logger: args.first[:Logger])
|
||||||
|
end
|
||||||
|
|
||||||
|
allow_any_instance_of(::WEBrick::HTTPServer).to receive(:start)
|
||||||
|
|
||||||
allow(settings).to receive(:enabled).and_return(true)
|
allow(settings).to receive(:enabled).and_return(true)
|
||||||
allow(settings).to receive(:port).and_return(3707)
|
allow(settings).to receive(:port).and_return(8082)
|
||||||
allow(settings).to receive(:address).and_return('localhost')
|
allow(settings).to receive(:address).and_return('localhost')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
exporter.stop
|
||||||
|
end
|
||||||
|
|
||||||
describe 'when exporter is stopped' do
|
describe 'when exporter is stopped' do
|
||||||
describe '#start' do
|
describe '#start' do
|
||||||
it 'starts the exporter' do
|
it 'starts the exporter' do
|
||||||
expect { exporter.start.join }.to change { exporter.thread? }.from(false).to(true)
|
expect_any_instance_of(::WEBrick::HTTPServer).to receive(:start)
|
||||||
|
|
||||||
expect(server).to have_received(:start)
|
expect { exporter.start.join }.to change { exporter.thread? }.from(false).to(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'with custom settings' do
|
describe 'with custom settings' do
|
||||||
|
@ -45,23 +52,25 @@ describe Gitlab::Metrics::Exporter::BaseExporter do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'starts server with port and address from settings' do
|
it 'starts server with port and address from settings' do
|
||||||
exporter.start.join
|
expect(::WEBrick::HTTPServer).to receive(:new).with(
|
||||||
|
|
||||||
expect(::WEBrick::HTTPServer).to have_received(:new).with(
|
|
||||||
Port: port,
|
Port: port,
|
||||||
BindAddress: address,
|
BindAddress: address,
|
||||||
Logger: anything,
|
Logger: anything,
|
||||||
AccessLog: anything
|
AccessLog: anything
|
||||||
)
|
).and_wrap_original do |m, *args|
|
||||||
|
m.call(DoNotListen: true, Logger: args.first[:Logger])
|
||||||
|
end
|
||||||
|
|
||||||
|
exporter.start.join
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#stop' do
|
describe '#stop' do
|
||||||
it "doesn't shutdown stopped server" do
|
it "doesn't shutdown stopped server" do
|
||||||
expect { exporter.stop }.not_to change { exporter.thread? }
|
expect_any_instance_of(::WEBrick::HTTPServer).not_to receive(:shutdown)
|
||||||
|
|
||||||
expect(server).not_to have_received(:shutdown)
|
expect { exporter.stop }.not_to change { exporter.thread? }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -73,23 +82,69 @@ describe Gitlab::Metrics::Exporter::BaseExporter do
|
||||||
|
|
||||||
describe '#start' do
|
describe '#start' do
|
||||||
it "doesn't start running server" do
|
it "doesn't start running server" do
|
||||||
expect { exporter.start.join }.not_to change { exporter.thread? }
|
expect_any_instance_of(::WEBrick::HTTPServer).not_to receive(:start)
|
||||||
|
|
||||||
expect(server).to have_received(:start).once
|
expect { exporter.start.join }.not_to change { exporter.thread? }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#stop' do
|
describe '#stop' do
|
||||||
it 'shutdowns server' do
|
it 'shutdowns server' do
|
||||||
expect { exporter.stop }.to change { exporter.thread? }.from(true).to(false)
|
expect_any_instance_of(::WEBrick::HTTPServer).to receive(:shutdown)
|
||||||
|
|
||||||
expect(socket).to have_received(:close)
|
expect { exporter.stop }.to change { exporter.thread? }.from(true).to(false)
|
||||||
expect(server).to have_received(:shutdown)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'request handling' do
|
||||||
|
using RSpec::Parameterized::TableSyntax
|
||||||
|
|
||||||
|
where(:method_class, :path, :http_status) do
|
||||||
|
Net::HTTP::Get | '/metrics' | 200
|
||||||
|
Net::HTTP::Get | '/liveness' | 200
|
||||||
|
Net::HTTP::Get | '/readiness' | 200
|
||||||
|
Net::HTTP::Get | '/' | 404
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(settings).to receive(:enabled).and_return(true)
|
||||||
|
allow(settings).to receive(:port).and_return(0)
|
||||||
|
allow(settings).to receive(:address).and_return('127.0.0.1')
|
||||||
|
|
||||||
|
# We want to wrap original method
|
||||||
|
# and run handling of requests
|
||||||
|
# in separate thread
|
||||||
|
allow_any_instance_of(::WEBrick::HTTPServer)
|
||||||
|
.to receive(:start).and_wrap_original do |m, *args|
|
||||||
|
Thread.new do
|
||||||
|
m.call(*args)
|
||||||
|
rescue IOError
|
||||||
|
# is raised as we close listeners
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
exporter.start.join
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
exporter.stop
|
||||||
|
end
|
||||||
|
|
||||||
|
with_them do
|
||||||
|
let(:config) { exporter.server.config }
|
||||||
|
let(:request) { method_class.new(path) }
|
||||||
|
|
||||||
|
it 'responds with proper http_status' do
|
||||||
|
http = Net::HTTP.new(config[:BindAddress], config[:Port])
|
||||||
|
response = http.request(request)
|
||||||
|
|
||||||
|
expect(response.code).to eq(http_status.to_s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe 'when exporter is disabled' do
|
describe 'when exporter is disabled' do
|
||||||
before do
|
before do
|
||||||
allow(settings).to receive(:enabled).and_return(false)
|
allow(settings).to receive(:enabled).and_return(false)
|
||||||
|
@ -97,18 +152,18 @@ describe Gitlab::Metrics::Exporter::BaseExporter do
|
||||||
|
|
||||||
describe '#start' do
|
describe '#start' do
|
||||||
it "doesn't start" do
|
it "doesn't start" do
|
||||||
|
expect_any_instance_of(::WEBrick::HTTPServer).not_to receive(:start)
|
||||||
|
|
||||||
expect(exporter.start).to be_nil
|
expect(exporter.start).to be_nil
|
||||||
expect { exporter.start }.not_to change { exporter.thread? }
|
expect { exporter.start }.not_to change { exporter.thread? }
|
||||||
|
|
||||||
expect(server).not_to have_received(:start)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#stop' do
|
describe '#stop' do
|
||||||
it "doesn't shutdown" do
|
it "doesn't shutdown" do
|
||||||
expect { exporter.stop }.not_to change { exporter.thread? }
|
expect_any_instance_of(::WEBrick::HTTPServer).not_to receive(:shutdown)
|
||||||
|
|
||||||
expect(server).not_to have_received(:shutdown)
|
expect { exporter.stop }.not_to change { exporter.thread? }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -880,22 +880,6 @@ describe Group do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#has_parent?' do
|
|
||||||
context 'when the group has a parent' do
|
|
||||||
it 'is truthy' do
|
|
||||||
group = create(:group, :nested)
|
|
||||||
expect(group.has_parent?).to be_truthy
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the group has no parent' do
|
|
||||||
it 'is falsy' do
|
|
||||||
group = create(:group, parent: nil)
|
|
||||||
expect(group.has_parent?).to be_falsy
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with uploads' do
|
context 'with uploads' do
|
||||||
it_behaves_like 'model with uploads', true do
|
it_behaves_like 'model with uploads', true do
|
||||||
let(:model_object) { create(:group, :with_avatar) }
|
let(:model_object) { create(:group, :with_avatar) }
|
||||||
|
|
|
@ -933,4 +933,25 @@ describe Namespace do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#has_parent?' do
|
||||||
|
it 'returns true when the group has a parent' do
|
||||||
|
group = create(:group, :nested)
|
||||||
|
|
||||||
|
expect(group.has_parent?).to be_truthy
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns true when the group has an unsaved parent' do
|
||||||
|
parent = build(:group)
|
||||||
|
group = build(:group, parent: parent)
|
||||||
|
|
||||||
|
expect(group.has_parent?).to be_truthy
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns false when the group has no parent' do
|
||||||
|
group = create(:group, parent: nil)
|
||||||
|
|
||||||
|
expect(group.has_parent?).to be_falsy
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -41,7 +41,7 @@ describe BugzillaService do
|
||||||
{ project_url: url, issues_url: url, new_issue_url: url }
|
{ project_url: url, issues_url: url, new_issue_url: url }
|
||||||
end
|
end
|
||||||
|
|
||||||
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084
|
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
|
||||||
context 'when data are stored in properties' do
|
context 'when data are stored in properties' do
|
||||||
let(:properties) { access_params.merge(title: title, description: description) }
|
let(:properties) { access_params.merge(title: title, description: description) }
|
||||||
let(:service) do
|
let(:service) do
|
||||||
|
|
|
@ -55,7 +55,7 @@ describe CustomIssueTrackerService do
|
||||||
{ project_url: url, issues_url: url, new_issue_url: url }
|
{ project_url: url, issues_url: url, new_issue_url: url }
|
||||||
end
|
end
|
||||||
|
|
||||||
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084
|
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
|
||||||
context 'when data are stored in properties' do
|
context 'when data are stored in properties' do
|
||||||
let(:properties) { access_params.merge(title: title, description: description) }
|
let(:properties) { access_params.merge(title: title, description: description) }
|
||||||
let(:service) do
|
let(:service) do
|
||||||
|
|
|
@ -58,7 +58,7 @@ describe GitlabIssueTrackerService do
|
||||||
{ project_url: url, issues_url: url, new_issue_url: url }
|
{ project_url: url, issues_url: url, new_issue_url: url }
|
||||||
end
|
end
|
||||||
|
|
||||||
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084
|
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
|
||||||
context 'when data are stored in properties' do
|
context 'when data are stored in properties' do
|
||||||
let(:properties) { access_params.merge(title: title, description: description) }
|
let(:properties) { access_params.merge(title: title, description: description) }
|
||||||
let(:service) do
|
let(:service) do
|
||||||
|
|
|
@ -278,7 +278,7 @@ describe JiraService do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084
|
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
|
||||||
context 'when data are stored in properties' do
|
context 'when data are stored in properties' do
|
||||||
let(:properties) { data_params.merge(title: title, description: description) }
|
let(:properties) { data_params.merge(title: title, description: description) }
|
||||||
let!(:service) do
|
let!(:service) do
|
||||||
|
|
|
@ -57,7 +57,7 @@ describe RedmineService do
|
||||||
{ project_url: url, issues_url: url, new_issue_url: url }
|
{ project_url: url, issues_url: url, new_issue_url: url }
|
||||||
end
|
end
|
||||||
|
|
||||||
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084
|
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
|
||||||
context 'when data are stored in properties' do
|
context 'when data are stored in properties' do
|
||||||
let(:properties) { access_params.merge(title: title, description: description) }
|
let(:properties) { access_params.merge(title: title, description: description) }
|
||||||
let(:service) do
|
let(:service) do
|
||||||
|
|
|
@ -45,7 +45,7 @@ describe YoutrackService do
|
||||||
{ project_url: url, issues_url: url, new_issue_url: url }
|
{ project_url: url, issues_url: url, new_issue_url: url }
|
||||||
end
|
end
|
||||||
|
|
||||||
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084
|
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
|
||||||
context 'when data are stored in properties' do
|
context 'when data are stored in properties' do
|
||||||
let(:properties) { access_params.merge(title: title, description: description) }
|
let(:properties) { access_params.merge(title: title, description: description) }
|
||||||
let(:service) do
|
let(:service) do
|
||||||
|
|
|
@ -121,7 +121,7 @@ describe Service do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084
|
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
|
||||||
context 'when data are stored in properties' do
|
context 'when data are stored in properties' do
|
||||||
let(:properties) { data_params.merge(title: title, description: description) }
|
let(:properties) { data_params.merge(title: title, description: description) }
|
||||||
let!(:template) do
|
let!(:template) do
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe API::Groups do
|
describe API::Groups do
|
||||||
|
include GroupAPIHelpers
|
||||||
include UploadHelpers
|
include UploadHelpers
|
||||||
|
|
||||||
let(:user1) { create(:user, can_create_group: false) }
|
let(:user1) { create(:user, can_create_group: false) }
|
||||||
|
@ -350,6 +351,13 @@ describe API::Groups do
|
||||||
expect(json_response['description']).to eq(group1.description)
|
expect(json_response['description']).to eq(group1.description)
|
||||||
expect(json_response['visibility']).to eq(Gitlab::VisibilityLevel.string_level(group1.visibility_level))
|
expect(json_response['visibility']).to eq(Gitlab::VisibilityLevel.string_level(group1.visibility_level))
|
||||||
expect(json_response['avatar_url']).to eq(group1.avatar_url(only_path: false))
|
expect(json_response['avatar_url']).to eq(group1.avatar_url(only_path: false))
|
||||||
|
expect(json_response['share_with_group_lock']).to eq(group1.share_with_group_lock)
|
||||||
|
expect(json_response['require_two_factor_authentication']).to eq(group1.require_two_factor_authentication)
|
||||||
|
expect(json_response['two_factor_grace_period']).to eq(group1.two_factor_grace_period)
|
||||||
|
expect(json_response['auto_devops_enabled']).to eq(group1.auto_devops_enabled)
|
||||||
|
expect(json_response['emails_disabled']).to eq(group1.emails_disabled)
|
||||||
|
expect(json_response['project_creation_level']).to eq('maintainer')
|
||||||
|
expect(json_response['subgroup_creation_level']).to eq('maintainer')
|
||||||
expect(json_response['web_url']).to eq(group1.web_url)
|
expect(json_response['web_url']).to eq(group1.web_url)
|
||||||
expect(json_response['request_access_enabled']).to eq(group1.request_access_enabled)
|
expect(json_response['request_access_enabled']).to eq(group1.request_access_enabled)
|
||||||
expect(json_response['full_name']).to eq(group1.full_name)
|
expect(json_response['full_name']).to eq(group1.full_name)
|
||||||
|
@ -485,11 +493,30 @@ describe API::Groups do
|
||||||
|
|
||||||
context 'when authenticated as the group owner' do
|
context 'when authenticated as the group owner' do
|
||||||
it 'updates the group' do
|
it 'updates the group' do
|
||||||
put api("/groups/#{group1.id}", user1), params: { name: new_group_name, request_access_enabled: true }
|
put api("/groups/#{group1.id}", user1), params: {
|
||||||
|
name: new_group_name,
|
||||||
|
request_access_enabled: true,
|
||||||
|
project_creation_level: "noone",
|
||||||
|
subgroup_creation_level: "maintainer"
|
||||||
|
}
|
||||||
|
|
||||||
expect(response).to have_gitlab_http_status(200)
|
expect(response).to have_gitlab_http_status(200)
|
||||||
expect(json_response['name']).to eq(new_group_name)
|
expect(json_response['name']).to eq(new_group_name)
|
||||||
|
expect(json_response['description']).to eq('')
|
||||||
|
expect(json_response['visibility']).to eq('public')
|
||||||
|
expect(json_response['share_with_group_lock']).to eq(false)
|
||||||
|
expect(json_response['require_two_factor_authentication']).to eq(false)
|
||||||
|
expect(json_response['two_factor_grace_period']).to eq(48)
|
||||||
|
expect(json_response['auto_devops_enabled']).to eq(nil)
|
||||||
|
expect(json_response['emails_disabled']).to eq(nil)
|
||||||
|
expect(json_response['project_creation_level']).to eq("noone")
|
||||||
|
expect(json_response['subgroup_creation_level']).to eq("maintainer")
|
||||||
expect(json_response['request_access_enabled']).to eq(true)
|
expect(json_response['request_access_enabled']).to eq(true)
|
||||||
|
expect(json_response['parent_id']).to eq(nil)
|
||||||
|
expect(json_response['projects']).to be_an Array
|
||||||
|
expect(json_response['projects'].length).to eq(2)
|
||||||
|
expect(json_response['shared_projects']).to be_an Array
|
||||||
|
expect(json_response['shared_projects'].length).to eq(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns 404 for a non existing group' do
|
it 'returns 404 for a non existing group' do
|
||||||
|
@ -864,7 +891,9 @@ describe API::Groups do
|
||||||
describe "POST /groups" do
|
describe "POST /groups" do
|
||||||
context "when authenticated as user without group permissions" do
|
context "when authenticated as user without group permissions" do
|
||||||
it "does not create group" do
|
it "does not create group" do
|
||||||
post api("/groups", user1), params: attributes_for(:group)
|
group = attributes_for_group_api
|
||||||
|
|
||||||
|
post api("/groups", user1), params: group
|
||||||
|
|
||||||
expect(response).to have_gitlab_http_status(403)
|
expect(response).to have_gitlab_http_status(403)
|
||||||
end
|
end
|
||||||
|
@ -896,7 +925,7 @@ describe API::Groups do
|
||||||
|
|
||||||
context "when authenticated as user with group permissions" do
|
context "when authenticated as user with group permissions" do
|
||||||
it "creates group" do
|
it "creates group" do
|
||||||
group = attributes_for(:group, { request_access_enabled: false })
|
group = attributes_for_group_api request_access_enabled: false
|
||||||
|
|
||||||
post api("/groups", user3), params: group
|
post api("/groups", user3), params: group
|
||||||
|
|
||||||
|
@ -911,7 +940,7 @@ describe API::Groups do
|
||||||
it "creates a nested group" do
|
it "creates a nested group" do
|
||||||
parent = create(:group)
|
parent = create(:group)
|
||||||
parent.add_owner(user3)
|
parent.add_owner(user3)
|
||||||
group = attributes_for(:group, { parent_id: parent.id })
|
group = attributes_for_group_api parent_id: parent.id
|
||||||
|
|
||||||
post api("/groups", user3), params: group
|
post api("/groups", user3), params: group
|
||||||
|
|
||||||
|
|
|
@ -634,10 +634,47 @@ describe API::Users do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "GET /users/sign_up" do
|
describe "GET /users/sign_up" do
|
||||||
it "redirects to sign in page" do
|
context 'when experimental_separate_sign_up_flow is active' do
|
||||||
get "/users/sign_up"
|
before do
|
||||||
expect(response).to have_gitlab_http_status(302)
|
stub_feature_flags(experimental_separate_sign_up_flow: true)
|
||||||
expect(response).to redirect_to(new_user_session_path)
|
end
|
||||||
|
|
||||||
|
context 'on gitlab.com' do
|
||||||
|
before do
|
||||||
|
allow(::Gitlab).to receive(:com?).and_return(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "shows sign up page" do
|
||||||
|
get "/users/sign_up"
|
||||||
|
expect(response).to have_gitlab_http_status(200)
|
||||||
|
expect(response).to render_template(:new)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'not on gitlab.com' do
|
||||||
|
before do
|
||||||
|
allow(::Gitlab).to receive(:com?).and_return(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "redirects to sign in page" do
|
||||||
|
get "/users/sign_up"
|
||||||
|
expect(response).to have_gitlab_http_status(302)
|
||||||
|
expect(response).to redirect_to(new_user_session_path(anchor: 'register-pane'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when experimental_separate_sign_up_flow is not active' do
|
||||||
|
before do
|
||||||
|
allow(::Gitlab).to receive(:com?).and_return(true)
|
||||||
|
stub_feature_flags(experimental_separate_sign_up_flow: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "redirects to sign in page" do
|
||||||
|
get "/users/sign_up"
|
||||||
|
expect(response).to have_gitlab_http_status(302)
|
||||||
|
expect(response).to redirect_to(new_user_session_path(anchor: 'register-pane'))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
11
spec/support/helpers/group_api_helpers.rb
Normal file
11
spec/support/helpers/group_api_helpers.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module GroupAPIHelpers
|
||||||
|
extend self
|
||||||
|
|
||||||
|
def attributes_for_group_api(params = {})
|
||||||
|
# project_creation_level and subgroup_creation_level are Integers in the model
|
||||||
|
# but are strings in the API
|
||||||
|
attributes_for(:group, params).except(:project_creation_level, :subgroup_creation_level)
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue