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 - chrome_debug.log
- coverage-javascript/ - coverage-javascript/
codequality: code_quality:
<<: *dedicated-no-docs-no-db-pull-cache-job <<: *dedicated-no-docs-no-db-pull-cache-job
image: docker:stable image: docker:stable
allow_failure: true allow_failure: true
@ -757,9 +757,13 @@ codequality:
script: script:
# Extract "MAJOR.MINOR" from CI_SERVER_VERSION and generate "MAJOR-MINOR-stable" for Security Products # 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/') - 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: artifacts:
paths: [codeclimate.json] paths: [gl-code-quality-report.json]
expire_in: 1 week expire_in: 1 week
sast: sast:

View File

@ -64,11 +64,11 @@ As of July 2018, all the documentation for contributing to the GitLab project ha
## Contribute to GitLab ## 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 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). 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 edition. Throughout this guide you will see references to CE and EE for
abbreviation. 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). 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 ## 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 # Flowdock integration
gem 'gitlab-flowdock-git-hook', '~> 1.0.1' gem 'gitlab-flowdock-git-hook', '~> 1.0.1'
# Gemnasium integration
gem 'gemnasium-gitlab-service', '~> 0.2'
# Slack integration # Slack integration
gem 'slack-notifier', '~> 1.5.1' gem 'slack-notifier', '~> 1.5.1'
@ -423,7 +420,7 @@ group :ed25519 do
end end
# Gitaly GRPC client # Gitaly GRPC client
gem 'gitaly-proto', '~> 0.112.0', require: 'gitaly' gem 'gitaly-proto', '~> 0.113.0', require: 'gitaly'
gem 'grpc', '~> 1.11.0' gem 'grpc', '~> 1.11.0'
# Locked until https://github.com/google/protobuf/issues/4210 is closed # Locked until https://github.com/google/protobuf/issues/4210 is closed

View File

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

View File

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

View File

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

View File

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

View File

@ -1,67 +1,39 @@
class AutocompleteController < ApplicationController class AutocompleteController < ApplicationController
AWARD_EMOJI_MAX = 100
skip_before_action :authenticate_user!, only: [:users, :award_emojis] skip_before_action :authenticate_user!, only: [:users, :award_emojis]
before_action :load_project, only: [:users]
before_action :load_group, only: [:users]
def 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 end
def user def user
@user = User.find(params[:id]) user = UserFinder.new(params).execute!
render json: UserSerializer.new.represent(@user)
render json: UserSerializer.new.represent(user)
end end
# Displays projects to use for the dropdown when moving a resource from one
# project to another.
def projects def projects
project = Project.find_by_id(params[:project_id]) projects = Autocomplete::MoveToProjectFinder
projects = projects_finder.execute(project, search: params[:search], offset_id: params[:offset_id]) .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 end
def award_emojis def award_emojis
emoji_with_count = AwardEmoji render json: AwardedEmojiFinder.new(current_user).execute
.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)
end end
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) .where('name IN (?) AND awardable_type = ? AND awardable_id IN (?)', [DOWNVOTE_NAME, UPVOTE_NAME], type, ids)
.group('name', 'awardable_id') .group('name', 'awardable_id')
end 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 end
def downvote? 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 WithUploads
include BatchDestroyDependentAssociations include BatchDestroyDependentAssociations
include FeatureGate include FeatureGate
include OptionallySearch
extend Gitlab::Cache::RequestCache extend Gitlab::Cache::RequestCache
extend Gitlab::ConfigHelper extend Gitlab::ConfigHelper
@ -140,7 +141,6 @@ class Project < ActiveRecord::Base
has_one :flowdock_service has_one :flowdock_service
has_one :assembla_service has_one :assembla_service
has_one :asana_service has_one :asana_service
has_one :gemnasium_service
has_one :mattermost_slash_commands_service has_one :mattermost_slash_commands_service
has_one :mattermost_service has_one :mattermost_service
has_one :slack_slash_commands_service has_one :slack_slash_commands_service
@ -384,6 +384,26 @@ class Project < ActiveRecord::Base
only_integer: true, only_integer: true,
message: 'needs to be beetween 10 minutes and 1 month' } 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 # Returns a collection of projects that is either public or visible to the
# logged in user. # logged in user.
def self.public_or_visible_to_user(user = nil) 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 BulkMemberAccessLoad
include BlocksJsonSerialization include BlocksJsonSerialization
include WithUploads include WithUploads
include OptionallySearch
DEFAULT_NOTIFICATION_LEVEL = :participating DEFAULT_NOTIFICATION_LEVEL = :participating
@ -253,11 +254,41 @@ class User < ActiveRecord::Base
scope :external, -> { where(external: true) } scope :external, -> { where(external: true) }
scope :active, -> { with_state(:active).non_internal } 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 :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_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 :order_oldest_sign_in, -> { reorder(Gitlab::Database.nulls_last_order('current_sign_in_at', 'ASC')) }
scope :confirmed, -> { where.not(confirmed_at: nil) } 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 def self.with_two_factor_indistinct
joins("LEFT OUTER JOIN u2f_registrations AS u2f ON u2f.user_id = users.id") 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) .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) ).reorder(order % { query: ActiveRecord::Base.connection.quote(query) }, :name)
end 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 # searches user by given pattern
# it compares name, email, username fields and user's secondary emails with 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. # 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' = submit_tag 'Search', class: 'btn'
.float-right.light .float-right.light
Runners with last contact more than a minute ago: #{@active_runners_cnt} Runners currently online: #{@active_runners_cnt}
%br %br

