workato-connector-sdk 1.0.1 → 1.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.
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