summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG-EE.md14
-rw-r--r--CHANGELOG.md14
-rw-r--r--app/assets/javascripts/lib/utils/datetime_utility.js3
-rw-r--r--app/assets/javascripts/pages/registrations/new/index.js9
-rw-r--r--app/assets/stylesheets/pages/experimental_separate_sign_up.scss51
-rw-r--r--app/assets/stylesheets/pages/login.scss6
-rw-r--r--app/controllers/health_controller.rb20
-rw-r--r--app/controllers/registrations_controller.rb18
-rw-r--r--app/helpers/sessions_helper.rb4
-rw-r--r--app/models/concerns/group_api_compatibility.rb22
-rw-r--r--app/models/group.rb1
-rw-r--r--app/models/namespace.rb2
-rw-r--r--app/models/project_services/data_fields.rb2
-rw-r--r--app/models/project_services/issue_tracker_service.rb8
-rw-r--r--app/models/project_services/jira_service.rb2
-rw-r--r--app/views/admin/application_settings/_influx.html.haml2
-rw-r--r--app/views/devise/registrations/new.html.haml5
-rw-r--r--app/views/devise/sessions/new.html.haml3
-rw-r--r--app/views/devise/shared/_experimental_separate_sign_up_flow_box.html.haml34
-rw-r--r--app/views/devise/shared/_sign_in_link.html.haml2
-rw-r--r--app/views/devise/shared/_signin_box.html.haml5
-rw-r--r--app/views/layouts/_head.html.haml12
-rw-r--r--app/views/layouts/devise_experimental_separate_sign_up_flow.html.haml25
-rw-r--r--changelogs/unreleased/16482-split-sign-in-and-sign-up.yml5
-rw-r--r--changelogs/unreleased/add-health-checks-exporter.yml5
-rw-r--r--changelogs/unreleased/fix-moved-help-doc-administration-monitoring-performance.yml5
-rw-r--r--changelogs/unreleased/groups_api.yml5
-rw-r--r--changelogs/unreleased/security-search-by-iid-leaks-data.yml6
-rw-r--r--doc/api/groups.md35
-rw-r--r--lib/api/entities.rb7
-rw-r--r--lib/api/helpers/groups_helpers.rb8
-rw-r--r--lib/gitlab/access.rb27
-rw-r--r--lib/gitlab/health_checks/probes/liveness.rb13
-rw-r--r--lib/gitlab/health_checks/probes/readiness.rb53
-rw-r--r--lib/gitlab/health_checks/probes/status.rb14
-rw-r--r--lib/gitlab/metrics/exporter/base_exporter.rb18
-rw-r--r--locale/gitlab.pot9
-rw-r--r--qa/qa.rb2
-rw-r--r--qa/qa/page/project/milestone/index.rb2
-rw-r--r--qa/qa/page/project/milestone/show.rb14
-rw-r--r--qa/qa/support/dates.rb21
-rw-r--r--spec/controllers/health_controller_spec.rb19
-rw-r--r--spec/features/users/signup_spec.rb145
-rw-r--r--spec/lib/gitlab/health_checks/probes/liveness_spec.rb17
-rw-r--r--spec/lib/gitlab/health_checks/probes/readiness_spec.rb39
-rw-r--r--spec/lib/gitlab/metrics/exporter/base_exporter_spec.rb105
-rw-r--r--spec/models/group_spec.rb16
-rw-r--r--spec/models/namespace_spec.rb21
-rw-r--r--spec/models/project_services/bugzilla_service_spec.rb2
-rw-r--r--spec/models/project_services/custom_issue_tracker_service_spec.rb2
-rw-r--r--spec/models/project_services/gitlab_issue_tracker_service_spec.rb2
-rw-r--r--spec/models/project_services/jira_service_spec.rb2
-rw-r--r--spec/models/project_services/redmine_service_spec.rb2
-rw-r--r--spec/models/project_services/youtrack_service_spec.rb2
-rw-r--r--spec/models/service_spec.rb2
-rw-r--r--spec/requests/api/groups_spec.rb37
-rw-r--r--spec/requests/api/users_spec.rb45
-rw-r--r--spec/support/helpers/group_api_helpers.rb11
58 files changed, 840 insertions, 142 deletions
diff --git a/CHANGELOG-EE.md b/CHANGELOG-EE.md
index eb43ae6a328..6e5a6e26804 100644
--- a/CHANGELOG-EE.md
+++ b/CHANGELOG-EE.md
@@ -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.
+## 12.2.8
+
+### Fixed (1 change)
+
+- Geo: LFS not being synced. !17633
+
+
## 12.2.7
### 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.
+## 12.1.14
+
+### Fixed (1 change)
+
+- Geo: LFS not being synced. !17633
+
+
## 12.1.12
### Security (4 changes)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index da0e41c6d0e..279c6ede932 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -307,6 +307,13 @@ entry.
- 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
### Security (1 change)
@@ -649,6 +656,13 @@ entry.
- 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
### Security (12 changes)
diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js
index cb70837f9e9..37b0215f6f9 100644
--- a/app/assets/javascripts/lib/utils/datetime_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime_utility.js
@@ -561,3 +561,6 @@ export const getDateInPast = (date, daysInPast) => {
dateClone.setTime(dateClone.getTime() - daysInPast * 24 * 60 * 60 * 1000),
).toISOString();
};
+
+export const beginOfDayTime = 'T00:00:00Z';
+export const endOfDayTime = 'T23:59:59Z';
diff --git a/app/assets/javascripts/pages/registrations/new/index.js b/app/assets/javascripts/pages/registrations/new/index.js
new file mode 100644
index 00000000000..a33d11f3613
--- /dev/null
+++ b/app/assets/javascripts/pages/registrations/new/index.js
@@ -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
+});
diff --git a/app/assets/stylesheets/pages/experimental_separate_sign_up.scss b/app/assets/stylesheets/pages/experimental_separate_sign_up.scss
new file mode 100644
index 00000000000..8b1ec1ced35
--- /dev/null
+++ b/app/assets/stylesheets/pages/experimental_separate_sign_up.scss
@@ -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;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/pages/login.scss b/app/assets/stylesheets/pages/login.scss
index d8aabecc036..7488a5b16a2 100644
--- a/app/assets/stylesheets/pages/login.scss
+++ b/app/assets/stylesheets/pages/login.scss
@@ -215,6 +215,12 @@
body {
// offset height of fixed header + 1 to avoid scroll
height: calc(100% - 51px);
+
+ // offset without the header
+ &.navless {
+ height: calc(100% - 11px);
+ }
+
margin: 0;
padding: 0;
diff --git a/app/controllers/health_controller.rb b/app/controllers/health_controller.rb
index 99840e40af1..d88ec06a18b 100644
--- a/app/controllers/health_controller.rb
+++ b/app/controllers/health_controller.rb
@@ -5,23 +5,21 @@ class HealthController < ActionController::Base
include RequiresWhitelistedMonitoringClient
def readiness
- results = checks.flat_map(&: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
+ render_probe(::Gitlab::HealthChecks::Probes::Readiness)
end
def liveness
- render json: { status: 'ok' }, status: :ok
+ render_probe(::Gitlab::HealthChecks::Probes::Liveness)
end
private
- def checks
- ::Gitlab::HealthChecks::CHECKS
+ def render_probe(probe_class)
+ 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
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index 2e4c6a801b0..3a2975e92d6 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -6,13 +6,19 @@ class RegistrationsController < Devise::RegistrationsController
include RecaptchaExperimentHelper
include InvisibleCaptcha
+ layout :choose_layout
+
prepend_before_action :check_captcha, only: :create
before_action :whitelist_query_limiting, only: [:destroy]
before_action :ensure_terms_accepted,
if: -> { action_name == 'create' && Gitlab::CurrentSettings.current_application_settings.enforce_terms? }
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
def create
@@ -144,6 +150,16 @@ class RegistrationsController < Devise::RegistrationsController
def stored_location_or_dashboard(user)
stored_location_for(user) || dashboard_projects_path
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
RegistrationsController.prepend_if_ee('EE::RegistrationsController')
diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb
index af98a611b8b..2a5a3b9eac6 100644
--- a/app/helpers/sessions_helper.rb
+++ b/app/helpers/sessions_helper.rb
@@ -4,4 +4,8 @@ module SessionsHelper
def unconfirmed_email?
flash[:alert] == t(:unconfirmed, scope: [:devise, :failure])
end
+
+ def use_experimental_separate_sign_up_flow?
+ ::Gitlab.dev_env_or_com? && Feature.enabled?(:experimental_separate_sign_up_flow)
+ end
end
diff --git a/app/models/concerns/group_api_compatibility.rb b/app/models/concerns/group_api_compatibility.rb
new file mode 100644
index 00000000000..f02aa2035e5
--- /dev/null
+++ b/app/models/concerns/group_api_compatibility.rb
@@ -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
diff --git a/app/models/group.rb b/app/models/group.rb
index 1b62db04ab7..5df9d97dcb6 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -14,6 +14,7 @@ class Group < Namespace
include TokenAuthenticatable
include WithUploads
include Gitlab::Utils::StrongMemoize
+ include GroupAPICompatibility
ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT = 10
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 0e6059f8715..7c0220a705a 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -256,7 +256,7 @@ class Namespace < ApplicationRecord
end
def has_parent?
- parent.present?
+ parent_id.present? || parent.present?
end
def root_ancestor
diff --git a/app/models/project_services/data_fields.rb b/app/models/project_services/data_fields.rb
index 46136556ade..cffb493d569 100644
--- a/app/models/project_services/data_fields.rb
+++ b/app/models/project_services/data_fields.rb
@@ -5,7 +5,7 @@ module DataFields
class_methods do
# 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)
args.each do |arg|
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb
index 278677edcdf..9e1393196ff 100644
--- a/app/models/project_services/issue_tracker_service.rb
+++ b/app/models/project_services/issue_tracker_service.rb
@@ -4,7 +4,7 @@ class IssueTrackerService < Service
validate :one_issue_tracker, if: :activated?, on: :manual_change
# 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
default_value_for :category, 'issue_tracker'
@@ -25,7 +25,7 @@ class IssueTrackerService < Service
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
if title_attribute = read_attribute(:title)
title_attribute
@@ -36,7 +36,7 @@ class IssueTrackerService < Service
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
if description_attribute = read_attribute(:description)
description_attribute
@@ -49,7 +49,7 @@ class IssueTrackerService < Service
def handle_properties
# 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
@legacy_properties_data = properties.dup
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index cfdf55b5155..6ebec17e703 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -19,7 +19,7 @@ class JiraService < IssueTrackerService
# for more information check: https://gitlab.com/gitlab-org/gitlab-foss/issues/49936.
# 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
before_update :reset_password
diff --git a/app/views/admin/application_settings/_influx.html.haml b/app/views/admin/application_settings/_influx.html.haml
index 98c7a9659c3..300b01c6777 100644
--- a/app/views/admin/application_settings/_influx.html.haml
+++ b/app/views/admin/application_settings/_influx.html.haml
@@ -7,7 +7,7 @@
in running SQL queries. These settings require a
= link_to 'restart', help_page_path('administration/restart_gitlab')
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-check
= f.check_box :metrics_enabled, class: 'form-check-input'
diff --git a/app/views/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml
index 42cfbbf84f2..dfdf7429dc5 100644
--- a/app/views/devise/registrations/new.html.haml
+++ b/app/views/devise/registrations/new.html.haml
@@ -1,4 +1,7 @@
- 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'
diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml
index 30ed7ed6b29..17e5da501f5 100644
--- a/app/views/devise/sessions/new.html.haml
+++ b/app/views/devise/sessions/new.html.haml
@@ -4,7 +4,8 @@
- if form_based_providers.any?
= render 'devise/shared/tabs_ldap'
- else
- = render 'devise/shared/tabs_normal'
+ - unless use_experimental_separate_sign_up_flow?
+ = render 'devise/shared/tabs_normal'
.tab-content
- if password_authentication_enabled_for_web? || ldap_enabled? || crowd_enabled?
= render 'devise/shared/signin_box'
diff --git a/app/views/devise/shared/_experimental_separate_sign_up_flow_box.html.haml b/app/views/devise/shared/_experimental_separate_sign_up_flow_box.html.haml
new file mode 100644
index 00000000000..f92c29da5e6
--- /dev/null
+++ b/app/views/devise/shared/_experimental_separate_sign_up_flow_box.html.haml
@@ -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' }
diff --git a/app/views/devise/shared/_sign_in_link.html.haml b/app/views/devise/shared/_sign_in_link.html.haml
index 77ef103cc47..9a7d8a0a160 100644
--- a/app/views/devise/shared/_sign_in_link.html.haml
+++ b/app/views/devise/shared/_sign_in_link.html.haml
@@ -1,4 +1,4 @@
-%p
+%p.text-center
%span.light
Already have login and password?
= link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes')
diff --git a/app/views/devise/shared/_signin_box.html.haml b/app/views/devise/shared/_signin_box.html.haml
index f8f36a8bfff..deaceccbfc7 100644
--- a/app/views/devise/shared/_signin_box.html.haml
+++ b/app/views/devise/shared/_signin_box.html.haml
@@ -22,3 +22,8 @@
.login-box.tab-pane.active{ id: 'login-pane', role: 'tabpanel' }
.login-body
= 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)
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index 68abfd3f61f..1efd8647a67 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -1,5 +1,17 @@
- 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"
%head{ prefix: "og: http://ogp.me/ns#" }
%meta{ charset: "utf-8" }
diff --git a/app/views/layouts/devise_experimental_separate_sign_up_flow.html.haml b/app/views/layouts/devise_experimental_separate_sign_up_flow.html.haml
new file mode 100644
index 00000000000..b10145b62af
--- /dev/null
+++ b/app/views/layouts/devise_experimental_separate_sign_up_flow.html.haml
@@ -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
diff --git a/changelogs/unreleased/16482-split-sign-in-and-sign-up.yml b/changelogs/unreleased/16482-split-sign-in-and-sign-up.yml
new file mode 100644
index 00000000000..bb3c01385d8
--- /dev/null
+++ b/changelogs/unreleased/16482-split-sign-in-and-sign-up.yml
@@ -0,0 +1,5 @@
+---
+title: Experimental separate sign up flow
+merge_request: 16482
+author:
+type: other
diff --git a/changelogs/unreleased/add-health-checks-exporter.yml b/changelogs/unreleased/add-health-checks-exporter.yml
new file mode 100644
index 00000000000..7ffce51b82c
--- /dev/null
+++ b/changelogs/unreleased/add-health-checks-exporter.yml
@@ -0,0 +1,5 @@
+---
+title: Export liveness and readiness probes
+merge_request:
+author:
+type: changed
diff --git a/changelogs/unreleased/fix-moved-help-doc-administration-monitoring-performance.yml b/changelogs/unreleased/fix-moved-help-doc-administration-monitoring-performance.yml
new file mode 100644
index 00000000000..2fe34855ee8
--- /dev/null
+++ b/changelogs/unreleased/fix-moved-help-doc-administration-monitoring-performance.yml
@@ -0,0 +1,5 @@
+---
+title: Fix moved help URL for monitoring performance
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/groups_api.yml b/changelogs/unreleased/groups_api.yml
new file mode 100644
index 00000000000..09e85c45811
--- /dev/null
+++ b/changelogs/unreleased/groups_api.yml
@@ -0,0 +1,5 @@
+---
+title: 'API: Add missing group parameters'
+merge_request: 17220
+author: Mathieu Parent
+type: added
diff --git a/changelogs/unreleased/security-search-by-iid-leaks-data.yml b/changelogs/unreleased/security-search-by-iid-leaks-data.yml
new file mode 100644
index 00000000000..cf68fe504de
--- /dev/null
+++ b/changelogs/unreleased/security-search-by-iid-leaks-data.yml
@@ -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
diff --git a/doc/api/groups.md b/doc/api/groups.md
index b0d60d58049..312bd04e24c 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -31,6 +31,13 @@ GET /groups
"path": "foo-bar",
"description": "An interesting group",
"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,
"avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg",
"web_url": "http://localhost:3000/groups/foo-bar",
@@ -57,6 +64,13 @@ GET /groups?statistics=true
"path": "foo-bar",
"description": "An interesting group",
"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,
"avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg",
"web_url": "http://localhost:3000/groups/foo-bar",
@@ -119,6 +133,13 @@ GET /groups/:id/subgroups
"path": "foo-bar",
"description": "An interesting group",
"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,
"avatar_url": "http://gitlab.example.com/uploads/group/avatar/1/foo.jpg",
"web_url": "http://gitlab.example.com/groups/foo-bar",
@@ -434,6 +455,13 @@ Parameters:
| `path` | string | yes | The path of the group. |
| `description` | string | no | The group's description. |
| `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. |
| `request_access_enabled` | boolean | no | Allow users to request member access. |
| `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. |
| `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`. |
+| `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. |
| `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. |
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 16cc20e95c5..6dd2e171d77 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -378,6 +378,13 @@ module API
class Group < BasicGroupDetails
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 :avatar_url do |group, options|
group.avatar_url(only_path: false)
diff --git a/lib/api/helpers/groups_helpers.rb b/lib/api/helpers/groups_helpers.rb
index abe9d457a5b..2cc18acb7ec 100644
--- a/lib/api/helpers/groups_helpers.rb
+++ b/lib/api/helpers/groups_helpers.rb
@@ -11,9 +11,15 @@ module API
optional :visibility, type: String,
values: Gitlab::VisibilityLevel.string_values,
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 :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
params :optional_params_ee do
diff --git a/lib/gitlab/access.rb b/lib/gitlab/access.rb
index ed5816482a9..6492ccc286a 100644
--- a/lib/gitlab/access.rb
+++ b/lib/gitlab/access.rb
@@ -103,10 +103,22 @@ module Gitlab
}
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
project_creation_options.values
end
+ def project_creation_string_values
+ project_creation_string_options.keys
+ end
+
def project_creation_level_name(name)
project_creation_options.key(name)
end
@@ -117,6 +129,21 @@ module Gitlab
s_('SubgroupCreationlevel|Maintainers') => MAINTAINER_SUBGROUP_ACCESS
}
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
def human_access
diff --git a/lib/gitlab/health_checks/probes/liveness.rb b/lib/gitlab/health_checks/probes/liveness.rb
new file mode 100644
index 00000000000..b4d346e945e
--- /dev/null
+++ b/lib/gitlab/health_checks/probes/liveness.rb
@@ -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
diff --git a/lib/gitlab/health_checks/probes/readiness.rb b/lib/gitlab/health_checks/probes/readiness.rb
new file mode 100644
index 00000000000..b789cbe1ae6
--- /dev/null
+++ b/lib/gitlab/health_checks/probes/readiness.rb
@@ -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
diff --git a/lib/gitlab/health_checks/probes/status.rb b/lib/gitlab/health_checks/probes/status.rb
new file mode 100644
index 00000000000..192e9366001
--- /dev/null
+++ b/lib/gitlab/health_checks/probes/status.rb
@@ -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
diff --git a/lib/gitlab/metrics/exporter/base_exporter.rb b/lib/gitlab/metrics/exporter/base_exporter.rb
index de7870dfb8c..b56770e224b 100644
--- a/lib/gitlab/metrics/exporter/base_exporter.rb
+++ b/lib/gitlab/metrics/exporter/base_exporter.rb
@@ -31,7 +31,15 @@ module Gitlab
@server = ::WEBrick::HTTPServer.new(
Port: settings.port, BindAddress: settings.address,
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
end
@@ -51,6 +59,14 @@ module Gitlab
run -> (env) { [404, {}, ['']] }
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
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 28e95173006..e40a1c2a4ea 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -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"
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-----'."
msgstr ""
@@ -13081,6 +13084,12 @@ msgstr ""
msgid "Register and see your runners for this project."
msgstr ""
+msgid "Register for GitLab.com"
+msgstr ""
+
+msgid "Register now"
+msgstr ""
+
msgid "Register with two-factor app"
msgstr ""
diff --git a/qa/qa.rb b/qa/qa.rb
index cff6f9b9d56..205e6b82aec 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -259,6 +259,7 @@ module QA
module Milestone
autoload :New, 'qa/page/project/milestone/new'
autoload :Index, 'qa/page/project/milestone/index'
+ autoload :Show, 'qa/page/project/milestone/show'
end
module Operations
@@ -449,6 +450,7 @@ module QA
autoload :Logging, 'qa/support/page/logging'
end
autoload :Api, 'qa/support/api'
+ autoload :Dates, 'qa/support/dates'
autoload :Waiter, 'qa/support/waiter'
autoload :Retrier, 'qa/support/retrier'
end
diff --git a/qa/qa/page/project/milestone/index.rb b/qa/qa/page/project/milestone/index.rb
index 8ad7689ce70..6895c44f72f 100644
--- a/qa/qa/page/project/milestone/index.rb
+++ b/qa/qa/page/project/milestone/index.rb
@@ -17,5 +17,3 @@ module QA
end
end
end
-
-QA::Page::Project::Milestone::Index.prepend_if_ee('QA::EE::Page::Project::Milestone::Index')
diff --git a/qa/qa/page/project/milestone/show.rb b/qa/qa/page/project/milestone/show.rb
new file mode 100644
index 00000000000..a6ad76cb33b
--- /dev/null
+++ b/qa/qa/page/project/milestone/show.rb
@@ -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')
diff --git a/qa/qa/support/dates.rb b/qa/qa/support/dates.rb
new file mode 100644
index 00000000000..47fc721afc1
--- /dev/null
+++ b/qa/qa/support/dates.rb
@@ -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
diff --git a/spec/controllers/health_controller_spec.rb b/spec/controllers/health_controller_spec.rb
index dd6aac4b126..8a2291bccd7 100644
--- a/spec/controllers/health_controller_spec.rb
+++ b/spec/controllers/health_controller_spec.rb
@@ -24,11 +24,12 @@ describe HealthController do
it 'responds with readiness checks data' do
subject
- expect(json_response['db_check']['status']).to eq('ok')
- expect(json_response['cache_check']['status']).to eq('ok')
- expect(json_response['queues_check']['status']).to eq('ok')
- expect(json_response['shared_state_check']['status']).to eq('ok')
- expect(json_response['gitaly_check']['status']).to eq('ok')
+ expect(json_response['db_check']).to contain_exactly({ 'status' => 'ok' })
+ expect(json_response['cache_check']).to contain_exactly({ 'status' => 'ok' })
+ expect(json_response['queues_check']).to contain_exactly({ 'status' => 'ok' })
+ expect(json_response['shared_state_check']).to contain_exactly({ 'status' => 'ok' })
+ expect(json_response['gitaly_check']).to contain_exactly(
+ { 'status' => 'ok', 'labels' => { 'shard' => 'default' } })
end
it 'responds with readiness checks data when a failure happens' do
@@ -37,9 +38,9 @@ describe HealthController do
subject
- expect(json_response['redis_check']['status']).to eq('failed')
- expect(json_response['redis_check']['message']).to eq('check error')
- expect(json_response['cache_check']['status']).to eq('ok')
+ expect(json_response['cache_check']).to contain_exactly({ 'status' => 'ok' })
+ expect(json_response['redis_check']).to contain_exactly(
+ { 'status' => 'failed', 'message' => 'check error' })
expect(response.status).to eq(503)
expect(response.headers['X-GitLab-Custom-Error']).to eq(1)
@@ -90,7 +91,7 @@ describe HealthController do
it 'responds with liveness checks data' do
subject
- expect(json_response['status']).to eq('ok')
+ expect(json_response).to eq('status' => 'ok')
end
end
diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb
index fb927a9ca3b..0846ec8dfb4 100644
--- a/spec/features/users/signup_spec.rb
+++ b/spec/features/users/signup_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe 'Signup' do
+shared_examples 'Signup' do
include TermsHelper
before do
@@ -13,8 +13,7 @@ describe 'Signup' do
describe 'username validation', :js do
before do
- visit root_path
- click_link 'Register'
+ visit new_user_registration_path
end
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
before do
- visit root_path
- click_link 'Register'
+ visit new_user_registration_path
end
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
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_username', with: new_user.username
- 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
+ fill_in 'new_user_name', with: new_user.name
+ fill_in 'new_user_username', with: new_user.username
+ fill_in 'new_user_email', with: new_user.email
+
+ 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)
@@ -198,13 +200,17 @@ describe 'Signup' do
end
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_username', with: new_user.username
+ fill_in 'new_user_email', with: new_user.email
+
+ unless Feature.enabled?(:experimental_separate_sign_up_flow)
+ fill_in 'new_user_email_confirmation', with: new_user.email
+ end
- fill_in 'new_user_name', with: new_user.name
- fill_in 'new_user_username', with: new_user.username
- 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
+ fill_in 'new_user_password', with: new_user.password
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
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_username', with: new_user.username
- 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
+ fill_in 'new_user_name', with: new_user.name
+ fill_in 'new_user_username', with: new_user.username
+ fill_in 'new_user_email', with: new_user.email
+
+ 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"
expect(current_path).to eq dashboard_projects_path
@@ -236,13 +246,17 @@ describe 'Signup' do
end
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_username', with: new_user.username
+ fill_in 'new_user_email', with: new_user.email
- fill_in 'new_user_name', with: new_user.name
- fill_in 'new_user_username', with: new_user.username
- 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"
expect(current_path).to eq dashboard_projects_path
@@ -255,28 +269,34 @@ describe 'Signup' do
it "displays the errors" do
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_email', with: existing_user.email
+ fill_in 'new_user_email', with: existing_user.email
fill_in 'new_user_password', with: new_user.password
click_button "Register"
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")
- expect(page).to have_content("Email confirmation doesn't match")
+
+ if Feature.enabled?(:experimental_separate_sign_up_flow)
+ 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
it 'does not redisplay the password' do
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_email', with: existing_user.email
+ fill_in 'new_user_email', with: existing_user.email
fill_in 'new_user_password', with: new_user.password
click_button "Register"
@@ -291,13 +311,17 @@ describe 'Signup' do
end
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_username', with: new_user.username
+ fill_in 'new_user_email', with: new_user.email
+
+ unless Feature.enabled?(:experimental_separate_sign_up_flow)
+ fill_in 'new_user_email_confirmation', with: new_user.email
+ end
- fill_in 'new_user_name', with: new_user.name
- fill_in 'new_user_username', with: new_user.username
- 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
+ fill_in 'new_user_password', with: new_user.password
click_button 'Register'
@@ -306,13 +330,17 @@ describe 'Signup' do
end
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_username', with: new_user.username
+ fill_in 'new_user_email', with: new_user.email
+
+ unless Feature.enabled?(:experimental_separate_sign_up_flow)
+ fill_in 'new_user_email_confirmation', with: new_user.email
+ end
- fill_in 'new_user_name', with: new_user.name
- fill_in 'new_user_username', with: new_user.username
- 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
+ fill_in 'new_user_password', with: new_user.password
check :terms_opt_in
click_button "Register"
@@ -321,3 +349,20 @@ describe 'Signup' do
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
diff --git a/spec/lib/gitlab/health_checks/probes/liveness_spec.rb b/spec/lib/gitlab/health_checks/probes/liveness_spec.rb
new file mode 100644
index 00000000000..91066cb8ba0
--- /dev/null
+++ b/spec/lib/gitlab/health_checks/probes/liveness_spec.rb
@@ -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
diff --git a/spec/lib/gitlab/health_checks/probes/readiness_spec.rb b/spec/lib/gitlab/health_checks/probes/readiness_spec.rb
new file mode 100644
index 00000000000..d88ffd984c2
--- /dev/null
+++ b/spec/lib/gitlab/health_checks/probes/readiness_spec.rb
@@ -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
diff --git a/spec/lib/gitlab/metrics/exporter/base_exporter_spec.rb b/spec/lib/gitlab/metrics/exporter/base_exporter_spec.rb
index 5fd7438d28a..bedf4fedcfa 100644
--- a/spec/lib/gitlab/metrics/exporter/base_exporter_spec.rb
+++ b/spec/lib/gitlab/metrics/exporter/base_exporter_spec.rb
@@ -4,35 +4,42 @@ require 'spec_helper'
describe Gitlab::Metrics::Exporter::BaseExporter do
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(:settings) { double('settings') }
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(:settings).and_return(settings)
end
describe 'when exporter is enabled' 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(:port).and_return(3707)
+ allow(settings).to receive(:port).and_return(8082)
allow(settings).to receive(:address).and_return('localhost')
end
+ after do
+ exporter.stop
+ end
+
describe 'when exporter is stopped' do
describe '#start' 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
describe 'with custom settings' do
@@ -45,23 +52,25 @@ describe Gitlab::Metrics::Exporter::BaseExporter do
end
it 'starts server with port and address from settings' do
- exporter.start.join
-
- expect(::WEBrick::HTTPServer).to have_received(:new).with(
+ expect(::WEBrick::HTTPServer).to receive(:new).with(
Port: port,
BindAddress: address,
Logger: anything,
AccessLog: anything
- )
+ ).and_wrap_original do |m, *args|
+ m.call(DoNotListen: true, Logger: args.first[:Logger])
+ end
+
+ exporter.start.join
end
end
end
describe '#stop' 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
@@ -73,20 +82,66 @@ describe Gitlab::Metrics::Exporter::BaseExporter do
describe '#start' 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
describe '#stop' do
it 'shutdowns server' do
+ expect_any_instance_of(::WEBrick::HTTPServer).to receive(:shutdown)
+
expect { exporter.stop }.to change { exporter.thread? }.from(true).to(false)
+ end
+ end
+ end
+ end
+
+ describe 'request handling' do
+ using RSpec::Parameterized::TableSyntax
- expect(socket).to have_received(:close)
- expect(server).to have_received(:shutdown)
+ 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
@@ -97,18 +152,18 @@ describe Gitlab::Metrics::Exporter::BaseExporter do
describe '#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 }.not_to change { exporter.thread? }
-
- expect(server).not_to have_received(:start)
end
end
describe '#stop' 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
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 796b6917fb2..3f149f9d7ee 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -880,22 +880,6 @@ describe Group do
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
it_behaves_like 'model with uploads', true do
let(:model_object) { create(:group, :with_avatar) }
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 797be0d1fe2..60f0dd49ff3 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -933,4 +933,25 @@ describe Namespace do
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
diff --git a/spec/models/project_services/bugzilla_service_spec.rb b/spec/models/project_services/bugzilla_service_spec.rb
index 66481a461ca..d0ab5afc765 100644
--- a/spec/models/project_services/bugzilla_service_spec.rb
+++ b/spec/models/project_services/bugzilla_service_spec.rb
@@ -41,7 +41,7 @@ describe BugzillaService do
{ project_url: url, issues_url: url, new_issue_url: url }
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
let(:properties) { access_params.merge(title: title, description: description) }
let(:service) do
diff --git a/spec/models/project_services/custom_issue_tracker_service_spec.rb b/spec/models/project_services/custom_issue_tracker_service_spec.rb
index 50bf15cfc8c..e749ea6eacc 100644
--- a/spec/models/project_services/custom_issue_tracker_service_spec.rb
+++ b/spec/models/project_services/custom_issue_tracker_service_spec.rb
@@ -55,7 +55,7 @@ describe CustomIssueTrackerService do
{ project_url: url, issues_url: url, new_issue_url: url }
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
let(:properties) { access_params.merge(title: title, description: description) }
let(:service) do
diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
index 2dc0b67239c..defebcee9c6 100644
--- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
+++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
@@ -58,7 +58,7 @@ describe GitlabIssueTrackerService do
{ project_url: url, issues_url: url, new_issue_url: url }
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
let(:properties) { access_params.merge(title: title, description: description) }
let(:service) do
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index c3b2e52848c..28d2ea79641 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -278,7 +278,7 @@ describe JiraService do
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
let(:properties) { data_params.merge(title: title, description: description) }
let!(:service) do
diff --git a/spec/models/project_services/redmine_service_spec.rb b/spec/models/project_services/redmine_service_spec.rb
index 2339c5a8421..6220d7b1fac 100644
--- a/spec/models/project_services/redmine_service_spec.rb
+++ b/spec/models/project_services/redmine_service_spec.rb
@@ -57,7 +57,7 @@ describe RedmineService do
{ project_url: url, issues_url: url, new_issue_url: url }
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
let(:properties) { access_params.merge(title: title, description: description) }
let(:service) do
diff --git a/spec/models/project_services/youtrack_service_spec.rb b/spec/models/project_services/youtrack_service_spec.rb
index fe608baf16b..19d4cb95315 100644
--- a/spec/models/project_services/youtrack_service_spec.rb
+++ b/spec/models/project_services/youtrack_service_spec.rb
@@ -45,7 +45,7 @@ describe YoutrackService do
{ project_url: url, issues_url: url, new_issue_url: url }
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
let(:properties) { access_params.merge(title: title, description: description) }
let(:service) do
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index 4049ddcff7f..64077b76f01 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -121,7 +121,7 @@ describe Service do
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
let(:properties) { data_params.merge(title: title, description: description) }
let!(:template) do
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index ec587a28f4f..902a5ec2a86 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -1,6 +1,7 @@
require 'spec_helper'
describe API::Groups do
+ include GroupAPIHelpers
include UploadHelpers
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['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['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['request_access_enabled']).to eq(group1.request_access_enabled)
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
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(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['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
it 'returns 404 for a non existing group' do
@@ -864,7 +891,9 @@ describe API::Groups do
describe "POST /groups" do
context "when authenticated as user without group permissions" 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)
end
@@ -896,7 +925,7 @@ describe API::Groups do
context "when authenticated as user with group permissions" 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
@@ -911,7 +940,7 @@ describe API::Groups do
it "creates a nested group" do
parent = create(:group)
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
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index af2bee4563a..df76b62b40e 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -634,10 +634,47 @@ describe API::Users do
end
describe "GET /users/sign_up" do
- 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)
+ context 'when experimental_separate_sign_up_flow is active' do
+ before do
+ stub_feature_flags(experimental_separate_sign_up_flow: true)
+ 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
diff --git a/spec/support/helpers/group_api_helpers.rb b/spec/support/helpers/group_api_helpers.rb
new file mode 100644
index 00000000000..56c4cc121a7
--- /dev/null
+++ b/spec/support/helpers/group_api_helpers.rb
@@ -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