View File

@ -2,11 +2,4 @@
- page_title "Metrics for environment", @environment.name - page_title "Metrics for environment", @environment.name
.prometheus-container{ class: container_class } .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) } #prometheus-graphs{ data: metrics_data(@project, @environment) }

View File

@ -13,4 +13,4 @@
%h4.underlined-title Available specific runners %h4.underlined-title Available specific runners
%ul.bordered-list.available-specific-runners %ul.bordered-list.available-specific-runners
= render partial: 'projects/runners/runner', collection: @assignable_runners, as: :runner = 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`: 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/.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 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 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 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 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 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 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 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 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 1. Create the shared directories. These may be different depending on your NFS

View File

@ -42,7 +42,7 @@ Registry, etc.
## Hashed Storage ## Hashed Storage
> **Warning:** Hashed storage is in **Beta**. For the latest updates, check the > **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. > and please report any problems you encounter.
Hashed Storage is the new storage behavior we are rolling out with 10.0. Instead 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 ## 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 GET /events
@ -119,9 +121,11 @@ Example response:
### Get user contribution events ### 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 GET /users/:id/events

View File

@ -401,48 +401,6 @@ Get Flowdock service settings for a project.
GET /projects/:id/services/flowdock 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 ## Hangouts Chat
Google GSuite team collaboration tool. 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) - [Trigger pipelines on a schedule](../user/project/pipelines/schedules.md)
- [Kubernetes clusters](../user/project/clusters/index.md) - Integrate one or - [Kubernetes clusters](../user/project/clusters/index.md) - Integrate one or
more Kubernetes clusters to your project 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 ## 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 The actual test scenarios and steps are [part of GitLab Rails] so that they're
always in-sync with the codebase. 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 Read a separate document about [end-to-end tests](end_to_end_tests.md) to
learn more. 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). 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:** > **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 ## Installing GitLab using the Helm Chart
> **Note:** > **Note:**

View File

@ -30,7 +30,7 @@ Bitbucket.org account
## Project services ## 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][]. Pivotal Tracker, and Slack are available in the form of a [Project Service][].
[Project Service]: ../user/project/integrations/project_services.md [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 | | [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 | | 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 | | 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 | | [Hangouts Chat](hangouts_chat.md) | Receive events notifications in Google Hangouts Chat |
| [HipChat](hipchat.md) | Private group chat and IM | | [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 | | [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_finished_at": null,
"build_duration": null, "build_duration": null,
"build_allow_failure": false, "build_allow_failure": false,
"build_failure_reason": "script_failure",
"project_id": 380, "project_id": 380,
"project_name": "gitlab-org/gitlab-test", "project_name": "gitlab-org/gitlab-test",
"user": { "user": {

View File

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

View File

@ -354,20 +354,6 @@ module API
desc: 'Flowdock token' 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' => [ 'hangouts-chat' => [
{ {
required: true, required: true,
@ -695,7 +681,6 @@ module API
EmailsOnPushService, EmailsOnPushService,
ExternalWikiService, ExternalWikiService,
FlowdockService, FlowdockService,
GemnasiumService,
HangoutsChatService, HangoutsChatService,
HipchatService, HipchatService,
IrkerService, 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 @filters ||= begin
super.insert_after(Filter::TableOfContentsFilter, Filter::GollumTagsFilter) super.insert_after(Filter::TableOfContentsFilter, Filter::GollumTagsFilter)
.insert_before(Filter::TaskListFilter, Filter::WikiLinkFilter) .insert_before(Filter::TaskListFilter, Filter::WikiLinkFilter)
.insert_before(Filter::WikiLinkFilter, Filter::SpacedLinkFilter)
end end
end end
end end

View File

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

View File

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

View File

@ -1,7 +1,7 @@
module Gitlab module Gitlab
module GitalyClient module GitalyClient
class Diff 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 include AttributesBag
end end

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,50 +1,52 @@
module Gitlab module Gitlab
module HookData module HookData
class IssueBuilder < BaseBuilder 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[ SAFE_HOOK_RELATIONS = %i[
assignees assignees
labels labels
total_time_spent total_time_spent
].freeze ].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 alias_method :issue, :object
def build def build
attrs = { attrs = {
description: absolute_image_urls(issue.description), description: absolute_image_urls(issue.description),
url: Gitlab::UrlBuilder.build(issue), url: Gitlab::UrlBuilder.build(issue),
total_time_spent: issue.total_time_spent, total_time_spent: issue.total_time_spent,
human_total_time_spent: issue.human_total_time_spent, human_total_time_spent: issue.human_total_time_spent,
human_time_estimate: issue.human_time_estimate, human_time_estimate: issue.human_time_estimate,
assignee_ids: issue.assignee_ids, assignee_ids: issue.assignee_ids,
assignee_id: issue.assignee_ids.first # This key is deprecated assignee_id: issue.assignee_ids.first # This key is deprecated
} }
issue.attributes.with_indifferent_access.slice(*SAFE_HOOK_ATTRIBUTES) issue.attributes.with_indifferent_access.slice(*self.class.safe_hook_attributes)
.merge!(attrs) .merge!(attrs)
end end
end end
end end

View File

@ -1,33 +1,35 @@
module Gitlab module Gitlab
module HookData module HookData
class MergeRequestBuilder < BaseBuilder class MergeRequestBuilder < BaseBuilder
SAFE_HOOK_ATTRIBUTES = %i[ def self.safe_hook_attributes
assignee_id %i[
author_id assignee_id
created_at author_id
description created_at
head_pipeline_id description
id head_pipeline_id
iid id
last_edited_at iid
last_edited_by_id last_edited_at
merge_commit_sha last_edited_by_id
merge_error merge_commit_sha
merge_params merge_error
merge_status merge_params
merge_user_id merge_status
merge_when_pipeline_succeeds merge_user_id
milestone_id merge_when_pipeline_succeeds
source_branch milestone_id
source_project_id source_branch
state source_project_id
target_branch state
target_project_id target_branch
time_estimate target_project_id
title time_estimate
updated_at title
updated_by_id updated_at
].freeze updated_by_id
].freeze
end
SAFE_HOOK_RELATIONS = %i[ SAFE_HOOK_RELATIONS = %i[
assignee assignee
@ -50,8 +52,8 @@ module Gitlab
human_time_estimate: merge_request.human_time_estimate human_time_estimate: merge_request.human_time_estimate
} }
merge_request.attributes.with_indifferent_access.slice(*SAFE_HOOK_ATTRIBUTES) merge_request.attributes.with_indifferent_access.slice(*self.class.safe_hook_attributes)
.merge!(attrs) .merge!(attrs)
end end
end 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`: `qa/specs/features`:
``` ```
bin/qa Test::Instance http://localhost:3000 bin/qa Test::Instance::All http://localhost:3000
``` ```
### Writing tests ### 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: 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` Since the arguments would be passed to `rspec`, you could use all `rspec`
options there. For example, passing `--backtrace` and also line number: 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 ### 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` 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 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_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: 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). 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 :Bootable, 'qa/scenario/bootable'
autoload :Actable, 'qa/scenario/actable' autoload :Actable, 'qa/scenario/actable'
autoload :Taggable, 'qa/scenario/taggable'
autoload :Template, 'qa/scenario/template' autoload :Template, 'qa/scenario/template'
## ##
# Test scenario entrypoints. # Test scenario entrypoints.
# #
module Test 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 module Integration
autoload :Github, 'qa/scenario/test/integration/github' autoload :Github, 'qa/scenario/test/integration/github'

