Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2019-10-07 15:05:59 +00:00
parent 185f428fa5
commit 31040b5bfe
58 changed files with 841 additions and 143 deletions

View file

@ -203,6 +203,13 @@ Please view this file on the master branch, on stable branches it's out of date.
- Fixes style-lint errors and warnings for EE builds.scss file. - Fixes style-lint errors and warnings for EE builds.scss file.
## 12.2.8
### Fixed (1 change)
- Geo: LFS not being synced. !17633
## 12.2.7 ## 12.2.7
### Security (1 change) ### Security (1 change)
@ -471,6 +478,13 @@ Please view this file on the master branch, on stable branches it's out of date.
- Fix alignment of activity dropdown in epic tabs; add counter to discussion tab. - Fix alignment of activity dropdown in epic tabs; add counter to discussion tab.
## 12.1.14
### Fixed (1 change)
- Geo: LFS not being synced. !17633
## 12.1.12 ## 12.1.12
### Security (4 changes) ### Security (4 changes)

View file

@ -307,6 +307,13 @@ entry.
- Updates tooltip of 'detached' label/state. - Updates tooltip of 'detached' label/state.
## 12.2.8
### Security (1 change)
- Limit search for IID to a type to avoid leaking records with the same IID that the user does not have access to.
## 12.2.7 ## 12.2.7
### Security (1 change) ### Security (1 change)
@ -649,6 +656,13 @@ entry.
- Update Packer.gitlab-ci.yml to use latest image. (Kelly Hair) - Update Packer.gitlab-ci.yml to use latest image. (Kelly Hair)
## 12.1.14
### Security (1 change)
- Limit search for IID to a type to avoid leaking records with the same IID that the user does not have access to.
## 12.1.12 ## 12.1.12
### Security (12 changes) ### Security (12 changes)

View file

@ -561,3 +561,6 @@ export const getDateInPast = (date, daysInPast) => {
dateClone.setTime(dateClone.getTime() - daysInPast * 24 * 60 * 60 * 1000), dateClone.setTime(dateClone.getTime() - daysInPast * 24 * 60 * 60 * 1000),
).toISOString(); ).toISOString();
}; };
export const beginOfDayTime = 'T00:00:00Z';
export const endOfDayTime = 'T23:59:59Z';

View 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
});

View file

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

View file

