Commit 29c01c6c authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent eed996ac
...@@ -449,7 +449,7 @@ group :ed25519 do ...@@ -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'
......
...@@ -358,7 +358,7 @@ GEM ...@@ -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 ...@@ -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)
......
...@@ -301,6 +301,7 @@ export default { ...@@ -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"
......
...@@ -18,6 +18,11 @@ export default { ...@@ -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 { ...@@ -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"
......
...@@ -16,6 +16,11 @@ export default { ...@@ -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 { ...@@ -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,
......
...@@ -7,17 +7,8 @@ module PreviewMarkdown ...@@ -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 ...@@ -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
...@@ -5,12 +5,15 @@ module Clusters ...@@ -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 ...@@ -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 ...@@ -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
...@@ -60,6 +60,24 @@ module Clusters ...@@ -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
......
...@@ -12,7 +12,7 @@ class Environment < ApplicationRecord ...@@ -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 ...@@ -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
......
...@@ -287,7 +287,7 @@ class Project < ApplicationRecord ...@@ -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
......
...@@ -50,16 +50,24 @@ class BaseService ...@@ -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
......
...@@ -23,14 +23,15 @@ module Commits ...@@ -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
...@@ -3,7 +3,15 @@ ...@@ -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 ...@@ -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,
......
---
title: Enable environments dashboard by default
merge_request: 19838
author:
type: added
---
title: Fix broken images when previewing markdown files in Web IDE
merge_request: 18899
author:
type: fixed
---
title: Increase PumaWorkerKiller memory limit in development environment
merge_request: 20039
author:
type: performance
---
title: Helm v2.16.1
merge_request: 19981
author:
type: fixed
---
title: 'Add an `error_code` attribute to the API response when a cherry-pick or revert fails.'
merge_request: 19518
author:
type: added
...@@ -317,6 +317,21 @@ Example response: ...@@ -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: ...@@ -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.
......
...@@ -32,10 +32,23 @@ Management projects are restricted to the following: ...@@ -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)
......
...@@ -223,7 +223,7 @@ module API ...@@ -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 ...@@ -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
......
.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
......
.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
......
...@@ -3,7 +3,12 @@ ...@@ -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 ...@@ -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
......
...@@ -25,9 +25,18 @@ module Gitlab ...@@ -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
......
...@@ -447,7 +447,7 @@ module Gitlab ...@@ -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)
......
...@@ -3,7 +3,7 @@ ...@@ -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'
......
...@@ -227,17 +227,18 @@ describe Admin::ClustersController do ...@@ -227,17 +227,18 @@ 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)
end end
...@@ -467,7 +468,9 @@ describe Admin::ClustersController do ...@@ -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
......
...@@ -13,7 +13,9 @@ describe Admin::IdentitiesController do ...@@ -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 ...@@ -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
......
...@@ -39,7 +39,9 @@ describe Admin::SpamLogsController do ...@@ -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 }
......
...@@ -20,8 +20,9 @@ describe Import::GitlabController do ...@@ -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
......
...@@ -104,7 +104,9 @@ describe Projects::DiscussionsController do ...@@ -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 ...@@ -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|
expect(instance).to receive(:represent)
.with(instance_of(Discussion), { context: instance_of(described_class), render_truncated_diff_lines: true }) .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 ...@@ -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|
expect(instance).to receive(:represent)
.with(instance_of(Discussion), { context: instance_of(described_class), render_truncated_diff_lines: true }) .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
......
...@@ -13,8 +13,9 @@ describe Projects::MattermostsController do ...@@ -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 ...@@ -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 ...@@ -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
......
...@@ -85,7 +85,9 @@ describe Projects::MergeRequests::CreationsController do ...@@ -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')
......
...@@ -86,7 +86,9 @@ describe Projects::MergeRequests::DiffsController do ...@@ -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 ...@@ -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
......
...@@ -785,7 +785,9 @@ describe Projects::NotesController do ...@@ -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
......
...@@ -45,7 +45,9 @@ describe Projects::ProjectMembersController do ...@@ -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 ...@@ -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,
......
...@@ -85,7 +85,9 @@ describe Projects::Prometheus::MetricsController do ...@@ -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
......
...@@ -125,7 +125,9 @@ describe Projects::Settings::CiCdController do ...@@ -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 ...@@ -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
......
...@@ -92,7 +92,9 @@ describe Projects::SnippetsController do ...@@ -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 ...@@ -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 ...@@ -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
......
...@@ -927,6 +927,30 @@ describe ProjectsController do ...@@ -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
......
...@@ -174,7 +174,9 @@ describe UsersController do ...@@ -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)
......
...@@ -73,8 +73,9 @@ describe "Admin::Projects" do ...@@ -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
......
...@@ -179,7 +179,9 @@ describe "Admin::Users" do ...@@ -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
......
...@@ -40,7 +40,9 @@ describe 'Cycle Analytics', :js do ...@@ -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 ...@@ -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)
......
...@@ -21,7 +21,9 @@ describe 'Global search' do ...@@ -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
......
...@@ -13,8 +13,12 @@ describe 'User Cluster', :js do ...@@ -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
......
...@@ -17,7 +17,9 @@ describe "Jira", :js do ...@@ -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)
......
...@@ -47,7 +47,9 @@ describe 'User squashes a merge request', :js do ...@@ -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
......
...@@ -13,8 +13,12 @@ describe 'User Cluster', :js do ...@@ -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
......
...@@ -57,7 +57,9 @@ describe 'User browses commits' do ...@@ -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 ...@@ -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))
......
...@@ -107,7 +107,9 @@ describe "Compare", :js do ...@@ -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')
......
...@@ -175,8 +175,9 @@ describe 'Environment' do ...@@ -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
......
...@@ -71,7 +71,9 @@ describe 'Environments page', :js do ...@@ -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
......
...@@ -42,7 +42,9 @@ describe 'Edit Project Settings' do ...@@ -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 ...@@ -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)
......
...@@ -26,7 +26,9 @@ describe 'Import/Export - project export integration test', :js do ...@@ -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
......
...@@ -11,7 +11,9 @@ describe 'Import/Export - project import integration test', :js do ...@@ -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
......
...@@ -18,7 +18,9 @@ describe "Pages with Let's Encrypt", :https_pages_enabled do ...@@ -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
......
...@@ -264,7 +264,9 @@ describe "Internal Project Access" do ...@@ -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 ...@@ -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) }
......
...@@ -236,7 +236,9 @@ describe "Private Project Access" do ...@@ -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 ...@@ -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) }
......
...@@ -477,7 +477,9 @@ describe "Public Project Access" do ...@@ -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 ...@@ -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) }
......
...@@ -39,9 +39,11 @@ describe 'Developer deletes tag' do ...@@ -39,9 +39,11 @@ 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|
allow(instance).to receive(:rm_tag)
.and_raise(Gitlab::Git::PreReceiveError, 'GitLab: Do not delete tags') .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
delete_first_tag delete_first_tag
......
...@@ -379,7 +379,9 @@ shared_examples 'Signup' do ...@@ -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
......
...@@ -34,7 +34,9 @@ context 'U2F' do ...@@ -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
......
...@@ -89,6 +89,35 @@ describe MarkupHelper do ...@@ -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
......
...@@ -70,4 +70,30 @@ describe('ContentViewer', () => { ...@@ -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();
});
});
}); });
...@@ -211,10 +211,12 @@ describe Gitlab::GitalyClient::OperationService do ...@@ -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
......
...@@ -340,7 +340,7 @@ project: ...@@ -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
......
...@@ -30,7 +30,7 @@ describe Gitlab::Kubernetes::Helm::Pod do ...@@ -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"])
......
...@@ -3,6 +3,8 @@ ...@@ -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 ...@@ -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
...@@ -1376,6 +1376,12 @@ describe API::Commits do ...@@ -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 ...@@ -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
......
...@@ -16,7 +16,7 @@ module KubernetesHelpers ...@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment