redmine_remotes 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/project_remote_issues_controller.rb +44 -0
- data/app/controllers/remote_issues_controller.rb +14 -0
- data/app/models/redmine_remotes/tableless/add_remote_issue/_local_issue.rb +57 -0
- data/app/models/redmine_remotes/tableless/add_remote_issue/_provider_issue.rb +19 -0
- data/app/models/redmine_remotes/tableless/add_remote_issue/_remote_issue.rb +27 -0
- data/app/models/redmine_remotes/tableless/add_remote_issue.rb +65 -0
- data/app/models/remote_issue.rb +17 -0
- data/app/models/remote_tracker/_jira.rb +11 -0
- data/app/models/remote_tracker.rb +12 -1
- data/app/models/remote_user.rb +4 -2
- data/app/views/project_remote_issues/_trackers.html.erb +30 -0
- data/app/views/project_remote_issues/index.html.erb +2 -0
- data/app/views/project_remote_issues/new.html.erb +12 -0
- data/config/initializers/001_patches.rb +1 -0
- data/config/initializers/nonproject_modules.rb +6 -0
- data/config/locales/en.yml +6 -2
- data/config/locales/pt-BR.yml +6 -2
- data/config/routes.rb +7 -0
- data/db/migrate/20190912000000_create_remote_issues.rb +13 -0
- data/init.rb +10 -0
- data/lib/redmine_remotes/jira/entities/issue.rb +37 -0
- data/lib/redmine_remotes/jira/instance.rb +26 -0
- data/lib/redmine_remotes/patches/issue.rb +20 -0
- data/lib/redmine_remotes/rest_provider/entity.rb +18 -0
- data/lib/redmine_remotes/rest_provider/http_response.rb +31 -0
- data/lib/redmine_remotes/rest_provider/instance.rb +53 -0
- data/lib/redmine_remotes/version.rb +1 -1
- data/lib/tasks/redmine_remotes.rake +24 -0
- metadata +74 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9520f14afbdb893e412eb0147142ac2ceee118152436f62a8a2d2e9a6b0b48dd
|
4
|
+
data.tar.gz: f388fd2ae10c72cec289ad779a994fd099748e991878e275bba9b2ed645adedc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d86ac7fb4ba1d2a0c687770f453645ee2738acc6c8110df8f5b85ea716c0ce53cfa744517a130e779183f666cdc2d4263215e229b1305828bddae1b895708c04
|
7
|
+
data.tar.gz: 2477b10e006b1240faa0ddf2374def403e65878686a74f54fc1744e7df08327da7ed541cd1f49d7bd939a9e810f2b29964bfcbabdaed45c8119a8019da3bd868
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ProjectRemoteIssuesController < ApplicationController
|
4
|
+
before_action :find_project
|
5
|
+
before_action :find_remote_tracker, only: %i[create new]
|
6
|
+
|
7
|
+
def index
|
8
|
+
@trackers = ::RemoteTracker.order(profile: :asc, root_url: :asc, username: :asc)
|
9
|
+
end
|
10
|
+
|
11
|
+
def new
|
12
|
+
@add_issue = model_class.new(context_params)
|
13
|
+
end
|
14
|
+
|
15
|
+
def create
|
16
|
+
@add_issue = model_class.new(create_params)
|
17
|
+
if @add_issue.save
|
18
|
+
flash[:notice] = "Demanda salva: \##{@add_issue.local_issue.id}"
|
19
|
+
redirect_to url_for(action: 'index', id: @project.identifier, tracker_id: @remote_tracker.id)
|
20
|
+
else
|
21
|
+
render 'new'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def model_class
|
28
|
+
::RedmineRemotes::Tableless::AddRemoteIssue
|
29
|
+
end
|
30
|
+
|
31
|
+
def context_params
|
32
|
+
{ project_id: @project.id, remote_tracker_id: @remote_tracker.id }
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_params
|
36
|
+
params.fetch(model_class.model_name.param_key).permit(
|
37
|
+
:issue_remote_code, :local_tracker_id
|
38
|
+
).merge(context_params)
|
39
|
+
end
|
40
|
+
|
41
|
+
def find_remote_tracker
|
42
|
+
@remote_tracker = ::RemoteTracker.find(params[:tracker_id])
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class RemoteIssuesController < ApplicationController
|
4
|
+
READ_PERMISSION = 'remote_issue.read'
|
5
|
+
WRITE_PERMISSION = 'remote_issue.write'
|
6
|
+
PERMISSIONS = READ_PERMISSION
|
7
|
+
|
8
|
+
layout 'nonproject_modules'
|
9
|
+
require_permission PERMISSIONS
|
10
|
+
|
11
|
+
active_scaffold :remote_issue do |conf|
|
12
|
+
conf.columns[:tracker].form_ui = :select
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RedmineRemotes
|
4
|
+
module Tableless
|
5
|
+
class AddRemoteIssue < ::EacRailsUtils::TablelessModel
|
6
|
+
private
|
7
|
+
|
8
|
+
def create_local_issue
|
9
|
+
return true if local_issue.save
|
10
|
+
|
11
|
+
fetch_record_errors(local_issue, default_column: :issue_remote_code)
|
12
|
+
false
|
13
|
+
end
|
14
|
+
|
15
|
+
def local_issue_uncached
|
16
|
+
::Issue.new(
|
17
|
+
subject: local_issue_subject, project: project, tracker: local_tracker,
|
18
|
+
priority: local_issue_priority, author: local_issue_author, status: local_issue_status,
|
19
|
+
created_on: provider_issue.created_on, updated_on: provider_issue.updated_on
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def local_issue_priority
|
24
|
+
::IssuePriority.default
|
25
|
+
end
|
26
|
+
|
27
|
+
def local_issue_subject
|
28
|
+
"[#{provider_issue.code}] #{provider_issue.subject}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def local_issue_author_uncached
|
32
|
+
return nil if provider_issue.blank?
|
33
|
+
|
34
|
+
::RemoteUser.find_local_user(
|
35
|
+
provider_issue.author_login,
|
36
|
+
remote_tracker
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def local_issue_status
|
41
|
+
local_issue_status_from_remote_tracker || local_issue_status_from_local_tracker
|
42
|
+
end
|
43
|
+
|
44
|
+
def local_issue_status_from_remote_tracker
|
45
|
+
::RemoteIssueStatus.find_local_issue_status(
|
46
|
+
provider_issue.status_name,
|
47
|
+
remote_tracker,
|
48
|
+
local_tracker
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def local_issue_status_from_local_tracker
|
53
|
+
local_tracker.default_status
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RedmineRemotes
|
4
|
+
module Tableless
|
5
|
+
class AddRemoteIssue < ::EacRailsUtils::TablelessModel
|
6
|
+
private
|
7
|
+
|
8
|
+
def provider_issue_uncached
|
9
|
+
return nil unless remote_tracker.present? && issue_remote_code.present?
|
10
|
+
|
11
|
+
remote_tracker.find_remote_issue(issue_remote_code)
|
12
|
+
rescue ::RedmineRemotes::RestProvider::HttpResponse => e
|
13
|
+
errors.add(:issue_remote_code, "Requisição a \"#{e.url}\" retornou com status #{e.status}")
|
14
|
+
puts "====> #{e.body}"
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RedmineRemotes
|
4
|
+
module Tableless
|
5
|
+
class AddRemoteIssue < ::EacRailsUtils::TablelessModel
|
6
|
+
private
|
7
|
+
|
8
|
+
def create_remote_issue
|
9
|
+
return true if remote_issue.save
|
10
|
+
|
11
|
+
fetch_record_errors(remote_issue, default_column: :issue_remote_code)
|
12
|
+
false
|
13
|
+
end
|
14
|
+
|
15
|
+
def update_remote_issue_with_issue
|
16
|
+
return true if remote_issue.update(local_issue: local_issue)
|
17
|
+
|
18
|
+
fetch_record_errors(remote_issue, default_column: :issue_remote_code)
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
def remote_issue_uncached
|
23
|
+
::RemoteIssue.new(remote_tracker: remote_tracker, remote_code: issue_remote_code)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'eac_ruby_utils/require_sub'
|
4
|
+
require 'eac_ruby_utils/simple_cache'
|
5
|
+
require 'eac/model'
|
6
|
+
|
7
|
+
module RedmineRemotes
|
8
|
+
module Tableless
|
9
|
+
class AddRemoteIssue < ::EacRailsUtils::TablelessModel
|
10
|
+
include ::EacRubyUtils::SimpleCache
|
11
|
+
include ::Eac::Model
|
12
|
+
::EacRubyUtils.require_sub(__FILE__)
|
13
|
+
|
14
|
+
attribute :issue_remote_code, ::String
|
15
|
+
attribute :local_tracker_id, ::Integer
|
16
|
+
attribute :project_id, ::Integer
|
17
|
+
attribute :remote_tracker_id, ::Integer
|
18
|
+
|
19
|
+
belongs_to :local_tracker, class_name: 'Tracker'
|
20
|
+
belongs_to :project, class_name: 'Project'
|
21
|
+
belongs_to :remote_tracker, class_name: 'RemoteTracker'
|
22
|
+
|
23
|
+
validates :local_tracker, presence: true
|
24
|
+
validates :remote_tracker, presence: true
|
25
|
+
validates :project, presence: true
|
26
|
+
validates :issue_remote_code, presence: true
|
27
|
+
|
28
|
+
validate :tracker_in_project
|
29
|
+
validate :author_present
|
30
|
+
validate :provider_issue_present
|
31
|
+
|
32
|
+
def save
|
33
|
+
return false unless valid?
|
34
|
+
return false unless create_remote_issue
|
35
|
+
return false unless create_local_issue
|
36
|
+
return false unless update_remote_issue_with_issue
|
37
|
+
|
38
|
+
true
|
39
|
+
end
|
40
|
+
|
41
|
+
def tracker_in_project
|
42
|
+
return unless local_tracker.present? && project.present?
|
43
|
+
return if project.trackers.include?(local_tracker)
|
44
|
+
|
45
|
+
errors.add(:local_tracker, 'is not a tracker of project')
|
46
|
+
end
|
47
|
+
|
48
|
+
def author_present
|
49
|
+
return if provider_issue.blank?
|
50
|
+
return if local_issue_author.present?
|
51
|
+
|
52
|
+
errors.add(:remote_code,
|
53
|
+
"Usuário local não encontrado para \"#{provider_issue.author_login}\"")
|
54
|
+
end
|
55
|
+
|
56
|
+
def provider_issue_present
|
57
|
+
return if issue_remote_code.blank?
|
58
|
+
return if provider_issue.present?
|
59
|
+
|
60
|
+
errors.add(:remote_code,
|
61
|
+
"Demanda remota não encontrada com o código \"#{issue_remote_code}\"")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class RemoteIssue < ActiveRecord::Base
|
4
|
+
include ::RedmineRemotes::Sanitizer
|
5
|
+
|
6
|
+
downcase_columns :remote_code
|
7
|
+
|
8
|
+
belongs_to :remote_tracker, class_name: 'RemoteTracker', inverse_of: :issues
|
9
|
+
belongs_to :local_issue, class_name: 'Issue', inverse_of: :remote_issue
|
10
|
+
|
11
|
+
validates :remote_tracker, presence: true
|
12
|
+
validates :remote_code, presence: true, uniqueness: { scope: [:remote_tracker] }
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
"#{remote_tracker}|#{remote_code}"
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class RemoteTracker < ActiveRecord::Base
|
4
|
+
def jira_find_remote_issue(issue_id)
|
5
|
+
jira_create_instance.find_issue(issue_id)
|
6
|
+
end
|
7
|
+
|
8
|
+
def jira_create_instance
|
9
|
+
::RedmineRemotes::Jira::Instance.new(root_url, username, password)
|
10
|
+
end
|
11
|
+
end
|
@@ -4,9 +4,14 @@ require 'eac_ruby_utils/listable'
|
|
4
4
|
require 'validate_url'
|
5
5
|
|
6
6
|
class RemoteTracker < ActiveRecord::Base
|
7
|
+
require_relative 'remote_tracker/_jira'
|
8
|
+
|
7
9
|
include ::EacRubyUtils::Listable
|
8
10
|
|
9
|
-
|
11
|
+
has_many :issues, class_name: 'RemoteIssue', inverse_of: :remote_tracker,
|
12
|
+
dependent: :restrict_with_error
|
13
|
+
|
14
|
+
lists.add_string :profile, :jira
|
10
15
|
|
11
16
|
has_many :issue_statuses, class_name: 'RemoteIssueStatus', inverse_of: :remote_tracker,
|
12
17
|
dependent: :destroy
|
@@ -23,4 +28,10 @@ class RemoteTracker < ActiveRecord::Base
|
|
23
28
|
def to_s
|
24
29
|
"#{root_url} [#{profile_label}, #{username}]"
|
25
30
|
end
|
31
|
+
|
32
|
+
def find_remote_issue(issue_id)
|
33
|
+
raise 'Profile blank' if profile.blank?
|
34
|
+
|
35
|
+
send("#{profile}_find_remote_issue", issue_id)
|
36
|
+
end
|
26
37
|
end
|
data/app/models/remote_user.rb
CHANGED
@@ -12,14 +12,16 @@ class RemoteUser < ActiveRecord::Base
|
|
12
12
|
validates :local_user, presence: true
|
13
13
|
|
14
14
|
class << self
|
15
|
-
def find_local_user(remote_login,
|
16
|
-
[
|
15
|
+
def find_local_user(remote_login, remote_tracker = nil)
|
16
|
+
[remote_tracker, nil].each do |tracker|
|
17
17
|
remote_user = ::RemoteUser.where(
|
18
18
|
remote_tracker: tracker,
|
19
19
|
remote_login: remote_login_sanitize(remote_login)
|
20
20
|
).first
|
21
21
|
return remote_user.local_user if remote_user
|
22
22
|
end
|
23
|
+
return remote_tracker.default_local_user if remote_tracker.present?
|
24
|
+
|
23
25
|
nil
|
24
26
|
end
|
25
27
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<h3>Trackers</h3>
|
2
|
+
<% if @trackers.any? %>
|
3
|
+
<table class="list files">
|
4
|
+
<thead>
|
5
|
+
<tr>
|
6
|
+
<th>Profile</th>
|
7
|
+
<th>Root URL</th>
|
8
|
+
<th>Username</th>
|
9
|
+
<th></th>
|
10
|
+
</tr>
|
11
|
+
</thead>
|
12
|
+
<tbody>
|
13
|
+
<% @trackers.each do |tracker| %>
|
14
|
+
<tr>
|
15
|
+
<td><%= tracker.profile %></td>
|
16
|
+
<td><%= tracker.root_url %></td>
|
17
|
+
<td><%= tracker.username %></td>
|
18
|
+
<td class="buttons">
|
19
|
+
<%= link_to 'Add issue', new_project_remote_issue_path(
|
20
|
+
id: @project.identifier,
|
21
|
+
tracker_id: tracker.id
|
22
|
+
) %>
|
23
|
+
</td>
|
24
|
+
</tr>
|
25
|
+
<% end %>
|
26
|
+
</tbody>
|
27
|
+
</table>
|
28
|
+
<% else %>
|
29
|
+
<p><em>No trackers registered.</em></p>
|
30
|
+
<% end %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<h2><%= @tracker %> » Add Remote Issue</h2>
|
2
|
+
<%= labelled_form_for @add_issue, :url => create_project_remote_issue_path(
|
3
|
+
id: @project.identifier,
|
4
|
+
tracker_id: @remote_tracker.id
|
5
|
+
), method: :post do |f| %>
|
6
|
+
<%= error_messages_for 'add_issue' %>
|
7
|
+
<div class="box tabular">
|
8
|
+
<p><%= f.select :local_tracker_id, @project.trackers.map {|t| [t.to_s, t.id]} %></p>
|
9
|
+
<p><%= f.text_field :issue_remote_code %></p>
|
10
|
+
</div>
|
11
|
+
<%= submit_tag l(:button_save) %>
|
12
|
+
<% end %>
|
@@ -5,6 +5,11 @@
|
|
5
5
|
::RemoteTrackersController::WRITE_PERMISSION,
|
6
6
|
dependencies: [::RemoteTrackersController::READ_PERMISSION]
|
7
7
|
)
|
8
|
+
::GroupPermission.add_permission(::RemoteIssuesController::READ_PERMISSION)
|
9
|
+
::GroupPermission.add_permission(
|
10
|
+
::RemoteIssuesController::WRITE_PERMISSION,
|
11
|
+
dependencies: [::RemoteIssuesController::READ_PERMISSION]
|
12
|
+
)
|
8
13
|
::GroupPermission.add_permission(::RemoteIssueStatusesController::READ_PERMISSION)
|
9
14
|
::GroupPermission.add_permission(
|
10
15
|
::RemoteIssueStatusesController::WRITE_PERMISSION,
|
@@ -18,6 +23,7 @@
|
|
18
23
|
|
19
24
|
Redmine::MenuManager.map ::RedmineRemotes::SLUG.to_sym do |menu|
|
20
25
|
menu.push_controller(:remote_trackers)
|
26
|
+
menu.push_controller(:remote_issues)
|
21
27
|
menu.push_controller(:remote_issue_statuses)
|
22
28
|
menu.push_controller(:remote_users)
|
23
29
|
end
|
data/config/locales/en.yml
CHANGED
@@ -3,8 +3,12 @@ en:
|
|
3
3
|
listable:
|
4
4
|
remote_tracker:
|
5
5
|
profile:
|
6
|
-
|
7
|
-
label:
|
6
|
+
jira:
|
7
|
+
label: Jira
|
8
|
+
field_issue_remote_code: Remote issue's code
|
9
|
+
field_local_tracker: Local tracker
|
10
|
+
label_remote_issues: Remote issues
|
8
11
|
label_remote_trackers: Remote trackers
|
9
12
|
label_remote_issue_statuses: Remote issue statuses
|
10
13
|
label_remote_users: Remote users
|
14
|
+
label_remotes: Remotes
|
data/config/locales/pt-BR.yml
CHANGED
@@ -3,8 +3,12 @@ pt-BR:
|
|
3
3
|
listable:
|
4
4
|
remote_tracker:
|
5
5
|
profile:
|
6
|
-
|
7
|
-
label:
|
6
|
+
jira:
|
7
|
+
label: Jira
|
8
|
+
field_issue_remote_code: Código da demanda remota
|
9
|
+
field_local_tracker: Tipo de tarefa local
|
10
|
+
label_remote_issues: Demandas remotas
|
8
11
|
label_remote_trackers: Trackers remotos
|
9
12
|
label_remote_issue_statuses: Situações de demandas remotas
|
10
13
|
label_remote_users: Usuários remotos
|
14
|
+
label_remotes: Remotos
|
data/config/routes.rb
CHANGED
@@ -1,7 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RedmineApp::Application.routes.draw do
|
4
|
+
get '/projects/:id/remotes', to: 'project_remote_issues#index'
|
5
|
+
get '/projects/:id/tracker/:tracker_id/new_issue', to: 'project_remote_issues#new',
|
6
|
+
as: 'new_project_remote_issue'
|
7
|
+
post '/projects/:id/tracker/:tracker_id/new_issue', to: 'project_remote_issues#create',
|
8
|
+
as: 'create_project_remote_issue'
|
9
|
+
resources(:project_remote_issues, only: [:index])
|
4
10
|
resources(:remote_trackers) { as_routes }
|
11
|
+
resources(:remote_issues) { as_routes }
|
5
12
|
resources(:remote_issue_statuses) { as_routes }
|
6
13
|
resources(:remote_users) { as_routes }
|
7
14
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateRemoteIssues < ActiveRecord::Migration
|
4
|
+
def change
|
5
|
+
create_table :remote_issues do |t|
|
6
|
+
t.references :remote_tracker, index: true
|
7
|
+
t.references :local_issue, index: true, nullable: true
|
8
|
+
t.string :remote_code
|
9
|
+
end
|
10
|
+
add_foreign_key :remote_issues, :remote_trackers, column: :remote_tracker_id
|
11
|
+
add_foreign_key :remote_issues, :issues, column: :local_issue_id
|
12
|
+
end
|
13
|
+
end
|
data/init.rb
CHANGED
@@ -7,4 +7,14 @@ Redmine::Plugin.register ::RedmineRemotes::SLUG.to_sym do
|
|
7
7
|
author ::RedmineRemotes::AUTHOR
|
8
8
|
description ::RedmineRemotes::SUMMARY
|
9
9
|
version ::RedmineRemotes::VERSION
|
10
|
+
|
11
|
+
project_module :redmine_remotes do
|
12
|
+
permission :view_trackers, project_remote_issues: [:index]
|
13
|
+
permission :add_issues, project_remote_issues: %i[new create]
|
14
|
+
end
|
15
|
+
|
16
|
+
Redmine::MenuManager.map :project_menu do |menu|
|
17
|
+
menu.push :remotes_issues, { controller: 'project_remote_issues', action: 'index' },
|
18
|
+
caption: :label_remotes, after: :issues
|
19
|
+
end
|
10
20
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RedmineRemotes
|
4
|
+
module Jira
|
5
|
+
module Entities
|
6
|
+
class Issue < ::RedmineRemotes::RestProvider::Entity
|
7
|
+
def code
|
8
|
+
data.fetch('key')
|
9
|
+
end
|
10
|
+
|
11
|
+
def created_on
|
12
|
+
fields.fetch('created')
|
13
|
+
end
|
14
|
+
|
15
|
+
def fields
|
16
|
+
data.fetch('fields')
|
17
|
+
end
|
18
|
+
|
19
|
+
def subject
|
20
|
+
fields.fetch('summary')
|
21
|
+
end
|
22
|
+
|
23
|
+
def status_name
|
24
|
+
fields.fetch('status').fetch('name')
|
25
|
+
end
|
26
|
+
|
27
|
+
def updated_on
|
28
|
+
fields.fetch('updated')
|
29
|
+
end
|
30
|
+
|
31
|
+
def author_login
|
32
|
+
fields.fetch('reporter').fetch('key')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RedmineRemotes
|
4
|
+
module Jira
|
5
|
+
class Instance < ::RedmineRemotes::RestProvider::Instance
|
6
|
+
ISSUE_ID_PATTERN = /\A([a-z][a-z0-9]+)\-(\d+)\z/i.freeze
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def parse_issue_id(global_issue_id)
|
10
|
+
m = ISSUE_ID_PATTERN.match(global_issue_id)
|
11
|
+
return nil unless m
|
12
|
+
|
13
|
+
::OpenStruct.new(provider_issue_id: m[0], project_id: m[1], project_issue_id: m[2])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def build_service_url(service_url_suffix)
|
18
|
+
"#{root_url}/rest/api/latest#{service_url_suffix}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def issue_get_url_suffix(provider_issue_id)
|
22
|
+
"/issue/#{provider_issue_id}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EacRedmineUsability
|
4
|
+
module Patches
|
5
|
+
module Issue
|
6
|
+
extend ::ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
has_one :remote_issue, class_name: 'RemoteIssue',
|
10
|
+
inverse_of: :local_issue, dependent: :restrict_with_error,
|
11
|
+
foreign_key: :local_issue_id
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
require_dependency 'issue'
|
18
|
+
patch = ::EacRedmineUsability::Patches::Issue
|
19
|
+
target = ::Issue
|
20
|
+
target.send(:include, patch) unless target.included_modules.include?(patch)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'eac_ruby_utils/simple_cache'
|
4
|
+
|
5
|
+
module RedmineRemotes
|
6
|
+
module RestProvider
|
7
|
+
class Entity
|
8
|
+
include ::EacRubyUtils::SimpleCache
|
9
|
+
|
10
|
+
attr_reader :instance, :data
|
11
|
+
|
12
|
+
def initialize(instance, data)
|
13
|
+
@instance = instance
|
14
|
+
@data = data
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RedmineRemotes
|
4
|
+
module RestProvider
|
5
|
+
class HttpResponse < ::StandardError
|
6
|
+
class << self
|
7
|
+
def new_from_curl_easy(curl_easy)
|
8
|
+
new(
|
9
|
+
curl_easy.url,
|
10
|
+
curl_easy.status.to_i,
|
11
|
+
curl_easy.body_str
|
12
|
+
)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :url, :status, :body
|
17
|
+
|
18
|
+
def initialize(url, status, body)
|
19
|
+
@url = url
|
20
|
+
@status = status
|
21
|
+
@body = body
|
22
|
+
end
|
23
|
+
|
24
|
+
def body_or_raise
|
25
|
+
return body if status == 200
|
26
|
+
|
27
|
+
raise self
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'curb'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module RedmineRemotes
|
7
|
+
module RestProvider
|
8
|
+
# Abstract methods
|
9
|
+
# * parse_issue_id(global_issue_id)
|
10
|
+
# * self.build_service_url(service_url_suffix)
|
11
|
+
# * self.issue_get_url_suffix(provider_issue_id)
|
12
|
+
class Instance
|
13
|
+
attr_reader :root_url, :username, :password
|
14
|
+
|
15
|
+
def initialize(root_url, username, password)
|
16
|
+
@root_url = root_url
|
17
|
+
@username = username
|
18
|
+
@password = password
|
19
|
+
end
|
20
|
+
|
21
|
+
def find_issue(global_issue_id)
|
22
|
+
parsed = self.class.parse_issue_id(global_issue_id)
|
23
|
+
parsed.present? ? issue(parsed.provider_issue_id) : nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def issue(provider_issue_id)
|
27
|
+
issue_class.new(self, request(issue_get_url_suffix(provider_issue_id)))
|
28
|
+
end
|
29
|
+
|
30
|
+
def request(service_url_suffix)
|
31
|
+
JSON.parse(curl_perform(service_url_suffix).body_or_raise)
|
32
|
+
end
|
33
|
+
|
34
|
+
def issue_class
|
35
|
+
"#{self.class.name.deconstantize}::Entities::Issue".constantize
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# @return [RedmineRemotes::RestProvider::HttpResponse]
|
41
|
+
def curl_perform(service_url_suffix)
|
42
|
+
c = ::Curl::Easy.new(build_service_url(service_url_suffix))
|
43
|
+
c.http_auth_types = :basic
|
44
|
+
c.username = username
|
45
|
+
c.password = password
|
46
|
+
c.headers['Accept'] = 'application/json'
|
47
|
+
return ::RedmineRemotes::RestProvider::HttpResponse.new_from_curl_easy(c) if c.perform
|
48
|
+
|
49
|
+
raise 'Curl failed'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -8,4 +8,28 @@ namespace :redmine_remotes do
|
|
8
8
|
t.verbose = false
|
9
9
|
t.warning = false
|
10
10
|
end
|
11
|
+
|
12
|
+
namespace :issues do
|
13
|
+
desc 'Adds a remote issue.'
|
14
|
+
task :add, [:remote_tracker_id, :issue_remote_code, :project_identifier, :local_tracker_id] => :environment do |t, args|
|
15
|
+
remote_tracker = ::RemoteTracker.find(args.remote_tracker_id)
|
16
|
+
::Rails.logger.info("Remote tracker: #{remote_tracker}")
|
17
|
+
|
18
|
+
project = ::Project.find_by_identifier(args.project_identifier)
|
19
|
+
::Rails.logger.info("Project: #{project}")
|
20
|
+
|
21
|
+
local_tracker = args.local_tracker_id ? ::Tracker.find(args.local_tracker_id) : project.trackers.first
|
22
|
+
::Rails.logger.info("Local tracker: #{local_tracker}")
|
23
|
+
|
24
|
+
add = ::RedmineRemotes::Tableless::AddRemoteIssue.new(
|
25
|
+
remote_tracker: remote_tracker, project: project, local_tracker: local_tracker,
|
26
|
+
issue_remote_code: args.issue_remote_code
|
27
|
+
)
|
28
|
+
if add.save
|
29
|
+
::Rails.logger.info "[Success] Issue ID: \"#{add.local_issue.id}\""
|
30
|
+
else
|
31
|
+
::Rails.logger.info "[Failed] #{add.errors.messages.pretty_inspect}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
11
35
|
end
|
metadata
CHANGED
@@ -1,15 +1,69 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redmine_remotes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eduardo Henrique Bogoni
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-11-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: aranha-parsers
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.2'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.2.1
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.2'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.2.1
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: curb
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0.9'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 0.9.10
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0.9'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 0.9.10
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: eac_rails_utils
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0.5'
|
60
|
+
type: :runtime
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - "~>"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0.5'
|
13
67
|
- !ruby/object:Gem::Dependency
|
14
68
|
name: eac_ruby_utils
|
15
69
|
requirement: !ruby/object:Gem::Requirement
|
@@ -56,12 +110,23 @@ executables: []
|
|
56
110
|
extensions: []
|
57
111
|
extra_rdoc_files: []
|
58
112
|
files:
|
113
|
+
- app/controllers/project_remote_issues_controller.rb
|
59
114
|
- app/controllers/remote_issue_statuses_controller.rb
|
115
|
+
- app/controllers/remote_issues_controller.rb
|
60
116
|
- app/controllers/remote_trackers_controller.rb
|
61
117
|
- app/controllers/remote_users_controller.rb
|
118
|
+
- app/models/redmine_remotes/tableless/add_remote_issue.rb
|
119
|
+
- app/models/redmine_remotes/tableless/add_remote_issue/_local_issue.rb
|
120
|
+
- app/models/redmine_remotes/tableless/add_remote_issue/_provider_issue.rb
|
121
|
+
- app/models/redmine_remotes/tableless/add_remote_issue/_remote_issue.rb
|
122
|
+
- app/models/remote_issue.rb
|
62
123
|
- app/models/remote_issue_status.rb
|
63
124
|
- app/models/remote_tracker.rb
|
125
|
+
- app/models/remote_tracker/_jira.rb
|
64
126
|
- app/models/remote_user.rb
|
127
|
+
- app/views/project_remote_issues/_trackers.html.erb
|
128
|
+
- app/views/project_remote_issues/index.html.erb
|
129
|
+
- app/views/project_remote_issues/new.html.erb
|
65
130
|
- config/initializers/000_dependencies.rb
|
66
131
|
- config/initializers/001_patches.rb
|
67
132
|
- config/initializers/nonproject_modules.rb
|
@@ -72,12 +137,19 @@ files:
|
|
72
137
|
- db/migrate/20190910182842_create_remote_users.rb
|
73
138
|
- db/migrate/20190910203552_create_remote_issue_statuses.rb
|
74
139
|
- db/migrate/20190911165556_rename_issue_status_id_to_local_issue_status_id_in_remote_issue_statuses.rb
|
140
|
+
- db/migrate/20190912000000_create_remote_issues.rb
|
75
141
|
- db/migrate/20190913195930_add_default_local_user_id_to_remote_trackers.rb
|
76
142
|
- init.rb
|
77
143
|
- lib/redmine_remotes.rb
|
144
|
+
- lib/redmine_remotes/jira/entities/issue.rb
|
145
|
+
- lib/redmine_remotes/jira/instance.rb
|
146
|
+
- lib/redmine_remotes/patches/issue.rb
|
78
147
|
- lib/redmine_remotes/patches/issue_status.rb
|
79
148
|
- lib/redmine_remotes/patches/tracker.rb
|
80
149
|
- lib/redmine_remotes/patches/user.rb
|
150
|
+
- lib/redmine_remotes/rest_provider/entity.rb
|
151
|
+
- lib/redmine_remotes/rest_provider/http_response.rb
|
152
|
+
- lib/redmine_remotes/rest_provider/instance.rb
|
81
153
|
- lib/redmine_remotes/sanitizer.rb
|
82
154
|
- lib/redmine_remotes/version.rb
|
83
155
|
- lib/tasks/redmine_remotes.rake
|