@ -215,6 +215,12 @@
body { body {
// offset height of fixed header + 1 to avoid scroll // offset height of fixed header + 1 to avoid scroll
height: calc(100% - 51px); height: calc(100% - 51px);
// offset without the header
&.navless {
height: calc(100% - 11px);
}
margin: 0; margin: 0;
padding: 0; padding: 0;

View file

@ -5,23 +5,21 @@ class HealthController < ActionController::Base
include RequiresWhitelistedMonitoringClient include RequiresWhitelistedMonitoringClient
def readiness def readiness
results = checks.flat_map(&:readiness) render_probe(::Gitlab::HealthChecks::Probes::Readiness)
success = results.all?(&:success)
# disable static error pages at the gitlab-workhorse level, we want to see this error response even in production
headers["X-GitLab-Custom-Error"] = 1 unless success
response = results.map { |result| [result.name, result.payload] }.to_h
render json: response, status: success ? :ok : :service_unavailable
end end
def liveness def liveness
render json: { status: 'ok' }, status: :ok render_probe(::Gitlab::HealthChecks::Probes::Liveness)
end end
private private
def checks def render_probe(probe_class)
::Gitlab::HealthChecks::CHECKS result = probe_class.new.execute
# disable static error pages at the gitlab-workhorse level, we want to see this error response even in production
headers["X-GitLab-Custom-Error"] = 1 unless result.success?
render json: result.json, status: result.http_status
end end
end end

View file

@ -6,13 +6,19 @@ class RegistrationsController < Devise::RegistrationsController
include RecaptchaExperimentHelper include RecaptchaExperimentHelper
include InvisibleCaptcha include InvisibleCaptcha
layout :choose_layout
prepend_before_action :check_captcha, only: :create prepend_before_action :check_captcha, only: :create
before_action :whitelist_query_limiting, only: [:destroy] before_action :whitelist_query_limiting, only: [:destroy]
before_action :ensure_terms_accepted, before_action :ensure_terms_accepted,
if: -> { action_name == 'create' && Gitlab::CurrentSettings.current_application_settings.enforce_terms? } if: -> { action_name == 'create' && Gitlab::CurrentSettings.current_application_settings.enforce_terms? }
def new def new
redirect_to(new_user_session_path) if helpers.use_experimental_separate_sign_up_flow?
@resource = build_resource
else
redirect_to new_user_session_path(anchor: 'register-pane')
end
end end
def create def create
@ -144,6 +150,16 @@ class RegistrationsController < Devise::RegistrationsController
def stored_location_or_dashboard(user) def stored_location_or_dashboard(user)
stored_location_for(user) || dashboard_projects_path stored_location_for(user) || dashboard_projects_path
end end
# Part of an experiment to build a new sign up flow. Will be resolved
# with https://gitlab.com/gitlab-org/growth/engineering/issues/64
def choose_layout
if helpers.use_experimental_separate_sign_up_flow?
'devise_experimental_separate_sign_up_flow'
else
'devise'
end
end
end end
RegistrationsController.prepend_if_ee('EE::RegistrationsController') RegistrationsController.prepend_if_ee('EE::RegistrationsController')

View file

@ -4,4 +4,8 @@ module SessionsHelper
def unconfirmed_email? def unconfirmed_email?
flash[:alert] == t(:unconfirmed, scope: [:devise, :failure]) flash[:alert] == t(:unconfirmed, scope: [:devise, :failure])
end end
def use_experimental_separate_sign_up_flow?
::Gitlab.dev_env_or_com? && Feature.enabled?(:experimental_separate_sign_up_flow)
end
end end

View 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

View file

@ -14,6 +14,7 @@ class Group < Namespace
include TokenAuthenticatable include TokenAuthenticatable
include WithUploads include WithUploads
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
include GroupAPICompatibility
ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT = 10 ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT = 10

View file

@ -256,7 +256,7 @@ class Namespace < ApplicationRecord
end end
def has_parent? def has_parent?
parent.present? parent_id.present? || parent.present?
end end
def root_ancestor def root_ancestor

View file

@ -5,7 +5,7 @@ module DataFields
class_methods do class_methods do
# Provide convenient accessor methods for data fields. # Provide convenient accessor methods for data fields.
# TODO: Simplify as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084 # TODO: Simplify as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
def data_field(*args) def data_field(*args)
args.each do |arg| args.each do |arg|
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1 self.class_eval <<-RUBY, __FILE__, __LINE__ + 1

View file

@ -4,7 +4,7 @@ class IssueTrackerService < Service
validate :one_issue_tracker, if: :activated?, on: :manual_change validate :one_issue_tracker, if: :activated?, on: :manual_change
# TODO: we can probably just delegate as part of # TODO: we can probably just delegate as part of
# https://gitlab.com/gitlab-org/gitlab-foss/issues/63084 # https://gitlab.com/gitlab-org/gitlab/issues/29404
data_field :project_url, :issues_url, :new_issue_url data_field :project_url, :issues_url, :new_issue_url
default_value_for :category, 'issue_tracker' default_value_for :category, 'issue_tracker'
@ -25,7 +25,7 @@ class IssueTrackerService < Service
end end
end end
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084 # this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
def title def title
if title_attribute = read_attribute(:title) if title_attribute = read_attribute(:title)
title_attribute title_attribute
@ -36,7 +36,7 @@ class IssueTrackerService < Service
end end
end end
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084 # this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
def description def description
if description_attribute = read_attribute(:description) if description_attribute = read_attribute(:description)
description_attribute description_attribute
@ -49,7 +49,7 @@ class IssueTrackerService < Service
def handle_properties def handle_properties
# this has been moved from initialize_properties and should be improved # this has been moved from initialize_properties and should be improved
# as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084 # as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
return unless properties return unless properties
@legacy_properties_data = properties.dup @legacy_properties_data = properties.dup

View file

@ -19,7 +19,7 @@ class JiraService < IssueTrackerService
# for more information check: https://gitlab.com/gitlab-org/gitlab-foss/issues/49936. # for more information check: https://gitlab.com/gitlab-org/gitlab-foss/issues/49936.
# TODO: we can probably just delegate as part of # TODO: we can probably just delegate as part of
# https://gitlab.com/gitlab-org/gitlab-foss/issues/63084 # https://gitlab.com/gitlab-org/gitlab/issues/29404
data_field :username, :password, :url, :api_url, :jira_issue_transition_id data_field :username, :password, :url, :api_url, :jira_issue_transition_id
before_update :reset_password before_update :reset_password

View file

@ -7,7 +7,7 @@
in running SQL queries. These settings require a in running SQL queries. These settings require a
= link_to 'restart', help_page_path('administration/restart_gitlab') = link_to 'restart', help_page_path('administration/restart_gitlab')
to take effect. to take effect.
= link_to icon('question-circle'), help_page_path('administration/monitoring/performance/introduction') = link_to icon('question-circle'), help_page_path('administration/monitoring/performance/index')
.form-group .form-group
.form-check .form-check
= f.check_box :metrics_enabled, class: 'form-check-input' = f.check_box :metrics_enabled, class: 'form-check-input'

View file

@ -1,4 +1,7 @@
- page_title "Sign up" - page_title "Sign up"
= render 'devise/shared/signup_box' - if use_experimental_separate_sign_up_flow?
= render 'devise/shared/experimental_separate_sign_up_flow_box'
- else
= render 'devise/shared/signup_box'
= render 'devise/shared/sign_in_link' = render 'devise/shared/sign_in_link'

View file

@ -4,7 +4,8 @@
- if form_based_providers.any? - if form_based_providers.any?
= render 'devise/shared/tabs_ldap' = render 'devise/shared/tabs_ldap'
- else - else
= render 'devise/shared/tabs_normal' - unless use_experimental_separate_sign_up_flow?
= render 'devise/shared/tabs_normal'
.tab-content .tab-content
- if password_authentication_enabled_for_web? || ldap_enabled? || crowd_enabled? - if password_authentication_enabled_for_web? || ldap_enabled? || crowd_enabled?
= render 'devise/shared/signin_box' = render 'devise/shared/signin_box'

View file

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

View file

@ -1,4 +1,4 @@
%p %p.text-center
%span.light %span.light
Already have login and password? Already have login and password?
= link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes') = link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes')

View file

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

View file

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

View file

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

View file

@ -0,0 +1,5 @@
---
title: Experimental separate sign up flow
merge_request: 16482
author:
type: other

View file

@ -0,0 +1,5 @@
---
title: Export liveness and readiness probes
merge_request:
author:
type: changed

View file

@ -0,0 +1,5 @@
---
title: Fix moved help URL for monitoring performance
merge_request:
author:
type: fixed

View file

@ -0,0 +1,5 @@
---
title: 'API: Add missing group parameters'
merge_request: 17220
author: Mathieu Parent
type: added

View file

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

View file

@ -31,6 +31,13 @@ GET /groups
"path": "foo-bar", "path": "foo-bar",
"description": "An interesting group", "description": "An interesting group",
"visibility": "public", "visibility": "public",
"share_with_group_lock": false,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"project_creation_level": "developer",
"auto_devops_enabled": null,
"subgroup_creation_level": "owner",
"emails_disabled": null,
"lfs_enabled": true, "lfs_enabled": true,
"avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg", "avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg",
"web_url": "http://localhost:3000/groups/foo-bar", "web_url": "http://localhost:3000/groups/foo-bar",
@ -57,6 +64,13 @@ GET /groups?statistics=true
"path": "foo-bar", "path": "foo-bar",
"description": "An interesting group", "description": "An interesting group",
"visibility": "public", "visibility": "public",
"share_with_group_lock": false,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"project_creation_level": "developer",
"auto_devops_enabled": null,
"subgroup_creation_level": "owner",
"emails_disabled": null,
"lfs_enabled": true, "lfs_enabled": true,
"avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg", "avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg",
"web_url": "http://localhost:3000/groups/foo-bar", "web_url": "http://localhost:3000/groups/foo-bar",
@ -119,6 +133,13 @@ GET /groups/:id/subgroups
"path": "foo-bar", "path": "foo-bar",
"description": "An interesting group", "description": "An interesting group",
"visibility": "public", "visibility": "public",
"share_with_group_lock": false,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"project_creation_level": "developer",
"auto_devops_enabled": null,
"subgroup_creation_level": "owner",
"emails_disabled": null,
"lfs_enabled": true, "lfs_enabled": true,
"avatar_url": "http://gitlab.example.com/uploads/group/avatar/1/foo.jpg", "avatar_url": "http://gitlab.example.com/uploads/group/avatar/1/foo.jpg",
"web_url": "http://gitlab.example.com/groups/foo-bar", "web_url": "http://gitlab.example.com/groups/foo-bar",
@ -434,6 +455,13 @@ Parameters:
| `path` | string | yes | The path of the group. | | `path` | string | yes | The path of the group. |
| `description` | string | no | The group's description. | | `description` | string | no | The group's description. |
| `visibility` | string | no | The group's visibility. Can be `private`, `internal`, or `public`. | | `visibility` | string | no | The group's visibility. Can be `private`, `internal`, or `public`. |
| `share_with_group_lock` | boolean | no | Prevent sharing a project with another group within this group. |
| `require_two_factor_authentication` | boolean | no | Require all users in this group to setup Two-factor authentication. |
| `two_factor_grace_period` | integer | no | Time before Two-factor authentication is enforced (in hours). |
| `project_creation_level` | string | no | Determine if developers can create projects in the group. Can be `noone` (No one), `maintainer` (Maintainers), or `developer` (Developers + Maintainers). |
| `auto_devops_enabled` | boolean | no | Default to Auto DevOps pipeline for all projects within this group. |
| `subgroup_creation_level` | integer | no | Allowed to create subgroups. Can be `owner` (Owners), or `maintainer` (Maintainers). |
| `emails_disabled` | boolean | no | Disable email notifications |
| `lfs_enabled` | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group. | | `lfs_enabled` | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group. |
| `request_access_enabled` | boolean | no | Allow users to request member access. | | `request_access_enabled` | boolean | no | Allow users to request member access. |
| `parent_id` | integer | no | The parent group ID for creating nested group. | | `parent_id` | integer | no | The parent group ID for creating nested group. |
@ -472,6 +500,13 @@ PUT /groups/:id
| `membership_lock` | boolean | no | **(STARTER)** Prevent adding new members to project membership within this group. | | `membership_lock` | boolean | no | **(STARTER)** Prevent adding new members to project membership within this group. |
| `share_with_group_lock` | boolean | no | Prevent sharing a project with another group within this group. | | `share_with_group_lock` | boolean | no | Prevent sharing a project with another group within this group. |
| `visibility` | string | no | The visibility level of the group. Can be `private`, `internal`, or `public`. | | `visibility` | string | no | The visibility level of the group. Can be `private`, `internal`, or `public`. |
| `share_with_group_lock` | boolean | no | Prevent sharing a project with another group within this group. |
| `require_two_factor_authentication` | boolean | no | Require all users in this group to setup Two-factor authentication. |
| `two_factor_grace_period` | integer | no | Time before Two-factor authentication is enforced (in hours). |
| `project_creation_level` | string | no | Determine if developers can create projects in the group. Can be `noone` (No one), `maintainer` (Maintainers), or `developer` (Developers + Maintainers). |
| `auto_devops_enabled` | boolean | no | Default to Auto DevOps pipeline for all projects within this group. |
| `subgroup_creation_level` | integer | no | Allowed to create subgroups. Can be `owner` (Owners), or `maintainer` (Maintainers). |
| `emails_disabled` | boolean | no | Disable email notifications |
| `lfs_enabled` (optional) | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group. | | `lfs_enabled` (optional) | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group. |
| `request_access_enabled` | boolean | no | Allow users to request member access. | | `request_access_enabled` | boolean | no | Allow users to request member access. |
| `file_template_project_id` | integer | no | **(PREMIUM)** The ID of a project to load custom file templates from. | | `file_template_project_id` | integer | no | **(PREMIUM)** The ID of a project to load custom file templates from. |

View file

@ -378,6 +378,13 @@ module API
class Group < BasicGroupDetails class Group < BasicGroupDetails
expose :path, :description, :visibility expose :path, :description, :visibility
expose :share_with_group_lock
expose :require_two_factor_authentication
expose :two_factor_grace_period
expose :project_creation_level_str, as: :project_creation_level
expose :auto_devops_enabled
expose :subgroup_creation_level_str, as: :subgroup_creation_level
expose :emails_disabled
expose :lfs_enabled?, as: :lfs_enabled expose :lfs_enabled?, as: :lfs_enabled
expose :avatar_url do |group, options| expose :avatar_url do |group, options|
group.avatar_url(only_path: false) group.avatar_url(only_path: false)

View file

@ -11,9 +11,15 @@ module API
optional :visibility, type: String, optional :visibility, type: String,
values: Gitlab::VisibilityLevel.string_values, values: Gitlab::VisibilityLevel.string_values,
desc: 'The visibility of the group' desc: 'The visibility of the group'
optional :share_with_group_lock, type: Boolean, desc: 'Prevent sharing a project with another group within this group'
optional :require_two_factor_authentication, type: Boolean, desc: 'Require all users in this group to setup Two-factor authentication'
optional :two_factor_grace_period, type: Integer, desc: 'Time before Two-factor authentication is enforced'
optional :project_creation_level, type: String, values: ::Gitlab::Access.project_creation_string_values, desc: 'Determine if developers can create projects in the group', as: :project_creation_level_str
optional :auto_devops_enabled, type: Boolean, desc: 'Default to Auto DevOps pipeline for all projects within this group'
optional :subgroup_creation_level, type: String, values: ::Gitlab::Access.subgroup_creation_string_values, desc: 'Allowed to create subgroups', as: :subgroup_creation_level_str
optional :emails_disabled, type: Boolean, desc: 'Disable email notifications'
optional :lfs_enabled, type: Boolean, desc: 'Enable/disable LFS for the projects in this group' optional :lfs_enabled, type: Boolean, desc: 'Enable/disable LFS for the projects in this group'
optional :request_access_enabled, type: Boolean, desc: 'Allow users to request member access' optional :request_access_enabled, type: Boolean, desc: 'Allow users to request member access'
optional :share_with_group_lock, type: Boolean, desc: 'Prevent sharing a project with another group within this group'
end end
params :optional_params_ee do params :optional_params_ee do

View file

@ -103,10 +103,22 @@ module Gitlab
} }
end end
def project_creation_string_options
{
'noone' => NO_ONE_PROJECT_ACCESS,
'maintainer' => MAINTAINER_PROJECT_ACCESS,
'developer' => DEVELOPER_MAINTAINER_PROJECT_ACCESS
}
end
def project_creation_values def project_creation_values
project_creation_options.values project_creation_options.values
end end
def project_creation_string_values
project_creation_string_options.keys
end
def project_creation_level_name(name) def project_creation_level_name(name)
project_creation_options.key(name) project_creation_options.key(name)
end end
@ -117,6 +129,21 @@ module Gitlab
s_('SubgroupCreationlevel|Maintainers') => MAINTAINER_SUBGROUP_ACCESS s_('SubgroupCreationlevel|Maintainers') => MAINTAINER_SUBGROUP_ACCESS
} }
end end
def subgroup_creation_string_options
{
'owner' => OWNER_SUBGROUP_ACCESS,
'maintainer' => MAINTAINER_SUBGROUP_ACCESS
}
end
def subgroup_creation_values
subgroup_creation_options.values
end
def subgroup_creation_string_values
subgroup_creation_string_options.keys
end
end end
def human_access def human_access

