Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
eed996ac33
commit
29c01c6c91
2
Gemfile
2
Gemfile
|
@ -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
|
||||||
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)
|
||||||
|
|
|
@ -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 {
|
||||||
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"
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
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
|
||||||
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 @@
|
||||||
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,
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Enable environments dashboard by default
|
||||||
|
merge_request: 19838
|
||||||
|
author:
|
||||||
|
type: added
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Fix broken images when previewing markdown files in Web IDE
|
||||||
|
merge_request: 18899
|
||||||
|
author:
|
||||||
|
type: fixed
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Increase PumaWorkerKiller memory limit in development environment
|
||||||
|
merge_request: 20039
|
||||||
|
author:
|
||||||
|
type: performance
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Helm v2.16.1
|
||||||
|
merge_request: 19981
|
||||||
|
author:
|
||||||
|
type: fixed
|
|
@ -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
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
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 @@
|
||||||
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,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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
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
|
||||||
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
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
|
||||||
|
|
|
@ -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
|
||||||
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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
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
|
||||||
|
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
|
|
||||||
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))
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
#
|
#
|
||||||
# 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
|
||||||
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
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
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
|
||||||
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
|
||||||
|
|
||||||
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) }
|
||||||
|
|
|
@ -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) }
|
||||||
|
|
|
@ -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) }
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
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
|
||||||
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', () => {
|
||||||
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
|
||||||
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:
|
||||||
- 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
|
||||||
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 @@
|
||||||
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue