workato-connector-sdk 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -11
  3. data/lib/workato/cli/edit_command.rb +4 -3
  4. data/lib/workato/cli/exec_command.rb +27 -35
  5. data/lib/workato/cli/generate_command.rb +1 -0
  6. data/lib/workato/cli/generators/connector_generator.rb +1 -0
  7. data/lib/workato/cli/generators/master_key_generator.rb +1 -0
  8. data/lib/workato/cli/main.rb +44 -11
  9. data/lib/workato/cli/oauth2_command.rb +6 -5
  10. data/lib/workato/cli/push_command.rb +8 -5
  11. data/lib/workato/cli/schema_command.rb +6 -7
  12. data/lib/workato/connector/sdk/account_properties.rb +1 -0
  13. data/lib/workato/connector/sdk/action.rb +78 -20
  14. data/lib/workato/connector/sdk/block_invocation_refinements.rb +1 -0
  15. data/lib/workato/connector/sdk/connection.rb +204 -44
  16. data/lib/workato/connector/sdk/connector.rb +200 -65
  17. data/lib/workato/connector/sdk/dsl/account_property.rb +1 -0
  18. data/lib/workato/connector/sdk/dsl/aws.rb +23 -27
  19. data/lib/workato/connector/sdk/dsl/call.rb +6 -2
  20. data/lib/workato/connector/sdk/dsl/error.rb +1 -0
  21. data/lib/workato/connector/sdk/dsl/http.rb +2 -7
  22. data/lib/workato/connector/sdk/dsl/lookup_table.rb +1 -0
  23. data/lib/workato/connector/sdk/dsl/time.rb +6 -0
  24. data/lib/workato/connector/sdk/dsl/workato_code_lib.rb +38 -0
  25. data/lib/workato/connector/sdk/dsl/workato_schema.rb +1 -0
  26. data/lib/workato/connector/sdk/dsl.rb +19 -4
  27. data/lib/workato/connector/sdk/errors.rb +62 -4
  28. data/lib/workato/connector/sdk/lookup_tables.rb +1 -0
  29. data/lib/workato/connector/sdk/object_definitions.rb +22 -17
  30. data/lib/workato/connector/sdk/operation.rb +127 -88
  31. data/lib/workato/connector/sdk/request.rb +95 -31
  32. data/lib/workato/connector/sdk/schema/field/array.rb +1 -0
  33. data/lib/workato/connector/sdk/schema/field/convertors.rb +1 -0
  34. data/lib/workato/connector/sdk/schema/field/date.rb +1 -0
  35. data/lib/workato/connector/sdk/schema/field/date_time.rb +1 -0
  36. data/lib/workato/connector/sdk/schema/field/integer.rb +1 -0
  37. data/lib/workato/connector/sdk/schema/field/number.rb +1 -0
  38. data/lib/workato/connector/sdk/schema/field/object.rb +1 -0
  39. data/lib/workato/connector/sdk/schema/field/string.rb +1 -0
  40. data/lib/workato/connector/sdk/schema/type/time.rb +1 -0
  41. data/lib/workato/connector/sdk/schema/type/unicode_string.rb +1 -0
  42. data/lib/workato/connector/sdk/schema.rb +1 -0
  43. data/lib/workato/connector/sdk/settings.rb +9 -4
  44. data/lib/workato/connector/sdk/summarize.rb +3 -2
  45. data/lib/workato/connector/sdk/trigger.rb +106 -10
  46. data/lib/workato/connector/sdk/version.rb +2 -1
  47. data/lib/workato/connector/sdk/workato_schemas.rb +1 -0
  48. data/lib/workato/connector/sdk/xml.rb +1 -0
  49. data/lib/workato/connector/sdk.rb +8 -0
  50. data/lib/workato/extension/array.rb +1 -0
  51. data/lib/workato/extension/case_sensitive_headers.rb +1 -0
  52. data/lib/workato/extension/currency.rb +2 -1
  53. data/lib/workato/extension/date.rb +1 -0
  54. data/lib/workato/extension/enumerable.rb +1 -0
  55. data/lib/workato/extension/extra_chain_cert.rb +1 -0
  56. data/lib/workato/extension/hash.rb +1 -0
  57. data/lib/workato/extension/integer.rb +1 -0
  58. data/lib/workato/extension/nil_class.rb +1 -0
  59. data/lib/workato/extension/object.rb +1 -0
  60. data/lib/workato/extension/phone.rb +2 -1
  61. data/lib/workato/extension/string.rb +6 -2
  62. data/lib/workato/extension/symbol.rb +1 -0
  63. data/lib/workato/extension/time.rb +1 -0
  64. data/lib/workato/testing/vcr_encrypted_cassette_serializer.rb +5 -0
  65. data/lib/workato/testing/vcr_multipart_body_matcher.rb +1 -0
  66. data/lib/workato/utilities/encoding.rb +57 -0
  67. data/lib/workato/web/app.rb +1 -0
  68. data/lib/workato-connector-sdk.rb +1 -0
  69. metadata +88 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 70241ed06aeae85f14f775ff2366ec4edbc54322aa034f0931dd987e9fd1fb2c
4
- data.tar.gz: 1a99f10c8c3c4dfe036e591cddb81504980586b0fb48cd319f7cfd5e510a1512
3
+ metadata.gz: 053e48199f2b1406ef47a84fb43d7b7d0cc74d74ce0f1f1b650c01fc422bc683
4
+ data.tar.gz: e2155ca61c45230234b105ff0f4ab033205c86b49b35838d88e8a8e473a957b3
5
5
  SHA512:
6
- metadata.gz: b74c573b4e5c00509b955a14477a132ce01cfa6824382f21e50646bc10ce5ee44f3f2bf9bbf06ad7e565ddedfd0cce8c5017ae31e28e3b470164600abbb29d6d
7
- data.tar.gz: 1f1139718e2f18faa63087e3782c42a0bb0b3bae237086044873283bad8128f9ce42b26b3738d0a3a8ff22e529180a6d8df821f7c7eee9da68b85d3b97098340
6
+ metadata.gz: 4d34393bda1fc5eef5e138c7e742a2a05a7c1ced8fb5a4a8969a1770473c4534cf015c7096cf17a18eb69c669301ca8761ff51a88b3ee8a04ad4550467a23588
7
+ data.tar.gz: b293f65e21f45ef2bab573d687cd12cd77981a7375bec619ce45561ead9e96f895f633e65910dad7226213daacb38b95453c890b96e7b7a957b5085e5055ff94
data/README.md CHANGED
@@ -248,8 +248,9 @@ Usage:
248
248
  workato edit <PATH>
249
249
 
250
250
  Options:
251
- -k, [--key=KEY] # Path to file with encrypt/decrypt key. NOTE: key from WORKATO_CONNECTOR_MASTER_KEY has higher priority
252
- [--verbose], [--no-verbose]
251
+ -k, [--key=KEY] # Path to file with encrypt/decrypt key.
252
+ # NOTE: key from WORKATO_CONNECTOR_MASTER_KEY has higher priority
253
+ [--verbose], [--no-verbose]
253
254
 
254
255
  Edit encrypted file, e.g. settings.yaml.enc
255
256
  ```
@@ -261,6 +262,7 @@ Edit encrypted file, e.g. settings.yaml.enc
261
262
  ### 3.3 workato exec
262
263
  ```
263
264
  workato help exec
265
+
264
266
  Usage:
265
267
  workato exec <PATH>
266
268
 
@@ -268,7 +270,8 @@ Options:
268
270
  -c, [--connector=CONNECTOR] # Path to connector source code
269
271
  -s, [--settings=SETTINGS] # Path to plain or encrypted file with connection configs, passwords, tokens, secrets etc
270
272
  -n, [--connection=CONNECTION] # Connection name if settings file contains multiple settings
271
- -k, [--key=KEY] # Path to file with encrypt/decrypt key. NOTE: key from WORKATO_CONNECTOR_MASTER_KEY has higher priority
273
+ -k, [--key=KEY] # Path to file with encrypt/decrypt key.
274
+ # NOTE: key from WORKATO_CONNECTOR_MASTER_KEY has higher priority
272
275
  -i, [--input=INPUT] # Path to file with input JSON
273
276
  [--closure=CLOSURE] # Path to file with next poll closure JSON
274
277
  [--continue=CONTINUE] # Path to file with next multistep action continue closure JSON
@@ -286,7 +289,7 @@ Options:
286
289
  [--redirect-url=REDIRECT_URL] # OAuth2 callback url
287
290
  [--refresh-token=REFRESH_TOKEN] # OAuth2 refresh token
288
291
  [--debug], [--no-debug]
289
- [--verbose], [--no-verbose]
292
+ [--verbose], [--no-verbose]
290
293
 
291
294
  Description:
292
295
  The 'workato exec' executes connector's lambda block at <PATH>. Lambda's parameters can be provided if needed, see options part.
@@ -394,13 +397,14 @@ Options:
394
397
  -c, [--connector=CONNECTOR] # Path to connector source code
395
398
  -s, [--settings=SETTINGS] # Path to plain or encrypted file with connection configs, passwords, tokens, secrets etc
396
399
  -n, [--connection=CONNECTION] # Connection name if settings file contains multiple settings
397
- -k, [--key=KEY] # Path to file with encrypt/decrypt key. NOTE: key from WORKATO_CONNECTOR_MASTER_KEY has higher priority
400
+ -k, [--key=KEY] # Path to file with encrypt/decrypt key.
401
+ # NOTE: key from WORKATO_CONNECTOR_MASTER_KEY has higher priority
398
402
  [--port=PORT] # Listen requests on specific port
399
403
  # Default: 45555
400
404
  [--ip=IP] # Listen requests on specific interface
401
405
  # Default: 127.0.0.1
402
406
  [--https], [--no-https] # Start HTTPS server using self-signed certificate
403
- [--verbose], [--no-verbose]
407
+ [--verbose], [--no-verbose]
404
408
 
405
409
  Implements OAuth Authorization Code flow
406
410
  ```
@@ -420,11 +424,13 @@ Options:
420
424
  -l, [--logo=LOGO] # Path to connector logo: png or jpeg file
421
425
  -n, [--notes=NOTES] # Release notes
422
426
  -c, [--connector=CONNECTOR] # Path to connector source code
423
- [--api-email=API_EMAIL] # Email for accessing Workato API or set WORKATO_API_EMAIL environment variable
424
- [--api-token=API_TOKEN] # Token for accessing Workato API or set WORKATO_API_TOKEN environment variable
425
- [--environment=ENVIRONMENT] # Server to push connector code to
426
- # Default: live
427
- # Possible values: preview, preview-eu, live, live-eu
427
+ [--api-email=API_EMAIL] # Email for accessing Workato API.
428
+ # If present overrides value from WORKATO_API_EMAIL environment variable.
429
+ [--api-token=API_TOKEN] # Token for accessing Workato API.
430
+ # If present overrides value from WORKATO_API_TOKEN environment variable.
431
+ [--environment=ENVIRONMENT] # Data center specific URL to push connector code.
432
+ # If present overrides value from WORKATO_BASE_URL environment variable.
433
+ # Examples: 'https://app.workato.com', 'https://app.eu.workato.com'
428
434
  [--folder=FOLDER] # Folder ID if you what to push to folder other than Home
429
435
  [--verbose], [--no-verbose]
430
436
 
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require 'active_support/encrypted_configuration'
@@ -33,9 +34,9 @@ module Workato
33
34
 
34
35
  private
35
36
 
36
- attr_reader :key_path,
37
- :encrypted_file_path,
38
- :encrypted_config
37
+ attr_reader :key_path
38
+ attr_reader :encrypted_file_path
39
+ attr_reader :encrypted_config
39
40
 
40
41
  def ensure_encryption_key_present
41
42
  return if encrypted_config.key.present?
@@ -1,3 +1,4 @@
1
+ # typed: false
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require 'thor'
@@ -24,8 +25,8 @@ module Workato
24
25
 
25
26
  private
26
27
 
27
- attr_reader :path,
28
- :options
28
+ attr_reader :path
29
+ attr_reader :options
29
30
 
30
31
  # rubocop:disable Style/GuardClause
31
32
  def load_from_default_files
@@ -46,11 +47,9 @@ module Workato
46
47
 
47
48
  def params
48
49
  @params ||= {
49
- connector: connector,
50
50
  settings: settings,
51
51
  input: from_json(options[:input]),
52
- output: from_json(options[:input]),
53
- webhook_subscribe_output: from_json(options[:webhook_subscribe_output]).presence,
52
+ webhook_subscribe_output: from_json(options[:webhook_subscribe_output]),
54
53
  args: from_json(options[:args]).presence || [],
55
54
  extended_input_schema: from_json(options[:extended_input_schema]).presence || [],
56
55
  extended_output_schema: from_json(options[:extended_output_schema]).presence || [],
@@ -69,7 +68,7 @@ module Workato
69
68
  end
70
69
 
71
70
  def connector
72
- Workato::Connector::Sdk::Connector.from_file(
71
+ @connector ||= Workato::Connector::Sdk::Connector.from_file(
73
72
  options[:connector] || Workato::Connector::Sdk::DEFAULT_CONNECTOR_PATH,
74
73
  settings
75
74
  )
@@ -85,16 +84,26 @@ module Workato
85
84
  )
86
85
  @settings = settings_store.read
87
86
 
88
- Workato::Connector::Sdk::Operation.on_settings_updated = lambda do |message, new_settings|
89
- $stdout.pause if verbose?
90
- say('')
91
- say(message)
92
- loop do
93
- answer = ask('Updated settings file with new connection attributes? (Yes or No)').to_s.downcase
94
- break if %w[n no].include?(answer)
95
- break settings_store.update(new_settings) if %w[y yes].include?(answer)
87
+ Workato::Connector::Sdk::Connection.on_settings_update = lambda do |message, &refresher|
88
+ begin
89
+ $stdout.pause if verbose?
90
+ say('')
91
+ say(message)
92
+
93
+ new_settings = refresher.call
94
+ break unless new_settings
95
+
96
+ loop do
97
+ answer = ask('Updated settings file with new connection attributes? (Yes or No)').to_s.downcase
98
+ break new_settings if %w[n no].include?(answer)
99
+ next unless %w[y yes].include?(answer)
100
+
101
+ settings_store.update(new_settings)
102
+ break new_settings
103
+ end
104
+ ensure
105
+ $stdout.resume if verbose?
96
106
  end
97
- $stdout.resume if verbose?
98
107
  end
99
108
 
100
109
  @settings
@@ -103,9 +112,9 @@ module Workato
103
112
  def from_json(path, parse_json_times: false)
104
113
  old_parse_json_times = ActiveSupport.parse_json_times
105
114
  ::ActiveSupport.parse_json_times = parse_json_times
106
- result = path ? ::ActiveSupport::JSON.decode(File.read(path)) : {}
115
+ path ? ::ActiveSupport::JSON.decode(File.read(path)) : {}
116
+ ensure
107
117
  ::ActiveSupport.parse_json_times = old_parse_json_times
108
- result
109
118
  end
110
119
 
111
120
  def inspect_params(params)
@@ -121,30 +130,13 @@ module Workato
121
130
  end
122
131
 
123
132
  def execute_path
124
- methods = path.split('.')
125
- method = methods.pop
126
- object = methods.inject(params[:connector]) { |obj, m| obj.public_send(m) }
127
- output = invoke_method(object, method)
128
- if output.respond_to?(:invoke)
129
- invoke_method(output, :invoke)
130
- else
131
- output
132
- end
133
+ connector.invoke(path, params)
133
134
  rescue Exception => e # rubocop:disable Lint/RescueException
134
135
  raise DebugExceptionError, e if options[:debug]
135
136
 
136
137
  raise
137
138
  end
138
139
 
139
- def invoke_method(object, method)
140
- parameters = object.method(method).parameters.reject { |p| p[0] == :block }.map(&:second)
141
- args = params.values_at(*parameters)
142
- if parameters.last == :args
143
- args = args.take(args.length - 1) + Array.wrap(args.last).flatten(1)
144
- end
145
- object.public_send(method, *args)
146
- end
147
-
148
140
  def show_output(output)
149
141
  if options[:output].present?
150
142
  File.open(options[:output], 'w') do |f|
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Workato
@@ -1,3 +1,4 @@
1
+ # typed: false
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Workato
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Workato
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require 'thor'
@@ -40,8 +41,8 @@ module Workato
40
41
  desc: 'Connection name if settings file contains multiple settings'
41
42
  method_option :key, type: :string, aliases: '-k',
42
43
  lazy_default: Workato::Connector::Sdk::DEFAULT_MASTER_KEY_PATH,
43
- desc: 'Path to file with encrypt/decrypt key. '\
44
- "NOTE: key from #{Workato::Connector::Sdk::DEFAULT_MASTER_KEY_ENV} has higher priority"
44
+ desc: "Path to file with encrypt/decrypt key.\n"\
45
+ "NOTE: key from #{Workato::Connector::Sdk::DEFAULT_MASTER_KEY_ENV} has higher priority"
45
46
  method_option :input, type: :string, aliases: '-i', desc: 'Path to file with input JSON'
46
47
  method_option :closure, type: :string, desc: 'Path to file with next poll closure JSON'
47
48
  method_option :continue, type: :string, desc: 'Path to file with next multistep action continue closure JSON'
@@ -74,7 +75,7 @@ module Workato
74
75
 
75
76
  method_option :key, type: :string, aliases: '-k',
76
77
  lazy_default: Workato::Connector::Sdk::DEFAULT_MASTER_KEY_PATH,
77
- desc: 'Path to file with encrypt/decrypt key. '\
78
+ desc: "Path to file with encrypt/decrypt key.\n"\
78
79
  "NOTE: key from #{Workato::Connector::Sdk::DEFAULT_MASTER_KEY_ENV} has higher priority"
79
80
 
80
81
  def edit(path)
@@ -126,17 +127,20 @@ module Workato
126
127
  lazy_default: Workato::Connector::Sdk::DEFAULT_CONNECTOR_PATH
127
128
  method_option :api_email,
128
129
  type: :string,
129
- desc: 'Email for accessing Workato API or '\
130
- "set #{Workato::Connector::Sdk::WORKATO_API_EMAIL_ENV} environment variable"
130
+ desc: "Email for accessing Workato API.\n"\
131
+ "If present overrides value from #{Workato::Connector::Sdk::WORKATO_API_EMAIL_ENV} "\
132
+ 'environment variable.'
131
133
  method_option :api_token,
132
134
  type: :string,
133
- desc: 'Token for accessing Workato API or ' \
134
- "set #{Workato::Connector::Sdk::WORKATO_API_TOKEN_ENV} environment variable"
135
+ desc: "Token for accessing Workato API.\n" \
136
+ "If present overrides value from #{Workato::Connector::Sdk::WORKATO_API_TOKEN_ENV} "\
137
+ 'environment variable.'
135
138
  method_option :environment,
136
139
  type: :string,
137
- enum: Workato::CLI::PushCommand::ENVIRONMENTS.keys,
138
- default: 'live',
139
- desc: 'Server to push connector code to'
140
+ desc: "Data center specific URL to push connector code.\n"\
141
+ "If present overrides value from #{Workato::Connector::Sdk::WORKATO_BASE_URL_ENV} "\
142
+ "environment variable.\n"\
143
+ "Examples: 'https://app.workato.com', 'https://app.eu.workato.com'"
140
144
  method_option :folder,
141
145
  type: :string,
142
146
  desc: 'Folder ID if you what to push to folder other than Home'
@@ -167,7 +171,7 @@ module Workato
167
171
  type: :string,
168
172
  aliases: '-k',
169
173
  lazy_default: Workato::Connector::Sdk::DEFAULT_MASTER_KEY_PATH,
170
- desc: 'Path to file with encrypt/decrypt key. '\
174
+ desc: "Path to file with encrypt/decrypt key.\n"\
171
175
  "NOTE: key from #{Workato::Connector::Sdk::DEFAULT_MASTER_KEY_ENV} has higher priority"
172
176
  method_option :port,
173
177
  type: :string,
@@ -186,6 +190,35 @@ module Workato
186
190
  options: options
187
191
  ).call
188
192
  end
193
+
194
+ class << self
195
+ def print_options(shell, options, group_name = nil)
196
+ return if options.empty?
197
+
198
+ list = []
199
+ padding = options.map { |o| o.aliases.size }.max.to_i * 4
200
+
201
+ options.each do |option|
202
+ next if option.hide
203
+
204
+ description = []
205
+ description_lines = option.description ? option.description.split("\n") : []
206
+ first_line = description_lines.shift
207
+ description << [option.usage(padding), first_line ? "# #{first_line}" : '']
208
+ description_lines.each do |line|
209
+ description << ['', "# #{line}"]
210
+ end
211
+
212
+ list.concat(description)
213
+ list << ['', "# Default: #{option.default}"] if option.show_default?
214
+ list << ['', "# Possible values: #{option.enum.join(', ')}"] if option.enum
215
+ end
216
+
217
+ shell.say(group_name ? "#{group_name} options:" : 'Options:')
218
+ shell.print_table(list, indent: 2)
219
+ shell.say ''
220
+ end
221
+ end
189
222
  end
190
223
  end
191
224
  end
@@ -1,3 +1,4 @@
1
+ # typed: false
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require 'securerandom'
@@ -55,11 +56,11 @@ module Workato
55
56
 
56
57
  private
57
58
 
58
- attr_reader :https,
59
- :base_url,
60
- :redirect_url,
61
- :port,
62
- :options
59
+ attr_reader :https
60
+ attr_reader :base_url
61
+ attr_reader :redirect_url
62
+ attr_reader :port
63
+ attr_reader :options
63
64
 
64
65
  def verbose?
65
66
  !!options[:verbose]
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require 'uri'
@@ -31,7 +32,9 @@ module Workato
31
32
 
32
33
  def initialize(options:)
33
34
  @options = options
34
- @api_base_url = ENVIRONMENTS.fetch(options[:environment])
35
+ @api_base_url = ENVIRONMENTS.fetch(options[:environment]) do
36
+ options[:environment].presence || Workato::Connector::Sdk::WORKATO_BASE_URL
37
+ end
35
38
  @api_email = options[:api_email] || ENV[Workato::Connector::Sdk::WORKATO_API_EMAIL_ENV]
36
39
  @api_token = options[:api_token] || ENV[Workato::Connector::Sdk::WORKATO_API_TOKEN_ENV]
37
40
  @folder_id = options[:folder]
@@ -55,10 +58,10 @@ module Workato
55
58
 
56
59
  private
57
60
 
58
- attr_reader :options,
59
- :api_token,
60
- :api_email,
61
- :api_base_url
61
+ attr_reader :options
62
+ attr_reader :api_token
63
+ attr_reader :api_email
64
+ attr_reader :api_base_url
62
65
 
63
66
  def verbose?
64
67
  @options[:verbose]
@@ -1,3 +1,4 @@
1
+ # typed: false
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Workato
@@ -8,7 +9,6 @@ module Workato
8
9
  SAMPLE_TO_SCHEMA_SUPPORT_TYPES = %w[csv json].freeze
9
10
  CSV_SEPARATORS = %w[comma space tab colon semicolon pipe].freeze
10
11
 
11
- WORKATO_BASE_URL = ENV['WORKATO_BASE_URL'] || 'https://app.workato.com'
12
12
  API_GENERATE_SCHEMA_PATH = '/api/sdk/generate_schema'
13
13
 
14
14
  def initialize(options:)
@@ -31,9 +31,9 @@ module Workato
31
31
 
32
32
  private
33
33
 
34
- attr_reader :options,
35
- :api_token,
36
- :api_email
34
+ attr_reader :options
35
+ attr_reader :api_token
36
+ attr_reader :api_email
37
37
 
38
38
  def verbose?
39
39
  @options[:verbose]
@@ -52,7 +52,7 @@ module Workato
52
52
  end
53
53
 
54
54
  def sample_to_schema(sample)
55
- url = "#{WORKATO_BASE_URL}#{API_GENERATE_SCHEMA_PATH}/#{sample.delete(:type)}"
55
+ url = "#{Workato::Connector::Sdk::WORKATO_BASE_URL}#{API_GENERATE_SCHEMA_PATH}/#{sample.delete(:type)}"
56
56
  response = RestClient.post(
57
57
  url,
58
58
  sample.to_json,
@@ -74,8 +74,7 @@ module Workato
74
74
  }
75
75
  end
76
76
 
77
- private_constant :API_GENERATE_SCHEMA_PATH,
78
- :WORKATO_BASE_URL
77
+ private_constant :API_GENERATE_SCHEMA_PATH
79
78
  end
80
79
  end
81
80
  end
@@ -1,3 +1,4 @@
1
+ # typed: false
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require 'csv'
@@ -1,3 +1,4 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require_relative './operation'
@@ -7,27 +8,52 @@ module Workato
7
8
  module Connector
8
9
  module Sdk
9
10
  class Action < Operation
11
+ extend T::Sig
10
12
  using BlockInvocationRefinements
11
13
 
12
- RETRY_DEFAULT_CODES = [429, 500, 502, 503, 504, 507].freeze
13
- RETRY_DEFAULT_METHODS = %i[get head].freeze
14
- RETRY_DELAY = 5.seconds
14
+ RETRY_DEFAULT_CODES = T.let([429, 500, 502, 503, 504, 507].freeze, T::Array[Integer])
15
+ RETRY_DEFAULT_METHODS = T.let(%i[get head].freeze, T::Array[Symbol])
16
+ RETRY_DELAY = T.let(5, Integer) # seconds
15
17
  MAX_RETRIES = 3
16
18
 
17
19
  MAX_REINVOKES = 5
18
20
 
19
- def initialize(action:, connection: {}, methods: {}, settings: {}, object_definitions: nil)
21
+ sig do
22
+ params(
23
+ action: SorbetTypes::SourceHash,
24
+ methods: SorbetTypes::SourceHash,
25
+ connection: Connection,
26
+ object_definitions: T.nilable(ObjectDefinitions)
27
+ ).void
28
+ end
29
+ def initialize(action:, methods: {}, connection: Connection.new, object_definitions: nil)
20
30
  super(
21
31
  operation: action,
22
32
  connection: connection,
23
33
  methods: methods,
24
- settings: settings,
25
34
  object_definitions: object_definitions
26
35
  )
27
36
 
37
+ @retries_left = T.let(0, Integer)
38
+ @retry_codes = T.let([], T::Array[Integer])
39
+ @retry_methods = T.let([], T::Array[String])
40
+ @retry_matchers = T.let([], T::Array[T.any(Symbol, String, Regexp)])
41
+
28
42
  initialize_retry
29
43
  end
30
44
 
45
+ sig do
46
+ params(
47
+ settings: T.nilable(SorbetTypes::SettingsHash),
48
+ input: SorbetTypes::OperationInputHash,
49
+ extended_input_schema: SorbetTypes::OperationSchema,
50
+ extended_output_schema: SorbetTypes::OperationSchema,
51
+ continue: T::Hash[T.any(Symbol, String), T.untyped],
52
+ block: T.nilable(SorbetTypes::OperationExecuteProc)
53
+ ).returns(
54
+ T.untyped
55
+ )
56
+ end
31
57
  def execute(settings = nil, input = {}, extended_input_schema = [], extended_output_schema = [], continue = {},
32
58
  &block)
33
59
  raise InvalidDefinitionError, "'execute' block is required for action" unless block || action[:execute]
@@ -39,7 +65,7 @@ module Workato
39
65
 
40
66
  reinvoke_sleep if @reinvoke_after
41
67
 
42
- @reinvoke_after = nil
68
+ reinvoke_reset
43
69
 
44
70
  result = super(
45
71
  settings,
@@ -52,15 +78,17 @@ module Workato
52
78
 
53
79
  break result unless @reinvoke_after
54
80
 
55
- continue = @reinvoke_after[:continue]
81
+ continue = @reinvoke_after.continue
56
82
  end
57
83
  rescue RequestError => e
58
84
  raise e unless retry?(e)
59
85
 
60
86
  @retries_left -= 1
61
- sleep(RETRY_DELAY) && retry
87
+ sleep(RETRY_DELAY)
88
+ retry
62
89
  end
63
90
 
91
+ sig { params(input: SorbetTypes::OperationInputHash).returns(T::Hash[T.any(String, Symbol), T.untyped]) }
64
92
  def invoke(input = {})
65
93
  extended_schema = extended_schema(nil, input)
66
94
  config_schema = Schema.new(schema: config_fields_schema)
@@ -72,63 +100,93 @@ module Workato
72
100
  apply_output_schema(output, output_schema)
73
101
  end
74
102
 
103
+ sig do
104
+ params(
105
+ continue: T::Hash[T.untyped, T.untyped],
106
+ temp_output: T.nilable(T::Hash[T.untyped, T.untyped])
107
+ ).void
108
+ end
75
109
  def checkpoint!(continue:, temp_output: nil)
76
110
  # no-op
77
111
  end
78
112
 
79
- def reinvoke_after(seconds:, continue:, temp_output: nil)
113
+ sig do
114
+ params(
115
+ seconds: Integer,
116
+ continue: T::Hash[T.untyped, T.untyped],
117
+ temp_output: T.nilable(T::Hash[T.untyped, T.untyped])
118
+ ).void
119
+ end
120
+ def reinvoke_after(seconds:, continue:, temp_output: nil) # rubocop:disable Lint/UnusedMethodArgument
121
+ @reinvokes_remaining = T.let(@reinvokes_remaining, T.nilable(Integer))
80
122
  @reinvokes_remaining = (@reinvokes_remaining ? @reinvokes_remaining - 1 : reinvoke_limit)
81
- @reinvoke_after = {
123
+ @reinvoke_after = ReinvokeAfter.new(
82
124
  seconds: seconds,
83
- continue: continue,
84
- temp_output: temp_output
85
- }
125
+ continue: continue
126
+ )
86
127
  end
87
128
 
88
129
  private
89
130
 
131
+ sig { returns(T::Array[T.any(Symbol, String, Regexp, Integer)]) }
90
132
  def retry_on_response
91
133
  Array(action[:retry_on_response])
92
134
  end
93
135
 
136
+ sig { returns(T::Array[T.any(Symbol, String, Regexp, Integer)]) }
94
137
  def retry_on_request
95
138
  Array(action[:retry_on_request])
96
139
  end
97
140
 
141
+ sig { returns(T.nilable(Integer)) }
98
142
  def max_retries
99
143
  action[:max_retries]
100
144
  end
101
145
 
146
+ sig { void }
102
147
  def initialize_retry
103
- @retries_left = 0
104
148
  return if retry_on_response.blank?
105
149
 
106
- @retry_codes = []
107
- @retry_matchers = []
108
150
  retry_on_response.each { |m| m.is_a?(::Integer) ? @retry_codes << m : @retry_matchers << m }
109
151
  @retry_codes = RETRY_DEFAULT_CODES if @retry_codes.empty?
110
152
  @retry_methods = (retry_on_request.presence || RETRY_DEFAULT_METHODS).map(&:to_s).map(&:downcase)
111
153
  @retries_left = [[max_retries.is_a?(::Integer) && max_retries || MAX_RETRIES, MAX_RETRIES].min, 0].max
112
154
  end
113
155
 
156
+ sig { params(exception: RequestError).returns(T::Boolean) }
114
157
  def retry?(exception)
115
- return unless @retries_left.positive?
116
- return unless @retry_codes.include?(exception.code.to_i)
117
- return unless @retry_matchers.empty? || @retry_matchers.any? do |m|
158
+ return false unless @retries_left.positive?
159
+ return false unless @retry_codes.include?(exception.code.to_i)
160
+ return false unless @retry_matchers.empty? || @retry_matchers.any? do |m|
118
161
  m === exception.message || m === exception.response
119
162
  end
120
163
 
121
164
  @retry_methods.include?(exception.method.to_s.downcase)
122
165
  end
123
166
 
167
+ sig { void }
124
168
  def reinvoke_sleep
125
- sleep((ENV['WAIT_REINVOKE_AFTER'].presence || @reinvoke_after[:seconds]).to_f)
169
+ sleep((ENV['WAIT_REINVOKE_AFTER'].presence || T.must(@reinvoke_after).seconds).to_f)
126
170
  end
127
171
 
172
+ sig { returns(Integer) }
128
173
  def reinvoke_limit
174
+ @reinvoke_limit = T.let(@reinvoke_limit, T.nilable(Integer))
129
175
  @reinvoke_limit ||= (ENV['MAX_REINVOKES'].presence || MAX_REINVOKES).to_i
130
176
  end
131
177
 
178
+ sig { void }
179
+ def reinvoke_reset
180
+ @reinvoke_after = T.let(nil, T.nilable(ReinvokeAfter))
181
+ end
182
+
183
+ class ReinvokeAfter < T::Struct
184
+ prop :seconds, T.any(Float, Integer)
185
+ prop :continue, T::Hash[T.untyped, T.untyped]
186
+ end
187
+
188
+ private_constant :ReinvokeAfter
189
+
132
190
  alias action operation
133
191
  end
134
192
  end
@@ -1,3 +1,4 @@
1
+ # typed: false
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Workato