workato-connector-sdk 0.1.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 +7 -0
- data/LICENSE.md +20 -0
- data/README.md +1093 -0
- data/exe/workato +5 -0
- data/lib/workato/cli/edit_command.rb +71 -0
- data/lib/workato/cli/exec_command.rb +191 -0
- data/lib/workato/cli/generate_command.rb +105 -0
- data/lib/workato/cli/generators/connector_generator.rb +94 -0
- data/lib/workato/cli/generators/master_key_generator.rb +56 -0
- data/lib/workato/cli/main.rb +142 -0
- data/lib/workato/cli/push_command.rb +208 -0
- data/lib/workato/connector/sdk/account_properties.rb +60 -0
- data/lib/workato/connector/sdk/action.rb +88 -0
- data/lib/workato/connector/sdk/block_invocation_refinements.rb +30 -0
- data/lib/workato/connector/sdk/connector.rb +230 -0
- data/lib/workato/connector/sdk/dsl/account_property.rb +15 -0
- data/lib/workato/connector/sdk/dsl/call.rb +17 -0
- data/lib/workato/connector/sdk/dsl/error.rb +15 -0
- data/lib/workato/connector/sdk/dsl/http.rb +60 -0
- data/lib/workato/connector/sdk/dsl/lookup_table.rb +15 -0
- data/lib/workato/connector/sdk/dsl/time.rb +21 -0
- data/lib/workato/connector/sdk/dsl/workato_code_lib.rb +105 -0
- data/lib/workato/connector/sdk/dsl/workato_schema.rb +15 -0
- data/lib/workato/connector/sdk/dsl.rb +46 -0
- data/lib/workato/connector/sdk/errors.rb +30 -0
- data/lib/workato/connector/sdk/lookup_tables.rb +62 -0
- data/lib/workato/connector/sdk/object_definitions.rb +74 -0
- data/lib/workato/connector/sdk/operation.rb +217 -0
- data/lib/workato/connector/sdk/request.rb +399 -0
- data/lib/workato/connector/sdk/settings.rb +130 -0
- data/lib/workato/connector/sdk/summarize.rb +61 -0
- data/lib/workato/connector/sdk/trigger.rb +96 -0
- data/lib/workato/connector/sdk/version.rb +9 -0
- data/lib/workato/connector/sdk/workato_schemas.rb +37 -0
- data/lib/workato/connector/sdk/xml.rb +35 -0
- data/lib/workato/connector/sdk.rb +58 -0
- data/lib/workato/extension/array.rb +124 -0
- data/lib/workato/extension/case_sensitive_headers.rb +51 -0
- data/lib/workato/extension/currency.rb +15 -0
- data/lib/workato/extension/date.rb +14 -0
- data/lib/workato/extension/enumerable.rb +55 -0
- data/lib/workato/extension/extra_chain_cert.rb +40 -0
- data/lib/workato/extension/hash.rb +13 -0
- data/lib/workato/extension/integer.rb +17 -0
- data/lib/workato/extension/nil_class.rb +17 -0
- data/lib/workato/extension/object.rb +38 -0
- data/lib/workato/extension/phone.rb +14 -0
- data/lib/workato/extension/string.rb +268 -0
- data/lib/workato/extension/symbol.rb +13 -0
- data/lib/workato/extension/time.rb +13 -0
- data/lib/workato/testing/vcr_encrypted_cassette_serializer.rb +38 -0
- data/lib/workato/testing/vcr_multipart_body_matcher.rb +32 -0
- data/lib/workato-connector-sdk.rb +3 -0
- data/templates/.rspec.erb +3 -0
- data/templates/Gemfile.erb +10 -0
- data/templates/connector.rb.erb +37 -0
- data/templates/spec/action_spec.rb.erb +36 -0
- data/templates/spec/connector_spec.rb.erb +18 -0
- data/templates/spec/method_spec.rb.erb +13 -0
- data/templates/spec/object_definition_spec.rb.erb +18 -0
- data/templates/spec/pick_list_spec.rb.erb +13 -0
- data/templates/spec/spec_helper.rb.erb +38 -0
- data/templates/spec/trigger_spec.rb.erb +61 -0
- metadata +372 -0
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './operation'
|
4
|
+
require_relative './block_invocation_refinements'
|
5
|
+
|
6
|
+
module Workato
|
7
|
+
module Connector
|
8
|
+
module Sdk
|
9
|
+
class Action < Operation
|
10
|
+
using BlockInvocationRefinements
|
11
|
+
|
12
|
+
RETRY_DEFAULT_CODES = [429, 500, 502, 503, 504, 507].freeze
|
13
|
+
RETRY_DEFAULT_METHODS = %i[get head].freeze
|
14
|
+
RETRY_DELAY = 5.seconds
|
15
|
+
MAX_RETRIES = 3
|
16
|
+
|
17
|
+
def initialize(action:, connection: {}, methods: {}, settings: {}, object_definitions: nil)
|
18
|
+
super(
|
19
|
+
operation: action,
|
20
|
+
connection: connection,
|
21
|
+
methods: methods,
|
22
|
+
settings: settings,
|
23
|
+
object_definitions: object_definitions
|
24
|
+
)
|
25
|
+
|
26
|
+
initialize_retry
|
27
|
+
end
|
28
|
+
|
29
|
+
def execute(settings = nil, input = {}, extended_input_schema = [], extended_output_schema = [], &block)
|
30
|
+
raise InvalidDefinitionError, "'execute' block is required for action" unless block || action[:execute]
|
31
|
+
|
32
|
+
super(settings, input, extended_input_schema, extended_output_schema, &(block || action[:execute]))
|
33
|
+
rescue RequestError => e
|
34
|
+
raise e unless retry?(e)
|
35
|
+
|
36
|
+
@retries_left -= 1
|
37
|
+
sleep(RETRY_DELAY) && retry
|
38
|
+
end
|
39
|
+
|
40
|
+
def checkpoint!(continue:, temp_output: nil)
|
41
|
+
raise NotImplementedError
|
42
|
+
end
|
43
|
+
|
44
|
+
def reinvoke_after(seconds:, continue:, temp_output: nil)
|
45
|
+
raise NotImplementedError
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def retry_on_response
|
51
|
+
Array(action[:retry_on_response])
|
52
|
+
end
|
53
|
+
|
54
|
+
def retry_on_request
|
55
|
+
Array(action[:retry_on_request])
|
56
|
+
end
|
57
|
+
|
58
|
+
def max_retries
|
59
|
+
action[:max_retries]
|
60
|
+
end
|
61
|
+
|
62
|
+
def initialize_retry
|
63
|
+
@retries_left = 0
|
64
|
+
return if retry_on_response.blank?
|
65
|
+
|
66
|
+
@retry_codes = []
|
67
|
+
@retry_matchers = []
|
68
|
+
retry_on_response.each { |m| m.is_a?(::Integer) ? @retry_codes << m : @retry_matchers << m }
|
69
|
+
@retry_codes = RETRY_DEFAULT_CODES if @retry_codes.empty?
|
70
|
+
@retry_methods = (retry_on_request.presence || RETRY_DEFAULT_METHODS).map(&:to_s).map(&:downcase)
|
71
|
+
@retries_left = [[max_retries.is_a?(::Integer) && max_retries || MAX_RETRIES, MAX_RETRIES].min, 0].max
|
72
|
+
end
|
73
|
+
|
74
|
+
def retry?(exception)
|
75
|
+
return unless @retries_left.positive?
|
76
|
+
return unless @retry_codes.include?(exception.code.to_i)
|
77
|
+
return unless @retry_matchers.empty? || @retry_matchers.any? do |m|
|
78
|
+
m === exception.message || m === exception.response
|
79
|
+
end
|
80
|
+
|
81
|
+
@retry_methods.include?(exception.method.to_s.downcase)
|
82
|
+
end
|
83
|
+
|
84
|
+
alias action operation
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Workato
|
4
|
+
module Connector
|
5
|
+
module Sdk
|
6
|
+
# match proc's arguments, even if it's a lambda.
|
7
|
+
module BlockInvocationRefinements
|
8
|
+
module CallRefinement
|
9
|
+
def call(*args, &block)
|
10
|
+
super(*args.take(parameters.length), &block)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
refine Proc do
|
15
|
+
prepend CallRefinement
|
16
|
+
end
|
17
|
+
|
18
|
+
module InstanceExecRefinement
|
19
|
+
def instance_exec(*args, &block)
|
20
|
+
super(*args.take(block.parameters.length), &block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
refine BasicObject do
|
25
|
+
prepend InstanceExecRefinement
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,230 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Workato
|
4
|
+
module Connector
|
5
|
+
module Sdk
|
6
|
+
class Connector
|
7
|
+
attr_reader :source
|
8
|
+
|
9
|
+
def self.from_file(path_to_source_code = DEFAULT_CONNECTOR_PATH, settings = {})
|
10
|
+
new(eval(File.read(path_to_source_code), binding, path_to_source_code), settings) # rubocop:disable Security/Eval
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(definition, settings = {})
|
14
|
+
@source = definition.with_indifferent_access
|
15
|
+
@settings = settings.with_indifferent_access
|
16
|
+
@connection_source = @source[:connection] || {}
|
17
|
+
@methods_source = @source[:methods] || {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def title
|
21
|
+
@source[:title]
|
22
|
+
end
|
23
|
+
|
24
|
+
def actions
|
25
|
+
@actions ||= ActionsProxy.new(
|
26
|
+
actions: source[:actions].presence || {},
|
27
|
+
object_definitions: object_definitions,
|
28
|
+
methods: methods_source,
|
29
|
+
connection: connection_source,
|
30
|
+
settings: settings
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def methods
|
35
|
+
@methods ||= MethodsProxy.new(
|
36
|
+
methods: methods_source,
|
37
|
+
connection: connection_source,
|
38
|
+
settings: settings
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test(settings = nil)
|
43
|
+
@test ||= Action.new(
|
44
|
+
action: {
|
45
|
+
execute: source[:test]
|
46
|
+
},
|
47
|
+
methods: methods_source,
|
48
|
+
connection: connection_source,
|
49
|
+
settings: send(:settings)
|
50
|
+
).execute(settings)
|
51
|
+
end
|
52
|
+
|
53
|
+
def triggers
|
54
|
+
@triggers ||= TriggersProxy.new(
|
55
|
+
triggers: source[:triggers].presence || {},
|
56
|
+
object_definitions: object_definitions,
|
57
|
+
methods: methods_source,
|
58
|
+
connection: connection_source,
|
59
|
+
settings: settings
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
def object_definitions
|
64
|
+
@object_definitions ||= ObjectDefinitions.new(
|
65
|
+
object_definitions: source[:object_definitions].presence || {},
|
66
|
+
methods: methods_source,
|
67
|
+
connection: connection_source,
|
68
|
+
settings: settings
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
def pick_lists
|
73
|
+
@pick_lists ||= PickListsProxy.new(
|
74
|
+
pick_lists: source[:pick_lists].presence || {},
|
75
|
+
methods: methods_source,
|
76
|
+
connection: connection_source,
|
77
|
+
settings: settings
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
attr_reader :methods_source,
|
84
|
+
:connection_source,
|
85
|
+
:settings
|
86
|
+
end
|
87
|
+
|
88
|
+
class ActionsProxy
|
89
|
+
def initialize(actions:, object_definitions:, methods:, connection:, settings:)
|
90
|
+
@methods = methods
|
91
|
+
@connection = connection
|
92
|
+
@object_definitions = object_definitions
|
93
|
+
@settings = settings
|
94
|
+
define_action_methods(actions)
|
95
|
+
end
|
96
|
+
|
97
|
+
def [](action)
|
98
|
+
public_send(action)
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
attr_reader :methods,
|
104
|
+
:connection,
|
105
|
+
:object_definitions,
|
106
|
+
:settings
|
107
|
+
|
108
|
+
def define_action_methods(actions)
|
109
|
+
actions.each do |action, definition|
|
110
|
+
define_singleton_method(action) do
|
111
|
+
@actions ||= {}
|
112
|
+
@actions[action] ||= Action.new(
|
113
|
+
action: definition,
|
114
|
+
object_definitions: object_definitions,
|
115
|
+
methods: methods,
|
116
|
+
connection: connection,
|
117
|
+
settings: settings
|
118
|
+
)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class MethodsProxy
|
125
|
+
def initialize(methods:, connection:, settings:)
|
126
|
+
@methods = methods
|
127
|
+
@connection = connection
|
128
|
+
@settings = settings
|
129
|
+
define_action_methods
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
attr_reader :methods,
|
135
|
+
:connection,
|
136
|
+
:settings
|
137
|
+
|
138
|
+
def define_action_methods
|
139
|
+
methods.each do |method, _definition|
|
140
|
+
define_singleton_method(method) do |*args|
|
141
|
+
@actions ||= {}
|
142
|
+
@actions[method] ||= Action.new(
|
143
|
+
action: {
|
144
|
+
execute: -> { call(method, *args) }
|
145
|
+
},
|
146
|
+
methods: methods,
|
147
|
+
connection: connection,
|
148
|
+
settings: settings
|
149
|
+
)
|
150
|
+
@actions[method].execute
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
class PickListsProxy
|
157
|
+
def initialize(pick_lists:, methods:, connection:, settings:)
|
158
|
+
@methods = methods
|
159
|
+
@connection = connection
|
160
|
+
@settings = settings
|
161
|
+
define_action_methods(pick_lists)
|
162
|
+
end
|
163
|
+
|
164
|
+
private
|
165
|
+
|
166
|
+
attr_reader :methods,
|
167
|
+
:connection,
|
168
|
+
:settings
|
169
|
+
|
170
|
+
def define_action_methods(pick_lists)
|
171
|
+
pick_lists.each do |pick_list, pick_list_proc|
|
172
|
+
define_singleton_method(pick_list) do |settings = nil, args = {}|
|
173
|
+
@actions ||= {}
|
174
|
+
@actions[pick_list] ||= Action.new(
|
175
|
+
action: {
|
176
|
+
execute: lambda do |connection, input|
|
177
|
+
case pick_list_proc.parameters.length
|
178
|
+
when 0
|
179
|
+
instance_exec(&pick_list_proc)
|
180
|
+
when 1
|
181
|
+
instance_exec(connection, &pick_list_proc)
|
182
|
+
else
|
183
|
+
instance_exec(connection, **input.symbolize_keys, &pick_list_proc)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
},
|
187
|
+
methods: methods,
|
188
|
+
connection: connection,
|
189
|
+
settings: send(:settings)
|
190
|
+
)
|
191
|
+
@actions[pick_list].execute(settings, args)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
class TriggersProxy
|
198
|
+
def initialize(triggers:, object_definitions:, methods:, connection:, settings:)
|
199
|
+
@methods = methods
|
200
|
+
@connection = connection
|
201
|
+
@object_definitions = object_definitions
|
202
|
+
@settings = settings
|
203
|
+
@triggers = {}
|
204
|
+
define_trigger_methods(triggers)
|
205
|
+
end
|
206
|
+
|
207
|
+
private
|
208
|
+
|
209
|
+
attr_reader :methods,
|
210
|
+
:connection,
|
211
|
+
:object_definitions,
|
212
|
+
:settings
|
213
|
+
|
214
|
+
def define_trigger_methods(triggers)
|
215
|
+
triggers.each do |trigger, definition|
|
216
|
+
define_singleton_method(trigger) do
|
217
|
+
@triggers[trigger] ||= Trigger.new(
|
218
|
+
trigger: definition,
|
219
|
+
object_definitions: object_definitions,
|
220
|
+
methods: methods,
|
221
|
+
connection: connection,
|
222
|
+
settings: settings
|
223
|
+
)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Workato
|
4
|
+
module Connector
|
5
|
+
module Sdk
|
6
|
+
module Dsl
|
7
|
+
module Call
|
8
|
+
def call(method, *args)
|
9
|
+
raise InvalidDefinitionError, "method '#{method}' does not exists" unless @_methods[method]
|
10
|
+
|
11
|
+
instance_exec(*args, &@_methods[method])
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Workato
|
4
|
+
module Connector
|
5
|
+
module Sdk
|
6
|
+
module Dsl
|
7
|
+
# https://docs.workato.com/developing-connectors/sdk/sdk-reference/http.html#http-methods
|
8
|
+
module HTTP
|
9
|
+
def get(url, params = {})
|
10
|
+
http_request(url, method: 'GET').params(params).response_format_json
|
11
|
+
end
|
12
|
+
|
13
|
+
def options(url, params = {})
|
14
|
+
http_request(url, method: 'OPTIONS').params(params).response_format_json
|
15
|
+
end
|
16
|
+
|
17
|
+
def head(url, params = {})
|
18
|
+
http_request(url, method: 'HEAD').params(params).response_format_json
|
19
|
+
end
|
20
|
+
|
21
|
+
def post(url, payload = nil)
|
22
|
+
http_request(url, method: 'POST').payload(payload).format_json
|
23
|
+
end
|
24
|
+
|
25
|
+
def patch(url, payload = nil)
|
26
|
+
http_request(url, method: 'PATCH').payload(payload).format_json
|
27
|
+
end
|
28
|
+
|
29
|
+
def put(url, payload = nil)
|
30
|
+
http_request(url, method: 'PUT').payload(payload).format_json
|
31
|
+
end
|
32
|
+
|
33
|
+
def delete(url, payload = nil)
|
34
|
+
http_request(url, method: 'DELETE').payload(payload).format_json
|
35
|
+
end
|
36
|
+
|
37
|
+
def copy(url, payload = nil)
|
38
|
+
http_request(url, method: 'COPY').payload(payload).format_json
|
39
|
+
end
|
40
|
+
|
41
|
+
def move(url, payload = nil)
|
42
|
+
http_request(url, method: 'MOVE').payload(payload).format_json
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def http_request(url, method:)
|
48
|
+
Request.new(
|
49
|
+
url,
|
50
|
+
method: method,
|
51
|
+
connection: connection,
|
52
|
+
settings: settings,
|
53
|
+
action: self
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|