Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
8952f285
Commit
8952f285
authored
Apr 02, 2020
by
Alexandru Croitor
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Track jira import state in its own data structure
Add JiraImportState model to track jira imports.
parent
80d68a7b
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
334 additions
and
0 deletions
+334
-0
app/models/jira_import_state.rb
app/models/jira_import_state.rb
+79
-0
app/models/project.rb
app/models/project.rb
+5
-0
locale/gitlab.pot
locale/gitlab.pot
+3
-0
spec/factories/jira_import_states.rb
spec/factories/jira_import_states.rb
+28
-0
spec/lib/gitlab/import_export/all_models.yml
spec/lib/gitlab/import_export/all_models.yml
+1
-0
spec/models/jira_import_state_spec.rb
spec/models/jira_import_state_spec.rb
+149
-0
spec/models/project_spec.rb
spec/models/project_spec.rb
+29
-0
spec/support/shared_examples/models/jira_import_state_shared_examples.rb
...ared_examples/models/jira_import_state_shared_examples.rb
+40
-0
No files found.
app/models/jira_import_state.rb
0 → 100644
View file @
8952f285
# frozen_string_literal: true
class
JiraImportState
<
ApplicationRecord
include
AfterCommitQueue
self
.
table_name
=
'jira_imports'
STATUSES
=
{
initial:
0
,
scheduled:
1
,
started:
2
,
failed:
3
,
finished:
4
}.
freeze
belongs_to
:project
belongs_to
:user
belongs_to
:label
validates
:project
,
presence:
true
validates
:jira_project_key
,
presence:
true
validates
:jira_project_name
,
presence:
true
validates
:jira_project_xid
,
presence:
true
validates
:project
,
uniqueness:
{
conditions:
->
{
where
.
not
(
status:
STATUSES
.
values_at
(
:failed
,
:finished
))
},
message:
_
(
'Cannot have multiple Jira imports running at the same time'
)
}
state_machine
:status
,
initial: :initial
do
event
:schedule
do
transition
initial: :scheduled
end
event
:start
do
transition
scheduled: :started
end
event
:finish
do
transition
started: :finished
end
event
:do_fail
do
transition
[
:initial
,
:scheduled
,
:started
]
=>
:failed
end
after_transition
initial: :scheduled
do
|
state
,
_
|
state
.
run_after_commit
do
job_id
=
Gitlab
::
JiraImport
::
Stage
::
StartImportWorker
.
perform_async
(
project
.
id
)
state
.
update
(
jid:
job_id
)
if
job_id
end
end
after_transition
any
=>
:finished
do
|
state
,
_
|
if
state
.
jid
.
present?
Gitlab
::
SidekiqStatus
.
unset
(
state
.
jid
)
state
.
update_column
(
:jid
,
nil
)
end
end
# Supress warning:
# both JiraImportState and its :status machine have defined a different default for "status".
# although both have same value but represented in 2 ways: integer(0) and symbol(:initial)
def
owner_class_attribute_default
'initial'
end
end
enum
status:
STATUSES
def
in_progress?
scheduled?
||
started?
end
def
refresh_jid_expiration
return
unless
jid
Gitlab
::
SidekiqStatus
.
set
(
jid
,
StuckImportJobsWorker
::
IMPORT_JOBS_EXPIRATION
)
end
def
self
.
jid_by
(
project_id
:,
status
:)
select
(
:jid
).
with_status
(
status
).
find_by
(
project_id:
project_id
)
end
end
app/models/project.rb
View file @
8952f285
...
...
@@ -314,6 +314,7 @@ class Project < ApplicationRecord
has_one
:pages_metadatum
,
class_name:
'ProjectPagesMetadatum'
,
inverse_of: :project
has_many
:import_failures
,
inverse_of: :project
has_many
:jira_imports
,
->
{
order
'jira_imports.created_at'
},
class_name:
'JiraImportState'
,
inverse_of: :project
has_many
:daily_report_results
,
class_name:
'Ci::DailyReportResult'
...
...
@@ -2424,6 +2425,10 @@ class Project < ApplicationRecord
environments
.
where
(
"name LIKE (
#{
::
Gitlab
::
SQL
::
Glob
.
to_like
(
quoted_scope
)
}
)"
)
# rubocop:disable GitlabSecurity/SqlInjection
end
def
latest_jira_import
jira_imports
.
last
end
private
def
find_service
(
services
,
name
)
...
...
locale/gitlab.pot
View file @
8952f285
...
...
@@ -3353,6 +3353,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
msgid "Cannot make epic confidential if it contains not-confidential issues"
msgstr ""
...
...
spec/factories/jira_import_states.rb
0 → 100644
View file @
8952f285
# frozen_string_literal: true
FactoryBot
.
define
do
factory
:jira_import_state
do
project
user
{
project
&
.
creator
}
label
jira_project_name
{
generate
(
:name
)
}
jira_project_key
{
generate
(
:name
)
}
jira_project_xid
{
1234
}
end
trait
:scheduled
do
status
{
:scheduled
}
end
trait
:started
do
status
{
:started
}
end
trait
:failed
do
status
{
:failed
}
end
trait
:finished
do
status
{
:finished
}
end
end
spec/lib/gitlab/import_export/all_models.yml
View file @
8952f285
...
...
@@ -476,6 +476,7 @@ project:
-
requirements
-
export_jobs
-
daily_report_results
-
jira_imports
award_emoji
:
-
awardable
-
user
...
...
spec/models/jira_import_state_spec.rb
0 → 100644
View file @
8952f285
# frozen_string_literal: true
require
'spec_helper'
describe
JiraImportState
do
describe
"associations"
do
it
{
is_expected
.
to
belong_to
(
:project
)
}
it
{
is_expected
.
to
belong_to
(
:user
)
}
it
{
is_expected
.
to
belong_to
(
:label
)
}
end
describe
'modules'
do
subject
{
described_class
}
it
{
is_expected
.
to
include_module
(
AfterCommitQueue
)
}
end
describe
'validations'
do
it
{
is_expected
.
to
validate_presence_of
(
:project
)
}
it
{
is_expected
.
to
validate_presence_of
(
:jira_project_key
)
}
it
{
is_expected
.
to
validate_presence_of
(
:jira_project_name
)
}
it
{
is_expected
.
to
validate_presence_of
(
:jira_project_xid
)
}
context
'when trying to run multiple imports'
do
let
(
:project
)
{
create
(
:project
)
}
context
'when project has an initial jira_import'
do
let!
(
:jira_import
)
{
create
(
:jira_import_state
,
project:
project
)}
it_behaves_like
'multiple running imports not allowed'
end
context
'when project has a scheduled jira_import'
do
let!
(
:jira_import
)
{
create
(
:jira_import_state
,
:scheduled
,
project:
project
)}
it_behaves_like
'multiple running imports not allowed'
end
context
'when project has a started jira_import'
do
let!
(
:jira_import
)
{
create
(
:jira_import_state
,
:started
,
project:
project
)}
it_behaves_like
'multiple running imports not allowed'
end
context
'when project has a failed jira_import'
do
let!
(
:jira_import
)
{
create
(
:jira_import_state
,
:failed
,
project:
project
)}
it
'returns valid'
do
new_import
=
build
(
:jira_import_state
,
project:
project
)
expect
(
new_import
).
to
be_valid
expect
(
new_import
.
errors
[
:project
]).
to
be_empty
end
end
context
'when project has a finished jira_import'
do
let!
(
:jira_import
)
{
create
(
:jira_import_state
,
:finished
,
project:
project
)}
it
'returns valid'
do
new_import
=
build
(
:jira_import_state
,
project:
project
)
expect
(
new_import
).
to
be_valid
expect
(
new_import
.
errors
[
:project
]).
to
be_empty
end
end
end
end
describe
'#in_progress?'
do
context
'statuses that return in progress'
do
it_behaves_like
'in progress'
,
:scheduled
it_behaves_like
'in progress'
,
:started
end
context
'statuses that return not in progress'
do
it_behaves_like
'not in progress'
,
:initial
it_behaves_like
'not in progress'
,
:failed
it_behaves_like
'not in progress'
,
:finished
end
end
describe
'states transition flow'
do
let
(
:project
)
{
create
(
:project
)
}
context
'when jira import is in initial state'
do
let!
(
:jira_import
)
{
build
(
:jira_import_state
,
project:
project
)}
it_behaves_like
'can transition'
,
[
:schedule
,
:do_fail
]
it_behaves_like
'cannot transition'
,
[
:start
,
:finish
]
end
context
'when jira import is in scheduled state'
do
let!
(
:jira_import
)
{
build
(
:jira_import_state
,
:scheduled
,
project:
project
)}
it_behaves_like
'can transition'
,
[
:start
,
:do_fail
]
it_behaves_like
'cannot transition'
,
[
:finish
]
end
context
'when jira import is in started state'
do
let!
(
:jira_import
)
{
build
(
:jira_import_state
,
:started
,
project:
project
)}
it_behaves_like
'can transition'
,
[
:finish
,
:do_fail
]
it_behaves_like
'cannot transition'
,
[
:schedule
]
end
context
'when jira import is in failed state'
do
let!
(
:jira_import
)
{
build
(
:jira_import_state
,
:failed
,
project:
project
)}
it_behaves_like
'cannot transition'
,
[
:schedule
,
:finish
,
:do_fail
]
end
context
'when jira import is in finished state'
do
let!
(
:jira_import
)
{
build
(
:jira_import_state
,
:finished
,
project:
project
)}
it_behaves_like
'cannot transition'
,
[
:schedule
,
:do_fail
,
:start
]
end
context
'after transition to scheduled'
do
let!
(
:jira_import
)
{
build
(
:jira_import_state
,
project:
project
)}
it
'triggers the import job'
do
expect
(
Gitlab
::
JiraImport
::
Stage
::
StartImportWorker
).
to
receive
(
:perform_async
).
and_return
(
'some-job-id'
)
jira_import
.
schedule
expect
(
jira_import
.
jid
).
to
eq
(
'some-job-id'
)
end
end
context
'after transition to finished'
do
let!
(
:jira_import
)
{
build
(
:jira_import_state
,
:started
,
jid:
'some-other-jid'
,
project:
project
)}
it
'triggers the import job'
do
jira_import
.
finish
expect
(
jira_import
.
jid
).
to
be_nil
end
it
'triggers the import job'
do
jira_import
.
update!
(
status: :scheduled
)
jira_import
.
finish
expect
(
jira_import
.
status
).
to
eq
(
'scheduled'
)
expect
(
jira_import
.
jid
).
to
eq
(
'some-other-jid'
)
end
end
end
end
spec/models/project_spec.rb
View file @
8952f285
...
...
@@ -110,6 +110,7 @@ describe Project do
it
{
is_expected
.
to
have_many
(
:source_pipelines
)
}
it
{
is_expected
.
to
have_many
(
:prometheus_alert_events
)
}
it
{
is_expected
.
to
have_many
(
:self_managed_prometheus_alert_events
)
}
it
{
is_expected
.
to
have_many
(
:jira_imports
)
}
it_behaves_like
'model with repository'
do
let_it_be
(
:container
)
{
create
(
:project
,
:repository
,
path:
'somewhere'
)
}
...
...
@@ -5987,6 +5988,34 @@ describe Project do
end
end
describe
'#latest_jira_import'
do
let_it_be
(
:project
)
{
create
(
:project
)
}
context
'when no jira imports'
do
it
'returns nil'
do
expect
(
project
.
latest_jira_import
).
to
be
nil
end
end
context
'when single jira import'
do
let!
(
:jira_import1
)
{
create
(
:jira_import_state
,
project:
project
)
}
it
'returns the jira import'
do
expect
(
project
.
latest_jira_import
).
to
eq
(
jira_import1
)
end
end
context
'when multiple jira imports'
do
let!
(
:jira_import1
)
{
create
(
:jira_import_state
,
:finished
,
created_at:
1
.
day
.
ago
,
project:
project
)
}
let!
(
:jira_import2
)
{
create
(
:jira_import_state
,
:failed
,
created_at:
2
.
days
.
ago
,
project:
project
)
}
let!
(
:jira_import3
)
{
create
(
:jira_import_state
,
:started
,
created_at:
3
.
days
.
ago
,
project:
project
)
}
it
'returns latest jira import by created_at'
do
expect
(
project
.
jira_imports
.
pluck
(
:id
)).
to
eq
([
jira_import3
.
id
,
jira_import2
.
id
,
jira_import1
.
id
])
expect
(
project
.
latest_jira_import
).
to
eq
(
jira_import1
)
end
end
end
def
finish_job
(
export_job
)
export_job
.
start
export_job
.
finish
...
...
spec/support/shared_examples/models/jira_import_state_shared_examples.rb
0 → 100644
View file @
8952f285
# frozen_string_literal: true
shared_examples
'multiple running imports not allowed'
do
it
'returns not valid'
do
new_import
=
build
(
:jira_import_state
,
project:
project
)
expect
(
new_import
).
not_to
be_valid
expect
(
new_import
.
errors
[
:project
]).
not_to
be_nil
end
end
shared_examples
'in progress'
do
|
status
|
it
'returns true'
do
jira_import_state
=
build
(
:jira_import_state
,
status:
status
)
expect
(
jira_import_state
).
to
be_in_progress
end
end
shared_examples
'not in progress'
do
|
status
|
it
'returns false'
do
jira_import_state
=
build
(
:jira_import_state
,
status:
status
)
expect
(
jira_import_state
).
not_to
be_in_progress
end
end
shared_examples
'can transition'
do
|
states
|
states
.
each
do
|
state
|
it
'returns true'
do
expect
(
jira_import
.
send
(
state
)).
to
be
true
end
end
end
shared_examples
'cannot transition'
do
|
states
|
states
.
each
do
|
state
|
it
'returns false'
do
expect
(
jira_import
.
send
(
state
)).
to
be
false
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment