activeproject 0.2.0 → 0.5.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/README.md +248 -51
- data/lib/active_project/adapters/base.rb +154 -14
- data/lib/active_project/adapters/basecamp/comments.rb +34 -0
- data/lib/active_project/adapters/basecamp/connection.rb +10 -23
- data/lib/active_project/adapters/basecamp/issues.rb +6 -5
- data/lib/active_project/adapters/basecamp/webhooks.rb +7 -8
- data/lib/active_project/adapters/basecamp_adapter.rb +2 -11
- data/lib/active_project/adapters/fizzy/columns.rb +116 -0
- data/lib/active_project/adapters/fizzy/comments.rb +129 -0
- data/lib/active_project/adapters/fizzy/connection.rb +41 -0
- data/lib/active_project/adapters/fizzy/issues.rb +221 -0
- data/lib/active_project/adapters/fizzy/projects.rb +105 -0
- data/lib/active_project/adapters/fizzy_adapter.rb +151 -0
- data/lib/active_project/adapters/github_project/comments.rb +91 -0
- data/lib/active_project/adapters/github_project/connection.rb +58 -0
- data/lib/active_project/adapters/github_project/helpers.rb +100 -0
- data/lib/active_project/adapters/github_project/issues.rb +287 -0
- data/lib/active_project/adapters/github_project/projects.rb +139 -0
- data/lib/active_project/adapters/github_project/webhooks.rb +168 -0
- data/lib/active_project/adapters/github_project.rb +8 -0
- data/lib/active_project/adapters/github_project_adapter.rb +65 -0
- data/lib/active_project/adapters/github_repo/connection.rb +62 -0
- data/lib/active_project/adapters/github_repo/issues.rb +242 -0
- data/lib/active_project/adapters/github_repo/projects.rb +116 -0
- data/lib/active_project/adapters/github_repo/webhooks.rb +354 -0
- data/lib/active_project/adapters/github_repo_adapter.rb +134 -0
- data/lib/active_project/adapters/jira/attribute_normalizer.rb +16 -0
- data/lib/active_project/adapters/jira/comments.rb +41 -0
- data/lib/active_project/adapters/jira/connection.rb +43 -24
- data/lib/active_project/adapters/jira/issues.rb +21 -7
- data/lib/active_project/adapters/jira/projects.rb +3 -1
- data/lib/active_project/adapters/jira/transitions.rb +2 -1
- data/lib/active_project/adapters/jira/webhooks.rb +5 -7
- data/lib/active_project/adapters/jira_adapter.rb +23 -30
- data/lib/active_project/adapters/trello/comments.rb +34 -0
- data/lib/active_project/adapters/trello/connection.rb +28 -21
- data/lib/active_project/adapters/trello/issues.rb +7 -5
- data/lib/active_project/adapters/trello/webhooks.rb +5 -7
- data/lib/active_project/adapters/trello_adapter.rb +5 -25
- data/lib/active_project/association_proxy.rb +3 -2
- data/lib/active_project/async.rb +9 -0
- data/lib/active_project/configuration.rb +6 -3
- data/lib/active_project/configurations/base_adapter_configuration.rb +102 -0
- data/lib/active_project/configurations/basecamp_configuration.rb +42 -0
- data/lib/active_project/configurations/fizzy_configuration.rb +47 -0
- data/lib/active_project/configurations/github_configuration.rb +57 -0
- data/lib/active_project/configurations/jira_configuration.rb +54 -0
- data/lib/active_project/configurations/trello_configuration.rb +24 -2
- data/lib/active_project/connections/base.rb +35 -0
- data/lib/active_project/connections/graph_ql.rb +83 -0
- data/lib/active_project/connections/http_client.rb +79 -0
- data/lib/active_project/connections/pagination.rb +44 -0
- data/lib/active_project/connections/rest.rb +33 -0
- data/lib/active_project/error_mapper.rb +38 -0
- data/lib/active_project/errors.rb +13 -0
- data/lib/active_project/railtie.rb +33 -0
- data/lib/active_project/resource_factory.rb +18 -0
- data/lib/active_project/resources/base_resource.rb +13 -14
- data/lib/active_project/resources/comment.rb +46 -2
- data/lib/active_project/resources/issue.rb +106 -18
- data/lib/active_project/resources/persistable_resource.rb +47 -0
- data/lib/active_project/resources/project.rb +1 -1
- data/lib/active_project/status_mapper.rb +145 -0
- data/lib/active_project/version.rb +1 -1
- data/lib/active_project/webhook_event.rb +34 -12
- data/lib/activeproject.rb +11 -6
- metadata +107 -6
|
@@ -2,34 +2,122 @@
|
|
|
2
2
|
|
|
3
3
|
module ActiveProject
|
|
4
4
|
module Resources
|
|
5
|
-
#
|
|
6
|
-
class Issue <
|
|
5
|
+
# Whether it's a Jira ticket, Trello card, GitHub Issue, or Basecamp Todo
|
|
6
|
+
class Issue < PersistableResource
|
|
7
7
|
def_members :id, :key, :title, :description, :status, :assignees,
|
|
8
8
|
:reporter, :project_id, :created_at, :updated_at, :due_on,
|
|
9
9
|
:priority, :adapter_source
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
def initialize(adapter, attributes = {})
|
|
12
|
+
super
|
|
13
|
+
@initial_title = attributes[:title]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Persist the record, creating it if it does not yet exist.
|
|
14
17
|
def save
|
|
15
|
-
|
|
18
|
+
unless project_id
|
|
19
|
+
raise ActiveProject::NotImplementedError,
|
|
20
|
+
"#save not supported on transient records"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
attrs = to_h.slice(:title, :description, :status, :assignees,
|
|
24
|
+
:reporter, :due_on, :priority)
|
|
25
|
+
|
|
26
|
+
if @adapter.is_a?(ActiveProject::Adapters::JiraAdapter)
|
|
27
|
+
if id.nil? # first persist ⇒ create_issue
|
|
28
|
+
attrs.delete(:title) # remove :title entirely
|
|
29
|
+
attrs[:summary] = @initial_title # use the ORIGINAL title
|
|
30
|
+
elsif attrs.key?(:title) # later saves ⇒ update_issue
|
|
31
|
+
attrs[:summary] = attrs.delete(:title)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
attrs.delete(:status) unless @adapter.status_known?(project_id, attrs[:status])
|
|
36
|
+
|
|
37
|
+
fresh =
|
|
38
|
+
if id.nil?
|
|
39
|
+
adapter.create_issue(project_id, attrs)
|
|
40
|
+
else
|
|
41
|
+
adapter_update_issue(id, attrs)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
copy_from(fresh)
|
|
45
|
+
true
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Update attributes and persist them.
|
|
49
|
+
def update(attributes = {})
|
|
50
|
+
unless project_id && id
|
|
51
|
+
raise ActiveProject::NotImplementedError,
|
|
52
|
+
"#update not supported on transient records"
|
|
53
|
+
end
|
|
54
|
+
unless attributes.is_a?(Hash)
|
|
55
|
+
raise ActiveProject::NotImplementedError,
|
|
56
|
+
"attributes must be a Hash"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
ident = key || id
|
|
60
|
+
adapter_update_issue(ident, attributes)
|
|
61
|
+
copy_from(adapter_find_issue(ident))
|
|
62
|
+
true
|
|
16
63
|
end
|
|
17
64
|
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
raise NotImplementedError, "#update not yet implemented for #{self.class.name}"
|
|
65
|
+
# Delete remote record.
|
|
66
|
+
def delete
|
|
67
|
+
raise "project_id missing – can't destroy" unless project_id
|
|
68
|
+
raise "id missing – record not persisted" if id.nil?
|
|
69
|
+
|
|
70
|
+
adapter_delete_issue(id)
|
|
71
|
+
freeze
|
|
72
|
+
true
|
|
27
73
|
end
|
|
74
|
+
alias destroy delete
|
|
28
75
|
|
|
29
|
-
#
|
|
30
|
-
# @return [AssociationProxy<Resources::Comment>]
|
|
76
|
+
# Lazy association proxy for comments.
|
|
31
77
|
def comments
|
|
32
|
-
AssociationProxy.new(owner: self, adapter:
|
|
78
|
+
AssociationProxy.new(owner: self, adapter: adapter, association_name: :comments)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def copy_from(other)
|
|
84
|
+
self.class.members.each { |m| public_send("#{m}=", other.public_send(m)) }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Adapter-aware update_issue call that handles different signatures
|
|
88
|
+
def adapter_update_issue(issue_id, attrs)
|
|
89
|
+
case @adapter
|
|
90
|
+
when ActiveProject::Adapters::BasecampAdapter
|
|
91
|
+
@adapter.update_issue(issue_id, attrs, { project_id: project_id })
|
|
92
|
+
when ActiveProject::Adapters::GithubProjectAdapter
|
|
93
|
+
@adapter.update_issue(project_id, issue_id, attrs)
|
|
94
|
+
else
|
|
95
|
+
# Jira, Trello, GithubRepo: (id, attrs, context)
|
|
96
|
+
@adapter.update_issue(issue_id, attrs, {})
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Adapter-aware find_issue call that handles different signatures
|
|
101
|
+
def adapter_find_issue(issue_id)
|
|
102
|
+
case @adapter
|
|
103
|
+
when ActiveProject::Adapters::BasecampAdapter
|
|
104
|
+
@adapter.find_issue(issue_id, { project_id: project_id })
|
|
105
|
+
else
|
|
106
|
+
@adapter.find_issue(issue_id, {})
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Adapter-aware delete_issue call that handles different signatures
|
|
111
|
+
def adapter_delete_issue(issue_id)
|
|
112
|
+
case @adapter
|
|
113
|
+
when ActiveProject::Adapters::BasecampAdapter
|
|
114
|
+
@adapter.delete_issue(issue_id, { project_id: project_id })
|
|
115
|
+
when ActiveProject::Adapters::GithubProjectAdapter
|
|
116
|
+
@adapter.delete_issue(project_id, issue_id)
|
|
117
|
+
else
|
|
118
|
+
# Jira, Trello, GithubRepo: (id, context)
|
|
119
|
+
@adapter.delete_issue(issue_id, {})
|
|
120
|
+
end
|
|
33
121
|
end
|
|
34
122
|
end
|
|
35
123
|
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveProject
|
|
4
|
+
module Resources
|
|
5
|
+
class PersistableResource < BaseResource
|
|
6
|
+
# Indicates if the resource has been persisted (typically by checking for an ID)
|
|
7
|
+
def persisted?
|
|
8
|
+
!id.nil? # Assumes an 'id' member
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# These are now expected to be implemented by concrete subclasses
|
|
12
|
+
# like Issue and Comment, or this class could provide a template
|
|
13
|
+
# that calls conventionally named adapter methods.
|
|
14
|
+
def save
|
|
15
|
+
raise NotImplementedError, "#{self.class.name} must implement #save"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def update(attributes)
|
|
19
|
+
raise NotImplementedError, "#{self.class.name} must implement #update"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def delete
|
|
23
|
+
raise NotImplementedError, "#{self.class.name} must implement #delete"
|
|
24
|
+
end
|
|
25
|
+
alias destroy delete
|
|
26
|
+
|
|
27
|
+
protected
|
|
28
|
+
|
|
29
|
+
# Common logic for copying attributes after an API call
|
|
30
|
+
def copy_from(other_resource)
|
|
31
|
+
# Ensure it's the same type of resource before copying
|
|
32
|
+
return unless other_resource.is_a?(self.class)
|
|
33
|
+
|
|
34
|
+
self.class.members.each do |member_name|
|
|
35
|
+
setter_method = "#{member_name}="
|
|
36
|
+
# Check if both the current resource and the other resource can handle this member
|
|
37
|
+
if respond_to?(setter_method) && other_resource.respond_to?(member_name)
|
|
38
|
+
public_send(setter_method, other_resource.public_send(member_name))
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
# Optionally, update raw_data as well if it's part of the contract
|
|
42
|
+
# @raw_data = other_resource.raw_data if other_resource.respond_to?(:raw_data)
|
|
43
|
+
self # Return self for chaining or assignment
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module ActiveProject
|
|
4
4
|
module Resources
|
|
5
5
|
# Represents a Project (e.g., Jira Project, Trello Board, Basecamp Project)
|
|
6
|
-
class Project <
|
|
6
|
+
class Project < PersistableResource
|
|
7
7
|
def_members :id, :key, :name, :adapter_source
|
|
8
8
|
# raw_data and adapter are inherited from BaseResource
|
|
9
9
|
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveProject
|
|
4
|
+
# Handles bidirectional status mapping between platform-specific statuses
|
|
5
|
+
# and normalized ActiveProject status symbols.
|
|
6
|
+
#
|
|
7
|
+
# Supports:
|
|
8
|
+
# - Standard status symbols (:open, :in_progress, :closed, :blocked, :on_hold)
|
|
9
|
+
# - Platform-specific status preservation
|
|
10
|
+
# - Configurable status mappings per adapter
|
|
11
|
+
# - Fallback to standard status normalization
|
|
12
|
+
class StatusMapper
|
|
13
|
+
# Standard ActiveProject status symbols with their meanings
|
|
14
|
+
STANDARD_STATUSES = {
|
|
15
|
+
open: "New, unstarted work",
|
|
16
|
+
in_progress: "Currently being worked on",
|
|
17
|
+
blocked: "Waiting on external dependency",
|
|
18
|
+
on_hold: "Temporarily paused",
|
|
19
|
+
closed: "Completed or resolved"
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
# Default mapping rules for common status patterns
|
|
23
|
+
DEFAULT_MAPPINGS = {
|
|
24
|
+
# Open/New statuses
|
|
25
|
+
/^(new|open|todo|to do|backlog|ready|created)$/i => :open,
|
|
26
|
+
|
|
27
|
+
# In Progress statuses
|
|
28
|
+
/^(in progress|in_progress|active|working|started|doing)$/i => :in_progress,
|
|
29
|
+
|
|
30
|
+
# Blocked statuses
|
|
31
|
+
/^(blocked|waiting|pending|on hold|on_hold|paused)$/i => :blocked,
|
|
32
|
+
|
|
33
|
+
# Closed statuses
|
|
34
|
+
/^(done|closed|completed|finished|resolved|fixed)$/i => :closed
|
|
35
|
+
}.freeze
|
|
36
|
+
|
|
37
|
+
attr_reader :adapter_type, :custom_mappings
|
|
38
|
+
|
|
39
|
+
# @param adapter_type [Symbol] The adapter type (:jira, :trello, etc.)
|
|
40
|
+
# @param custom_mappings [Hash] Custom status mappings from configuration
|
|
41
|
+
def initialize(adapter_type, custom_mappings = {})
|
|
42
|
+
@adapter_type = adapter_type
|
|
43
|
+
@custom_mappings = custom_mappings || {}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Converts a platform-specific status to a normalized status symbol.
|
|
47
|
+
# @param platform_status [String, Symbol] The platform-specific status
|
|
48
|
+
# @param context [Hash] Optional context (e.g., project_id for project-specific mappings)
|
|
49
|
+
# @return [Symbol] Normalized status symbol
|
|
50
|
+
def normalize_status(platform_status, context = {})
|
|
51
|
+
return platform_status if STANDARD_STATUSES.key?(platform_status.to_sym)
|
|
52
|
+
|
|
53
|
+
# Try custom mappings first
|
|
54
|
+
if custom_mappings.is_a?(Hash)
|
|
55
|
+
# Support project-specific mappings (for Trello, GitHub)
|
|
56
|
+
project_mappings = custom_mappings[context[:project_id]] || custom_mappings
|
|
57
|
+
|
|
58
|
+
# Check direct mapping
|
|
59
|
+
if project_mappings[platform_status.to_s]
|
|
60
|
+
return project_mappings[platform_status.to_s].to_sym
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Fall back to pattern matching
|
|
65
|
+
status_str = platform_status.to_s.strip
|
|
66
|
+
DEFAULT_MAPPINGS.each do |pattern, normalized_status|
|
|
67
|
+
return normalized_status if status_str.match?(pattern)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# If no mapping found, return as symbol for platform-specific handling
|
|
71
|
+
platform_status.to_s.downcase.tr(" -", "_").to_sym
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Converts a normalized status symbol back to platform-specific status.
|
|
75
|
+
# @param normalized_status [Symbol] The normalized status symbol
|
|
76
|
+
# @param context [Hash] Optional context for platform-specific conversion
|
|
77
|
+
# @return [String, Symbol] Platform-specific status representation
|
|
78
|
+
def denormalize_status(normalized_status, context = {})
|
|
79
|
+
# If it's already a standard status, delegate to adapter-specific logic
|
|
80
|
+
return normalized_status if STANDARD_STATUSES.key?(normalized_status.to_sym)
|
|
81
|
+
|
|
82
|
+
# Try reverse lookup in custom mappings
|
|
83
|
+
if custom_mappings.is_a?(Hash)
|
|
84
|
+
project_mappings = custom_mappings[context[:project_id]] || custom_mappings
|
|
85
|
+
|
|
86
|
+
# Find the platform status that maps to this normalized status
|
|
87
|
+
project_mappings.each do |platform_status, mapped_status|
|
|
88
|
+
return platform_status if mapped_status.to_sym == normalized_status.to_sym
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Default: return the status as-is for platform handling
|
|
93
|
+
normalized_status
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Checks if a status is known/valid for the given context.
|
|
97
|
+
# @param status [Symbol, String] The status to check
|
|
98
|
+
# @param context [Hash] Optional context for validation
|
|
99
|
+
# @return [Boolean] true if the status is valid
|
|
100
|
+
def status_known?(status, context = {})
|
|
101
|
+
# Handle nil status
|
|
102
|
+
return false if status.nil?
|
|
103
|
+
|
|
104
|
+
# Standard statuses are always known
|
|
105
|
+
return true if STANDARD_STATUSES.key?(status.to_sym)
|
|
106
|
+
|
|
107
|
+
# Check custom mappings
|
|
108
|
+
if custom_mappings.is_a?(Hash)
|
|
109
|
+
project_mappings = custom_mappings[context[:project_id]] || custom_mappings
|
|
110
|
+
return true if project_mappings.key?(status.to_s)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Check if it matches any default patterns
|
|
114
|
+
status_str = status.to_s.strip
|
|
115
|
+
DEFAULT_MAPPINGS.any? { |pattern, _| status_str.match?(pattern) }
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Returns all valid statuses for the given context.
|
|
119
|
+
# @param context [Hash] Optional context
|
|
120
|
+
# @return [Array<Symbol>] Array of valid status symbols
|
|
121
|
+
def valid_statuses(context = {})
|
|
122
|
+
statuses = STANDARD_STATUSES.keys.dup
|
|
123
|
+
|
|
124
|
+
# Add custom mapped statuses
|
|
125
|
+
if custom_mappings.is_a?(Hash)
|
|
126
|
+
project_mappings = custom_mappings[context[:project_id]] || custom_mappings
|
|
127
|
+
project_mappings.each do |platform_status, normalized_status|
|
|
128
|
+
statuses << normalized_status.to_sym
|
|
129
|
+
statuses << platform_status.to_s.downcase.tr(" -", "_").to_sym
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
statuses.uniq
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Creates a status mapper instance from adapter configuration.
|
|
137
|
+
# @param adapter_type [Symbol] The adapter type
|
|
138
|
+
# @param config [ActiveProject::Configurations::BaseAdapterConfiguration] Adapter config
|
|
139
|
+
# @return [StatusMapper] Configured status mapper
|
|
140
|
+
def self.from_config(adapter_type, config)
|
|
141
|
+
status_mappings = config.respond_to?(:status_mappings) ? config.status_mappings : {}
|
|
142
|
+
new(adapter_type, status_mappings)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
@@ -4,17 +4,39 @@ module ActiveProject
|
|
|
4
4
|
# Represents a standardized event parsed from a webhook payload.
|
|
5
5
|
# Using Struct for simplicity for now. Could be a full class inheriting BaseResource if needed.
|
|
6
6
|
WebhookEvent = Struct.new(
|
|
7
|
-
:
|
|
8
|
-
:
|
|
9
|
-
:
|
|
10
|
-
:
|
|
11
|
-
:
|
|
12
|
-
:
|
|
13
|
-
:
|
|
14
|
-
:
|
|
15
|
-
:
|
|
16
|
-
:
|
|
17
|
-
:raw_data, # The original, parsed webhook payload hash
|
|
7
|
+
:source, # Symbol representing the source platform (e.g., :github, :jira, :trello)
|
|
8
|
+
:webhook_type, # Symbol representing the adapter type (e.g., :github_repo, :github_project, :jira, :basecamp)
|
|
9
|
+
:type, # Symbol representing the event type (e.g., :issue_created, :comment_added)
|
|
10
|
+
:resource_type, # Symbol representing the type of resource involved (e.g., :issue, :comment)
|
|
11
|
+
:resource_id, # String ID of the primary resource
|
|
12
|
+
:project_id, # String ID of the associated project/repository
|
|
13
|
+
:actor, # User resource representing the user who triggered the event (optional)
|
|
14
|
+
:timestamp, # Time object representing when the event occurred (optional)
|
|
15
|
+
:data, # Hash containing event-specific data (e.g., issue, comment, changes)
|
|
16
|
+
:raw_data, # The original, parsed webhook payload hash (optional)
|
|
18
17
|
keyword_init: true
|
|
19
|
-
)
|
|
18
|
+
) do
|
|
19
|
+
# For backward compatibility
|
|
20
|
+
alias_method :event_type, :type
|
|
21
|
+
alias_method :object_kind, :resource_type
|
|
22
|
+
alias_method :event_object_id, :resource_id
|
|
23
|
+
alias_method :adapter_source, :source
|
|
24
|
+
alias_method :object_data, :data
|
|
25
|
+
|
|
26
|
+
# Additional aliases that might be expected
|
|
27
|
+
def object_key
|
|
28
|
+
data&.dig(:object_key) || data&.dig("object_key")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def changes
|
|
32
|
+
changes_data = data&.dig(:changes) || data&.dig("changes")
|
|
33
|
+
changes_data.nil? || changes_data.empty? ? nil : changes_data
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Helper method to get the resource object
|
|
37
|
+
def resource
|
|
38
|
+
return data[resource_type] if data && data.key?(resource_type)
|
|
39
|
+
nil
|
|
40
|
+
end
|
|
41
|
+
end
|
|
20
42
|
end
|
data/lib/activeproject.rb
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "zeitwerk"
|
|
2
4
|
require "concurrent"
|
|
3
5
|
require_relative "active_project/errors"
|
|
4
6
|
require_relative "active_project/version"
|
|
7
|
+
require_relative "active_project/railtie" if defined?(Rails::Railtie)
|
|
8
|
+
require "active_support/concern"
|
|
9
|
+
require "active_support/core_ext/class/attribute"
|
|
5
10
|
|
|
6
11
|
module ActiveProject
|
|
7
12
|
class << self
|
|
@@ -64,19 +69,18 @@ module ActiveProject
|
|
|
64
69
|
raise ArgumentError, error_message
|
|
65
70
|
end
|
|
66
71
|
|
|
67
|
-
adapter_class_name = "ActiveProject::Adapters::#{adapter_type.to_s.
|
|
72
|
+
adapter_class_name = "ActiveProject::Adapters::#{adapter_type.to_s.classify}Adapter"
|
|
68
73
|
|
|
69
74
|
begin
|
|
70
75
|
require "active_project/adapters/#{adapter_type}_adapter"
|
|
71
|
-
rescue LoadError
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
raise LoadError, error_message
|
|
76
|
+
rescue LoadError
|
|
77
|
+
raise LoadError, "Could not load adapter '#{adapter_type}'. " \
|
|
78
|
+
"Expected class #{adapter_class_name} in adapters/#{adapter_type}_adapter.rb"
|
|
75
79
|
end
|
|
76
80
|
|
|
77
81
|
begin
|
|
78
82
|
adapter_class = Object.const_get(adapter_class_name)
|
|
79
|
-
rescue NameError
|
|
83
|
+
rescue NameError
|
|
80
84
|
error_message = "Could not find adapter class #{adapter_class_name}.\n"
|
|
81
85
|
error_message += "Make sure you have defined the class correctly in active_project/adapters/#{adapter_type}_adapter.rb"
|
|
82
86
|
raise NameError, error_message
|
|
@@ -110,4 +114,5 @@ loader.inflector.inflect("activeproject" => "ActiveProject")
|
|
|
110
114
|
loader.do_not_eager_load("#{__dir__}/active_project/adapters")
|
|
111
115
|
loader.ignore("#{__dir__}/active_project/errors.rb")
|
|
112
116
|
loader.ignore("#{__dir__}/active_project/version.rb")
|
|
117
|
+
loader.ignore("#{__dir__}/active_project/railtie.rb")
|
|
113
118
|
loader.setup
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activeproject
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Abdelkader Boudih
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: activesupport
|
|
@@ -30,6 +29,62 @@ dependencies:
|
|
|
30
29
|
- - "<"
|
|
31
30
|
- !ruby/object:Gem::Version
|
|
32
31
|
version: '9.0'
|
|
32
|
+
- !ruby/object:Gem::Dependency
|
|
33
|
+
name: async
|
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - ">="
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '2.35'
|
|
39
|
+
type: :runtime
|
|
40
|
+
prerelease: false
|
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
42
|
+
requirements:
|
|
43
|
+
- - ">="
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '2.35'
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: async-http
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '0.92'
|
|
53
|
+
type: :runtime
|
|
54
|
+
prerelease: false
|
|
55
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
56
|
+
requirements:
|
|
57
|
+
- - ">="
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: '0.92'
|
|
60
|
+
- !ruby/object:Gem::Dependency
|
|
61
|
+
name: async-http-faraday
|
|
62
|
+
requirement: !ruby/object:Gem::Requirement
|
|
63
|
+
requirements:
|
|
64
|
+
- - ">="
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: '0.22'
|
|
67
|
+
type: :runtime
|
|
68
|
+
prerelease: false
|
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
70
|
+
requirements:
|
|
71
|
+
- - ">="
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: '0.22'
|
|
74
|
+
- !ruby/object:Gem::Dependency
|
|
75
|
+
name: concurrent-ruby
|
|
76
|
+
requirement: !ruby/object:Gem::Requirement
|
|
77
|
+
requirements:
|
|
78
|
+
- - ">="
|
|
79
|
+
- !ruby/object:Gem::Version
|
|
80
|
+
version: '1.2'
|
|
81
|
+
type: :runtime
|
|
82
|
+
prerelease: false
|
|
83
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
84
|
+
requirements:
|
|
85
|
+
- - ">="
|
|
86
|
+
- !ruby/object:Gem::Version
|
|
87
|
+
version: '1.2'
|
|
33
88
|
- !ruby/object:Gem::Dependency
|
|
34
89
|
name: faraday
|
|
35
90
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -58,6 +113,20 @@ dependencies:
|
|
|
58
113
|
- - ">="
|
|
59
114
|
- !ruby/object:Gem::Version
|
|
60
115
|
version: '0'
|
|
116
|
+
- !ruby/object:Gem::Dependency
|
|
117
|
+
name: async-safe
|
|
118
|
+
requirement: !ruby/object:Gem::Requirement
|
|
119
|
+
requirements:
|
|
120
|
+
- - ">="
|
|
121
|
+
- !ruby/object:Gem::Version
|
|
122
|
+
version: '0'
|
|
123
|
+
type: :development
|
|
124
|
+
prerelease: false
|
|
125
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
126
|
+
requirements:
|
|
127
|
+
- - ">="
|
|
128
|
+
- !ruby/object:Gem::Version
|
|
129
|
+
version: '0'
|
|
61
130
|
- !ruby/object:Gem::Dependency
|
|
62
131
|
name: mocha
|
|
63
132
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -92,6 +161,26 @@ files:
|
|
|
92
161
|
- lib/active_project/adapters/basecamp/projects.rb
|
|
93
162
|
- lib/active_project/adapters/basecamp/webhooks.rb
|
|
94
163
|
- lib/active_project/adapters/basecamp_adapter.rb
|
|
164
|
+
- lib/active_project/adapters/fizzy/columns.rb
|
|
165
|
+
- lib/active_project/adapters/fizzy/comments.rb
|
|
166
|
+
- lib/active_project/adapters/fizzy/connection.rb
|
|
167
|
+
- lib/active_project/adapters/fizzy/issues.rb
|
|
168
|
+
- lib/active_project/adapters/fizzy/projects.rb
|
|
169
|
+
- lib/active_project/adapters/fizzy_adapter.rb
|
|
170
|
+
- lib/active_project/adapters/github_project.rb
|
|
171
|
+
- lib/active_project/adapters/github_project/comments.rb
|
|
172
|
+
- lib/active_project/adapters/github_project/connection.rb
|
|
173
|
+
- lib/active_project/adapters/github_project/helpers.rb
|
|
174
|
+
- lib/active_project/adapters/github_project/issues.rb
|
|
175
|
+
- lib/active_project/adapters/github_project/projects.rb
|
|
176
|
+
- lib/active_project/adapters/github_project/webhooks.rb
|
|
177
|
+
- lib/active_project/adapters/github_project_adapter.rb
|
|
178
|
+
- lib/active_project/adapters/github_repo/connection.rb
|
|
179
|
+
- lib/active_project/adapters/github_repo/issues.rb
|
|
180
|
+
- lib/active_project/adapters/github_repo/projects.rb
|
|
181
|
+
- lib/active_project/adapters/github_repo/webhooks.rb
|
|
182
|
+
- lib/active_project/adapters/github_repo_adapter.rb
|
|
183
|
+
- lib/active_project/adapters/jira/attribute_normalizer.rb
|
|
95
184
|
- lib/active_project/adapters/jira/comments.rb
|
|
96
185
|
- lib/active_project/adapters/jira/connection.rb
|
|
97
186
|
- lib/active_project/adapters/jira/issues.rb
|
|
@@ -107,16 +196,30 @@ files:
|
|
|
107
196
|
- lib/active_project/adapters/trello/webhooks.rb
|
|
108
197
|
- lib/active_project/adapters/trello_adapter.rb
|
|
109
198
|
- lib/active_project/association_proxy.rb
|
|
199
|
+
- lib/active_project/async.rb
|
|
110
200
|
- lib/active_project/configuration.rb
|
|
111
201
|
- lib/active_project/configurations/base_adapter_configuration.rb
|
|
202
|
+
- lib/active_project/configurations/basecamp_configuration.rb
|
|
203
|
+
- lib/active_project/configurations/fizzy_configuration.rb
|
|
204
|
+
- lib/active_project/configurations/github_configuration.rb
|
|
205
|
+
- lib/active_project/configurations/jira_configuration.rb
|
|
112
206
|
- lib/active_project/configurations/trello_configuration.rb
|
|
207
|
+
- lib/active_project/connections/base.rb
|
|
208
|
+
- lib/active_project/connections/graph_ql.rb
|
|
209
|
+
- lib/active_project/connections/http_client.rb
|
|
210
|
+
- lib/active_project/connections/pagination.rb
|
|
211
|
+
- lib/active_project/connections/rest.rb
|
|
212
|
+
- lib/active_project/error_mapper.rb
|
|
113
213
|
- lib/active_project/errors.rb
|
|
214
|
+
- lib/active_project/railtie.rb
|
|
114
215
|
- lib/active_project/resource_factory.rb
|
|
115
216
|
- lib/active_project/resources/base_resource.rb
|
|
116
217
|
- lib/active_project/resources/comment.rb
|
|
117
218
|
- lib/active_project/resources/issue.rb
|
|
219
|
+
- lib/active_project/resources/persistable_resource.rb
|
|
118
220
|
- lib/active_project/resources/project.rb
|
|
119
221
|
- lib/active_project/resources/user.rb
|
|
222
|
+
- lib/active_project/status_mapper.rb
|
|
120
223
|
- lib/active_project/version.rb
|
|
121
224
|
- lib/active_project/webhook_event.rb
|
|
122
225
|
- lib/activeproject.rb
|
|
@@ -126,7 +229,6 @@ licenses:
|
|
|
126
229
|
metadata:
|
|
127
230
|
homepage_uri: https://github.com/seuros/active_project
|
|
128
231
|
source_code_uri: https://github.com/seuros/active_project
|
|
129
|
-
post_install_message:
|
|
130
232
|
rdoc_options: []
|
|
131
233
|
require_paths:
|
|
132
234
|
- lib
|
|
@@ -141,8 +243,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
141
243
|
- !ruby/object:Gem::Version
|
|
142
244
|
version: '0'
|
|
143
245
|
requirements: []
|
|
144
|
-
rubygems_version:
|
|
145
|
-
signing_key:
|
|
246
|
+
rubygems_version: 4.0.1
|
|
146
247
|
specification_version: 4
|
|
147
248
|
summary: A standardized Ruby interface for multiple project management APIs (Jira,
|
|
148
249
|
Basecamp, Trello, etc.).
|