summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJarka Košanová <jarka@gitlab.com>2019-09-10 14:47:06 +0200
committerJarka Košanová <jarka@gitlab.com>2019-09-10 14:47:06 +0200
commit78056d049dd47a60bd63b927f32310a391b54760 (patch)
tree3c54311bb785ade7d3c5f3f6b4af7f6e5ab00f48
parent34bb2453f3e692429ce30cd4b832670d497055de (diff)
downloadgitlab-ce-63082-jira-service-data.tar.gz
Use data_fields for issue trackers63082-jira-service-data
- create and update data only in data fields tables - keep backwards compatibility for reading from properties - simlify factories
-rw-r--r--app/models/project_services/bugzilla_service.rb4
-rw-r--r--app/models/project_services/data_fields.rb62
-rw-r--r--app/models/project_services/gitlab_issue_tracker_service.rb4
-rw-r--r--app/models/project_services/issue_tracker_service.rb59
-rw-r--r--app/models/project_services/jira_service.rb39
-rw-r--r--app/models/project_services/redmine_service.rb4
-rw-r--r--app/models/project_services/youtrack_service.rb4
-rw-r--r--lib/api/entities.rb6
-rw-r--r--lib/gitlab/usage_data.rb16
-rw-r--r--spec/controllers/projects/services_controller_spec.rb4
-rw-r--r--spec/factories/services.rb74
-rw-r--r--spec/features/issuables/markdown_references/jira_spec.rb4
-rw-r--r--spec/lib/banzai/pipeline/gfm_pipeline_spec.rb6
-rw-r--r--spec/models/project_services/bugzilla_service_spec.rb25
-rw-r--r--spec/models/project_services/gitlab_issue_tracker_service_spec.rb15
-rw-r--r--spec/models/project_services/issue_tracker_service_spec.rb2
-rw-r--r--spec/models/project_services/jira_service_spec.rb319
-rw-r--r--spec/models/project_services/redmine_service_spec.rb23
-rw-r--r--spec/models/project_services/youtrack_service_spec.rb20
-rw-r--r--spec/models/service_spec.rb4
-rw-r--r--spec/services/system_note_service_spec.rb2
-rw-r--r--spec/support/helpers/jira_service_helper.rb3
22 files changed, 394 insertions, 305 deletions
diff --git a/app/models/project_services/bugzilla_service.rb b/app/models/project_services/bugzilla_service.rb
index 8b79b5e9f0c..3d7fa973c7e 100644
--- a/app/models/project_services/bugzilla_service.rb
+++ b/app/models/project_services/bugzilla_service.rb
@@ -1,10 +1,6 @@
# frozen_string_literal: true
class BugzillaService < IssueTrackerService
- validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated?
-
- prop_accessor :project_url, :issues_url, :new_issue_url
-
def default_title
'Bugzilla'
end
diff --git a/app/models/project_services/data_fields.rb b/app/models/project_services/data_fields.rb
index 438d85098c8..ee11847fa02 100644
--- a/app/models/project_services/data_fields.rb
+++ b/app/models/project_services/data_fields.rb
@@ -3,8 +3,66 @@
module DataFields
extend ActiveSupport::Concern
+ class_methods do
+ # Provide convenient accessor methods
+ # for each serialized property.
+ # Also keep track of updated properties in a similar way as ActiveModel::Dirty
+ def data_field(*args)
+ args.each do |arg|
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ unless method_defined?(arg)
+ def #{arg}
+ data_fields.send('#{arg}') || (properties && properties['#{arg}'])
+ end
+ end
+
+ def #{arg}=(value)
+ @old_data_fields ||= {}
+ @old_data_fields['#{arg}'] ||= #{arg} # set only on the first assignment, IOW we remember the original value only
+ data_fields.send('#{arg}=', value)
+ end
+
+ def #{arg}_touched?
+ @old_data_fields ||= {}
+ @old_data_fields.has_key?('#{arg}')
+ end
+
+
+ # def #{arg}=(value)
+ # data_fields.send('#{arg}=', value)
+ # updated_properties['#{arg}'] = value unless updated_properties['#{arg}']
+ # end
+
+ def #{arg}_changed?
+ #{arg}_touched? && @old_data_fields['#{arg}'] != #{arg}
+ end
+
+ # def #{arg}_touched?
+ # updated_properties.include?('#{arg}')
+ # end
+
+ def #{arg}_is
+ data_fields.#{arg}
+ end
+
+ def #{arg}_was
+ data_fields.#{arg}_was || updated_properties['#{arg}']
+ end
+ RUBY
+ end
+ end
+ end
+
included do
- has_one :issue_tracker_data
- has_one :jira_tracker_data
+ has_one :issue_tracker_data, autosave: true
+ has_one :jira_tracker_data, autosave: true
+
+ def data_fields
+ raise NotImplementedError
+ end
+
+ def updated_data_fields
+ @updated_data_fields ||= ActiveSupport::HashWithIndifferentAccess.new
+ end
end
end
diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb
index 51032932eab..4011c308484 100644
--- a/app/models/project_services/gitlab_issue_tracker_service.rb
+++ b/app/models/project_services/gitlab_issue_tracker_service.rb
@@ -3,10 +3,6 @@
class GitlabIssueTrackerService < IssueTrackerService
include Gitlab::Routing
- validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated?
-
- prop_accessor :project_url, :issues_url, :new_issue_url
-
default_value_for :default, true
def default_title
diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb
index 3a1130ffc15..06efdc9014f 100644
--- a/app/models/project_services/issue_tracker_service.rb
+++ b/app/models/project_services/issue_tracker_service.rb
@@ -3,9 +3,12 @@
class IssueTrackerService < Service
validate :one_issue_tracker, if: :activated?, on: :manual_change
+ data_field :project_url, :issues_url, :new_issue_url
+
default_value_for :category, 'issue_tracker'
- before_save :handle_properties
+ before_validation :handle_properties
+ before_validation :set_default_data, on: :create
# Pattern used to extract links from comments
# Override this method on services that uses different patterns
@@ -43,12 +46,30 @@ class IssueTrackerService < Service
end
def handle_properties
- properties.slice('title', 'description').each do |key, _|
+ # this has been moved from initialize_properties and should be improved
+ # as part of https://gitlab.com/gitlab-org/gitlab-ce/issues/63084
+ return unless properties
+
+ data_values = properties.slice!('title', 'description')
+ properties.each do |key, _|
current_value = self.properties.delete(key)
value = attribute_changed?(key) ? attribute_change(key).last : current_value
write_attribute(key, value)
end
+
+ updated_properties.each do |key, value|
+ updated_properties[key] = data_values[key]
+ end
+ data_values.reject! { |key| data_fields.changed.include?(key) }
+
+ data_fields.assign_attributes(data_values) if data_values.present?
+
+ self.properties = {}
+ end
+
+ def data_fields(values = {})
+ issue_tracker_data || self.build_issue_tracker_data(values)
end
def default?
@@ -56,7 +77,7 @@ class IssueTrackerService < Service
end
def issue_url(iid)
- self.issues_url.gsub(':id', iid.to_s)
+ issues_url.gsub(':id', iid.to_s)
end
def issue_tracker_path
@@ -80,25 +101,21 @@ class IssueTrackerService < Service
]
end
+ def initialize_properties
+ {}
+ end
+
# Initialize with default properties values
- # or receive a block with custom properties
- def initialize_properties(&block)
- return unless properties.nil?
-
- if enabled_in_gitlab_config
- if block_given?
- yield
- else
- self.properties = {
- title: issues_tracker['title'],
- project_url: issues_tracker['project_url'],
- issues_url: issues_tracker['issues_url'],
- new_issue_url: issues_tracker['new_issue_url']
- }
- end
- else
- self.properties = {}
- end
+ def set_default_data
+ return unless issues_tracker.present?
+
+ self.title ||= issues_tracker['title']
+
+ return if project_url
+
+ data_fields.project_url = issues_tracker['project_url']
+ data_fields.issues_url = issues_tracker['issues_url']
+ data_fields.new_issue_url = issues_tracker['new_issue_url']
end
def self.supported_events
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index 0728c83005e..a3941340703 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -5,19 +5,10 @@ class JiraService < IssueTrackerService
include ApplicationHelper
include ActionView::Helpers::AssetUrlHelper
- validates :url, public_url: true, presence: true, if: :activated?
- validates :api_url, public_url: true, allow_blank: true
- validates :username, presence: true, if: :activated?
- validates :password, presence: true, if: :activated?
-
- validates :jira_issue_transition_id,
- format: { with: Gitlab::Regex.jira_transition_id_regex, message: s_("JiraService|transition ids can have only numbers which can be split with , or ;") },
- allow_blank: true
-
# Jira Cloud version is deprecating authentication via username and password.
# We should use username/password for Jira Server and email/api_token for Jira Cloud,
# for more information check: https://gitlab.com/gitlab-org/gitlab-ce/issues/49936.
- prop_accessor :username, :password, :url, :api_url, :jira_issue_transition_id
+ data_field :username, :password, :url, :api_url, :jira_issue_transition_id
before_update :reset_password
@@ -35,24 +26,34 @@ class JiraService < IssueTrackerService
end
def initialize_properties
- super do
- self.properties = {
- url: issues_tracker['url'],
- api_url: issues_tracker['api_url']
- }
- end
+ {}
+ end
+
+ def data_fields(values = {})
+ jira_tracker_data || self.build_jira_tracker_data(values)
end
def reset_password
- self.password = nil if reset_password?
+ data_fields.password = nil if reset_password?
+ end
+
+ def set_default_data
+ return unless issues_tracker.present?
+
+ self.title ||= issues_tracker['title']
+
+ return if url
+
+ data_fields.url ||= issues_tracker['url']
+ data_fields.api_url ||= issues_tracker['api_url']
end
def options
url = URI.parse(client_url)
{
- username: self.username,
- password: self.password,
+ username: username,
+ password: password,
site: URI.join(url, '/').to_s, # Intended to find the root
context_path: url.path,
auth_type: :basic,
diff --git a/app/models/project_services/redmine_service.rb b/app/models/project_services/redmine_service.rb
index 5ca057ca833..ef66d88629e 100644
--- a/app/models/project_services/redmine_service.rb
+++ b/app/models/project_services/redmine_service.rb
@@ -1,10 +1,6 @@
# frozen_string_literal: true
class RedmineService < IssueTrackerService
- validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated?
-
- prop_accessor :project_url, :issues_url, :new_issue_url
-
def default_title
'Redmine'
end
diff --git a/app/models/project_services/youtrack_service.rb b/app/models/project_services/youtrack_service.rb
index f9de1f7dc49..37eb1c4d4c1 100644
--- a/app/models/project_services/youtrack_service.rb
+++ b/app/models/project_services/youtrack_service.rb
@@ -1,10 +1,6 @@
# frozen_string_literal: true
class YoutrackService < IssueTrackerService
- validates :project_url, :issues_url, presence: true, public_url: true, if: :activated?
-
- prop_accessor :project_url, :issues_url
-
# {PROJECT-KEY}-{NUMBER} Examples: YT-1, PRJ-1, gl-030
def self.reference_pattern(only_long: false)
if only_long
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 312c8d5b548..cc45679dd0e 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -1044,7 +1044,11 @@ module API
expose :job_events
# Expose serialized properties
expose :properties do |service, options|
- service.properties.slice(*service.api_field_names)
+ if service.properties.present?
+ service.properties.slice(*service.api_field_names)
+ else
+ service.data_fields.as_json.slice(*service.api_field_names)
+ end
end
end
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index a93301cb4ce..e6df1884a33 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -172,16 +172,16 @@ module Gitlab
def jira_usage
# Jira Cloud does not support custom domains as per https://jira.atlassian.com/browse/CLOUD-6999
# so we can just check for subdomains of atlassian.net
- services = count(
- Service.unscoped.where(type: :JiraService, active: true)
- .group("CASE WHEN properties LIKE '%.atlassian.net%' THEN 'cloud' ELSE 'server' END"),
- fallback: Hash.new(-1)
- )
+ services = Service.unscoped.where(type: :JiraService, active: true).includes(:jira_tracker_data)
+
+ counts = services.group_by do |service|
+ service.jira_tracker_data.url.include?('.atlassian.net') ? :cloud : :server
+ end
{
- projects_jira_server_active: services['server'] || 0,
- projects_jira_cloud_active: services['cloud'] || 0,
- projects_jira_active: services['server'] == -1 ? -1 : services.values.sum
+ projects_jira_server_active: counts[:server]&.count || 0,
+ projects_jira_cloud_active: counts[:cloud]&.count || 0,
+ projects_jira_active: services ? count(services) : -1
}
end
diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb
index 0c074714bf3..4a678e63165 100644
--- a/spec/controllers/projects/services_controller_spec.rb
+++ b/spec/controllers/projects/services_controller_spec.rb
@@ -5,7 +5,9 @@ require 'spec_helper'
describe Projects::ServicesController do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
- let(:service) { create(:jira_service, project: project) }
+ let(:service) do
+ create(:jira_service, project: project).tap { |service| service.jira_tracker_data.destroy }
+ end
let(:service_params) { { username: 'username', password: 'password', url: 'http://example.com' } }
before do
diff --git a/spec/factories/services.rb b/spec/factories/services.rb
index b2d6ada91fa..ada042726aa 100644
--- a/spec/factories/services.rb
+++ b/spec/factories/services.rb
@@ -47,12 +47,23 @@ FactoryBot.define do
factory :jira_service do
project
active true
- properties(
- url: 'https://jira.example.com',
- username: 'jira_user',
- password: 'my-secret-password',
- project_key: 'jira-key'
- )
+
+ transient do
+ create_data true
+ url 'https://jira.example.com'
+ api_url 'https://jira-api.example.com'
+ username 'jira_username'
+ password 'jira_password'
+ jira_issue_transition_id '56-1'
+ end
+
+ after(:build) do |service, evaluator|
+ if evaluator.create_data
+ create(:jira_tracker_data, service: service,
+ url: evaluator.url, api_url: evaluator.api_url, jira_issue_transition_id: evaluator.jira_issue_transition_id,
+ username: evaluator.username, password: evaluator.password )
+ end
+ end
end
factory :bugzilla_service do
@@ -80,20 +91,31 @@ FactoryBot.define do
end
trait :issue_tracker do
- properties(
- project_url: 'http://issue-tracker.example.com',
- issues_url: 'http://issue-tracker.example.com/issues/:id',
- new_issue_url: 'http://issue-tracker.example.com'
- )
+ transient do
+ create_data true
+ project_url 'http://issuetracker.example.com'
+ issues_url 'http://issues.example.com/issues/:id'
+ new_issue_url 'http://new-issue.example.com'
+ end
+
+ after(:build) do |service, evaluator|
+ if evaluator.create_data
+ create(:issue_tracker_data, service: service,
+ project_url: evaluator.project_url, issues_url: evaluator.issues_url, new_issue_url: evaluator.new_issue_url
+ )
+ end
+ end
end
trait :jira_cloud_service do
- properties(
- url: 'https://mysite.atlassian.net',
- username: 'jira_user',
- password: 'my-secret-password',
- project_key: 'jira-key'
- )
+ after(:build) do |service|
+ create(:jira_tracker_data,
+ service: service,
+ url: 'https://mysite.atlassian.net',
+ username: 'jira_user',
+ password: 'my-secret-password'
+ )
+ end
end
factory :hipchat_service do
@@ -102,15 +124,21 @@ FactoryBot.define do
token 'test_token'
end
+
+ # this is for testing storing values inside properties, which is deprecated and will be removed in
+ # https://gitlab.com/gitlab-org/gitlab-ce/issues/63084
trait :without_properties_callback do
- after(:build) do |service|
- allow(service).to receive(:handle_properties)
+ jira_tracker_data nil
+ issue_tracker_data nil
+
+ after(:build) do
+ IssueTrackerService.skip_callback(:validation, :before, :handle_properties)
end
- after(:create) do |service|
- # we have to remove the stub because the behaviour of
- # handle_properties method is tested after the creation
- allow(service).to receive(:handle_properties).and_call_original
+ to_create { |instance| instance.save(validate: false)}
+
+ after(:create) do
+ IssueTrackerService.set_callback(:validation, :before, :handle_properties)
end
end
end
diff --git a/spec/features/issuables/markdown_references/jira_spec.rb b/spec/features/issuables/markdown_references/jira_spec.rb
index 8085918f533..b64c63c1c81 100644
--- a/spec/features/issuables/markdown_references/jira_spec.rb
+++ b/spec/features/issuables/markdown_references/jira_spec.rb
@@ -15,8 +15,8 @@ describe "Jira", :js do
before do
remotelink = double(:remotelink, all: [], build: double(save!: true))
- stub_request(:get, "https://jira.example.com/rest/api/2/issue/JIRA-5")
- stub_request(:post, "https://jira.example.com/rest/api/2/issue/JIRA-5/comment")
+ stub_request(:get, "https://jira-api.example.com/rest/api/2/issue/JIRA-5")
+ stub_request(:post, "https://jira-api.example.com/rest/api/2/issue/JIRA-5/comment")
allow_any_instance_of(JIRA::Resource::Issue).to receive(:remotelink).and_return(remotelink)
sign_in(user)
diff --git a/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb b/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb
index 7eb63fea413..47ea273ef3a 100644
--- a/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb
@@ -34,7 +34,7 @@ describe Banzai::Pipeline::GfmPipeline do
result = described_class.call(markdown, project: project)[:output]
link = result.css('a').first
- expect(link['href']).to eq 'http://issue-tracker.example.com/issues/12'
+ expect(link['href']).to eq 'http://issues.example.com/issues/12'
end
it 'parses cross-project references to regular issues' do
@@ -63,7 +63,7 @@ describe Banzai::Pipeline::GfmPipeline do
result = described_class.call(markdown, project: project)[:output]
link = result.css('a').first
- expect(link['href']).to eq 'http://issue-tracker.example.com/issues/12'
+ expect(link['href']).to eq 'http://issues.example.com/issues/12'
end
it 'allows to use long external reference syntax for Redmine' do
@@ -72,7 +72,7 @@ describe Banzai::Pipeline::GfmPipeline do
result = described_class.call(markdown, project: project)[:output]
link = result.css('a').first
- expect(link['href']).to eq 'http://issue-tracker.example.com/issues/12'
+ expect(link['href']).to eq 'http://issues.example.com/issues/12'
end
it 'parses cross-project references to regular issues' do
diff --git a/spec/models/project_services/bugzilla_service_spec.rb b/spec/models/project_services/bugzilla_service_spec.rb
index 74c85a13c88..4ad8f2c1f17 100644
--- a/spec/models/project_services/bugzilla_service_spec.rb
+++ b/spec/models/project_services/bugzilla_service_spec.rb
@@ -8,31 +8,6 @@ describe BugzillaService do
it { is_expected.to have_one :service_hook }
end
- describe 'Validations' do
- context 'when service is active' do
- before do
- subject.active = true
- end
-
- it { is_expected.to validate_presence_of(:project_url) }
- it { is_expected.to validate_presence_of(:issues_url) }
- it { is_expected.to validate_presence_of(:new_issue_url) }
- it_behaves_like 'issue tracker service URL attribute', :project_url
- it_behaves_like 'issue tracker service URL attribute', :issues_url
- it_behaves_like 'issue tracker service URL attribute', :new_issue_url
- end
-
- context 'when service is inactive' do
- before do
- subject.active = false
- end
-
- it { is_expected.not_to validate_presence_of(:project_url) }
- it { is_expected.not_to validate_presence_of(:issues_url) }
- it { is_expected.not_to validate_presence_of(:new_issue_url) }
- end
- end
-
context 'overriding properties' do
let(:default_title) { 'JIRA' }
let(:default_description) { 'JiraService|Jira issue tracker' }
diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
index 0c4fc290a13..a2c38063df6 100644
--- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
+++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
@@ -8,21 +8,6 @@ describe GitlabIssueTrackerService do
it { is_expected.to have_one :service_hook }
end
- describe 'Validations' do
- context 'when service is active' do
- subject { described_class.new(project: create(:project), active: true) }
-
- it { is_expected.to validate_presence_of(:issues_url) }
- it_behaves_like 'issue tracker service URL attribute', :issues_url
- end
-
- context 'when service is inactive' do
- subject { described_class.new(project: create(:project), active: false) }
-
- it { is_expected.not_to validate_presence_of(:issues_url) }
- end
- end
-
describe 'project and issue urls' do
let(:project) { create(:project) }
let(:service) { project.create_gitlab_issue_tracker_service(active: true) }
diff --git a/spec/models/project_services/issue_tracker_service_spec.rb b/spec/models/project_services/issue_tracker_service_spec.rb
index 2fc4d69c2db..f1cdee5c4a3 100644
--- a/spec/models/project_services/issue_tracker_service_spec.rb
+++ b/spec/models/project_services/issue_tracker_service_spec.rb
@@ -7,7 +7,7 @@ describe IssueTrackerService do
let(:project) { create :project }
describe 'only one issue tracker per project' do
- let(:service) { RedmineService.new(project: project, active: true) }
+ let(:service) { RedmineService.new(project: project, active: true, issue_tracker_data: build(:issue_tracker_data)) }
before do
create(:custom_issue_tracker_service, project: project)
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index ae109aadcc0..33112296a03 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -6,10 +6,18 @@ describe JiraService do
include Gitlab::Routing
include AssetsHelpers
+ let(:title) { 'custom title' }
+ let(:description) { 'custom description' }
+ let(:url) { 'http://jira.example.com' }
+ let(:api_url) { 'http://api-jira.example.com' }
+ let(:username) { 'jira-username' }
+ let(:password) { 'jira-password' }
+ let(:transition_id) { 'test27' }
+
describe '#options' do
let(:service) do
- described_class.new(
- project: build_stubbed(:project),
+ described_class.create(
+ project: create(:project),
active: true,
username: 'username',
password: 'test',
@@ -46,55 +54,227 @@ describe JiraService do
describe '#create' do
let(:params) do
{
- project: create(:project), title: 'custom title', description: 'custom description'
+ project: create(:project),
+ title: 'custom title', description: 'custom description',
+ url: url, api_url: api_url,
+ username: username, password: password,
+ jira_issue_transition_id: transition_id
}
end
subject { described_class.create(params) }
- it 'does not store title & description into properties' do
- expect(subject.properties.keys).not_to include('title', 'description')
+ it 'does not store data into properties' do
+ expect(subject.properties).to be_nil
end
- it 'sets title & description correctly' do
+ it 'sets title correctly' do
+ service = subject
+
+ expect(service.title).to eq('custom title')
+ end
+
+ it 'sets service data correctly' do
service = subject
expect(service.title).to eq('custom title')
expect(service.description).to eq('custom description')
end
+
+ it 'stores data in data_fields correcty' do
+ service = subject
+
+ expect(service.jira_tracker_data.url).to eq(url)
+ expect(service.jira_tracker_data.api_url).to eq(api_url)
+ expect(service.jira_tracker_data.username).to eq(username)
+ expect(service.jira_tracker_data.password).to eq(password)
+ expect(service.jira_tracker_data.jira_issue_transition_id).to eq(transition_id)
+ end
end
+ # we need to make sure we are able to read both from properties and jira_tracker_data table
+ # TODO: change this as part of #63084
context 'overriding properties' do
- let(:url) { 'http://issue_tracker.example.com' }
let(:access_params) do
- { url: url, username: 'username', password: 'password' }
+ { url: url, api_url: api_url, username: username, password: password,
+ jira_issue_transition_id: transition_id }
+ end
+
+ shared_examples 'handles jira fields' do
+ let(:data_params) do
+ {
+ url: url, api_url: api_url,
+ username: username, password: password,
+ jira_issue_transition_id: transition_id,
+ title: title, description: description
+ }
+ end
+
+ context 'reading data' do
+ it 'reads data correctly' do
+ expect(service.url).to eq(url)
+ expect(service.api_url).to eq(api_url)
+ expect(service.username).to eq(username)
+ expect(service.password).to eq(password)
+ expect(service.jira_issue_transition_id).to eq(transition_id)
+ end
+ end
+
+ context '#update' do
+ context 'basic update' do
+ let(:new_username) { 'new_username' }
+ let(:new_url) { 'http://jira-new.example.com' }
+
+ before do
+ service.update(username: new_username, url: new_url)
+ end
+
+ it 'leaves properties field emtpy' do
+ # expect(service.reload.properties).to be_empty
+ end
+
+ it 'stores updated data in jira_tracker_data table' do
+ data = service.jira_tracker_data.reload
+
+ expect(data.url).to eq(new_url)
+ expect(data.api_url).to eq(api_url)
+ expect(data.username).to eq(new_username)
+ expect(data.password).to eq(password)
+ expect(data.jira_issue_transition_id).to eq(transition_id)
+ end
+ end
+
+ context 'stored password invalidation' do
+ context 'when a password was previously set' do
+ context 'when only web url present' do
+ let(:data_params) do
+ {
+ url: url, api_url: nil,
+ username: username, password: password,
+ jira_issue_transition_id: transition_id
+ }
+ end
+
+ it 'resets password if url changed' do
+ service
+ service.url = 'http://jira_edited.example.com'
+ service.save
+
+ expect(service.reload.url).to eq('http://jira_edited.example.com')
+ expect(service.password).to be_nil
+ end
+
+ it 'resets password if url not changed but api url added' do
+ service.api_url = 'http://jira_edited.example.com/rest/api/2'
+ service.save
+
+ expect(service.reload.api_url).to eq('http://jira_edited.example.com/rest/api/2')
+ expect(service.password).to be_nil
+ end
+
+ it 'does not reset password if new url is set together with password, even if it\'s the same password' do
+ service.url = 'http://jira_edited.example.com'
+ service.password = password
+ service.save
+
+ expect(service.password).to eq(password)
+ expect(service.url).to eq('http://jira_edited.example.com')
+ end
+
+ it 'resets password if url changed, even if setter called multiple times' do
+ service.url = 'http://jira1.example.com/rest/api/2'
+ service.url = 'http://jira1.example.com/rest/api/2'
+ service.save
+
+ expect(service.password).to be_nil
+ end
+
+ it 'does not reset password if username changed' do
+ service.username = 'some_name'
+ service.save
+
+ expect(service.reload.password).to eq(password)
+ end
+ end
+
+ context 'when both web and api url present' do
+ let(:data_params) do
+ {
+ url: url, api_url: 'http://jira.example.com/rest/api/2',
+ username: username, password: password,
+ jira_issue_transition_id: transition_id
+ }
+ end
+
+ it 'resets password if api url changed' do
+ service.api_url = 'http://jira_edited.example.com/rest/api/2'
+ service.save
+
+ expect(service.password).to be_nil
+ end
+
+ it 'does not reset password if url changed' do
+ service.url = 'http://jira_edited.example.com'
+ service.save
+
+ expect(service.password).to eq(password)
+ end
+
+ it 'resets password if api url set to empty' do
+ service.update(api_url: '')
+
+ expect(service.reload.password).to be_nil
+ end
+ end
+ end
+
+ context 'when no password was previously set' do
+ let(:data_params) do
+ {
+ url: url, username: username
+ }
+ end
+
+ it 'saves password if new url is set together with password' do
+ service.url = 'http://jira_edited.example.com/rest/api/2'
+ service.password = 'password'
+ service.save
+ expect(service.reload.password).to eq('password')
+ expect(service.reload.url).to eq('http://jira_edited.example.com/rest/api/2')
+ end
+ end
+ end
+ end
end
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab-ce/issues/63084
context 'when data are stored in properties' do
- let(:properties) { access_params.merge(title: title, description: description) }
- let(:service) do
- create(:jira_service, :without_properties_callback, properties: properties)
+ let(:properties) { data_params.merge(title: title, description: description) }
+ let!(:service) do
+ create(:jira_service, :without_properties_callback, properties: properties, create_data: false)
end
include_examples 'issue tracker fields'
+ include_examples 'handles jira fields'
end
context 'when data are stored in separated fields' do
let(:service) do
- create(:jira_service, title: title, description: description, properties: access_params)
+ create(:jira_service, data_params.merge(properties: {}))
end
include_examples 'issue tracker fields'
+ include_examples 'handles jira fields'
end
context 'when data are stored in both properties and separated fields' do
- let(:properties) { access_params.merge(title: 'wrong title', description: 'wrong description') }
+ let(:properties) { data_params.merge(title: 'wrong title', description: 'wrong description') }
let(:service) do
- create(:jira_service, :without_properties_callback, title: title, description: description, properties: properties)
+ create(:jira_service, :without_properties_callback, data_params.merge(properties: {}))
end
include_examples 'issue tracker fields'
+ include_examples 'handles jira fields'
end
context 'when no title & description are set' do
@@ -338,111 +518,6 @@ describe JiraService do
end
end
- describe 'Stored password invalidation' do
- let(:project) { create(:project) }
-
- context 'when a password was previously set' do
- before do
- @jira_service = described_class.create!(
- project: project,
- properties: {
- url: 'http://jira.example.com/web',
- username: 'mic',
- password: 'password'
- }
- )
- end
-
- context 'when only web url present' do
- it 'reset password if url changed' do
- @jira_service.url = 'http://jira_edited.example.com/rest/api/2'
- @jira_service.save
-
- expect(@jira_service.password).to be_nil
- end
-
- it 'reset password if url not changed but api url added' do
- @jira_service.api_url = 'http://jira_edited.example.com/rest/api/2'
- @jira_service.save
-
- expect(@jira_service.password).to be_nil
- end
- end
-
- context 'when both web and api url present' do
- before do
- @jira_service.api_url = 'http://jira.example.com/rest/api/2'
- @jira_service.password = 'password'
-
- @jira_service.save
- end
- it 'reset password if api url changed' do
- @jira_service.api_url = 'http://jira_edited.example.com/rest/api/2'
- @jira_service.save
-
- expect(@jira_service.password).to be_nil
- end
-
- it 'does not reset password if url changed' do
- @jira_service.url = 'http://jira_edited.example.com/rweb'
- @jira_service.save
-
- expect(@jira_service.password).to eq('password')
- end
-
- it 'reset password if api url set to empty' do
- @jira_service.api_url = ''
- @jira_service.save
-
- expect(@jira_service.password).to be_nil
- end
- end
-
- it 'does not reset password if username changed' do
- @jira_service.username = 'some_name'
- @jira_service.save
-
- expect(@jira_service.password).to eq('password')
- end
-
- it 'does not reset password if new url is set together with password, even if it\'s the same password' do
- @jira_service.url = 'http://jira_edited.example.com/rest/api/2'
- @jira_service.password = 'password'
- @jira_service.save
-
- expect(@jira_service.password).to eq('password')
- expect(@jira_service.url).to eq('http://jira_edited.example.com/rest/api/2')
- end
-
- it 'resets password if url changed, even if setter called multiple times' do
- @jira_service.url = 'http://jira1.example.com/rest/api/2'
- @jira_service.url = 'http://jira1.example.com/rest/api/2'
- @jira_service.save
- expect(@jira_service.password).to be_nil
- end
- end
-
- context 'when no password was previously set' do
- before do
- @jira_service = described_class.create(
- project: project,
- properties: {
- url: 'http://jira.example.com/rest/api/2',
- username: 'mic'
- }
- )
- end
-
- it 'saves password if new url is set together with password' do
- @jira_service.url = 'http://jira_edited.example.com/rest/api/2'
- @jira_service.password = 'password'
- @jira_service.save
- expect(@jira_service.password).to eq('password')
- expect(@jira_service.url).to eq('http://jira_edited.example.com/rest/api/2')
- end
- end
- end
-
describe 'description and title' do
let(:title) { 'Jira One' }
let(:description) { 'Jira One issue tracker' }
@@ -467,7 +542,7 @@ describe JiraService do
context 'when it is set in properties' do
it 'values from properties are returned' do
- service = create(:jira_service, properties: properties)
+ service = create(:jira_service, :without_properties_callback, properties: properties)
expect(service.title).to eq(title)
expect(service.description).to eq(description)
@@ -530,8 +605,8 @@ describe JiraService do
project = create(:project)
service = project.create_jira_service(active: true)
- expect(service.properties['url']).to eq('http://jira.sample/projects/project_a')
- expect(service.properties['api_url']).to eq('http://jira.sample/api')
+ expect(service.url).to eq('http://jira.sample/projects/project_a')
+ expect(service.api_url).to eq('http://jira.sample/api')
end
end
diff --git a/spec/models/project_services/redmine_service_spec.rb b/spec/models/project_services/redmine_service_spec.rb
index c1ee6546b12..310ec1450eb 100644
--- a/spec/models/project_services/redmine_service_spec.rb
+++ b/spec/models/project_services/redmine_service_spec.rb
@@ -9,28 +9,7 @@ describe RedmineService do
end
describe 'Validations' do
- context 'when service is active' do
- before do
- subject.active = true
- end
-
- it { is_expected.to validate_presence_of(:project_url) }
- it { is_expected.to validate_presence_of(:issues_url) }
- it { is_expected.to validate_presence_of(:new_issue_url) }
- it_behaves_like 'issue tracker service URL attribute', :project_url
- it_behaves_like 'issue tracker service URL attribute', :issues_url
- it_behaves_like 'issue tracker service URL attribute', :new_issue_url
- end
-
- context 'when service is inactive' do
- before do
- subject.active = false
- end
-
- it { is_expected.not_to validate_presence_of(:project_url) }
- it { is_expected.not_to validate_presence_of(:issues_url) }
- it { is_expected.not_to validate_presence_of(:new_issue_url) }
- end
+ # TODO validate data fields
end
describe '.reference_pattern' do
diff --git a/spec/models/project_services/youtrack_service_spec.rb b/spec/models/project_services/youtrack_service_spec.rb
index c48bf487af0..9366ce16644 100644
--- a/spec/models/project_services/youtrack_service_spec.rb
+++ b/spec/models/project_services/youtrack_service_spec.rb
@@ -9,25 +9,7 @@ describe YoutrackService do
end
describe 'Validations' do
- context 'when service is active' do
- before do
- subject.active = true
- end
-
- it { is_expected.to validate_presence_of(:project_url) }
- it { is_expected.to validate_presence_of(:issues_url) }
- it_behaves_like 'issue tracker service URL attribute', :project_url
- it_behaves_like 'issue tracker service URL attribute', :issues_url
- end
-
- context 'when service is inactive' do
- before do
- subject.active = false
- end
-
- it { is_expected.not_to validate_presence_of(:project_url) }
- it { is_expected.not_to validate_presence_of(:issues_url) }
- end
+ # TODO validate data fields
end
describe '.reference_pattern' do
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index 0797b9a9d83..d96e1398677 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -257,8 +257,8 @@ describe Service do
expect(service.title).to eq('random title')
end
- it 'creates the properties' do
- expect(service.properties).to eq({ "project_url" => "http://gitlab.example.com" })
+ it 'sets data correctly' do
+ expect(service.data_fields.project_url).to eq('http://gitlab.example.com')
end
end
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 910fe3b50b7..1f2a2e161a1 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -824,7 +824,7 @@ describe SystemNoteService do
let(:jira_tracker) { project.jira_service }
let(:commit) { project.commit }
let(:comment_url) { jira_api_comment_url(jira_issue.id) }
- let(:success_message) { "SUCCESS: Successfully posted to http://jira.example.net." }
+ let(:success_message) { "SUCCESS: Successfully posted to https://jira-api.example.com." }
before do
stub_jira_urls(jira_issue.id)
diff --git a/spec/support/helpers/jira_service_helper.rb b/spec/support/helpers/jira_service_helper.rb
index 57c33c81ea3..151cd7054e7 100644
--- a/spec/support/helpers/jira_service_helper.rb
+++ b/spec/support/helpers/jira_service_helper.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module JiraServiceHelper
- JIRA_URL = "http://jira.example.net".freeze
+ JIRA_URL = "https://jira-api.example.com".freeze
JIRA_API = JIRA_URL + "/rest/api/2"
def jira_service_settings
@@ -10,7 +10,6 @@ module JiraServiceHelper
url: JIRA_URL,
username: 'jira-user',
password: 'my-secret-password',
- project_key: "JIRA",
jira_issue_transition_id: '1'
}