View File

@ -4,7 +4,12 @@ module QA
class Fork < Factory::Base class Fork < Factory::Base
dependency Factory::Repository::ProjectPush, as: :push 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 } product(:user) { |factory| factory.user }

View File

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

View File

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

View File

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

View File

@ -11,12 +11,12 @@ module QA
element :register_button, 'submit "Register"' element :register_button, 'submit "Register"'
end end
def sign_up!(name:, username:, email:, password:) def sign_up!(user)
fill_in :new_user_name, with: name fill_in :new_user_name, with: user.name
fill_in :new_user_username, with: username fill_in :new_user_username, with: user.username
fill_in :new_user_email, with: email fill_in :new_user_email, with: user.email
fill_in :new_user_email_confirmation, with: email fill_in :new_user_email_confirmation, with: user.email
fill_in :new_user_password, with: password fill_in :new_user_password, with: user.password
click_button 'Register' click_button 'Register'
Page::Menu::Main.act { has_personal_area? } 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 # After we fill the key, JS would generate another field so
# we need to use the same index to find the corresponding one. # we need to use the same index to find the corresponding one.
keys[index].set(key) 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 end
def save_variables def save_variables

View File

@ -39,6 +39,18 @@ module QA
ENV['GITLAB_PASSWORD'] ENV['GITLAB_PASSWORD']
end 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 def ldap_username
ENV['GITLAB_LDAP_USERNAME'] ENV['GITLAB_LDAP_USERNAME']
end end

