Commit f42cb701 authored by charlie ablett's avatar charlie ablett

Merge branch '211660-track-jira-imports' into 'master'

Track Jira import progress in a separate data structure

Closes #211660

See merge request gitlab-org/gitlab!28610
parents e86e63fa 14ee4c77
...@@ -9,7 +9,7 @@ module Projects ...@@ -9,7 +9,7 @@ module Projects
def show def show
return if Feature.enabled?(:jira_issue_import_vue, @project) return if Feature.enabled?(:jira_issue_import_vue, @project)
unless @project.import_state&.in_progress? unless @project.latest_jira_import&.in_progress?
jira_client = @project.jira_service.client jira_client = @project.jira_service.client
jira_projects = jira_client.Project.all jira_projects = jira_client.Project.all
...@@ -20,7 +20,7 @@ module Projects ...@@ -20,7 +20,7 @@ module Projects
end end
end end
flash[:notice] = _("Import %{status}") % { status: @project.import_state.status } if @project.import_state.present? && !@project.import_state.none? flash[:notice] = _("Import %{status}") % { status: @project.jira_import_status } unless @project.latest_jira_import&.initial?
end end
def import def import
......
...@@ -30,11 +30,11 @@ module Mutations ...@@ -30,11 +30,11 @@ module Mutations
service_response = ::JiraImport::StartImportService service_response = ::JiraImport::StartImportService
.new(context[:current_user], project, jira_project_key) .new(context[:current_user], project, jira_project_key)
.execute .execute
import_data = service_response.payload[:import_data] jira_import = service_response.success? ? service_response.payload[:import_data] : nil
errors = service_response.error? ? [service_response.message] : []
{ {
jira_import: import_data.errors.blank? ? import_data.projects.last : nil, jira_import: jira_import,
errors: errors_on_object(import_data) errors: errors
} }
end end
......
...@@ -8,11 +8,9 @@ module Resolvers ...@@ -8,11 +8,9 @@ module Resolvers
alias_method :project, :object alias_method :project, :object
def resolve(**args) def resolve(**args)
return JiraImportData.none unless project&.import_data.present?
authorize!(project) authorize!(project)
project.import_data.becomes(JiraImportData).projects project.jira_imports
end end
def authorized_resource?(project) def authorized_resource?(project)
......
...@@ -8,20 +8,12 @@ module Types ...@@ -8,20 +8,12 @@ module Types
graphql_name 'JiraImport' graphql_name 'JiraImport'
field :scheduled_at, Types::TimeType, null: true, field :scheduled_at, Types::TimeType, null: true,
description: 'Timestamp of when the Jira import was created/started' method: :created_at,
description: 'Timestamp of when the Jira import was created'
field :scheduled_by, Types::UserType, null: true, field :scheduled_by, Types::UserType, null: true,
description: 'User that started the Jira import' description: 'User that started the Jira import'
field :jira_project_key, GraphQL::STRING_TYPE, null: false, field :jira_project_key, GraphQL::STRING_TYPE, null: false,
description: 'Project key for the imported Jira project', description: 'Project key for the imported Jira project'
method: :key
def scheduled_at
DateTime.parse(object.scheduled_at)
end
def scheduled_by
::Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.scheduled_by['user_id']).find
end
end end
# rubocop: enable Graphql/AuthorizeTypes # rubocop: enable Graphql/AuthorizeTypes
end end
...@@ -16,7 +16,7 @@ module ImportState ...@@ -16,7 +16,7 @@ module ImportState
end end
def self.jid_by(project_id:, status:) def self.jid_by(project_id:, status:)
select(:jid).with_status(status).find_by(project_id: project_id) select(:jid).where(status: status).find_by(project_id: project_id)
end end
end end
end end
......
# frozen_string_literal: true
class JiraImportData < ProjectImportData
JiraProjectDetails = Struct.new(:key, :scheduled_at, :scheduled_by)
FORCE_IMPORT_KEY = 'force-import'
def projects
return [] unless data
projects = data.dig('jira', 'projects')&.map do |p|
JiraProjectDetails.new(p['key'], p['scheduled_at'], p['scheduled_by'])
end
projects&.sort_by { |jp| jp.scheduled_at } || []
end
def <<(project)
self.data ||= { 'jira' => { 'projects' => [] } }
self.data['jira'] ||= { 'projects' => [] }
self.data['jira']['projects'] = [] if data['jira']['projects'].blank? || !data['jira']['projects'].is_a?(Array)
self.data['jira']['projects'] << project.to_h
self.data.deep_stringify_keys!
end
def force_import!
self.data ||= {}
self.data.deep_merge!({ 'jira' => { FORCE_IMPORT_KEY => true } })
self.data.deep_stringify_keys!
end
def force_import?
!!data&.dig('jira', FORCE_IMPORT_KEY) && !projects.blank?
end
def finish_import!
return if data&.dig('jira', FORCE_IMPORT_KEY).nil?
data['jira'].delete(FORCE_IMPORT_KEY)
end
def current_project
projects.last
end
end
...@@ -22,6 +22,8 @@ class JiraImportState < ApplicationRecord ...@@ -22,6 +22,8 @@ class JiraImportState < ApplicationRecord
message: _('Cannot have multiple Jira imports running at the same time') message: _('Cannot have multiple Jira imports running at the same time')
} }
alias_method :scheduled_by, :user
state_machine :status, initial: :initial do state_machine :status, initial: :initial do
event :schedule do event :schedule do
transition initial: :scheduled transition initial: :scheduled
...@@ -46,6 +48,11 @@ class JiraImportState < ApplicationRecord ...@@ -46,6 +48,11 @@ class JiraImportState < ApplicationRecord
end end
end end
before_transition any => :finished do |state, _|
InternalId.flush_records!(project: state.project)
state.project.update_project_counter_caches
end
after_transition any => :finished do |state, _| after_transition any => :finished do |state, _|
if state.jid.present? if state.jid.present?
Gitlab::SidekiqStatus.unset(state.jid) Gitlab::SidekiqStatus.unset(state.jid)
...@@ -67,4 +74,8 @@ class JiraImportState < ApplicationRecord ...@@ -67,4 +74,8 @@ class JiraImportState < ApplicationRecord
def in_progress? def in_progress?
scheduled? || started? scheduled? || started?
end end
def non_initial?
!initial?
end
end end
...@@ -859,9 +859,7 @@ class Project < ApplicationRecord ...@@ -859,9 +859,7 @@ class Project < ApplicationRecord
end end
def jira_import_status def jira_import_status
return import_status if jira_force_import? latest_jira_import&.status || 'initial'
import_data&.becomes(JiraImportData)&.projects.blank? ? 'none' : 'finished'
end end
def human_import_status_name def human_import_status_name
...@@ -875,8 +873,6 @@ class Project < ApplicationRecord ...@@ -875,8 +873,6 @@ class Project < ApplicationRecord
elsif gitlab_project_import? elsif gitlab_project_import?
# Do not retry on Import/Export until https://gitlab.com/gitlab-org/gitlab-foss/issues/26189 is solved. # Do not retry on Import/Export until https://gitlab.com/gitlab-org/gitlab-foss/issues/26189 is solved.
RepositoryImportWorker.set(retry: false).perform_async(self.id) RepositoryImportWorker.set(retry: false).perform_async(self.id)
elsif jira_import?
Gitlab::JiraImport::Stage::StartImportWorker.perform_async(self.id)
else else
RepositoryImportWorker.perform_async(self.id) RepositoryImportWorker.perform_async(self.id)
end end
...@@ -909,7 +905,7 @@ class Project < ApplicationRecord ...@@ -909,7 +905,7 @@ class Project < ApplicationRecord
# This method is overridden in EE::Project model # This method is overridden in EE::Project model
def remove_import_data def remove_import_data
import_data&.destroy unless jira_import? import_data&.destroy
end end
def ci_config_path=(value) def ci_config_path=(value)
...@@ -972,11 +968,7 @@ class Project < ApplicationRecord ...@@ -972,11 +968,7 @@ class Project < ApplicationRecord
end end
def jira_import? def jira_import?
import_type == 'jira' && Feature.enabled?(:jira_issue_import, self) import_type == 'jira' && latest_jira_import.present? && Feature.enabled?(:jira_issue_import, self)
end
def jira_force_import?
jira_import? && import_data&.becomes(JiraImportData)&.force_import?
end end
def gitlab_project_import? def gitlab_project_import?
......
...@@ -20,23 +20,27 @@ module JiraImport ...@@ -20,23 +20,27 @@ module JiraImport
private private
def create_and_schedule_import def create_and_schedule_import
import_data = project.create_or_update_import_data(data: {}).becomes(JiraImportData) jira_import = build_jira_import
jira_project_details = JiraImportData::JiraProjectDetails.new(
jira_project_key,
Time.now.strftime('%Y-%m-%d %H:%M:%S'),
{ user_id: user.id, name: user.name }
)
import_data << jira_project_details
import_data.force_import!
project.import_type = 'jira' project.import_type = 'jira'
project.import_state.schedule if project.save! project.save! && jira_import.schedule!
ServiceResponse.success(payload: { import_data: import_data } ) ServiceResponse.success(payload: { import_data: jira_import } )
rescue => ex rescue => ex
# in case project.save! raises an erorr # in case project.save! raises an erorr
Gitlab::ErrorTracking.track_exception(ex, project_id: project.id) Gitlab::ErrorTracking.track_exception(ex, project_id: project.id)
build_error_response(ex.message) build_error_response(ex.message)
jira_import.do_fail!
end
def build_jira_import
project.jira_imports.build(
user: user,
jira_project_key: jira_project_key,
# we do not have the jira_project_name or jira_project_xid yet so just set a mock value,
# we will once https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28190
jira_project_name: jira_project_key,
jira_project_xid: 0
)
end end
def validate def validate
...@@ -48,18 +52,11 @@ module JiraImport ...@@ -48,18 +52,11 @@ module JiraImport
end end
def build_error_response(message) def build_error_response(message)
import_data = JiraImportData.new(project: project) ServiceResponse.error(message: message, http_status: 400)
import_data.errors.add(:base, message)
ServiceResponse.error(
message: import_data.errors.full_messages.to_sentence,
http_status: 400,
payload: { import_data: import_data }
)
end end
def import_in_progress? def import_in_progress?
import_state = project.import_state || project.create_import_state project.latest_jira_import&.in_progress?
import_state.in_progress?
end end
end end
end end
...@@ -28,7 +28,7 @@ module Gitlab ...@@ -28,7 +28,7 @@ module Gitlab
return false unless project return false unless project
return false if Feature.disabled?(:jira_issue_import, project) return false if Feature.disabled?(:jira_issue_import, project)
project.import_state.started? project.latest_jira_import&.started?
end end
end end
end end
......
...@@ -17,7 +17,7 @@ module Gitlab ...@@ -17,7 +17,7 @@ module Gitlab
}.freeze }.freeze
def find_import_state(project_id) def find_import_state(project_id)
ProjectImportState.jid_by(project_id: project_id, status: :started) JiraImportState.jid_by(project_id: project_id, status: :started)
end end
private private
......
...@@ -9,11 +9,8 @@ module Gitlab ...@@ -9,11 +9,8 @@ module Gitlab
private private
def import(project) def import(project)
project.after_import
ensure
JiraImport.cache_cleanup(project.id) JiraImport.cache_cleanup(project.id)
project.import_data.becomes(JiraImportData).finish_import! project.latest_jira_import&.finish!
project.import_data.save!
end end
end end
end end
......
...@@ -13,7 +13,7 @@ module Gitlab ...@@ -13,7 +13,7 @@ module Gitlab
# new job waiter will have zero jobs_remaining by default, so it will just pass on to next stage # new job waiter will have zero jobs_remaining by default, so it will just pass on to next stage
fake_waiter = JobWaiter.new fake_waiter = JobWaiter.new
project.import_state.refresh_jid_expiration project.latest_jira_import.refresh_jid_expiration
Gitlab::JiraImport::AdvanceStageWorker.perform_async(project.id, { fake_waiter.key => fake_waiter.jobs_remaining }, :notes) Gitlab::JiraImport::AdvanceStageWorker.perform_async(project.id, { fake_waiter.key => fake_waiter.jobs_remaining }, :notes)
end end
end end
......
...@@ -11,7 +11,7 @@ module Gitlab ...@@ -11,7 +11,7 @@ module Gitlab
def import(project) def import(project)
jobs_waiter = Gitlab::JiraImport::IssuesImporter.new(project).execute jobs_waiter = Gitlab::JiraImport::IssuesImporter.new(project).execute
project.import_state.refresh_jid_expiration project.latest_jira_import.refresh_jid_expiration
Gitlab::JiraImport::AdvanceStageWorker.perform_async( Gitlab::JiraImport::AdvanceStageWorker.perform_async(
project.id, project.id,
......
...@@ -12,7 +12,7 @@ module Gitlab ...@@ -12,7 +12,7 @@ module Gitlab
# fake notes import workers for now # fake notes import workers for now
# new job waiter will have zero jobs_remaining by default, so it will just pass on to next stage # new job waiter will have zero jobs_remaining by default, so it will just pass on to next stage
jobs_waiter = JobWaiter.new jobs_waiter = JobWaiter.new
project.import_state.refresh_jid_expiration project.latest_jira_import.refresh_jid_expiration
Gitlab::JiraImport::AdvanceStageWorker.perform_async(project.id, { jobs_waiter.key => jobs_waiter.jobs_remaining }, :finish) Gitlab::JiraImport::AdvanceStageWorker.perform_async(project.id, { jobs_waiter.key => jobs_waiter.jobs_remaining }, :finish)
end end
......
...@@ -16,7 +16,7 @@ module Gitlab ...@@ -16,7 +16,7 @@ module Gitlab
return unless start_import return unless start_import
Gitlab::Import::SetAsyncJid.set_jid(project.import_state) Gitlab::Import::SetAsyncJid.set_jid(project.latest_jira_import)
Gitlab::JiraImport::Stage::ImportLabelsWorker.perform_async(project.id) Gitlab::JiraImport::Stage::ImportLabelsWorker.perform_async(project.id)
end end
...@@ -26,14 +26,13 @@ module Gitlab ...@@ -26,14 +26,13 @@ module Gitlab
def start_import def start_import
return false unless project return false unless project
return false if Feature.disabled?(:jira_issue_import, project) return false if Feature.disabled?(:jira_issue_import, project)
return false unless project.jira_force_import? return true if start(project.latest_jira_import)
return true if start(project.import_state)
Gitlab::Import::Logger.info( Gitlab::Import::Logger.info(
{ {
project_id: project.id, project_id: project.id,
project_path: project.full_path, project_path: project.full_path,
state: project&.import_status, state: project&.jira_import_status,
message: 'inconsistent state while importing' message: 'inconsistent state while importing'
} }
) )
......
...@@ -4265,7 +4265,7 @@ type JiraImport { ...@@ -4265,7 +4265,7 @@ type JiraImport {
jiraProjectKey: String! jiraProjectKey: String!
""" """
Timestamp of when the Jira import was created/started Timestamp of when the Jira import was created
""" """
scheduledAt: Time scheduledAt: Time
......
...@@ -12108,7 +12108,7 @@ ...@@ -12108,7 +12108,7 @@
}, },
{ {
"name": "scheduledAt", "name": "scheduledAt",
"description": "Timestamp of when the Jira import was created/started", "description": "Timestamp of when the Jira import was created",
"args": [ "args": [
], ],
......
...@@ -637,7 +637,7 @@ Autogenerated return type of IssueSetWeight ...@@ -637,7 +637,7 @@ Autogenerated return type of IssueSetWeight
| Name | Type | Description | | Name | Type | Description |
| --- | ---- | ---------- | | --- | ---- | ---------- |
| `jiraProjectKey` | String! | Project key for the imported Jira project | | `jiraProjectKey` | String! | Project key for the imported Jira project |
| `scheduledAt` | Time | Timestamp of when the Jira import was created/started | | `scheduledAt` | Time | Timestamp of when the Jira import was created |
| `scheduledBy` | User | User that started the Jira import | | `scheduledBy` | User | User that started the Jira import |
## JiraImportStartPayload ## JiraImportStartPayload
......
...@@ -346,14 +346,7 @@ module EE ...@@ -346,14 +346,7 @@ module EE
# Historically this was intended ensure `super` is only called # Historically this was intended ensure `super` is only called
# when a project is imported(usually on project creation only) so `repository_exists?` # when a project is imported(usually on project creation only) so `repository_exists?`
# check was added so that it does not stop mirroring if later on mirroring option is added to the project. # check was added so that it does not stop mirroring if later on mirroring option is added to the project.
# return super if import? && !repository_exists?
# With jira importer we need to allow to run the import multiple times on same project,
# which can conflict with scheduled mirroring(if that project had or will have mirroring enabled),
# so we are checking if its a jira reimport then we trigger that and skip mirroring even if mirroring
# should have been started. When we run into race condition with mirroring on a jira imported project
# the mirroring would still be picked up 1 minute later, based on `Gitlab::Mirror::SCHEDULER_CRON` and
# `ProjectUpdateState#mirror_update_due?``
return super if jira_force_import? || import? && !repository_exists?
if mirror? if mirror?
::Gitlab::Metrics.add_event(:mirrors_scheduled) ::Gitlab::Metrics.add_event(:mirrors_scheduled)
......
...@@ -1761,35 +1761,20 @@ describe Project do ...@@ -1761,35 +1761,20 @@ describe Project do
end end
context 'when mirror true on a jira imported project' do context 'when mirror true on a jira imported project' do
let(:user) { create(:user) } let_it_be(:user) { create(:user) }
let(:symbol_keys_project) do let_it_be(:project) { create(:project, :repository, import_type: 'jira', mirror: true, import_url: 'http://some_url.com', mirror_user_id: user.id) }
{ key: 'AA', scheduled_at: 2.days.ago.strftime('%Y-%m-%d %H:%M:%S'), scheduled_by: { 'user_id' => 1, 'name' => 'tester1' } } let_it_be(:jira_import) { create(:jira_import_state, project: project) }
end
let(:project) { create(:project, :repository, import_type: 'jira', mirror: true, import_url: 'http://some_url.com', mirror_user_id: user.id, import_data: import_data) }
context 'when jira import is forced' do
let(:import_data) { JiraImportData.new(data: { jira: { projects: [symbol_keys_project], JiraImportData::FORCE_IMPORT_KEY => true } }) }
it 'does not trigger mirror update' do
expect(RepositoryUpdateMirrorWorker).not_to receive(:perform_async)
expect(Gitlab::JiraImport::Stage::StartImportWorker).to receive(:perform_async)
expect(project.mirror).to be true
expect(project.jira_import?).to be true
expect(project.jira_force_import?).to be true
project.add_import_job context 'when jira import is in progress' do
before do
jira_import.start
end end
end
context 'when jira import is not forced' do
let(:import_data) { JiraImportData.new(data: { jira: { projects: [symbol_keys_project] } }) }
it 'does trigger mirror update' do it 'does trigger mirror update' do
expect(RepositoryUpdateMirrorWorker).to receive(:perform_async) expect(RepositoryUpdateMirrorWorker).to receive(:perform_async)
expect(Gitlab::JiraImport::Stage::StartImportWorker).not_to receive(:perform_async) expect(Gitlab::JiraImport::Stage::StartImportWorker).not_to receive(:perform_async)
expect(project.mirror).to be true expect(project.mirror).to be true
expect(project.jira_import?).to be true expect(project.jira_import?).to be true
expect(project.jira_force_import?).to be false
project.add_import_job project.add_import_job
end end
......
...@@ -9,7 +9,7 @@ module Gitlab ...@@ -9,7 +9,7 @@ module Gitlab
raise Projects::ImportService::Error, _('Jira import feature is disabled.') unless Feature.enabled?(:jira_issue_import, project) raise Projects::ImportService::Error, _('Jira import feature is disabled.') unless Feature.enabled?(:jira_issue_import, project)
raise Projects::ImportService::Error, _('Jira integration not configured.') unless project.jira_service&.active? raise Projects::ImportService::Error, _('Jira integration not configured.') unless project.jira_service&.active?
@jira_project_key = project&.import_data&.becomes(JiraImportData)&.current_project&.key @jira_project_key = project.latest_jira_import&.jira_project_key
raise Projects::ImportService::Error, _('Unable to find Jira project to import data from.') unless @jira_project_key raise Projects::ImportService::Error, _('Unable to find Jira project to import data from.') unless @jira_project_key
@project = project @project = project
......
...@@ -105,16 +105,16 @@ describe Projects::Import::JiraController do ...@@ -105,16 +105,16 @@ describe Projects::Import::JiraController do
context 'when everything is ok' do context 'when everything is ok' do
it 'creates import state' do it 'creates import state' do
expect(project.import_state).to be_nil expect(project.latest_jira_import).to be_nil
post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: 'Test' } post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: 'Test' }
project.reload project.reload
jira_project = project.import_data.data.dig('jira', 'projects').first jira_import = project.latest_jira_import
expect(project.import_type).to eq 'jira' expect(project.import_type).to eq 'jira'
expect(project.import_state.status).to eq 'scheduled' expect(jira_import.status).to eq 'scheduled'
expect(jira_project['key']).to eq 'Test' expect(jira_import.jira_project_key).to eq 'Test'
expect(response).to redirect_to(project_import_jira_path(project)) expect(response).to redirect_to(project_import_jira_path(project))
end end
end end
...@@ -122,29 +122,19 @@ describe Projects::Import::JiraController do ...@@ -122,29 +122,19 @@ describe Projects::Import::JiraController do
end end
context 'when import state is scheduled' do context 'when import state is scheduled' do
let_it_be(:import_state) { create(:import_state, project: project, status: :scheduled) } let_it_be(:jira_import_state) { create(:jira_import_state, :scheduled, project: project) }
context 'get show' do context 'get show' do
it 'renders import status' do it 'renders import status' do
get :show, params: { namespace_id: project.namespace.to_param, project_id: project } get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
expect(project.import_state.status).to eq 'scheduled' jira_import = project.latest_jira_import
expect(jira_import.status).to eq 'scheduled'
expect(flash.now[:notice]).to eq 'Import scheduled' expect(flash.now[:notice]).to eq 'Import scheduled'
end end
end end
context 'post import' do context 'post import' do
before do
project.reload
project.create_import_data(
data: {
'jira': {
'projects': [{ 'key': 'Test', scheduled_at: 5.days.ago, scheduled_by: { user_id: user.id, name: user.name } }]
}
}
)
end
it 'uses the existing import data' do it 'uses the existing import data' do
post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: 'New Project' } post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: 'New Project' }
...@@ -155,39 +145,27 @@ describe Projects::Import::JiraController do ...@@ -155,39 +145,27 @@ describe Projects::Import::JiraController do
end end
context 'when jira import ran before' do context 'when jira import ran before' do
let_it_be(:import_state) { create(:import_state, project: project, status: :finished) } let_it_be(:jira_import_state) { create(:jira_import_state, :finished, project: project, jira_project_key: 'Test') }
context 'get show' do context 'get show' do
it 'renders import status' do it 'renders import status' do
allow(JIRA::Resource::Project).to receive(:all).and_return([]) allow(JIRA::Resource::Project).to receive(:all).and_return([])
get :show, params: { namespace_id: project.namespace.to_param, project_id: project } get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
expect(project.import_state.status).to eq 'finished' expect(project.latest_jira_import.status).to eq 'finished'
expect(flash.now[:notice]).to eq 'Import finished' expect(flash.now[:notice]).to eq 'Import finished'
end end
end end
context 'post import' do context 'post import' do
before do
project.reload
project.create_import_data(
data: {
'jira': {
'projects': [{ 'key': 'Test', scheduled_at: 5.days.ago, scheduled_by: { user_id: user.id, name: user.name } }]
}
}
)
end
it 'uses the existing import data' do it 'uses the existing import data' do
post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: 'New Project' } post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: 'New Project' }
project.reload project.reload
expect(project.import_state.status).to eq 'scheduled' expect(project.latest_jira_import.status).to eq 'scheduled'
jira_imported_projects = project.import_data.data.dig('jira', 'projects') expect(project.jira_imports.size).to eq 2
expect(jira_imported_projects.size).to eq 2 expect(project.jira_imports.first.jira_project_key).to eq 'Test'
expect(jira_imported_projects.first['key']).to eq 'Test' expect(project.jira_imports.last.jira_project_key).to eq 'New Project'
expect(jira_imported_projects.last['key']).to eq 'New Project'
expect(response).to redirect_to(project_import_jira_path(project)) expect(response).to redirect_to(project_import_jira_path(project))
end end
end end
......
...@@ -7,29 +7,16 @@ describe Resolvers::Projects::JiraImportsResolver do ...@@ -7,29 +7,16 @@ describe Resolvers::Projects::JiraImportsResolver do
describe '#resolve' do describe '#resolve' do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:jira_import_data) do let_it_be(:project, reload: true) { create(:project, :public) }
data = JiraImportData.new
data << JiraImportData::JiraProjectDetails.new('AA', 2.days.ago.strftime('%Y-%m-%d %H:%M:%S'), { user_id: user.id, name: user.name })
data << JiraImportData::JiraProjectDetails.new('BB', 5.days.ago.strftime('%Y-%m-%d %H:%M:%S'), { user_id: user.id, name: user.name })
data
end
context 'when feature flag disabled' do
let_it_be(:project) { create(:project, :private, import_data: jira_import_data) }
before do
stub_feature_flags(jira_issue_import: false)
end
it_behaves_like 'no jira import access' context 'when project does not have Jira imports' do
end let(:current_user) { user }
context 'when project does not have Jira import data' do
let_it_be(:project) { create(:project, :private, import_data: nil) }
context 'when user cannot read Jira import data' do context 'when user cannot read Jira imports' do
context 'when anonymous user' do context 'when anonymous user' do
it_behaves_like 'no jira import data present' let(:current_user) { nil }
it_behaves_like 'no jira import access'
end end
context 'when user developer' do context 'when user developer' do
...@@ -37,7 +24,7 @@ describe Resolvers::Projects::JiraImportsResolver do ...@@ -37,7 +24,7 @@ describe Resolvers::Projects::JiraImportsResolver do
project.add_developer(user) project.add_developer(user)
end end
it_behaves_like 'no jira import data present' it_behaves_like 'no jira import access'
end end
end end
...@@ -50,11 +37,25 @@ describe Resolvers::Projects::JiraImportsResolver do ...@@ -50,11 +37,25 @@ describe Resolvers::Projects::JiraImportsResolver do
end end
end end
context 'when project has Jira import data' do context 'when project has Jira imports' do
let_it_be(:project) { create(:project, :private, import_data: jira_import_data) } let_it_be(:current_user) { user }
let_it_be(:jira_import1) { create(:jira_import_state, :finished, project: project, jira_project_key: 'AA', created_at: 2.days.ago) }
let_it_be(:jira_import2) { create(:jira_import_state, :finished, project: project, jira_project_key: 'BB', created_at: 5.days.ago) }
context 'when feature flag disabled' do
let(:current_user) { user }
before do
stub_feature_flags(jira_issue_import: false)
end
it_behaves_like 'no jira import access'
end
context 'when user cannot read Jira import data' do context 'when user cannot read Jira imports' do
context 'when anonymous user' do context 'when anonymous user' do
let(:current_user) { nil }
it_behaves_like 'no jira import access' it_behaves_like 'no jira import access'
end end
...@@ -67,22 +68,22 @@ describe Resolvers::Projects::JiraImportsResolver do ...@@ -67,22 +68,22 @@ describe Resolvers::Projects::JiraImportsResolver do
end end
end end
context 'when user can access Jira import data' do context 'when user can access Jira imports' do
before do before do
project.add_maintainer(user) project.add_maintainer(user)
end end
it 'returns Jira imports sorted ascending by scheduledAt time' do it 'returns Jira imports sorted ascending by created_at time' do
imports = resolve_imports imports = resolve_imports
expect(imports.size).to eq 2 expect(imports.size).to eq 2
expect(imports.map(&:key)).to eq %w(BB AA) expect(imports.map(&:jira_project_key)).to eq %w(BB AA)
end end
end end
end end
end end
def resolve_imports(args = {}, context = { current_user: user }) def resolve_imports(args = {}, context = { current_user: current_user })
resolve(described_class, obj: project, args: args, ctx: context) resolve(described_class, obj: project, args: args, ctx: context)
end end
end end
...@@ -37,12 +37,8 @@ describe Gitlab::JiraImport::BaseImporter do ...@@ -37,12 +37,8 @@ describe Gitlab::JiraImport::BaseImporter do
end end
context 'when import data exists' do context 'when import data exists' do
let(:jira_import_data) do let_it_be(:project) { create(:project) }
data = JiraImportData.new let_it_be(:jira_import) { create(:jira_import_state, project: project) }
data << JiraImportData::JiraProjectDetails.new('xx', Time.now.strftime('%Y-%m-%d %H:%M:%S'), { user_id: 1, name: 'root' })
data
end
let(:project) { create(:project, import_data: jira_import_data) }
let(:subject) { described_class.new(project) } let(:subject) { described_class.new(project) }
context 'when #imported_items_cache_key is not implemented' do context 'when #imported_items_cache_key is not implemented' do
......
...@@ -3,14 +3,10 @@ ...@@ -3,14 +3,10 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::JiraImport::IssuesImporter do describe Gitlab::JiraImport::IssuesImporter do
let(:user) { create(:user) } let_it_be(:user) { create(:user) }
let(:jira_import_data) do let_it_be(:project) { create(:project) }
data = JiraImportData.new let_it_be(:jira_import) { create(:jira_import_state, project: project) }
data << JiraImportData::JiraProjectDetails.new('XX', Time.now.strftime('%Y-%m-%d %H:%M:%S'), { user_id: user.id, name: user.name }) let_it_be(:jira_service) { create(:jira_service, project: project) }
data
end
let(:project) { create(:project, import_data: jira_import_data) }
let!(:jira_service) { create(:jira_service, project: project) }
subject { described_class.new(project) } subject { described_class.new(project) }
......
...@@ -3,14 +3,10 @@ ...@@ -3,14 +3,10 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::JiraImport::LabelsImporter do describe Gitlab::JiraImport::LabelsImporter do
let(:user) { create(:user) } let_it_be(:user) { create(:user) }
let(:jira_import_data) do let_it_be(:project) { create(:project) }
data = JiraImportData.new let_it_be(:jira_import) { create(:jira_import_state, project: project) }
data << JiraImportData::JiraProjectDetails.new('XX', Time.now.strftime('%Y-%m-%d %H:%M:%S'), { user_id: user.id, name: user.name }) let_it_be(:jira_service) { create(:jira_service, project: project) }
data
end
let(:project) { create(:project, import_data: jira_import_data) }
let!(:jira_service) { create(:jira_service, project: project) }
subject { described_class.new(project).execute } subject { described_class.new(project).execute }
......
# frozen_string_literal: true
require 'spec_helper'
describe JiraImportData do
let(:symbol_keys_project) do
{ key: 'AA', scheduled_at: 2.days.ago.strftime('%Y-%m-%d %H:%M:%S'), scheduled_by: { 'user_id' => 1, 'name' => 'tester1' } }
end
let(:string_keys_project) do
{ 'key': 'BB', 'scheduled_at': 1.hour.ago.strftime('%Y-%m-%d %H:%M:%S'), 'scheduled_by': { 'user_id': 2, 'name': 'tester2' } }
end
let(:jira_project_details) do
JiraImportData::JiraProjectDetails.new('CC', 1.day.ago.strftime('%Y-%m-%d %H:%M:%S'), { user_id: 3, name: 'tester3' })
end
describe '#projects' do
it 'returns empty array if no data' do
expect(described_class.new.projects).to eq([])
end
it 'returns empty array if no projects' do
import_data = described_class.new(data: { 'some-key' => 10 })
expect(import_data.projects).to eq([])
end
it 'returns JiraProjectDetails sorted by scheduled_at time' do
import_data = described_class.new(data: { jira: { projects: [symbol_keys_project, string_keys_project, jira_project_details] } })
expect(import_data.projects.size).to eq 3
expect(import_data.projects.map(&:key)).to eq(%w(AA CC BB))
expect(import_data.projects.map(&:scheduled_by).map {|e| e['name']}).to eq %w(tester1 tester3 tester2)
expect(import_data.projects.map(&:scheduled_by).map {|e| e['user_id']}).to eq [1, 3, 2]
end
end
describe 'add projects' do
it 'adds project when data is nil' do
import_data = described_class.new
expect(import_data.data).to be nil
import_data << string_keys_project
expect(import_data.data).to eq({ 'jira' => { 'projects' => [string_keys_project] } })
end
it 'adds project when data has some random info' do
import_data = described_class.new(data: { 'one-key': 10 })
expect(import_data.data).to eq({ 'one-key' => 10 })
import_data << string_keys_project
expect(import_data.data).to eq({ 'one-key' => 10, 'jira' => { 'projects' => [string_keys_project] } })
end
it 'adds project when data already has some jira projects' do
import_data = described_class.new(data: { jira: { projects: [symbol_keys_project] } })
expect(import_data.projects.map(&:to_h)).to eq [symbol_keys_project]
import_data << string_keys_project
expect(import_data.data['jira']['projects'].size).to eq 2
expect(import_data.projects.map(&:key)).to eq(%w(AA BB))
expect(import_data.projects.map(&:scheduled_by).map {|e| e['name']}).to eq %w(tester1 tester2)
expect(import_data.projects.map(&:scheduled_by).map {|e| e['user_id']}).to eq [1, 2]
end
end
describe '#force_import!' do
it 'sets force import when data is nil' do
import_data = described_class.new
import_data.force_import!
expect(import_data.data['jira'][JiraImportData::FORCE_IMPORT_KEY]).to be true
expect(import_data.force_import?).to be false
end
it 'sets force import when data is present but no jira key' do
import_data = described_class.new(data: { 'some-key': 'some-data' })
import_data.force_import!
expect(import_data.data['jira'][JiraImportData::FORCE_IMPORT_KEY]).to be true
expect(import_data.data).to eq({ 'some-key' => 'some-data', 'jira' => { JiraImportData::FORCE_IMPORT_KEY => true } })
expect(import_data.force_import?).to be false
end
it 'sets force import when data and jira keys exist' do
import_data = described_class.new(data: { 'some-key': 'some-data', 'jira': {} })
import_data.force_import!
expect(import_data.data['jira'][JiraImportData::FORCE_IMPORT_KEY]).to be true
expect(import_data.data).to eq({ 'some-key' => 'some-data', 'jira' => { JiraImportData::FORCE_IMPORT_KEY => true } })
expect(import_data.force_import?).to be false
end
it 'sets force import when data and jira project data exist' do
import_data = described_class.new(data: { jira: { projects: [symbol_keys_project], JiraImportData::FORCE_IMPORT_KEY => false }, 'some-key': 'some-data' })
import_data.force_import!
expect(import_data.data['jira'][JiraImportData::FORCE_IMPORT_KEY]).to be true
expect(import_data.data).to eq({ 'some-key' => 'some-data', 'jira' => { 'projects' => [symbol_keys_project.deep_stringify_keys!], JiraImportData::FORCE_IMPORT_KEY => true } })
expect(import_data.force_import?).to be true
end
end
describe '#force_import?' do
it 'returns false when data blank' do
expect(described_class.new.force_import?).to be false
end
it 'returns false if there is no project data present' do
import_data = described_class.new(data: { jira: { JiraImportData::FORCE_IMPORT_KEY => true }, 'one-key': 10 })
expect(import_data.force_import?).to be false
end
it 'returns false when force import set to false' do
import_data = described_class.new(data: { jira: { projects: [symbol_keys_project], JiraImportData::FORCE_IMPORT_KEY => false }, 'one-key': 10 })
expect(import_data.force_import?).to be false
end
it 'returns true when force import set to true' do
import_data = described_class.new(data: { jira: { projects: [symbol_keys_project], JiraImportData::FORCE_IMPORT_KEY => true } })
expect(import_data.force_import?).to be true
end
end
end
...@@ -2281,38 +2281,35 @@ describe Project do ...@@ -2281,38 +2281,35 @@ describe Project do
end end
describe '#jira_import_status' do describe '#jira_import_status' do
let(:project) { create(:project, :import_started, import_type: 'jira') } let(:project) { create(:project, import_type: 'jira') }
context 'when import_data is nil' do context 'when no jira imports' do
it 'returns none' do it 'returns none' do
expect(project.import_data).to be nil expect(project.jira_import_status).to eq('initial')
expect(project.jira_import_status).to eq('none')
end end
end end
context 'when import_data is set' do context 'when there are jira imports' do
let(:jira_import_data) { JiraImportData.new } let(:jira_import1) { build(:jira_import_state, :finished, project: project) }
let(:project) { create(:project, :import_started, import_data: jira_import_data, import_type: 'jira') } let(:jira_import2) { build(:jira_import_state, project: project) }
it 'returns none' do before do
expect(project.import_data.becomes(JiraImportData).force_import?).to be false expect(project).to receive(:latest_jira_import).and_return(jira_import2)
expect(project.jira_import_status).to eq('none')
end end
context 'when jira_force_import is true' do context 'when latest import status is initial or jira imports are mising' do
let(:imported_jira_project) do it 'returns initial' do
JiraImportData::JiraProjectDetails.new('xx', Time.now.strftime('%Y-%m-%d %H:%M:%S'), { user_id: 1, name: 'root' }) expect(project.jira_import_status).to eq('initial')
end end
end
context 'when latest import status is scheduled' do
before do before do
jira_import_data = project.import_data.becomes(JiraImportData) jira_import2.schedule!
jira_import_data << imported_jira_project
jira_import_data.force_import!
end end
it 'returns started' do it 'returns scheduled' do
expect(project.import_data.becomes(JiraImportData).force_import?).to be true expect(project.jira_import_status).to eq('scheduled')
expect(project.jira_import_status).to eq('started')
end end
end end
end end
...@@ -2375,52 +2372,46 @@ describe Project do ...@@ -2375,52 +2372,46 @@ describe Project do
context 'jira import' do context 'jira import' do
it 'schedules a jira import job' do it 'schedules a jira import job' do
project = create(:project, import_type: 'jira') project = create(:project, import_type: 'jira')
jira_import = create(:jira_import_state, project: project)
expect(Gitlab::JiraImport::Stage::StartImportWorker).to receive(:perform_async).with(project.id).and_return(import_jid) expect(Gitlab::JiraImport::Stage::StartImportWorker).to receive(:perform_async).with(project.id).and_return(import_jid)
expect(project.add_import_job).to eq(import_jid)
jira_import.schedule!
expect(jira_import.jid).to eq(import_jid)
end end
end end
end end
describe '#jira_import?' do describe '#jira_import?' do
subject(:project) { build(:project, import_type: 'jira') } let_it_be(:project) { build(:project, import_type: 'jira') }
let_it_be(:jira_import) { build(:jira_import_state, project: project) }
it { expect(project.jira_import?).to be true } before do
it { expect(project.import?).to be true } expect(project).to receive(:jira_imports).and_return([jira_import])
end
describe '#jira_force_import?' do
let(:imported_jira_project) do
JiraImportData::JiraProjectDetails.new('xx', Time.now.strftime('%Y-%m-%d %H:%M:%S'), { user_id: 1, name: 'root' })
end
let(:jira_import_data) do
data = JiraImportData.new
data << imported_jira_project
data.force_import!
data
end end
subject(:project) { build(:project, import_type: 'jira', import_data: jira_import_data) } it { expect(project.jira_import?).to be true }
it { expect(project.import?).to be true }
it { expect(project.jira_force_import?).to be true }
end end
describe '#remove_import_data' do describe '#remove_import_data' do
let(:import_data) { ProjectImportData.new(data: { 'test' => 'some data' }) } let_it_be(:import_data) { ProjectImportData.new(data: { 'test' => 'some data' }) }
context 'when jira import' do context 'when jira import' do
let!(:project) { create(:project, import_type: 'jira', import_data: import_data) } let_it_be(:project, reload: true) { create(:project, import_type: 'jira', import_data: import_data) }
let_it_be(:jira_import) { create(:jira_import_state, project: project) }
it 'does not remove import data' do it 'does remove import data' do
expect(project.mirror?).to be false expect(project.mirror?).to be false
expect(project.jira_import?).to be true expect(project.jira_import?).to be true
expect { project.remove_import_data }.not_to change { ProjectImportData.count } expect { project.remove_import_data }.to change { ProjectImportData.count }.by(-1)
end end
end end
context 'when not mirror neither jira import' do context 'when neither a mirror nor a jira import' do
let(:user) { create(:user) } let_it_be(:user) { create(:user) }
let!(:project) { create(:project, import_type: 'github', import_data: import_data) } let_it_be(:project) { create(:project, import_type: 'github', import_data: import_data) }
it 'removes import data' do it 'removes import data' do
expect(project.mirror?).to be false expect(project.mirror?).to be false
......
...@@ -118,9 +118,8 @@ describe 'Starting a Jira Import' do ...@@ -118,9 +118,8 @@ describe 'Starting a Jira Import' do
expect(jira_import['jiraProjectKey']).to eq 'AA' expect(jira_import['jiraProjectKey']).to eq 'AA'
expect(jira_import['scheduledBy']['username']).to eq current_user.username expect(jira_import['scheduledBy']['username']).to eq current_user.username
expect(project.import_state).not_to be nil expect(project.latest_jira_import).not_to be_nil
expect(project.import_state.status).to eq 'scheduled' expect(project.latest_jira_import).to be_scheduled
expect(project.import_data.becomes(JiraImportData).projects.last.scheduled_by['user_id']).to eq current_user.id
end end
end end
end end
......
...@@ -6,19 +6,10 @@ describe 'query jira import data' do ...@@ -6,19 +6,10 @@ describe 'query jira import data' do
include GraphqlHelpers include GraphqlHelpers
let_it_be(:current_user) { create(:user) } let_it_be(:current_user) { create(:user) }
let_it_be(:jira_import_data) do let_it_be(:project) { create(:project, :private, :import_started, import_type: 'jira') }
data = JiraImportData.new let_it_be(:jira_import1) { create(:jira_import_state, :finished, project: project, jira_project_key: 'AA', user: current_user, created_at: 2.days.ago) }
data << JiraImportData::JiraProjectDetails.new( let_it_be(:jira_import2) { create(:jira_import_state, :finished, project: project, jira_project_key: 'BB', user: current_user, created_at: 5.days.ago) }
'AA', 2.days.ago.strftime('%Y-%m-%d %H:%M:%S'),
{ user_id: current_user.id, name: current_user.name }
)
data << JiraImportData::JiraProjectDetails.new(
'BB', 5.days.ago.strftime('%Y-%m-%d %H:%M:%S'),
{ user_id: current_user.id, name: current_user.name }
)
data
end
let_it_be(:project) { create(:project, :private, :import_started, import_data: jira_import_data, import_type: 'jira') }
let(:query) do let(:query) do
%( %(
query { query {
...@@ -48,7 +39,7 @@ describe 'query jira import data' do ...@@ -48,7 +39,7 @@ describe 'query jira import data' do
context 'when anonymous user' do context 'when anonymous user' do
let(:current_user) { nil } let(:current_user) { nil }
it { expect(jira_imports).to be nil } it { expect(jira_imports).to be_nil }
end end
context 'when user developer' do context 'when user developer' do
...@@ -56,7 +47,7 @@ describe 'query jira import data' do ...@@ -56,7 +47,7 @@ describe 'query jira import data' do
project.add_developer(current_user) project.add_developer(current_user)
end end
it { expect(jira_imports).to be nil } it { expect(jira_imports).to be_nil }
end end
end end
...@@ -139,7 +130,7 @@ describe 'query jira import data' do ...@@ -139,7 +130,7 @@ describe 'query jira import data' do
it 'does not return import status' do it 'does not return import status' do
post_graphql(query, current_user: current_user) post_graphql(query, current_user: current_user)
expect(graphql_data['project']).to be nil expect(graphql_data['project']).to be_nil
end end
end end
...@@ -149,12 +140,12 @@ describe 'query jira import data' do ...@@ -149,12 +140,12 @@ describe 'query jira import data' do
end end
context 'when import never ran' do context 'when import never ran' do
let(:project) { create(:project) } let_it_be(:initial_jira_import) { create(:jira_import_state, project: project, jira_project_key: 'BB', user: current_user) }
it 'returns import status' do it 'returns import status' do
post_graphql(query, current_user: current_user) post_graphql(query, current_user: current_user)
expect(jira_import_status).to eq('none') expect(jira_import_status).to eq('initial')
end end
end end
...@@ -166,11 +157,8 @@ describe 'query jira import data' do ...@@ -166,11 +157,8 @@ describe 'query jira import data' do
end end
end end
context 'when import running, i.e. force-import: true' do context 'when import running' do
before do let_it_be(:started_jira_import) { create(:jira_import_state, :started, project: project, jira_project_key: 'BB', user: current_user) }
project.import_data.becomes(JiraImportData).force_import!
project.save!
end
it 'returns import status' do it 'returns import status' do
post_graphql(query, current_user: current_user) post_graphql(query, current_user: current_user)
......
...@@ -4,7 +4,7 @@ require 'spec_helper' ...@@ -4,7 +4,7 @@ require 'spec_helper'
describe JiraImport::StartImportService do describe JiraImport::StartImportService do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let(:project) { create(:project) } let_it_be(:project, reload: true) { create(:project) }
subject { described_class.new(user, project, '').execute } subject { described_class.new(user, project, '').execute }
...@@ -46,10 +46,12 @@ describe JiraImport::StartImportService do ...@@ -46,10 +46,12 @@ describe JiraImport::StartImportService do
end end
context 'when correct data provided' do context 'when correct data provided' do
subject { described_class.new(user, project, 'some-key').execute } let(:fake_key) { 'some-key' }
subject { described_class.new(user, project, fake_key).execute }
context 'when import is already running' do context 'when import is already running' do
let!(:import_state) { create(:import_state, project: project, status: :started) } let_it_be(:jira_import_state) { create(:jira_import_state, :started, project: project) }
it_behaves_like 'responds with error', 'Jira import is already running.' it_behaves_like 'responds with error', 'Jira import is already running.'
end end
...@@ -62,17 +64,16 @@ describe JiraImport::StartImportService do ...@@ -62,17 +64,16 @@ describe JiraImport::StartImportService do
it 'schedules jira import' do it 'schedules jira import' do
subject subject
expect(project.import_state.status).to eq('scheduled') expect(project.latest_jira_import).to be_scheduled
end end
it 'creates jira import data' do it 'creates jira import data' do
subject jira_import = subject.payload[:import_data]
jira_import_data = project.import_data.becomes(JiraImportData) expect(jira_import.jira_project_xid).to eq(0)
expect(jira_import_data.force_import?).to be true expect(jira_import.jira_project_name).to eq(fake_key)
imported_project_data = jira_import_data.projects.last expect(jira_import.jira_project_key).to eq(fake_key)
expect(imported_project_data.key).to eq('some-key') expect(jira_import.user).to eq(user)
expect(imported_project_data.scheduled_by['user_id']).to eq(user.id)
end end
end end
end end
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
shared_examples 'no jira import data present' do shared_examples 'no jira import data present' do
it 'returns none' do it 'returns none' do
expect(resolve_imports).to eq JiraImportData.none expect(resolve_imports).to eq JiraImportState.none
end end
end end
......
...@@ -12,14 +12,23 @@ shared_examples 'include import workers modules' do ...@@ -12,14 +12,23 @@ shared_examples 'include import workers modules' do
end end
end end
shared_examples 'exit import not started' do shared_examples 'does not advance to next stage' do
it 'does nothing, and exits' do it 'does not advance to next stage' do
expect(Gitlab::JiraImport::AdvanceStageWorker).not_to receive(:perform_async) expect(Gitlab::JiraImport::AdvanceStageWorker).not_to receive(:perform_async)
described_class.new.perform(project.id) described_class.new.perform(project.id)
end end
end end
shared_examples 'cannot do jira import' do
it 'does not advance to next stage' do
worker = described_class.new
expect(worker).not_to receive(:import)
worker.perform(project.id)
end
end
shared_examples 'advance to next stage' do |next_stage| shared_examples 'advance to next stage' do |next_stage|
let(:job_waiter) { Gitlab::JobWaiter.new(2, 'some-job-key') } let(:job_waiter) { Gitlab::JobWaiter.new(2, 'some-job-key') }
......
...@@ -5,6 +5,7 @@ require 'spec_helper' ...@@ -5,6 +5,7 @@ require 'spec_helper'
describe Gitlab::JiraImport::ImportIssueWorker do describe Gitlab::JiraImport::ImportIssueWorker do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project) }
let(:some_key) { 'some-key' }
describe 'modules' do describe 'modules' do
it { expect(described_class).to include_module(ApplicationWorker) } it { expect(described_class).to include_module(ApplicationWorker) }
...@@ -23,7 +24,7 @@ describe Gitlab::JiraImport::ImportIssueWorker do ...@@ -23,7 +24,7 @@ describe Gitlab::JiraImport::ImportIssueWorker do
allow(subject).to receive(:insert_and_return_id).and_raise(StandardError) allow(subject).to receive(:insert_and_return_id).and_raise(StandardError)
expect(Gitlab::JobWaiter).to receive(:notify) expect(Gitlab::JobWaiter).to receive(:notify)
subject.perform(project.id, 123, issue_attrs, 'some-key') subject.perform(project.id, 123, issue_attrs, some_key)
end end
it 'record a failed to import issue' do it 'record a failed to import issue' do
...@@ -36,7 +37,7 @@ describe Gitlab::JiraImport::ImportIssueWorker do ...@@ -36,7 +37,7 @@ describe Gitlab::JiraImport::ImportIssueWorker do
context 'when import label does not exist' do context 'when import label does not exist' do
it 'does not record import failure' do it 'does not record import failure' do
subject.perform(project.id, 123, issue_attrs, 'some-key') subject.perform(project.id, 123, issue_attrs, some_key)
expect(label.issues.count).to eq(0) expect(label.issues.count).to eq(0)
expect(Gitlab::Cache::Import::Caching.read(Gitlab::JiraImport.failed_issues_counter_cache_key(project.id)).to_i).to eq(0) expect(Gitlab::Cache::Import::Caching.read(Gitlab::JiraImport.failed_issues_counter_cache_key(project.id)).to_i).to eq(0)
...@@ -49,7 +50,7 @@ describe Gitlab::JiraImport::ImportIssueWorker do ...@@ -49,7 +50,7 @@ describe Gitlab::JiraImport::ImportIssueWorker do
end end
it 'does not record import failure' do it 'does not record import failure' do
subject.perform(project.id, 123, issue_attrs, 'some-key') subject.perform(project.id, 123, issue_attrs, some_key)
expect(label.issues.count).to eq(1) expect(label.issues.count).to eq(1)
expect(Gitlab::Cache::Import::Caching.read(Gitlab::JiraImport.failed_issues_counter_cache_key(project.id)).to_i).to eq(0) expect(Gitlab::Cache::Import::Caching.read(Gitlab::JiraImport.failed_issues_counter_cache_key(project.id)).to_i).to eq(0)
......
...@@ -16,46 +16,29 @@ describe Gitlab::JiraImport::Stage::FinishImportWorker do ...@@ -16,46 +16,29 @@ describe Gitlab::JiraImport::Stage::FinishImportWorker do
stub_feature_flags(jira_issue_import: false) stub_feature_flags(jira_issue_import: false)
end end
it_behaves_like 'exit import not started' it_behaves_like 'cannot do jira import'
end end
context 'when feature flag enabled' do context 'when feature flag enabled' do
let_it_be(:jira_import) { create(:jira_import_state, :scheduled, project: project) }
before do before do
stub_feature_flags(jira_issue_import: true) stub_feature_flags(jira_issue_import: true)
end end
context 'when import did not start' do context 'when import did not start' do
let!(:import_state) { create(:import_state, project: project) } it_behaves_like 'cannot do jira import'
it_behaves_like 'exit import not started'
end end
context 'when import started' do context 'when import started' do
let(:imported_jira_project) do before do
JiraImportData::JiraProjectDetails.new('xx', Time.now.strftime('%Y-%m-%d %H:%M:%S'), { user_id: 1, name: 'root' }) jira_import.start!
end end
let(:jira_import_data) do
data = JiraImportData.new
data << imported_jira_project
data.force_import!
data
end
let(:import_state) { create(:import_state, status: :started) }
let(:project) { create(:project, import_type: 'jira', import_data: jira_import_data, import_state: import_state) }
it 'changes import state to finished' do it 'changes import state to finished' do
worker.perform(project.id) worker.perform(project.id)
expect(project.reload.import_state.status).to eq("finished") expect(project.jira_import_status).to eq('finished')
end
it 'removes force-import flag' do
expect(project.reload.import_data.data['jira'][JiraImportData::FORCE_IMPORT_KEY]).to be true
worker.perform(project.id)
expect(project.reload.import_data.data['jira'][JiraImportData::FORCE_IMPORT_KEY]).to be nil
expect(project.reload.import_data.data['jira']).not_to be nil
end end
end end
end end
......
...@@ -3,34 +3,38 @@ ...@@ -3,34 +3,38 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::JiraImport::Stage::ImportAttachmentsWorker do describe Gitlab::JiraImport::Stage::ImportAttachmentsWorker do
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project, import_type: 'jira') }
describe 'modules' do describe 'modules' do
it_behaves_like 'include import workers modules' it_behaves_like 'include import workers modules'
end end
describe '#perform' do describe '#perform' do
context 'when feature flag enabled' do context 'when feature flag disabled' do
before do before do
stub_feature_flags(jira_issue_import: false) stub_feature_flags(jira_issue_import: false)
end end
it_behaves_like 'exit import not started' it_behaves_like 'cannot do jira import'
it_behaves_like 'does not advance to next stage'
end end
context 'when feature flag enabled' do context 'when feature flag enabled' do
let_it_be(:jira_import) { create(:jira_import_state, :scheduled, project: project) }
before do before do
stub_feature_flags(jira_issue_import: true) stub_feature_flags(jira_issue_import: true)
end end
context 'when import did not start' do context 'when import did not start' do
let!(:import_state) { create(:import_state, project: project) } it_behaves_like 'cannot do jira import'
it_behaves_like 'does not advance to next stage'
it_behaves_like 'exit import not started'
end end
context 'when import started' do context 'when import started' do
let!(:import_state) { create(:import_state, status: :started, project: project) } before do
jira_import.start!
end
it_behaves_like 'advance to next stage', :notes it_behaves_like 'advance to next stage', :notes
end end
......
...@@ -4,43 +4,39 @@ require 'spec_helper' ...@@ -4,43 +4,39 @@ require 'spec_helper'
describe Gitlab::JiraImport::Stage::ImportIssuesWorker do describe Gitlab::JiraImport::Stage::ImportIssuesWorker do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project, import_type: 'jira') }
describe 'modules' do describe 'modules' do
it_behaves_like 'include import workers modules' it_behaves_like 'include import workers modules'
end end
describe '#perform' do describe '#perform' do
context 'when feature flag enabled' do context 'when feature flag disabled' do
before do before do
stub_feature_flags(jira_issue_import: false) stub_feature_flags(jira_issue_import: false)
end end
it_behaves_like 'exit import not started' it_behaves_like 'cannot do jira import'
it_behaves_like 'does not advance to next stage'
end end
context 'when feature flag enabled' do context 'when feature flag enabled' do
let_it_be(:jira_import, reload: true) { create(:jira_import_state, :scheduled, project: project) }
before do before do
stub_feature_flags(jira_issue_import: true) stub_feature_flags(jira_issue_import: true)
end end
context 'when import did not start' do context 'when import did not start' do
let!(:import_state) { create(:import_state, project: project) } it_behaves_like 'cannot do jira import'
it_behaves_like 'does not advance to next stage'
it_behaves_like 'exit import not started'
end end
context 'when import started', :clean_gitlab_redis_cache do context 'when import started', :clean_gitlab_redis_cache do
let(:jira_import_data) do let_it_be(:jira_service) { create(:jira_service, project: project) }
data = JiraImportData.new
data << JiraImportData::JiraProjectDetails.new('XX', Time.now.strftime('%Y-%m-%d %H:%M:%S'), { user_id: user.id, name: user.name })
data
end
let(:project) { create(:project, import_data: jira_import_data) }
let!(:jira_service) { create(:jira_service, project: project) }
let!(:import_state) { create(:import_state, status: :started, project: project) }
before do before do
jira_import.start!
allow_next_instance_of(Gitlab::JiraImport::IssuesImporter) do |instance| allow_next_instance_of(Gitlab::JiraImport::IssuesImporter) do |instance|
allow(instance).to receive(:fetch_issues).and_return([]) allow(instance).to receive(:fetch_issues).and_return([])
end end
......
...@@ -4,41 +4,40 @@ require 'spec_helper' ...@@ -4,41 +4,40 @@ require 'spec_helper'
describe Gitlab::JiraImport::Stage::ImportLabelsWorker do describe Gitlab::JiraImport::Stage::ImportLabelsWorker do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project, import_type: 'jira') }
describe 'modules' do describe 'modules' do
it_behaves_like 'include import workers modules' it_behaves_like 'include import workers modules'
end end
describe '#perform' do describe '#perform' do
context 'when feature flag enabled' do context 'when feature flag disabled' do
before do before do
stub_feature_flags(jira_issue_import: false) stub_feature_flags(jira_issue_import: false)
end end
it_behaves_like 'exit import not started' it_behaves_like 'cannot do jira import'
it_behaves_like 'does not advance to next stage'
end end
context 'when feature flag enabled' do context 'when feature flag enabled' do
let_it_be(:jira_import, reload: true) { create(:jira_import_state, :scheduled, project: project) }
before do before do
stub_feature_flags(jira_issue_import: true) stub_feature_flags(jira_issue_import: true)
end end
context 'when import did not start' do context 'when import did not start' do
let!(:import_state) { create(:import_state, project: project) } it_behaves_like 'cannot do jira import'
it_behaves_like 'does not advance to next stage'
it_behaves_like 'exit import not started'
end end
context 'when import started' do context 'when import started' do
let(:jira_import_data) do
data = JiraImportData.new
data << JiraImportData::JiraProjectDetails.new('XX', Time.now.strftime('%Y-%m-%d %H:%M:%S'), { user_id: user.id, name: user.name })
data
end
let(:project) { create(:project, import_data: jira_import_data) }
let!(:jira_service) { create(:jira_service, project: project) } let!(:jira_service) { create(:jira_service, project: project) }
let!(:import_state) { create(:import_state, status: :started, project: project) }
before do
jira_import.start!
end
it_behaves_like 'advance to next stage', :issues it_behaves_like 'advance to next stage', :issues
......
...@@ -3,34 +3,38 @@ ...@@ -3,34 +3,38 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::JiraImport::Stage::ImportNotesWorker do describe Gitlab::JiraImport::Stage::ImportNotesWorker do
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project, import_type: 'jira') }
describe 'modules' do describe 'modules' do
it_behaves_like 'include import workers modules' it_behaves_like 'include import workers modules'
end end
describe '#perform' do describe '#perform' do
context 'when feature flag enabled' do context 'when feature flag disabled' do
before do before do
stub_feature_flags(jira_issue_import: false) stub_feature_flags(jira_issue_import: false)
end end
it_behaves_like 'exit import not started' it_behaves_like 'cannot do jira import'
it_behaves_like 'does not advance to next stage'
end end
context 'when feature flag enabled' do context 'when feature flag enabled' do
let_it_be(:jira_import) { create(:jira_import_state, :scheduled, project: project) }
before do before do
stub_feature_flags(jira_issue_import: true) stub_feature_flags(jira_issue_import: true)
end end
context 'when import did not start' do context 'when import did not start' do
let!(:import_state) { create(:import_state, project: project) } it_behaves_like 'cannot do jira import'
it_behaves_like 'does not advance to next stage'
it_behaves_like 'exit import not started'
end end
context 'when import started' do context 'when import started' do
let!(:import_state) { create(:import_state, status: :started, project: project) } before do
jira_import.start!
end
it_behaves_like 'advance to next stage', :finish it_behaves_like 'advance to next stage', :finish
end end
......
...@@ -3,16 +3,16 @@ ...@@ -3,16 +3,16 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::JiraImport::Stage::StartImportWorker do describe Gitlab::JiraImport::Stage::StartImportWorker do
let(:project) { create(:project, import_type: 'jira') } let_it_be(:project) { create(:project, import_type: 'jira') }
let_it_be(:jid) { '12345678' }
let(:worker) { described_class.new } let(:worker) { described_class.new }
let(:jid) { '12345678' }
describe 'modules' do describe 'modules' do
it_behaves_like 'include import workers modules' it_behaves_like 'include import workers modules'
end end
describe '#perform' do describe '#perform' do
context 'when feature flag not enabled' do context 'when feature flag not disabled' do
before do before do
stub_feature_flags(jira_issue_import: false) stub_feature_flags(jira_issue_import: false)
end end
...@@ -25,19 +25,13 @@ describe Gitlab::JiraImport::Stage::StartImportWorker do ...@@ -25,19 +25,13 @@ describe Gitlab::JiraImport::Stage::StartImportWorker do
end end
context 'when feature flag enabled' do context 'when feature flag enabled' do
let(:symbol_keys_project) do let_it_be(:jira_import, reload: true) { create(:jira_import_state, project: project, jid: jid) }
{ key: 'AA', scheduled_at: 2.days.ago.strftime('%Y-%m-%d %H:%M:%S'), scheduled_by: { 'user_id' => 1, 'name' => 'tester1' } }
end
let(:import_data) { JiraImportData.new( data: { 'jira' => { JiraImportData::FORCE_IMPORT_KEY => true, projects: [symbol_keys_project] } }) }
before do before do
stub_feature_flags(jira_issue_import: true) stub_feature_flags(jira_issue_import: true)
end end
context 'when import is not scheduled' do context 'when import is not scheduled' do
let(:project) { create(:project, import_type: 'jira') }
let(:import_state) { create(:import_state, project: project, status: :none, jid: jid) }
it 'exits because import not started' do it 'exits because import not started' do
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async) expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async)
...@@ -46,32 +40,21 @@ describe Gitlab::JiraImport::Stage::StartImportWorker do ...@@ -46,32 +40,21 @@ describe Gitlab::JiraImport::Stage::StartImportWorker do
end end
context 'when import is scheduled' do context 'when import is scheduled' do
let(:import_state) { create(:import_state, status: :scheduled, jid: jid) } before do
let(:project) { create(:project, import_type: 'jira', import_state: import_state) } jira_import.schedule!
context 'when this is a mirror sync in a jira imported project' do
it 'exits early' do
expect(Gitlab::Import::SetAsyncJid).not_to receive(:set_jid)
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async)
worker.perform(project.id)
end
end end
context 'when scheduled import is a hard triggered jira import and not a mirror' do it 'advances to importing labels' do
let!(:project) { create(:project, import_type: 'jira', import_data: import_data, import_state: import_state) } expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).to receive(:perform_async)
it 'advances to importing labels' do
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).to receive(:perform_async)
worker.perform(project.id) worker.perform(project.id)
end
end end
end end
context 'when import is started' do context 'when import is started' do
let!(:import_state) { create(:import_state, status: :started, jid: jid) } before do
let!(:project) { create(:project, import_type: 'jira', import_data: import_data, import_state: import_state) } jira_import.update!(status: :started)
end
context 'when this is the same worker that stated import' do context 'when this is the same worker that stated import' do
it 'advances to importing labels' do it 'advances to importing labels' do
...@@ -93,8 +76,9 @@ describe Gitlab::JiraImport::Stage::StartImportWorker do ...@@ -93,8 +76,9 @@ describe Gitlab::JiraImport::Stage::StartImportWorker do
end end
context 'when import is finished' do context 'when import is finished' do
let!(:import_state) { create(:import_state, status: :finished, jid: jid) } before do
let!(:project) { create(:project, import_type: 'jira', import_data: import_data, import_state: import_state) } jira_import.update!(status: :finished)
end
it 'advances to importing labels' do it 'advances to importing labels' do
allow(worker).to receive(:jid).and_return(jid) allow(worker).to receive(:jid).and_return(jid)
......
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