redmine_remotes 0.11.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/project_remote_issues_controller/create.rb +1 -1
- data/app/controllers/project_remote_issues_controller/update.rb +1 -1
- data/app/controllers/remote_trackers_controller.rb +4 -1
- data/app/models/remote_issue.rb +11 -0
- data/app/models/remote_issue_fetch/base.rb +45 -0
- data/app/models/remote_issue_fetch/base/_local_issue.rb +77 -0
- data/app/models/remote_issue_fetch/base/_provider_issue.rb +18 -0
- data/app/models/remote_issue_fetch/base/_remote_issue.rb +19 -0
- data/app/models/remote_issue_fetch/create.rb +44 -0
- data/app/models/remote_issue_fetch/create/_local_issue.rb +21 -0
- data/app/models/remote_issue_fetch/create/_remote_issue.rb +21 -0
- data/app/models/remote_issue_fetch/update.rb +18 -0
- data/app/models/remote_issue_fetch/update/_local_issue.rb +15 -0
- data/app/models/remote_issue_fetch/update/_remote_issue.rb +15 -0
- data/app/models/remote_tracker.rb +7 -1
- data/app/models/remote_tracker/find_issue_local_status.rb +1 -1
- data/app/models/remote_tracker/remote.rb +32 -8
- data/app/models/remote_tracker_fetch.rb +47 -0
- data/app/models/remote_tracker_fetch/provider.rb +13 -0
- data/app/models/remote_tracker_fetch/remote_issues.rb +27 -0
- data/app/models/remote_tracker_fetch/remote_tracker.rb +16 -0
- data/app/models/remote_user/find_local_user.rb +3 -3
- data/config/initializers/001_patches.rb +1 -0
- data/config/locales/en.yml +1 -0
- data/config/locales/pt-BR.yml +1 -0
- data/config/routes.rb +6 -5
- data/db/migrate/20190531171641_create_remote_trackers.rb +1 -1
- data/db/migrate/20190910182842_create_remote_users.rb +1 -1
- data/db/migrate/20190910203552_create_remote_issue_statuses.rb +1 -1
- data/db/migrate/20190912000000_create_remote_issues.rb +1 -1
- data/db/migrate/20200602192120_add_outdated_at_to_remote_issues.rb +7 -0
- data/db/migrate/20200602194753_add_fetched_at_to_remote_issues.rb +7 -0
- data/db/migrate/20200602203020_add_fetched_at_to_remote_trackers.rb +7 -0
- data/lib/redmine_remotes/esosti/entities/issue.rb +40 -1
- data/lib/redmine_remotes/esosti/instance.rb +8 -5
- data/lib/redmine_remotes/jira/entities/issue.rb +6 -2
- data/lib/redmine_remotes/jira/instance.rb +4 -17
- data/lib/redmine_remotes/jobs/fetch_issues.rb +31 -0
- data/lib/redmine_remotes/jobs/fetch_trackers.rb +30 -0
- data/lib/redmine_remotes/patches/avmtrf1_rest_provider_instance.rb +22 -0
- data/lib/redmine_remotes/version.rb +1 -1
- data/lib/tasks/redmine_remotes.rake +16 -11
- metadata +49 -27
- data/app/models/redmine_remotes/tableless/remote_issue_fetch/base.rb +0 -39
- data/app/models/redmine_remotes/tableless/remote_issue_fetch/base/_local_issue.rb +0 -67
- data/app/models/redmine_remotes/tableless/remote_issue_fetch/base/_provider_issue.rb +0 -22
- data/app/models/redmine_remotes/tableless/remote_issue_fetch/create.rb +0 -57
- data/app/models/redmine_remotes/tableless/remote_issue_fetch/create/_local_issue.rb +0 -25
- data/app/models/redmine_remotes/tableless/remote_issue_fetch/create/_remote_issue.rb +0 -32
- data/app/models/redmine_remotes/tableless/remote_issue_fetch/update.rb +0 -30
- data/app/models/redmine_remotes/tableless/remote_issue_fetch/update/_local_issue.rb +0 -19
- data/app/models/redmine_remotes/tableless/remote_issue_fetch/update/_remote_issue.rb +0 -19
- data/lib/redmine_remotes/rest_provider/http_response.rb +0 -31
- data/lib/redmine_remotes/rest_provider/instance.rb +0 -35
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'eac_ruby_utils/core_ext'
|
4
|
+
|
5
|
+
class RemoteTrackerFetch < ::EacRailsUtils::Models::Tableless
|
6
|
+
require_sub __FILE__, include_modules: true, require_dependency: true
|
7
|
+
enable_simple_cache
|
8
|
+
include ::EacRailsUtils::Models::FetchErrors
|
9
|
+
|
10
|
+
attribute :remote_tracker_id, ::Integer
|
11
|
+
belongs_to :remote_tracker, class_name: 'RemoteTracker'
|
12
|
+
|
13
|
+
validates :remote_tracker, presence: true
|
14
|
+
validates :start_time, presence: true
|
15
|
+
validates :end_time, presence: true
|
16
|
+
validate :remote_tracker_fetchable_validation
|
17
|
+
|
18
|
+
def save
|
19
|
+
::Issue.transaction do
|
20
|
+
return false unless valid?
|
21
|
+
return false unless save_remote_issues
|
22
|
+
return false unless save_remote_tracker
|
23
|
+
end
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
def default_error_column
|
28
|
+
:remote_tracker_id
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def end_time_uncached
|
34
|
+
::Time.zone.now
|
35
|
+
end
|
36
|
+
|
37
|
+
def start_time_uncached
|
38
|
+
remote_tracker.try(:fetched_at) || end_time
|
39
|
+
end
|
40
|
+
|
41
|
+
def remote_tracker_fetchable_validation
|
42
|
+
return if remote_tracker.blank?
|
43
|
+
return if remote_tracker.fetchable?
|
44
|
+
|
45
|
+
errors.add(:remote_tracker, "Remote tracker \"#{remote_tracker}\" is not fetchable")
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'eac_ruby_utils/core_ext'
|
4
|
+
|
5
|
+
class RemoteTrackerFetch < ::EacRailsUtils::Models::Tableless
|
6
|
+
module Provider
|
7
|
+
private
|
8
|
+
|
9
|
+
def provider_issues_codes
|
10
|
+
remote_tracker.remote_instance.fetch_issues_changed(start_time, end_time)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'eac_ruby_utils/core_ext'
|
4
|
+
|
5
|
+
class RemoteTrackerFetch < ::EacRailsUtils::Models::Tableless
|
6
|
+
module RemoteIssues
|
7
|
+
private
|
8
|
+
|
9
|
+
def save_remote_issues
|
10
|
+
remote_issues.all? { |remote_issue| save_remote_issue(remote_issue) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def save_remote_issue(remote_issue)
|
14
|
+
return true if remote_issue.update(outdated_at: end_time)
|
15
|
+
|
16
|
+
fetch_record_errors(remote_issue, default_column: default_error_column)
|
17
|
+
false
|
18
|
+
end
|
19
|
+
|
20
|
+
def remote_issues_uncached
|
21
|
+
provider_issues_codes.map do |code|
|
22
|
+
::RemoteIssue.find_by(remote_tracker: remote_tracker,
|
23
|
+
remote_code: ::RemoteIssue.remote_code_sanitize(code))
|
24
|
+
end.reject(&:blank?)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'eac_ruby_utils/core_ext'
|
4
|
+
|
5
|
+
class RemoteTrackerFetch < ::EacRailsUtils::Models::Tableless
|
6
|
+
module RemoteTracker
|
7
|
+
private
|
8
|
+
|
9
|
+
def save_remote_tracker
|
10
|
+
return true if remote_tracker.update(fetched_at: end_time)
|
11
|
+
|
12
|
+
fetch_record_errors(remote_tracker, default_column: default_error_column)
|
13
|
+
false
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -25,7 +25,7 @@ class RemoteUser < ActiveRecord::Base
|
|
25
25
|
|
26
26
|
def result_by_local_user_mail_address
|
27
27
|
condition = ::EmailAddress.arel_table[:address].matches("#{remote_login}@%")
|
28
|
-
::EmailAddress.
|
28
|
+
::EmailAddress.find_by(condition).try(:user)
|
29
29
|
end
|
30
30
|
|
31
31
|
def result_by_register_not_found
|
@@ -47,10 +47,10 @@ class RemoteUser < ActiveRecord::Base
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def remote_tracker_result(remote_tracker)
|
50
|
-
::RemoteUser.
|
50
|
+
::RemoteUser.find_by(
|
51
51
|
remote_tracker: remote_tracker,
|
52
52
|
remote_login: remote_login
|
53
|
-
).
|
53
|
+
).try(:local_user)
|
54
54
|
end
|
55
55
|
|
56
56
|
def remote_trackers_to_search
|
data/config/locales/en.yml
CHANGED
data/config/locales/pt-BR.yml
CHANGED
data/config/routes.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RedmineApp::Application.routes.draw do
|
4
|
+
concern :active_scaffold, ActiveScaffold::Routing::Basic.new(association: true)
|
4
5
|
get '/projects/:id/remotes', to: 'project_remote_issues#index'
|
5
6
|
get '/projects/:id/tracker/:tracker_id/new_issue', to: 'project_remote_issues#new',
|
6
7
|
as: 'new_project_remote_issue'
|
@@ -9,9 +10,9 @@ RedmineApp::Application.routes.draw do
|
|
9
10
|
put '/projects/:id/remote_issue/:remote_issue_id/update', to: 'project_remote_issues#update',
|
10
11
|
as: 'update_project_remote_issue'
|
11
12
|
resources(:project_remote_issues, only: [:index])
|
12
|
-
resources(:remote_trackers
|
13
|
-
resources(:remote_tracker_settings
|
14
|
-
resources(:remote_issues
|
15
|
-
resources(:remote_issue_statuses
|
16
|
-
resources(:remote_users
|
13
|
+
resources(:remote_trackers, concerns: :active_scaffold)
|
14
|
+
resources(:remote_tracker_settings, concerns: :active_scaffold)
|
15
|
+
resources(:remote_issues, concerns: :active_scaffold)
|
16
|
+
resources(:remote_issue_statuses, concerns: :active_scaffold)
|
17
|
+
resources(:remote_users, concerns: :active_scaffold)
|
17
18
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
class CreateRemoteUsers < ActiveRecord::Migration
|
4
4
|
def change
|
5
|
-
create_table :remote_users do |t|
|
5
|
+
create_table :remote_users do |t| # rubocop:disable Rails/CreateTableWithTimestamps
|
6
6
|
t.references :remote_tracker, index: true
|
7
7
|
t.string :remote_login
|
8
8
|
t.references :local_user, index: true
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
class CreateRemoteIssueStatuses < ActiveRecord::Migration
|
4
4
|
def change
|
5
|
-
create_table :remote_issue_statuses do |t|
|
5
|
+
create_table :remote_issue_statuses do |t| # rubocop:disable Rails/CreateTableWithTimestamps
|
6
6
|
t.references :remote_tracker, index: true
|
7
7
|
t.references :local_tracker, index: true
|
8
8
|
t.string :remote_name
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
class CreateRemoteIssues < ActiveRecord::Migration
|
4
4
|
def change
|
5
|
-
create_table :remote_issues do |t|
|
5
|
+
create_table :remote_issues do |t| # rubocop:disable Rails/CreateTableWithTimestamps
|
6
6
|
t.references :remote_tracker, index: true
|
7
7
|
t.references :local_issue, index: true, nullable: true
|
8
8
|
t.string :remote_code
|
@@ -6,8 +6,19 @@ module RedmineRemotes
|
|
6
6
|
module Esosti
|
7
7
|
module Entities
|
8
8
|
class Issue < ::Avmtrf1::Esosti::Entities::Issue
|
9
|
+
EXTRA_DESCRIPTION_BEFORE = { reported_by: 'Relatado por', affected_person: 'Pessoa afetada',
|
10
|
+
type_description: 'Tipo de solicitação' }.freeze
|
11
|
+
|
12
|
+
def human_view_url
|
13
|
+
instance.issue_human_view_url(uid)
|
14
|
+
end
|
15
|
+
|
9
16
|
def author_login
|
10
|
-
attributes.fetch('CREATEDBY')
|
17
|
+
mail_local_part(attributes.fetch('CREATEDBY'))
|
18
|
+
end
|
19
|
+
|
20
|
+
def affected_person
|
21
|
+
mail_local_part(attributes.fetch('AFFECTEDPERSON'))
|
11
22
|
end
|
12
23
|
|
13
24
|
def attributes
|
@@ -28,17 +39,45 @@ module RedmineRemotes
|
|
28
39
|
)
|
29
40
|
end
|
30
41
|
|
42
|
+
def extra_description_before
|
43
|
+
{
|
44
|
+
'Relatado por' => "user:#{reported_by}",
|
45
|
+
'Pessoa afetada' => "user:#{affected_person}",
|
46
|
+
'Tipo de solicitação' => type_description
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
31
50
|
def related_mbos
|
32
51
|
data.first.fetch('RelatedMbos')
|
33
52
|
end
|
34
53
|
|
54
|
+
def reported_by
|
55
|
+
mail_local_part(attributes.fetch('REPORTEDBY'))
|
56
|
+
end
|
57
|
+
|
35
58
|
def status_name
|
36
59
|
attributes.fetch('STATUS')
|
37
60
|
end
|
38
61
|
|
39
62
|
def subject
|
63
|
+
description.gsub(/\s+/, ' ')
|
64
|
+
end
|
65
|
+
|
66
|
+
def type_description
|
40
67
|
attributes.fetch('DESCRIPTION')
|
41
68
|
end
|
69
|
+
|
70
|
+
def uid
|
71
|
+
attributes.fetch('TICKETUID').fetch('content')
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def mail_local_part(mail_address)
|
77
|
+
mail_address.if_present do |v|
|
78
|
+
/\A([^@]+)@/.if_match(v, false) { |m| m[1].downcase }.if_present(mail_address)
|
79
|
+
end
|
80
|
+
end
|
42
81
|
end
|
43
82
|
end
|
44
83
|
end
|
@@ -1,8 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'avmtrf1/esosti/instance'
|
4
|
+
require 'avmtrf1/esosti/raw_data_sanitizer'
|
5
|
+
|
3
6
|
module RedmineRemotes
|
4
7
|
module Esosti
|
5
|
-
class Instance < ::
|
8
|
+
class Instance < ::Avmtrf1::Esosti::Instance
|
6
9
|
ISSUE_ID_PATTERN = /\A(?:ss|in)[0-9]+\z/i.freeze
|
7
10
|
|
8
11
|
class << self
|
@@ -14,12 +17,12 @@ module RedmineRemotes
|
|
14
17
|
end
|
15
18
|
end
|
16
19
|
|
17
|
-
def
|
18
|
-
"#{root_url}/
|
20
|
+
def issue_human_view_url(ticket_uid)
|
21
|
+
"#{root_url}/itsm/ui/?event=loadapp&value=ms_sr&uniqueid=#{ticket_uid}"
|
19
22
|
end
|
20
23
|
|
21
|
-
def
|
22
|
-
|
24
|
+
def fetch_issues_changed(start_time, _end_time)
|
25
|
+
changed(start_time)
|
23
26
|
end
|
24
27
|
end
|
25
28
|
end
|
@@ -1,11 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'avmtrf1/
|
3
|
+
require 'avmtrf1/jira/entities/issue'
|
4
4
|
|
5
5
|
module RedmineRemotes
|
6
6
|
module Jira
|
7
7
|
module Entities
|
8
|
-
class Issue < ::Avmtrf1::
|
8
|
+
class Issue < ::Avmtrf1::Jira::Entities::Issue
|
9
|
+
def human_view_url
|
10
|
+
instance.issue_human_view_url(code)
|
11
|
+
end
|
12
|
+
|
9
13
|
def code
|
10
14
|
data.fetch('key')
|
11
15
|
end
|
@@ -1,33 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'eac_ruby_utils/core_ext'
|
4
|
+
require 'avmtrf1/jira/instance'
|
4
5
|
|
5
6
|
module RedmineRemotes
|
6
7
|
module Jira
|
7
|
-
class Instance < ::
|
8
|
-
ISSUE_ID_PATTERN = /\A([a-z][a-z0-9]+)\-(\d+)\z/i.freeze
|
8
|
+
class Instance < ::Avmtrf1::Jira::Instance
|
9
9
|
DEFAULT_DESCRIPTION_FIELD = 'description'
|
10
10
|
|
11
|
-
class << self
|
12
|
-
def parse_issue_id(global_issue_id)
|
13
|
-
m = ISSUE_ID_PATTERN.match(global_issue_id)
|
14
|
-
return nil unless m
|
15
|
-
|
16
|
-
::OpenStruct.new(provider_issue_id: m[0], project_id: m[1], project_issue_id: m[2])
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def build_service_url(service_url_suffix)
|
21
|
-
"#{root_url}/rest/api/latest#{service_url_suffix}"
|
22
|
-
end
|
23
|
-
|
24
11
|
def description_field
|
25
12
|
remote_tracker.setting_value(::RemoteTrackerSetting::NAME_FIELD_DESCRIPTION)
|
26
13
|
.if_present(DEFAULT_DESCRIPTION_FIELD)
|
27
14
|
end
|
28
15
|
|
29
|
-
def
|
30
|
-
"/
|
16
|
+
def issue_human_view_url(issue_code)
|
17
|
+
"#{root_url}/browse/#{issue_code.to_s.upcase}"
|
31
18
|
end
|
32
19
|
end
|
33
20
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RedmineRemotes
|
4
|
+
module Jobs
|
5
|
+
class FetchIssues
|
6
|
+
enable_simple_cache
|
7
|
+
|
8
|
+
def run
|
9
|
+
::Rails.logger.info("Issues to fetch: #{issues_to_fetch.count}")
|
10
|
+
issues_to_fetch.each { |issue| fetch_issue(issue) }
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def issues_to_fetch_uncached
|
16
|
+
::RemoteIssue.outdated
|
17
|
+
end
|
18
|
+
|
19
|
+
def fetch_issue(remote_issue)
|
20
|
+
::Rails.logger.info 'Fetching remote issue ' \
|
21
|
+
"\"#{remote_issue}|\##{remote_issue.local_issue.id}\""
|
22
|
+
record = ::RemoteIssueFetch::Update.new(
|
23
|
+
remote_issue: remote_issue
|
24
|
+
)
|
25
|
+
return if record.save
|
26
|
+
|
27
|
+
::Rails.logger.warn "Fetch failed with errors: #{record.errors.messages}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RedmineRemotes
|
4
|
+
module Jobs
|
5
|
+
class FetchTrackers
|
6
|
+
enable_simple_cache
|
7
|
+
|
8
|
+
def run
|
9
|
+
::Rails.logger.info("Trackers to fetch: #{trackers_to_fetch.count}")
|
10
|
+
trackers_to_fetch.each { |tracker| fetch_tracker(tracker) }
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def fetch_tracker(remote_tracker)
|
16
|
+
::Rails.logger.info "Fetch remote tracker \"#{remote_tracker}\"..."
|
17
|
+
record = ::RemoteTrackerFetch.new(
|
18
|
+
remote_tracker: remote_tracker
|
19
|
+
)
|
20
|
+
return if record.save
|
21
|
+
|
22
|
+
::Rails.logger.warn "Fetched failed with errors: #{record.errors.messages}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def trackers_to_fetch_uncached
|
26
|
+
::RemoteTracker.where(profile: ::RemoteTracker::PROFILE_ESOSTI)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|