Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2019-11-14 03:06:25 +00:00
parent eed996ac33
commit 29c01c6c91
72 changed files with 549 additions and 109 deletions

View File

@ -449,7 +449,7 @@ group :ed25519 do
end end
# Gitaly GRPC protocol definitions # Gitaly GRPC protocol definitions
gem 'gitaly', '~> 1.65.0' gem 'gitaly', '~> 1.70.0'
gem 'grpc', '~> 1.24.0' gem 'grpc', '~> 1.24.0'

View File

@ -358,7 +358,7 @@ GEM
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
git (1.5.0) git (1.5.0)
gitaly (1.65.0) gitaly (1.70.0)
grpc (~> 1.0) grpc (~> 1.0)
github-markup (1.7.0) github-markup (1.7.0)
gitlab-labkit (0.7.0) gitlab-labkit (0.7.0)
@ -1167,7 +1167,7 @@ DEPENDENCIES
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 (~> 1.65.0) gitaly (~> 1.70.0)
github-markup (~> 1.7.0) github-markup (~> 1.7.0)
gitlab-labkit (~> 0.5) gitlab-labkit (~> 0.5)
gitlab-license (~> 1.0) gitlab-license (~> 1.0)

View File

@ -301,6 +301,7 @@ export default {
v-if="showContentViewer" v-if="showContentViewer"
:content="file.content || file.raw" :content="file.content || file.raw"
:path="file.rawPath || file.path" :path="file.rawPath || file.path"
:file-path="file.path"
:file-size="file.size" :file-size="file.size"
:project-path="file.projectId" :project-path="file.projectId"
:type="fileType" :type="fileType"

View File

@ -18,6 +18,11 @@ export default {
required: false, required: false,
default: 0, default: 0,
}, },
filePath: {
type: String,
required: false,
default: '',
},
projectPath: { projectPath: {
type: String, type: String,
required: false, required: false,
@ -52,6 +57,7 @@ export default {
<component <component
:is="viewer" :is="viewer"
:path="path" :path="path"
:file-path="filePath"
:file-size="fileSize" :file-size="fileSize"
:project-path="projectPath" :project-path="projectPath"
:content="content" :content="content"

View File

@ -16,6 +16,11 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
filePath: {
type: String,
required: false,
default: '',
},
projectPath: { projectPath: {
type: String, type: String,
required: true, required: true,
@ -48,6 +53,7 @@ export default {
this.isLoading = true; this.isLoading = true;
const postBody = { const postBody = {
text: this.content, text: this.content,
path: this.filePath,
}; };
const postOptions = { const postOptions = {
cancelToken: axiosSource.token, cancelToken: axiosSource.token,

View File

@ -7,17 +7,8 @@ module PreviewMarkdown
def preview_markdown def preview_markdown
result = PreviewMarkdownService.new(@project, current_user, markdown_service_params).execute result = PreviewMarkdownService.new(@project, current_user, markdown_service_params).execute
markdown_params =
case controller_name
when 'wikis' then { pipeline: :wiki, project_wiki: @project_wiki, page_slug: params[:id] }
when 'snippets' then { skip_project_check: true }
when 'groups' then { group: group }
when 'projects' then projects_filter_params
else {}
end
render json: { render json: {
body: view_context.markdown(result[:text], markdown_params), body: view_context.markdown(result[:text], markdown_context_params),
references: { references: {
users: result[:users], users: result[:users],
suggestions: SuggestionSerializer.new.represent_diff(result[:suggestions]), suggestions: SuggestionSerializer.new.represent_diff(result[:suggestions]),
@ -38,5 +29,16 @@ module PreviewMarkdown
def markdown_service_params def markdown_service_params
params params
end end
def markdown_context_params
case controller_name
when 'wikis' then { pipeline: :wiki, project_wiki: @project_wiki, page_slug: params[:id] }
when 'snippets' then { skip_project_check: true }
when 'groups' then { group: group }
when 'projects' then projects_filter_params
else {}
end.merge(requested_path: params[:path])
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables # rubocop:enable Gitlab/ModuleWithInstanceVariables
end end

View File

@ -5,12 +5,15 @@ module Clusters
class ElasticStack < ApplicationRecord class ElasticStack < ApplicationRecord
VERSION = '1.8.0' VERSION = '1.8.0'
ELASTICSEARCH_PORT = 9200
self.table_name = 'clusters_applications_elastic_stacks' self.table_name = 'clusters_applications_elastic_stacks'
include ::Clusters::Concerns::ApplicationCore include ::Clusters::Concerns::ApplicationCore
include ::Clusters::Concerns::ApplicationStatus include ::Clusters::Concerns::ApplicationStatus
include ::Clusters::Concerns::ApplicationVersion include ::Clusters::Concerns::ApplicationVersion
include ::Clusters::Concerns::ApplicationData include ::Clusters::Concerns::ApplicationData
include ::Gitlab::Utils::StrongMemoize
default_value_for :version, VERSION default_value_for :version, VERSION
@ -49,6 +52,28 @@ module Clusters
) )
end end
def elasticsearch_client
strong_memoize(:elasticsearch_client) do
next unless kube_client
proxy_url = kube_client.proxy_url('service', 'elastic-stack-elasticsearch-client', ::Clusters::Applications::ElasticStack::ELASTICSEARCH_PORT, Gitlab::Kubernetes::Helm::NAMESPACE)
Elasticsearch::Client.new(url: proxy_url) do |faraday|
# ensures headers containing auth data are appended to original client options
faraday.headers.merge!(kube_client.headers)
# ensure TLS certs are properly verified
faraday.ssl[:verify] = kube_client.ssl_options[:verify_ssl]
faraday.ssl[:cert_store] = kube_client.ssl_options[:cert_store]
end
rescue Kubeclient::HttpError => error
# If users have mistakenly set parameters or removed the depended clusters,
# `proxy_url` could raise an exception because gitlab can not communicate with the cluster.
# We check for a nil client in downstream use and behaviour is equivalent to an empty state
log_exception(error, :failed_to_create_elasticsearch_client)
end
end
private private
def specification def specification
@ -74,6 +99,10 @@ module Clusters
Gitlab::Kubernetes::KubectlCmd.delete("pvc", "--selector", "release=elastic-stack") Gitlab::Kubernetes::KubectlCmd.delete("pvc", "--selector", "release=elastic-stack")
].compact ].compact
end end
def kube_client
cluster&.kubeclient&.core_client
end
end end
end end
end end

View File

@ -60,6 +60,24 @@ module Clusters
# Override if your application needs any action after # Override if your application needs any action after
# being uninstalled by Helm # being uninstalled by Helm
end end
def logger
@logger ||= Gitlab::Kubernetes::Logger.build
end
def log_exception(error, event)
logger.error({
exception: error.class.name,
status_code: error.error_code,
cluster_id: cluster&.id,
application_id: id,
class_name: self.class.name,
event: event,
message: error.message
})
Gitlab::Sentry.track_acceptable_exception(error, extra: { cluster_id: cluster&.id, application_id: id })
end
end end
end end
end end

View File

@ -12,7 +12,7 @@ class Environment < ApplicationRecord
has_one :last_deployment, -> { success.order('deployments.id DESC') }, class_name: 'Deployment' has_one :last_deployment, -> { success.order('deployments.id DESC') }, class_name: 'Deployment'
has_one :last_deployable, through: :last_deployment, source: 'deployable', source_type: 'CommitStatus' has_one :last_deployable, through: :last_deployment, source: 'deployable', source_type: 'CommitStatus'
has_one :last_pipeline, through: :last_deployable, source: 'pipeline' has_one :last_pipeline, through: :last_deployable, source: 'pipeline'
has_one :last_visible_deployment, -> { visible.distinct_on_environment }, class_name: 'Deployment' has_one :last_visible_deployment, -> { visible.distinct_on_environment }, inverse_of: :environment, class_name: 'Deployment'
has_one :last_visible_deployable, through: :last_visible_deployment, source: 'deployable', source_type: 'CommitStatus' has_one :last_visible_deployable, through: :last_visible_deployment, source: 'deployable', source_type: 'CommitStatus'
has_one :last_visible_pipeline, through: :last_visible_deployable, source: 'pipeline' has_one :last_visible_pipeline, through: :last_visible_deployable, source: 'pipeline'
@ -66,6 +66,9 @@ class Environment < ApplicationRecord
scope :for_project, -> (project) { where(project_id: project) } scope :for_project, -> (project) { where(project_id: project) }
scope :with_deployment, -> (sha) { where('EXISTS (?)', Deployment.select(1).where('deployments.environment_id = environments.id').where(sha: sha)) } scope :with_deployment, -> (sha) { where('EXISTS (?)', Deployment.select(1).where('deployments.environment_id = environments.id').where(sha: sha)) }
scope :unfoldered, -> { where(environment_type: nil) } scope :unfoldered, -> { where(environment_type: nil) }
scope :with_rank, -> do
select('environments.*, rank() OVER (PARTITION BY project_id ORDER BY id DESC)')
end
state_machine :state, initial: :available do state_machine :state, initial: :available do
event :start do event :start do

View File

@ -287,7 +287,7 @@ class Project < ApplicationRecord
has_many :variables, class_name: 'Ci::Variable' has_many :variables, class_name: 'Ci::Variable'
has_many :triggers, class_name: 'Ci::Trigger' has_many :triggers, class_name: 'Ci::Trigger'
has_many :environments has_many :environments
has_many :unfoldered_environments, -> { unfoldered.available }, class_name: 'Environment' has_many :environments_for_dashboard, -> { from(with_rank.unfoldered.available, :environments).where('rank <= 3') }, class_name: 'Environment'
has_many :deployments has_many :deployments
has_many :pipeline_schedules, class_name: 'Ci::PipelineSchedule' has_many :pipeline_schedules, class_name: 'Ci::PipelineSchedule'
has_many :project_deploy_tokens has_many :project_deploy_tokens

View File

@ -50,16 +50,24 @@ class BaseService
private private
def error(message, http_status = nil) # Return a Hash with an `error` status
#
# message - Error message to include in the Hash
# http_status - Optional HTTP status code override (default: nil)
# pass_back - Additional attributes to be included in the resulting Hash
def error(message, http_status = nil, pass_back: {})
result = { result = {
message: message, message: message,
status: :error status: :error
} }.reverse_merge(pass_back)
result[:http_status] = http_status if http_status result[:http_status] = http_status if http_status
result result
end end
# Return a Hash with a `success` status
#
# pass_back - Additional attributes to be included in the resulting Hash
def success(pass_back = {}) def success(pass_back = {})
pass_back[:status] = :success pass_back[:status] = :success
pass_back pass_back

View File

@ -23,14 +23,15 @@ module Commits
message, message,
start_project: @start_project, start_project: @start_project,
start_branch_name: @start_branch) start_branch_name: @start_branch)
rescue Gitlab::Git::Repository::CreateTreeError rescue Gitlab::Git::Repository::CreateTreeError => ex
act = action.to_s.dasherize act = action.to_s.dasherize
type = @commit.change_type_title(current_user) type = @commit.change_type_title(current_user)
error_msg = "Sorry, we cannot #{act} this #{type} automatically. " \ error_msg = "Sorry, we cannot #{act} this #{type} automatically. " \
"This #{type} may already have been #{act}ed, or a more recent " \ "This #{type} may already have been #{act}ed, or a more recent " \
"commit may have updated some of its content." "commit may have updated some of its content."
raise ChangeError, error_msg
raise ChangeError.new(error_msg, ex.error_code)
end end
end end
end end

View File

@ -3,7 +3,15 @@
module Commits module Commits
class CreateService < ::BaseService class CreateService < ::BaseService
ValidationError = Class.new(StandardError) ValidationError = Class.new(StandardError)
ChangeError = Class.new(StandardError) class ChangeError < StandardError
attr_reader :error_code
def initialize(message, error_code = nil)
super(message)
@error_code = error_code
end
end
def initialize(*args) def initialize(*args)
super super
@ -21,8 +29,9 @@ module Commits
new_commit = create_commit! new_commit = create_commit!
success(result: new_commit) success(result: new_commit)
rescue ChangeError => ex
error(ex.message, pass_back: { error_code: ex.error_code })
rescue ValidationError, rescue ValidationError,
ChangeError,
Gitlab::Git::Index::IndexError, Gitlab::Git::Index::IndexError,
Gitlab::Git::CommitError, Gitlab::Git::CommitError,
Gitlab::Git::PreReceiveError, Gitlab::Git::PreReceiveError,

View File

@ -0,0 +1,5 @@
---
title: Enable environments dashboard by default
merge_request: 19838
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Fix broken images when previewing markdown files in Web IDE
merge_request: 18899
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Increase PumaWorkerKiller memory limit in development environment
merge_request: 20039
author:
type: performance

View File

@ -0,0 +1,5 @@
---
title: Helm v2.16.1
merge_request: 19981
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: 'Add an `error_code` attribute to the API response when a cherry-pick or revert fails.'
merge_request: 19518
author:
type: added

View File

@ -317,6 +317,21 @@ Example response:
} }
``` ```
In the event of a failed cherry-pick, the response will provide context about
why:
```json
{
"message": "Sorry, we cannot cherry-pick this commit automatically. This commit may already have been cherry-picked, or a more recent commit may have updated some of its content.",
"error_code": "empty"
}
```
In this case, the cherry-pick failed because the changeset was empty and likely
indicates that the commit already exists in the target branch. The other
possible error code is `conflict`, which indicates that there was a merge
conflict.
## Revert a commit ## Revert a commit
> [Introduced][ce-22919] in GitLab 11.5. > [Introduced][ce-22919] in GitLab 11.5.
@ -358,6 +373,19 @@ Example response:
} }
``` ```
In the event of a failed revert, the response will provide context about why:
```json
{
"message": "Sorry, we cannot revert this commit automatically. This commit may already have been reverted, or a more recent commit may have updated some of its content.",
"error_code": "conflict"
}
```
In this case, the revert failed because the attempted revert generated a merge
conflict. The other possible error code is `empty`, which indicates that the
changeset was empty, likely due to the change having already been reverted.
## Get the diff of a commit ## Get the diff of a commit
Get the diff of a commit in a project. Get the diff of a commit in a project.

View File

@ -32,10 +32,23 @@ Management projects are restricted to the following:
## Usage ## Usage
To use a cluster management project for a cluster:
1. Select the project.
1. Configure your pipelines.
1. Set an environment scope.
### Selecting a cluster management project ### Selecting a cluster management project
You can select a management project for the cluster under **Advanced To select a cluster management project to use:
settings**.
1. Navigate to the appropriate configuration page. For a:
- [Project-level cluster](../project/clusters/index.md), navigate to your project's
**Operations > Kubernetes** page.
- [Group-level cluster](../group/clusters/index.md), navigate to your group's **Kubernetes**
page.
1. Select the project using **Cluster management project field** in the **Advanced settings**
section.
![Selecting a cluster management project under Advanced settings](img/advanced-settings-cluster-management-project-v12_5.png) ![Selecting a cluster management project under Advanced settings](img/advanced-settings-cluster-management-project-v12_5.png)

View File

@ -223,7 +223,7 @@ module API
present user_project.repository.commit(result[:result]), present user_project.repository.commit(result[:result]),
with: Entities::Commit with: Entities::Commit
else else
render_api_error!(result[:message], 400) error!(result.slice(:message, :error_code), 400, header)
end end
end end
@ -257,7 +257,7 @@ module API
present user_project.repository.commit(result[:result]), present user_project.repository.commit(result[:result]),
with: Entities::Commit with: Entities::Commit
else else
render_api_error!(result[:message], 400) error!(result.slice(:message, :error_code), 400, header)
end end
end end

View File

@ -1,5 +1,5 @@
.dast-auto-deploy: .dast-auto-deploy:
image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v0.4.0" image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v0.6.0"
dast_environment_deploy: dast_environment_deploy:
extends: .dast-auto-deploy extends: .dast-auto-deploy

View File

@ -1,5 +1,5 @@
.auto-deploy: .auto-deploy:
image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v0.4.0" image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v0.6.0"
review: review:
extends: .auto-deploy extends: .auto-deploy

View File

@ -3,7 +3,12 @@
module Gitlab module Gitlab
module Cluster module Cluster
class PumaWorkerKillerInitializer class PumaWorkerKillerInitializer
def self.start(puma_options, puma_per_worker_max_memory_mb: 850, puma_master_max_memory_mb: 550) def self.start(
puma_options,
puma_per_worker_max_memory_mb: 850,
puma_master_max_memory_mb: 550,
additional_puma_dev_max_memory_mb: 200
)
require 'puma_worker_killer' require 'puma_worker_killer'
PumaWorkerKiller.config do |config| PumaWorkerKiller.config do |config|
@ -14,7 +19,11 @@ module Gitlab
# The Puma Worker Killer checks the total RAM used by both the master # The Puma Worker Killer checks the total RAM used by both the master
# and worker processes. # and worker processes.
# https://github.com/schneems/puma_worker_killer/blob/v0.1.0/lib/puma_worker_killer/puma_memory.rb#L57 # https://github.com/schneems/puma_worker_killer/blob/v0.1.0/lib/puma_worker_killer/puma_memory.rb#L57
config.ram = puma_master_max_memory_mb + (worker_count * puma_per_worker_max_memory_mb) #
# Additional memory is added when running in `development`
config.ram = puma_master_max_memory_mb +
(worker_count * puma_per_worker_max_memory_mb) +
(Rails.env.development? ? (1 + worker_count) * additional_puma_dev_max_memory_mb : 0)
config.frequency = 20 # seconds config.frequency = 20 # seconds

View File

@ -25,9 +25,18 @@ module Gitlab
InvalidRef = Class.new(StandardError) InvalidRef = Class.new(StandardError)
GitError = Class.new(StandardError) GitError = Class.new(StandardError)
DeleteBranchError = Class.new(StandardError) DeleteBranchError = Class.new(StandardError)
CreateTreeError = Class.new(StandardError)
TagExistsError = Class.new(StandardError) TagExistsError = Class.new(StandardError)
ChecksumError = Class.new(StandardError) ChecksumError = Class.new(StandardError)
class CreateTreeError < StandardError
attr_reader :error_code
def initialize(error_code)
super(self.class.name)
# The value coming from Gitaly is an uppercase String (e.g., "EMPTY")
@error_code = error_code.downcase.to_sym
end
end
# Directory name of repo # Directory name of repo
attr_reader :name attr_reader :name

View File

@ -447,7 +447,7 @@ module Gitlab
elsif response.commit_error.presence elsif response.commit_error.presence
raise Gitlab::Git::CommitError, response.commit_error raise Gitlab::Git::CommitError, response.commit_error
elsif response.create_tree_error.presence elsif response.create_tree_error.presence
raise Gitlab::Git::Repository::CreateTreeError, response.create_tree_error raise Gitlab::Git::Repository::CreateTreeError, response.create_tree_error_code
end end
Gitlab::Git::OperationService::BranchUpdate.from_gitaly(response.branch_update) Gitlab::Git::OperationService::BranchUpdate.from_gitaly(response.branch_update)

View File

@ -3,7 +3,7 @@
module Gitlab module Gitlab
module Kubernetes module Kubernetes
module Helm module Helm
HELM_VERSION = '2.15.1' HELM_VERSION = '2.16.1'
KUBECTL_VERSION = '1.13.12' KUBECTL_VERSION = '1.13.12'
NAMESPACE = 'gitlab-managed-apps' NAMESPACE = 'gitlab-managed-apps'
SERVICE_ACCOUNT = 'tiller' SERVICE_ACCOUNT = 'tiller'

View File

@ -227,16 +227,17 @@ describe Admin::ClustersController do
describe 'security' do describe 'security' do
before do before do
allow_any_instance_of(described_class) allow_next_instance_of(described_class) do |instance|
.to receive(:token_in_session).and_return('token') allow(instance).to receive(:token_in_session).and_return('token')
allow_any_instance_of(described_class) allow(instance).to receive(:expires_at_in_session).and_return(1.hour.since.to_i.to_s)
.to receive(:expires_at_in_session).and_return(1.hour.since.to_i.to_s) end
allow_any_instance_of(GoogleApi::CloudPlatform::Client) allow_next_instance_of(GoogleApi::CloudPlatform::Client) do |instance|
.to receive(:projects_zones_clusters_create) do allow(instance).to receive(:projects_zones_clusters_create) do
OpenStruct.new( OpenStruct.new(
self_link: 'projects/gcp-project-12345/zones/us-central1-a/operations/ope-123', self_link: 'projects/gcp-project-12345/zones/us-central1-a/operations/ope-123',
status: 'RUNNING' status: 'RUNNING'
) )
end
end end
allow(WaitForClusterCreationWorker).to receive(:perform_in).and_return(nil) allow(WaitForClusterCreationWorker).to receive(:perform_in).and_return(nil)
@ -467,7 +468,9 @@ describe Admin::ClustersController do
end end
it 'invokes schedule_status_update on each application' do it 'invokes schedule_status_update on each application' do
expect_any_instance_of(Clusters::Applications::Ingress).to receive(:schedule_status_update) expect_next_instance_of(Clusters::Applications::Ingress) do |instance|
expect(instance).to receive(:schedule_status_update)
end
get_cluster_status get_cluster_status
end end

View File

@ -13,7 +13,9 @@ describe Admin::IdentitiesController do
let(:user) { create(:omniauth_user, provider: 'ldapmain', extern_uid: 'uid=myuser,ou=people,dc=example,dc=com') } let(:user) { create(:omniauth_user, provider: 'ldapmain', extern_uid: 'uid=myuser,ou=people,dc=example,dc=com') }
it 'repairs ldap blocks' do it 'repairs ldap blocks' do
expect_any_instance_of(RepairLdapBlockedUserService).to receive(:execute) expect_next_instance_of(RepairLdapBlockedUserService) do |instance|
expect(instance).to receive(:execute)
end
put :update, params: { user_id: user.username, id: user.ldap_identity.id, identity: { provider: 'twitter' } } put :update, params: { user_id: user.username, id: user.ldap_identity.id, identity: { provider: 'twitter' } }
end end
@ -23,7 +25,9 @@ describe Admin::IdentitiesController do
let(:user) { create(:omniauth_user, provider: 'ldapmain', extern_uid: 'uid=myuser,ou=people,dc=example,dc=com') } let(:user) { create(:omniauth_user, provider: 'ldapmain', extern_uid: 'uid=myuser,ou=people,dc=example,dc=com') }
it 'repairs ldap blocks' do it 'repairs ldap blocks' do
expect_any_instance_of(RepairLdapBlockedUserService).to receive(:execute) expect_next_instance_of(RepairLdapBlockedUserService) do |instance|
expect(instance).to receive(:execute)
end
delete :destroy, params: { user_id: user.username, id: user.ldap_identity.id } delete :destroy, params: { user_id: user.username, id: user.ldap_identity.id }
end end

View File

@ -39,7 +39,9 @@ describe Admin::SpamLogsController do
describe '#mark_as_ham' do describe '#mark_as_ham' do
before do before do
allow_any_instance_of(AkismetService).to receive(:submit_ham).and_return(true) allow_next_instance_of(AkismetService) do |instance|
allow(instance).to receive(:submit_ham).and_return(true)
end
end end
it 'submits the log as ham' do it 'submits the log as ham' do
post :mark_as_ham, params: { id: first_spam.id } post :mark_as_ham, params: { id: first_spam.id }

View File

@ -20,8 +20,9 @@ describe Import::GitlabController do
describe "GET callback" do describe "GET callback" do
it "updates access token" do it "updates access token" do
allow_any_instance_of(Gitlab::GitlabImport::Client) allow_next_instance_of(Gitlab::GitlabImport::Client) do |instance|
.to receive(:get_token).and_return(token) allow(instance).to receive(:get_token).and_return(token)
end
stub_omniauth_provider('gitlab') stub_omniauth_provider('gitlab')
get :callback get :callback

View File

@ -104,7 +104,9 @@ describe Projects::DiscussionsController do
end end
it "sends notifications if all discussions are resolved" do it "sends notifications if all discussions are resolved" do
expect_any_instance_of(MergeRequests::ResolvedDiscussionNotificationService).to receive(:execute).with(merge_request) expect_next_instance_of(MergeRequests::ResolvedDiscussionNotificationService) do |instance|
expect(instance).to receive(:execute).with(merge_request)
end
post :resolve, params: request_params post :resolve, params: request_params
end end
@ -122,8 +124,10 @@ describe Projects::DiscussionsController do
end end
it "renders discussion with serializer" do it "renders discussion with serializer" do
expect_any_instance_of(DiscussionSerializer).to receive(:represent) expect_next_instance_of(DiscussionSerializer) do |instance|
.with(instance_of(Discussion), { context: instance_of(described_class), render_truncated_diff_lines: true }) expect(instance).to receive(:represent)
.with(instance_of(Discussion), { context: instance_of(described_class), render_truncated_diff_lines: true })
end
post :resolve, params: request_params post :resolve, params: request_params
end end
@ -193,8 +197,10 @@ describe Projects::DiscussionsController do
end end
it "renders discussion with serializer" do it "renders discussion with serializer" do
expect_any_instance_of(DiscussionSerializer).to receive(:represent) expect_next_instance_of(DiscussionSerializer) do |instance|
.with(instance_of(Discussion), { context: instance_of(described_class), render_truncated_diff_lines: true }) expect(instance).to receive(:represent)
.with(instance_of(Discussion), { context: instance_of(described_class), render_truncated_diff_lines: true })
end
delete :unresolve, params: request_params delete :unresolve, params: request_params
end end

View File

@ -13,8 +13,9 @@ describe Projects::MattermostsController do
describe 'GET #new' do describe 'GET #new' do
before do before do
allow_any_instance_of(MattermostSlashCommandsService) allow_next_instance_of(MattermostSlashCommandsService) do |instance|
.to receive(:list_teams).and_return([]) allow(instance).to receive(:list_teams).and_return([])
end
end end
it 'accepts the request' do it 'accepts the request' do
@ -42,7 +43,9 @@ describe Projects::MattermostsController do
context 'no request can be made to mattermost' do context 'no request can be made to mattermost' do
it 'shows the error' do it 'shows the error' do
allow_any_instance_of(MattermostSlashCommandsService).to receive(:configure).and_return([false, "error message"]) allow_next_instance_of(MattermostSlashCommandsService) do |instance|
allow(instance).to receive(:configure).and_return([false, "error message"])
end
expect(subject).to redirect_to(new_project_mattermost_url(project)) expect(subject).to redirect_to(new_project_mattermost_url(project))
end end
@ -50,7 +53,9 @@ describe Projects::MattermostsController do
context 'the request is succesull' do context 'the request is succesull' do
before do before do
allow_any_instance_of(Mattermost::Command).to receive(:create).and_return('token') allow_next_instance_of(Mattermost::Command) do |instance|
allow(instance).to receive(:create).and_return('token')
end
end end
it 'redirects to the new page' do it 'redirects to the new page' do

View File

@ -85,7 +85,9 @@ describe Projects::MergeRequests::CreationsController do
describe 'GET diffs' do describe 'GET diffs' do
context 'when merge request cannot be created' do context 'when merge request cannot be created' do
it 'does not assign diffs var' do it 'does not assign diffs var' do
allow_any_instance_of(MergeRequest).to receive(:can_be_created).and_return(false) allow_next_instance_of(MergeRequest) do |instance|
allow(instance).to receive(:can_be_created).and_return(false)
end
get :diffs, params: get_diff_params.merge(format: 'json') get :diffs, params: get_diff_params.merge(format: 'json')

View File

@ -86,7 +86,9 @@ describe Projects::MergeRequests::DiffsController do
end end
it 'serializes merge request diff collection' do it 'serializes merge request diff collection' do
expect_any_instance_of(DiffsSerializer).to receive(:represent).with(an_instance_of(Gitlab::Diff::FileCollection::MergeRequestDiff), an_instance_of(Hash)) expect_next_instance_of(DiffsSerializer) do |instance|
expect(instance).to receive(:represent).with(an_instance_of(Gitlab::Diff::FileCollection::MergeRequestDiff), an_instance_of(Hash))
end
go go
end end
@ -98,7 +100,9 @@ describe Projects::MergeRequests::DiffsController do
end end
it 'serializes merge request diff collection' do it 'serializes merge request diff collection' do
expect_any_instance_of(DiffsSerializer).to receive(:represent).with(an_instance_of(Gitlab::Diff::FileCollection::MergeRequestDiff), an_instance_of(Hash)) expect_next_instance_of(DiffsSerializer) do |instance|
expect(instance).to receive(:represent).with(an_instance_of(Gitlab::Diff::FileCollection::MergeRequestDiff), an_instance_of(Hash))
end
go go
end end

View File

@ -785,7 +785,9 @@ describe Projects::NotesController do
end end
it "sends notifications if all discussions are resolved" do it "sends notifications if all discussions are resolved" do
expect_any_instance_of(MergeRequests::ResolvedDiscussionNotificationService).to receive(:execute).with(merge_request) expect_next_instance_of(MergeRequests::ResolvedDiscussionNotificationService) do |instance|
expect(instance).to receive(:execute).with(merge_request)
end
post :resolve, params: request_params post :resolve, params: request_params
end end

View File

@ -45,7 +45,9 @@ describe Projects::ProjectMembersController do
end end
it 'adds user to members' do it 'adds user to members' do
expect_any_instance_of(Members::CreateService).to receive(:execute).and_return(status: :success) expect_next_instance_of(Members::CreateService) do |instance|
expect(instance).to receive(:execute).and_return(status: :success)
end
post :create, params: { post :create, params: {
namespace_id: project.namespace, namespace_id: project.namespace,
@ -59,7 +61,9 @@ describe Projects::ProjectMembersController do
end end
it 'adds no user to members' do it 'adds no user to members' do
expect_any_instance_of(Members::CreateService).to receive(:execute).and_return(status: :failure, message: 'Message') expect_next_instance_of(Members::CreateService) do |instance|
expect(instance).to receive(:execute).and_return(status: :failure, message: 'Message')
end
post :create, params: { post :create, params: {
namespace_id: project.namespace, namespace_id: project.namespace,

View File

@ -85,7 +85,9 @@ describe Projects::Prometheus::MetricsController do
end end
it 'calls prometheus adapter service' do it 'calls prometheus adapter service' do
expect_any_instance_of(::Prometheus::AdapterService).to receive(:prometheus_adapter) expect_next_instance_of(::Prometheus::AdapterService) do |instance|
expect(instance).to receive(:prometheus_adapter)
end
subject.__send__(:prometheus_adapter) subject.__send__(:prometheus_adapter)
end end

View File

@ -125,7 +125,9 @@ describe Projects::Settings::CiCdController do
context 'when run_auto_devops_pipeline is true' do context 'when run_auto_devops_pipeline is true' do
before do before do
expect_any_instance_of(Projects::UpdateService).to receive(:run_auto_devops_pipeline?).and_return(true) expect_next_instance_of(Projects::UpdateService) do |instance|
expect(instance).to receive(:run_auto_devops_pipeline?).and_return(true)
end
end end
context 'when the project repository is empty' do context 'when the project repository is empty' do
@ -159,7 +161,9 @@ describe Projects::Settings::CiCdController do
context 'when run_auto_devops_pipeline is not true' do context 'when run_auto_devops_pipeline is not true' do
before do before do
expect_any_instance_of(Projects::UpdateService).to receive(:run_auto_devops_pipeline?).and_return(false) expect_next_instance_of(Projects::UpdateService) do |instance|
expect(instance).to receive(:run_auto_devops_pipeline?).and_return(false)
end
end end
it 'does not queue a CreatePipelineWorker' do it 'does not queue a CreatePipelineWorker' do

View File

@ -92,7 +92,9 @@ describe Projects::SnippetsController do
context 'when the snippet is spam' do context 'when the snippet is spam' do
before do before do
allow_any_instance_of(AkismetService).to receive(:spam?).and_return(true) allow_next_instance_of(AkismetService) do |instance|
allow(instance).to receive(:spam?).and_return(true)
end
end end
context 'when the snippet is private' do context 'when the snippet is private' do
@ -170,7 +172,9 @@ describe Projects::SnippetsController do
context 'when the snippet is spam' do context 'when the snippet is spam' do
before do before do
allow_any_instance_of(AkismetService).to receive(:spam?).and_return(true) allow_next_instance_of(AkismetService) do |instance|
allow(instance).to receive(:spam?).and_return(true)
end
end end
context 'when the snippet is private' do context 'when the snippet is private' do
@ -278,7 +282,9 @@ describe Projects::SnippetsController do
let(:snippet) { create(:project_snippet, :private, project: project, author: user) } let(:snippet) { create(:project_snippet, :private, project: project, author: user) }
before do before do
allow_any_instance_of(AkismetService).to receive_messages(submit_spam: true) allow_next_instance_of(AkismetService) do |instance|
allow(instance).to receive_messages(submit_spam: true)
end
stub_application_setting(akismet_enabled: true) stub_application_setting(akismet_enabled: true)
end end

View File

@ -927,6 +927,30 @@ describe ProjectsController do
expect(json_response['body']).to match(/\!#{merge_request.iid} \(closed\)/) expect(json_response['body']).to match(/\!#{merge_request.iid} \(closed\)/)
end end
end end
context 'when path parameter is provided' do
let(:project_with_repo) { create(:project, :repository) }
let(:preview_markdown_params) do
{
namespace_id: project_with_repo.namespace,
id: project_with_repo,
text: "![](./logo-white.png)\n",
path: 'files/images/README.md'
}
end
before do
project_with_repo.add_maintainer(user)
end
it 'renders JSON body with image links expanded' do
expanded_path = "/#{project_with_repo.full_path}/raw/master/files/images/logo-white.png"
post :preview_markdown, params: preview_markdown_params
expect(json_response['body']).to include(expanded_path)
end
end
end end
describe '#ensure_canonical_path' do describe '#ensure_canonical_path' do

View File

@ -174,7 +174,9 @@ describe UsersController do
let(:user) { create(:user) } let(:user) { create(:user) }
before do before do
allow_any_instance_of(User).to receive(:contributed_projects_ids).and_return([project.id]) allow_next_instance_of(User) do |instance|
allow(instance).to receive(:contributed_projects_ids).and_return([project.id])
end
sign_in(user) sign_in(user)
project.add_developer(user) project.add_developer(user)

View File

@ -73,8 +73,9 @@ describe "Admin::Projects" do
before do before do
create(:group, name: 'Web') create(:group, name: 'Web')
allow_any_instance_of(Projects::TransferService) allow_next_instance_of(Projects::TransferService) do |instance|
.to receive(:move_uploads_to_new_namespace).and_return(true) allow(instance).to receive(:move_uploads_to_new_namespace).and_return(true)
end
end end
it 'transfers project to group web', :js do it 'transfers project to group web', :js do

View File

@ -179,7 +179,9 @@ describe "Admin::Users" do
end end
it "calls send mail" do it "calls send mail" do
expect_any_instance_of(NotificationService).to receive(:new_user) expect_next_instance_of(NotificationService) do |instance|
expect(instance).to receive(:new_user)
end
click_button "Create user" click_button "Create user"
end end

View File

@ -40,7 +40,9 @@ describe 'Cycle Analytics', :js do
context "when there's cycle analytics data" do context "when there's cycle analytics data" do
before do before do
allow_any_instance_of(Gitlab::ReferenceExtractor).to receive(:issues).and_return([issue]) allow_next_instance_of(Gitlab::ReferenceExtractor) do |instance|
allow(instance).to receive(:issues).and_return([issue])
end
project.add_maintainer(user) project.add_maintainer(user)
@build = create_cycle(user, project, issue, mr, milestone, pipeline) @build = create_cycle(user, project, issue, mr, milestone, pipeline)
@ -99,7 +101,9 @@ describe 'Cycle Analytics', :js do
project.add_developer(user) project.add_developer(user)
project.add_guest(guest) project.add_guest(guest)
allow_any_instance_of(Gitlab::ReferenceExtractor).to receive(:issues).and_return([issue]) allow_next_instance_of(Gitlab::ReferenceExtractor) do |instance|
allow(instance).to receive(:issues).and_return([issue])
end
create_cycle(user, project, issue, mr, milestone, pipeline) create_cycle(user, project, issue, mr, milestone, pipeline)
deploy_master(user, project) deploy_master(user, project)

View File

@ -21,7 +21,9 @@ describe 'Global search' do
describe 'I search through the issues and I see pagination' do describe 'I search through the issues and I see pagination' do
before do before do
allow_any_instance_of(Gitlab::SearchResults).to receive(:per_page).and_return(1) allow_next_instance_of(Gitlab::SearchResults) do |instance|
allow(instance).to receive(:per_page).and_return(1)
end
create_list(:issue, 2, project: project, title: 'initial') create_list(:issue, 2, project: project, title: 'initial')
end end

View File

@ -13,8 +13,12 @@ describe 'User Cluster', :js do
gitlab_sign_in(user) gitlab_sign_in(user)
allow(Groups::ClustersController).to receive(:STATUS_POLLING_INTERVAL) { 100 } allow(Groups::ClustersController).to receive(:STATUS_POLLING_INTERVAL) { 100 }
allow_any_instance_of(Clusters::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute) allow_next_instance_of(Clusters::Kubernetes::CreateOrUpdateNamespaceService) do |instance|
allow_any_instance_of(Clusters::Cluster).to receive(:retrieve_connection_status).and_return(:connected) allow(instance).to receive(:execute)
end
allow_next_instance_of(Clusters::Cluster) do |instance|
allow(instance).to receive(:retrieve_connection_status).and_return(:connected)
end
end end
context 'when user does not have a cluster and visits cluster index page' do context 'when user does not have a cluster and visits cluster index page' do

View File

@ -17,7 +17,9 @@ describe "Jira", :js do
stub_request(:get, "https://jira.example.com/rest/api/2/issue/JIRA-5") stub_request(:get, "https://jira.example.com/rest/api/2/issue/JIRA-5")
stub_request(:post, "https://jira.example.com/rest/api/2/issue/JIRA-5/comment") stub_request(:post, "https://jira.example.com/rest/api/2/issue/JIRA-5/comment")
allow_any_instance_of(JIRA::Resource::Issue).to receive(:remotelink).and_return(remotelink) allow_next_instance_of(JIRA::Resource::Issue) do |instance|
allow(instance).to receive(:remotelink).and_return(remotelink)
end
sign_in(user) sign_in(user)

View File

@ -47,7 +47,9 @@ describe 'User squashes a merge request', :js do
before do before do
# Prevent source branch from being removed so we can use be_merged_to_root_ref # Prevent source branch from being removed so we can use be_merged_to_root_ref
# method to check if squash was performed or not # method to check if squash was performed or not
allow_any_instance_of(MergeRequest).to receive(:force_remove_source_branch?).and_return(false) allow_next_instance_of(MergeRequest) do |instance|
allow(instance).to receive(:force_remove_source_branch?).and_return(false)
end
project.add_maintainer(user) project.add_maintainer(user)
sign_in user sign_in user

View File

@ -13,8 +13,12 @@ describe 'User Cluster', :js do
gitlab_sign_in(user) gitlab_sign_in(user)
allow(Projects::ClustersController).to receive(:STATUS_POLLING_INTERVAL) { 100 } allow(Projects::ClustersController).to receive(:STATUS_POLLING_INTERVAL) { 100 }
allow_any_instance_of(Clusters::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute) allow_next_instance_of(Clusters::Kubernetes::CreateOrUpdateNamespaceService) do |instance|
allow_any_instance_of(Clusters::Cluster).to receive(:retrieve_connection_status).and_return(:connected) allow(instance).to receive(:execute)
end
allow_next_instance_of(Clusters::Cluster) do |instance|
allow(instance).to receive(:retrieve_connection_status).and_return(:connected)
end
end end
context 'when user does not have a cluster and visits cluster index page' do context 'when user does not have a cluster and visits cluster index page' do

View File

@ -57,7 +57,9 @@ describe 'User browses commits' do
create(:ci_build, pipeline: pipeline) create(:ci_build, pipeline: pipeline)
allow_any_instance_of(Ci::Pipeline).to receive(:ci_yaml_file).and_return('') allow_next_instance_of(Ci::Pipeline) do |instance|
allow(instance).to receive(:ci_yaml_file).and_return('')
end
end end
it 'renders commit ci info' do it 'renders commit ci info' do
@ -94,8 +96,12 @@ describe 'User browses commits' do
let(:commit) { create(:commit, project: project) } let(:commit) { create(:commit, project: project) }
it 'renders successfully' do it 'renders successfully' do
allow_any_instance_of(Gitlab::Diff::File).to receive(:blob).and_return(nil) allow_next_instance_of(Gitlab::Diff::File) do |instance|
allow_any_instance_of(Gitlab::Diff::File).to receive(:binary?).and_return(true) allow(instance).to receive(:blob).and_return(nil)
end
allow_next_instance_of(Gitlab::Diff::File) do |instance|
allow(instance).to receive(:binary?).and_return(true)
end
visit(project_commit_path(project, commit)) visit(project_commit_path(project, commit))

View File

@ -107,7 +107,9 @@ describe "Compare", :js do
visit project_compare_index_path(project, from: "feature", to: "master") visit project_compare_index_path(project, from: "feature", to: "master")
allow(Commit).to receive(:max_diff_options).and_return(max_files: 3) allow(Commit).to receive(:max_diff_options).and_return(max_files: 3)
allow_any_instance_of(DiffHelper).to receive(:render_overflow_warning?).and_return(true) allow_next_instance_of(DiffHelper) do |instance|
allow(instance).to receive(:render_overflow_warning?).and_return(true)
end
click_button('Compare') click_button('Compare')

View File

@ -175,8 +175,9 @@ describe 'Environment' do
# #
# In EE we have to stub EE::Environment since it overwrites # In EE we have to stub EE::Environment since it overwrites
# the "terminals" method. # the "terminals" method.
allow_any_instance_of(Gitlab.ee? ? EE::Environment : Environment) allow_next_instance_of(Gitlab.ee? ? EE::Environment : Environment) do |instance|
.to receive(:terminals) { nil } allow(instance).to receive(:terminals) { nil }
end
visit terminal_project_environment_path(project, environment) visit terminal_project_environment_path(project, environment)
end end

View File

@ -71,7 +71,9 @@ describe 'Environments page', :js do
let!(:application_prometheus) { create(:clusters_applications_prometheus, :installed, cluster: cluster) } let!(:application_prometheus) { create(:clusters_applications_prometheus, :installed, cluster: cluster) }
before do before do
allow_any_instance_of(Kubeclient::Client).to receive(:proxy_url).and_raise(Kubeclient::HttpError.new(401, 'Unauthorized', nil)) allow_next_instance_of(Kubeclient::Client) do |instance|
allow(instance).to receive(:proxy_url).and_raise(Kubeclient::HttpError.new(401, 'Unauthorized', nil))
end
end end
it 'shows one environment without error' do it 'shows one environment without error' do

View File

@ -42,7 +42,9 @@ describe 'Edit Project Settings' do
context 'When external issue tracker is enabled and issues enabled on project settings' do context 'When external issue tracker is enabled and issues enabled on project settings' do
it 'does not hide issues tab' do it 'does not hide issues tab' do
allow_any_instance_of(Project).to receive(:external_issue_tracker).and_return(JiraService.new) allow_next_instance_of(Project) do |instance|
allow(instance).to receive(:external_issue_tracker).and_return(JiraService.new)
end
visit project_path(project) visit project_path(project)
@ -54,7 +56,9 @@ describe 'Edit Project Settings' do
it 'hides issues tab' do it 'hides issues tab' do
project.issues_enabled = false project.issues_enabled = false
project.save! project.save!
allow_any_instance_of(Project).to receive(:external_issue_tracker).and_return(JiraService.new) allow_next_instance_of(Project) do |instance|
allow(instance).to receive(:external_issue_tracker).and_return(JiraService.new)
end
visit project_path(project) visit project_path(project)

View File

@ -26,7 +26,9 @@ describe 'Import/Export - project export integration test', :js do
let(:project) { setup_project } let(:project) { setup_project }
before do before do
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) allow_next_instance_of(Gitlab::ImportExport) do |instance|
allow(instance).to receive(:storage_path).and_return(export_path)
end
end end
after do after do

View File

@ -11,7 +11,9 @@ describe 'Import/Export - project import integration test', :js do
before do before do
stub_uploads_object_storage(FileUploader) stub_uploads_object_storage(FileUploader)
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) allow_next_instance_of(Gitlab::ImportExport) do |instance|
allow(instance).to receive(:storage_path).and_return(export_path)
end
gitlab_sign_in(user) gitlab_sign_in(user)
end end

View File

@ -18,7 +18,9 @@ describe "Pages with Let's Encrypt", :https_pages_enabled do
project.add_role(user, role) project.add_role(user, role)
sign_in(user) sign_in(user)
project.namespace.update(owner: user) project.namespace.update(owner: user)
allow_any_instance_of(Project).to receive(:pages_deployed?) { true } allow_next_instance_of(Project) do |instance|
allow(instance).to receive(:pages_deployed?) { true }
end
end end
context 'when the auto SSL management is initially disabled' do context 'when the auto SSL management is initially disabled' do

View File

@ -264,7 +264,9 @@ describe "Internal Project Access" do
before do before do
# Speed increase # Speed increase
allow_any_instance_of(Project).to receive(:branches).and_return([]) allow_next_instance_of(Project) do |instance|
allow(instance).to receive(:branches).and_return([])
end
end end
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -283,7 +285,9 @@ describe "Internal Project Access" do
before do before do
# Speed increase # Speed increase
allow_any_instance_of(Project).to receive(:tags).and_return([]) allow_next_instance_of(Project) do |instance|
allow(instance).to receive(:tags).and_return([])
end
end end
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }

View File

@ -236,7 +236,9 @@ describe "Private Project Access" do
before do before do
# Speed increase # Speed increase
allow_any_instance_of(Project).to receive(:branches).and_return([]) allow_next_instance_of(Project) do |instance|
allow(instance).to receive(:branches).and_return([])
end
end end
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -255,7 +257,9 @@ describe "Private Project Access" do
before do before do
# Speed increase # Speed increase
allow_any_instance_of(Project).to receive(:tags).and_return([]) allow_next_instance_of(Project) do |instance|
allow(instance).to receive(:tags).and_return([])
end
end end
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }

View File

@ -477,7 +477,9 @@ describe "Public Project Access" do
before do before do
# Speed increase # Speed increase
allow_any_instance_of(Project).to receive(:branches).and_return([]) allow_next_instance_of(Project) do |instance|
allow(instance).to receive(:branches).and_return([])
end
end end
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -496,7 +498,9 @@ describe "Public Project Access" do
before do before do
# Speed increase # Speed increase
allow_any_instance_of(Project).to receive(:tags).and_return([]) allow_next_instance_of(Project) do |instance|
allow(instance).to receive(:tags).and_return([])
end
end end
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }

View File

@ -39,8 +39,10 @@ describe 'Developer deletes tag' do
context 'when pre-receive hook fails', :js do context 'when pre-receive hook fails', :js do
before do before do
allow_any_instance_of(Gitlab::GitalyClient::OperationService).to receive(:rm_tag) allow_next_instance_of(Gitlab::GitalyClient::OperationService) do |instance|
.and_raise(Gitlab::Git::PreReceiveError, 'GitLab: Do not delete tags') allow(instance).to receive(:rm_tag)
.and_raise(Gitlab::Git::PreReceiveError, 'GitLab: Do not delete tags')
end
end end
it 'shows the error message' do it 'shows the error message' do

View File

@ -379,7 +379,9 @@ shared_examples 'Signup' do
before do before do
InvisibleCaptcha.timestamp_enabled = true InvisibleCaptcha.timestamp_enabled = true
stub_application_setting(recaptcha_enabled: true) stub_application_setting(recaptcha_enabled: true)
allow_any_instance_of(RegistrationsController).to receive(:verify_recaptcha).and_return(false) allow_next_instance_of(RegistrationsController) do |instance|
allow(instance).to receive(:verify_recaptcha).and_return(false)
end
end end
after do after do

View File

@ -34,7 +34,9 @@ context 'U2F' do
before do before do
sign_in(user) sign_in(user)
allow_any_instance_of(Profiles::TwoFactorAuthsController).to receive(:build_qr_code).and_return('qrcode:blackandwhitesquares') allow_next_instance_of(Profiles::TwoFactorAuthsController) do |instance|
allow(instance).to receive(:build_qr_code).and_return('qrcode:blackandwhitesquares')
end
end end
it 'u2f/register.html' do it 'u2f/register.html' do

View File

@ -89,6 +89,35 @@ describe MarkupHelper do
end end
end end
end end
context 'when text contains a relative link to an image in the repository' do
let(:image_file) { "logo-white.png" }
let(:text_with_relative_path) { "![](./#{image_file})\n" }
let(:generated_html) { helper.markdown(text_with_relative_path, requested_path: requested_path) }
subject { Nokogiri::HTML.parse(generated_html) }
context 'when requested_path is provided in the context' do
let(:requested_path) { 'files/images/README.md' }
it 'returns the correct HTML for the image' do
expanded_path = "/#{project.full_path}/raw/master/files/images/#{image_file}"
expect(subject.css('a')[0].attr('href')).to eq(expanded_path)
expect(subject.css('img')[0].attr('data-src')).to eq(expanded_path)
end
end
context 'when requested_path parameter is not provided' do
let(:requested_path) { nil }
it 'returns the link to the image path as a relative path' do
expanded_path = "/#{project.full_path}/master/./#{image_file}"
expect(subject.css('a')[0].attr('href')).to eq(expanded_path)
end
end
end
end end
describe '#markdown_field' do describe '#markdown_field' do

View File

@ -70,4 +70,30 @@ describe('ContentViewer', () => {
done(); done();
}); });
}); });
it('markdown preview receives the file path as a parameter', done => {
mock = new MockAdapter(axios);
spyOn(axios, 'post').and.callThrough();
mock.onPost(`${gon.relative_url_root}/testproject/preview_markdown`).reply(200, {
body: '<b>testing</b>',
});
createComponent({
path: 'test.md',
content: '* Test',
projectPath: 'testproject',
type: 'markdown',
filePath: 'foo/test.md',
});
setTimeout(() => {
expect(axios.post).toHaveBeenCalledWith(
`${gon.relative_url_root}/testproject/preview_markdown`,
{ path: 'foo/test.md', text: '* Test' },
jasmine.any(Object),
);
done();
});
});
}); });

View File

@ -211,10 +211,12 @@ describe Gitlab::GitalyClient::OperationService do
end end
context 'when a create_tree_error is present' do context 'when a create_tree_error is present' do
let(:response) { response_class.new(create_tree_error: "something failed") } let(:response) { response_class.new(create_tree_error: "something failed", create_tree_error_code: 'EMPTY') }
it 'raises a CreateTreeError' do it 'raises a CreateTreeError' do
expect { subject }.to raise_error(Gitlab::Git::Repository::CreateTreeError, "something failed") expect { subject }.to raise_error(Gitlab::Git::Repository::CreateTreeError) do |error|
expect(error.error_code).to eq(:empty)
end
end end
end end

View File

@ -340,7 +340,7 @@ project:
- triggers - triggers
- pipeline_schedules - pipeline_schedules
- environments - environments
- unfoldered_environments - environments_for_dashboard
- deployments - deployments
- project_feature - project_feature
- auto_devops - auto_devops

View File

@ -30,7 +30,7 @@ describe Gitlab::Kubernetes::Helm::Pod do
it 'generates the appropriate specifications for the container' do it 'generates the appropriate specifications for the container' do
container = subject.generate.spec.containers.first container = subject.generate.spec.containers.first
expect(container.name).to eq('helm') expect(container.name).to eq('helm')
expect(container.image).to eq('registry.gitlab.com/gitlab-org/cluster-integration/helm-install-image/releases/2.15.1-kube-1.13.12') expect(container.image).to eq('registry.gitlab.com/gitlab-org/cluster-integration/helm-install-image/releases/2.16.1-kube-1.13.12')
expect(container.env.count).to eq(3) expect(container.env.count).to eq(3)
expect(container.env.map(&:name)).to match_array([:HELM_VERSION, :TILLER_NAMESPACE, :COMMAND_SCRIPT]) expect(container.env.map(&:name)).to match_array([:HELM_VERSION, :TILLER_NAMESPACE, :COMMAND_SCRIPT])
expect(container.command).to match_array(["/bin/sh"]) expect(container.command).to match_array(["/bin/sh"])

View File

@ -3,6 +3,8 @@
require 'spec_helper' require 'spec_helper'
describe Clusters::Applications::ElasticStack do describe Clusters::Applications::ElasticStack do
include KubernetesHelpers
include_examples 'cluster application core specs', :clusters_applications_elastic_stack include_examples 'cluster application core specs', :clusters_applications_elastic_stack
include_examples 'cluster application status specs', :clusters_applications_elastic_stack include_examples 'cluster application status specs', :clusters_applications_elastic_stack
include_examples 'cluster application version specs', :clusters_applications_elastic_stack include_examples 'cluster application version specs', :clusters_applications_elastic_stack
@ -110,4 +112,68 @@ describe Clusters::Applications::ElasticStack do
expect(values).to include('ELASTICSEARCH_HOSTS') expect(values).to include('ELASTICSEARCH_HOSTS')
end end
end end
describe '#elasticsearch_client' do
context 'cluster is nil' do
it 'returns nil' do
expect(subject.cluster).to be_nil
expect(subject.elasticsearch_client).to be_nil
end
end
context "cluster doesn't have kubeclient" do
let(:cluster) { create(:cluster) }
subject { create(:clusters_applications_elastic_stack, cluster: cluster) }
it 'returns nil' do
expect(subject.elasticsearch_client).to be_nil
end
end
context 'cluster has kubeclient' do
let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:kubernetes_url) { subject.cluster.platform_kubernetes.api_url }
let(:kube_client) { subject.cluster.kubeclient.core_client }
subject { create(:clusters_applications_elastic_stack, cluster: cluster) }
before do
subject.cluster.platform_kubernetes.namespace = 'a-namespace'
stub_kubeclient_discover(cluster.platform_kubernetes.api_url)
create(:cluster_kubernetes_namespace,
cluster: cluster,
cluster_project: cluster.cluster_project,
project: cluster.cluster_project.project)
end
it 'creates proxy elasticsearch_client' do
expect(subject.elasticsearch_client).to be_instance_of(Elasticsearch::Transport::Client)
end
it 'copies proxy_url, options and headers from kube client to elasticsearch_client' do
expect(Elasticsearch::Client)
.to(receive(:new))
.with(url: a_valid_url)
.and_call_original
client = subject.elasticsearch_client
faraday_connection = client.transport.connections.first.connection
expect(faraday_connection.headers["Authorization"]).to eq(kube_client.headers[:Authorization])
expect(faraday_connection.ssl.cert_store).to be_instance_of(OpenSSL::X509::Store)
expect(faraday_connection.ssl.verify).to eq(1)
end
context 'when cluster is not reachable' do
before do
allow(kube_client).to receive(:proxy_url).and_raise(Kubeclient::HttpError.new(401, 'Unauthorized', nil))
end
it 'returns nil' do
expect(subject.elasticsearch_client).to be_nil
end
end
end
end
end end

View File

@ -1376,6 +1376,12 @@ describe API::Commits do
it_behaves_like '400 response' do it_behaves_like '400 response' do
let(:request) { post api(route, current_user), params: { branch: 'markdown' } } let(:request) { post api(route, current_user), params: { branch: 'markdown' } }
end end
it 'includes an error_code in the response' do
post api(route, current_user), params: { branch: 'markdown' }
expect(json_response['error_code']).to eq 'empty'
end
end end
context 'when ref contains a dot' do context 'when ref contains a dot' do
@ -1535,6 +1541,19 @@ describe API::Commits do
let(:request) { post api(route, current_user) } let(:request) { post api(route, current_user) }
end end
end end
context 'when commit is already reverted in the target branch' do
it 'includes an error_code in the response' do
# First one actually reverts
post api(route, current_user), params: { branch: 'markdown' }
# Second one is redundant and should be empty
post api(route, current_user), params: { branch: 'markdown' }
expect(response).to have_gitlab_http_status(400)
expect(json_response['error_code']).to eq 'empty'
end
end
end end
context 'when authenticated', 'as a developer' do context 'when authenticated', 'as a developer' do

View File

@ -16,7 +16,7 @@ module KubernetesHelpers
end end
def kube_logs_response def kube_logs_response
kube_response(kube_logs_body) { body: kube_logs_body }
end end
def kube_deployments_response def kube_deployments_response