Skip to content
Snippets Groups Projects
Commit a5fceaa9 authored by Rémy Coutable's avatar Rémy Coutable
Browse files

Merge branch '2847-jenkins-license-checks' into 'master'

Check license before showing Jenkins in list of integrations

Closes #2847

See merge request !2459
parents 0fa728f9 42b5554c
No related branches found
No related tags found
2 merge requests!2536Resolve "Trial and license purchases inside GitLab EE",!2459Check license before showing Jenkins in list of integrations
Pipeline #
Loading
Loading
@@ -18,10 +18,16 @@ def show
 
# Returns a list of services that should be hidden from the list
def service_exceptions
exceptions = @project.disabled_services.dup
exceptions << slack_service
end
def slack_service
if current_application_settings.slack_app_enabled
['slack_slash_commands']
'slack_slash_commands'
else
['gitlab_slack_application']
'gitlab_slack_application'
end
end
end
Loading
Loading
Loading
Loading
@@ -454,6 +454,27 @@ def rename_repo
).create
end
 
# Override to reject disabled services
def find_or_initialize_services(exceptions: [])
available_services = super
available_services.reject do |service|
disabled_services.include?(service.to_param)
end
end
def disabled_services
return @disabled_services if defined?(@disabled_services)
@disabled_services = []
unless feature_available?(:jenkins_integration)
@disabled_services.push('jenkins', 'jenkins_deprecated')
end
@disabled_services
end
private
 
def licensed_feature_available?(feature)
Loading
Loading
Loading
Loading
@@ -17,6 +17,7 @@ class License < ActiveRecord::Base
ISSUE_BOARD_FOCUS_MODE_FEATURE = 'GitLab_IssueBoardFocusMode'.freeze
ISSUE_BOARD_MILESTONE_FEATURE = 'GitLab_IssueBoardMilestone'.freeze
ISSUE_WEIGHTS_FEATURE = 'GitLab_IssueWeights'.freeze
JENKINS_INTEGRATION_FEATURE = 'GitLab_JenkinsIntegration'.freeze
MERGE_REQUEST_APPROVERS_FEATURE = 'GitLab_MergeRequestApprovers'.freeze
MERGE_REQUEST_REBASE_FEATURE = 'GitLab_MergeRequestRebase'.freeze
MERGE_REQUEST_SQUASH_FEATURE = 'GitLab_MergeRequestSquash'.freeze
Loading
Loading
@@ -54,6 +55,7 @@ class License < ActiveRecord::Base
issue_board_focus_mode: ISSUE_BOARD_FOCUS_MODE_FEATURE,
issue_board_milestone: ISSUE_BOARD_MILESTONE_FEATURE,
issue_weights: ISSUE_WEIGHTS_FEATURE,
jenkins_integration: JENKINS_INTEGRATION_FEATURE,
merge_request_approvers: MERGE_REQUEST_APPROVERS_FEATURE,
merge_request_rebase: MERGE_REQUEST_REBASE_FEATURE,
merge_request_squash: MERGE_REQUEST_SQUASH_FEATURE,
Loading
Loading
@@ -80,6 +82,7 @@ class License < ActiveRecord::Base
{ ISSUE_BOARD_FOCUS_MODE_FEATURE => 1 },
{ ISSUE_BOARD_MILESTONE_FEATURE => 1 },
{ ISSUE_WEIGHTS_FEATURE => 1 },
{ JENKINS_INTEGRATION_FEATURE => 1 },
{ MERGE_REQUEST_APPROVERS_FEATURE => 1 },
{ MERGE_REQUEST_REBASE_FEATURE => 1 },
{ MERGE_REQUEST_SQUASH_FEATURE => 1 },
Loading
Loading
Loading
Loading
@@ -9,8 +9,6 @@ class JenkinsDeprecatedService < CiService
 
validates :project_url, presence: true, if: :activated?
 
delegate :execute, to: :service_hook, prefix: nil
after_save :compose_service_hook, if: :activated?
 
def compose_service_hook
Loading
Loading
@@ -20,6 +18,12 @@ def compose_service_hook
hook.save
end
 
def execute(data, hook_name = 'service_hook')
return if project.disabled_services.include?(to_param)
service_hook.execute(data, hook_name)
end
def title
'Jenkins CI (Deprecated)'
end
Loading
Loading
Loading
Loading
@@ -28,6 +28,7 @@ def compose_service_hook
end
 
def execute(data)
return if project.disabled_services.include?(to_param)
return unless supported_events.include?(data[:object_kind])
 