View 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

View 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

View 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

View file

@ -31,7 +31,15 @@ module Gitlab
@server = ::WEBrick::HTTPServer.new( @server = ::WEBrick::HTTPServer.new(
Port: settings.port, BindAddress: settings.address, Port: settings.port, BindAddress: settings.address,
Logger: logger, AccessLog: access_log) Logger: logger, AccessLog: access_log)
server.mount "/", Rack::Handler::WEBrick, rack_app server.mount_proc '/readiness' do |req, res|
render_probe(
::Gitlab::HealthChecks::Probes::Readiness.new, req, res)
end
server.mount_proc '/liveness' do |req, res|
render_probe(
::Gitlab::HealthChecks::Probes::Liveness.new, req, res)
end
server.mount '/', Rack::Handler::WEBrick, rack_app
server.start server.start
end end
@ -51,6 +59,14 @@ module Gitlab
run -> (env) { [404, {}, ['']] } run -> (env) { [404, {}, ['']] }
end end
end end
def render_probe(probe, req, res)
result = probe.execute
res.status = result.http_status
res.content_type = 'application/json; charset=utf-8'
res.body = result.json.to_json
end
end end
end end
end end

View file

@ -5472,6 +5472,9 @@ msgstr ""
msgid "Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled" msgid "Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled"
msgstr "" msgstr ""
msgid "Don't have an account yet?"
msgstr ""
msgid "Don't paste the private part of the GPG key. Paste the public part which begins with '-----BEGIN PGP PUBLIC KEY BLOCK-----'." msgid "Don't paste the private part of the GPG key. Paste the public part which begins with '-----BEGIN PGP PUBLIC KEY BLOCK-----'."
msgstr "" msgstr ""
@ -13081,6 +13084,12 @@ msgstr ""
msgid "Register and see your runners for this project." msgid "Register and see your runners for this project."
msgstr "" msgstr ""
msgid "Register for GitLab.com"
msgstr ""
msgid "Register now"
msgstr ""
msgid "Register with two-factor app" msgid "Register with two-factor app"
msgstr "" msgstr ""

View file

@ -259,6 +259,7 @@ module QA
module Milestone module Milestone
autoload :New, 'qa/page/project/milestone/new' autoload :New, 'qa/page/project/milestone/new'
autoload :Index, 'qa/page/project/milestone/index' autoload :Index, 'qa/page/project/milestone/index'
autoload :Show, 'qa/page/project/milestone/show'
end end
module Operations module Operations
@ -449,6 +450,7 @@ module QA
autoload :Logging, 'qa/support/page/logging' autoload :Logging, 'qa/support/page/logging'
end end
autoload :Api, 'qa/support/api' autoload :Api, 'qa/support/api'
autoload :Dates, 'qa/support/dates'
autoload :Waiter, 'qa/support/waiter' autoload :Waiter, 'qa/support/waiter'
autoload :Retrier, 'qa/support/retrier' autoload :Retrier, 'qa/support/retrier'
end end

View file

@ -17,5 +17,3 @@ module QA
end end
end end
end end
QA::Page::Project::Milestone::Index.prepend_if_ee('QA::EE::Page::Project::Milestone::Index')

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

View file

@ -24,11 +24,12 @@ describe HealthController do
it 'responds with readiness checks data' do it 'responds with readiness checks data' do
subject subject
expect(json_response['db_check']['status']).to eq('ok') expect(json_response['db_check']).to contain_exactly({ 'status' => 'ok' })
expect(json_response['cache_check']['status']).to eq('ok') expect(json_response['cache_check']).to contain_exactly({ 'status' => 'ok' })
expect(json_response['queues_check']['status']).to eq('ok') expect(json_response['queues_check']).to contain_exactly({ 'status' => 'ok' })
expect(json_response['shared_state_check']['status']).to eq('ok') expect(json_response['shared_state_check']).to contain_exactly({ 'status' => 'ok' })
expect(json_response['gitaly_check']['status']).to eq('ok') expect(json_response['gitaly_check']).to contain_exactly(
{ 'status' => 'ok', 'labels' => { 'shard' => 'default' } })
end end
it 'responds with readiness checks data when a failure happens' do it 'responds with readiness checks data when a failure happens' do
@ -37,9 +38,9 @@ describe HealthController do
subject subject
expect(json_response['redis_check']['status']).to eq('failed') expect(json_response['cache_check']).to contain_exactly({ 'status' => 'ok' })
expect(json_response['redis_check']['message']).to eq('check error') expect(json_response['redis_check']).to contain_exactly(
expect(json_response['cache_check']['status']).to eq('ok') { 'status' => 'failed', 'message' => 'check error' })
expect(response.status).to eq(503) expect(response.status).to eq(503)
expect(response.headers['X-GitLab-Custom-Error']).to eq(1) expect(response.headers['X-GitLab-Custom-Error']).to eq(1)
@ -90,7 +91,7 @@ describe HealthController do
it 'responds with liveness checks data' do it 'responds with liveness checks data' do
subject subject
expect(json_response['status']).to eq('ok') expect(json_response).to eq('status' => 'ok')
end end
end end