View File

@ -3,12 +3,12 @@ module QA
module User module User
extend self extend self
def default_name def default_username
'root' 'root'
end end
def name def username
Runtime::Env.user_username || default_name Runtime::Env.user_username || default_username
end end
def password 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 QA
module Scenario module Scenario
class Template class Template
def self.perform(*args) class << self
new.tap do |scenario| def perform(*args)
yield scenario if block_given? new.tap do |scenario|
break scenario.perform(*args) yield scenario if block_given?
break scenario.perform(*args)
end
end
def tags(*tags)
@tags = tags
end
def focus
@tags.to_a
end end
end end
def perform(*_args) def perform(address, *rspec_options)
raise NotImplementedError 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 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' require 'securerandom'
module QA module QA
describe 'API basics', :core do describe 'API basics' do
before(:context) do before(:context) do
@api_client = Runtime::API::Client.new(:gitlab) @api_client = Runtime::API::Client.new(:gitlab)
end end
let(:project_name) { "api-basics-#{SecureRandom.hex(8)}" } 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 it 'user creates a project with a file and deletes them afterwards' do
create_project_request = Runtime::API::Request.new(@api_client, '/projects') create_project_request = Runtime::API::Request.new(@api_client, '/projects')

View File

@ -1,5 +1,5 @@
module QA module QA
describe 'API users', :core do describe 'API users' do
before(:context) do before(:context) do
@api_client = Runtime::API::Client.new(:gitlab) @api_client = Runtime::API::Client.new(:gitlab)
end end
@ -14,11 +14,11 @@ module QA
end end
it 'submit request with a valid user name' do 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_status(200)
expect(json_body).to contain_exactly( expect(json_body).to contain_exactly(
a_hash_including(username: Runtime::User.name) a_hash_including(username: Runtime::User.username)
) )
end 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 module QA
describe 'LDAP user login', :ldap do describe 'LDAP user login', :orchestrated, :ldap do
before do before do
Runtime::Env.user_type = 'ldap' Runtime::Env.user_type = 'ldap'
end end

View File

@ -1,5 +1,5 @@
module QA 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 it 'creating a group with a mattermost team' do
Runtime::Browser.visit(:gitlab, Page::Main::Login) Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials } Page::Main::Login.act { sign_in_using_credentials }

View File

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

View File

@ -1,5 +1,5 @@
module QA 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 it 'user creates a new merge request' do
Runtime::Browser.visit(:gitlab, Page::Main::Login) Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials } Page::Main::Login.act { sign_in_using_credentials }
@ -29,4 +29,25 @@ module QA
end end
end 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 end

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
require 'pathname' require 'pathname'
module QA module QA
describe 'Auto Devops', :kubernetes do describe 'Auto Devops', :orchestrated, :kubernetes do
after do after do
@cluster&.remove! @cluster&.remove!
end end
@ -15,6 +15,13 @@ module QA
p.description = 'Project with Auto Devops' p.description = 'Project with Auto Devops'
end 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 # Create Auto Devops compatible repo
Factory::Repository::ProjectPush.fabricate! do |push| Factory::Repository::ProjectPush.fabricate! do |push|
push.project = project push.project = project

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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