service_hook.execute(data, "#{data[:object_kind]}_hook")
Loading
Loading
require 'spec_helper'
 
describe Projects::Settings::IntegrationsController do
let(:project) { create(:empty_project, :public) }
let(:namespace) { create(:group, :private) }
let(:project) { create(:empty_project, :private, namespace: namespace) }
let(:user) { create(:user) }
 
before do
Loading
Loading
@@ -18,14 +19,31 @@
end
end
 
shared_examples 'endpoint with some disabled services' do
it 'has some disabled services' do
get :show, namespace_id: project.namespace, project_id: project
expect(active_services).not_to include(*disabled_services)
end
end
shared_examples 'endpoint without disabled services' do
it 'does not have disabled services' do
get :show, namespace_id: project.namespace, project_id: project
expect(active_services).to include(*disabled_services)
end
end
context 'Sets correct services list' do
let(:active_services) { assigns(:services).map(&:type) }
let(:disabled_services) { %w(JenkinsService JenkinsDeprecatedService) }
it 'enables SlackSlashCommandsService and disables GitlabSlackApplication' do
get :show, namespace_id: project.namespace, project_id: project
 
services = assigns(:services).map(&:type)
expect(services).to include('SlackSlashCommandsService')
expect(services).not_to include('GitlabSlackApplicationService')
expect(active_services).to include('SlackSlashCommandsService')
expect(active_services).not_to include('GitlabSlackApplicationService')
end
 
it 'enables GitlabSlackApplication and disables SlackSlashCommandsService' do
Loading
Loading
@@ -34,10 +52,42 @@
 
get :show, namespace_id: project.namespace, project_id: project
 
services = assigns(:services).map(&:type)
expect(active_services).to include('GitlabSlackApplicationService')
expect(active_services).not_to include('SlackSlashCommandsService')
end
context 'without a license key' do
before do
License.destroy_all
end
it_behaves_like 'endpoint with some disabled services'
end
context 'with a license key' do
context 'when checking of namespace plan is enabled' do
before do
allow_any_instance_of(Project).to receive_message_chain(:current_application_settings, :should_check_namespace_plan?) { true }
end
context 'and namespace does not have a plan' do
it_behaves_like 'endpoint with some disabled services'
end
context 'and namespace has a plan' do
let(:namespace) { create(:group, :private, plan: Namespace::BRONZE_PLAN) }
it_behaves_like 'endpoint without disabled services'
end
end
context 'when checking of namespace plan is not enabled' do
before do
allow_any_instance_of(Project).to receive_message_chain(:current_application_settings, :should_check_namespace_plan?) { false }
end
 
expect(services).to include('GitlabSlackApplicationService')
expect(services).not_to include('SlackSlashCommandsService')
it_behaves_like 'endpoint without disabled services'
end
end
end
end
Loading
Loading
@@ -714,4 +714,56 @@
end
end
end
shared_examples 'project with disabled services' do
it 'has some disabled services' do
expect(project.disabled_services).to match_array(disabled_services)
end
end
shared_examples 'project without disabled services' do
it 'has some disabled services' do
expect(project.disabled_services).to be_empty
end
end
describe '#disabled_services' do
let(:namespace) { create(:group, :private) }
let(:project) { create(:project, :private, namespace: namespace) }
let(:disabled_services) { %w(jenkins jenkins_deprecated) }
context 'without a license key' do
before do
License.destroy_all
end
it_behaves_like 'project with disabled services'
end
context 'with a license key' do
context 'when checking of namespace plan is enabled' do
before do
stub_application_setting_on_object(project, should_check_namespace_plan: true)
end
context 'and namespace does not have a plan' do
it_behaves_like 'project with disabled services'
end
context 'and namespace has a plan' do
let(:namespace) { create(:group, :private, plan: Namespace::BRONZE_PLAN) }
it_behaves_like 'project without disabled services'
end
end
context 'when checking of namespace plan is not enabled' do
before do
stub_application_setting_on_object(project, should_check_namespace_plan: false)
end
it_behaves_like 'project without disabled services'
end
end
end
end
Loading
Loading
@@ -103,4 +103,65 @@ def status_body_for_icon(state)
end
end
end
shared_examples 'a disabled jenkins deprecated service' do
it 'does not invoke the service hook' do
expect_any_instance_of(ServiceHook).not_to receive(:execute)
jenkins_service.execute(push_sample_data)
end
end
shared_examples 'an enabled jenkins deprecated service' do
it 'invokes the service hook' do
expect_any_instance_of(ServiceHook).to receive(:execute)
jenkins_service.execute(push_sample_data)
end
end
describe '#execute' do
let(:user) { create(:user, username: 'username') }
let(:namespace) { create(:group, :private) }
let(:project) { create(:project, :private, name: 'project', namespace: namespace) }
let(:push_sample_data) { Gitlab::DataBuilder::Push.build_sample(project, user) }
let(:jenkins_service) { described_class.create(active: true, project: project) }
let!(:service_hook) { create(:service_hook, service: jenkins_service) }
context 'without a license key' do
before do
License.destroy_all
end
it_behaves_like 'a disabled jenkins deprecated service'
end
context 'with a license key' do
context 'when namespace plan check is not enabled' do
before do
stub_application_setting_on_object(project, should_check_namespace_plan: false)
end
it_behaves_like 'an enabled jenkins deprecated service'
end
context 'when namespace plan check is enabled' do
before do
stub_application_setting_on_object(project, should_check_namespace_plan: true)
end
context 'when namespace does not have a plan' do
let(:namespace) { create(:group, :private) }
it_behaves_like 'a disabled jenkins deprecated service'
end
context 'when namespace has a plan' do
let(:namespace) { create(:group, :private, plan: Namespace::BRONZE_PLAN) }
it_behaves_like 'an enabled jenkins deprecated service'
end
end
end
end
end
Loading
Loading
@@ -136,35 +136,83 @@
end
end
 