View file

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe 'Signup' do shared_examples 'Signup' do
include TermsHelper include TermsHelper
before do before do
@ -13,8 +13,7 @@ describe 'Signup' do
describe 'username validation', :js do describe 'username validation', :js do
before do before do
visit root_path visit new_user_registration_path
click_link 'Register'
end end
it 'does not show an error border if the username is available' do it 'does not show an error border if the username is available' do
@ -130,8 +129,7 @@ describe 'Signup' do
describe 'user\'s full name validation', :js do describe 'user\'s full name validation', :js do
before do before do
visit root_path visit new_user_registration_path
click_link 'Register'
end end
it 'does not show an error border if the user\'s fullname length is not longer than 128 characters' do it 'does not show an error border if the user\'s fullname length is not longer than 128 characters' do
@ -177,13 +175,17 @@ describe 'Signup' do
end end
it 'creates the user account and sends a confirmation email' do it 'creates the user account and sends a confirmation email' do
visit root_path visit new_user_registration_path
fill_in 'new_user_name', with: new_user.name fill_in 'new_user_name', with: new_user.name
fill_in 'new_user_username', with: new_user.username fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: new_user.email fill_in 'new_user_email', with: new_user.email
fill_in 'new_user_email_confirmation', with: new_user.email
fill_in 'new_user_password', with: new_user.password unless Feature.enabled?(:experimental_separate_sign_up_flow)
fill_in 'new_user_email_confirmation', with: new_user.email
end
fill_in 'new_user_password', with: new_user.password
expect { click_button 'Register' }.to change { User.count }.by(1) expect { click_button 'Register' }.to change { User.count }.by(1)
@ -198,13 +200,17 @@ describe 'Signup' do
end end
it 'creates the user account and sends a confirmation email' do it 'creates the user account and sends a confirmation email' do
visit root_path visit new_user_registration_path
fill_in 'new_user_name', with: new_user.name fill_in 'new_user_name', with: new_user.name
fill_in 'new_user_username', with: new_user.username fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: new_user.email fill_in 'new_user_email', with: new_user.email
fill_in 'new_user_email_confirmation', with: new_user.email
fill_in 'new_user_password', with: new_user.password unless Feature.enabled?(:experimental_separate_sign_up_flow)
fill_in 'new_user_email_confirmation', with: new_user.email
end
fill_in 'new_user_password', with: new_user.password
expect { click_button 'Register' }.to change { User.count }.by(1) expect { click_button 'Register' }.to change { User.count }.by(1)
@ -216,13 +222,17 @@ describe 'Signup' do
context "when sigining up with different cased emails" do context "when sigining up with different cased emails" do
it "creates the user successfully" do it "creates the user successfully" do
visit root_path visit new_user_registration_path
fill_in 'new_user_name', with: new_user.name fill_in 'new_user_name', with: new_user.name
fill_in 'new_user_username', with: new_user.username fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: new_user.email fill_in 'new_user_email', with: new_user.email
fill_in 'new_user_email_confirmation', with: new_user.email.capitalize
fill_in 'new_user_password', with: new_user.password unless Feature.enabled?(:experimental_separate_sign_up_flow)
fill_in 'new_user_email_confirmation', with: new_user.email.capitalize
end
fill_in 'new_user_password', with: new_user.password
click_button "Register" click_button "Register"
expect(current_path).to eq dashboard_projects_path expect(current_path).to eq dashboard_projects_path
@ -236,13 +246,17 @@ describe 'Signup' do
end end
it 'creates the user account and goes to dashboard' do it 'creates the user account and goes to dashboard' do
visit root_path visit new_user_registration_path
fill_in 'new_user_name', with: new_user.name fill_in 'new_user_name', with: new_user.name
fill_in 'new_user_username', with: new_user.username fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: new_user.email fill_in 'new_user_email', with: new_user.email
fill_in 'new_user_email_confirmation', with: new_user.email
fill_in 'new_user_password', with: new_user.password unless Feature.enabled?(:experimental_separate_sign_up_flow)
fill_in 'new_user_email_confirmation', with: new_user.email
end
fill_in 'new_user_password', with: new_user.password
click_button "Register" click_button "Register"
expect(current_path).to eq dashboard_projects_path expect(current_path).to eq dashboard_projects_path
@ -255,28 +269,34 @@ describe 'Signup' do
it "displays the errors" do it "displays the errors" do
existing_user = create(:user) existing_user = create(:user)
visit root_path visit new_user_registration_path
fill_in 'new_user_name', with: new_user.name fill_in 'new_user_name', with: new_user.name
fill_in 'new_user_username', with: new_user.username fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: existing_user.email fill_in 'new_user_email', with: existing_user.email
fill_in 'new_user_password', with: new_user.password fill_in 'new_user_password', with: new_user.password
click_button "Register" click_button "Register"
expect(current_path).to eq user_registration_path expect(current_path).to eq user_registration_path
expect(page).to have_content("errors prohibited this user from being saved")
expect(page).to have_content("Email has already been taken") if Feature.enabled?(:experimental_separate_sign_up_flow)
expect(page).to have_content("Email confirmation doesn't match") expect(page).to have_content("error prohibited this user from being saved")
expect(page).to have_content("Email has already been taken")
else
expect(page).to have_content("errors prohibited this user from being saved")
expect(page).to have_content("Email has already been taken")
expect(page).to have_content("Email confirmation doesn't match")
end
end end
it 'does not redisplay the password' do it 'does not redisplay the password' do
existing_user = create(:user) existing_user = create(:user)
visit root_path visit new_user_registration_path
fill_in 'new_user_name', with: new_user.name fill_in 'new_user_name', with: new_user.name
fill_in 'new_user_username', with: new_user.username fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: existing_user.email fill_in 'new_user_email', with: existing_user.email
fill_in 'new_user_password', with: new_user.password fill_in 'new_user_password', with: new_user.password
click_button "Register" click_button "Register"
@ -291,13 +311,17 @@ describe 'Signup' do
end end
it 'requires the user to check the checkbox' do it 'requires the user to check the checkbox' do
visit root_path visit new_user_registration_path
fill_in 'new_user_name', with: new_user.name fill_in 'new_user_name', with: new_user.name
fill_in 'new_user_username', with: new_user.username fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: new_user.email fill_in 'new_user_email', with: new_user.email
fill_in 'new_user_email_confirmation', with: new_user.email
fill_in 'new_user_password', with: new_user.password unless Feature.enabled?(:experimental_separate_sign_up_flow)
fill_in 'new_user_email_confirmation', with: new_user.email
end
fill_in 'new_user_password', with: new_user.password
click_button 'Register' click_button 'Register'
@ -306,13 +330,17 @@ describe 'Signup' do
end end
it 'asks the user to accept terms before going to the dashboard' do it 'asks the user to accept terms before going to the dashboard' do
visit root_path visit new_user_registration_path
fill_in 'new_user_name', with: new_user.name fill_in 'new_user_name', with: new_user.name
fill_in 'new_user_username', with: new_user.username fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: new_user.email fill_in 'new_user_email', with: new_user.email
fill_in 'new_user_email_confirmation', with: new_user.email
fill_in 'new_user_password', with: new_user.password unless Feature.enabled?(:experimental_separate_sign_up_flow)
fill_in 'new_user_email_confirmation', with: new_user.email
end
fill_in 'new_user_password', with: new_user.password
check :terms_opt_in check :terms_opt_in
click_button "Register" click_button "Register"
@ -321,3 +349,20 @@ describe 'Signup' do
end end
end end
end end
describe 'With original flow' do
it_behaves_like 'Signup' do
before do
stub_feature_flags(experimental_separate_sign_up_flow: false)
end
end
end
describe 'With experimental flow on GitLab.com' do
it_behaves_like 'Signup' do
before do
expect(Gitlab).to receive(:com?).and_return(true).at_least(:once)
stub_feature_flags(experimental_separate_sign_up_flow: true)
end
end
end

View 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

View 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

View file

@ -4,35 +4,42 @@ require 'spec_helper'
describe Gitlab::Metrics::Exporter::BaseExporter do describe Gitlab::Metrics::Exporter::BaseExporter do
let(:exporter) { described_class.new } let(:exporter) { described_class.new }
let(:server) { double('server') }
let(:socket) { double('socket') }
let(:log_filename) { File.join(Rails.root, 'log', 'sidekiq_exporter.log') } let(:log_filename) { File.join(Rails.root, 'log', 'sidekiq_exporter.log') }
let(:settings) { double('settings') } let(:settings) { double('settings') }
before do before do
allow(::WEBrick::HTTPServer).to receive(:new).and_return(server)
allow(server).to receive(:mount)
allow(server).to receive(:start)
allow(server).to receive(:shutdown)
allow(server).to receive(:listeners) { [socket] }
allow(socket).to receive(:close)
allow_any_instance_of(described_class).to receive(:log_filename).and_return(log_filename) allow_any_instance_of(described_class).to receive(:log_filename).and_return(log_filename)
allow_any_instance_of(described_class).to receive(:settings).and_return(settings) allow_any_instance_of(described_class).to receive(:settings).and_return(settings)
end end
describe 'when exporter is enabled' do describe 'when exporter is enabled' do
before do before do
allow(::WEBrick::HTTPServer).to receive(:new).with(
Port: anything,
BindAddress: anything,
Logger: anything,
AccessLog: anything
).and_wrap_original do |m, *args|
m.call(DoNotListen: true, Logger: args.first[:Logger])
end
allow_any_instance_of(::WEBrick::HTTPServer).to receive(:start)
allow(settings).to receive(:enabled).and_return(true) allow(settings).to receive(:enabled).and_return(true)
allow(settings).to receive(:port).and_return(3707) allow(settings).to receive(:port).and_return(8082)
allow(settings).to receive(:address).and_return('localhost') allow(settings).to receive(:address).and_return('localhost')
end end
after do
exporter.stop
end
describe 'when exporter is stopped' do describe 'when exporter is stopped' do
describe '#start' do describe '#start' do
it 'starts the exporter' do it 'starts the exporter' do
expect { exporter.start.join }.to change { exporter.thread? }.from(false).to(true) expect_any_instance_of(::WEBrick::HTTPServer).to receive(:start)
expect(server).to have_received(:start) expect { exporter.start.join }.to change { exporter.thread? }.from(false).to(true)
end end
describe 'with custom settings' do describe 'with custom settings' do
@ -45,23 +52,25 @@ describe Gitlab::Metrics::Exporter::BaseExporter do
end end
it 'starts server with port and address from settings' do it 'starts server with port and address from settings' do
exporter.start.join expect(::WEBrick::HTTPServer).to receive(:new).with(
expect(::WEBrick::HTTPServer).to have_received(:new).with(
Port: port, Port: port,
BindAddress: address, BindAddress: address,
Logger: anything, Logger: anything,
AccessLog: anything AccessLog: anything
) ).and_wrap_original do |m, *args|
m.call(DoNotListen: true, Logger: args.first[:Logger])
end
exporter.start.join
end end
end end
end end
describe '#stop' do describe '#stop' do
it "doesn't shutdown stopped server" do it "doesn't shutdown stopped server" do
expect { exporter.stop }.not_to change { exporter.thread? } expect_any_instance_of(::WEBrick::HTTPServer).not_to receive(:shutdown)
expect(server).not_to have_received(:shutdown) expect { exporter.stop }.not_to change { exporter.thread? }
end end
end end
end end
@ -73,23 +82,69 @@ describe Gitlab::Metrics::Exporter::BaseExporter do
describe '#start' do describe '#start' do
it "doesn't start running server" do it "doesn't start running server" do
expect { exporter.start.join }.not_to change { exporter.thread? } expect_any_instance_of(::WEBrick::HTTPServer).not_to receive(:start)
expect(server).to have_received(:start).once expect { exporter.start.join }.not_to change { exporter.thread? }
end end
end end
describe '#stop' do describe '#stop' do
it 'shutdowns server' do it 'shutdowns server' do
expect { exporter.stop }.to change { exporter.thread? }.from(true).to(false) expect_any_instance_of(::WEBrick::HTTPServer).to receive(:shutdown)
expect(socket).to have_received(:close) expect { exporter.stop }.to change { exporter.thread? }.from(true).to(false)
expect(server).to have_received(:shutdown)
end end
end end
end end
end end
describe 'request handling' do
using RSpec::Parameterized::TableSyntax
where(:method_class, :path, :http_status) do
Net::HTTP::Get | '/metrics' | 200
Net::HTTP::Get | '/liveness' | 200
Net::HTTP::Get | '/readiness' | 200
Net::HTTP::Get | '/' | 404
end
before do
allow(settings).to receive(:enabled).and_return(true)
allow(settings).to receive(:port).and_return(0)
allow(settings).to receive(:address).and_return('127.0.0.1')
# We want to wrap original method
# and run handling of requests
# in separate thread
allow_any_instance_of(::WEBrick::HTTPServer)
.to receive(:start).and_wrap_original do |m, *args|
Thread.new do
m.call(*args)
rescue IOError
# is raised as we close listeners
end
end
exporter.start.join
end
after do
exporter.stop
end
with_them do
let(:config) { exporter.server.config }
let(:request) { method_class.new(path) }
it 'responds with proper http_status' do
http = Net::HTTP.new(config[:BindAddress], config[:Port])
response = http.request(request)
expect(response.code).to eq(http_status.to_s)
end
end
end
describe 'when exporter is disabled' do describe 'when exporter is disabled' do
before do before do
allow(settings).to receive(:enabled).and_return(false) allow(settings).to receive(:enabled).and_return(false)
@ -97,18 +152,18 @@ describe Gitlab::Metrics::Exporter::BaseExporter do
describe '#start' do describe '#start' do
it "doesn't start" do it "doesn't start" do
expect_any_instance_of(::WEBrick::HTTPServer).not_to receive(:start)
expect(exporter.start).to be_nil expect(exporter.start).to be_nil
expect { exporter.start }.not_to change { exporter.thread? } expect { exporter.start }.not_to change { exporter.thread? }
expect(server).not_to have_received(:start)
end end
end end
describe '#stop' do describe '#stop' do
it "doesn't shutdown" do it "doesn't shutdown" do
expect { exporter.stop }.not_to change { exporter.thread? } expect_any_instance_of(::WEBrick::HTTPServer).not_to receive(:shutdown)
expect(server).not_to have_received(:shutdown) expect { exporter.stop }.not_to change { exporter.thread? }
end end
end end
end end

View file

@ -880,22 +880,6 @@ describe Group do
end end
end end
describe '#has_parent?' do
context 'when the group has a parent' do
it 'is truthy' do
group = create(:group, :nested)
expect(group.has_parent?).to be_truthy
end
end
context 'when the group has no parent' do
it 'is falsy' do
group = create(:group, parent: nil)
expect(group.has_parent?).to be_falsy
end
end
end
context 'with uploads' do context 'with uploads' do
it_behaves_like 'model with uploads', true do it_behaves_like 'model with uploads', true do
let(:model_object) { create(:group, :with_avatar) } let(:model_object) { create(:group, :with_avatar) }

View file

@ -933,4 +933,25 @@ describe Namespace do
end end
end end
end end
describe '#has_parent?' do
it 'returns true when the group has a parent' do
group = create(:group, :nested)
expect(group.has_parent?).to be_truthy
end
it 'returns true when the group has an unsaved parent' do
parent = build(:group)
group = build(:group, parent: parent)
expect(group.has_parent?).to be_truthy
end
it 'returns false when the group has no parent' do
group = create(:group, parent: nil)
expect(group.has_parent?).to be_falsy
end
end
end end

View file

@ -41,7 +41,7 @@ describe BugzillaService do
{ project_url: url, issues_url: url, new_issue_url: url } { project_url: url, issues_url: url, new_issue_url: url }
end end
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084 # this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
context 'when data are stored in properties' do context 'when data are stored in properties' do
let(:properties) { access_params.merge(title: title, description: description) } let(:properties) { access_params.merge(title: title, description: description) }
let(:service) do let(:service) do

View file

@ -55,7 +55,7 @@ describe CustomIssueTrackerService do
{ project_url: url, issues_url: url, new_issue_url: url } { project_url: url, issues_url: url, new_issue_url: url }
end end
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084 # this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
context 'when data are stored in properties' do context 'when data are stored in properties' do
let(:properties) { access_params.merge(title: title, description: description) } let(:properties) { access_params.merge(title: title, description: description) }
let(:service) do let(:service) do

View file

@ -58,7 +58,7 @@ describe GitlabIssueTrackerService do
{ project_url: url, issues_url: url, new_issue_url: url } { project_url: url, issues_url: url, new_issue_url: url }
end end
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084 # this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
context 'when data are stored in properties' do context 'when data are stored in properties' do
let(:properties) { access_params.merge(title: title, description: description) } let(:properties) { access_params.merge(title: title, description: description) }
let(:service) do let(:service) do

View file

@ -278,7 +278,7 @@ describe JiraService do
end end
end end
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084 # this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
context 'when data are stored in properties' do context 'when data are stored in properties' do
let(:properties) { data_params.merge(title: title, description: description) } let(:properties) { data_params.merge(title: title, description: description) }
let!(:service) do let!(:service) do

View file

@ -57,7 +57,7 @@ describe RedmineService do
{ project_url: url, issues_url: url, new_issue_url: url } { project_url: url, issues_url: url, new_issue_url: url }
end end
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084 # this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
context 'when data are stored in properties' do context 'when data are stored in properties' do
let(:properties) { access_params.merge(title: title, description: description) } let(:properties) { access_params.merge(title: title, description: description) }
let(:service) do let(:service) do

View file

@ -45,7 +45,7 @@ describe YoutrackService do
{ project_url: url, issues_url: url, new_issue_url: url } { project_url: url, issues_url: url, new_issue_url: url }
end end
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084 # this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
context 'when data are stored in properties' do context 'when data are stored in properties' do
let(:properties) { access_params.merge(title: title, description: description) } let(:properties) { access_params.merge(title: title, description: description) }
let(:service) do let(:service) do

View file

@ -121,7 +121,7 @@ describe Service do
end end
end end
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-foss/issues/63084 # this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
context 'when data are stored in properties' do context 'when data are stored in properties' do
let(:properties) { data_params.merge(title: title, description: description) } let(:properties) { data_params.merge(title: title, description: description) }
let!(:template) do let!(:template) do

View file

@ -1,6 +1,7 @@
require 'spec_helper' require 'spec_helper'
describe API::Groups do describe API::Groups do
include GroupAPIHelpers
include UploadHelpers include UploadHelpers
let(:user1) { create(:user, can_create_group: false) } let(:user1) { create(:user, can_create_group: false) }
@ -350,6 +351,13 @@ describe API::Groups do
expect(json_response['description']).to eq(group1.description) expect(json_response['description']).to eq(group1.description)
expect(json_response['visibility']).to eq(Gitlab::VisibilityLevel.string_level(group1.visibility_level)) expect(json_response['visibility']).to eq(Gitlab::VisibilityLevel.string_level(group1.visibility_level))
expect(json_response['avatar_url']).to eq(group1.avatar_url(only_path: false)) expect(json_response['avatar_url']).to eq(group1.avatar_url(only_path: false))
expect(json_response['share_with_group_lock']).to eq(group1.share_with_group_lock)
expect(json_response['require_two_factor_authentication']).to eq(group1.require_two_factor_authentication)
expect(json_response['two_factor_grace_period']).to eq(group1.two_factor_grace_period)
expect(json_response['auto_devops_enabled']).to eq(group1.auto_devops_enabled)
expect(json_response['emails_disabled']).to eq(group1.emails_disabled)
expect(json_response['project_creation_level']).to eq('maintainer')
expect(json_response['subgroup_creation_level']).to eq('maintainer')
expect(json_response['web_url']).to eq(group1.web_url) expect(json_response['web_url']).to eq(group1.web_url)
expect(json_response['request_access_enabled']).to eq(group1.request_access_enabled) expect(json_response['request_access_enabled']).to eq(group1.request_access_enabled)
expect(json_response['full_name']).to eq(group1.full_name) expect(json_response['full_name']).to eq(group1.full_name)
@ -485,11 +493,30 @@ describe API::Groups do
context 'when authenticated as the group owner' do context 'when authenticated as the group owner' do
it 'updates the group' do it 'updates the group' do
put api("/groups/#{group1.id}", user1), params: { name: new_group_name, request_access_enabled: true } put api("/groups/#{group1.id}", user1), params: {
name: new_group_name,
request_access_enabled: true,
project_creation_level: "noone",
subgroup_creation_level: "maintainer"
}
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(json_response['name']).to eq(new_group_name) expect(json_response['name']).to eq(new_group_name)
expect(json_response['description']).to eq('')
expect(json_response['visibility']).to eq('public')
expect(json_response['share_with_group_lock']).to eq(false)
expect(json_response['require_two_factor_authentication']).to eq(false)
expect(json_response['two_factor_grace_period']).to eq(48)
expect(json_response['auto_devops_enabled']).to eq(nil)
expect(json_response['emails_disabled']).to eq(nil)
expect(json_response['project_creation_level']).to eq("noone")
expect(json_response['subgroup_creation_level']).to eq("maintainer")
expect(json_response['request_access_enabled']).to eq(true) expect(json_response['request_access_enabled']).to eq(true)
expect(json_response['parent_id']).to eq(nil)
expect(json_response['projects']).to be_an Array
expect(json_response['projects'].length).to eq(2)
expect(json_response['shared_projects']).to be_an Array
expect(json_response['shared_projects'].length).to eq(0)
end end
it 'returns 404 for a non existing group' do it 'returns 404 for a non existing group' do
@ -864,7 +891,9 @@ describe API::Groups do
describe "POST /groups" do describe "POST /groups" do
context "when authenticated as user without group permissions" do context "when authenticated as user without group permissions" do
it "does not create group" do it "does not create group" do
post api("/groups", user1), params: attributes_for(:group) group = attributes_for_group_api
post api("/groups", user1), params: group
expect(response).to have_gitlab_http_status(403) expect(response).to have_gitlab_http_status(403)
end end
@ -896,7 +925,7 @@ describe API::Groups do
context "when authenticated as user with group permissions" do context "when authenticated as user with group permissions" do
it "creates group" do it "creates group" do
group = attributes_for(:group, { request_access_enabled: false }) group = attributes_for_group_api request_access_enabled: false
post api("/groups", user3), params: group post api("/groups", user3), params: group
@ -911,7 +940,7 @@ describe API::Groups do
it "creates a nested group" do it "creates a nested group" do
parent = create(:group) parent = create(:group)
parent.add_owner(user3) parent.add_owner(user3)
group = attributes_for(:group, { parent_id: parent.id }) group = attributes_for_group_api parent_id: parent.id
post api("/groups", user3), params: group post api("/groups", user3), params: group

View file

@ -634,10 +634,47 @@ describe API::Users do
end end
describe "GET /users/sign_up" do describe "GET /users/sign_up" do
it "redirects to sign in page" do context 'when experimental_separate_sign_up_flow is active' do
get "/users/sign_up" before do
expect(response).to have_gitlab_http_status(302) stub_feature_flags(experimental_separate_sign_up_flow: true)
expect(response).to redirect_to(new_user_session_path) end
context 'on gitlab.com' do
before do
allow(::Gitlab).to receive(:com?).and_return(true)
end
it "shows sign up page" do
get "/users/sign_up"
expect(response).to have_gitlab_http_status(200)
expect(response).to render_template(:new)
end
end
context 'not on gitlab.com' do
before do
allow(::Gitlab).to receive(:com?).and_return(false)
end
it "redirects to sign in page" do
get "/users/sign_up"
expect(response).to have_gitlab_http_status(302)
expect(response).to redirect_to(new_user_session_path(anchor: 'register-pane'))
end
end
end
context 'when experimental_separate_sign_up_flow is not active' do
before do
allow(::Gitlab).to receive(:com?).and_return(true)
stub_feature_flags(experimental_separate_sign_up_flow: false)
end
it "redirects to sign in page" do
get "/users/sign_up"
expect(response).to have_gitlab_http_status(302)
expect(response).to redirect_to(new_user_session_path(anchor: 'register-pane'))
end
end end
end end

View 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