Commit c803cc90 authored by Sean McGivern's avatar Sean McGivern

Merge branch 'ee-58886-issue-tracker-fields' into 'master'

Create models for issue trackers data

See merge request gitlab-org/gitlab-ee!14187
parents 9f8c3267 3e12c0b9
# frozen_string_literal: true
module DataFields
extend ActiveSupport::Concern
included do
has_one :issue_tracker_data
has_one :jira_tracker_data
end
end
# frozen_string_literal: true
class IssueTrackerData < ApplicationRecord
belongs_to :service
delegate :activated?, to: :service, allow_nil: true
validates :service, presence: true
validates :project_url, presence: true, public_url: { enforce_sanitization: true }, if: :activated?
validates :issues_url, presence: true, public_url: { enforce_sanitization: true }, if: :activated?
validates :new_issue_url, public_url: { enforce_sanitization: true }, if: :activated?
def self.encryption_options
{
key: Settings.attr_encrypted_db_key_base_32,
encode: true,
mode: :per_attribute_iv,
algorithm: 'aes-256-gcm'
}
end
attr_encrypted :project_url, encryption_options
attr_encrypted :issues_url, encryption_options
attr_encrypted :new_issue_url, encryption_options
end
# frozen_string_literal: true
class JiraTrackerData < ApplicationRecord
belongs_to :service
delegate :activated?, to: :service, allow_nil: true
validates :service, presence: true
validates :url, public_url: { enforce_sanitization: true }, presence: true, if: :activated?
validates :api_url, public_url: { enforce_sanitization: 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
def self.encryption_options
{
key: Settings.attr_encrypted_db_key_base_32,
encode: true,
mode: :per_attribute_iv,
algorithm: 'aes-256-gcm'
}
end
attr_encrypted :url, encryption_options
attr_encrypted :api_url, encryption_options
attr_encrypted :username, encryption_options
attr_encrypted :password, encryption_options
end
......@@ -6,6 +6,7 @@ class Service < ApplicationRecord
include Sortable
include Importable
include ProjectServicesLoggable
include DataFields
serialize :properties, JSON # rubocop:disable Cop/ActiveRecordSerialize
......
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class CreateIssueTrackerData < ActiveRecord::Migration[5.1]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :issue_tracker_data do |t|
t.references :service, foreign_key: { on_delete: :cascade }, type: :integer, index: true, null: false
t.timestamps_with_timezone
t.string :encrypted_project_url
t.string :encrypted_project_url_iv
t.string :encrypted_issues_url
t.string :encrypted_issues_url_iv
t.string :encrypted_new_issue_url
t.string :encrypted_new_issue_url_iv
end
end
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class CreateJiraTrackerData < ActiveRecord::Migration[5.1]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :jira_tracker_data do |t|
t.references :service, foreign_key: { on_delete: :cascade }, type: :integer, index: true, null: false
t.timestamps_with_timezone
t.string :encrypted_url
t.string :encrypted_url_iv
t.string :encrypted_api_url
t.string :encrypted_api_url_iv
t.string :encrypted_username
t.string :encrypted_username_iv
t.string :encrypted_password
t.string :encrypted_password_iv
t.string :jira_issue_transition_id
end
end
end
......@@ -1617,6 +1617,19 @@ ActiveRecord::Schema.define(version: 20190611161641) do
t.index ["issue_id"], name: "index_issue_metrics", using: :btree
end
create_table "issue_tracker_data", force: :cascade do |t|
t.integer "service_id", null: false
t.datetime_with_timezone "created_at", null: false
t.datetime_with_timezone "updated_at", null: false
t.string "encrypted_project_url"
t.string "encrypted_project_url_iv"
t.string "encrypted_issues_url"
t.string "encrypted_issues_url_iv"
t.string "encrypted_new_issue_url"
t.string "encrypted_new_issue_url_iv"
t.index ["service_id"], name: "index_issue_tracker_data_on_service_id", using: :btree
end
create_table "issues", id: :serial, force: :cascade do |t|
t.string "title"
t.integer "author_id"
......@@ -1680,6 +1693,22 @@ ActiveRecord::Schema.define(version: 20190611161641) do
t.index ["namespace_id"], name: "index_jira_connect_subscriptions_on_namespace_id", using: :btree
end
create_table "jira_tracker_data", force: :cascade do |t|
t.integer "service_id", null: false
t.datetime_with_timezone "created_at", null: false
t.datetime_with_timezone "updated_at", null: false
t.string "encrypted_url"
t.string "encrypted_url_iv"
t.string "encrypted_api_url"
t.string "encrypted_api_url_iv"
t.string "encrypted_username"
t.string "encrypted_username_iv"
t.string "encrypted_password"
t.string "encrypted_password_iv"
t.string "jira_issue_transition_id"
t.index ["service_id"], name: "index_jira_tracker_data_on_service_id", using: :btree
end
create_table "keys", id: :serial, force: :cascade do |t|
t.integer "user_id"
t.datetime "created_at"
......@@ -3663,6 +3692,7 @@ ActiveRecord::Schema.define(version: 20190611161641) do
add_foreign_key "issue_links", "issues", column: "source_id", name: "fk_c900194ff2", on_delete: :cascade
add_foreign_key "issue_links", "issues", column: "target_id", name: "fk_e71bb44f1f", on_delete: :cascade
add_foreign_key "issue_metrics", "issues", on_delete: :cascade
add_foreign_key "issue_tracker_data", "services", on_delete: :cascade
add_foreign_key "issues", "issues", column: "moved_to_id", name: "fk_a194299be1", on_delete: :nullify
add_foreign_key "issues", "milestones", name: "fk_96b1dd429c", on_delete: :nullify
add_foreign_key "issues", "projects", name: "fk_899c8f3231", on_delete: :cascade
......@@ -3671,6 +3701,7 @@ ActiveRecord::Schema.define(version: 20190611161641) do
add_foreign_key "issues", "users", column: "updated_by_id", name: "fk_ffed080f01", on_delete: :nullify
add_foreign_key "jira_connect_subscriptions", "jira_connect_installations", on_delete: :cascade
add_foreign_key "jira_connect_subscriptions", "namespaces", on_delete: :cascade
add_foreign_key "jira_tracker_data", "services", on_delete: :cascade
add_foreign_key "label_links", "labels", name: "fk_d97dd08678", on_delete: :cascade
add_foreign_key "label_priorities", "labels", on_delete: :cascade
add_foreign_key "label_priorities", "projects", on_delete: :cascade
......
......@@ -30,6 +30,7 @@ describe 'Database schema' do
forked_project_links: %w[forked_from_project_id],
identities: %w[user_id],
issues: %w[last_edited_by_id state_id],
jira_tracker_data: %w[jira_issue_transition_id],
keys: %w[user_id],
label_links: %w[target_id],
lfs_objects_projects: %w[lfs_object_id project_id],
......
# frozen_string_literal: true
FactoryBot.define do
factory :jira_tracker_data do
service
url 'http://jira.example.com'
api_url 'http://api-jira.example.com'
username 'jira_username'
password 'jira_password'
end
factory :issue_tracker_data do
service
project_url 'http://issuetracker.example.com'
issues_url 'http://issues.example.com'
new_issue_url 'http://new-issue.example.com'
end
end
......@@ -175,6 +175,8 @@ deploy_keys:
services:
- project
- service_hook
- jira_tracker_data
- issue_tracker_data
hooks:
- project
- web_hook_logs
......
# frozen_string_literal: true
require 'spec_helper'
describe IssueTrackerData do
let(:service) { create(:custom_issue_tracker_service, active: false, properties: {}) }
describe 'Associations' do
it { is_expected.to belong_to :service }
end
describe 'Validations' do
subject { described_class.new(service: service) }
context 'url validations' do
context 'when service is inactive' do
it { is_expected.not_to validate_presence_of(:project_url) }
it { is_expected.not_to validate_presence_of(:issues_url) }
end
context 'when service is active' do
before do
service.update(active: true)
end
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
it { is_expected.to validate_presence_of(:project_url) }
it { is_expected.to validate_presence_of(:issues_url) }
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe JiraTrackerData do
let(:service) { create(:jira_service, active: false, properties: {}) }
describe 'Associations' do
it { is_expected.to belong_to(:service) }
end
describe 'Validations' do
subject { described_class.new(service: service) }
context 'jira_issue_transition_id' do
it { is_expected.to allow_value(nil).for(:jira_issue_transition_id) }
it { is_expected.to allow_value('1,2,3').for(:jira_issue_transition_id) }
it { is_expected.to allow_value('1;2;3').for(:jira_issue_transition_id) }
it { is_expected.not_to allow_value('a,b,cd').for(:jira_issue_transition_id) }
end
context 'url validations' do
context 'when service is inactive' do
it { is_expected.not_to validate_presence_of(:url) }
it { is_expected.not_to validate_presence_of(:username) }
it { is_expected.not_to validate_presence_of(:password) }
end
context 'when service is active' do
before do
service.update(active: true)
end
it_behaves_like 'issue tracker service URL attribute', :url
it { is_expected.to validate_presence_of(:url) }
it { is_expected.to validate_presence_of(:username) }
it { is_expected.to validate_presence_of(:password) }
end
end
end
end
......@@ -6,6 +6,8 @@ describe Service do
describe "Associations" do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
it { is_expected.to have_one :jira_tracker_data }
it { is_expected.to have_one :issue_tracker_data }
end
describe 'Validations' do
......
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