describe '#execute' do
it 'adds default web hook headers to the request' do
user = create(:user, username: 'username')
project = create(:project, name: 'project')
push_sample_data = Gitlab::DataBuilder::Push.build_sample(project, user)
jenkins_service = described_class.create(jenkins_params)
stub_request(:post, jenkins_hook_url)
shared_examples 'project with disabled Jenkins service' do
it 'does not invoke the Jenkins API' do
jenkins_service.execute(push_sample_data)
 
expect(a_request(:any, jenkins_hook_url)).not_to have_been_made
end
end
shared_examples 'project with enabled Jenkins service' do
it 'invokes the Jenkins API' do
jenkins_service.execute(push_sample_data)
 
expect(
a_request(:post, jenkins_hook_url)
.with(headers: { 'X-Gitlab-Event' => 'Push Hook', 'Authorization' => jenkins_authorization })
).to have_been_made.once
expect(a_request(:post, jenkins_hook_url)).to have_been_made.once
end
end
 
it 'request url contains properly serialized username and password' do
user = create(:user, username: 'username')
project = create(:project, name: 'project')
push_sample_data = Gitlab::DataBuilder::Push.build_sample(project, user)
jenkins_service = described_class.create(jenkins_params)
describe '#execute' do
let(:user) { create(:user, username: 'username') }
let(:namespace) { create(:group, :private) }
let(:project) { create(:project, :private, name: 'project', namespace: namespace) }
let(:push_sample_data) { Gitlab::DataBuilder::Push.build_sample(project, user) }
let(:jenkins_service) { described_class.create(jenkins_params) }
before do
stub_request(:post, jenkins_hook_url)
end
 
jenkins_service.execute(push_sample_data)
context 'without a license key' do
before do
License.destroy_all
end
it_behaves_like 'project with disabled Jenkins service'
end
context 'with a license key' do
context 'when namespace plan check is not enabled' do
before do
stub_application_setting_on_object(project, should_check_namespace_plan: false)
end
it_behaves_like 'project with enabled Jenkins service'
end
context 'when namespace plan check is enabled' do
before do
stub_application_setting_on_object(project, should_check_namespace_plan: true)
end
context 'when namespace does not have a plan' do
let(:namespace) { create(:group, :private) }
it_behaves_like 'project with disabled Jenkins service'
end
context 'when namespace has a plan' do
let(:namespace) { create(:group, :private, plan: Namespace::BRONZE_PLAN) }
 
expect(
a_request(:post, 'http://jenkins.example.com/project/my_project')
.with(headers: { 'Authorization' => jenkins_authorization })
).to have_been_made.once
it 'adds default web hook headers to the request' do
jenkins_service.execute(push_sample_data)
expect(
a_request(:post, jenkins_hook_url)
.with(headers: { 'X-Gitlab-Event' => 'Push Hook', 'Authorization' => jenkins_authorization })
).to have_been_made.once
end
it 'request url contains properly serialized username and password' do
jenkins_service.execute(push_sample_data)
expect(
a_request(:post, 'http://jenkins.example.com/project/my_project')
.with(headers: { 'Authorization' => jenkins_authorization })
).to have_been_made.once
end
end
end
end
end
 
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment