Merge branch 'master' into sh-add-object-storage-qa

* master: (31 commits)
This commit is contained in:
Grzegorz Bizon 2018-08-21 11:12:23 +02:00
commit 6232c26ac7
131 changed files with 1775 additions and 786 deletions

View File

@ -739,7 +739,7 @@ karma:
- chrome_debug.log
- coverage-javascript/
codequality:
code_quality:
<<: *dedicated-no-docs-no-db-pull-cache-job
image: docker:stable
allow_failure: true
@ -757,9 +757,13 @@ codequality:
script:
# Extract "MAJOR.MINOR" from CI_SERVER_VERSION and generate "MAJOR-MINOR-stable" for Security Products
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
- docker run --env SOURCE_CODE="$PWD" --volume "$PWD":/code --volume /var/run/docker.sock:/var/run/docker.sock "registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code
- docker run
--env SOURCE_CODE="$PWD"
--volume "$PWD":/code
--volume /var/run/docker.sock:/var/run/docker.sock
"registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code
artifacts:
paths: [codeclimate.json]
paths: [gl-code-quality-report.json]
expire_in: 1 week
sast:

View File

@ -64,11 +64,11 @@ As of July 2018, all the documentation for contributing to the GitLab project ha
## Contribute to GitLab
For a first-time step-by-step guide to the contribution process, see
["Contributing to GitLab"](https://about.gitlab.com/contributing/).
Thank you for your interest in contributing to GitLab. This guide details how
to contribute to GitLab in a way that is efficient for everyone.
to contribute to GitLab in a way that is easy for everyone.
For a first-time step-by-step guide to the contribution process, please see
["Contributing to GitLab"](https://about.gitlab.com/contributing/).
Looking for something to work on? Look for issues with the label [Accepting Merge Requests](#i-want-to-contribute).
@ -77,10 +77,10 @@ source edition, and GitLab Enterprise Edition (EE) which is our commercial
edition. Throughout this guide you will see references to CE and EE for
abbreviation.
If you have read this guide and want to know how the GitLab [core team]
If you want to know how the GitLab [core team]
operates please see [the GitLab contributing process](PROCESS.md).
- [GitLab Inc engineers should refer to the engineering workflow document](https://about.gitlab.com/handbook/engineering/workflow/)
[GitLab Inc engineers should refer to the engineering workflow document](https://about.gitlab.com/handbook/engineering/workflow/)
## Security vulnerability disclosure

View File

@ -1 +1 @@
0.117.1
0.117.2

View File

@ -214,9 +214,6 @@ gem 'jira-ruby', '~> 1.4'
# Flowdock integration
gem 'gitlab-flowdock-git-hook', '~> 1.0.1'
# Gemnasium integration
gem 'gemnasium-gitlab-service', '~> 0.2'
# Slack integration
gem 'slack-notifier', '~> 1.5.1'
@ -423,7 +420,7 @@ group :ed25519 do
end
# Gitaly GRPC client
gem 'gitaly-proto', '~> 0.112.0', require: 'gitaly'
gem 'gitaly-proto', '~> 0.113.0', require: 'gitaly'
gem 'grpc', '~> 1.11.0'
# Locked until https://github.com/google/protobuf/issues/4210 is closed

View File

@ -269,8 +269,6 @@ GEM
fuubar (2.2.0)
rspec-core (~> 3.0)
ruby-progressbar (~> 1.4)
gemnasium-gitlab-service (0.2.6)
rugged (~> 0.21)
gemojione (3.3.0)
json
get_process_mem (0.2.0)
@ -284,7 +282,7 @@ GEM
gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gitaly-proto (0.112.0)
gitaly-proto (0.113.0)
google-protobuf (~> 3.1)
grpc (~> 1.10)
github-linguist (5.3.3)
@ -1040,12 +1038,11 @@ DEPENDENCIES
font-awesome-rails (~> 4.7)
foreman (~> 0.84.0)
fuubar (~> 2.2.0)
gemnasium-gitlab-service (~> 0.2)
gemojione (~> 3.3)
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
gitaly-proto (~> 0.112.0)
gitaly-proto (~> 0.113.0)
github-linguist (~> 5.3.3)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-gollum-lib (~> 4.2)

View File

@ -272,8 +272,6 @@ GEM
fuubar (2.2.0)
rspec-core (~> 3.0)
ruby-progressbar (~> 1.4)
gemnasium-gitlab-service (0.2.6)
rugged (~> 0.21)
gemojione (3.3.0)
json
get_process_mem (0.2.0)
@ -287,7 +285,7 @@ GEM
gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gitaly-proto (0.112.0)
gitaly-proto (0.113.0)
google-protobuf (~> 3.1)
grpc (~> 1.10)
github-linguist (5.3.3)
@ -1052,12 +1050,11 @@ DEPENDENCIES
font-awesome-rails (~> 4.7)
foreman (~> 0.84.0)
fuubar (~> 2.2.0)
gemnasium-gitlab-service (~> 0.2)
gemojione (~> 3.3)
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
gitaly-proto (~> 0.112.0)
gitaly-proto (~> 0.113.0)
github-linguist (~> 5.3.3)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-gollum-lib (~> 4.2)
@ -1216,4 +1213,4 @@ DEPENDENCIES
wikicloth (= 0.8.1)
BUNDLED WITH
1.16.2
1.16.3

View File

@ -58,7 +58,7 @@ You can access a new installation with the login **`root`** and password **`5ive
## Contributing
GitLab is an open source project and we are very happy to accept community contributions. Please refer to [CONTRIBUTING.md](/CONTRIBUTING.md) for details.
GitLab is an open source project and we are very happy to accept community contributions. Please refer to [Contributing to GitLab page](https://about.gitlab.com/contributing/) for more details.
## Licensing
@ -66,7 +66,7 @@ GitLab Community Edition (CE) is available freely under the MIT Expat license.
All third party components incorporated into the GitLab Software are licensed under the original license provided by the owner of the applicable component.
All Documentation content that resides under the doc/ directory of this repository is licensed under Creative Commons: CC BY-SA 4.0.
All Documentation content that resides under the `doc/` directory of this repository is licensed under Creative Commons: CC BY-SA 4.0.
## Install a development environment

View File

@ -172,7 +172,7 @@ export default {
<template>
<div
v-if="!showEmptyState"
class="prometheus-graphs prepend-top-10"
class="prometheus-graphs prepend-top-default"
>
<div class="environments d-flex align-items-center">
{{ s__('Metrics|Environment') }}

View File

@ -25,7 +25,7 @@
&.svg-#{$width} {
img,
svg {
width: #{$width + 'px'};
max-width: #{$width + 'px'};
}
}
}

View File

@ -1,67 +1,39 @@
class AutocompleteController < ApplicationController
AWARD_EMOJI_MAX = 100
skip_before_action :authenticate_user!, only: [:users, :award_emojis]
before_action :load_project, only: [:users]
before_action :load_group, only: [:users]
def users
@users = AutocompleteUsersFinder.new(params: params, current_user: current_user, project: @project, group: @group).execute
project = Autocomplete::ProjectFinder
.new(current_user, params)
.execute
render json: UserSerializer.new.represent(@users)
group = Autocomplete::GroupFinder
.new(current_user, project, params)
.execute
users = Autocomplete::UsersFinder
.new(params: params, current_user: current_user, project: project, group: group)
.execute
render json: UserSerializer.new.represent(users)
end
def user
@user = User.find(params[:id])
render json: UserSerializer.new.represent(@user)
user = UserFinder.new(params).execute!
render json: UserSerializer.new.represent(user)
end
# Displays projects to use for the dropdown when moving a resource from one
# project to another.
def projects
project = Project.find_by_id(params[:project_id])
projects = projects_finder.execute(project, search: params[:search], offset_id: params[:offset_id])
projects = Autocomplete::MoveToProjectFinder
.new(current_user, params)
.execute
render json: projects.to_json(only: [:id, :name_with_namespace], methods: :name_with_namespace)
render json: MoveToProjectSerializer.new.represent(projects)
end
def award_emojis
emoji_with_count = AwardEmoji
.limit(AWARD_EMOJI_MAX)
.where(user: current_user)
.group(:name)
.order('count_all DESC, name ASC')
.count
# Transform from hash to array to guarantee json order
# e.g. { 'thumbsup' => 2, 'thumbsdown' = 1 }
# => [{ name: 'thumbsup' }, { name: 'thumbsdown' }]
render json: emoji_with_count.map { |k, v| { name: k } }
end
private
def load_group
@group ||= begin
if @project.blank? && params[:group_id].present?
group = Group.find(params[:group_id])
return render_404 unless can?(current_user, :read_group, group)
group
end
end
end
def load_project
@project ||= begin
if params[:project_id].present?
project = Project.find(params[:project_id])
return render_404 unless can?(current_user, :read_project, project)
project
end
end
end
def projects_finder
MoveToProjectFinder.new(current_user)
render json: AwardedEmojiFinder.new(current_user).execute
end
end

View File

@ -0,0 +1,37 @@
# frozen_string_literal: true
module Autocomplete
# Finder for retrieving a group to use for autocomplete data sources.
class GroupFinder
attr_reader :current_user, :project, :group_id
# current_user - The currently logged in user, if any.
# project - The Project (if any) to use for the autocomplete data sources.
# params - A Hash containing parameters to use for finding the project.
#
# The following parameters are supported:
#
# * group_id: The ID of the group to find.
def initialize(current_user = nil, project = nil, params = {})
@current_user = current_user
@project = project
@group_id = params[:group_id]
end
# Attempts to find a Group based on the current group ID.
def execute
return unless project.blank? && group_id.present?
group = Group.find(group_id)
# This removes the need for using `return render_404` and similar patterns
# in controllers that use this finder.
unless Ability.allowed?(current_user, :read_group, group)
raise ActiveRecord::RecordNotFound
.new("Could not find a Group with ID #{group_id}")
end
group
end
end
end

View File

@ -0,0 +1,35 @@
# frozen_string_literal: true
module Autocomplete
# Finder that retrieves a list of projects that an issue can be moved to.
class MoveToProjectFinder
attr_reader :current_user, :search, :project_id, :offset_id
# current_user - The User object of the user that wants to view the list of
# projects.
#
# params - A Hash containing additional parameters to set.
#
# The following parameters can be set (as Symbols):
#
# * search: An optional search query to apply to the list of projects.
# * project_id: The ID of a project to exclude from the returned relation.
# * offset_id: The ID of a project to use for pagination. When given, only
# projects with a lower ID are included in the list.
def initialize(current_user, params = {})
@current_user = current_user
@search = params[:search]
@project_id = params[:project_id]
@offset_id = params[:offset_id]
end
def execute
current_user
.projects_where_can_admin_issues
.optionally_search(search)
.excluding_project(project_id)
.paginate_in_descending_order_using_id(before: offset_id)
.eager_load_namespace_and_owner
end
end
end

View File

@ -0,0 +1,35 @@
# frozen_string_literal: true
module Autocomplete
# Finder for retrieving a project to use for autocomplete data sources.
class ProjectFinder
attr_reader :current_user, :project_id
# current_user - The currently logged in user, if any.
# params - A Hash containing parameters to use for finding the project.
#
# The following parameters are supported:
#
# * project_id: The ID of the project to find.
def initialize(current_user = nil, params = {})
@current_user = current_user
@project_id = params[:project_id]
end
# Attempts to find a Project based on the current project ID.
def execute
return if project_id.blank?
project = Project.find(project_id)
# This removes the need for using `return render_404` and similar patterns
# in controllers that use this finder.
unless Ability.allowed?(current_user, :read_project, project)
raise ActiveRecord::RecordNotFound
.new("Could not find a Project with ID #{project_id}")
end
project
end
end
end

View File

@ -0,0 +1,85 @@
# frozen_string_literal: true
module Autocomplete
class UsersFinder
# The number of users to display in the results is hardcoded to 20, and
# pagination is not supported. This ensures that performance remains
# consistent and removes the need for implementing keyset pagination to
# ensure good performance.
LIMIT = 20
attr_reader :current_user, :project, :group, :search, :skip_users,
:author_id, :todo_filter, :todo_state_filter,
:filter_by_current_user
def initialize(params:, current_user:, project:, group:)
@current_user = current_user
@project = project
@group = group
@search = params[:search]
@skip_users = params[:skip_users]
@author_id = params[:author_id]
@todo_filter = params[:todo_filter]
@todo_state_filter = params[:todo_state_filter]
@filter_by_current_user = params[:current_user]
end
def execute
items = limited_users
if search.blank?
# Include current user if available to filter by "Me"
items.unshift(current_user) if prepend_current_user?
if prepend_author? && (author = User.find_by_id(author_id))
items.unshift(author)
end
end
items.uniq
end
private
# Returns the users based on the input parameters, as an Array.
#
# This method is separate so it is easier to extend in EE.
def limited_users
# When changing the order of these method calls, make sure that
# reorder_by_name() is called _before_ optionally_search(), otherwise
# reorder_by_name will break the ORDER BY applied in optionally_search().
find_users
.active
.reorder_by_name
.optionally_search(search)
.where_not_in(skip_users)
.limit_to_todo_authors(
user: current_user,
with_todos: todo_filter,
todo_state: todo_state_filter
)
.limit(LIMIT)
.to_a
end
def prepend_current_user?
filter_by_current_user.present? && current_user
end
def prepend_author?
author_id.present? && current_user
end
def find_users
if project
project.authorized_users.union_with_user(author_id)
elsif group
group.users_with_parents
elsif current_user
User.all
else
User.none
end
end
end
end

View File

@ -1,68 +0,0 @@
class AutocompleteUsersFinder
# The number of users to display in the results is hardcoded to 20, and
# pagination is not supported. This ensures that performance remains
# consistent and removes the need for implementing keyset pagination to ensure
# good performance.
LIMIT = 20
attr_reader :current_user, :project, :group, :search, :skip_users,
:author_id, :params
def initialize(params:, current_user:, project:, group:)
@current_user = current_user
@project = project
@group = group
@search = params[:search]
@skip_users = params[:skip_users]
@author_id = params[:author_id]
@params = params
end
def execute
items = find_users
items = items.active
items = items.reorder(:name)
items = items.search(search) if search.present?
items = items.where.not(id: skip_users) if skip_users.present?
items = items.limit(LIMIT)
if params[:todo_filter].present? && current_user
items = items.todo_authors(current_user.id, params[:todo_state_filter])
end
if search.blank?
# Include current user if available to filter by "Me"
if params[:current_user].present? && current_user
items = [current_user, *items].uniq
end
if author_id.present? && current_user
author = User.find_by_id(author_id)
items = [author, *items].uniq if author
end
end
items
end
private
def find_users
return users_from_project if project
return group.users_with_parents if group
return User.all if current_user
User.none
end
def users_from_project
if author_id.present?
union = Gitlab::SQL::Union
.new([project.authorized_users, User.where(id: author_id)])
User.from("(#{union.to_sql}) #{User.table_name}")
else
project.authorized_users
end
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
# Class for retrieving information about emoji awarded _by_ a particular user.
class AwardedEmojiFinder
attr_reader :current_user
# current_user - The User to generate the data for.
def initialize(current_user = nil)
@current_user = current_user
end
def execute
return [] unless current_user
# We want the resulting data set to be an Array containing the emoji names
# in descending order, based on how often they were awarded.
AwardEmoji
.award_counts_for_user(current_user)
.map { |name, _| { name: name } }
end
end

View File

@ -1,21 +0,0 @@
class MoveToProjectFinder
PAGE_SIZE = 50
def initialize(user)
@user = user
end
def execute(from_project, search: nil, offset_id: nil)
projects = @user.projects_where_can_admin_issues
projects = projects.search(search) if search.present?
projects = projects.excluding_project(from_project)
projects = projects.order_id_desc
# infinite scroll using offset
projects = projects.where('projects.id < ?', offset_id) if offset_id.present?
projects = projects.limit(PAGE_SIZE)
# to ask for Project#name_with_namespace
projects.includes(namespace: :owner)
end
end

View File

@ -0,0 +1,26 @@
# frozen_string_literal: true
# A simple finding for obtaining a single User.
#
# While using `User.find_by` directly is straightforward, it can lead to a lot
# of code duplication. Sometimes we just want to find a user by an ID, other
# times we may want to exclude blocked user. By using this finder (and extending
# it whenever necessary) we can keep this logic in one place.
class UserFinder
attr_reader :params
def initialize(params)
@params = params
end
# Tries to find a User, returning nil if none could be found.
def execute
User.find_by(id: params[:id])
end
# Tries to find a User, raising a `ActiveRecord::RecordNotFound` if it could
# not be found.
def execute!
User.find(params[:id])
end
end

View File

@ -28,6 +28,23 @@ class AwardEmoji < ActiveRecord::Base
.where('name IN (?) AND awardable_type = ? AND awardable_id IN (?)', [DOWNVOTE_NAME, UPVOTE_NAME], type, ids)
.group('name', 'awardable_id')
end
# Returns the top 100 emoji awarded by the given user.
#
# The returned value is a Hash mapping emoji names to the number of times
# they were awarded:
#
# { 'thumbsup' => 2, 'thumbsdown' => 1 }
#
# user - The User to get the awards for.
# limt - The maximum number of emoji to return.
def award_counts_for_user(user, limit = 100)
limit(limit)
.where(user: user)
.group(:name)
.order('count_all DESC, name ASC')
.count
end
end
def downvote?

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
module OptionallySearch
extend ActiveSupport::Concern
module ClassMethods
def search(*)
raise(
NotImplementedError,
'Your model must implement the "search" class method'
)
end
# Optionally limits a result set to those matching the given search query.
def optionally_search(query = nil)
query.present? ? search(query) : all
end
end
end

View File

@ -28,6 +28,7 @@ class Project < ActiveRecord::Base
include WithUploads
include BatchDestroyDependentAssociations
include FeatureGate
include OptionallySearch
extend Gitlab::Cache::RequestCache
extend Gitlab::ConfigHelper
@ -140,7 +141,6 @@ class Project < ActiveRecord::Base
has_one :flowdock_service
has_one :assembla_service
has_one :asana_service
has_one :gemnasium_service
has_one :mattermost_slash_commands_service
has_one :mattermost_service
has_one :slack_slash_commands_service
@ -384,6 +384,26 @@ class Project < ActiveRecord::Base
only_integer: true,
message: 'needs to be beetween 10 minutes and 1 month' }
# Paginates a collection using a `WHERE id < ?` condition.
#
# before - A project ID to use for filtering out projects with an equal or
# greater ID. If no ID is given, all projects are included.
#
# limit - The maximum number of rows to include.
def self.paginate_in_descending_order_using_id(
before: nil,
limit: Kaminari.config.default_per_page
)
relation = order_id_desc.limit(limit)
relation = relation.where('projects.id < ?', before) if before
relation
end
def self.eager_load_namespace_and_owner
includes(namespace: :owner)
end
# Returns a collection of projects that is either public or visible to the
# logged in user.
def self.public_or_visible_to_user(user = nil)

View File

@ -1,62 +0,0 @@
# frozen_string_literal: true
require "gemnasium/gitlab_service"
class GemnasiumService < Service
prop_accessor :token, :api_key
validates :token, :api_key, presence: true, if: :activated?
validate :deprecation_validation
def title
'Gemnasium'
end
def description
'Gemnasium monitors your project dependencies and alerts you about updates and security vulnerabilities.'
end
def self.to_param
'gemnasium'
end
def fields
[
{ type: 'text', name: 'api_key', placeholder: 'Your personal API KEY on gemnasium.com ', required: true },
{ type: 'text', name: 'token', placeholder: 'The project\'s slug on gemnasium.com', required: true }
]
end
def self.supported_events
%w(push)
end
def deprecated?
true
end
def deprecation_message
"Gemnasium has been acquired by GitLab in January 2018. Since May 15, 2018, the service provided by Gemnasium is no longer available."
end
def deprecation_validation
errors[:base] << deprecation_message
end
def execute(data)
return unless supported_events.include?(data[:object_kind])
# Gitaly: this class will be removed https://gitlab.com/gitlab-org/gitlab-ee/issues/6010
repo_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
project.repository.path_to_repo
end
Gemnasium::GitlabService.execute(
ref: data[:ref],
before: data[:before],
after: data[:after],
token: token,
api_key: api_key,
repo: repo_path
)
end
end

View File

@ -19,6 +19,7 @@ class User < ActiveRecord::Base
include BulkMemberAccessLoad
include BlocksJsonSerialization
include WithUploads
include OptionallySearch
DEFAULT_NOTIFICATION_LEVEL = :participating
@ -253,11 +254,41 @@ class User < ActiveRecord::Base
scope :external, -> { where(external: true) }
scope :active, -> { with_state(:active).non_internal }
scope :without_projects, -> { joins('LEFT JOIN project_authorizations ON users.id = project_authorizations.user_id').where(project_authorizations: { user_id: nil }) }
scope :todo_authors, ->(user_id, state) { where(id: Todo.where(user_id: user_id, state: state).select(:author_id)) }
scope :order_recent_sign_in, -> { reorder(Gitlab::Database.nulls_last_order('current_sign_in_at', 'DESC')) }
scope :order_oldest_sign_in, -> { reorder(Gitlab::Database.nulls_last_order('current_sign_in_at', 'ASC')) }
scope :confirmed, -> { where.not(confirmed_at: nil) }
# Limits the users to those that have TODOs, optionally in the given state.
#
# user - The user to get the todos for.
#
# with_todos - If we should limit the result set to users that are the
# authors of todos.
#
# todo_state - An optional state to require the todos to be in.
def self.limit_to_todo_authors(user: nil, with_todos: false, todo_state: nil)
if user && with_todos
where(id: Todo.where(user: user, state: todo_state).select(:author_id))
else
all
end
end
# Returns a relation that optionally includes the given user.
#
# user_id - The ID of the user to include.
def self.union_with_user(user_id = nil)
if user_id.present?
union = Gitlab::SQL::Union.new([all, User.unscoped.where(id: user_id)])
# We use "unscoped" here so that any inner conditions are not repeated for
# the outer query, which would be redundant.
User.unscoped.from("(#{union.to_sql}) #{User.table_name}")
else
all
end
end
def self.with_two_factor_indistinct
joins("LEFT OUTER JOIN u2f_registrations AS u2f ON u2f.user_id = users.id")
.where("u2f.id IS NOT NULL OR users.otp_required_for_login = ?", true)
@ -365,6 +396,18 @@ class User < ActiveRecord::Base
).reorder(order % { query: ActiveRecord::Base.connection.quote(query) }, :name)
end
# Limits the result set to users _not_ in the given query/list of IDs.
#
# users - The list of users to ignore. This can be an
# `ActiveRecord::Relation`, or an Array.
def where_not_in(users = nil)
users ? where.not(id: users) : all
end
def reorder_by_name
reorder(:name)
end
# searches user by given pattern
# it compares name, email, username fields and user's secondary emails with given pattern
# This method uses ILIKE on PostgreSQL and LIKE on MySQL.

View File

@ -0,0 +1,6 @@
# frozen_string_literal: true
class MoveToProjectEntity < Grape::Entity
expose :id
expose :name_with_namespace
end

View File

@ -0,0 +1,5 @@
# frozen_string_literal: true
class MoveToProjectSerializer < BaseSerializer
entity MoveToProjectEntity
end

View File

@ -49,7 +49,7 @@
= submit_tag 'Search', class: 'btn'
.float-right.light
Runners with last contact more than a minute ago: #{@active_runners_cnt}
Runners currently online: #{@active_runners_cnt}
%br

View File

@ -2,11 +2,4 @@
- page_title "Metrics for environment", @environment.name
.prometheus-container{ class: container_class }
.top-area
.row
.col-sm-6
%h3
Environment:
= link_to @environment.name, environment_path(@environment)
#prometheus-graphs{ data: metrics_data(@project, @environment) }

View File

@ -13,4 +13,4 @@
%h4.underlined-title Available specific runners
%ul.bordered-list.available-specific-runners
= render partial: 'projects/runners/runner', collection: @assignable_runners, as: :runner
= paginate @assignable_runners, theme: "gitlab"
= paginate @assignable_runners, theme: "gitlab", :params => { :anchor => '#js-runners-settings' }

View File

@ -0,0 +1,5 @@
---
title: Does not collapse runners section when using pagination
merge_request:
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: "#47845 Add failure_reason to job webhook"
merge_request: 21143
author: matemaciek
type: added

View File

@ -0,0 +1,5 @@
---
title: Fixes SVGs for empty states in job page overflowing on mobile
merge_request:
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Allow spaces in wiki markdown links when using CommonMark
merge_request: 20417
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Fix merge requests not showing any diff files for big patches
merge_request: 21125
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Remove redundant header from metrics page
merge_request: 21282
author:
type: changed

View File

@ -0,0 +1,5 @@
---
title: Remove Gemnasium service
merge_request: 21185
author:
type: removed

View File

@ -0,0 +1,5 @@
---
title: 'Events API now requires the read_user or api scope.'
merge_request: 20627
author: Warren Parad
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Clarify current runners online text
merge_request: 21151
author: Ben Bodenmiller
type: other

View File

@ -25,11 +25,11 @@ for each GitLab application server in your environment.
options. Here is an example snippet to add to `/etc/fstab`:
```
10.1.0.1:/var/opt/gitlab/.ssh /var/opt/gitlab/.ssh nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
10.1.0.1:/var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/uploads nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
10.1.0.1:/var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-rails/shared nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
10.1.0.1:/var/opt/gitlab/gitlab-ci/builds /var/opt/gitlab/gitlab-ci/builds nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
10.1.0.1:/var/opt/gitlab/git-data /var/opt/gitlab/git-data nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
10.1.0.1:/var/opt/gitlab/.ssh /var/opt/gitlab/.ssh nfs4 defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
10.1.0.1:/var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/uploads nfs4 defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
10.1.0.1:/var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-rails/shared nfs4 defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
10.1.0.1:/var/opt/gitlab/gitlab-ci/builds /var/opt/gitlab/gitlab-ci/builds nfs4 defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
10.1.0.1:/var/opt/gitlab/git-data /var/opt/gitlab/git-data nfs4 defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
```
1. Create the shared directories. These may be different depending on your NFS

View File

@ -42,7 +42,7 @@ Registry, etc.
## Hashed Storage
> **Warning:** Hashed storage is in **Beta**. For the latest updates, check the
> associated [issue](https://gitlab.com/gitlab-com/infrastructure/issues/2821)
> associated [issue](https://gitlab.com/gitlab-com/infrastructure/issues/3542)
> and please report any problems you encounter.
Hashed Storage is the new storage behavior we are rolling out with 10.0. Instead

View File

@ -48,9 +48,11 @@ GitLab removes events older than 1 year from the events table for performance re
## List currently authenticated user's events
>**Note:** This endpoint was introduced in GitLab 9.3.
>**Notes:**
> This endpoint was introduced in GitLab 9.3.
> `read_user` access was introduced in GitLab 11.3.
Get a list of events for the authenticated user.
Get a list of events for the authenticated user. Scope `read_user` or `api` is required.
```
GET /events
@ -119,9 +121,11 @@ Example response:
### Get user contribution events
>**Note:** Documentation was formerly located in the [Users API pages][users-api].
>**Notes:**
> Documentation was formerly located in the [Users API pages][users-api].
> `read_user` access was introduced in GitLab 11.3.
Get the contribution events for the specified user, sorted from newest to oldest.
Get the contribution events for the specified user, sorted from newest to oldest. Scope `read_user` or `api` is required.
```
GET /users/:id/events

View File

@ -401,48 +401,6 @@ Get Flowdock service settings for a project.
GET /projects/:id/services/flowdock
```
## Gemnasium
Gemnasium monitors your project dependencies and alerts you about updates and security vulnerabilities.
CAUTION: **Warning:**
Gemnasium service integration has been deprecated in GitLab 11.0. Gemnasium has been
[acquired by GitLab](https://about.gitlab.com/press/releases/2018-01-30-gemnasium-acquisition.html)
in January 2018 and since May 15, 2018, the service provided by Gemnasium is no longer available.
You can [migrate from Gemnasium to GitLab](https://docs.gitlab.com/ee/user/project/import/gemnasium.html)
to keep monitoring your dependencies.
### Create/Edit Gemnasium service
Set Gemnasium service for a project.
```
PUT /projects/:id/services/gemnasium
```
Parameters:
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `api_key` | string | true | Your personal API KEY on gemnasium.com |
| `token` | string | true | The project's slug on gemnasium.com |
### Delete Gemnasium service
Delete Gemnasium service for a project.
```
DELETE /projects/:id/services/gemnasium
```
### Get Gemnasium service settings
Get Gemnasium service settings for a project.
```
GET /projects/:id/services/gemnasium
```
## Hangouts Chat
Google GSuite team collaboration tool.

View File

@ -76,6 +76,8 @@ learn how to leverage its potential even more.
- [Trigger pipelines on a schedule](../user/project/pipelines/schedules.md)
- [Kubernetes clusters](../user/project/clusters/index.md) - Integrate one or
more Kubernetes clusters to your project
- [Interactive web terminal](interactive_web_terminal/index.md) - Open an interactive
web terminal to debug the running jobs
## GitLab CI/CD for Docker

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@ -0,0 +1,52 @@
# Getting started with interactive web terminals
> Introduced in GitLab 11.3.
CAUTION: **Warning:**
Interactive web terminals are in beta, so they might not work properly and
lack features. For more information [follow issue #25990](https://gitlab.com/gitlab-org/gitlab-ce/issues/25990).
Interactive web terminals give the user access to a terminal in GitLab for
running one-of commands for their CI pipeline.
NOTE: **Note:**
This is not available for the shared Runners on GitLab.com.
To make use of this feature, you need to provide your
[own Runner](https://docs.gitlab.com/runner/install/) and properly
[configure it](#configuration).
## Configuration
Two things need to be configured for the interactive web terminal to work:
- The Runner needs to have [`[session_server]` configured
properly][session-server]
- Web terminals need to be
[enabled](../../administration/integration/terminal.md#enabling-and-disabling-terminal-support)
## Debugging a running job
NOTE: **Note:** Not all executors are
[supported](https://docs.gitlab.com/runner/executors/#compatibility-chart).
Sometimes, when a job is running, things don't go as you would expect, and it
would be helpful if one can have a shell to aid debugging. When a job is
running, on the right panel you can see a button `debug` that will open the terminal
for the current job.
![Example of job running with terminal
available](img/interactive_web_terminal_running_job.png)
When clicked, a new tab will open to the terminal page where you can access
the terminal and type commands like a normal shell.
![terminal of the job](img/interactive_web_terminal_page.png)
If you have the terminal open and the job has finished with its tasks, the
terminal will block the job from finishing for the duration configured in
[`[session_server].terminal_max_retention_time`][session-server] until you
close the terminal window.
![finished job with terminal open](img/finished_job_with_terminal_open.png)
[session-server]: https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-session_server-section

View File

@ -0,0 +1,16 @@
# Smoke Tests
It is imperative in any testing suite that we have Smoke Tests. In short, smoke tests are will run quick sanity
end-to-end functional tests from GitLab QA and are designed to run against the specified environment to ensure that
basic functionality is working.
Currently, our suite consists of this basic functionality coverage:
- User Login (Standard Auth)
- Project Creation
- Issue Creation
- Merge Request Creation
---
[Return to Testing documentation](index.md)

View File

@ -120,6 +120,14 @@ running feature tests (i.e. using Capybara) against it.
The actual test scenarios and steps are [part of GitLab Rails] so that they're
always in-sync with the codebase.
### Smoke tests
Smoke tests are quick tests that may be run at any time (especially after the pre-deployment migrations).
Much like feature tests - these tests run against the UI and ensure that basic functionality is working.
> See [Smoke Tests](smoke.md) for more information.
Read a separate document about [end-to-end tests](end_to_end_tests.md) to
learn more.

View File

@ -120,7 +120,7 @@ gitlabConfigStorageSize: 1Gi
Ingress routing and SSL are automatically configured within this Chart. An NGINX ingress is provisioned and configured, and will route traffic to any service. SSL certificates are automatically created and configured by [kube-lego](https://github.com/kubernetes/charts/tree/master/stable/kube-lego).
> **Note:**
Let's Encrypt limits a single TLD to five certificate requests within a single week. This means that common DNS wildcard services like [nip.io](http://nip.io) and [nip.io](http://nip.io) are unlikely to work.
Let's Encrypt limits a single TLD to five certificate requests within a single week. This means that common DNS wildcard services like [nip.io](http://nip.io) are unlikely to work.
## Installing GitLab using the Helm Chart
> **Note:**

View File

@ -30,7 +30,7 @@ Bitbucket.org account
## Project services
Integration with services such as Campfire, Flowdock, Gemnasium, HipChat,
Integration with services such as Campfire, Flowdock, HipChat,
Pivotal Tracker, and Slack are available in the form of a [Project Service][].
[Project Service]: ../user/project/integrations/project_services.md

View File

@ -34,7 +34,6 @@ Click on the service links to see further configuration instructions and details
| [Emails on push](emails_on_push.md) | Email the commits and diff of each push to a list of recipients |
| External Wiki | Replaces the link to the internal wiki with a link to an external wiki |
| Flowdock | Flowdock is a collaboration web app for technical teams |
| Gemnasium _(Has been deprecated in GitLab 11.0)_ | Gemnasium monitors your project dependencies and alerts you about updates and security vulnerabilities |
| [Hangouts Chat](hangouts_chat.md) | Receive events notifications in Google Hangouts Chat |
| [HipChat](hipchat.md) | Private group chat and IM |
| [Irker (IRC gateway)](irker.md) | Send IRC messages, on update, to a list of recipients through an Irker gateway |

View File

@ -1102,6 +1102,7 @@ X-Gitlab-Event: Build Hook
"build_finished_at": null,
"build_duration": null,
"build_allow_failure": false,
"build_failure_reason": "script_failure",
"project_id": 380,
"project_name": "gitlab-org/gitlab-test",
"user": {

View File

@ -1,6 +1,7 @@
module API
class Events < Grape::API
include PaginationParams
include APIGuard
helpers do
params :event_filter_params do
@ -24,6 +25,8 @@ module API
end
resource :events do
allow_access_with_scope :read_user, if: -> (request) { request.get? }
desc "List currently authenticated user's events" do
detail 'This feature was introduced in GitLab 9.3.'
success Entities::Event
@ -46,6 +49,8 @@ module API
requires :id, type: String, desc: 'The ID or Username of the user'
end
resource :users do
allow_access_with_scope :read_user, if: -> (request) { request.get? }
desc 'Get the contribution events of a specified user' do
detail 'This feature was introduced in GitLab 8.13.'
success Entities::Event

View File

@ -354,20 +354,6 @@ module API
desc: 'Flowdock token'
}
],
'gemnasium' => [
{
required: true,
name: :api_key,
type: String,
desc: 'Your personal API key on gemnasium.com'
},
{
required: true,
name: :token,
type: String,
desc: "The project's slug on gemnasium.com"
}
],
'hangouts-chat' => [
{
required: true,
@ -695,7 +681,6 @@ module API
EmailsOnPushService,
ExternalWikiService,
FlowdockService,
GemnasiumService,
HangoutsChatService,
HipchatService,
IrkerService,

View File

@ -0,0 +1,77 @@
# frozen_string_literal: true
require 'uri'
module Banzai
module Filter
# HTML Filter for markdown links with spaces in the URLs
#
# Based on Banzai::Filter::AutolinkFilter
#
# CommonMark does not allow spaces in the url portion of a link.
# For example, `[example](page slug)` is not valid. However,
# in our wikis, we support (via RedCarpet) this type of link, allowing
# wiki pages to be easily linked by their title. This filter adds that functionality.
# The intent is for this to only be used in Wikis - in general, we want
# to adhere to CommonMark's spec.
#
class SpacedLinkFilter < HTML::Pipeline::Filter
include ActionView::Helpers::TagHelper
# Pattern to match a standard markdown link
#
# Rubular: http://rubular.com/r/z9EAHxYmKI
LINK_PATTERN = /\[([^\]]+)\]\(([^)"]+)(?: \"([^\"]+)\")?\)/
# Text matching LINK_PATTERN inside these elements will not be linked
IGNORE_PARENTS = %w(a code kbd pre script style).to_set
# The XPath query to use for finding text nodes to parse.
TEXT_QUERY = %Q(descendant-or-self::text()[
not(#{IGNORE_PARENTS.map { |p| "ancestor::#{p}" }.join(' or ')})
and contains(., ']\(')
]).freeze
def call
return doc if context[:markdown_engine] == :redcarpet
doc.xpath(TEXT_QUERY).each do |node|
content = node.to_html
next unless content.match(LINK_PATTERN)
html = spaced_link_filter(content)
next if html == content
node.replace(html)
end
doc
end
private
def spaced_link_match(link)
match = LINK_PATTERN.match(link)
return link unless match && match[1] && match[2]
# escape the spaces in the url so that it's a valid markdown link,
# then run it through the markdown processor again, let it do its magic
text = match[1]
new_link = match[2].gsub(' ', '%20')
title = match[3] ? " \"#{match[3]}\"" : ''
html = Banzai::Filter::MarkdownFilter.call("[#{text}](#{new_link}#{title})", context)
# link is wrapped in a <p>, so strip that off
html.sub('<p>', '').chomp('</p>')
end
def spaced_link_filter(text)
Gitlab::StringRegexMarker.new(CGI.unescapeHTML(text), text.html_safe).mark(LINK_PATTERN) do |link, left:, right:|
spaced_link_match(link)
end
end
end
end
end

View File

@ -5,6 +5,7 @@ module Banzai
@filters ||= begin
super.insert_after(Filter::TableOfContentsFilter, Filter::GollumTagsFilter)
.insert_before(Filter::TaskListFilter, Filter::WikiLinkFilter)
.insert_before(Filter::WikiLinkFilter, Filter::SpacedLinkFilter)
end
end
end

View File

@ -28,6 +28,7 @@ module Gitlab
build_finished_at: build.finished_at,
build_duration: build.duration,
build_allow_failure: build.allow_failure,
build_failure_reason: build.failure_reason,
# TODO: do we still need it?
project_id: project.id,

View File

@ -226,6 +226,7 @@ module Gitlab
@new_file = diff.from_id == BLANK_SHA
@renamed_file = diff.from_path != diff.to_path
@deleted_file = diff.to_id == BLANK_SHA
@too_large = diff.too_large if diff.respond_to?(:too_large)
collapse! if diff.respond_to?(:collapsed) && diff.collapsed
end

View File

@ -1,7 +1,7 @@
module Gitlab
module GitalyClient
class Diff
ATTRS = %i(from_path to_path old_mode new_mode from_id to_id patch overflow_marker collapsed).freeze
ATTRS = %i(from_path to_path old_mode new_mode from_id to_id patch overflow_marker collapsed too_large).freeze
include AttributesBag
end

View File

@ -13,7 +13,7 @@ module Gitlab
@note = note
@project = project
@client = client
@user_finder = UserFinder.new(project, client)
@user_finder = GithubImport::UserFinder.new(project, client)
end
def execute

View File

@ -19,7 +19,7 @@ module Gitlab
@issue = issue
@project = project
@client = client
@user_finder = UserFinder.new(project, client)
@user_finder = GithubImport::UserFinder.new(project, client)
@milestone_finder = MilestoneFinder.new(project)
@issuable_finder = GithubImport::IssuableFinder.new(project, issue)
end

View File

@ -13,7 +13,7 @@ module Gitlab
@note = note
@project = project
@client = client
@user_finder = UserFinder.new(project, client)
@user_finder = GithubImport::UserFinder.new(project, client)
end
def execute

View File

@ -15,7 +15,7 @@ module Gitlab
@pull_request = pull_request
@project = project
@client = client
@user_finder = UserFinder.new(project, client)
@user_finder = GithubImport::UserFinder.new(project, client)
@milestone_finder = MilestoneFinder.new(project)
@issuable_finder =
GithubImport::IssuableFinder.new(project, pull_request)

View File

@ -28,7 +28,7 @@ module Gitlab
end
def safe_keys
issuable_builder::SAFE_HOOK_ATTRIBUTES + issuable_builder::SAFE_HOOK_RELATIONS
issuable_builder.safe_hook_attributes + issuable_builder::SAFE_HOOK_RELATIONS
end
private

View File

@ -1,50 +1,52 @@
module Gitlab
module HookData
class IssueBuilder < BaseBuilder
SAFE_HOOK_ATTRIBUTES = %i[
assignee_id
author_id
closed_at
confidential
created_at
description
due_date
id
iid
last_edited_at
last_edited_by_id
milestone_id
moved_to_id
project_id
relative_position
state
time_estimate
title
updated_at
updated_by_id
].freeze
SAFE_HOOK_RELATIONS = %i[
assignees
labels
total_time_spent
].freeze
def self.safe_hook_attributes
%i[
assignee_id
author_id
closed_at
confidential
created_at
description
due_date
id
iid
last_edited_at
last_edited_by_id
milestone_id
moved_to_id
project_id
relative_position
state
time_estimate
title
updated_at
updated_by_id
].freeze
end
alias_method :issue, :object
def build
attrs = {
description: absolute_image_urls(issue.description),
url: Gitlab::UrlBuilder.build(issue),
total_time_spent: issue.total_time_spent,
human_total_time_spent: issue.human_total_time_spent,
human_time_estimate: issue.human_time_estimate,
assignee_ids: issue.assignee_ids,
assignee_id: issue.assignee_ids.first # This key is deprecated
description: absolute_image_urls(issue.description),
url: Gitlab::UrlBuilder.build(issue),
total_time_spent: issue.total_time_spent,
human_total_time_spent: issue.human_total_time_spent,
human_time_estimate: issue.human_time_estimate,
assignee_ids: issue.assignee_ids,
assignee_id: issue.assignee_ids.first # This key is deprecated
}
issue.attributes.with_indifferent_access.slice(*SAFE_HOOK_ATTRIBUTES)
.merge!(attrs)
issue.attributes.with_indifferent_access.slice(*self.class.safe_hook_attributes)
.merge!(attrs)
end
end
end

View File

@ -1,33 +1,35 @@
module Gitlab
module HookData
class MergeRequestBuilder < BaseBuilder
SAFE_HOOK_ATTRIBUTES = %i[
assignee_id
author_id
created_at
description
head_pipeline_id
id
iid
last_edited_at
last_edited_by_id
merge_commit_sha
merge_error
merge_params
merge_status
merge_user_id
merge_when_pipeline_succeeds
milestone_id
source_branch
source_project_id
state
target_branch
target_project_id
time_estimate
title
updated_at
updated_by_id
].freeze
def self.safe_hook_attributes
%i[
assignee_id
author_id
created_at
description
head_pipeline_id
id
iid
last_edited_at
last_edited_by_id
merge_commit_sha
merge_error
merge_params
merge_status
merge_user_id
merge_when_pipeline_succeeds
milestone_id
source_branch
source_project_id
state
target_branch
target_project_id
time_estimate
title
updated_at
updated_by_id
].freeze
end
SAFE_HOOK_RELATIONS = %i[
assignee
@ -50,8 +52,8 @@ module Gitlab
human_time_estimate: merge_request.human_time_estimate
}
merge_request.attributes.with_indifferent_access.slice(*SAFE_HOOK_ATTRIBUTES)
.merge!(attrs)
merge_request.attributes.with_indifferent_access.slice(*self.class.safe_hook_attributes)
.merge!(attrs)
end
end
end

View File

@ -35,7 +35,7 @@ following call would login to a local [GDK] instance and run all specs in
`qa/specs/features`:
```
bin/qa Test::Instance http://localhost:3000
bin/qa Test::Instance::All http://localhost:3000
```
### Writing tests
@ -48,14 +48,14 @@ You can also supply specific tests to run as another parameter. For example, to
run the repository-related specs, you can execute:
```
bin/qa Test::Instance http://localhost qa/specs/features/repository/
bin/qa Test::Instance::All http://localhost qa/specs/features/repository/
```
Since the arguments would be passed to `rspec`, you could use all `rspec`
options there. For example, passing `--backtrace` and also line number:
```
bin/qa Test::Instance http://localhost qa/specs/features/project/create_spec.rb:3 --backtrace
bin/qa Test::Instance::All http://localhost qa/specs/features/project/create_spec.rb:3 --backtrace
```
### Overriding the authenticated user
@ -67,7 +67,7 @@ If you need to authenticate as a different user, you can provide the
`GITLAB_USERNAME` and `GITLAB_PASSWORD` environment variables:
```
GITLAB_USERNAME=jsmith GITLAB_PASSWORD=password bin/qa Test::Instance https://gitlab.example.com
GITLAB_USERNAME=jsmith GITLAB_PASSWORD=password bin/qa Test::Instance::All https://gitlab.example.com
```
If your user doesn't have permission to default sandbox group
@ -75,13 +75,13 @@ If your user doesn't have permission to default sandbox group
`GITLAB_SANDBOX_NAME`:
```
GITLAB_USERNAME=jsmith GITLAB_PASSWORD=password GITLAB_SANDBOX_NAME=jsmith-qa-sandbox bin/qa Test::Instance https://gitlab.example.com
GITLAB_USERNAME=jsmith GITLAB_PASSWORD=password GITLAB_SANDBOX_NAME=jsmith-qa-sandbox bin/qa Test::Instance::All https://gitlab.example.com
```
In addition, the `GITLAB_USER_TYPE` can be set to "ldap" to sign in as an LDAP user:
```
GITLAB_USER_TYPE=ldap GITLAB_USERNAME=jsmith GITLAB_PASSWORD=password GITLAB_SANDBOX_NAME=jsmith-qa-sandbox bin/qa Test::Instance https://gitlab.example.com
GITLAB_USER_TYPE=ldap GITLAB_USERNAME=jsmith GITLAB_PASSWORD=password GITLAB_SANDBOX_NAME=jsmith-qa-sandbox bin/qa Test::Instance::All https://gitlab.example.com
```
All [supported environment variables are here](https://gitlab.com/gitlab-org/gitlab-qa#supported-environment-variables).

View File

@ -77,14 +77,16 @@ module QA
#
autoload :Bootable, 'qa/scenario/bootable'
autoload :Actable, 'qa/scenario/actable'
autoload :Taggable, 'qa/scenario/taggable'
autoload :Template, 'qa/scenario/template'
##
# Test scenario entrypoints.
#
module Test
autoload :Instance, 'qa/scenario/test/instance'
module Instance
autoload :All, 'qa/scenario/test/instance/all'
autoload :Smoke, 'qa/scenario/test/instance/smoke'
end
module Integration
autoload :Github, 'qa/scenario/test/integration/github'

View File

@ -4,7 +4,12 @@ module QA
class Fork < Factory::Base
dependency Factory::Repository::ProjectPush, as: :push
dependency Factory::Resource::User, as: :user
dependency Factory::Resource::User, as: :user do |user|
if Runtime::Env.forker?
user.username = Runtime::Env.forker_username
user.password = Runtime::Env.forker_password
end
end
product(:user) { |factory| factory.user }

View File

@ -4,28 +4,52 @@ module QA
module Factory
module Resource
class User < Factory::Base
attr_accessor :name, :username, :email, :password
attr_reader :unique_id
attr_writer :username, :password, :name, :email
def initialize
@name = "name-#{SecureRandom.hex(8)}"
@username = "username-#{SecureRandom.hex(8)}"
@email = "mail#{SecureRandom.hex(8)}@mail.com"
@password = 'password'
@unique_id = SecureRandom.hex(8)
end
def username
@username ||= "qa-user-#{unique_id}"
end
def password
@password ||= 'password'
end
def name
@name ||= username
end
def email
@email ||= "#{username}@example.com"
end
def credentials_given?
defined?(@username) && defined?(@password)
end
product(:name) { |factory| factory.name }
product(:username) { |factory| factory.username }
product(:email) { |factory| factory.email }
product(:password) { |factory| factory.password }
def fabricate!
Page::Menu::Main.act { sign_out }
Page::Main::Login.act { switch_to_register_tab }
Page::Main::SignUp.perform do |page|
page.sign_up!(name: name, username: username, email: email, password: password)
Page::Menu::Main.perform { |main| main.sign_out }
if credentials_given?
Page::Main::Login.perform do |login|
login.sign_in_using_credentials(self)
end
else
Page::Main::Login.perform do |login|
login.switch_to_register_tab
end
Page::Main::SignUp.perform do |signup|
signup.sign_up!(self)
end
end
end
end

View File

@ -28,7 +28,7 @@ module QA
end
def use_default_credentials
self.username = Runtime::User.name
self.username = Runtime::User.username
self.password = Runtime::User.password
end

View File

@ -40,17 +40,19 @@ module QA
end
end
def sign_in_using_credentials
def sign_in_using_credentials(user = nil)
# Don't try to log-in if we're already logged-in
return if Page::Menu::Main.act { has_personal_area?(wait: 0) }
using_wait_time 0 do
set_initial_password_if_present
raise NotImplementedError if Runtime::User.ldap_user? && user&.credentials_given?
if Runtime::User.ldap_user?
sign_in_using_ldap_credentials
else
sign_in_using_gitlab_credentials
sign_in_using_gitlab_credentials(user || Runtime::User)
end
end
@ -69,21 +71,30 @@ module QA
click_on 'Register'
end
def switch_to_ldap_tab
click_on 'LDAP'
end
def switch_to_standard_tab
click_on 'Standard'
end
private
def sign_in_using_ldap_credentials
click_link 'LDAP'
switch_to_ldap_tab
fill_in :username, with: Runtime::User.ldap_username
fill_in :password, with: Runtime::User.ldap_password
click_button 'Sign in'
end
def sign_in_using_gitlab_credentials
click_link 'Standard' if page.has_content?('LDAP')
def sign_in_using_gitlab_credentials(user)
switch_to_sign_in_tab unless page.has_button?('Sign in')
switch_to_standard_tab if page.has_content?('LDAP')
fill_in :user_login, with: Runtime::User.name
fill_in :user_password, with: Runtime::User.password
fill_in :user_login, with: user.username
fill_in :user_password, with: user.password
click_button 'Sign in'
end

View File

@ -11,12 +11,12 @@ module QA
element :register_button, 'submit "Register"'
end
def sign_up!(name:, username:, email:, password:)
fill_in :new_user_name, with: name
fill_in :new_user_username, with: username
fill_in :new_user_email, with: email
fill_in :new_user_email_confirmation, with: email
fill_in :new_user_password, with: password
def sign_up!(user)
fill_in :new_user_name, with: user.name
fill_in :new_user_username, with: user.username
fill_in :new_user_email, with: user.email
fill_in :new_user_email_confirmation, with: user.email
fill_in :new_user_password, with: user.password
click_button 'Register'
Page::Menu::Main.act { has_personal_area? }

View File

@ -23,7 +23,13 @@ module QA
# After we fill the key, JS would generate another field so
# we need to use the same index to find the corresponding one.
keys[index].set(key)
all_elements(:ci_variable_input_value)[index].set(value)
node = all_elements(:ci_variable_input_value)[index]
# Simply run `node.set(value)` is too slow for long text here,
# so we need to run JavaScript directly to set the value.
# The code was inspired from:
# https://github.com/teamcapybara/capybara/blob/679548cea10773d45e32808f4d964377cfe5e892/lib/capybara/selenium/node.rb#L217
execute_script("arguments[0].value = #{value.to_json}", node)
end
def save_variables

View File

@ -39,6 +39,18 @@ module QA
ENV['GITLAB_PASSWORD']
end
def forker?
forker_username && forker_password
end
def forker_username
ENV['GITLAB_FORKER_USERNAME']
end
def forker_password
ENV['GITLAB_FORKER_PASSWORD']
end
def ldap_username
ENV['GITLAB_LDAP_USERNAME']
end

View File

@ -3,12 +3,12 @@ module QA
module User
extend self
def default_name
def default_username
'root'
end
def name
Runtime::Env.user_username || default_name
def username
Runtime::Env.user_username || default_username
end
def password

View File

@ -1,17 +0,0 @@
module QA
module Scenario
module Taggable
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def tags(*tags)
@tags = tags
end
def focus
@tags.to_a
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
end
end
end

View File

@ -1,15 +1,36 @@
module QA
module Scenario
class Template
def self.perform(*args)
new.tap do |scenario|
yield scenario if block_given?
break scenario.perform(*args)
class << self
def perform(*args)
new.tap do |scenario|
yield scenario if block_given?
break scenario.perform(*args)
end
end
def tags(*tags)
@tags = tags
end
def focus
@tags.to_a
end
end
def perform(*_args)
raise NotImplementedError
def perform(address, *rspec_options)
Runtime::Scenario.define(:gitlab_address, address)
Specs::Runner.perform do |specs|
specs.tty = true
specs.tags = self.class.focus
specs.options =
if rspec_options.any?
rspec_options
else
::File.expand_path('../specs/features', __dir__)
end
end
end
end
end

View File

@ -1,36 +0,0 @@
module QA
module Scenario
module Test
##
# Base class for running the suite against any GitLab instance,
# including staging and on-premises installation.
#
class Instance < Template
include Bootable
extend Taggable
tags :core
def perform(address, *rspec_options)
Runtime::Scenario.define(:gitlab_address, address)
##
# Perform before hooks, which are different for CE and EE
#
Runtime::Release.perform_before_hooks
Specs::Runner.perform do |specs|
specs.tty = true
specs.tags = self.class.focus
specs.options =
if rspec_options.any?
rspec_options
else
::File.expand_path('../../specs/features', __dir__)
end
end
end
end
end
end
end

View File

@ -0,0 +1,15 @@
module QA
module Scenario
module Test
##
# Base class for running the suite against any GitLab instance,
# including staging and on-premises installation.
#
module Instance
class All < Template
include Bootable
end
end
end
end
end

View File

@ -0,0 +1,17 @@
module QA
module Scenario
module Test
module Instance
##
# Base class for running the suite against any GitLab instance,
# including staging and on-premises installation.
#
class Smoke < Template
include Bootable
tags :smoke
end
end
end
end
end

View File

@ -1,13 +1,13 @@
require 'securerandom'
module QA
describe 'API basics', :core do
describe 'API basics' do
before(:context) do
@api_client = Runtime::API::Client.new(:gitlab)
end
let(:project_name) { "api-basics-#{SecureRandom.hex(8)}" }
let(:sanitized_project_path) { CGI.escape("#{Runtime::User.name}/#{project_name}") }
let(:sanitized_project_path) { CGI.escape("#{Runtime::User.username}/#{project_name}") }
it 'user creates a project with a file and deletes them afterwards' do
create_project_request = Runtime::API::Request.new(@api_client, '/projects')

View File

@ -1,5 +1,5 @@
module QA
describe 'API users', :core do
describe 'API users' do
before(:context) do
@api_client = Runtime::API::Client.new(:gitlab)
end
@ -14,11 +14,11 @@ module QA
end
it 'submit request with a valid user name' do
get request.url, { params: { username: Runtime::User.name } }
get request.url, { params: { username: Runtime::User.username } }
expect_status(200)
expect(json_body).to contain_exactly(
a_hash_including(username: Runtime::User.name)
a_hash_including(username: Runtime::User.username)
)
end

View File

@ -0,0 +1,15 @@
module QA
describe 'basic user login', :smoke do
it 'user logs in using basic credentials' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }
# TODO, since `Signed in successfully` message was removed
# this is the only way to tell if user is signed in correctly.
#
Page::Menu::Main.perform do |menu|
expect(menu).to have_personal_area
end
end
end
end

View File

@ -1,5 +1,5 @@
module QA
describe 'LDAP user login', :ldap do
describe 'LDAP user login', :orchestrated, :ldap do
before do
Runtime::Env.user_type = 'ldap'
end

View File

@ -1,5 +1,5 @@
module QA
describe 'create a new group', :mattermost do
describe 'create a new group', :orchestrated, :mattermost do
it 'creating a group with a mattermost team' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }

View File

@ -1,5 +1,5 @@
module QA
describe 'logging in to Mattermost', :mattermost do
describe 'logging in to Mattermost', :orchestrated, :mattermost do
it 'can use gitlab oauth' do
Runtime::Browser.visit(:gitlab, Page::Main::Login) do
Page::Main::Login.act { sign_in_using_credentials }

View File

@ -1,5 +1,5 @@
module QA
describe 'creates a merge request', :core do
describe 'creates a merge request with milestone' do
it 'user creates a new merge request' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }
@ -29,4 +29,25 @@ module QA
end
end
end
describe 'creates a merge request', :smoke do
it 'user creates a new merge request' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }
current_project = Factory::Resource::Project.fabricate! do |project|
project.name = 'project-with-merge-request'
end
Factory::Resource::MergeRequest.fabricate! do |merge_request|
merge_request.title = 'This is a merge request'
merge_request.description = 'Great feature'
merge_request.project = current_project
end
expect(page).to have_content('This is a merge request')
expect(page).to have_content('Great feature')
expect(page).to have_content(/Opened [\w\s]+ ago/)
end
end
end

View File

@ -1,5 +1,5 @@
module QA
describe 'merge request rebase', :core do
describe 'merge request rebase' do
it 'rebases source branch of merge request' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }

View File

@ -1,5 +1,5 @@
module QA
describe 'merge request squash commits', :core do
describe 'merge request squash commits' do
it 'when squash commits is marked before merge' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }

View File

@ -1,5 +1,5 @@
module QA
describe 'activity page', :core do
describe 'activity page' do
it 'push creates an event in the activity page' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }

View File

@ -1,5 +1,5 @@
module QA
describe 'deploy keys support', :core do
describe 'deploy keys support' do
it 'user adds a deploy key' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }

View File

@ -1,5 +1,5 @@
module QA
describe 'secret variables support', :core do
describe 'secret variables support' do
it 'user adds a secret variable' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }

View File

@ -1,7 +1,7 @@
require 'pathname'
module QA
describe 'Auto Devops', :kubernetes do
describe 'Auto Devops', :orchestrated, :kubernetes do
after do
@cluster&.remove!
end
@ -15,6 +15,13 @@ module QA
p.description = 'Project with Auto Devops'
end
# Disable code_quality check in Auto DevOps pipeline as it takes
# too long and times out the test
Factory::Resource::SecretVariable.fabricate! do |resource|
resource.key = 'CODE_QUALITY_DISABLED'
resource.value = '1'
end
# Create Auto Devops compatible repo
Factory::Repository::ProjectPush.fabricate! do |push|
push.project = project

View File

@ -1,5 +1,5 @@
module QA
describe 'creates issue', :core do
describe 'creates issue', :smoke do
let(:issue_title) { 'issue title' }
def create_issue

View File

@ -1,5 +1,5 @@
module QA
describe 'create a new project', :core do
describe 'create a new project', :smoke do
it 'user creates a new project' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }

View File

@ -1,7 +1,7 @@
require 'digest/sha1'
module QA
describe 'cloning code using a deploy key', :core, :docker do
describe 'cloning code using a deploy key', :docker do
def login
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }

View File

@ -1,5 +1,5 @@
module QA
describe 'Project fork', :core do
describe 'Project fork' do
it 'can submit merge requests to upstream master' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }
@ -8,14 +8,12 @@ module QA
merge_request.fork_branch = 'feature-branch'
end
Page::Menu::Main.act { sign_out }
Page::Main::Login.act do
switch_to_sign_in_tab
sign_in_using_credentials
end
Page::Menu::Main.perform { |main| main.sign_out }
Page::Main::Login.perform { |login| login.sign_in_using_credentials }
merge_request.visit!
Page::MergeRequest::Show.act { merge! }
Page::MergeRequest::Show.perform { |show| show.merge! }
expect(page).to have_content('The changes were merged')
end

View File

@ -1,5 +1,5 @@
module QA
describe 'user imports a GitHub repo', :core, :github do
describe 'user imports a GitHub repo', :orchestrated, :github do
let(:imported_project) do
Factory::Resource::ProjectImportedFromGithub.fabricate! do |project|
project.name = 'imported-project'

View File

@ -1,5 +1,5 @@
module QA
describe 'CI/CD Pipelines', :core, :docker do
describe 'CI/CD Pipelines', :orchestrated, :docker do
let(:executor) { "qa-runner-#{Time.now.to_i}" }
after do

Some files were not shown because too many files have changed in this diff Show More