Commit 15648bee authored by Heinrich Lee Yu's avatar Heinrich Lee Yu

Merge branch 'move-jira-dvcs-and-connect-app-to-core' into 'master'

Move Jira Development Panel integration to Core [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!40485
parents e17bff08 3fbe1e3b
...@@ -116,10 +116,12 @@ linters: ...@@ -116,10 +116,12 @@ linters:
- "app/views/import/bitbucket/status.html.haml" - "app/views/import/bitbucket/status.html.haml"
- "app/views/import/bitbucket_server/status.html.haml" - "app/views/import/bitbucket_server/status.html.haml"
- "app/views/invites/show.html.haml" - "app/views/invites/show.html.haml"
- "app/views/jira_connect/subscriptions/index.html.haml"
- "app/views/layouts/_mailer.html.haml" - "app/views/layouts/_mailer.html.haml"
- "app/views/layouts/experiment_mailer.html.haml" - "app/views/layouts/experiment_mailer.html.haml"
- "app/views/layouts/header/_default.html.haml" - "app/views/layouts/header/_default.html.haml"
- "app/views/layouts/header/_new_dropdown.haml" - "app/views/layouts/header/_new_dropdown.haml"
- "app/views/layouts/jira_connect.html.haml"
- "app/views/layouts/notify.html.haml" - "app/views/layouts/notify.html.haml"
- "app/views/notify/_failed_builds.html.haml" - "app/views/notify/_failed_builds.html.haml"
- "app/views/notify/_reassigned_issuable_email.html.haml" - "app/views/notify/_reassigned_issuable_email.html.haml"
...@@ -333,8 +335,6 @@ linters: ...@@ -333,8 +335,6 @@ linters:
- "ee/app/views/groups/group_members/_sync_button.html.haml" - "ee/app/views/groups/group_members/_sync_button.html.haml"
- "ee/app/views/groups/hooks/edit.html.haml" - "ee/app/views/groups/hooks/edit.html.haml"
- "ee/app/views/groups/ldap_group_links/index.html.haml" - "ee/app/views/groups/ldap_group_links/index.html.haml"
- "ee/app/views/jira_connect/subscriptions/index.html.haml"
- "ee/app/views/layouts/jira_connect.html.haml"
- "ee/app/views/layouts/nav/ee/admin/_new_monitoring_sidebar.html.haml" - "ee/app/views/layouts/nav/ee/admin/_new_monitoring_sidebar.html.haml"
- "ee/app/views/layouts/service_desk.html.haml" - "ee/app/views/layouts/service_desk.html.haml"
- "ee/app/views/ldap_group_links/_form.html.haml" - "ee/app/views/ldap_group_links/_form.html.haml"
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
/** /**
* This script is not going through Webpack bundling * This script is not going through Webpack bundling
* as it is only included in `ee/app/views/jira_connect/subscriptions/index.html.haml` * as it is only included in `app/views/jira_connect/subscriptions/index.html.haml`
* which is going to be rendered within iframe on Jira app dashboard * which is going to be rendered within iframe on Jira app dashboard
* hence any code written here needs to be IE11+ compatible (no fully ES6) * hence any code written here needs to be IE11+ compatible (no fully ES6)
*/ */
......
...@@ -254,6 +254,7 @@ class Project < ApplicationRecord ...@@ -254,6 +254,7 @@ class Project < ApplicationRecord
has_one :import_data, class_name: 'ProjectImportData', inverse_of: :project, autosave: true has_one :import_data, class_name: 'ProjectImportData', inverse_of: :project, autosave: true
has_one :project_feature, inverse_of: :project has_one :project_feature, inverse_of: :project
has_one :statistics, class_name: 'ProjectStatistics' has_one :statistics, class_name: 'ProjectStatistics'
has_one :feature_usage, class_name: 'ProjectFeatureUsage'
has_one :cluster_project, class_name: 'Clusters::Project' has_one :cluster_project, class_name: 'Clusters::Project'
has_many :clusters, through: :cluster_project, class_name: 'Clusters::Cluster' has_many :clusters, through: :cluster_project, class_name: 'Clusters::Cluster'
...@@ -393,6 +394,8 @@ class Project < ApplicationRecord ...@@ -393,6 +394,8 @@ class Project < ApplicationRecord
to: :project_setting to: :project_setting
delegate :active?, to: :prometheus_service, allow_nil: true, prefix: true delegate :active?, to: :prometheus_service, allow_nil: true, prefix: true
delegate :log_jira_dvcs_integration_usage, :jira_dvcs_server_last_sync_at, :jira_dvcs_cloud_last_sync_at, to: :feature_usage
# Validations # Validations
validates :creator, presence: true, on: :create validates :creator, presence: true, on: :create
validates :description, length: { maximum: 2000 }, allow_blank: true validates :description, length: { maximum: 2000 }, allow_blank: true
...@@ -476,6 +479,9 @@ class Project < ApplicationRecord ...@@ -476,6 +479,9 @@ class Project < ApplicationRecord
scope :for_milestones, ->(ids) { joins(:milestones).where('milestones.id' => ids).distinct } scope :for_milestones, ->(ids) { joins(:milestones).where('milestones.id' => ids).distinct }
scope :with_push, -> { joins(:events).merge(Event.pushed_action) } scope :with_push, -> { joins(:events).merge(Event.pushed_action) }
scope :with_project_feature, -> { joins('LEFT JOIN project_features ON projects.id = project_features.project_id') } scope :with_project_feature, -> { joins('LEFT JOIN project_features ON projects.id = project_features.project_id') }
scope :with_active_jira_services, -> { joins(:services).merge(::JiraService.active) } # rubocop:disable CodeReuse/ServiceClass
scope :with_jira_dvcs_cloud, -> { joins(:feature_usage).merge(ProjectFeatureUsage.with_jira_dvcs_integration_enabled(cloud: true)) }
scope :with_jira_dvcs_server, -> { joins(:feature_usage).merge(ProjectFeatureUsage.with_jira_dvcs_integration_enabled(cloud: false)) }
scope :inc_routes, -> { includes(:route, namespace: :route) } scope :inc_routes, -> { includes(:route, namespace: :route) }
scope :with_statistics, -> { includes(:statistics) } scope :with_statistics, -> { includes(:statistics) }
scope :with_namespace, -> { includes(:namespace) } scope :with_namespace, -> { includes(:namespace) }
...@@ -1444,6 +1450,10 @@ class Project < ApplicationRecord ...@@ -1444,6 +1450,10 @@ class Project < ApplicationRecord
http_url_to_repo http_url_to_repo
end end
def feature_usage
super.presence || build_feature_usage
end
def forked? def forked?
fork_network && fork_network.root_project != self fork_network && fork_network.root_project != self
end end
...@@ -2426,6 +2436,10 @@ class Project < ApplicationRecord ...@@ -2426,6 +2436,10 @@ class Project < ApplicationRecord
false false
end end
def jira_subscription_exists?
JiraConnectSubscription.for_project(self).exists?
end
def uses_default_ci_config? def uses_default_ci_config?
ci_config_path.blank? || ci_config_path == Gitlab::FileDetector::PATTERNS[:gitlab_ci] ci_config_path.blank? || ci_config_path == Gitlab::FileDetector::PATTERNS[:gitlab_ci]
end end
......
...@@ -116,6 +116,7 @@ class GroupPolicy < BasePolicy ...@@ -116,6 +116,7 @@ class GroupPolicy < BasePolicy
enable :update_cluster enable :update_cluster
enable :admin_cluster enable :admin_cluster
enable :read_deploy_token enable :read_deploy_token
enable :create_jira_connect_subscription
end end
rule { owner }.policy do rule { owner }.policy do
......
...@@ -12,6 +12,7 @@ class NamespacePolicy < BasePolicy ...@@ -12,6 +12,7 @@ class NamespacePolicy < BasePolicy
enable :admin_namespace enable :admin_namespace
enable :read_namespace enable :read_namespace
enable :read_statistics enable :read_statistics
enable :create_jira_connect_subscription
end end
rule { personal_project & ~can_create_personal_project }.prevent :create_projects rule { personal_project & ~can_create_personal_project }.prevent :create_projects
......
...@@ -75,6 +75,7 @@ module Git ...@@ -75,6 +75,7 @@ module Git
def branch_change_hooks def branch_change_hooks
enqueue_process_commit_messages enqueue_process_commit_messages
enqueue_jira_connect_sync_messages
end end
def branch_remove_hooks def branch_remove_hooks
...@@ -103,6 +104,17 @@ module Git ...@@ -103,6 +104,17 @@ module Git
end end
end end
def enqueue_jira_connect_sync_messages
return unless project.jira_subscription_exists?
branch_to_sync = branch_name if Atlassian::JiraIssueKeyExtractor.has_keys?(branch_name)
commits_to_sync = limited_commits.select { |commit| Atlassian::JiraIssueKeyExtractor.has_keys?(commit.safe_message) }.map(&:sha)
if branch_to_sync || commits_to_sync.any?
JiraConnect::SyncBranchWorker.perform_async(project.id, branch_to_sync, commits_to_sync)
end
end
def unsigned_x509_shas(commits) def unsigned_x509_shas(commits)
X509CommitSignature.unsigned_commit_shas(commits.map(&:sha)) X509CommitSignature.unsigned_commit_shas(commits.map(&:sha))
end end
......
...@@ -9,8 +9,6 @@ module JiraConnectSubscriptions ...@@ -9,8 +9,6 @@ module JiraConnectSubscriptions
return error('Invalid namespace. Please make sure you have sufficient permissions', 401) return error('Invalid namespace. Please make sure you have sufficient permissions', 401)
end end
return error('This feature is not available', 422) unless namespace.feature_available?(:jira_dev_panel_integration)
create_subscription create_subscription
end end
......
...@@ -23,6 +23,8 @@ module MergeRequests ...@@ -23,6 +23,8 @@ module MergeRequests
merge_data = hook_data(merge_request, action, old_rev: old_rev, old_associations: old_associations) merge_data = hook_data(merge_request, action, old_rev: old_rev, old_associations: old_associations)
merge_request.project.execute_hooks(merge_data, :merge_request_hooks) merge_request.project.execute_hooks(merge_data, :merge_request_hooks)
merge_request.project.execute_services(merge_data, :merge_request_hooks) merge_request.project.execute_services(merge_data, :merge_request_hooks)
enqueue_jira_connect_messages_for(merge_request)
end end
def cleanup_environments(merge_request) def cleanup_environments(merge_request)
...@@ -52,6 +54,14 @@ module MergeRequests ...@@ -52,6 +54,14 @@ module MergeRequests
private private
def enqueue_jira_connect_messages_for(merge_request)
return unless project.jira_subscription_exists?
if Atlassian::JiraIssueKeyExtractor.has_keys?(merge_request.title, merge_request.description)
JiraConnect::SyncMergeRequestWorker.perform_async(merge_request.id)
end
end
def create(merge_request) def create(merge_request)
self.params = assign_allowed_merge_params(merge_request, params) self.params = assign_allowed_merge_params(merge_request, params)
......
...@@ -25,4 +25,4 @@ ...@@ -25,4 +25,4 @@
%td= link_to 'Remove', jira_connect_subscription_path(subscription), class: 'remove-subscription' %td= link_to 'Remove', jira_connect_subscription_path(subscription), class: 'remove-subscription'
= page_specific_javascript_tag('jira_connect.js') = page_specific_javascript_tag('jira_connect.js')
= stylesheet_link_tag 'pages/jira_connect' = stylesheet_link_tag 'page_bundles/jira_connect'
...@@ -723,6 +723,22 @@ ...@@ -723,6 +723,22 @@
:weight: 2 :weight: 2
:idempotent: :idempotent:
:tags: [] :tags: []
- :name: jira_connect:jira_connect_sync_branch
:feature_category: :integrations
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
:idempotent:
:tags: []
- :name: jira_connect:jira_connect_sync_merge_request
:feature_category: :integrations
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
:idempotent:
:tags: []
- :name: jira_importer:jira_import_advance_stage - :name: jira_importer:jira_import_advance_stage
:feature_category: :importers :feature_category: :importers
:has_external_dependencies: :has_external_dependencies:
......
---
title: Move Jira Development Panel integration to Core
merge_request: 40485
author:
type: changed
...@@ -178,6 +178,7 @@ module Gitlab ...@@ -178,6 +178,7 @@ module Gitlab
config.assets.precompile << "mailers/*.css" config.assets.precompile << "mailers/*.css"
config.assets.precompile << "page_bundles/_mixins_and_variables_and_functions.css" config.assets.precompile << "page_bundles/_mixins_and_variables_and_functions.css"
config.assets.precompile << "page_bundles/ide.css" config.assets.precompile << "page_bundles/ide.css"
config.assets.precompile << "page_bundles/jira_connect.css"
config.assets.precompile << "page_bundles/todos.css" config.assets.precompile << "page_bundles/todos.css"
config.assets.precompile << "page_bundles/xterm.css" config.assets.precompile << "page_bundles/xterm.css"
config.assets.precompile << "performance_bar.css" config.assets.precompile << "performance_bar.css"
...@@ -187,6 +188,7 @@ module Gitlab ...@@ -187,6 +188,7 @@ module Gitlab
config.assets.precompile << "locale/**/app.js" config.assets.precompile << "locale/**/app.js"
config.assets.precompile << "emoji_sprites.css" config.assets.precompile << "emoji_sprites.css"
config.assets.precompile << "errors.css" config.assets.precompile << "errors.css"
config.assets.precompile << "jira_connect.js"
config.assets.precompile << "highlight/themes/*.css" config.assets.precompile << "highlight/themes/*.css"
...@@ -205,14 +207,6 @@ module Gitlab ...@@ -205,14 +207,6 @@ module Gitlab
config.assets.paths << "#{config.root}/node_modules/xterm/src/" config.assets.paths << "#{config.root}/node_modules/xterm/src/"
config.assets.precompile << "xterm.css" config.assets.precompile << "xterm.css"
if Gitlab.ee?
%w[images javascripts stylesheets].each do |path|
config.assets.paths << "#{config.root}/ee/app/assets/#{path}"
config.assets.precompile << "jira_connect.js"
config.assets.precompile << "pages/jira_connect.css"
end
end
# Import path for EE specific SCSS entry point # Import path for EE specific SCSS entry point
# In CE it will import a noop file, in EE a functioning file # In CE it will import a noop file, in EE a functioning file
# Order is important, so that the ee file takes precedence: # Order is important, so that the ee file takes precedence:
......
...@@ -32,13 +32,10 @@ Rails.application.routes.draw do ...@@ -32,13 +32,10 @@ Rails.application.routes.draw do
# This prefixless path is required because Jira gets confused if we set it up with a path # This prefixless path is required because Jira gets confused if we set it up with a path
# More information: https://gitlab.com/gitlab-org/gitlab/issues/6752 # More information: https://gitlab.com/gitlab-org/gitlab/issues/6752
scope path: '/login/oauth', controller: 'oauth/jira/authorizations', as: :oauth_jira do scope path: '/login/oauth', controller: 'oauth/jira/authorizations', as: :oauth_jira do
Gitlab.ee do get :authorize, action: :new
get :authorize, action: :new get :callback
get :callback post :access_token
post :access_token
end
# This helps minimize merge conflicts with CE for this scope block
match '*all', via: [:get, :post], to: proc { [404, {}, ['']] } match '*all', via: [:get, :post], to: proc { [404, {}, ['']] }
end end
...@@ -127,11 +124,11 @@ Rails.application.routes.draw do ...@@ -127,11 +124,11 @@ Rails.application.routes.draw do
get 'ide/*vueroute' => 'ide#index', format: false get 'ide/*vueroute' => 'ide#index', format: false
draw :operations draw :operations
draw :jira_connect
Gitlab.ee do Gitlab.ee do
draw :security draw :security
draw :smartcard draw :smartcard
draw :jira_connect
draw :username draw :username
draw :trial draw :trial
draw :trial_registration draw :trial_registration
......
...@@ -564,3 +564,37 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do ...@@ -564,3 +564,37 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
# rubocop: enable Cop/PutProjectRoutesUnderScope # rubocop: enable Cop/PutProjectRoutesUnderScope
end end
end end
# It's under /-/jira scope but cop is only checking /-/
# rubocop: disable Cop/PutProjectRoutesUnderScope
scope path: '(/-/jira)', constraints: ::Constraints::JiraEncodedUrlConstrainer.new, as: :jira do
scope path: '*namespace_id/:project_id',
namespace_id: Gitlab::Jira::Dvcs::ENCODED_ROUTE_REGEX,
project_id: Gitlab::Jira::Dvcs::ENCODED_ROUTE_REGEX do
get '/', to: redirect { |params, req|
::Gitlab::Jira::Dvcs.restore_full_path(
namespace: params[:namespace_id],
project: params[:project_id]
)
}
get 'commit/:id', constraints: { id: /\h{7,40}/ }, to: redirect { |params, req|
project_full_path = ::Gitlab::Jira::Dvcs.restore_full_path(
namespace: params[:namespace_id],
project: params[:project_id]
)
"/#{project_full_path}/commit/#{params[:id]}"
}
get 'tree/*id', as: nil, to: redirect { |params, req|
project_full_path = ::Gitlab::Jira::Dvcs.restore_full_path(
namespace: params[:namespace_id],
project: params[:project_id]
)
"/#{project_full_path}/-/tree/#{params[:id]}"
}
end
end
# rubocop: enable Cop/PutProjectRoutesUnderScope
...@@ -4,9 +4,10 @@ group: Ecosystem ...@@ -4,9 +4,10 @@ group: Ecosystem
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
--- ---
# GitLab Jira Development Panel integration **(PREMIUM)** # GitLab Jira Development Panel integration **(CORE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/2381) in [GitLab Premium](https://about.gitlab.com/pricing/) 10.0. > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/2381) in [GitLab Premium](https://about.gitlab.com/pricing/) 10.0.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/233149) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.4.
The Jira Development Panel integration allows you to reference Jira issues within GitLab, displaying activity in the [Development panel](https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/) in the issue. It complements the [GitLab Jira integration](../user/project/integrations/jira.md). You may choose to configure both integrations to take advantage of both sets of features. (See a [feature comparison](../user/project/integrations/jira_integrations.md#feature-comparison)). The Jira Development Panel integration allows you to reference Jira issues within GitLab, displaying activity in the [Development panel](https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/) in the issue. It complements the [GitLab Jira integration](../user/project/integrations/jira.md). You may choose to configure both integrations to take advantage of both sets of features. (See a [feature comparison](../user/project/integrations/jira_integrations.md#feature-comparison)).
...@@ -199,9 +200,8 @@ Potential resolutions: ...@@ -199,9 +200,8 @@ Potential resolutions:
- If you're using GitLab versions 11.10-12.7, upgrade to GitLab 12.8.10 or later - If you're using GitLab versions 11.10-12.7, upgrade to GitLab 12.8.10 or later
to resolve an identified [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/37012). to resolve an identified [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/37012).
- The Jira Development Panel integration requires GitLab Premium, GitLab.com Silver, - If you're using GitLab Core or GitLab Starter, be sure you're using
or a higher tier. If you're using a lower tier of GitLab, you'll need to upgrade GitLab 13.4 or later.
to use this feature.
[Contact GitLab Support](https://about.gitlab.com/support) if none of these reasons apply. [Contact GitLab Support](https://about.gitlab.com/support) if none of these reasons apply.
...@@ -234,7 +234,9 @@ For a walkthrough of the integration with GitLab for Jira, watch [Configure GitL ...@@ -234,7 +234,9 @@ For a walkthrough of the integration with GitLab for Jira, watch [Configure GitL
1. After installing, click **Get started** to go to the configurations page. This page is always available under **Jira Settings > Apps > Manage apps**. 1. After installing, click **Get started** to go to the configurations page. This page is always available under **Jira Settings > Apps > Manage apps**.
![Start GitLab App configuration on Jira](img/jira_dev_panel_setup_com_2.png) ![Start GitLab App configuration on Jira](img/jira_dev_panel_setup_com_2.png)
1. Enter the group or personal namespace in the **Namespace** field and click **Link namespace to Jira**. Make sure you are logged in on GitLab.com and the namespace has a Silver or above license. The user setting up _GitLab for Jira_ must have **Maintainer** access to the GitLab namespace. 1. In **Namespace**, enter the group or personal namespace, and then click
**Link namespace to Jira**. The user setting up *GitLab for Jira* must have
*Maintainer* access to the GitLab namespace.
NOTE: **Note:** NOTE: **Note:**
The GitLab user only needs access when adding a new namespace. For syncing with Jira, we do not depend on the user's token. The GitLab user only needs access when adding a new namespace. For syncing with Jira, we do not depend on the user's token.
......
...@@ -18,7 +18,7 @@ Although you can [migrate](../../../user/project/import/jira.md) your Jira issue ...@@ -18,7 +18,7 @@ Although you can [migrate](../../../user/project/import/jira.md) your Jira issue
The following Jira integrations allow different types of cross-referencing between GitLab activity and Jira issues, with additional features: The following Jira integrations allow different types of cross-referencing between GitLab activity and Jira issues, with additional features:
- [**Jira integration**](jira.md) - This is built in to GitLab. In a given GitLab project, it can be configured to connect to any Jira instance, self-managed or Cloud. - [**Jira integration**](jira.md) - This is built in to GitLab. In a given GitLab project, it can be configured to connect to any Jira instance, self-managed or Cloud.
- [**Jira development panel integration**](../../../integration/jira_development_panel.md) **(PREMIUM)** - This connects all GitLab projects under a specified group or personal namespace. - [**Jira development panel integration**](../../../integration/jira_development_panel.md) - This connects all GitLab projects under a specified group or personal namespace.
- If you're using Jira Cloud and GitLab.com, install the [GitLab for Jira](https://marketplace.atlassian.com/apps/1221011/gitlab-for-jira) app in the Atlassian Marketplace and see its [documentation](../../../integration/jira_development_panel.md#gitlab-for-jira-app). - If you're using Jira Cloud and GitLab.com, install the [GitLab for Jira](https://marketplace.atlassian.com/apps/1221011/gitlab-for-jira) app in the Atlassian Marketplace and see its [documentation](../../../integration/jira_development_panel.md#gitlab-for-jira-app).
- For all other environments, use the [Jira DVCS Connector configuration instructions](../../../integration/jira_development_panel.md#configuration). - For all other environments, use the [Jira DVCS Connector configuration instructions](../../../integration/jira_development_panel.md#configuration).
......
$header-item-height: 60px; $header-item-height: 60px;
$item-height: 50px; $item-height: 50px;
$details-cell-width: 320px; $details-cell-width: px-to-rem(320px);
$timeline-cell-height: 32px; $timeline-cell-height: 32px;
$timeline-cell-width: 180px; $timeline-cell-width: 180px;
$border-style: 1px solid $border-gray-normal; $border-style: 1px solid $border-gray-normal;
......
...@@ -43,7 +43,6 @@ module EE ...@@ -43,7 +43,6 @@ module EE
has_one :gitlab_slack_application_service has_one :gitlab_slack_application_service
has_one :tracing_setting, class_name: 'ProjectTracingSetting' has_one :tracing_setting, class_name: 'ProjectTracingSetting'
has_one :feature_usage, class_name: 'ProjectFeatureUsage'
has_one :status_page_setting, inverse_of: :project, class_name: 'StatusPage::ProjectSetting' has_one :status_page_setting, inverse_of: :project, class_name: 'StatusPage::ProjectSetting'
has_one :compliance_framework_setting, class_name: 'ComplianceManagement::ComplianceFramework::ProjectSettings', inverse_of: :project has_one :compliance_framework_setting, class_name: 'ComplianceManagement::ComplianceFramework::ProjectSettings', inverse_of: :project
has_one :security_setting, class_name: 'ProjectSecuritySetting' has_one :security_setting, class_name: 'ProjectSecuritySetting'
...@@ -122,9 +121,6 @@ module EE ...@@ -122,9 +121,6 @@ module EE
scope :requiring_code_owner_approval, scope :requiring_code_owner_approval,
-> { joins(:protected_branches).where(protected_branches: { code_owner_approval_required: true }) } -> { joins(:protected_branches).where(protected_branches: { code_owner_approval_required: true }) }
scope :with_active_services, -> { joins(:services).merge(::Service.active) } scope :with_active_services, -> { joins(:services).merge(::Service.active) }
scope :with_active_jira_services, -> { joins(:services).merge(::JiraService.active) }
scope :with_jira_dvcs_cloud, -> { joins(:feature_usage).merge(ProjectFeatureUsage.with_jira_dvcs_integration_enabled(cloud: true)) }
scope :with_jira_dvcs_server, -> { joins(:feature_usage).merge(ProjectFeatureUsage.with_jira_dvcs_integration_enabled(cloud: false)) }
scope :github_imported, -> { where(import_type: 'github') } scope :github_imported, -> { where(import_type: 'github') }
scope :with_protected_branches, -> { joins(:protected_branches) } scope :with_protected_branches, -> { joins(:protected_branches) }
scope :with_repositories_enabled, -> { joins(:project_feature).where(project_features: { repository_access_level: ::ProjectFeature::ENABLED }) } scope :with_repositories_enabled, -> { joins(:project_feature).where(project_features: { repository_access_level: ::ProjectFeature::ENABLED }) }
...@@ -166,8 +162,6 @@ module EE ...@@ -166,8 +162,6 @@ module EE
:ever_updated_successfully?, :hard_failed?, :ever_updated_successfully?, :hard_failed?,
to: :import_state, prefix: :mirror, allow_nil: true to: :import_state, prefix: :mirror, allow_nil: true
delegate :log_jira_dvcs_integration_usage, :jira_dvcs_server_last_sync_at, :jira_dvcs_cloud_last_sync_at, to: :feature_usage
delegate :merge_pipelines_enabled, :merge_pipelines_enabled=, :merge_pipelines_enabled?, :merge_pipelines_were_disabled?, to: :ci_cd_settings delegate :merge_pipelines_enabled, :merge_pipelines_enabled=, :merge_pipelines_enabled?, :merge_pipelines_were_disabled?, to: :ci_cd_settings
delegate :merge_trains_enabled?, to: :ci_cd_settings delegate :merge_trains_enabled?, to: :ci_cd_settings
delegate :closest_gitlab_subscription, to: :namespace delegate :closest_gitlab_subscription, to: :namespace
...@@ -628,10 +622,6 @@ module EE ...@@ -628,10 +622,6 @@ module EE
geo_primary_http_url_to_repo(self) geo_primary_http_url_to_repo(self)
end end
def feature_usage
super.presence || build_feature_usage
end
def adjourned_deletion? def adjourned_deletion?
feature_available?(:adjourned_deletion_for_projects_and_groups) && feature_available?(:adjourned_deletion_for_projects_and_groups) &&
::Gitlab::CurrentSettings.deletion_adjourned_period > 0 && ::Gitlab::CurrentSettings.deletion_adjourned_period > 0 &&
...@@ -685,10 +675,6 @@ module EE ...@@ -685,10 +675,6 @@ module EE
::Project.with_groups_level_repos_templates.exists?(id) ::Project.with_groups_level_repos_templates.exists?(id)
end end
def jira_subscription_exists?
feature_available?(:jira_dev_panel_integration) && JiraConnectSubscription.for_project(self).exists?
end
override :predefined_variables override :predefined_variables
def predefined_variables def predefined_variables
super.concat(requirements_ci_variables) super.concat(requirements_ci_variables)
......
...@@ -87,7 +87,6 @@ class License < ApplicationRecord ...@@ -87,7 +87,6 @@ class License < ApplicationRecord
group_project_templates group_project_templates
group_saml group_saml
issues_analytics issues_analytics
jira_dev_panel_integration
jira_issues_integration jira_issues_integration
ldap_group_sync_filter ldap_group_sync_filter
merge_pipelines merge_pipelines
......
...@@ -114,7 +114,6 @@ module EE ...@@ -114,7 +114,6 @@ module EE
end end
rule { maintainer }.policy do rule { maintainer }.policy do
enable :create_jira_connect_subscription
enable :maintainer_access enable :maintainer_access
enable :admin_wiki enable :admin_wiki
end end
......
...@@ -7,10 +7,6 @@ module EE ...@@ -7,10 +7,6 @@ module EE
prepended do prepended do
condition(:over_storage_limit, scope: :subject) { @subject.over_storage_limit? } condition(:over_storage_limit, scope: :subject) { @subject.over_storage_limit? }
rule { owner | admin }.policy do
enable :create_jira_connect_subscription
end
rule { admin & is_gitlab_com }.enable :update_subscription_limit rule { admin & is_gitlab_com }.enable :update_subscription_limit
rule { over_storage_limit }.policy do rule { over_storage_limit }.policy do
......
...@@ -7,20 +7,6 @@ module EE ...@@ -7,20 +7,6 @@ module EE
private private
override :branch_change_hooks
def branch_change_hooks
super
return unless project.jira_subscription_exists?
branch_to_sync = branch_name if Atlassian::JiraIssueKeyExtractor.has_keys?(branch_name)
commits_to_sync = limited_commits.select { |commit| Atlassian::JiraIssueKeyExtractor.has_keys?(commit.safe_message) }.map(&:sha)
if branch_to_sync || commits_to_sync.any?
JiraConnect::SyncBranchWorker.perform_async(project.id, branch_to_sync, commits_to_sync)
end
end
override :pipeline_options override :pipeline_options
def pipeline_options def pipeline_options
mirror_update = project.mirror? && mirror_update = project.mirror? &&
......
...@@ -5,17 +5,6 @@ module EE ...@@ -5,17 +5,6 @@ module EE
module BaseService module BaseService
extend ::Gitlab::Utils::Override extend ::Gitlab::Utils::Override
override :execute_hooks
def execute_hooks(merge_request, action = 'open', old_rev: nil, old_associations: {})
super
return unless project.jira_subscription_exists?
if Atlassian::JiraIssueKeyExtractor.has_keys?(merge_request.title, merge_request.description)
JiraConnect::SyncMergeRequestWorker.perform_async(merge_request.id)
end
end
private private
attr_accessor :blocking_merge_requests_params attr_accessor :blocking_merge_requests_params
......
...@@ -483,22 +483,6 @@ ...@@ -483,22 +483,6 @@
:weight: 1 :weight: 1
:idempotent: :idempotent:
:tags: [] :tags: []
- :name: jira_connect:jira_connect_sync_branch
:feature_category: :integrations
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
:idempotent:
:tags: []
- :name: jira_connect:jira_connect_sync_merge_request
:feature_category: :integrations
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
:idempotent:
:tags: []
- :name: personal_access_tokens:personal_access_tokens_groups_policy - :name: personal_access_tokens:personal_access_tokens_groups_policy
:feature_category: :authentication_and_authorization :feature_category: :authentication_and_authorization
:has_external_dependencies: :has_external_dependencies:
......
...@@ -146,37 +146,3 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do ...@@ -146,37 +146,3 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end end
end end
end end
# It's under /-/jira scope but cop is only checking /-/
# rubocop: disable Cop/PutProjectRoutesUnderScope
scope path: '(/-/jira)', constraints: ::Constraints::JiraEncodedUrlConstrainer.new, as: :jira do
scope path: '*namespace_id/:project_id',
namespace_id: Gitlab::Jira::Dvcs::ENCODED_ROUTE_REGEX,
project_id: Gitlab::Jira::Dvcs::ENCODED_ROUTE_REGEX do
get '/', to: redirect { |params, req|
::Gitlab::Jira::Dvcs.restore_full_path(
namespace: params[:namespace_id],
project: params[:project_id]
)
}
get 'commit/:id', constraints: { id: /\h{7,40}/ }, to: redirect { |params, req|
project_full_path = ::Gitlab::Jira::Dvcs.restore_full_path(
namespace: params[:namespace_id],
project: params[:project_id]
)
"/#{project_full_path}/commit/#{params[:id]}"
}
get 'tree/*id', as: nil, to: redirect { |params, req|
project_full_path = ::Gitlab::Jira::Dvcs.restore_full_path(
namespace: params[:namespace_id],
project: params[:project_id]
)
"/#{project_full_path}/-/tree/#{params[:id]}"
}
end
end
# rubocop: enable Cop/PutProjectRoutesUnderScope
...@@ -50,16 +50,6 @@ module EE ...@@ -50,16 +50,6 @@ module EE
mount ::API::Analytics::GroupActivityAnalytics mount ::API::Analytics::GroupActivityAnalytics
mount ::API::ProtectedEnvironments mount ::API::ProtectedEnvironments
mount ::API::ResourceWeightEvents mount ::API::ResourceWeightEvents
version 'v3', using: :path do
# Although the following endpoints are kept behind V3 namespace,
# they're not deprecated neither should be removed when V3 get
# removed. They're needed as a layer to integrate with Jira
# Development Panel.
namespace '/', requirements: ::API::V3::Github::ENDPOINT_REQUIREMENTS do
mount ::API::V3::Github
end
end
end end
end end
end end
......
...@@ -189,8 +189,6 @@ module EE ...@@ -189,8 +189,6 @@ module EE
override :jira_usage override :jira_usage
def jira_usage def jira_usage
super.merge( super.merge(
projects_jira_dvcs_cloud_active: count(ProjectFeatureUsage.with_jira_dvcs_integration_enabled),
projects_jira_dvcs_server_active: count(ProjectFeatureUsage.with_jira_dvcs_integration_enabled(cloud: false)),
projects_jira_issuelist_active: projects_jira_issuelist_active projects_jira_issuelist_active: projects_jira_issuelist_active
) )
end end
...@@ -275,10 +273,7 @@ module EE ...@@ -275,10 +273,7 @@ module EE
assignee_lists: distinct_count(::List.assignee.where(time_period), :user_id), assignee_lists: distinct_count(::List.assignee.where(time_period), :user_id),
epics: distinct_count(::Epic.where(time_period), :author_id), epics: distinct_count(::Epic.where(time_period), :author_id),
label_lists: distinct_count(::List.label.where(time_period), :user_id), label_lists: distinct_count(::List.label.where(time_period), :user_id),
milestone_lists: distinct_count(::List.milestone.where(time_period), :user_id), milestone_lists: distinct_count(::List.milestone.where(time_period), :user_id)
projects_jira_active: distinct_count(::Project.with_active_jira_services.where(time_period), :creator_id),
projects_jira_dvcs_cloud_active: distinct_count(::Project.with_active_jira_services.with_jira_dvcs_cloud.where(time_period), :creator_id),
projects_jira_dvcs_server_active: distinct_count(::Project.with_active_jira_services.with_jira_dvcs_server.where(time_period), :creator_id)
}) })
end end
......
...@@ -23,18 +23,6 @@ FactoryBot.modify do ...@@ -23,18 +23,6 @@ FactoryBot.modify do
last_repository_updated_at { rand(1.year).seconds.ago } last_repository_updated_at { rand(1.year).seconds.ago }
end end
trait :jira_dvcs_cloud do
before(:create) do |project|
create(:project_feature_usage, :dvcs_cloud, project: project)
end
end
trait :jira_dvcs_server do
before(:create) do |project|
create(:project_feature_usage, :dvcs_server, project: project)
end
end
trait :github_imported do trait :github_imported do
import_type { 'github' } import_type { 'github' }
end end
......
...@@ -102,8 +102,6 @@ RSpec.describe Gitlab::UsageData do ...@@ -102,8 +102,6 @@ RSpec.describe Gitlab::UsageData do
operations_dashboard_users_with_projects_added operations_dashboard_users_with_projects_added
pod_logs_usages_total pod_logs_usages_total
projects_jenkins_active projects_jenkins_active
projects_jira_dvcs_cloud_active
projects_jira_dvcs_server_active
projects_jira_issuelist_active projects_jira_issuelist_active
projects_mirrored_with_pipelines_enabled projects_mirrored_with_pipelines_enabled
projects_reporting_ci_cd_back_to_github projects_reporting_ci_cd_back_to_github
...@@ -431,27 +429,19 @@ RSpec.describe Gitlab::UsageData do ...@@ -431,27 +429,19 @@ RSpec.describe Gitlab::UsageData do
create(:milestone_list, board: board, milestone: create(:milestone, project: project), user: user) create(:milestone_list, board: board, milestone: create(:milestone, project: project), user: user)
create(:list, board: board, label: create(:label, project: project), user: user) create(:list, board: board, label: create(:label, project: project), user: user)
create(:epic, author: user) create(:epic, author: user)
create(:jira_service, :jira_cloud_service, active: true, project: create(:project, :jira_dvcs_cloud, creator: user))
create(:jira_service, active: true, project: create(:project, :jira_dvcs_server, creator: user))
end end
expect(described_class.usage_activity_by_stage_plan({})).to include( expect(described_class.usage_activity_by_stage_plan({})).to include(
assignee_lists: 2, assignee_lists: 2,
epics: 2, epics: 2,
label_lists: 2, label_lists: 2,
milestone_lists: 2, milestone_lists: 2
projects_jira_active: 2,
projects_jira_dvcs_cloud_active: 2,
projects_jira_dvcs_server_active: 2
) )
expect(described_class.usage_activity_by_stage_plan(described_class.last_28_days_time_period)).to include( expect(described_class.usage_activity_by_stage_plan(described_class.last_28_days_time_period)).to include(
assignee_lists: 1, assignee_lists: 1,
epics: 1, epics: 1,
label_lists: 1, label_lists: 1,
milestone_lists: 1, milestone_lists: 1
projects_jira_active: 1,
projects_jira_dvcs_cloud_active: 1,
projects_jira_dvcs_server_active: 1
) )
end end
end end
......
...@@ -85,36 +85,6 @@ RSpec.describe Project do ...@@ -85,36 +85,6 @@ RSpec.describe Project do
end end
end end
describe '.with_active_jira_services' do
it 'returns the correct project' do
active_jira_service = create(:jira_service)
active_service = create(:service, active: true)
expect(described_class.with_active_jira_services).to include(active_jira_service.project)
expect(described_class.with_active_jira_services).not_to include(active_service.project)
end
end
describe '.with_jira_dvcs_cloud' do
it 'returns the correct project' do
jira_dvcs_cloud_project = create(:project, :jira_dvcs_cloud)
jira_dvcs_server_project = create(:project, :jira_dvcs_server)
expect(described_class.with_jira_dvcs_cloud).to include(jira_dvcs_cloud_project)
expect(described_class.with_jira_dvcs_cloud).not_to include(jira_dvcs_server_project)
end
end
describe '.with_jira_dvcs_server' do
it 'returns the correct project' do
jira_dvcs_server_project = create(:project, :jira_dvcs_server)
jira_dvcs_cloud_project = create(:project, :jira_dvcs_cloud)
expect(described_class.with_jira_dvcs_server).to include(jira_dvcs_server_project)
expect(described_class.with_jira_dvcs_server).not_to include(jira_dvcs_cloud_project)
end
end
describe '.github_imported' do describe '.github_imported' do
it 'returns the correct project' do it 'returns the correct project' do
project_imported_from_github = create(:project, :github_imported) project_imported_from_github = create(:project, :github_imported)
...@@ -2536,24 +2506,6 @@ RSpec.describe Project do ...@@ -2536,24 +2506,6 @@ RSpec.describe Project do
end end
end end
describe '#jira_subscription_exists?' do
subject { project.jira_subscription_exists? }
context 'jira connect subscription exists' do
let!(:jira_connect_subscription) { create(:jira_connect_subscription, namespace: project.namespace) }
it { is_expected.to eq(false) }
context 'dev panel integration is available' do
before do
stub_licensed_features(jira_dev_panel_integration: true)
end
it { is_expected.to eq(true) }
end
end
end
describe '#remove_import_data' do describe '#remove_import_data' do
let(:import_data) { ProjectImportData.new(data: { 'test' => 'some data' }) } let(:import_data) { ProjectImportData.new(data: { 'test' => 'some data' }) }
......
...@@ -528,50 +528,6 @@ RSpec.describe GroupPolicy do ...@@ -528,50 +528,6 @@ RSpec.describe GroupPolicy do
end end
end end
describe 'create_jira_connect_subscription' do
context 'admin' do
let(:current_user) { admin }
it { is_expected.to be_allowed(:create_jira_connect_subscription) }
end
context 'with owner' do
let(:current_user) { owner }
it { is_expected.to be_allowed(:create_jira_connect_subscription) }
end
context 'with maintainer' do
let(:current_user) { maintainer }
it { is_expected.to be_allowed(:create_jira_connect_subscription) }
end
context 'with reporter' do
let(:current_user) { reporter }
it { is_expected.to be_disallowed(:create_jira_connect_subscription) }
end
context 'with guest' do
let(:current_user) { guest }
it { is_expected.to be_disallowed(:create_jira_connect_subscription) }
end
context 'with non member' do
let(:current_user) { create(:user) }
it { is_expected.to be_disallowed(:create_jira_connect_subscription) }
end
context 'with anonymous' do
let(:current_user) { nil }
it { is_expected.to be_disallowed(:create_jira_connect_subscription) }
end
end
describe 'read_group_credentials_inventory' do describe 'read_group_credentials_inventory' do
context 'with admin' do context 'with admin' do
let(:current_user) { admin } let(:current_user) { admin }
......
...@@ -23,32 +23,6 @@ RSpec.describe NamespacePolicy do ...@@ -23,32 +23,6 @@ RSpec.describe NamespacePolicy do
end end
end end
describe 'create_jira_connect_subscription' do
context 'admin' do
let(:current_user) { build_stubbed(:admin) }
context 'when admin mode enabled', :enable_admin_mode do
it { is_expected.to be_allowed(:create_jira_connect_subscription) }
end
context 'when admin mode disabled' do
it { is_expected.to be_disallowed(:create_jira_connect_subscription) }
end
end
context 'owner' do
let(:current_user) { owner }
it { is_expected.to be_allowed(:create_jira_connect_subscription) }
end
context 'other user' do
let(:current_user) { build_stubbed(:user) }
it { is_expected.to be_disallowed(:create_jira_connect_subscription) }
end
end
context ':over_storage_limit' do context ':over_storage_limit' do
let(:current_user) { owner } let(:current_user) { owner }
......
...@@ -138,75 +138,4 @@ RSpec.describe Git::BranchPushService do ...@@ -138,75 +138,4 @@ RSpec.describe Git::BranchPushService do
end end
end end
end end
context 'Jira Connect hooks' do
let_it_be(:project) { create(:project, :repository) }
let(:branch_to_sync) { nil }
let(:commits_to_sync) { [] }
shared_examples 'enqueues Jira sync worker' do
specify do
Sidekiq::Testing.fake! do
expect(JiraConnect::SyncBranchWorker).to receive(:perform_async)
.with(project.id, branch_to_sync, commits_to_sync)
.and_call_original
expect { subject.execute }.to change(JiraConnect::SyncBranchWorker.jobs, :size).by(1)
end
end
end
shared_examples 'does not enqueue Jira sync worker' do
specify do
Sidekiq::Testing.fake! do
expect { subject.execute }.not_to change(JiraConnect::SyncBranchWorker.jobs, :size)
end
end
end
context 'has Jira dev panel integration license' do
before do
stub_licensed_features(jira_dev_panel_integration: true)
end
context 'with a Jira subscription' do
before do
create(:jira_connect_subscription, namespace: project.namespace)
end
context 'branch name contains Jira issue key' do
let(:branch_to_sync) { 'branch-JIRA-123' }
let(:ref) { "refs/heads/#{branch_to_sync}" }
it_behaves_like 'enqueues Jira sync worker'
end
context 'commit message contains Jira issue key' do
let(:commits_to_sync) { [newrev] }
before do
allow_any_instance_of(Commit).to receive(:safe_message).and_return('Commit with key JIRA-123')
end
it_behaves_like 'enqueues Jira sync worker'
end
context 'branch name and commit message does not contain Jira issue key' do
it_behaves_like 'does not enqueue Jira sync worker'
end
end
context 'without a Jira subscription' do
it_behaves_like 'does not enqueue Jira sync worker'
end
end
context 'does not have Jira dev panel integration license' do
before do
stub_licensed_features(jira_dev_panel_integration: false)
end
it_behaves_like 'does not enqueue Jira sync worker'
end
end
end end
...@@ -18,58 +18,6 @@ RSpec.describe MergeRequests::BaseService do ...@@ -18,58 +18,6 @@ RSpec.describe MergeRequests::BaseService do
subject { MergeRequests::CreateService.new(project, project.owner, params) } subject { MergeRequests::CreateService.new(project, project.owner, params) }
describe '#execute_hooks' do
shared_examples 'enqueues Jira sync worker' do
it do
Sidekiq::Testing.fake! do
expect { subject.execute }.to change(JiraConnect::SyncMergeRequestWorker.jobs, :size).by(1)
end
end
end
shared_examples 'does not enqueue Jira sync worker' do
it do
Sidekiq::Testing.fake! do
expect { subject.execute }.not_to change(JiraConnect::SyncMergeRequestWorker.jobs, :size)
end
end
end
context 'has Jira dev panel integration license' do
before do
stub_licensed_features(jira_dev_panel_integration: true)
end
context 'with a Jira subscription' do
before do
create(:jira_connect_subscription, namespace: project.namespace)
end
context 'MR contains Jira issue key' do
let(:title) { 'Awesome merge_request with issue JIRA-123' }
it_behaves_like 'enqueues Jira sync worker'
end
context 'MR does not contain Jira issue key' do
it_behaves_like 'does not enqueue Jira sync worker'
end
end
context 'without a Jira subscription' do
it_behaves_like 'does not enqueue Jira sync worker'
end
end
context 'does not have Jira dev panel integration license' do
before do
stub_licensed_features(jira_dev_panel_integration: false)
end
it_behaves_like 'does not enqueue Jira sync worker'
end
end
describe '#filter_params' do describe '#filter_params' do
let(:params_filtering_service) { double(:params_filtering_service) } let(:params_filtering_service) { double(:params_filtering_service) }
......
...@@ -246,6 +246,16 @@ module API ...@@ -246,6 +246,16 @@ module API
mount ::API::Internal::Pages mount ::API::Internal::Pages
mount ::API::Internal::Kubernetes mount ::API::Internal::Kubernetes
version 'v3', using: :path do
# Although the following endpoints are kept behind V3 namespace,
# they're not deprecated neither should be removed when V3 get
# removed. They're needed as a layer to integrate with Jira
# Development Panel.
namespace '/', requirements: ::API::V3::Github::ENDPOINT_REQUIREMENTS do
mount ::API::V3::Github
end
end
route :any, '*path' do route :any, '*path' do
error!('404 Not Found', 404) error!('404 Not Found', 404)
end end
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
module API module API
module V3 module V3
class Github < Grape::API::Instance class Github < Grape::API::Instance
JIRA_DEV_PANEL_FEATURE = :jira_dev_panel_integration.freeze
NO_SLASH_URL_PART_REGEX = %r{[^/]+}.freeze NO_SLASH_URL_PART_REGEX = %r{[^/]+}.freeze
ENDPOINT_REQUIREMENTS = { ENDPOINT_REQUIREMENTS = {
namespace: NO_SLASH_URL_PART_REGEX, namespace: NO_SLASH_URL_PART_REGEX,
...@@ -54,15 +53,14 @@ module API ...@@ -54,15 +53,14 @@ module API
project = find_project!( project = find_project!(
::Gitlab::Jira::Dvcs.restore_full_path(params.slice(:namespace, :project).symbolize_keys) ::Gitlab::Jira::Dvcs.restore_full_path(params.slice(:namespace, :project).symbolize_keys)
) )
not_found! unless licensed?(project) && can?(current_user, :download_code, project) not_found! unless can?(current_user, :download_code, project)
project project
end end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def find_merge_requests def find_merge_requests
merge_requests = authorized_merge_requests.reorder(updated_at: :desc).preload(:target_project) merge_requests = authorized_merge_requests.reorder(updated_at: :desc)
merge_requests = paginate(merge_requests) paginate(merge_requests)
merge_requests.select { |mr| licensed?(mr.target_project) }
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
...@@ -90,10 +88,6 @@ module API ...@@ -90,10 +88,6 @@ module API
notes.select { |n| n.readable_by?(current_user) } notes.select { |n| n.readable_by?(current_user) }
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
def licensed?(routable)
routable.feature_available?(JIRA_DEV_PANEL_FEATURE)
end
end end
resource :orgs do resource :orgs do
...@@ -115,7 +109,7 @@ module API ...@@ -115,7 +109,7 @@ module API
get ':namespace/repos' do get ':namespace/repos' do
namespace = Namespace.find_by_full_path(params[:namespace]) namespace = Namespace.find_by_full_path(params[:namespace])
not_found!('Namespace') unless namespace && licensed?(namespace) not_found!('Namespace') unless namespace
projects = current_user.can_read_all_resources? ? Project.all : current_user.authorized_projects projects = current_user.can_read_all_resources? ? Project.all : current_user.authorized_projects
projects = projects.in_namespace(namespace.self_and_descendants) projects = projects.in_namespace(namespace.self_and_descendants)
......
...@@ -376,7 +376,9 @@ module Gitlab ...@@ -376,7 +376,9 @@ module Gitlab
# so we can just check for subdomains of atlassian.net # so we can just check for subdomains of atlassian.net
results = { results = {
projects_jira_server_active: 0, projects_jira_server_active: 0,
projects_jira_cloud_active: 0 projects_jira_cloud_active: 0,
projects_jira_dvcs_cloud_active: count(ProjectFeatureUsage.with_jira_dvcs_integration_enabled),
projects_jira_dvcs_server_active: count(ProjectFeatureUsage.with_jira_dvcs_integration_enabled(cloud: false))
} }
# rubocop: disable UsageData/LargeTable: # rubocop: disable UsageData/LargeTable:
...@@ -566,7 +568,10 @@ module Gitlab ...@@ -566,7 +568,10 @@ module Gitlab
projects: distinct_count(::Project.where(time_period), :creator_id), projects: distinct_count(::Project.where(time_period), :creator_id),
todos: distinct_count(::Todo.where(time_period), :author_id), todos: distinct_count(::Todo.where(time_period), :author_id),
service_desk_enabled_projects: distinct_count_service_desk_enabled_projects(time_period), service_desk_enabled_projects: distinct_count_service_desk_enabled_projects(time_period),
service_desk_issues: count(::Issue.service_desk.where(time_period)) service_desk_issues: count(::Issue.service_desk.where(time_period)),
projects_jira_active: distinct_count(::Project.with_active_jira_services.where(time_period), :creator_id),
projects_jira_dvcs_cloud_active: distinct_count(::Project.with_active_jira_services.with_jira_dvcs_cloud.where(time_period), :creator_id),
projects_jira_dvcs_server_active: distinct_count(::Project.with_active_jira_services.with_jira_dvcs_server.where(time_period), :creator_id)
} }
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
......
...@@ -64,10 +64,6 @@ RSpec.describe JiraConnect::SubscriptionsController do ...@@ -64,10 +64,6 @@ RSpec.describe JiraConnect::SubscriptionsController do
end end
context 'dev panel integration is available' do context 'dev panel integration is available' do
before do
stub_licensed_features(jira_dev_panel_integration: true)
end
it 'creates a subscription' do it 'creates a subscription' do
expect { subject }.to change { installation.subscriptions.count }.from(0).to(1) expect { subject }.to change { installation.subscriptions.count }.from(0).to(1)
end end
...@@ -78,18 +74,6 @@ RSpec.describe JiraConnect::SubscriptionsController do ...@@ -78,18 +74,6 @@ RSpec.describe JiraConnect::SubscriptionsController do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
end end
end end
context 'dev panel integration is not available' do
before do
stub_licensed_features(jira_dev_panel_integration: false)
end
it 'returns 422' do
subject
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
end
end end
context 'not signed in to GitLab' do context 'not signed in to GitLab' do
......
...@@ -109,6 +109,18 @@ FactoryBot.define do ...@@ -109,6 +109,18 @@ FactoryBot.define do
import_status { :failed } import_status { :failed }
end end
trait :jira_dvcs_cloud do
before(:create) do |project|
create(:project_feature_usage, :dvcs_cloud, project: project)
end
end
trait :jira_dvcs_server do
before(:create) do |project|
create(:project_feature_usage, :dvcs_server, project: project)
end
end
trait :archived do trait :archived do
archived { true } archived { true }
end end
......
...@@ -17,5 +17,5 @@ RSpec.describe Atlassian::JiraConnect::Serializers::RepositoryEntity do ...@@ -17,5 +17,5 @@ RSpec.describe Atlassian::JiraConnect::Serializers::RepositoryEntity do
).to_json ).to_json
end end
it { is_expected.to match_schema('jira_connect/repository', dir: 'ee') } it { is_expected.to match_schema('jira_connect/repository') }
end end
...@@ -286,6 +286,8 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do ...@@ -286,6 +286,8 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
create(:issue, project: project, author: User.support_bot) create(:issue, project: project, author: User.support_bot)
create(:note, project: project, noteable: issue, author: user) create(:note, project: project, noteable: issue, author: user)
create(:todo, project: project, target: issue, author: user) create(:todo, project: project, target: issue, author: user)
create(:jira_service, :jira_cloud_service, active: true, project: create(:project, :jira_dvcs_cloud, creator: user))
create(:jira_service, active: true, project: create(:project, :jira_dvcs_server, creator: user))
end end
expect(described_class.usage_activity_by_stage_plan({})).to include( expect(described_class.usage_activity_by_stage_plan({})).to include(
...@@ -294,7 +296,10 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do ...@@ -294,7 +296,10 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
projects: 2, projects: 2,
todos: 2, todos: 2,
service_desk_enabled_projects: 2, service_desk_enabled_projects: 2,
service_desk_issues: 2 service_desk_issues: 2,
projects_jira_active: 2,
projects_jira_dvcs_cloud_active: 2,
projects_jira_dvcs_server_active: 2
) )
expect(described_class.usage_activity_by_stage_plan(described_class.last_28_days_time_period)).to include( expect(described_class.usage_activity_by_stage_plan(described_class.last_28_days_time_period)).to include(
issues: 2, issues: 2,
...@@ -302,7 +307,10 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do ...@@ -302,7 +307,10 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
projects: 1, projects: 1,
todos: 1, todos: 1,
service_desk_enabled_projects: 1, service_desk_enabled_projects: 1,
service_desk_issues: 1 service_desk_issues: 1,
projects_jira_active: 1,
projects_jira_dvcs_cloud_active: 1,
projects_jira_dvcs_server_active: 1
) )
end end
end end
......
...@@ -1362,6 +1362,36 @@ RSpec.describe Project do ...@@ -1362,6 +1362,36 @@ RSpec.describe Project do
end end
end end
describe '.with_active_jira_services' do
it 'returns the correct project' do
active_jira_service = create(:jira_service)
active_service = create(:service, active: true)
expect(described_class.with_active_jira_services).to include(active_jira_service.project)
expect(described_class.with_active_jira_services).not_to include(active_service.project)
end
end
describe '.with_jira_dvcs_cloud' do
it 'returns the correct project' do
jira_dvcs_cloud_project = create(:project, :jira_dvcs_cloud)
jira_dvcs_server_project = create(:project, :jira_dvcs_server)
expect(described_class.with_jira_dvcs_cloud).to include(jira_dvcs_cloud_project)
expect(described_class.with_jira_dvcs_cloud).not_to include(jira_dvcs_server_project)
end
end
describe '.with_jira_dvcs_server' do
it 'returns the correct project' do
jira_dvcs_server_project = create(:project, :jira_dvcs_server)
jira_dvcs_cloud_project = create(:project, :jira_dvcs_cloud)
expect(described_class.with_jira_dvcs_server).to include(jira_dvcs_server_project)
expect(described_class.with_jira_dvcs_server).not_to include(jira_dvcs_cloud_project)
end
end
describe '.cached_count', :use_clean_rails_memory_store_caching do describe '.cached_count', :use_clean_rails_memory_store_caching do
let(:group) { create(:group, :public) } let(:group) { create(:group, :public) }
let!(:project1) { create(:project, :public, group: group) } let!(:project1) { create(:project, :public, group: group) }
...@@ -6068,6 +6098,18 @@ RSpec.describe Project do ...@@ -6068,6 +6098,18 @@ RSpec.describe Project do
end end
end end
describe '#jira_subscription_exists?' do
let(:project) { create(:project) }
subject { project.jira_subscription_exists? }
context 'jira connect subscription exists' do
let!(:jira_connect_subscription) { create(:jira_connect_subscription, namespace: project.namespace) }
it { is_expected.to eq(true) }
end
end
describe 'with services and chat names' do describe 'with services and chat names' do
subject { create(:project) } subject { create(:project) }
......
...@@ -768,4 +768,48 @@ RSpec.describe GroupPolicy do ...@@ -768,4 +768,48 @@ RSpec.describe GroupPolicy do
end end
end end
end end
describe 'create_jira_connect_subscription' do
context 'admin' do
let(:current_user) { admin }
it { is_expected.to be_allowed(:create_jira_connect_subscription) }
end
context 'with owner' do
let(:current_user) { owner }
it { is_expected.to be_allowed(:create_jira_connect_subscription) }
end
context 'with maintainer' do
let(:current_user) { maintainer }
it { is_expected.to be_allowed(:create_jira_connect_subscription) }
end
context 'with reporter' do
let(:current_user) { reporter }
it { is_expected.to be_disallowed(:create_jira_connect_subscription) }
end
context 'with guest' do
let(:current_user) { guest }
it { is_expected.to be_disallowed(:create_jira_connect_subscription) }
end
context 'with non member' do
let(:current_user) { create(:user) }
it { is_expected.to be_disallowed(:create_jira_connect_subscription) }
end
context 'with anonymous' do
let(:current_user) { nil }
it { is_expected.to be_disallowed(:create_jira_connect_subscription) }
end
end
end end
...@@ -48,4 +48,30 @@ RSpec.describe NamespacePolicy do ...@@ -48,4 +48,30 @@ RSpec.describe NamespacePolicy do
it { is_expected.to be_disallowed(*owner_permissions) } it { is_expected.to be_disallowed(*owner_permissions) }
end end
end end
describe 'create_jira_connect_subscription' do
context 'admin' do
let(:current_user) { build_stubbed(:admin) }
context 'when admin mode enabled', :enable_admin_mode do
it { is_expected.to be_allowed(:create_jira_connect_subscription) }
end
context 'when admin mode disabled' do
it { is_expected.to be_disallowed(:create_jira_connect_subscription) }
end
end
context 'owner' do
let(:current_user) { owner }
it { is_expected.to be_allowed(:create_jira_connect_subscription) }
end
context 'other user' do
let(:current_user) { build_stubbed(:user) }
it { is_expected.to be_disallowed(:create_jira_connect_subscription) }
end
end
end end
...@@ -10,7 +10,6 @@ RSpec.describe API::V3::Github do ...@@ -10,7 +10,6 @@ RSpec.describe API::V3::Github do
before do before do
project.add_maintainer(user) project.add_maintainer(user)
stub_licensed_features(jira_dev_panel_integration: true)
end end
describe 'GET /orgs/:namespace/repos' do describe 'GET /orgs/:namespace/repos' do
...@@ -123,7 +122,7 @@ RSpec.describe API::V3::Github do ...@@ -123,7 +122,7 @@ RSpec.describe API::V3::Github do
jira_get v3_api("/users/#{user.username}", user) jira_get v3_api("/users/#{user.username}", user)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('entities/github/user', dir: 'ee') expect(response).to match_response_schema('entities/github/user')
end end
end end
...@@ -220,7 +219,7 @@ RSpec.describe API::V3::Github do ...@@ -220,7 +219,7 @@ RSpec.describe API::V3::Github do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an(Array) expect(json_response).to be_an(Array)
expect(json_response.size).to eq(2) expect(json_response.size).to eq(2)
expect(response).to match_response_schema('entities/github/pull_requests', dir: 'ee') expect(response).to match_response_schema('entities/github/pull_requests')
end end
end end
...@@ -231,7 +230,7 @@ RSpec.describe API::V3::Github do ...@@ -231,7 +230,7 @@ RSpec.describe API::V3::Github do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an(Array) expect(json_response).to be_an(Array)
expect(json_response.size).to eq(1) expect(json_response.size).to eq(1)
expect(response).to match_response_schema('entities/github/pull_requests', dir: 'ee') expect(response).to match_response_schema('entities/github/pull_requests')
end end
end end
...@@ -241,7 +240,7 @@ RSpec.describe API::V3::Github do ...@@ -241,7 +240,7 @@ RSpec.describe API::V3::Github do
jira_get v3_api("/repos/#{project.namespace.path}/#{project.path}/pulls/#{merge_request.id}", user) jira_get v3_api("/repos/#{project.namespace.path}/#{project.path}/pulls/#{merge_request.id}", user)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('entities/github/pull_request', dir: 'ee') expect(response).to match_response_schema('entities/github/pull_request')
end end
end end
...@@ -260,7 +259,7 @@ RSpec.describe API::V3::Github do ...@@ -260,7 +259,7 @@ RSpec.describe API::V3::Github do
jira_get v3_api("/repos/#{project.namespace.path}/#{project.path}/pulls/#{merge_request.id}", admin) jira_get v3_api("/repos/#{project.namespace.path}/#{project.path}/pulls/#{merge_request.id}", admin)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('entities/github/pull_request', dir: 'ee') expect(response).to match_response_schema('entities/github/pull_request')
end end
end end
end end
...@@ -274,7 +273,7 @@ RSpec.describe API::V3::Github do ...@@ -274,7 +273,7 @@ RSpec.describe API::V3::Github do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(response).to match_response_schema('entities/github/repositories', dir: 'ee') expect(response).to match_response_schema('entities/github/repositories')
projects.each do |project| projects.each do |project|
hash = json_response.find do |hash| hash = json_response.find do |hash|
...@@ -327,36 +326,16 @@ RSpec.describe API::V3::Github do ...@@ -327,36 +326,16 @@ RSpec.describe API::V3::Github do
expect_project_under_namespace([parent_group_project, child_group_project], group.parent, user) expect_project_under_namespace([parent_group_project, child_group_project], group.parent, user)
end end
context 'when namespace license checks are enabled' do it 'avoids N+1 queries' do
before do jira_get v3_api("/users/#{group.parent.path}/repos", user)
enable_namespace_license_check!
end
context 'when the root group does not have the correct license' do
it 'returns not found' do
jira_get v3_api("/users/#{group.parent.path}/repos", user)
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'when the root group has the correct license' do
before do
create(:gitlab_subscription, :gold, namespace: group.parent)
end
it 'avoids N+1 queries' do control = ActiveRecord::QueryRecorder.new { jira_get v3_api("/users/#{group.parent.path}/repos", user) }
jira_get v3_api("/users/#{group.parent.path}/repos", user)
control = ActiveRecord::QueryRecorder.new { jira_get v3_api("/users/#{group.parent.path}/repos", user) } new_group = create(:group, parent: group.parent)
create(:project, :repository, group: new_group, creator: user)
new_group = create(:group, parent: group.parent) expect { jira_get v3_api("/users/#{group.parent.path}/repos", user) }.not_to exceed_query_limit(control)
create(:project, :repository, group: new_group, creator: user) expect(response).to have_gitlab_http_status(:ok)
expect { jira_get v3_api("/users/#{group.parent.path}/repos", user) }.not_to exceed_query_limit(control)
expect(response).to have_gitlab_http_status(:ok)
end
end
end end
end end
...@@ -389,18 +368,6 @@ RSpec.describe API::V3::Github do ...@@ -389,18 +368,6 @@ RSpec.describe API::V3::Github do
end end
end end
it 'filters unlicensed namespace projects' do
licensed_project = create(:project, :empty_repo, group: group)
licensed_project.add_reporter(user)
create(:gitlab_subscription, :silver, namespace: licensed_project.namespace)
stub_application_setting_on_object(project, should_check_namespace_plan: true)
stub_application_setting_on_object(licensed_project, should_check_namespace_plan: true)
expect_project_under_namespace([licensed_project], group, user)
end
context 'namespace does not exist' do context 'namespace does not exist' do
it 'responds with not found status' do it 'responds with not found status' do
jira_get v3_api('/users/noo/repos', user) jira_get v3_api('/users/noo/repos', user)
...@@ -441,7 +408,7 @@ RSpec.describe API::V3::Github do ...@@ -441,7 +408,7 @@ RSpec.describe API::V3::Github do
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(json_response).to be_an(Array) expect(json_response).to be_an(Array)
expect(response).to match_response_schema('entities/github/branches', dir: 'ee') expect(response).to match_response_schema('entities/github/branches')
end end
it 'returns 200 when project path include a dot' do it 'returns 200 when project path include a dot' do
...@@ -479,15 +446,6 @@ RSpec.describe API::V3::Github do ...@@ -479,15 +446,6 @@ RSpec.describe API::V3::Github do
expect(response).to have_gitlab_http_status(:not_found) expect(response).to have_gitlab_http_status(:not_found)
end end
it 'returns 404 when not licensed' do
stub_licensed_features(jira_dev_panel_integration: false)
project.add_reporter(unauthorized_user)
jira_get v3_api("/repos/#{project.namespace.path}/#{project.path}/branches", unauthorized_user)
expect(response).to have_gitlab_http_status(:not_found)
end
end end
end end
...@@ -500,7 +458,7 @@ RSpec.describe API::V3::Github do ...@@ -500,7 +458,7 @@ RSpec.describe API::V3::Github do
jira_get v3_api("/repos/#{project.namespace.path}/#{project.path}/commits/#{commit_id}", user) jira_get v3_api("/repos/#{project.namespace.path}/#{project.path}/commits/#{commit_id}", user)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('entities/github/commit', dir: 'ee') expect(response).to match_response_schema('entities/github/commit')
end end
it 'returns 200 when project path include a dot' do it 'returns 200 when project path include a dot' do
...@@ -539,16 +497,6 @@ RSpec.describe API::V3::Github do ...@@ -539,16 +497,6 @@ RSpec.describe API::V3::Github do
expect(response).to have_gitlab_http_status(:not_found) expect(response).to have_gitlab_http_status(:not_found)
end end
it 'returns 404 when not licensed' do
stub_licensed_features(jira_dev_panel_integration: false)
project.add_reporter(unauthorized_user)
jira_get v3_api("/repos/#{project.namespace.path}/#{project.path}/commits/#{commit_id}",
unauthorized_user)
expect(response).to have_gitlab_http_status(:not_found)
end
end end
end end
......
...@@ -704,4 +704,68 @@ RSpec.describe Git::BranchPushService, services: true do ...@@ -704,4 +704,68 @@ RSpec.describe Git::BranchPushService, services: true do
service.execute service.execute
service service
end end
context 'Jira Connect hooks' do
let_it_be(:project) { create(:project, :repository) }
let(:branch_to_sync) { nil }
let(:commits_to_sync) { [] }
let(:params) do
{ change: { oldrev: oldrev, newrev: newrev, ref: ref } }
end
subject do
described_class.new(project, user, params)
end
shared_examples 'enqueues Jira sync worker' do
specify do
Sidekiq::Testing.fake! do
expect(JiraConnect::SyncBranchWorker).to receive(:perform_async)
.with(project.id, branch_to_sync, commits_to_sync)
.and_call_original
expect { subject.execute }.to change(JiraConnect::SyncBranchWorker.jobs, :size).by(1)
end
end
end
shared_examples 'does not enqueue Jira sync worker' do
specify do
Sidekiq::Testing.fake! do
expect { subject.execute }.not_to change(JiraConnect::SyncBranchWorker.jobs, :size)
end
end
end
context 'with a Jira subscription' do
before do
create(:jira_connect_subscription, namespace: project.namespace)
end
context 'branch name contains Jira issue key' do
let(:branch_to_sync) { 'branch-JIRA-123' }
let(:ref) { "refs/heads/#{branch_to_sync}" }
it_behaves_like 'enqueues Jira sync worker'
end
context 'commit message contains Jira issue key' do
let(:commits_to_sync) { [newrev] }
before do
allow_any_instance_of(Commit).to receive(:safe_message).and_return('Commit with key JIRA-123')
end
it_behaves_like 'enqueues Jira sync worker'
end
context 'branch name and commit message does not contain Jira issue key' do
it_behaves_like 'does not enqueue Jira sync worker'
end
end
context 'without a Jira subscription' do
it_behaves_like 'does not enqueue Jira sync worker'
end
end
end end
...@@ -24,11 +24,7 @@ RSpec.describe JiraConnectSubscriptions::CreateService do ...@@ -24,11 +24,7 @@ RSpec.describe JiraConnectSubscriptions::CreateService do
end end
end end
context 'when jira_dev_panel_integration is available' do context 'when user does have access' do
before do
stub_licensed_features(jira_dev_panel_integration: true)
end
it 'creates a subscription' do it 'creates a subscription' do
expect { subject }.to change { installation.subscriptions.count }.from(0).to(1) expect { subject }.to change { installation.subscriptions.count }.from(0).to(1)
end end
...@@ -36,24 +32,16 @@ RSpec.describe JiraConnectSubscriptions::CreateService do ...@@ -36,24 +32,16 @@ RSpec.describe JiraConnectSubscriptions::CreateService do
it 'returns success' do it 'returns success' do
expect(subject[:status]).to eq(:success) expect(subject[:status]).to eq(:success)
end end
end
context 'when path is invalid' do context 'when path is invalid' do
let(:path) { 'some_invalid_namespace_path' } let(:path) { 'some_invalid_namespace_path' }
it_behaves_like 'a failed execution'
end
context 'when user does not have access' do
subject { described_class.new(installation, create(:user), namespace_path: path).execute }
it_behaves_like 'a failed execution' it_behaves_like 'a failed execution'
end
end end
context 'when jira_dev_panel_integration is not available' do context 'when user does not have access' do
before do subject { described_class.new(installation, create(:user), namespace_path: path).execute }
stub_licensed_features(jira_dev_panel_integration: false)
end
it_behaves_like 'a failed execution' it_behaves_like 'a failed execution'
end end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe MergeRequests::BaseService do
include ProjectForksHelper
let_it_be(:project) { create(:project, :repository) }
let(:title) { 'Awesome merge_request' }
let(:params) do
{
title: title,
description: 'please fix',
source_branch: 'feature',
target_branch: 'master'
}
end
subject { MergeRequests::CreateService.new(project, project.owner, params) }
describe '#execute_hooks' do
shared_examples 'enqueues Jira sync worker' do
it do
Sidekiq::Testing.fake! do
expect { subject.execute }.to change(JiraConnect::SyncMergeRequestWorker.jobs, :size).by(1)
end
end
end
shared_examples 'does not enqueue Jira sync worker' do
it do
Sidekiq::Testing.fake! do
expect { subject.execute }.not_to change(JiraConnect::SyncMergeRequestWorker.jobs, :size)
end
end
end
context 'with a Jira subscription' do
before do
create(:jira_connect_subscription, namespace: project.namespace)
end
context 'MR contains Jira issue key' do
let(:title) { 'Awesome merge_request with issue JIRA-123' }
it_behaves_like 'enqueues Jira sync worker'
end
context 'MR does not contain Jira issue key' do
it_behaves_like 'does not enqueue Jira sync worker'
end
end
context 'without a Jira subscription' do
it_behaves_like 'does not enqueue Jira sync worker'
end
end
end
...@@ -88,6 +88,8 @@ module UsageDataHelpers ...@@ -88,6 +88,8 @@ module UsageDataHelpers
projects_jira_active projects_jira_active
projects_jira_server_active projects_jira_server_active
projects_jira_cloud_active projects_jira_cloud_active
projects_jira_dvcs_cloud_active
projects_jira_dvcs_server_active
projects_slack_active projects_slack_active
projects_slack_slash_commands_active projects_slack_slash_commands_active
projects_custom_issue_tracker_active projects_custom_issue_tracker_active
......
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