workato-platform-cli 1.0.0rc5.dev5__py3-none-any.whl

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 (306) hide show
  1. workato_platform_cli/__init__.py +135 -0
  2. workato_platform_cli/_version.py +34 -0
  3. workato_platform_cli/cli/__init__.py +126 -0
  4. workato_platform_cli/cli/commands/__init__.py +0 -0
  5. workato_platform_cli/cli/commands/api_clients.py +627 -0
  6. workato_platform_cli/cli/commands/api_collections.py +497 -0
  7. workato_platform_cli/cli/commands/assets.py +82 -0
  8. workato_platform_cli/cli/commands/connections.py +1205 -0
  9. workato_platform_cli/cli/commands/connectors/__init__.py +0 -0
  10. workato_platform_cli/cli/commands/connectors/command.py +178 -0
  11. workato_platform_cli/cli/commands/connectors/connector_manager.py +351 -0
  12. workato_platform_cli/cli/commands/data_tables.py +345 -0
  13. workato_platform_cli/cli/commands/guide.py +315 -0
  14. workato_platform_cli/cli/commands/init.py +229 -0
  15. workato_platform_cli/cli/commands/profiles.py +364 -0
  16. workato_platform_cli/cli/commands/projects/__init__.py +0 -0
  17. workato_platform_cli/cli/commands/projects/command.py +513 -0
  18. workato_platform_cli/cli/commands/projects/project_manager.py +338 -0
  19. workato_platform_cli/cli/commands/properties.py +174 -0
  20. workato_platform_cli/cli/commands/pull.py +327 -0
  21. workato_platform_cli/cli/commands/push/__init__.py +0 -0
  22. workato_platform_cli/cli/commands/push/command.py +320 -0
  23. workato_platform_cli/cli/commands/recipes/__init__.py +0 -0
  24. workato_platform_cli/cli/commands/recipes/command.py +847 -0
  25. workato_platform_cli/cli/commands/recipes/validator.py +1740 -0
  26. workato_platform_cli/cli/commands/workspace.py +73 -0
  27. workato_platform_cli/cli/containers.py +80 -0
  28. workato_platform_cli/cli/resources/data/connection-data.json +7364 -0
  29. workato_platform_cli/cli/resources/data/picklist-data.json +3706 -0
  30. workato_platform_cli/cli/resources/docs/README.md +178 -0
  31. workato_platform_cli/cli/resources/docs/actions.md +452 -0
  32. workato_platform_cli/cli/resources/docs/block-structure.md +424 -0
  33. workato_platform_cli/cli/resources/docs/connections-parameters.md +11946 -0
  34. workato_platform_cli/cli/resources/docs/data-mapping.md +779 -0
  35. workato_platform_cli/cli/resources/docs/formulas/array-list-formulas.md +1276 -0
  36. workato_platform_cli/cli/resources/docs/formulas/conditions.md +102 -0
  37. workato_platform_cli/cli/resources/docs/formulas/date-formulas.md +798 -0
  38. workato_platform_cli/cli/resources/docs/formulas/number-formulas.md +507 -0
  39. workato_platform_cli/cli/resources/docs/formulas/other-formulas.md +419 -0
  40. workato_platform_cli/cli/resources/docs/formulas/string-formulas.md +1353 -0
  41. workato_platform_cli/cli/resources/docs/formulas.md +214 -0
  42. workato_platform_cli/cli/resources/docs/naming-conventions.md +163 -0
  43. workato_platform_cli/cli/resources/docs/recipe-deployment-workflow.md +352 -0
  44. workato_platform_cli/cli/resources/docs/recipe-fundamentals.md +179 -0
  45. workato_platform_cli/cli/resources/docs/triggers.md +360 -0
  46. workato_platform_cli/cli/utils/__init__.py +10 -0
  47. workato_platform_cli/cli/utils/config/__init__.py +33 -0
  48. workato_platform_cli/cli/utils/config/manager.py +1001 -0
  49. workato_platform_cli/cli/utils/config/models.py +89 -0
  50. workato_platform_cli/cli/utils/config/profiles.py +491 -0
  51. workato_platform_cli/cli/utils/config/workspace.py +113 -0
  52. workato_platform_cli/cli/utils/exception_handler.py +531 -0
  53. workato_platform_cli/cli/utils/gitignore.py +32 -0
  54. workato_platform_cli/cli/utils/ignore_patterns.py +44 -0
  55. workato_platform_cli/cli/utils/spinner.py +63 -0
  56. workato_platform_cli/cli/utils/version_checker.py +237 -0
  57. workato_platform_cli/client/__init__.py +0 -0
  58. workato_platform_cli/client/workato_api/__init__.py +202 -0
  59. workato_platform_cli/client/workato_api/api/__init__.py +15 -0
  60. workato_platform_cli/client/workato_api/api/api_platform_api.py +2875 -0
  61. workato_platform_cli/client/workato_api/api/connections_api.py +1807 -0
  62. workato_platform_cli/client/workato_api/api/connectors_api.py +840 -0
  63. workato_platform_cli/client/workato_api/api/data_tables_api.py +604 -0
  64. workato_platform_cli/client/workato_api/api/export_api.py +621 -0
  65. workato_platform_cli/client/workato_api/api/folders_api.py +621 -0
  66. workato_platform_cli/client/workato_api/api/packages_api.py +1197 -0
  67. workato_platform_cli/client/workato_api/api/projects_api.py +590 -0
  68. workato_platform_cli/client/workato_api/api/properties_api.py +620 -0
  69. workato_platform_cli/client/workato_api/api/recipes_api.py +1379 -0
  70. workato_platform_cli/client/workato_api/api/users_api.py +285 -0
  71. workato_platform_cli/client/workato_api/api_client.py +807 -0
  72. workato_platform_cli/client/workato_api/api_response.py +21 -0
  73. workato_platform_cli/client/workato_api/configuration.py +601 -0
  74. workato_platform_cli/client/workato_api/docs/APIPlatformApi.md +844 -0
  75. workato_platform_cli/client/workato_api/docs/ApiClient.md +46 -0
  76. workato_platform_cli/client/workato_api/docs/ApiClientApiCollectionsInner.md +30 -0
  77. workato_platform_cli/client/workato_api/docs/ApiClientApiPoliciesInner.md +30 -0
  78. workato_platform_cli/client/workato_api/docs/ApiClientCreateRequest.md +46 -0
  79. workato_platform_cli/client/workato_api/docs/ApiClientListResponse.md +32 -0
  80. workato_platform_cli/client/workato_api/docs/ApiClientResponse.md +29 -0
  81. workato_platform_cli/client/workato_api/docs/ApiCollection.md +38 -0
  82. workato_platform_cli/client/workato_api/docs/ApiCollectionCreateRequest.md +32 -0
  83. workato_platform_cli/client/workato_api/docs/ApiEndpoint.md +41 -0
  84. workato_platform_cli/client/workato_api/docs/ApiKey.md +36 -0
  85. workato_platform_cli/client/workato_api/docs/ApiKeyCreateRequest.md +32 -0
  86. workato_platform_cli/client/workato_api/docs/ApiKeyListResponse.md +32 -0
  87. workato_platform_cli/client/workato_api/docs/ApiKeyResponse.md +29 -0
  88. workato_platform_cli/client/workato_api/docs/Asset.md +39 -0
  89. workato_platform_cli/client/workato_api/docs/AssetReference.md +37 -0
  90. workato_platform_cli/client/workato_api/docs/Connection.md +44 -0
  91. workato_platform_cli/client/workato_api/docs/ConnectionCreateRequest.md +35 -0
  92. workato_platform_cli/client/workato_api/docs/ConnectionUpdateRequest.md +34 -0
  93. workato_platform_cli/client/workato_api/docs/ConnectionsApi.md +526 -0
  94. workato_platform_cli/client/workato_api/docs/ConnectorAction.md +33 -0
  95. workato_platform_cli/client/workato_api/docs/ConnectorVersion.md +32 -0
  96. workato_platform_cli/client/workato_api/docs/ConnectorsApi.md +249 -0
  97. workato_platform_cli/client/workato_api/docs/CreateExportManifestRequest.md +29 -0
  98. workato_platform_cli/client/workato_api/docs/CreateFolderRequest.md +30 -0
  99. workato_platform_cli/client/workato_api/docs/CustomConnector.md +35 -0
  100. workato_platform_cli/client/workato_api/docs/CustomConnectorCodeResponse.md +29 -0
  101. workato_platform_cli/client/workato_api/docs/CustomConnectorCodeResponseData.md +29 -0
  102. workato_platform_cli/client/workato_api/docs/CustomConnectorListResponse.md +29 -0
  103. workato_platform_cli/client/workato_api/docs/DataTable.md +34 -0
  104. workato_platform_cli/client/workato_api/docs/DataTableColumn.md +37 -0
  105. workato_platform_cli/client/workato_api/docs/DataTableColumnRequest.md +37 -0
  106. workato_platform_cli/client/workato_api/docs/DataTableCreateRequest.md +31 -0
  107. workato_platform_cli/client/workato_api/docs/DataTableCreateResponse.md +29 -0
  108. workato_platform_cli/client/workato_api/docs/DataTableListResponse.md +29 -0
  109. workato_platform_cli/client/workato_api/docs/DataTableRelation.md +30 -0
  110. workato_platform_cli/client/workato_api/docs/DataTablesApi.md +172 -0
  111. workato_platform_cli/client/workato_api/docs/DeleteProject403Response.md +29 -0
  112. workato_platform_cli/client/workato_api/docs/Error.md +29 -0
  113. workato_platform_cli/client/workato_api/docs/ExportApi.md +175 -0
  114. workato_platform_cli/client/workato_api/docs/ExportManifestRequest.md +35 -0
  115. workato_platform_cli/client/workato_api/docs/ExportManifestResponse.md +29 -0
  116. workato_platform_cli/client/workato_api/docs/ExportManifestResponseResult.md +36 -0
  117. workato_platform_cli/client/workato_api/docs/Folder.md +35 -0
  118. workato_platform_cli/client/workato_api/docs/FolderAssetsResponse.md +29 -0
  119. workato_platform_cli/client/workato_api/docs/FolderAssetsResponseResult.md +29 -0
  120. workato_platform_cli/client/workato_api/docs/FolderCreationResponse.md +35 -0
  121. workato_platform_cli/client/workato_api/docs/FoldersApi.md +176 -0
  122. workato_platform_cli/client/workato_api/docs/ImportResults.md +32 -0
  123. workato_platform_cli/client/workato_api/docs/OAuthUrlResponse.md +29 -0
  124. workato_platform_cli/client/workato_api/docs/OAuthUrlResponseData.md +29 -0
  125. workato_platform_cli/client/workato_api/docs/OpenApiSpec.md +30 -0
  126. workato_platform_cli/client/workato_api/docs/PackageDetailsResponse.md +35 -0
  127. workato_platform_cli/client/workato_api/docs/PackageDetailsResponseRecipeStatusInner.md +30 -0
  128. workato_platform_cli/client/workato_api/docs/PackageResponse.md +33 -0
  129. workato_platform_cli/client/workato_api/docs/PackagesApi.md +364 -0
  130. workato_platform_cli/client/workato_api/docs/PicklistRequest.md +30 -0
  131. workato_platform_cli/client/workato_api/docs/PicklistResponse.md +29 -0
  132. workato_platform_cli/client/workato_api/docs/PlatformConnector.md +36 -0
  133. workato_platform_cli/client/workato_api/docs/PlatformConnectorListResponse.md +32 -0
  134. workato_platform_cli/client/workato_api/docs/Project.md +32 -0
  135. workato_platform_cli/client/workato_api/docs/ProjectsApi.md +173 -0
  136. workato_platform_cli/client/workato_api/docs/PropertiesApi.md +186 -0
  137. workato_platform_cli/client/workato_api/docs/Recipe.md +58 -0
  138. workato_platform_cli/client/workato_api/docs/RecipeConfigInner.md +33 -0
  139. workato_platform_cli/client/workato_api/docs/RecipeConnectionUpdateRequest.md +30 -0
  140. workato_platform_cli/client/workato_api/docs/RecipeListResponse.md +29 -0
  141. workato_platform_cli/client/workato_api/docs/RecipeStartResponse.md +31 -0
  142. workato_platform_cli/client/workato_api/docs/RecipesApi.md +367 -0
  143. workato_platform_cli/client/workato_api/docs/RuntimeUserConnectionCreateRequest.md +34 -0
  144. workato_platform_cli/client/workato_api/docs/RuntimeUserConnectionResponse.md +29 -0
  145. workato_platform_cli/client/workato_api/docs/RuntimeUserConnectionResponseData.md +30 -0
  146. workato_platform_cli/client/workato_api/docs/SuccessResponse.md +29 -0
  147. workato_platform_cli/client/workato_api/docs/UpsertProjectPropertiesRequest.md +29 -0
  148. workato_platform_cli/client/workato_api/docs/User.md +48 -0
  149. workato_platform_cli/client/workato_api/docs/UsersApi.md +84 -0
  150. workato_platform_cli/client/workato_api/docs/ValidationError.md +30 -0
  151. workato_platform_cli/client/workato_api/docs/ValidationErrorErrorsValue.md +28 -0
  152. workato_platform_cli/client/workato_api/exceptions.py +216 -0
  153. workato_platform_cli/client/workato_api/models/__init__.py +83 -0
  154. workato_platform_cli/client/workato_api/models/api_client.py +185 -0
  155. workato_platform_cli/client/workato_api/models/api_client_api_collections_inner.py +89 -0
  156. workato_platform_cli/client/workato_api/models/api_client_api_policies_inner.py +89 -0
  157. workato_platform_cli/client/workato_api/models/api_client_create_request.py +138 -0
  158. workato_platform_cli/client/workato_api/models/api_client_list_response.py +101 -0
  159. workato_platform_cli/client/workato_api/models/api_client_response.py +91 -0
  160. workato_platform_cli/client/workato_api/models/api_collection.py +110 -0
  161. workato_platform_cli/client/workato_api/models/api_collection_create_request.py +97 -0
  162. workato_platform_cli/client/workato_api/models/api_endpoint.py +117 -0
  163. workato_platform_cli/client/workato_api/models/api_key.py +102 -0
  164. workato_platform_cli/client/workato_api/models/api_key_create_request.py +93 -0
  165. workato_platform_cli/client/workato_api/models/api_key_list_response.py +101 -0
  166. workato_platform_cli/client/workato_api/models/api_key_response.py +91 -0
  167. workato_platform_cli/client/workato_api/models/asset.py +124 -0
  168. workato_platform_cli/client/workato_api/models/asset_reference.py +110 -0
  169. workato_platform_cli/client/workato_api/models/connection.py +173 -0
  170. workato_platform_cli/client/workato_api/models/connection_create_request.py +99 -0
  171. workato_platform_cli/client/workato_api/models/connection_update_request.py +97 -0
  172. workato_platform_cli/client/workato_api/models/connector_action.py +100 -0
  173. workato_platform_cli/client/workato_api/models/connector_version.py +99 -0
  174. workato_platform_cli/client/workato_api/models/create_export_manifest_request.py +91 -0
  175. workato_platform_cli/client/workato_api/models/create_folder_request.py +89 -0
  176. workato_platform_cli/client/workato_api/models/custom_connector.py +117 -0
  177. workato_platform_cli/client/workato_api/models/custom_connector_code_response.py +91 -0
  178. workato_platform_cli/client/workato_api/models/custom_connector_code_response_data.py +87 -0
  179. workato_platform_cli/client/workato_api/models/custom_connector_list_response.py +95 -0
  180. workato_platform_cli/client/workato_api/models/data_table.py +107 -0
  181. workato_platform_cli/client/workato_api/models/data_table_column.py +125 -0
  182. workato_platform_cli/client/workato_api/models/data_table_column_request.py +130 -0
  183. workato_platform_cli/client/workato_api/models/data_table_create_request.py +99 -0
  184. workato_platform_cli/client/workato_api/models/data_table_create_response.py +91 -0
  185. workato_platform_cli/client/workato_api/models/data_table_list_response.py +95 -0
  186. workato_platform_cli/client/workato_api/models/data_table_relation.py +90 -0
  187. workato_platform_cli/client/workato_api/models/delete_project403_response.py +87 -0
  188. workato_platform_cli/client/workato_api/models/error.py +87 -0
  189. workato_platform_cli/client/workato_api/models/export_manifest_request.py +107 -0
  190. workato_platform_cli/client/workato_api/models/export_manifest_response.py +91 -0
  191. workato_platform_cli/client/workato_api/models/export_manifest_response_result.py +112 -0
  192. workato_platform_cli/client/workato_api/models/folder.py +110 -0
  193. workato_platform_cli/client/workato_api/models/folder_assets_response.py +91 -0
  194. workato_platform_cli/client/workato_api/models/folder_assets_response_result.py +95 -0
  195. workato_platform_cli/client/workato_api/models/folder_creation_response.py +110 -0
  196. workato_platform_cli/client/workato_api/models/import_results.py +93 -0
  197. workato_platform_cli/client/workato_api/models/o_auth_url_response.py +91 -0
  198. workato_platform_cli/client/workato_api/models/o_auth_url_response_data.py +87 -0
  199. workato_platform_cli/client/workato_api/models/open_api_spec.py +96 -0
  200. workato_platform_cli/client/workato_api/models/package_details_response.py +126 -0
  201. workato_platform_cli/client/workato_api/models/package_details_response_recipe_status_inner.py +99 -0
  202. workato_platform_cli/client/workato_api/models/package_response.py +109 -0
  203. workato_platform_cli/client/workato_api/models/picklist_request.py +89 -0
  204. workato_platform_cli/client/workato_api/models/picklist_response.py +88 -0
  205. workato_platform_cli/client/workato_api/models/platform_connector.py +116 -0
  206. workato_platform_cli/client/workato_api/models/platform_connector_list_response.py +101 -0
  207. workato_platform_cli/client/workato_api/models/project.py +93 -0
  208. workato_platform_cli/client/workato_api/models/recipe.py +174 -0
  209. workato_platform_cli/client/workato_api/models/recipe_config_inner.py +100 -0
  210. workato_platform_cli/client/workato_api/models/recipe_connection_update_request.py +89 -0
  211. workato_platform_cli/client/workato_api/models/recipe_list_response.py +95 -0
  212. workato_platform_cli/client/workato_api/models/recipe_start_response.py +91 -0
  213. workato_platform_cli/client/workato_api/models/runtime_user_connection_create_request.py +97 -0
  214. workato_platform_cli/client/workato_api/models/runtime_user_connection_response.py +91 -0
  215. workato_platform_cli/client/workato_api/models/runtime_user_connection_response_data.py +89 -0
  216. workato_platform_cli/client/workato_api/models/success_response.py +87 -0
  217. workato_platform_cli/client/workato_api/models/upsert_project_properties_request.py +88 -0
  218. workato_platform_cli/client/workato_api/models/user.py +151 -0
  219. workato_platform_cli/client/workato_api/models/validation_error.py +102 -0
  220. workato_platform_cli/client/workato_api/models/validation_error_errors_value.py +143 -0
  221. workato_platform_cli/client/workato_api/rest.py +213 -0
  222. workato_platform_cli/client/workato_api/test/__init__.py +0 -0
  223. workato_platform_cli/client/workato_api/test/test_api_client.py +94 -0
  224. workato_platform_cli/client/workato_api/test/test_api_client_api_collections_inner.py +52 -0
  225. workato_platform_cli/client/workato_api/test/test_api_client_api_policies_inner.py +52 -0
  226. workato_platform_cli/client/workato_api/test/test_api_client_create_request.py +75 -0
  227. workato_platform_cli/client/workato_api/test/test_api_client_list_response.py +114 -0
  228. workato_platform_cli/client/workato_api/test/test_api_client_response.py +104 -0
  229. workato_platform_cli/client/workato_api/test/test_api_collection.py +72 -0
  230. workato_platform_cli/client/workato_api/test/test_api_collection_create_request.py +57 -0
  231. workato_platform_cli/client/workato_api/test/test_api_endpoint.py +75 -0
  232. workato_platform_cli/client/workato_api/test/test_api_key.py +64 -0
  233. workato_platform_cli/client/workato_api/test/test_api_key_create_request.py +56 -0
  234. workato_platform_cli/client/workato_api/test/test_api_key_list_response.py +78 -0
  235. workato_platform_cli/client/workato_api/test/test_api_key_response.py +68 -0
  236. workato_platform_cli/client/workato_api/test/test_api_platform_api.py +101 -0
  237. workato_platform_cli/client/workato_api/test/test_asset.py +67 -0
  238. workato_platform_cli/client/workato_api/test/test_asset_reference.py +62 -0
  239. workato_platform_cli/client/workato_api/test/test_connection.py +81 -0
  240. workato_platform_cli/client/workato_api/test/test_connection_create_request.py +59 -0
  241. workato_platform_cli/client/workato_api/test/test_connection_update_request.py +56 -0
  242. workato_platform_cli/client/workato_api/test/test_connections_api.py +73 -0
  243. workato_platform_cli/client/workato_api/test/test_connector_action.py +59 -0
  244. workato_platform_cli/client/workato_api/test/test_connector_version.py +58 -0
  245. workato_platform_cli/client/workato_api/test/test_connectors_api.py +52 -0
  246. workato_platform_cli/client/workato_api/test/test_create_export_manifest_request.py +88 -0
  247. workato_platform_cli/client/workato_api/test/test_create_folder_request.py +53 -0
  248. workato_platform_cli/client/workato_api/test/test_custom_connector.py +76 -0
  249. workato_platform_cli/client/workato_api/test/test_custom_connector_code_response.py +54 -0
  250. workato_platform_cli/client/workato_api/test/test_custom_connector_code_response_data.py +52 -0
  251. workato_platform_cli/client/workato_api/test/test_custom_connector_list_response.py +82 -0
  252. workato_platform_cli/client/workato_api/test/test_data_table.py +88 -0
  253. workato_platform_cli/client/workato_api/test/test_data_table_column.py +72 -0
  254. workato_platform_cli/client/workato_api/test/test_data_table_column_request.py +64 -0
  255. workato_platform_cli/client/workato_api/test/test_data_table_create_request.py +82 -0
  256. workato_platform_cli/client/workato_api/test/test_data_table_create_response.py +90 -0
  257. workato_platform_cli/client/workato_api/test/test_data_table_list_response.py +94 -0
  258. workato_platform_cli/client/workato_api/test/test_data_table_relation.py +54 -0
  259. workato_platform_cli/client/workato_api/test/test_data_tables_api.py +45 -0
  260. workato_platform_cli/client/workato_api/test/test_delete_project403_response.py +51 -0
  261. workato_platform_cli/client/workato_api/test/test_error.py +52 -0
  262. workato_platform_cli/client/workato_api/test/test_export_api.py +45 -0
  263. workato_platform_cli/client/workato_api/test/test_export_manifest_request.py +69 -0
  264. workato_platform_cli/client/workato_api/test/test_export_manifest_response.py +68 -0
  265. workato_platform_cli/client/workato_api/test/test_export_manifest_response_result.py +66 -0
  266. workato_platform_cli/client/workato_api/test/test_folder.py +64 -0
  267. workato_platform_cli/client/workato_api/test/test_folder_assets_response.py +80 -0
  268. workato_platform_cli/client/workato_api/test/test_folder_assets_response_result.py +78 -0
  269. workato_platform_cli/client/workato_api/test/test_folder_creation_response.py +64 -0
  270. workato_platform_cli/client/workato_api/test/test_folders_api.py +45 -0
  271. workato_platform_cli/client/workato_api/test/test_import_results.py +58 -0
  272. workato_platform_cli/client/workato_api/test/test_o_auth_url_response.py +54 -0
  273. workato_platform_cli/client/workato_api/test/test_o_auth_url_response_data.py +52 -0
  274. workato_platform_cli/client/workato_api/test/test_open_api_spec.py +54 -0
  275. workato_platform_cli/client/workato_api/test/test_package_details_response.py +64 -0
  276. workato_platform_cli/client/workato_api/test/test_package_details_response_recipe_status_inner.py +52 -0
  277. workato_platform_cli/client/workato_api/test/test_package_response.py +58 -0
  278. workato_platform_cli/client/workato_api/test/test_packages_api.py +59 -0
  279. workato_platform_cli/client/workato_api/test/test_picklist_request.py +53 -0
  280. workato_platform_cli/client/workato_api/test/test_picklist_response.py +52 -0
  281. workato_platform_cli/client/workato_api/test/test_platform_connector.py +94 -0
  282. workato_platform_cli/client/workato_api/test/test_platform_connector_list_response.py +106 -0
  283. workato_platform_cli/client/workato_api/test/test_project.py +57 -0
  284. workato_platform_cli/client/workato_api/test/test_projects_api.py +45 -0
  285. workato_platform_cli/client/workato_api/test/test_properties_api.py +45 -0
  286. workato_platform_cli/client/workato_api/test/test_recipe.py +124 -0
  287. workato_platform_cli/client/workato_api/test/test_recipe_config_inner.py +55 -0
  288. workato_platform_cli/client/workato_api/test/test_recipe_connection_update_request.py +54 -0
  289. workato_platform_cli/client/workato_api/test/test_recipe_list_response.py +134 -0
  290. workato_platform_cli/client/workato_api/test/test_recipe_start_response.py +54 -0
  291. workato_platform_cli/client/workato_api/test/test_recipes_api.py +59 -0
  292. workato_platform_cli/client/workato_api/test/test_runtime_user_connection_create_request.py +59 -0
  293. workato_platform_cli/client/workato_api/test/test_runtime_user_connection_response.py +56 -0
  294. workato_platform_cli/client/workato_api/test/test_runtime_user_connection_response_data.py +54 -0
  295. workato_platform_cli/client/workato_api/test/test_success_response.py +52 -0
  296. workato_platform_cli/client/workato_api/test/test_upsert_project_properties_request.py +52 -0
  297. workato_platform_cli/client/workato_api/test/test_user.py +85 -0
  298. workato_platform_cli/client/workato_api/test/test_users_api.py +38 -0
  299. workato_platform_cli/client/workato_api/test/test_validation_error.py +52 -0
  300. workato_platform_cli/client/workato_api/test/test_validation_error_errors_value.py +50 -0
  301. workato_platform_cli/client/workato_api_README.md +205 -0
  302. workato_platform_cli-1.0.0rc5.dev5.dist-info/METADATA +185 -0
  303. workato_platform_cli-1.0.0rc5.dev5.dist-info/RECORD +306 -0
  304. workato_platform_cli-1.0.0rc5.dev5.dist-info/WHEEL +4 -0
  305. workato_platform_cli-1.0.0rc5.dev5.dist-info/entry_points.txt +2 -0
  306. workato_platform_cli-1.0.0rc5.dev5.dist-info/licenses/LICENSE +7 -0
@@ -0,0 +1,847 @@
1
+ import json
2
+
3
+ from datetime import datetime
4
+ from pathlib import Path
5
+
6
+ import asyncclick as click
7
+
8
+ from dependency_injector.wiring import Provide, inject
9
+
10
+ from workato_platform_cli import Workato
11
+ from workato_platform_cli.cli.commands.recipes.validator import RecipeValidator
12
+ from workato_platform_cli.cli.containers import Container
13
+ from workato_platform_cli.cli.utils import Spinner
14
+ from workato_platform_cli.cli.utils.config import ConfigManager
15
+ from workato_platform_cli.cli.utils.exception_handler import (
16
+ handle_api_exceptions,
17
+ handle_cli_exceptions,
18
+ )
19
+ from workato_platform_cli.client.workato_api.models.asset import Asset
20
+ from workato_platform_cli.client.workato_api.models.recipe import Recipe
21
+ from workato_platform_cli.client.workato_api.models.recipe_connection_update_request import ( # noqa: E501
22
+ RecipeConnectionUpdateRequest,
23
+ )
24
+ from workato_platform_cli.client.workato_api.models.recipe_start_response import (
25
+ RecipeStartResponse,
26
+ )
27
+
28
+
29
+ @click.group()
30
+ def recipes() -> None:
31
+ """Manage recipes"""
32
+ pass
33
+
34
+
35
+ @recipes.command(name="list")
36
+ @click.option(
37
+ "--adapter-names-all", help="Comma-separated adapter names (recipes must use ALL)"
38
+ )
39
+ @click.option(
40
+ "--adapter-names-any", help="Comma-separated adapter names (recipes must use ANY)"
41
+ )
42
+ @click.option("--folder-id", type=int, help="Return recipes in specified folder")
43
+ @click.option(
44
+ "--order", type=click.Choice(["activity", "default"]), help="Ordering method"
45
+ )
46
+ @click.option("--running", is_flag=True, help="Return only running recipes")
47
+ @click.option(
48
+ "--since-id", type=int, help="Return recipes with IDs lower than this value"
49
+ )
50
+ @click.option(
51
+ "--stopped-after", help="Exclude recipes stopped after this date (ISO 8601 format)"
52
+ )
53
+ @click.option(
54
+ "--stop-cause",
55
+ type=click.Choice(
56
+ [
57
+ "trigger_errors_limit",
58
+ "action_quota_limit",
59
+ "trial_expired",
60
+ "txn_quota_limit",
61
+ ]
62
+ ),
63
+ help="Filter by stop reason",
64
+ )
65
+ @click.option(
66
+ "--updated-after", help="Include recipes updated after this date (ISO 8601 format)"
67
+ )
68
+ @click.option("--include-tags", help="Filter by recipe tags (comma-separated)")
69
+ @click.option(
70
+ "--exclude-code", is_flag=True, help="Exclude recipe code from response (faster)"
71
+ )
72
+ @click.option(
73
+ "--recursive", is_flag=True, help="Recursively list recipes in subfolders"
74
+ )
75
+ @handle_cli_exceptions
76
+ @inject
77
+ @handle_api_exceptions
78
+ async def list_recipes(
79
+ adapter_names_all: str | None = None,
80
+ adapter_names_any: str | None = None,
81
+ folder_id: int | None = None,
82
+ order: str | None = None,
83
+ running: bool | None = None,
84
+ since_id: int | None = None,
85
+ stopped_after: str | None = None,
86
+ stop_cause: str | None = None,
87
+ updated_after: str | None = None,
88
+ include_tags: str | None = None,
89
+ exclude_code: bool | None = None,
90
+ recursive: bool | None = None,
91
+ config_manager: ConfigManager = Provide[Container.config_manager],
92
+ ) -> None:
93
+ """List recipes with optional filtering"""
94
+
95
+ folder_id = folder_id or config_manager.load_config().folder_id
96
+
97
+ if not folder_id:
98
+ click.echo("❌ No folder ID provided and no project configured.")
99
+ click.echo("πŸ’‘ Use --folder-id <ID> or run 'workato init' first.")
100
+ return
101
+
102
+ # Handle recursive mode
103
+ if recursive:
104
+ # Recursive mode - ignore some filters
105
+ if any(
106
+ [
107
+ adapter_names_all,
108
+ adapter_names_any,
109
+ order,
110
+ since_id,
111
+ stopped_after,
112
+ stop_cause,
113
+ updated_after,
114
+ include_tags,
115
+ ]
116
+ ):
117
+ click.echo("⚠️ Recursive mode ignores most filters except --running")
118
+
119
+ click.echo(f"πŸ” Recursively searching for recipes in folder {folder_id}...")
120
+ click.echo()
121
+
122
+ # Get all recipes recursively
123
+ recipes = await get_recipes_recursive(folder_id)
124
+
125
+ # Apply running filter if specified
126
+ if running:
127
+ recipes = [recipe for recipe in recipes if recipe.running]
128
+
129
+ click.echo()
130
+ click.echo(f"πŸ“Š Total: {len(recipes)} recipe(s) found across all folders")
131
+
132
+ if not recipes:
133
+ click.echo(" ℹ️ No recipes found")
134
+ return
135
+
136
+ click.echo()
137
+
138
+ # Display all recipes
139
+ for recipe in recipes:
140
+ display_recipe_summary(recipe=recipe)
141
+ click.echo()
142
+
143
+ click.echo("πŸ’‘ Commands:")
144
+ click.echo(" β€’ Start recipe: workato recipes start --id <ID>")
145
+ click.echo(" β€’ View running only: workato recipes list --running --recursive")
146
+ return
147
+
148
+ # Non-recursive mode - get ALL recipes with pagination
149
+ # Build filter description for user feedback
150
+ filter_parts = []
151
+ if folder_id:
152
+ filter_parts.append(f"folder {folder_id}")
153
+ if running:
154
+ filter_parts.append("running recipes only")
155
+ if adapter_names_all:
156
+ filter_parts.append(f"using ALL adapters: {adapter_names_all}")
157
+ if adapter_names_any:
158
+ filter_parts.append(f"using ANY adapters: {adapter_names_any}")
159
+ if stop_cause:
160
+ filter_parts.append(f"stopped due to: {stop_cause}")
161
+
162
+ filter_desc = f" ({', '.join(filter_parts)})" if filter_parts else ""
163
+
164
+ spinner = Spinner(f"Fetching all recipes{filter_desc}")
165
+ spinner.start()
166
+
167
+ try:
168
+ recipes = await get_all_recipes_paginated(
169
+ folder_id=folder_id,
170
+ adapter_names_all=adapter_names_all,
171
+ adapter_names_any=adapter_names_any,
172
+ order=order,
173
+ running=running,
174
+ since_id=since_id,
175
+ stopped_after=stopped_after,
176
+ stop_cause=stop_cause,
177
+ updated_after=updated_after,
178
+ include_tags=include_tags,
179
+ exclude_code=exclude_code,
180
+ )
181
+ finally:
182
+ elapsed = spinner.stop()
183
+
184
+ click.echo(f"πŸ“‹ Recipes ({len(recipes)} found) - ({elapsed:.1f}s)")
185
+ if filter_parts:
186
+ click.echo(f" πŸ” Filters: {', '.join(filter_parts)}")
187
+
188
+ if not recipes:
189
+ click.echo(" ℹ️ No recipes found")
190
+ return
191
+
192
+ click.echo()
193
+
194
+ # Display recipes
195
+ for recipe in recipes:
196
+ display_recipe_summary(recipe=recipe)
197
+ click.echo()
198
+
199
+ click.echo("πŸ’‘ Commands:")
200
+ click.echo(" β€’ Start recipe: workato recipes start --id <ID>")
201
+ click.echo(" β€’ View running only: workato recipes list --running")
202
+ click.echo(" β€’ Recursive search: workato recipes list --recursive")
203
+ click.echo(" β€’ Filter by folder: workato recipes list --folder-id <ID>")
204
+
205
+
206
+ @recipes.command()
207
+ @click.option("--path", required=True, help="Path to the recipe JSON file")
208
+ @handle_cli_exceptions
209
+ @inject
210
+ @handle_api_exceptions
211
+ async def validate(
212
+ path: str,
213
+ recipe_validator: RecipeValidator = Provide[Container.recipe_validator],
214
+ ) -> None:
215
+ """Validate a recipe file"""
216
+
217
+ recipe_path = Path(path)
218
+
219
+ # Check if file exists
220
+ if not recipe_path.exists():
221
+ click.echo(f"❌ File not found: {path}")
222
+ return
223
+
224
+ # Check if it's a JSON file
225
+ if recipe_path.suffix.lower() != ".json":
226
+ click.echo(f"❌ File must be a JSON file: {path}")
227
+ return
228
+
229
+ try:
230
+ # Read and parse the recipe file
231
+ with open(recipe_path) as f:
232
+ recipe_data = json.load(f)
233
+
234
+ # Validate the recipe
235
+ spinner = Spinner(f"Validating recipe: {recipe_path.name}")
236
+ spinner.start()
237
+
238
+ try:
239
+ result = await recipe_validator.validate_recipe(recipe_data)
240
+ finally:
241
+ elapsed = spinner.stop()
242
+
243
+ # Display results
244
+ if result.is_valid:
245
+ click.echo(f"βœ… Recipe validation passed ({elapsed:.1f}s)")
246
+ click.echo(f" πŸ“„ File: {recipe_path.name}")
247
+ else:
248
+ click.echo(f"❌ Recipe validation failed ({elapsed:.1f}s)")
249
+ click.echo(f" πŸ“„ File: {recipe_path.name}")
250
+ click.echo(f" ❗ {len(result.errors)} error(s) found")
251
+
252
+ for i, error in enumerate(result.errors, 1):
253
+ click.echo(f"\n Error {i}:")
254
+ if error.line_number:
255
+ click.echo(f" Line: {error.line_number}")
256
+ if error.field_label:
257
+ click.echo(f" Field: {error.field_label}")
258
+ if error.field_path:
259
+ click.echo(f" Path: {' -> '.join(error.field_path)}")
260
+ click.echo(f" Message: {error.message}")
261
+ if error.error_type:
262
+ click.echo(f" Type: {error.error_type.value}")
263
+
264
+ # Display warnings if any
265
+ if result.warnings:
266
+ click.echo(f"\n⚠️ {len(result.warnings)} warning(s):")
267
+ for warning in result.warnings:
268
+ click.echo(f" β€’ {warning.message}")
269
+
270
+ except json.JSONDecodeError as e:
271
+ click.echo(f"❌ Invalid JSON file: {str(e)}")
272
+ except (FileNotFoundError, PermissionError) as e:
273
+ click.echo(f"❌ File access error: {str(e)}")
274
+ except ValueError as e:
275
+ click.echo(f"❌ Validation failed: {str(e)}")
276
+
277
+
278
+ @recipes.command()
279
+ @click.option("--id", "recipe_id", type=int, help="Recipe ID to start")
280
+ @click.option(
281
+ "--all", "start_all", is_flag=True, help="Start all recipes in current project"
282
+ )
283
+ @click.option("--folder-id", type=int, help="Start all recipes in specified folder")
284
+ @handle_cli_exceptions
285
+ @handle_api_exceptions
286
+ async def start(
287
+ recipe_id: int,
288
+ start_all: bool,
289
+ folder_id: int,
290
+ ) -> None:
291
+ """Start recipes (individual, all in project, or all in folder)"""
292
+
293
+ # Validate that exactly one option is provided
294
+ options_count = sum([bool(recipe_id), start_all, bool(folder_id)])
295
+ if options_count == 0:
296
+ click.echo("❌ Please specify one of: --id, --all, or --folder-id")
297
+ click.echo("πŸ’‘ Examples:")
298
+ click.echo(" workato recipes start --id 12345")
299
+ click.echo(" workato recipes start --all")
300
+ click.echo(" workato recipes start --folder-id 67890")
301
+ return
302
+ elif options_count > 1:
303
+ click.echo("❌ Please specify only one option: --id, --all, or --folder-id")
304
+ return
305
+
306
+ if recipe_id:
307
+ # Start single recipe
308
+ await start_single_recipe(recipe_id)
309
+ elif start_all:
310
+ # Start all recipes in current project
311
+ await start_project_recipes()
312
+ elif folder_id:
313
+ # Start all recipes in specified folder
314
+ await start_folder_recipes(folder_id)
315
+
316
+
317
+ @recipes.command()
318
+ @click.option("--id", "recipe_id", type=int, help="Recipe ID to stop")
319
+ @click.option(
320
+ "--all", "stop_all", is_flag=True, help="Stop all recipes in current project"
321
+ )
322
+ @click.option("--folder-id", type=int, help="Stop all recipes in specified folder")
323
+ async def stop(
324
+ recipe_id: int,
325
+ stop_all: bool,
326
+ folder_id: int,
327
+ ) -> None:
328
+ """Stop recipes (individual, all in project, or all in folder)"""
329
+
330
+ # Validate that exactly one option is provided
331
+ options_count = sum([bool(recipe_id), stop_all, bool(folder_id)])
332
+ if options_count == 0:
333
+ click.echo("❌ Please specify one of: --id, --all, or --folder-id")
334
+ click.echo("πŸ’‘ Examples:")
335
+ click.echo(" workato recipes stop --id 12345")
336
+ click.echo(" workato recipes stop --all")
337
+ click.echo(" workato recipes stop --folder-id 67890")
338
+ return
339
+ elif options_count > 1:
340
+ click.echo("❌ Please specify only one option: --id, --all, or --folder-id")
341
+ return
342
+
343
+ if recipe_id:
344
+ # Stop single recipe
345
+ await stop_single_recipe(recipe_id)
346
+ elif stop_all:
347
+ # Stop all recipes in current project
348
+ await stop_project_recipes()
349
+ elif folder_id:
350
+ # Stop all recipes in specified folder
351
+ await stop_folder_recipes(folder_id)
352
+
353
+
354
+ def _display_recipe_errors(
355
+ recipe_start_response: RecipeStartResponse,
356
+ indent: str = " ",
357
+ ) -> None:
358
+ """Display detailed recipe error information in a readable format"""
359
+ # Handle code_errors (validation errors in recipe steps)
360
+ code_errors = recipe_start_response.code_errors
361
+ if code_errors:
362
+ click.echo(f"{indent}πŸ“‹ Recipe Validation Errors:")
363
+
364
+ for step_error in code_errors:
365
+ if len(step_error) >= 2:
366
+ step_number = step_error[0]
367
+ error_details = step_error[1]
368
+
369
+ click.echo(f"{indent} πŸ”Έ Step {step_number}:")
370
+
371
+ for error in error_details:
372
+ field_label = error[0]
373
+ account_id = error[1] # Connection ID (account_id)
374
+ error_message = error[2]
375
+ field_path = error[3]
376
+
377
+ click.echo(f"{indent} β€’ {field_label}: {error_message}")
378
+ if account_id is not None:
379
+ click.echo(f"{indent} Connection ID: {account_id}")
380
+ if field_path:
381
+ click.echo(f"{indent} Field: {field_path}")
382
+
383
+ # Handle config_errors (configuration-level errors)
384
+ config_errors = recipe_start_response.config_errors
385
+ if config_errors:
386
+ click.echo(f"{indent}βš™οΈ Configuration Errors:")
387
+
388
+ for config_error in config_errors:
389
+ if isinstance(config_error, list) and len(config_error) >= 2:
390
+ step_number = config_error[0]
391
+ error_details = config_error[1]
392
+
393
+ click.echo(f"{indent} πŸ”Έ Step {step_number}:")
394
+
395
+ for error in error_details:
396
+ if len(error) >= 3:
397
+ field_name = error[0]
398
+ account_id = error[1] # Connection ID (account_id)
399
+ error_message = error[2]
400
+
401
+ click.echo(f"{indent} β€’ {field_name}: {error_message}")
402
+ if account_id is not None:
403
+ click.echo(f"{indent} Connection ID: {account_id}")
404
+ else:
405
+ click.echo(f"{indent} β€’ {config_error}")
406
+
407
+
408
+ @inject
409
+ async def start_single_recipe(
410
+ recipe_id: int,
411
+ workato_api_client: Workato = Provide[Container.workato_api_client],
412
+ ) -> None:
413
+ """Start a single recipe by ID"""
414
+ spinner = Spinner(f"Starting recipe {recipe_id}")
415
+ spinner.start()
416
+
417
+ try:
418
+ recipe_start_response = await workato_api_client.recipes_api.start_recipe(
419
+ recipe_id
420
+ )
421
+ finally:
422
+ elapsed = spinner.stop()
423
+
424
+ # Check if the API response indicates success
425
+ if recipe_start_response.success:
426
+ click.echo(f"βœ… Recipe {recipe_id} started successfully ({elapsed:.1f}s)")
427
+ else:
428
+ # API returned success: false - extract error message
429
+ click.echo(f"❌ Recipe {recipe_id} failed to start ({elapsed:.1f}s)")
430
+
431
+ # Handle detailed error information
432
+ _display_recipe_errors(recipe_start_response=recipe_start_response)
433
+ return
434
+
435
+
436
+ @inject
437
+ async def start_project_recipes(
438
+ config_manager: ConfigManager = Provide[Container.config_manager],
439
+ ) -> None:
440
+ """Start all recipes in the current project"""
441
+ # Get project folder ID from meta file
442
+ meta_data = config_manager.load_config()
443
+ folder_id = meta_data.folder_id
444
+
445
+ if not folder_id:
446
+ click.echo("❌ No project configured. Please run 'workato init' first.")
447
+ return
448
+
449
+ click.echo(f"πŸš€ Starting all recipes in current project (folder {folder_id})")
450
+ await start_folder_recipes(folder_id)
451
+
452
+
453
+ @inject
454
+ async def start_folder_recipes(
455
+ folder_id: int,
456
+ workato_api_client: Workato = Provide[Container.workato_api_client],
457
+ ) -> None:
458
+ """Start all recipes in a specific folder"""
459
+ # First, get all recipes in the folder using the assets API
460
+ recipe_assets = await get_folder_recipe_assets(folder_id)
461
+
462
+ if not recipe_assets:
463
+ click.echo(f"ℹ️ No recipes found in folder {folder_id}")
464
+ return
465
+
466
+ click.echo(f"πŸ“‹ Found {len(recipe_assets)} recipe(s) to start")
467
+ click.echo()
468
+
469
+ # Track results
470
+ started_count = 0
471
+ failed_count = 0
472
+ failed_recipes: list[Asset] = []
473
+
474
+ # Start each recipe
475
+ for recipe in recipe_assets:
476
+ recipe_id = recipe.id
477
+ recipe_name = recipe.name
478
+
479
+ response = await workato_api_client.recipes_api.start_recipe(recipe_id)
480
+
481
+ if response.success:
482
+ click.echo(f" βœ… {recipe_name} (ID: {recipe_id})")
483
+ started_count += 1
484
+ else:
485
+ # success is false or missing - show detailed error
486
+ click.echo(f" ❌ {recipe_name} (ID: {recipe_id})")
487
+ _display_recipe_errors(response, indent=" ")
488
+ failed_count += 1
489
+ failed_recipes.append(recipe)
490
+
491
+ # Summary
492
+ click.echo()
493
+ click.echo(f"πŸ“Š Results: {started_count} started, {failed_count} failed")
494
+
495
+ if failed_recipes:
496
+ click.echo()
497
+ click.echo("❌ Failed recipes (you can retry individually):")
498
+ for recipe in failed_recipes:
499
+ click.echo(f" β€’ {recipe.name} (ID: {recipe.id})")
500
+ click.echo(f" Retry: workato recipes start --id {recipe.id}")
501
+
502
+
503
+ @inject
504
+ async def stop_single_recipe(
505
+ recipe_id: int,
506
+ workato_api_client: Workato = Provide[Container.workato_api_client],
507
+ ) -> None:
508
+ """Stop a single recipe by ID"""
509
+ spinner = Spinner(f"Stopping recipe {recipe_id}")
510
+ spinner.start()
511
+
512
+ try:
513
+ await workato_api_client.recipes_api.stop_recipe(recipe_id)
514
+ finally:
515
+ elapsed = spinner.stop()
516
+
517
+ click.echo(f"βœ… Recipe {recipe_id} stopped successfully ({elapsed:.1f}s)")
518
+
519
+
520
+ @inject
521
+ async def stop_project_recipes(
522
+ config_manager: ConfigManager = Provide[Container.config_manager],
523
+ ) -> None:
524
+ """Stop all recipes in the current project"""
525
+ # Get project folder ID from meta file
526
+ meta_data = config_manager.load_config()
527
+ folder_id = meta_data.folder_id
528
+
529
+ if not folder_id:
530
+ click.echo("❌ No project configured. Please run 'workato init' first.")
531
+ return
532
+
533
+ click.echo(f"πŸš€ Stopping all recipes in current project (folder {folder_id})")
534
+ await stop_folder_recipes(folder_id)
535
+
536
+
537
+ @inject
538
+ async def stop_folder_recipes(
539
+ folder_id: int,
540
+ workato_api_client: Workato = Provide[Container.workato_api_client],
541
+ ) -> None:
542
+ """Stop all recipes in a specific folder"""
543
+ # First, get all recipes in the folder using the assets API
544
+ recipes = await get_folder_recipe_assets(folder_id)
545
+
546
+ if not recipes:
547
+ click.echo(f"ℹ️ No recipes found in folder {folder_id}")
548
+ return
549
+
550
+ click.echo(f"πŸ“‹ Found {len(recipes)} recipe(s) to stop")
551
+ click.echo()
552
+
553
+ # Track results
554
+ stopped_count = 0
555
+
556
+ # Stop each recipe
557
+ for recipe in recipes:
558
+ recipe_id = recipe.id
559
+ recipe_name = recipe.name
560
+
561
+ await workato_api_client.recipes_api.stop_recipe(recipe_id)
562
+
563
+ click.echo(f" βœ… {recipe_name} (ID: {recipe_id})")
564
+ stopped_count += 1
565
+
566
+ # Summary
567
+ click.echo()
568
+ click.echo(f"πŸ“Š Results: {stopped_count} stopped")
569
+
570
+
571
+ @inject
572
+ async def get_folder_recipe_assets(
573
+ folder_id: int,
574
+ workato_api_client: Workato = Provide[Container.workato_api_client],
575
+ ) -> list[Asset]:
576
+ """Get all recipes in a folder using the assets API"""
577
+ spinner = Spinner(f"Fetching recipes in folder {folder_id}")
578
+ spinner.start()
579
+
580
+ try:
581
+ # Use existing utility function
582
+ assets_response = await workato_api_client.export_api.list_assets_in_folder(
583
+ folder_id=folder_id,
584
+ )
585
+ finally:
586
+ elapsed = spinner.stop()
587
+
588
+ # Filter for recipe assets
589
+ recipes = [
590
+ asset for asset in assets_response.result.assets if asset.type == "recipe"
591
+ ]
592
+
593
+ click.echo(
594
+ f"πŸ” Found {len(recipes)} recipe(s) in folder {folder_id} ({elapsed:.1f}s)"
595
+ )
596
+
597
+ return recipes
598
+
599
+
600
+ @inject
601
+ async def get_all_recipes_paginated(
602
+ folder_id: int,
603
+ adapter_names_all: str | None = None,
604
+ adapter_names_any: str | None = None,
605
+ order: str | None = None,
606
+ running: bool | None = None,
607
+ since_id: int | None = None,
608
+ stopped_after: str | None = None,
609
+ stop_cause: str | None = None,
610
+ updated_after: str | None = None,
611
+ include_tags: str | None = None,
612
+ exclude_code: bool | None = None,
613
+ workato_api_client: Workato = Provide[Container.workato_api_client],
614
+ ) -> list[Recipe]:
615
+ """Get all recipes in a folder with automatic pagination"""
616
+ all_recipes = []
617
+ page = 1
618
+ while True:
619
+ response = await workato_api_client.recipes_api.list_recipes(
620
+ adapter_names_all=adapter_names_all,
621
+ adapter_names_any=adapter_names_any,
622
+ folder_id=folder_id,
623
+ order=order,
624
+ page=page,
625
+ per_page=100,
626
+ running=running,
627
+ since_id=since_id,
628
+ stopped_after=datetime.fromisoformat(stopped_after)
629
+ if stopped_after
630
+ else None,
631
+ stop_cause=stop_cause,
632
+ updated_after=datetime.fromisoformat(updated_after)
633
+ if updated_after
634
+ else None,
635
+ includes=[tag.strip() for tag in include_tags.split(",")]
636
+ if include_tags
637
+ else None,
638
+ exclude_code=exclude_code if exclude_code else None,
639
+ )
640
+
641
+ all_recipes.extend(response.items)
642
+
643
+ # If we got less than 100 results, we're on the last page
644
+ if len(response.items) < 100:
645
+ break
646
+
647
+ page += 1
648
+
649
+ return all_recipes
650
+
651
+
652
+ @inject
653
+ async def get_recipes_recursive(
654
+ folder_id: int,
655
+ visited_folders: set | None = None,
656
+ workato_api_client: Workato = Provide[Container.workato_api_client],
657
+ ) -> list[Recipe]:
658
+ """Recursively get all recipes in a folder and its subfolders"""
659
+ if visited_folders is None:
660
+ visited_folders = set()
661
+
662
+ # Prevent infinite loops in case of circular folder references
663
+ if folder_id in visited_folders:
664
+ return []
665
+
666
+ visited_folders.add(folder_id)
667
+
668
+ all_recipes = []
669
+
670
+ # Get ALL recipes in current folder with pagination
671
+ spinner = Spinner(f"Fetching recipes in folder {folder_id}")
672
+ spinner.start()
673
+
674
+ try:
675
+ folder_recipes = await get_all_recipes_paginated(
676
+ folder_id=folder_id,
677
+ exclude_code=True,
678
+ )
679
+ all_recipes.extend(folder_recipes)
680
+
681
+ finally:
682
+ elapsed = spinner.stop()
683
+
684
+ click.echo(
685
+ f"πŸ“‚ Found {len(folder_recipes)} recipe(s) in folder {folder_id} "
686
+ f"({elapsed:.1f}s)"
687
+ )
688
+
689
+ # Get ALL subfolders and recursively process them with pagination
690
+ spinner = Spinner(f"Fetching subfolders in folder {folder_id}")
691
+ spinner.start()
692
+
693
+ try:
694
+ folders = []
695
+ page = 1
696
+ while True:
697
+ folder_response = await workato_api_client.folders_api.list_folders(
698
+ parent_id=folder_id,
699
+ page=page,
700
+ per_page=100,
701
+ )
702
+
703
+ folders.extend(folder_response)
704
+
705
+ # If we got less than 100 results, we're on the last page
706
+ if len(folder_response) < 100:
707
+ break
708
+
709
+ page += 1
710
+
711
+ finally:
712
+ elapsed = spinner.stop()
713
+
714
+ folder_count = len(folders)
715
+ click.echo(
716
+ f"πŸ“ Found {folder_count} subfolder(s) in folder {folder_id} ({elapsed:.1f}s)"
717
+ )
718
+
719
+ # Recursively get recipes from each subfolder
720
+ for folder in folders:
721
+ subfolder_recipes = await get_recipes_recursive(
722
+ folder.id, visited_folders, workato_api_client
723
+ )
724
+ all_recipes.extend(subfolder_recipes)
725
+
726
+ return all_recipes
727
+
728
+
729
+ def display_recipe_summary(recipe: Recipe) -> None:
730
+ """Display a summary of a recipe"""
731
+ name = recipe.name
732
+ recipe_id = recipe.id
733
+ running = recipe.running
734
+
735
+ status_icon = "▢️" if running else "⏸️"
736
+ status_text = "Running" if running else "Stopped"
737
+
738
+ click.echo(f" {status_icon} {name}")
739
+ click.echo(f" πŸ†” ID: {recipe_id}")
740
+ click.echo(f" πŸ“Š Status: {status_text}")
741
+ click.echo(f" πŸ“± Trigger App: {recipe.trigger_application}")
742
+
743
+ # Show action applications if available
744
+ if recipe.action_applications:
745
+ apps_display = ", ".join(recipe.action_applications)
746
+ click.echo(f" πŸ”§ Action Apps: {apps_display}")
747
+
748
+ # Show config information (applications/connections configured)
749
+ if recipe.config:
750
+ config_apps = []
751
+ for config_item in recipe.config:
752
+ if config_item.keyword == "application":
753
+ name = config_item.name or ""
754
+
755
+ # Show account_id if present and not null
756
+ account_info = ""
757
+ if config_item.account_id:
758
+ account_info = f" (Account: {config_item.account_id})"
759
+
760
+ config_apps.append(f"{name}{account_info}")
761
+
762
+ if config_apps:
763
+ config_display = ", ".join(config_apps)
764
+ click.echo(f" βš™οΈ Config Apps: {config_display}")
765
+
766
+ click.echo(f" πŸ“ Folder ID: {recipe.folder_id}")
767
+
768
+ # Show job statistics if available
769
+ succeeded = recipe.job_succeeded_count
770
+ failed = recipe.job_failed_count
771
+ if succeeded > 0 or failed > 0:
772
+ click.echo(f" πŸ“Š Jobs: {succeeded} succeeded, {failed} failed")
773
+
774
+ # Show last run information if available
775
+ if recipe.last_run_at:
776
+ click.echo(f" πŸ• Last Run: {recipe.last_run_at.isoformat()}")
777
+
778
+ # Show stopped time if recipe is stopped
779
+ if not running and recipe.stopped_at:
780
+ click.echo(f" ⏹️ Stopped: {recipe.stopped_at.isoformat()}")
781
+
782
+ # Show stop cause if recipe is stopped and has a cause
783
+ if not running and recipe.stop_cause:
784
+ stop_cause = recipe.stop_cause.replace("_", " ").title()
785
+ click.echo(f" ⚠️ Stop Cause: {stop_cause}")
786
+
787
+ # Show creation date if available
788
+ if recipe.created_at:
789
+ click.echo(f" πŸ“… Created: {recipe.created_at.isoformat()}")
790
+
791
+ # Show author information if available
792
+ if recipe.author_name:
793
+ click.echo(f" πŸ‘€ Author: {recipe.author_name}")
794
+
795
+ if recipe.tags:
796
+ tags_display = ", ".join(recipe.tags)
797
+ click.echo(f" 🏷️ Tags: {tags_display}")
798
+
799
+ # Show description if available (truncated)
800
+ if recipe.description:
801
+ description = recipe.description
802
+ if len(description) > 80:
803
+ description = description[:77] + "..."
804
+ click.echo(f" πŸ“ Description: {description}")
805
+
806
+
807
+ @recipes.command()
808
+ @click.argument("recipe_id", type=int)
809
+ @click.option(
810
+ "--adapter-name",
811
+ required=True,
812
+ help="The internal name of the connector (e.g., box, salesforce)",
813
+ )
814
+ @click.option(
815
+ "--connection-id", required=True, type=int, help="The ID of the connection to use"
816
+ )
817
+ @handle_cli_exceptions
818
+ @inject
819
+ @handle_api_exceptions
820
+ async def update_connection(
821
+ recipe_id: int,
822
+ adapter_name: str,
823
+ connection_id: int,
824
+ workato_api_client: Workato = Provide[Container.workato_api_client],
825
+ ) -> None:
826
+ """Update a connection for a specific connector in a recipe"""
827
+
828
+ spinner = Spinner("Updating recipe connection...")
829
+ spinner.start()
830
+
831
+ try:
832
+ await workato_api_client.recipes_api.update_recipe_connection(
833
+ recipe_id=recipe_id,
834
+ recipe_connection_update_request=RecipeConnectionUpdateRequest(
835
+ adapter_name=adapter_name,
836
+ connection_id=connection_id,
837
+ ),
838
+ )
839
+
840
+ finally:
841
+ elapsed = spinner.stop()
842
+
843
+ click.echo(
844
+ f"βœ… Successfully updated connection for recipe {recipe_id} ({elapsed:.1f}s)"
845
+ )
846
+ click.echo(f" πŸ”— Connector: {adapter_name}")
847
+ click.echo(f" πŸ†” Connection ID: {connection_id}")