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.
|
||||
|
||||
|
||||
## 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)
|
||||
|
|
14
CHANGELOG.md
14
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)
|
||||
|
|
|
@ -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';
|
||||
|
|
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 {
|
||||
// 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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
|
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 WithUploads
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
include GroupAPICompatibility
|
||||
|
||||
ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT = 10
|
||||
|
||||
|
|
|
@ -256,7 +256,7 @@ class Namespace < ApplicationRecord
|
|||
end
|
||||
|
||||
def has_parent?
|
||||
parent.present?
|
||||
parent_id.present? || parent.present?
|
||||
end
|
||||
|
||||
def root_ancestor
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
Already have login and password?
|
||||
= 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-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)
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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",
|
||||
"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. |
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
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(
|
||||
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
|
||||
|
|
|
@ -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 ""
|
||||
|
||||
|
|
2
qa/qa.rb
2
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
|
||||
|
|
|
@ -17,5 +17,3 @@ module QA
|
|||
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
|
||||
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
|
||||
|
||||
|
|
|
@ -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
|
||||
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)
|
||||
|
||||
|
@ -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_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
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
|
|
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
|
||||
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,23 +82,69 @@ 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 { 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(server).to have_received(:shutdown)
|
||||
expect { exporter.stop }.to change { exporter.thread? }.from(true).to(false)
|
||||
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
|
||||
before do
|
||||
allow(settings).to receive(:enabled).and_return(false)
|
||||
|
@ -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
|
||||
|
|
|
@ -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) }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
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