Commit 23112c46 authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2017-11-30

# Conflicts:
#	app/assets/javascripts/main.js
#	app/assets/javascripts/project.js
#	app/assets/javascripts/repo/lib/editor_options.js
#	app/helpers/button_helper.rb
#	app/models/environment.rb
#	spec/javascripts/repo/lib/editor_options_spec.js
#	spec/javascripts/repo/lib/editor_spec.js
#	spec/models/project_spec.rb

[ci skip]
parents 4eacd587 fee2a543
...@@ -114,7 +114,7 @@ gem 'google-api-client', '~> 0.13.6' ...@@ -114,7 +114,7 @@ gem 'google-api-client', '~> 0.13.6'
gem 'unf', '~> 0.1.4' gem 'unf', '~> 0.1.4'
# Seed data # Seed data
gem 'seed-fu', '~> 2.3.7' gem 'seed-fu', '2.3.6' # Upgrade to > 2.3.7 once https://github.com/mbleigh/seed-fu/issues/123 is solved
# Search # Search
gem 'elasticsearch-model', '~> 0.1.9' gem 'elasticsearch-model', '~> 0.1.9'
......
...@@ -844,7 +844,7 @@ GEM ...@@ -844,7 +844,7 @@ GEM
rake (>= 0.9, < 13) rake (>= 0.9, < 13)
sass (~> 3.4.20) sass (~> 3.4.20)
securecompare (1.0.0) securecompare (1.0.0)
seed-fu (2.3.7) seed-fu (2.3.6)
activerecord (>= 3.1) activerecord (>= 3.1)
activesupport (>= 3.1) activesupport (>= 3.1)
select2-rails (3.5.9.3) select2-rails (3.5.9.3)
...@@ -1191,7 +1191,7 @@ DEPENDENCIES ...@@ -1191,7 +1191,7 @@ DEPENDENCIES
sanitize (~> 2.0) sanitize (~> 2.0)
sass-rails (~> 5.0.6) sass-rails (~> 5.0.6)
scss_lint (~> 0.54.0) scss_lint (~> 0.54.0)
seed-fu (~> 2.3.7) seed-fu (= 2.3.6)
select2-rails (~> 3.5.9) select2-rails (~> 3.5.9)
selenium-webdriver (~> 3.5) selenium-webdriver (~> 3.5)
sentry-raven (~> 2.5.3) sentry-raven (~> 2.5.3)
......
...@@ -44,8 +44,11 @@ import './commits'; ...@@ -44,8 +44,11 @@ import './commits';
import './compare'; import './compare';
import './compare_autocomplete'; import './compare_autocomplete';
import './confirm_danger_modal'; import './confirm_danger_modal';
<<<<<<< HEAD
import './diff'; import './diff';
import './files_comment_button'; import './files_comment_button';
=======
>>>>>>> upstream/master
import Flash, { removeFlashClickListener } from './flash'; import Flash, { removeFlashClickListener } from './flash';
import './gl_dropdown'; import './gl_dropdown';
import './gl_field_error'; import './gl_field_error';
......
...@@ -25,11 +25,14 @@ export default class Project { ...@@ -25,11 +25,14 @@ export default class Project {
$this.toggleClass('is-active'); $this.toggleClass('is-active');
$projectCloneField.val(url); $projectCloneField.val(url);
$cloneBtnText.text(activeText); $cloneBtnText.text(activeText);
<<<<<<< HEAD
$('#modal-geo-info').data({ $('#modal-geo-info').data({
cloneUrlSecondary: $this.attr('href'), cloneUrlSecondary: $this.attr('href'),
cloneUrlPrimary: $this.data('primaryUrl') || '', cloneUrlPrimary: $this.data('primaryUrl') || '',
}); });
=======
>>>>>>> upstream/master
return $('.clone').text(url); return $('.clone').text(url);
}); });
......
export default [{ export default [{
<<<<<<< HEAD
readOnly: model => !!model.file.file_lock, readOnly: model => !!model.file.file_lock,
=======
>>>>>>> upstream/master
}]; }];
...@@ -252,6 +252,10 @@ ...@@ -252,6 +252,10 @@
background: $white-light; background: $white-light;
} }
.login-page-broadcast {
margin-top: 50px;
}
.navless-container { .navless-container {
padding: 65px 15px; // height of footer + bottom padding of email confirmation link padding: 65px 15px; // height of footer + bottom padding of email confirmation link
......
...@@ -41,7 +41,7 @@ class Projects::BranchesController < Projects::ApplicationController ...@@ -41,7 +41,7 @@ class Projects::BranchesController < Projects::ApplicationController
branch_name = sanitize(strip_tags(params[:branch_name])) branch_name = sanitize(strip_tags(params[:branch_name]))
branch_name = Addressable::URI.unescape(branch_name) branch_name = Addressable::URI.unescape(branch_name)
redirect_to_autodeploy = project.empty_repo? && project.deployment_services.present? redirect_to_autodeploy = project.empty_repo? && project.deployment_platform.present?
result = CreateBranchService.new(project, current_user) result = CreateBranchService.new(project, current_user)
.execute(branch_name, ref) .execute(branch_name, ref)
......
...@@ -26,7 +26,7 @@ module AutoDevopsHelper ...@@ -26,7 +26,7 @@ module AutoDevopsHelper
def auto_devops_warning_message(project) def auto_devops_warning_message(project)
missing_domain = !project.auto_devops&.has_domain? missing_domain = !project.auto_devops&.has_domain?
missing_service = !project.kubernetes_service&.active? missing_service = !project.deployment_platform&.active?
if missing_service if missing_service
params = { params = {
......
...@@ -60,6 +60,7 @@ module ButtonHelper ...@@ -60,6 +60,7 @@ module ButtonHelper
protocol = gitlab_config.protocol.upcase protocol = gitlab_config.protocol.upcase
dropdown_description = http_dropdown_description(protocol) dropdown_description = http_dropdown_description(protocol)
append_url = project.http_url_to_repo if append_link append_url = project.http_url_to_repo if append_link
<<<<<<< HEAD
geo_url = geo_primary_http_url_to_repo(project) if Gitlab::Geo.secondary? geo_url = geo_primary_http_url_to_repo(project) if Gitlab::Geo.secondary?
dropdown_item_with_description(protocol, dropdown_description, href: append_url, geo_url: geo_url) dropdown_item_with_description(protocol, dropdown_description, href: append_url, geo_url: geo_url)
...@@ -107,6 +108,35 @@ module ButtonHelper ...@@ -107,6 +108,35 @@ module ButtonHelper
container: 'body', container: 'body',
title: 'Get a Kerberos token for your<br>account with kinit.' title: 'Get a Kerberos token for your<br>account with kinit.'
} }
=======
dropdown_item_with_description(protocol, dropdown_description, href: append_url)
end
def http_dropdown_description(protocol)
if current_user.try(:require_password_creation_for_git?)
_("Set a password on your account to pull or push via %{protocol}.") % { protocol: protocol }
else
_("Create a personal access token on your account to pull or push via %{protocol}.") % { protocol: protocol }
end
end
def ssh_clone_button(project, append_link: true)
dropdown_description = _("You won't be able to pull or push project code via SSH until you add an SSH key to your profile") if current_user.try(:require_ssh_key?)
append_url = project.ssh_url_to_repo if append_link
dropdown_item_with_description('SSH', dropdown_description, href: append_url)
end
def dropdown_item_with_description(title, description, href: nil)
button_content = content_tag(:strong, title, class: 'dropdown-menu-inner-title')
button_content << content_tag(:span, description, class: 'dropdown-menu-inner-content') if description
content_tag (href ? :a : :span),
button_content,
class: "#{title.downcase}-selector",
href: (href if href)
>>>>>>> upstream/master
end end
def geo_button(modal_target: nil) def geo_button(modal_target: nil)
......
...@@ -378,7 +378,7 @@ module Ci ...@@ -378,7 +378,7 @@ module Ci
end end
def has_kubernetes_active? def has_kubernetes_active?
project.kubernetes_service&.active? project.deployment_platform&.active?
end end
def has_stage_seeds? def has_stage_seeds?
......
...@@ -17,8 +17,7 @@ module Clusters ...@@ -17,8 +17,7 @@ module Clusters
# we force autosave to happen when we save `Cluster` model # we force autosave to happen when we save `Cluster` model
has_one :provider_gcp, class_name: 'Clusters::Providers::Gcp', autosave: true has_one :provider_gcp, class_name: 'Clusters::Providers::Gcp', autosave: true
# We have to ":destroy" it today to ensure that we clean also the Kubernetes Integration has_one :platform_kubernetes, class_name: 'Clusters::Platforms::Kubernetes'
has_one :platform_kubernetes, class_name: 'Clusters::Platforms::Kubernetes', autosave: true, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_one :application_helm, class_name: 'Clusters::Applications::Helm' has_one :application_helm, class_name: 'Clusters::Applications::Helm'
has_one :application_ingress, class_name: 'Clusters::Applications::Ingress' has_one :application_ingress, class_name: 'Clusters::Applications::Ingress'
...@@ -29,15 +28,9 @@ module Clusters ...@@ -29,15 +28,9 @@ module Clusters
validates :name, cluster_name: true validates :name, cluster_name: true
validate :restrict_modification, on: :update validate :restrict_modification, on: :update
# TODO: Move back this into Clusters::Platforms::Kubernetes in 10.3
# We need callback here because `enabled` belongs to Clusters::Cluster
# Callbacks in Clusters::Platforms::Kubernetes will not be called after update
after_save :update_kubernetes_integration!
delegate :status, to: :provider, allow_nil: true delegate :status, to: :provider, allow_nil: true
delegate :status_reason, to: :provider, allow_nil: true delegate :status_reason, to: :provider, allow_nil: true
delegate :on_creation?, to: :provider, allow_nil: true delegate :on_creation?, to: :provider, allow_nil: true
delegate :update_kubernetes_integration!, to: :platform, allow_nil: true
delegate :active?, to: :platform_kubernetes, prefix: true, allow_nil: true delegate :active?, to: :platform_kubernetes, prefix: true, allow_nil: true
delegate :installed?, to: :application_helm, prefix: true, allow_nil: true delegate :installed?, to: :application_helm, prefix: true, allow_nil: true
......
module Clusters module Clusters
module Platforms module Platforms
class Kubernetes < ActiveRecord::Base class Kubernetes < ActiveRecord::Base
include Gitlab::CurrentSettings
include Gitlab::Kubernetes
include ReactiveCaching
self.table_name = 'cluster_platforms_kubernetes' self.table_name = 'cluster_platforms_kubernetes'
self.reactive_cache_key = ->(kubernetes) { [kubernetes.class.model_name.singular, kubernetes.id] }
belongs_to :cluster, inverse_of: :platform_kubernetes, class_name: 'Clusters::Cluster' belongs_to :cluster, inverse_of: :platform_kubernetes, class_name: 'Clusters::Cluster'
...@@ -29,19 +34,14 @@ module Clusters ...@@ -29,19 +34,14 @@ module Clusters
validates :api_url, url: true, presence: true validates :api_url, url: true, presence: true
validates :token, presence: true validates :token, presence: true
# TODO: Glue code till we migrate Kubernetes Integration into Platforms::Kubernetes after_save :clear_reactive_cache!
after_destroy :destroy_kubernetes_integration!
alias_attribute :ca_pem, :ca_cert alias_attribute :ca_pem, :ca_cert
delegate :project, to: :cluster, allow_nil: true delegate :project, to: :cluster, allow_nil: true
delegate :enabled?, to: :cluster, allow_nil: true delegate :enabled?, to: :cluster, allow_nil: true
class << self alias_method :active?, :enabled?
def namespace_for_project(project)
"#{project.path}-#{project.id}"
end
end
def actual_namespace def actual_namespace
if namespace.present? if namespace.present?
...@@ -51,58 +51,127 @@ module Clusters ...@@ -51,58 +51,127 @@ module Clusters
end end
end end
def default_namespace def predefined_variables
self.class.namespace_for_project(project) if project config = YAML.dump(kubeconfig)
variables = [
{ key: 'KUBE_URL', value: api_url, public: true },
{ key: 'KUBE_TOKEN', value: token, public: false },
{ key: 'KUBE_NAMESPACE', value: actual_namespace, public: true },
{ key: 'KUBECONFIG', value: config, public: false, file: true }
]
if ca_pem.present?
variables << { key: 'KUBE_CA_PEM', value: ca_pem, public: true }
variables << { key: 'KUBE_CA_PEM_FILE', value: ca_pem, public: true, file: true }
end
variables
end end
def kubeclient # Constructs a list of terminals from the reactive cache
@kubeclient ||= kubernetes_service.kubeclient if manages_kubernetes_service? #
# Returns nil if the cache is empty, in which case you should try again a
# short time later
def terminals(environment)
with_reactive_cache do |data|
pods = filter_by_label(data[:pods], app: environment.slug)
terminals = pods.flat_map { |pod| terminals_for_pod(api_url, actual_namespace, pod) }
terminals.each { |terminal| add_terminal_auth(terminal, terminal_auth) }
end
end end
def update_kubernetes_integration! # Caches resources in the namespace so other calls don't need to block on
raise 'Kubernetes service already configured' unless manages_kubernetes_service? # network access
def calculate_reactive_cache
return unless enabled? && project && !project.pending_delete?
# This is neccesary, otheriwse enabled? returns true even though cluster updated with enabled: false # We may want to cache extra things in the future
cluster.reload { pods: read_pods }
end
ensure_kubernetes_service&.update!( def kubeclient
active: enabled?, @kubeclient ||= build_kubeclient!
api_url: api_url, end
namespace: namespace,
private
def kubeconfig
to_kubeconfig(
url: api_url,
namespace: actual_namespace,
token: token, token: token,
ca_pem: ca_cert ca_pem: ca_pem)
) end
def default_namespace
return unless project
slug = "#{project.path}-#{project.id}".downcase
slug.gsub(/[^-a-z0-9]/, '-').gsub(/^-+/, '')
end end
def active? def build_kubeclient!(api_path: 'api', api_version: 'v1')
manages_kubernetes_service? raise "Incomplete settings" unless api_url && actual_namespace
unless (username && password) || token
raise "Either username/password or token is required to access API"
end
::Kubeclient::Client.new(
join_api_url(api_path),
api_version,
auth_options: kubeclient_auth_options,
ssl_options: kubeclient_ssl_options,
http_proxy_uri: ENV['http_proxy']
)
end end
private # Returns a hash of all pods in the namespace
def read_pods
kubeclient = build_kubeclient!
def enforce_namespace_to_lower_case kubeclient.get_pods(namespace: actual_namespace).as_json
self.namespace = self.namespace&.downcase rescue KubeException => err
raise err unless err.error_code == 404
[]
end end
# TODO: glue code till we migrate Kubernetes Service into Platforms::Kubernetes class def kubeclient_ssl_options
def manages_kubernetes_service? opts = { verify_ssl: OpenSSL::SSL::VERIFY_PEER }
return true unless kubernetes_service&.active?
kubernetes_service.api_url == api_url if ca_pem.present?
opts[:cert_store] = OpenSSL::X509::Store.new
opts[:cert_store].add_cert(OpenSSL::X509::Certificate.new(ca_pem))
end
opts
end end
def destroy_kubernetes_integration! def kubeclient_auth_options
return unless manages_kubernetes_service? { bearer_token: token }
end
def join_api_url(api_path)
url = URI.parse(api_url)
prefix = url.path.sub(%r{/+\z}, '')
url.path = [prefix, api_path].join("/")
kubernetes_service&.destroy! url.to_s
end end
def kubernetes_service def terminal_auth
@kubernetes_service ||= project&.kubernetes_service {
token: token,
ca_pem: ca_pem,
max_session_time: current_application_settings.terminal_max_session_time
}
end end
def ensure_kubernetes_service def enforce_namespace_to_lower_case
@kubernetes_service ||= kubernetes_service || project&.build_kubernetes_service self.namespace = self.namespace&.downcase
end end
end end
end end
......
...@@ -137,6 +137,7 @@ class Environment < ActiveRecord::Base ...@@ -137,6 +137,7 @@ class Environment < ActiveRecord::Base
end end
end end
<<<<<<< HEAD
def deployment_service_ready? def deployment_service_ready?
project.deployment_service.present? && available? && last_deployment.present? project.deployment_service.present? && available? && last_deployment.present?
end end
...@@ -147,6 +148,14 @@ class Environment < ActiveRecord::Base ...@@ -147,6 +148,14 @@ class Environment < ActiveRecord::Base
def rollout_status def rollout_status
project.deployment_service.rollout_status(self) if deployment_service_ready? project.deployment_service.rollout_status(self) if deployment_service_ready?
=======
def has_terminals?
project.deployment_platform.present? && available? && last_deployment.present?
end
def terminals
project.deployment_platform.terminals(self) if has_terminals?
>>>>>>> upstream/master
end end
def has_metrics? def has_metrics?
......
...@@ -925,7 +925,8 @@ class MergeRequest < ActiveRecord::Base ...@@ -925,7 +925,8 @@ class MergeRequest < ActiveRecord::Base
def compute_diverged_commits_count def compute_diverged_commits_count
return 0 unless source_branch_sha && target_branch_sha return 0 unless source_branch_sha && target_branch_sha
Gitlab::Git::Commit.between(target_project.repository.raw_repository, source_branch_sha, target_branch_sha).size target_project.repository
.count_commits_between(source_branch_sha, target_branch_sha)
end end
private :compute_diverged_commits_count private :compute_diverged_commits_count
......
...@@ -906,12 +906,10 @@ class Project < ActiveRecord::Base ...@@ -906,12 +906,10 @@ class Project < ActiveRecord::Base
@ci_service ||= ci_services.reorder(nil).find_by(active: true) @ci_service ||= ci_services.reorder(nil).find_by(active: true)
end end
def deployment_services # TODO: This will be extended for multiple enviroment clusters
services.where(category: :deployment) def deployment_platform
end @deployment_platform ||= clusters.find_by(enabled: true)&.platform_kubernetes
@deployment_platform ||= services.where(category: :deployment).reorder(nil).find_by(active: true)
def deployment_service
@deployment_service ||= deployment_services.reorder(nil).find_by(active: true)
end end
def monitoring_services def monitoring_services
...@@ -1557,9 +1555,9 @@ class Project < ActiveRecord::Base ...@@ -1557,9 +1555,9 @@ class Project < ActiveRecord::Base
end end
def deployment_variables def deployment_variables
return [] unless deployment_service return [] unless deployment_platform
deployment_service.predefined_variables deployment_platform.predefined_variables
end end
def auto_devops_variables def auto_devops_variables
......
##
# NOTE:
# We'll move this class to Clusters::Platforms::Kubernetes, which contains exactly the same logic.
# After we've migrated data, we'll remove KubernetesService. This would happen in a few months.
# If you're modyfiyng this class, please note that you should update the same change in Clusters::Platforms::Kubernetes.
class KubernetesService < DeploymentService class KubernetesService < DeploymentService
include Gitlab::CurrentSettings include Gitlab::CurrentSettings
include Gitlab::Kubernetes include Gitlab::Kubernetes
......
...@@ -11,7 +11,9 @@ class ProtectedBranch < ActiveRecord::Base ...@@ -11,7 +11,9 @@ class ProtectedBranch < ActiveRecord::Base
def self.protected?(project, ref_name) def self.protected?(project, ref_name)
return true if project.empty_repo? && default_branch_protected? return true if project.empty_repo? && default_branch_protected?
self.matching(ref_name, protected_refs: project.protected_branches).present? refs = project.protected_branches.select(:name)
self.matching(ref_name, protected_refs: refs).present?
end end
def self.default_branch_protected? def self.default_branch_protected?
......
...@@ -6,6 +6,8 @@ class ProtectedTag < ActiveRecord::Base ...@@ -6,6 +6,8 @@ class ProtectedTag < ActiveRecord::Base
protected_ref_access_levels :create protected_ref_access_levels :create
def self.protected?(project, ref_name) def self.protected?(project, ref_name)
self.matching(ref_name, protected_refs: project.protected_tags).present? refs = project.protected_tags.select(:name)
self.matching(ref_name, protected_refs: refs).present?
end end
end end
.flash-container.flash-container-page .flash-container.flash-container-page
-# We currently only support `alert`, `notice`, `success` -# We currently only support `alert`, `notice`, `success`
- flash.each do |key, value| - flash.each do |key, value|
%div{ class: "flash-#{key}" } -# Don't show a flash message if the message is nil
%div{ class: (container_class) } - if value
%span= value %div{ class: "flash-#{key}" }
%div{ class: (container_class) }
%span= value
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
%body.ui_charcoal.login-page.application.navless{ data: { page: body_data_page } } %body.ui_charcoal.login-page.application.navless{ data: { page: body_data_page } }
.page-wrap .page-wrap
= render "layouts/header/empty" = render "layouts/header/empty"
= render "layouts/broadcast" .login-page-broadcast
= render "layouts/broadcast"
.container.navless-container .container.navless-container
.content .content
= render "layouts/flash" = render "layouts/flash"
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
.col-sm-4 .col-sm-4
= render 'sidebar' = render 'sidebar'
.col-sm-8 .col-sm-8
- if @project.kubernetes_service&.active? - if @project.deployment_platform&.active?
%h4.prepend-top-0= s_('ClusterIntegration|Cluster management') %h4.prepend-top-0= s_('ClusterIntegration|Cluster management')
%p= s_('ClusterIntegration|A cluster has been set up on this project through the Kubernetes integration page') %p= s_('ClusterIntegration|A cluster has been set up on this project through the Kubernetes integration page')
......
...@@ -159,7 +159,7 @@ ...@@ -159,7 +159,7 @@
%ul %ul
%li Be careful. Renaming a project's repository can have unintended side effects. %li Be careful. Renaming a project's repository can have unintended side effects.
%li You will need to update your local repositories to point to the new location. %li You will need to update your local repositories to point to the new location.
- if @project.deployment_services.any? - if @project.deployment_platform.present?
%li Your deployment services will be broken, you will need to manually fix the services after renaming. %li Your deployment services will be broken, you will need to manually fix the services after renaming.
= f.submit 'Rename project', class: "btn btn-warning" = f.submit 'Rename project', class: "btn btn-warning"
- if can?(current_user, :change_namespace, @project) - if can?(current_user, :change_namespace, @project)
......
- avatar = namespace_icon(namespace, 100)
- can_create_project = current_user.can?(:create_projects, namespace)
- if forked_project = namespace.find_fork_of(@project)
.bordered-box.fork-thumbnail.text-center.prepend-left-default.append-right-default.prepend-top-default.append-bottom-default.forked
= link_to project_path(forked_project) do
- if /no_((\w*)_)*avatar/.match(avatar)
= project_identicon(namespace, class: "avatar s100 identicon")
- else
.avatar-container.s100
= image_tag(avatar, class: "avatar s100")
%h5.prepend-top-default
= namespace.human_name
- else
.bordered-box.fork-thumbnail.text-center.prepend-left-default.append-right-default.prepend-top-default.append-bottom-default{ class: ("disabled" unless can_create_project) }
= link_to project_forks_path(@project, namespace_key: namespace.id),
method: "POST",
class: ("disabled has-tooltip" unless can_create_project),
title: (_('You have reached your project limit') unless can_create_project) do
- if /no_((\w*)_)*avatar/.match(avatar)
= project_identicon(namespace, class: "avatar s100 identicon")
- else
.avatar-container.s100
= image_tag(avatar, class: "avatar s100")
%h5.prepend-top-default
= namespace.human_name
...@@ -14,22 +14,7 @@ ...@@ -14,22 +14,7 @@
%h5.prepend-top-0.append-bottom-0.prepend-left-default.append-right-default %h5.prepend-top-0.append-bottom-0.prepend-left-default.append-right-default
Click to fork the project Click to fork the project
- @namespaces.each do |namespace| - @namespaces.each do |namespace|
- avatar = namespace_icon(namespace, 100) = render 'fork_button', namespace: namespace
- can_create_project = current_user.can?(:create_projects, namespace)
- forked_project = namespace.find_fork_of(@project)
- fork_path = forked_project ? project_path(forked_project) : project_forks_path(@project, namespace_key: namespace.id)
.bordered-box.fork-thumbnail.text-center.prepend-left-default.append-right-default.prepend-top-default.append-bottom-default{ class: [("disabled" unless can_create_project), ("forked" if forked_project)] }
= link_to fork_path,
method: "POST",
class: [("js-fork-thumbnail" unless forked_project), ("disabled has-tooltip" unless can_create_project)],
title: (_('You have reached your project limit') unless can_create_project) do
- if /no_((\w*)_)*avatar/.match(avatar)
= project_identicon(namespace, class: "avatar s100 identicon")
- else
.avatar-container.s100
= image_tag(avatar, class: "avatar s100")
%h5.prepend-top-default
= namespace.human_name
- else - else
%strong %strong
No available namespaces to fork the project. No available namespaces to fork the project.
......
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
- if koding_enabled? && @repository.koding_yml.blank? - if koding_enabled? && @repository.koding_yml.blank?
%li.missing %li.missing
= link_to _('Set up Koding'), add_koding_stack_path(@project) = link_to _('Set up Koding'), add_koding_stack_path(@project)
- if @repository.gitlab_ci_yml.blank? && @project.deployment_service.present? - if @repository.gitlab_ci_yml.blank? && @project.deployment_platform.present?
%li.missing %li.missing
= link_to add_special_file_path(@project, file_name: '.gitlab-ci.yml', commit_message: 'Set up auto deploy', branch_name: 'auto-deploy', context: 'autodeploy') do = link_to add_special_file_path(@project, file_name: '.gitlab-ci.yml', commit_message: 'Set up auto deploy', branch_name: 'auto-deploy', context: 'autodeploy') do
#{ _('Set up auto deploy') } #{ _('Set up auto deploy') }
......
---
title: Fix broadcast message not showing up on login page
merge_request: 15578
author:
type: fixed
---
title: added support for ordering and sorting in notes api
merge_request: 15342
author: haseebeqx
type: added
---
title: Fix search results when a filename would contain a special character.
merge_request: 15606
author: haseebeqx
type: fixed
---
title: Correctly link to a forked project from the new fork page.
merge_request: 15653
author:
type: fixed
---
title: Only load branch names for protected branch checks
merge_request:
author:
type: performance
---
title: Improve the performance for counting commits
merge_request: 15628
author:
type: performance
require './spec/support/sidekiq'
Gitlab::Seeder.quiet do
User.seed do |s|
s.id = 1
s.name = 'Administrator'
s.email = 'admin@example.com'
s.notification_email = 'admin@example.com'
s.username = 'root'
s.password = '5iveL!fe'
s.admin = true
s.projects_limit = 100
s.confirmed_at = DateTime.now
end
end
...@@ -10,12 +10,15 @@ Gets a list of all notes for a single issue. ...@@ -10,12 +10,15 @@ Gets a list of all notes for a single issue.
``` ```
GET /projects/:id/issues/:issue_iid/notes GET /projects/:id/issues/:issue_iid/notes
GET /projects/:id/issues/:issue_iid/notes?sort=asc&order_by=updated_at
``` ```
Parameters: | Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
- `issue_iid` (required) - The IID of an issue | `issue_iid` | integer | yes | The IID of an issue
| `sort` | string | no | Return issue notes sorted in `asc` or `desc` order. Default is `desc`
| `order_by` | string | no | Return issue notes ordered by `created_at` or `updated_at` fields. Default is `created_at`
```json ```json
[ [
...@@ -133,12 +136,15 @@ Gets a list of all notes for a single snippet. Snippet notes are comments users ...@@ -133,12 +136,15 @@ Gets a list of all notes for a single snippet. Snippet notes are comments users
``` ```
GET /projects/:id/snippets/:snippet_id/notes GET /projects/:id/snippets/:snippet_id/notes
GET /projects/:id/snippets/:snippet_id/notes?sort=asc&order_by=updated_at
``` ```
Parameters: | Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
- `snippet_id` (required) - The ID of a project snippet | `snippet_id` | integer | yes | The ID of a project snippet
| `sort` | string | no | Return snippet notes sorted in `asc` or `desc` order. Default is `desc`
| `order_by` | string | no | Return snippet notes ordered by `created_at` or `updated_at` fields. Default is `created_at`
### Get single snippet note ### Get single snippet note
...@@ -231,12 +237,15 @@ Gets a list of all notes for a single merge request. ...@@ -231,12 +237,15 @@ Gets a list of all notes for a single merge request.
``` ```
GET /projects/:id/merge_requests/:merge_request_iid/notes GET /projects/:id/merge_requests/:merge_request_iid/notes
GET /projects/:id/merge_requests/:merge_request_iid/notes?sort=asc&order_by=updated_at
``` ```
Parameters: | Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
- `merge_request_iid` (required) - The IID of a project merge request | `merge_request_iid` | integer | yes | The IID of a project merge request
| `sort` | string | no | Return merge request notes sorted in `asc` or `desc` order. Default is `desc`
| `order_by` | string | no | Return merge request notes ordered by `created_at` or `updated_at` fields. Default is `created_at`
### Get single merge request note ### Get single merge request note
......
...@@ -367,6 +367,9 @@ sudo usermod -aG redis git ...@@ -367,6 +367,9 @@ sudo usermod -aG redis git
# Enable packfile bitmaps # Enable packfile bitmaps
sudo -u git -H git config --global repack.writeBitmaps true sudo -u git -H git config --global repack.writeBitmaps true
# Enable push options
sudo -u git -H git config --global receive.advertisePushOptions true
# Configure Redis connection settings # Configure Redis connection settings
sudo -u git -H cp config/resque.yml.example config/resque.yml sudo -u git -H cp config/resque.yml.example config/resque.yml
......
...@@ -35,7 +35,7 @@ In Google's side: ...@@ -35,7 +35,7 @@ In Google's side:
1. You should now be able to see a Client ID and Client secret. Note them down 1. You should now be able to see a Client ID and Client secret. Note them down
or keep this page open as you will need them later. or keep this page open as you will need them later.
1. From the **Dashboard** select **ENABLE APIS AND SERVICES > Google Cloud APIs > Container Engine API > Enable** 1. From the **Dashboard** select **ENABLE APIS AND SERVICES > Compute > Google Container Engine API > Enable**
On your GitLab server: On your GitLab server:
......
...@@ -18,6 +18,10 @@ module API ...@@ -18,6 +18,10 @@ module API
end end
params do params do
requires :noteable_id, type: Integer, desc: 'The ID of the noteable' requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
optional :order_by, type: String, values: %w[created_at updated_at], default: 'created_at',
desc: 'Return notes ordered by `created_at` or `updated_at` fields.'
optional :sort, type: String, values: %w[asc desc], default: 'desc',
desc: 'Return notes sorted in `asc` or `desc` order.'
use :pagination use :pagination
end end
get ":id/#{noteables_str}/:noteable_id/notes" do get ":id/#{noteables_str}/:noteable_id/notes" do
...@@ -29,11 +33,12 @@ module API ...@@ -29,11 +33,12 @@ module API
# at the DB query level (which we cannot in that case), the current # at the DB query level (which we cannot in that case), the current
# page can have less elements than :per_page even if # page can have less elements than :per_page even if
# there's more than one page. # there's more than one page.
raw_notes = noteable.notes.with_metadata.reorder(params[:order_by] => params[:sort])
notes = notes =
# paginate() only works with a relation. This could lead to a # paginate() only works with a relation. This could lead to a
# mismatch between the pagination headers info and the actual notes # mismatch between the pagination headers info and the actual notes
# array returned, but this is really a edge-case. # array returned, but this is really a edge-case.
paginate(noteable.notes.with_metadata) paginate(raw_notes)
.reject { |n| n.cross_reference_not_visible_for?(current_user) } .reject { |n| n.cross_reference_not_visible_for?(current_user) }
present notes, with: Entities::Note present notes, with: Entities::Note
else else
......
...@@ -49,6 +49,7 @@ module Gitlab ...@@ -49,6 +49,7 @@ module Gitlab
# Keep in mind that this method may allocate a lot of memory. It is up # Keep in mind that this method may allocate a lot of memory. It is up
# to the caller to limit the number of blobs and blob_size_limit. # to the caller to limit the number of blobs and blob_size_limit.
# #
# Gitaly migration issue: https://gitlab.com/gitlab-org/gitaly/issues/798
def batch(repository, blob_references, blob_size_limit: nil) def batch(repository, blob_references, blob_size_limit: nil)
blob_size_limit ||= MAX_DATA_DISPLAY_SIZE blob_size_limit ||= MAX_DATA_DISPLAY_SIZE
blob_references.map do |sha, path| blob_references.map do |sha, path|
......
...@@ -506,7 +506,7 @@ module Gitlab ...@@ -506,7 +506,7 @@ module Gitlab
# Counts the amount of commits between `from` and `to`. # Counts the amount of commits between `from` and `to`.
def count_commits_between(from, to) def count_commits_between(from, to)
Commit.between(self, from, to).size count_commits(ref: "#{from}..#{to}")
end end
# Returns the SHA of the most recent common ancestor of +from+ and +to+ # Returns the SHA of the most recent common ancestor of +from+ and +to+
......
...@@ -47,8 +47,11 @@ module Gitlab ...@@ -47,8 +47,11 @@ module Gitlab
startline = 0 startline = 0
result.each_line.each_with_index do |line, index| result.each_line.each_with_index do |line, index|
if line =~ /^.*:.*:\d+:/ matches = line.match(/^(?<ref>[^:]*):(?<filename>.*):(?<startline>\d+):/)
ref, filename, startline = line.split(':') if matches
ref = matches[:ref]
filename = matches[:filename]
startline = matches[:startline]
startline = startline.to_i - index startline = startline.to_i - index
extname = Regexp.escape(File.extname(filename)) extname = Regexp.escape(File.extname(filename))
basename = filename.sub(/#{extname}$/, '') basename = filename.sub(/#{extname}$/, '')
......
...@@ -76,7 +76,7 @@ module Gitlab ...@@ -76,7 +76,7 @@ module Gitlab
timeframe_start: timeframe_start, timeframe_start: timeframe_start,
timeframe_end: timeframe_end, timeframe_end: timeframe_end,
ci_environment_slug: environment.slug, ci_environment_slug: environment.slug,
kube_namespace: environment.project.kubernetes_service&.actual_namespace || '', kube_namespace: environment.project.deployment_platform&.actual_namespace || '',
environment_filter: %{container_name!="POD",environment="#{environment.slug}"} environment_filter: %{container_name!="POD",environment="#{environment.slug}"}
} }
end end
......
#!/usr/bin/env ruby #!/usr/bin/env ruby
gitaly_dir = 'tmp/tests/gitaly' gitaly_dir = 'tmp/tests/gitaly'
env = { 'HOME' => File.expand_path('tmp/tests') }
args = %W[#{gitaly_dir}/gitaly #{gitaly_dir}/config.toml] args = %W[#{gitaly_dir}/gitaly #{gitaly_dir}/config.toml]
# Print the PID of the spawned process # Print the PID of the spawned process
puts spawn(*args, [:out, :err] => 'log/gitaly-test.log') puts spawn(env, *args, [:out, :err] => 'log/gitaly-test.log')
...@@ -113,22 +113,38 @@ describe Projects::BranchesController do ...@@ -113,22 +113,38 @@ describe Projects::BranchesController do
expect(response).to redirect_to project_tree_path(project, branch) expect(response).to redirect_to project_tree_path(project, branch)
end end
it 'redirects to autodeploy setup page' do shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
result = { status: :success, branch: double(name: branch) } it 'redirects to autodeploy setup page' do
result = { status: :success, branch: double(name: branch) }
expect_any_instance_of(CreateBranchService).to receive(:execute).and_return(result)
expect(SystemNoteService).to receive(:new_issue_branch).and_return(true)
post :create,
namespace_id: project.namespace.to_param,
project_id: project.to_param,
branch_name: branch,
issue_iid: issue.iid
expect(response.location).to include(project_new_blob_path(project, branch))
expect(response).to have_gitlab_http_status(302)
end
end
project.services << build(:kubernetes_service) context 'when user configured kubernetes from Integration > Kubernetes' do
before do
project.services << build(:kubernetes_service)
end
expect_any_instance_of(CreateBranchService).to receive(:execute).and_return(result) it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
expect(SystemNoteService).to receive(:new_issue_branch).and_return(true) end
post :create, context 'when user configured kubernetes from CI/CD > Clusters' do
namespace_id: project.namespace.to_param, before do
project_id: project.to_param, create(:cluster, :provided_by_gcp, projects: [project])
branch_name: branch, end
issue_iid: issue.iid
expect(response.location).to include(project_new_blob_path(project, branch)) it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
expect(response).to have_gitlab_http_status(302)
end end
end end
......
...@@ -4,52 +4,74 @@ describe 'Auto deploy' do ...@@ -4,52 +4,74 @@ describe 'Auto deploy' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
before do shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
create :kubernetes_service, project: project context 'when no deployment service is active' do
project.team << [user, :master] before do
sign_in user trun_off
end end
context 'when no deployment service is active' do it 'does not show a button to set up auto deploy' do
before do visit project_path(project)
project.kubernetes_service.update!(active: false) expect(page).to have_no_content('Set up auto deploy')
end
end end
it 'does not show a button to set up auto deploy' do context 'when a deployment service is active' do
visit project_path(project) before do
expect(page).to have_no_content('Set up auto deploy') trun_on
visit project_path(project)
end
it 'shows a button to set up auto deploy' do
expect(page).to have_link('Set up auto deploy')
end
it 'includes OpenShift as an available template', :js do
click_link 'Set up auto deploy'
click_button 'Apply a GitLab CI Yaml template'
within '.gitlab-ci-yml-selector' do
expect(page).to have_content('OpenShift')
end
end
it 'creates a merge request using "auto-deploy" branch', :js do
click_link 'Set up auto deploy'
click_button 'Apply a GitLab CI Yaml template'
within '.gitlab-ci-yml-selector' do
click_on 'OpenShift'
end
wait_for_requests
click_button 'Commit changes'
expect(page).to have_content('New Merge Request From auto-deploy into master')
end
end end
end end
context 'when a deployment service is active' do context 'when user configured kubernetes from Integration > Kubernetes' do
before do before do
project.kubernetes_service.update!(active: true) create :kubernetes_service, project: project
visit project_path(project) project.team << [user, :master]
sign_in user
end end
it 'shows a button to set up auto deploy' do let(:trun_on) { project.deployment_platform.update!(active: true) }
expect(page).to have_link('Set up auto deploy') let(:trun_off) { project.deployment_platform.update!(active: false) }
end
it 'includes OpenShift as an available template', :js do it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
click_link 'Set up auto deploy' end
click_button 'Apply a GitLab CI Yaml template'
within '.gitlab-ci-yml-selector' do context 'when user configured kubernetes from CI/CD > Clusters' do
expect(page).to have_content('OpenShift') before do
end create(:cluster, :provided_by_gcp, projects: [project])
project.team << [user, :master]
sign_in user
end end
it 'creates a merge request using "auto-deploy" branch', :js do let(:trun_on) { project.deployment_platform.cluster.update!(enabled: true) }
click_link 'Set up auto deploy' let(:trun_off) { project.deployment_platform.cluster.update!(enabled: false) }
click_button 'Apply a GitLab CI Yaml template'
within '.gitlab-ci-yml-selector' do
click_on 'OpenShift'
end
wait_for_requests
click_button 'Commit changes'
expect(page).to have_content('New Merge Request From auto-deploy into master') it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end
end end
end end
require 'spec_helper'
describe 'Logout/Sign out', :js do
let(:user) { create(:user) }
before do
sign_in(user)
visit root_path
end
it 'sign out redirects to sign in page' do
gitlab_sign_out
expect(current_path).to eq new_user_session_path
end
it 'sign out does not show signed out flash notice' do
gitlab_sign_out
expect(page).not_to have_selector('.flash-notice')
end
end
require 'spec_helper'
feature 'Interchangeability between KubernetesService and Platform::Kubernetes' do
EXCEPT_METHODS = %i[test title description help fields initialize_properties namespace namespace= api_url api_url=].freeze
EXCEPT_METHODS_GREP_V = %w[_touched? _changed? _was].freeze
it 'Clusters::Platform::Kubernetes covers core interfaces in KubernetesService' do
expected_interfaces = KubernetesService.instance_methods(false)
expected_interfaces = expected_interfaces - EXCEPT_METHODS
EXCEPT_METHODS_GREP_V.each do |g|
expected_interfaces = expected_interfaces.grep_v(/#{Regexp.escape(g)}\z/)
end
expect(expected_interfaces - Clusters::Platforms::Kubernetes.instance_methods).to be_empty
end
end
...@@ -101,35 +101,48 @@ feature 'Environment' do ...@@ -101,35 +101,48 @@ feature 'Environment' do
end end
context 'with terminal' do context 'with terminal' do
let(:project) { create(:kubernetes_project, :test_repo) } shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
context 'for project master' do
let(:role) { :master }
context 'for project master' do scenario 'it shows the terminal button' do
let(:role) { :master } expect(page).to have_terminal_button
end
scenario 'it shows the terminal button' do context 'web terminal', :js do
expect(page).to have_terminal_button before do
# Stub #terminals as it causes js-enabled feature specs to render the page incorrectly
allow_any_instance_of(Environment).to receive(:terminals) { nil }
visit terminal_project_environment_path(project, environment)
end
it 'displays a web terminal' do
expect(page).to have_selector('#terminal')
expect(page).to have_link(nil, href: environment.external_url)
end
end
end end
context 'web terminal', :js do context 'for developer' do
before do let(:role) { :developer }
# Stub #terminals as it causes js-enabled feature specs to render the page incorrectly
allow_any_instance_of(Environment).to receive(:terminals) { nil }
visit terminal_project_environment_path(project, environment)
end
it 'displays a web terminal' do scenario 'does not show terminal button' do
expect(page).to have_selector('#terminal') expect(page).not_to have_terminal_button
expect(page).to have_link(nil, href: environment.external_url)
end end
end end
end end
context 'for developer' do context 'when user configured kubernetes from Integration > Kubernetes' do
let(:role) { :developer } let(:project) { create(:kubernetes_project, :test_repo) }
scenario 'does not show terminal button' do it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
expect(page).not_to have_terminal_button end
end
context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end end
end end
......
...@@ -208,22 +208,35 @@ feature 'Environments page', :js do ...@@ -208,22 +208,35 @@ feature 'Environments page', :js do
end end
context 'when kubernetes terminal is available' do context 'when kubernetes terminal is available' do
let(:project) { create(:kubernetes_project, :test_repo) } shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
context 'for project master' do
let(:role) { :master }
context 'for project master' do it 'shows the terminal button' do
let(:role) { :master } expect(page).to have_terminal_button
end
end
context 'when user is a developer' do
let(:role) { :developer }
it 'shows the terminal button' do it 'does not show terminal button' do
expect(page).to have_terminal_button expect(page).not_to have_terminal_button
end
end end
end end
context 'when user is a developer' do context 'when user configured kubernetes from Integration > Kubernetes' do
let(:role) { :developer } let(:project) { create(:kubernetes_project, :test_repo) }
it 'does not show terminal button' do it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
expect(page).not_to have_terminal_button end
end
context 'when user configured kubernetes from CI/CD > Clusters' do
let(:cluster) { create(:cluster, :provided_by_gcp, projects: [create(:project, :repository)]) }
let(:project) { cluster.project }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end end
end end
end end
......
require 'spec_helper' require 'spec_helper'
describe 'Project fork' do describe 'Project fork' do
include ProjectForksHelper
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) } let(:project) { create(:project, :public, :repository) }
...@@ -24,8 +26,9 @@ describe 'Project fork' do ...@@ -24,8 +26,9 @@ describe 'Project fork' do
end end
context 'master in group' do context 'master in group' do
let(:group) { create(:group) }
before do before do
group = create(:group)
group.add_master(user) group.add_master(user)
end end
...@@ -53,5 +56,17 @@ describe 'Project fork' do ...@@ -53,5 +56,17 @@ describe 'Project fork' do
expect(page).to have_css('.fork-thumbnail', count: 2) expect(page).to have_css('.fork-thumbnail', count: 2)
expect(page).to have_css('.fork-thumbnail.disabled') expect(page).to have_css('.fork-thumbnail.disabled')
end end
it 'links to the fork if the project was already forked within that namespace' do
forked_project = fork_project(project, user, namespace: group, repository: true)
visit new_project_fork_path(project)
expect(page).to have_css('div.forked', text: group.full_name)
click_link group.full_name
expect(current_path).to eq(project_path(forked_project))
end
end end
end end
...@@ -4,8 +4,11 @@ describe('Multi-file editor library editor options', () => { ...@@ -4,8 +4,11 @@ describe('Multi-file editor library editor options', () => {
it('returns an array', () => { it('returns an array', () => {
expect(editorOptions).toEqual(jasmine.any(Array)); expect(editorOptions).toEqual(jasmine.any(Array));
}); });
<<<<<<< HEAD
it('contains readOnly option', () => { it('contains readOnly option', () => {
expect(editorOptions[0].readOnly).toBeDefined(); expect(editorOptions[0].readOnly).toBeDefined();
}); });
=======
>>>>>>> upstream/master
}); });
...@@ -92,6 +92,7 @@ describe('Multi-file editor library', () => { ...@@ -92,6 +92,7 @@ describe('Multi-file editor library', () => {
expect(instance.dirtyDiffController.reDecorate).toHaveBeenCalledWith(model); expect(instance.dirtyDiffController.reDecorate).toHaveBeenCalledWith(model);
}); });
<<<<<<< HEAD
describe('updateOptions', () => { describe('updateOptions', () => {
it('defaults readOnly to false', () => { it('defaults readOnly to false', () => {
...@@ -120,6 +121,8 @@ describe('Multi-file editor library', () => { ...@@ -120,6 +121,8 @@ describe('Multi-file editor library', () => {
}); });
}); });
}); });
=======
>>>>>>> upstream/master
}); });
describe('clearEditor', () => { describe('clearEditor', () => {
......
...@@ -4,11 +4,24 @@ describe Gitlab::Ci::Build::Policy::Kubernetes do ...@@ -4,11 +4,24 @@ describe Gitlab::Ci::Build::Policy::Kubernetes do
let(:pipeline) { create(:ci_pipeline, project: project) } let(:pipeline) { create(:ci_pipeline, project: project) }
context 'when kubernetes service is active' do context 'when kubernetes service is active' do
set(:project) { create(:kubernetes_project) } shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
it 'is satisfied by a kubernetes pipeline' do
expect(described_class.new('active'))
.to be_satisfied_by(pipeline)
end
end
it 'is satisfied by a kubernetes pipeline' do context 'when user configured kubernetes from Integration > Kubernetes' do
expect(described_class.new('active')) let(:project) { create(:kubernetes_project) }
.to be_satisfied_by(pipeline)
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end
context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end end
end end
......
...@@ -178,15 +178,29 @@ module Gitlab ...@@ -178,15 +178,29 @@ module Gitlab
end end
context 'when kubernetes is active' do context 'when kubernetes is active' do
let(:project) { create(:kubernetes_project) } shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
let(:pipeline) { create(:ci_empty_pipeline, project: project) } it 'returns seeds for kubernetes dependent job' do
seeds = subject.stage_seeds(pipeline)
it 'returns seeds for kubernetes dependent job' do expect(seeds.size).to eq 2
seeds = subject.stage_seeds(pipeline) expect(seeds.first.builds.dig(0, :name)).to eq 'spinach'
expect(seeds.second.builds.dig(0, :name)).to eq 'production'
end
end
expect(seeds.size).to eq 2 context 'when user configured kubernetes from Integration > Kubernetes' do
expect(seeds.first.builds.dig(0, :name)).to eq 'spinach' let(:project) { create(:kubernetes_project) }
expect(seeds.second.builds.dig(0, :name)).to eq 'production' let(:pipeline) { create(:ci_empty_pipeline, project: project) }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end
context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end end
end end
......
...@@ -70,6 +70,15 @@ describe Gitlab::ProjectSearchResults do ...@@ -70,6 +70,15 @@ describe Gitlab::ProjectSearchResults do
subject { described_class.parse_search_result(search_result) } subject { described_class.parse_search_result(search_result) }
it 'can correctly parse filenames including ":"' do
special_char_result = "\nmaster:testdata/project::function1.yaml-1----\nmaster:testdata/project::function1.yaml:2:test: data1\n"
blob = described_class.parse_search_result(special_char_result)
expect(blob.ref).to eq('master')
expect(blob.filename).to eq('testdata/project::function1.yaml')
end
it "returns a valid FoundBlob" do it "returns a valid FoundBlob" do
is_expected.to be_an Gitlab::SearchResults::FoundBlob is_expected.to be_an Gitlab::SearchResults::FoundBlob
expect(subject.id).to be_nil expect(subject.id).to be_nil
......
...@@ -561,10 +561,23 @@ describe Ci::Pipeline, :mailer do ...@@ -561,10 +561,23 @@ describe Ci::Pipeline, :mailer do
describe '#has_kubernetes_active?' do describe '#has_kubernetes_active?' do
context 'when kubernetes is active' do context 'when kubernetes is active' do
let(:project) { create(:kubernetes_project) } shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
it 'returns true' do
expect(pipeline).to have_kubernetes_active
end
end
it 'returns true' do context 'when user configured kubernetes from Integration > Kubernetes' do
expect(pipeline).to have_kubernetes_active let(:project) { create(:kubernetes_project) }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end
context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end end
end end
......
...@@ -9,7 +9,6 @@ describe Clusters::Cluster do ...@@ -9,7 +9,6 @@ describe Clusters::Cluster do
it { is_expected.to delegate_method(:status_reason).to(:provider) } it { is_expected.to delegate_method(:status_reason).to(:provider) }
it { is_expected.to delegate_method(:status_name).to(:provider) } it { is_expected.to delegate_method(:status_name).to(:provider) }
it { is_expected.to delegate_method(:on_creation?).to(:provider) } it { is_expected.to delegate_method(:on_creation?).to(:provider) }
it { is_expected.to delegate_method(:update_kubernetes_integration!).to(:platform) }
it { is_expected.to respond_to :project } it { is_expected.to respond_to :project }
describe '.enabled' do describe '.enabled' do
......
...@@ -5,6 +5,8 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching ...@@ -5,6 +5,8 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
include ReactiveCachingHelpers include ReactiveCachingHelpers
it { is_expected.to belong_to(:cluster) } it { is_expected.to belong_to(:cluster) }
it { is_expected.to be_kind_of(Gitlab::Kubernetes) }
it { is_expected.to be_kind_of(ReactiveCaching) }
it { is_expected.to respond_to :ca_pem } it { is_expected.to respond_to :ca_pem }
describe 'before_validation' do describe 'before_validation' do
...@@ -90,99 +92,175 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching ...@@ -90,99 +92,175 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
end end
end end
describe 'after_save from Clusters::Cluster' do describe '#actual_namespace' do
context 'when platform_kubernetes is being cerated' do subject { kubernetes.actual_namespace }
let(:enabled) { true }
let(:project) { create(:project) }
let(:cluster) { build(:cluster, provider_type: :gcp, platform_type: :kubernetes, platform_kubernetes: platform, provider_gcp: provider, enabled: enabled, projects: [project]) }
let(:platform) { build(:cluster_platform_kubernetes, :configured) }
let(:provider) { build(:cluster_provider_gcp) }
let(:kubernetes_service) { project.kubernetes_service }
it 'updates KubernetesService' do let!(:cluster) { create(:cluster, :project, platform_kubernetes: kubernetes) }
cluster.save! let(:project) { cluster.project }
let(:kubernetes) { create(:cluster_platform_kubernetes, :configured, namespace: namespace) }
expect(kubernetes_service.active).to eq(enabled) context 'when namespace is present' do
expect(kubernetes_service.api_url).to eq(platform.api_url) let(:namespace) { 'namespace-123' }
expect(kubernetes_service.namespace).to eq(platform.namespace)
expect(kubernetes_service.ca_pem).to eq(platform.ca_cert) it { is_expected.to eq(namespace) }
end
end end
context 'when platform_kubernetes has been created' do context 'when namespace is not present' do
let(:enabled) { false } let(:namespace) { nil }
let!(:project) { create(:project) }
let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } it { is_expected.to eq("#{project.path}-#{project.id}") }
let(:platform) { cluster.platform } end
let(:kubernetes_service) { project.kubernetes_service } end
it 'updates KubernetesService' do describe '#default_namespace' do
cluster.update(enabled: enabled) subject { kubernetes.send(:default_namespace) }
expect(kubernetes_service.active).to eq(enabled) let(:kubernetes) { create(:cluster_platform_kubernetes, :configured) }
context 'when cluster belongs to a project' do
let!(:cluster) { create(:cluster, :project, platform_kubernetes: kubernetes) }
let(:project) { cluster.project }
it { is_expected.to eq("#{project.path}-#{project.id}") }
end
context 'when cluster belongs to nothing' do
let!(:cluster) { create(:cluster, platform_kubernetes: kubernetes) }
it { is_expected.to be_nil }
end
end
describe '#predefined_variables' do
let!(:cluster) { create(:cluster, :project, platform_kubernetes: kubernetes) }
let(:kubernetes) { create(:cluster_platform_kubernetes, api_url: api_url, ca_cert: ca_pem, token: token) }
let(:api_url) { 'https://kube.domain.com' }
let(:ca_pem) { 'CA PEM DATA' }
let(:token) { 'token' }
let(:kubeconfig) do
config_file = expand_fixture_path('config/kubeconfig.yml')
config = YAML.load(File.read(config_file))
config.dig('users', 0, 'user')['token'] = token
config.dig('contexts', 0, 'context')['namespace'] = namespace
config.dig('clusters', 0, 'cluster')['certificate-authority-data'] =
Base64.strict_encode64(ca_pem)
YAML.dump(config)
end
shared_examples 'setting variables' do
it 'sets the variables' do
expect(kubernetes.predefined_variables).to include(
{ key: 'KUBE_URL', value: api_url, public: true },
{ key: 'KUBE_TOKEN', value: token, public: false },
{ key: 'KUBE_NAMESPACE', value: namespace, public: true },
{ key: 'KUBECONFIG', value: kubeconfig, public: false, file: true },
{ key: 'KUBE_CA_PEM', value: ca_pem, public: true },
{ key: 'KUBE_CA_PEM_FILE', value: ca_pem, public: true, file: true }
)
end end
end end
context 'when kubernetes_service has been configured without cluster integration' do context 'namespace is provided' do
let!(:project) { create(:project) } let(:namespace) { 'my-project' }
let(:cluster) { build(:cluster, provider_type: :gcp, platform_type: :kubernetes, platform_kubernetes: platform, provider_gcp: provider, projects: [project]) }
let(:platform) { build(:cluster_platform_kubernetes, :configured, api_url: 'https://111.111.111.111') }
let(:provider) { build(:cluster_provider_gcp) }
before do before do
create(:kubernetes_service, project: project) kubernetes.namespace = namespace
end end
it 'raises an error' do it_behaves_like 'setting variables'
expect { cluster.save! }.to raise_error('Kubernetes service already configured') end
context 'no namespace provided' do
let(:namespace) { kubernetes.actual_namespace }
it_behaves_like 'setting variables'
it 'sets the KUBE_NAMESPACE' do
kube_namespace = kubernetes.predefined_variables.find { |h| h[:key] == 'KUBE_NAMESPACE' }
expect(kube_namespace).not_to be_nil
expect(kube_namespace[:value]).to match(/\A#{Gitlab::PathRegex::PATH_REGEX_STR}-\d+\z/)
end end
end end
end end
describe '#actual_namespace' do describe '#terminals' do
subject { kubernetes.actual_namespace } subject { service.terminals(environment) }
let!(:cluster) { create(:cluster, :project, platform_kubernetes: kubernetes) } let!(:cluster) { create(:cluster, :project, platform_kubernetes: service) }
let(:project) { cluster.project } let(:project) { cluster.project }
let(:kubernetes) { create(:cluster_platform_kubernetes, :configured, namespace: namespace) } let(:service) { create(:cluster_platform_kubernetes, :configured) }
let(:environment) { build(:environment, project: project, name: "env", slug: "env-000000") }
context 'when namespace is present' do context 'with invalid pods' do
let(:namespace) { 'namespace-123' } it 'returns no terminals' do
stub_reactive_cache(service, pods: [{ "bad" => "pod" }])
it { is_expected.to eq(namespace) } is_expected.to be_empty
end
end end
context 'when namespace is not present' do context 'with valid pods' do
let(:namespace) { nil } let(:pod) { kube_pod(app: environment.slug) }
let(:terminals) { kube_terminals(service, pod) }
it { is_expected.to eq("#{project.path}-#{project.id}") } before do
stub_reactive_cache(
service,
pods: [pod, pod, kube_pod(app: "should-be-filtered-out")]
)
end
it 'returns terminals' do
is_expected.to eq(terminals + terminals)
end
it 'uses max session time from settings' do
stub_application_setting(terminal_max_session_time: 600)
times = subject.map { |terminal| terminal[:max_session_time] }
expect(times).to eq [600, 600, 600, 600]
end
end end
end end
describe '.namespace_for_project' do describe '#calculate_reactive_cache' do
subject { described_class.namespace_for_project(project) } subject { service.calculate_reactive_cache }
let(:project) { create(:project) } let!(:cluster) { create(:cluster, :project, enabled: enabled, platform_kubernetes: service) }
let(:service) { create(:cluster_platform_kubernetes, :configured) }
let(:enabled) { true }
it { is_expected.to eq("#{project.path}-#{project.id}") } context 'when cluster is disabled' do
end let(:enabled) { false }
describe '#default_namespace' do it { is_expected.to be_nil }
subject { kubernetes.default_namespace } end
let(:kubernetes) { create(:cluster_platform_kubernetes, :configured) } context 'when kubernetes responds with valid pods' do
before do
stub_kubeclient_pods
end
context 'when cluster belongs to a project' do it { is_expected.to eq(pods: [kube_pod]) }
let!(:cluster) { create(:cluster, :project, platform_kubernetes: kubernetes) } end
let(:project) { cluster.project }
it { is_expected.to eq("#{project.path}-#{project.id}") } context 'when kubernetes responds with 500s' do
before do
stub_kubeclient_pods(status: 500)
end
it { expect { subject }.to raise_error(KubeException) }
end end
context 'when cluster belongs to nothing' do context 'when kubernetes responds with 404s' do
let!(:cluster) { create(:cluster, platform_kubernetes: kubernetes) } before do
stub_kubeclient_pods(status: 404)
end
it { is_expected.to be_nil } it { is_expected.to eq(pods: []) }
end end
end end
end end
...@@ -327,15 +327,28 @@ describe Environment do ...@@ -327,15 +327,28 @@ describe Environment do
context 'when the enviroment is available' do context 'when the enviroment is available' do
context 'with a deployment service' do context 'with a deployment service' do
let(:project) { create(:kubernetes_project) } shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
context 'and a deployment' do
let!(:deployment) { create(:deployment, environment: environment) }
it { is_expected.to be_truthy }
end
context 'and a deployment' do context 'but no deployments' do
let!(:deployment) { create(:deployment, environment: environment) } it { is_expected.to be_falsy }
it { is_expected.to be_truthy } end
end end
context 'but no deployments' do context 'when user configured kubernetes from Integration > Kubernetes' do
it { is_expected.to be_falsy } let(:project) { create(:kubernetes_project) }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end
context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end end
end end
...@@ -356,7 +369,6 @@ describe Environment do ...@@ -356,7 +369,6 @@ describe Environment do
end end
describe '#terminals' do describe '#terminals' do
let(:project) { create(:kubernetes_project) }
subject { environment.terminals } subject { environment.terminals }
context 'when the environment has terminals' do context 'when the environment has terminals' do
...@@ -364,12 +376,27 @@ describe Environment do ...@@ -364,12 +376,27 @@ describe Environment do
allow(environment).to receive(:deployment_service_ready?).and_return(true) allow(environment).to receive(:deployment_service_ready?).and_return(true)
end end
it 'returns the terminals from the deployment service' do shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
expect(project.deployment_service) it 'returns the terminals from the deployment service' do
.to receive(:terminals).with(environment) expect(project.deployment_platform)
.and_return(:fake_terminals) .to receive(:terminals).with(environment)
.and_return(:fake_terminals)
is_expected.to eq(:fake_terminals)
end
end
context 'when user configured kubernetes from Integration > Kubernetes' do
let(:project) { create(:kubernetes_project) }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end
context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
is_expected.to eq(:fake_terminals) it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end end
end end
......
...@@ -4,8 +4,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do ...@@ -4,8 +4,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
include KubernetesHelpers include KubernetesHelpers
include ReactiveCachingHelpers include ReactiveCachingHelpers
let(:project) { build_stubbed(:kubernetes_project) } let(:project) { create(:kubernetes_project) }
let(:service) { project.kubernetes_service } let(:service) { project.deployment_platform }
describe 'Associations' do describe 'Associations' do
it { is_expected.to belong_to :project } it { is_expected.to belong_to :project }
......
...@@ -2365,12 +2365,25 @@ describe Project do ...@@ -2365,12 +2365,25 @@ describe Project do
end end
context 'when project has a deployment service' do context 'when project has a deployment service' do
let(:project) { create(:kubernetes_project) } shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
it 'returns variables from this service' do
expect(project.deployment_variables).to include(
{ key: 'KUBE_TOKEN', value: project.deployment_platform.token, public: false }
)
end
end
it 'returns variables from this service' do context 'when user configured kubernetes from Integration > Kubernetes' do
expect(project.deployment_variables).to include( let(:project) { create(:kubernetes_project) }
{ key: 'KUBE_TOKEN', value: project.kubernetes_service.token, public: false }
) it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end
context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end end
end end
end end
...@@ -3457,6 +3470,7 @@ describe Project do ...@@ -3457,6 +3470,7 @@ describe Project do
end end
end end
<<<<<<< HEAD
describe '#root_namespace' do describe '#root_namespace' do
let(:project) { build(:project, namespace: parent) } let(:project) { build(:project, namespace: parent) }
...@@ -3477,6 +3491,24 @@ describe Project do ...@@ -3477,6 +3491,24 @@ describe Project do
it 'returns current namespace' do it 'returns current namespace' do
is_expected.to eq(parent) is_expected.to eq(parent)
end end
=======
describe '#deployment_platform' do
subject { project.deployment_platform }
let(:project) { create(:project) }
context 'when user configured kubernetes from Integration > Kubernetes' do
let!(:kubernetes_service) { create(:kubernetes_service, project: project) }
it { is_expected.to eq(kubernetes_service) }
end
context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
let(:platform_kubernetes) { cluster.platform_kubernetes }
it { is_expected.to eq(platform_kubernetes) }
>>>>>>> upstream/master
end end
end end
end end
...@@ -34,6 +34,48 @@ describe API::Notes do ...@@ -34,6 +34,48 @@ describe API::Notes do
describe "GET /projects/:id/noteable/:noteable_id/notes" do describe "GET /projects/:id/noteable/:noteable_id/notes" do
context "when noteable is an Issue" do context "when noteable is an Issue" do
context 'sorting' do
before do
create_list(:note, 3, noteable: issue, project: project, author: user)
end
it 'sorts by created_at in descending order by default' do
get api("/projects/#{project.id}/issues/#{issue.iid}/notes", user)
response_dates = json_response.map { |noteable| noteable['created_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts by ascending order when requested' do
get api("/projects/#{project.id}/issues/#{issue.iid}/notes?sort=asc", user)
response_dates = json_response.map { |noteable| noteable['created_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort)
end
it 'sorts by updated_at in descending order when requested' do
get api("/projects/#{project.id}/issues/#{issue.iid}/notes?order_by=updated_at", user)
response_dates = json_response.map { |noteable| noteable['updated_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts by updated_at in ascending order when requested' do
get api("/projects/#{project.id}/issues/#{issue.iid}/notes??order_by=updated_at&sort=asc", user)
response_dates = json_response.map { |noteable| noteable['updated_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort)
end
end
it "returns an array of issue notes" do it "returns an array of issue notes" do
get api("/projects/#{project.id}/issues/#{issue.iid}/notes", user) get api("/projects/#{project.id}/issues/#{issue.iid}/notes", user)
...@@ -85,6 +127,47 @@ describe API::Notes do ...@@ -85,6 +127,47 @@ describe API::Notes do
end end
context "when noteable is a Snippet" do context "when noteable is a Snippet" do
context 'sorting' do
before do
create_list(:note, 3, noteable: snippet, project: project, author: user)
end
it 'sorts by created_at in descending order by default' do
get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
response_dates = json_response.map { |noteable| noteable['created_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts by ascending order when requested' do
get api("/projects/#{project.id}/snippets/#{snippet.id}/notes?sort=asc", user)
response_dates = json_response.map { |noteable| noteable['created_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort)
end
it 'sorts by updated_at in descending order when requested' do
get api("/projects/#{project.id}/snippets/#{snippet.id}/notes?order_by=updated_at", user)
response_dates = json_response.map { |noteable| noteable['updated_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts by updated_at in ascending order when requested' do
get api("/projects/#{project.id}/snippets/#{snippet.id}/notes??order_by=updated_at&sort=asc", user)
response_dates = json_response.map { |noteable| noteable['updated_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort)
end
end
it "returns an array of snippet notes" do it "returns an array of snippet notes" do
get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user) get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
...@@ -108,6 +191,47 @@ describe API::Notes do ...@@ -108,6 +191,47 @@ describe API::Notes do
end end
context "when noteable is a Merge Request" do context "when noteable is a Merge Request" do
context 'sorting' do
before do
create_list(:note, 3, noteable: merge_request, project: project, author: user)
end
it 'sorts by created_at in descending order by default' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes", user)
response_dates = json_response.map { |noteable| noteable['created_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts by ascending order when requested' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes?sort=asc", user)
response_dates = json_response.map { |noteable| noteable['created_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort)
end
it 'sorts by updated_at in descending order when requested' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes?order_by=updated_at", user)
response_dates = json_response.map { |noteable| noteable['updated_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts by updated_at in ascending order when requested' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes??order_by=updated_at&sort=asc", user)
response_dates = json_response.map { |noteable| noteable['updated_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort)
end
end
it "returns an array of merge_requests notes" do it "returns an array of merge_requests notes" do
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes", user) get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes", user)
......
...@@ -225,3 +225,6 @@ Shoulda::Matchers.configure do |config| ...@@ -225,3 +225,6 @@ Shoulda::Matchers.configure do |config|
with.library :rails with.library :rails
end end
end end
# Prevent Rugged from picking up local developer gitconfig.
Rugged::Settings['search_path_global'] = Rails.root.join('tmp/tests').to_s
...@@ -41,16 +41,30 @@ RSpec.shared_examples 'additional metrics query' do ...@@ -41,16 +41,30 @@ RSpec.shared_examples 'additional metrics query' do
end end
describe 'project has Kubernetes service' do describe 'project has Kubernetes service' do
let(:project) { create(:kubernetes_project) } shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
let(:environment) { create(:environment, slug: 'environment-slug', project: project) } let(:environment) { create(:environment, slug: 'environment-slug', project: project) }
let(:kube_namespace) { project.kubernetes_service.actual_namespace } let(:kube_namespace) { project.deployment_platform.actual_namespace }
it_behaves_like 'query context containing environment slug and filter' it_behaves_like 'query context containing environment slug and filter'
it 'query context contains kube_namespace' do it 'query context contains kube_namespace' do
expect(subject).to receive(:query_metrics).with(hash_including(kube_namespace: kube_namespace)) expect(subject).to receive(:query_metrics).with(hash_including(kube_namespace: kube_namespace))
subject.query(*query_params) subject.query(*query_params)
end
end
context 'when user configured kubernetes from Integration > Kubernetes' do
let(:project) { create(:kubernetes_project) }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end
context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end end
end end
......
...@@ -35,7 +35,7 @@ describe 'projects/pipelines_settings/_show' do ...@@ -35,7 +35,7 @@ describe 'projects/pipelines_settings/_show' do
context 'when kubernetes is active' do context 'when kubernetes is active' do
before do before do
project.build_kubernetes_service(active: true) create(:kubernetes_service, project: project)
end end
context 'when auto devops domain is not defined' do context 'when auto devops domain is not defined' do
......
require 'spec_helper' require 'spec_helper'
describe ReactiveCachingWorker do describe ReactiveCachingWorker do
let(:project) { create(:kubernetes_project) } let(:service) { project.deployment_platform }
let(:service) { project.deployment_service }
subject { described_class.new.perform("KubernetesService", service.id) }
describe '#perform' do describe '#perform' do
it 'calls #exclusively_update_reactive_cache!' do context 'when user configured kubernetes from Integration > Kubernetes' do
expect_any_instance_of(KubernetesService).to receive(:exclusively_update_reactive_cache!) let(:project) { create(:kubernetes_project) }
subject it 'calls #exclusively_update_reactive_cache!' do
expect_any_instance_of(KubernetesService).to receive(:exclusively_update_reactive_cache!)
described_class.new.perform("KubernetesService", service.id)
end
end
context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
it 'calls #exclusively_update_reactive_cache!' do
expect_any_instance_of(Clusters::Platforms::Kubernetes).to receive(:exclusively_update_reactive_cache!)
described_class.new.perform("Clusters::Platforms::Kubernetes", service.id)
end
end end
end end
end end
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