uipath 2.0.0.dev2__py3-none-any.whl → 2.0.1.dev1__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.

Potentially problematic release.


This version of uipath might be problematic. Click here for more details.

Files changed (76) hide show
  1. uipath/__init__.py +24 -0
  2. uipath/_cli/README.md +11 -0
  3. uipath/_cli/__init__.py +54 -0
  4. uipath/_cli/_auth/_auth_server.py +165 -0
  5. uipath/_cli/_auth/_models.py +51 -0
  6. uipath/_cli/_auth/_oidc_utils.py +69 -0
  7. uipath/_cli/_auth/_portal_service.py +163 -0
  8. uipath/_cli/_auth/_utils.py +51 -0
  9. uipath/_cli/_auth/auth_config.json +6 -0
  10. uipath/_cli/_auth/index.html +167 -0
  11. uipath/_cli/_auth/localhost.crt +25 -0
  12. uipath/_cli/_auth/localhost.key +27 -0
  13. uipath/_cli/_runtime/_contracts.py +429 -0
  14. uipath/_cli/_runtime/_logging.py +193 -0
  15. uipath/_cli/_runtime/_runtime.py +264 -0
  16. uipath/_cli/_templates/.psmdcp.template +9 -0
  17. uipath/_cli/_templates/.rels.template +5 -0
  18. uipath/_cli/_templates/[Content_Types].xml.template +9 -0
  19. uipath/_cli/_templates/main.py.template +25 -0
  20. uipath/_cli/_templates/package.nuspec.template +10 -0
  21. uipath/_cli/_utils/_common.py +24 -0
  22. uipath/_cli/_utils/_input_args.py +126 -0
  23. uipath/_cli/_utils/_parse_ast.py +542 -0
  24. uipath/_cli/cli_auth.py +97 -0
  25. uipath/_cli/cli_deploy.py +13 -0
  26. uipath/_cli/cli_init.py +113 -0
  27. uipath/_cli/cli_new.py +76 -0
  28. uipath/_cli/cli_pack.py +337 -0
  29. uipath/_cli/cli_publish.py +113 -0
  30. uipath/_cli/cli_run.py +133 -0
  31. uipath/_cli/middlewares.py +113 -0
  32. uipath/_config.py +6 -0
  33. uipath/_execution_context.py +83 -0
  34. uipath/_folder_context.py +62 -0
  35. uipath/_models/__init__.py +37 -0
  36. uipath/_models/action_schema.py +26 -0
  37. uipath/_models/actions.py +64 -0
  38. uipath/_models/assets.py +48 -0
  39. uipath/_models/connections.py +51 -0
  40. uipath/_models/context_grounding.py +18 -0
  41. uipath/_models/context_grounding_index.py +60 -0
  42. uipath/_models/exceptions.py +6 -0
  43. uipath/_models/interrupt_models.py +28 -0
  44. uipath/_models/job.py +66 -0
  45. uipath/_models/llm_gateway.py +101 -0
  46. uipath/_models/processes.py +48 -0
  47. uipath/_models/queues.py +167 -0
  48. uipath/_services/__init__.py +26 -0
  49. uipath/_services/_base_service.py +250 -0
  50. uipath/_services/actions_service.py +271 -0
  51. uipath/_services/api_client.py +89 -0
  52. uipath/_services/assets_service.py +257 -0
  53. uipath/_services/buckets_service.py +268 -0
  54. uipath/_services/connections_service.py +185 -0
  55. uipath/_services/connections_service.pyi +50 -0
  56. uipath/_services/context_grounding_service.py +402 -0
  57. uipath/_services/folder_service.py +49 -0
  58. uipath/_services/jobs_service.py +265 -0
  59. uipath/_services/llm_gateway_service.py +311 -0
  60. uipath/_services/processes_service.py +168 -0
  61. uipath/_services/queues_service.py +314 -0
  62. uipath/_uipath.py +98 -0
  63. uipath/_utils/__init__.py +17 -0
  64. uipath/_utils/_endpoint.py +79 -0
  65. uipath/_utils/_infer_bindings.py +30 -0
  66. uipath/_utils/_logs.py +15 -0
  67. uipath/_utils/_request_override.py +18 -0
  68. uipath/_utils/_request_spec.py +23 -0
  69. uipath/_utils/_user_agent.py +16 -0
  70. uipath/_utils/constants.py +25 -0
  71. uipath/py.typed +0 -0
  72. {uipath-2.0.0.dev2.dist-info → uipath-2.0.1.dev1.dist-info}/METADATA +2 -3
  73. uipath-2.0.1.dev1.dist-info/RECORD +75 -0
  74. uipath-2.0.0.dev2.dist-info/RECORD +0 -4
  75. {uipath-2.0.0.dev2.dist-info → uipath-2.0.1.dev1.dist-info}/WHEEL +0 -0
  76. {uipath-2.0.0.dev2.dist-info → uipath-2.0.1.dev1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,542 @@
1
+ # type: ignore
2
+
3
+ import ast
4
+ import os
5
+ from dataclasses import dataclass, field
6
+ from typing import Any, Dict, List, Optional
7
+
8
+ from ..._services import AssetsService, BucketsService, ProcessesService
9
+ from ..._utils import get_inferred_bindings_names
10
+
11
+
12
+ @dataclass
13
+ class ServiceMethodCall:
14
+ """Represents a call to a service method with its parameters."""
15
+
16
+ method_name: str
17
+ args: List[Any] = field(default_factory=list)
18
+ kwargs: Dict[str, Any] = field(default_factory=dict)
19
+ line_number: int = 0
20
+
21
+ def extract_string_arg(self, index: int = 0) -> Optional[str]:
22
+ """Extract a string argument at the given position if it exists."""
23
+ if index < len(self.args):
24
+ if isinstance(self.args[index], str):
25
+ return self.args[index]
26
+ elif isinstance(self.args[index], (int, float, bool)):
27
+ return str(self.args[index])
28
+ return None
29
+
30
+
31
+ service_name_resource_mapping = {
32
+ "assets": "asset",
33
+ "processes": "process",
34
+ "buckets": "bucket",
35
+ "connections": "connection",
36
+ }
37
+
38
+
39
+ def transform_connector_name(connector_name: str) -> str:
40
+ """Transform connector name from underscore format to hyphenated format.
41
+
42
+ Args:
43
+ connector_name: Connector name in format "one_two"
44
+
45
+ Returns:
46
+ str: Connector name in format "uipath-one-two"
47
+
48
+ Examples:
49
+ >>> transform_connector_name("google_gmail")
50
+ 'uipath-google-gmail'
51
+ >>> transform_connector_name("salesforce_sfdc")
52
+ 'uipath-salesforce-sfdc'
53
+ """
54
+ if not connector_name:
55
+ return ""
56
+ parts = connector_name.split("_")
57
+ return f"uipath-{'-'.join(parts)}"
58
+
59
+
60
+ @dataclass
61
+ class ServiceUsage:
62
+ """Collects all method calls for a specific service type."""
63
+
64
+ service_name: str
65
+ method_calls: List[ServiceMethodCall] = field(default_factory=list)
66
+
67
+ def get_component_info(self) -> List[Dict[str, str]]:
68
+ """Extract component names and folders based on the service type."""
69
+ result = []
70
+
71
+ if self.service_name == "assets":
72
+ for call in self.method_calls:
73
+ inferred_bindings = get_inferred_bindings_names(AssetsService)
74
+ if call.method_name in inferred_bindings:
75
+ name = extract_parameter(
76
+ call, inferred_bindings[call.method_name]["name"], 0
77
+ )
78
+ folder_path = extract_parameter(
79
+ call, inferred_bindings[call.method_name]["folder_path"]
80
+ )
81
+ if name:
82
+ result.append(
83
+ {
84
+ "name": name,
85
+ "folder": folder_path or "",
86
+ "method": call.method_name,
87
+ }
88
+ )
89
+
90
+ elif self.service_name == "processes":
91
+ for call in self.method_calls:
92
+ inferred_bindings = get_inferred_bindings_names(ProcessesService)
93
+ if call.method_name in inferred_bindings:
94
+ name = extract_parameter(
95
+ call, inferred_bindings[call.method_name]["name"], 0
96
+ )
97
+ folder_path = extract_parameter(
98
+ call, inferred_bindings[call.method_name]["folder_path"]
99
+ )
100
+ if name:
101
+ result.append(
102
+ {
103
+ "name": name,
104
+ "folder": folder_path or "",
105
+ "method": call.method_name,
106
+ }
107
+ )
108
+
109
+ elif self.service_name == "buckets":
110
+ for call in self.method_calls:
111
+ inferred_bindings = get_inferred_bindings_names(BucketsService)
112
+ if call.method_name in inferred_bindings:
113
+ name = extract_parameter(
114
+ call, inferred_bindings[call.method_name]["name"], 0
115
+ )
116
+ folder_path = extract_parameter(
117
+ call, inferred_bindings[call.method_name]["folder_path"]
118
+ )
119
+ if name:
120
+ result.append(
121
+ {
122
+ "name": name,
123
+ "folder": folder_path or "",
124
+ "method": call.method_name,
125
+ }
126
+ )
127
+
128
+ elif self.service_name == "connections":
129
+ for call in self.method_calls:
130
+ connection_id = None
131
+ if len(call.args) > 0:
132
+ connection_id = call.args[0]
133
+ if connection_id:
134
+ result.append(
135
+ {
136
+ "name": str(connection_id),
137
+ "connector": call.method_name,
138
+ "method": "connector",
139
+ }
140
+ )
141
+
142
+ return result
143
+
144
+
145
+ def extract_parameter(
146
+ method_call: ServiceMethodCall,
147
+ param_name: str,
148
+ position_index: Optional[int] = None,
149
+ ) -> Optional[Any]:
150
+ """Extract a parameter from a method call, checking both keyword and positional arguments.
151
+
152
+ Args:
153
+ method_call: The ServiceMethodCall object
154
+ param_name: The name of the parameter to extract
155
+ position_index: Optional position of the parameter if passed as a positional argument
156
+
157
+ Returns:
158
+ The parameter value if found, None otherwise
159
+ """
160
+ if param_name in method_call.kwargs:
161
+ return method_call.kwargs[param_name]
162
+
163
+ if position_index is not None and position_index < len(method_call.args):
164
+ return method_call.args[position_index]
165
+
166
+ return None
167
+
168
+
169
+ def parse_local_module(
170
+ module_path: str, base_dir: str
171
+ ) -> Dict[str, List[Dict[str, str]]]:
172
+ """Parse a local module and extract SDK usage.
173
+
174
+ Args:
175
+ module_path: Import path of the module (e.g., 'myapp.utils')
176
+ base_dir: Base directory to resolve relative imports
177
+
178
+ Returns:
179
+ Dictionary of SDK usage from the module
180
+ """
181
+ # Convert module path to file path
182
+ file_path = os.path.join(base_dir, *module_path.split(".")) + ".py"
183
+
184
+ # Check if the file exists
185
+ if not os.path.exists(file_path):
186
+ # Try as a package with __init__.py
187
+ file_path = os.path.join(base_dir, *module_path.split("."), "__init__.py")
188
+ if not os.path.exists(file_path):
189
+ return {}
190
+
191
+ # Parse the module
192
+ try:
193
+ with open(file_path, "r") as f:
194
+ source_code = f.read()
195
+ return parse_sdk_usage(source_code, base_dir)
196
+ except Exception:
197
+ return {}
198
+
199
+
200
+ class UiPathTracker:
201
+ """Tracks UiPath usage throughout the code."""
202
+
203
+ def __init__(self, source_code: str, base_dir: str = ""):
204
+ self.source_code = source_code
205
+ self.base_dir = base_dir
206
+ self.tree = ast.parse(source_code)
207
+ self.sdk_imports: Dict[str, str] = {} # Import alias -> original module
208
+ self.sdk_instances: Dict[str, str] = {} # Instance name -> class
209
+ self.local_imports: List[str] = [] # List of local module imports
210
+ self.service_usage: Dict[str, ServiceUsage] = {
211
+ "assets": ServiceUsage("assets"),
212
+ "processes": ServiceUsage("processes"),
213
+ "buckets": ServiceUsage("buckets"),
214
+ "actions": ServiceUsage("actions"),
215
+ "context_grounding": ServiceUsage("context_grounding"),
216
+ "api_client": ServiceUsage("api_client"),
217
+ "connections": ServiceUsage("connections"), # Add connections service
218
+ }
219
+
220
+ def analyze(self) -> None:
221
+ """Run all analysis steps."""
222
+ self._find_imports()
223
+ self._find_instances()
224
+ self._find_method_calls()
225
+
226
+ def _find_imports(self) -> None:
227
+ """Find all imports of UiPath and local modules."""
228
+
229
+ class ImportVisitor(ast.NodeVisitor):
230
+ def __init__(self):
231
+ self.imports = {}
232
+ self.local_imports = []
233
+
234
+ def visit_Import(self, node):
235
+ for alias in node.names:
236
+ if alias.name == "uipath":
237
+ self.imports[alias.asname or alias.name] = alias.name
238
+ elif (
239
+ not alias.name.startswith(("__", "builtins", "typing"))
240
+ and "." not in alias.name
241
+ ):
242
+ # Potential local import
243
+ self.local_imports.append(alias.name)
244
+ self.generic_visit(node)
245
+
246
+ def visit_ImportFrom(self, node):
247
+ if node.module == "uipath":
248
+ for alias in node.names:
249
+ if alias.name == "UiPath":
250
+ self.imports[alias.asname or alias.name] = "uipath.UiPath"
251
+ elif node.module and not node.module.startswith(
252
+ ("__", "builtins", "typing")
253
+ ):
254
+ # Potential local import
255
+ self.local_imports.append(node.module)
256
+ self.generic_visit(node)
257
+
258
+ visitor = ImportVisitor()
259
+ visitor.visit(self.tree)
260
+ self.sdk_imports = visitor.imports
261
+ self.local_imports = visitor.local_imports
262
+
263
+ def _find_instances(self) -> None:
264
+ """Find all instances created from UiPath."""
265
+
266
+ class InstanceVisitor(ast.NodeVisitor):
267
+ def __init__(self, sdk_imports):
268
+ self.sdk_imports = sdk_imports
269
+ self.instances = {}
270
+
271
+ def visit_Assign(self, node):
272
+ if isinstance(node.value, ast.Call):
273
+ call = node.value
274
+ if (
275
+ isinstance(call.func, ast.Name)
276
+ and call.func.id in self.sdk_imports
277
+ ):
278
+ for target in node.targets:
279
+ if isinstance(target, ast.Name):
280
+ self.instances[target.id] = "UiPath"
281
+ self.generic_visit(node)
282
+
283
+ visitor = InstanceVisitor(self.sdk_imports)
284
+ visitor.visit(self.tree)
285
+ self.sdk_instances = visitor.instances
286
+
287
+ def _find_method_calls(self) -> None:
288
+ """Find all method calls on UiPath instances."""
289
+
290
+ class MethodCallVisitor(ast.NodeVisitor):
291
+ def __init__(self, source_code, sdk_instances, service_usage):
292
+ self.source_code = source_code
293
+ self.sdk_instances = sdk_instances
294
+ self.service_usage = service_usage
295
+
296
+ def visit_Call(self, node):
297
+ if isinstance(node.func, ast.Attribute) and isinstance(
298
+ node.func.value, ast.Attribute
299
+ ):
300
+ if (
301
+ isinstance(node.func.value.value, ast.Name)
302
+ and node.func.value.value.id in self.sdk_instances
303
+ ):
304
+ service_name = node.func.value.attr
305
+ method_name = node.func.attr
306
+
307
+ if service_name in self.service_usage:
308
+ # Extract arguments
309
+ args = []
310
+ for arg in node.args:
311
+ if isinstance(arg, ast.Constant) and isinstance(
312
+ arg.value, str
313
+ ):
314
+ args.append(arg.value)
315
+ elif isinstance(arg, ast.Constant):
316
+ # Handle non-string constants normally
317
+ args.append(arg.value)
318
+ else:
319
+ # For expressions and variables, prefix with EXPR$
320
+ source_segment = ast.get_source_segment(
321
+ self.source_code, arg
322
+ )
323
+ args.append(f"EXPR${source_segment}")
324
+
325
+ kwargs = {}
326
+ for keyword in node.keywords:
327
+ if isinstance(keyword.value, ast.Constant):
328
+ kwargs[keyword.arg] = keyword.value.value
329
+ else:
330
+ source_segment = ast.get_source_segment(
331
+ self.source_code, keyword.value
332
+ )
333
+ kwargs[keyword.arg] = f"EXPR${source_segment}"
334
+
335
+ method_call = ServiceMethodCall(
336
+ method_name=method_name,
337
+ args=args,
338
+ kwargs=kwargs,
339
+ line_number=node.lineno,
340
+ )
341
+ self.service_usage[service_name].method_calls.append(
342
+ method_call
343
+ )
344
+
345
+ elif isinstance(node.func, ast.Attribute) and isinstance(
346
+ node.func.value, ast.Attribute
347
+ ):
348
+ if (
349
+ isinstance(node.func.value.value, ast.Name)
350
+ and node.func.value.value.id in self.sdk_instances
351
+ and node.func.value.attr == "connections"
352
+ ):
353
+ connector_name = node.func.attr
354
+
355
+ args = []
356
+ for arg in node.args:
357
+ if isinstance(arg, ast.Constant) and isinstance(
358
+ arg.value, (str, int)
359
+ ):
360
+ args.append(arg.value)
361
+ elif isinstance(arg, ast.Constant):
362
+ args.append(arg.value)
363
+ else:
364
+ source_segment = ast.get_source_segment(
365
+ self.source_code, arg
366
+ )
367
+ args.append(f"EXPR${source_segment}")
368
+
369
+ kwargs = {}
370
+ for keyword in node.keywords:
371
+ if isinstance(keyword.value, ast.Constant):
372
+ kwargs[keyword.arg] = keyword.value.value
373
+ else:
374
+ source_segment = ast.get_source_segment(
375
+ self.source_code, keyword.value
376
+ )
377
+ kwargs[keyword.arg] = f"EXPR${source_segment}"
378
+
379
+ method_call = ServiceMethodCall(
380
+ method_name=connector_name,
381
+ args=args,
382
+ kwargs=kwargs,
383
+ line_number=node.lineno,
384
+ )
385
+ self.service_usage["connections"].method_calls.append(
386
+ method_call
387
+ )
388
+
389
+ self.generic_visit(node)
390
+
391
+ visitor = MethodCallVisitor(
392
+ self.source_code, self.sdk_instances, self.service_usage
393
+ )
394
+ visitor.visit(self.tree)
395
+
396
+ def get_results(self) -> Dict[str, List[Dict[str, str]]]:
397
+ """Get the analysis results organized by service type."""
398
+ results = {}
399
+ for service_name, usage in self.service_usage.items():
400
+ components = usage.get_component_info()
401
+ if components:
402
+ results[service_name] = components
403
+ return results
404
+
405
+
406
+ def parse_sdk_usage(
407
+ source_code: str, base_dir: str = ""
408
+ ) -> Dict[str, List[Dict[str, str]]]:
409
+ """Parse the source code and return UiPath usage information.
410
+
411
+ Args:
412
+ source_code: The Python source code to analyze
413
+ base_dir: Base directory to resolve relative imports
414
+
415
+ Returns:
416
+ Dictionary of SDK usage information
417
+ """
418
+ tracker = UiPathTracker(source_code, base_dir)
419
+ tracker.analyze()
420
+ results = tracker.get_results()
421
+
422
+ # Parse local imports recursively
423
+ if base_dir:
424
+ for module_path in tracker.local_imports:
425
+ module_results = parse_local_module(module_path, base_dir)
426
+
427
+ # Merge results
428
+ for service_name, components in module_results.items():
429
+ if service_name in results:
430
+ results[service_name].extend(components)
431
+ else:
432
+ results[service_name] = components
433
+
434
+ return results
435
+
436
+
437
+ def convert_to_bindings_format(sdk_usage_data):
438
+ """Convert the output of parse_sdk_usage to a structure similar to bindings_v2.json.
439
+
440
+ Args:
441
+ sdk_usage_data: Dictionary output from parse_sdk_usage
442
+
443
+ Returns:
444
+ Dictionary in bindings_v2.json format
445
+ """
446
+ bindings = {"version": "2.0", "resources": []}
447
+
448
+ for resource_type, components in sdk_usage_data.items():
449
+ for component in components:
450
+ if resource_type == "connections":
451
+ connection_id = component.get("name", "")
452
+ connector_name = transform_connector_name(
453
+ component.get("connector", "")
454
+ )
455
+ is_connection_id_expression = connection_id.startswith("EXPR$")
456
+ connection_id = connection_id.replace("EXPR$", "")
457
+ resource_entry = {
458
+ "resource": "connection",
459
+ "key": connection_id,
460
+ "value": {
461
+ "ConnectionId": {
462
+ "defaultValue": connection_id,
463
+ "isExpression": is_connection_id_expression,
464
+ "displayName": "Connection",
465
+ "description": "The connection to be used",
466
+ }
467
+ },
468
+ "metadata": {
469
+ "BindingsVersion": "2.1",
470
+ "Connector": connector_name,
471
+ "UseConnectionService": "True",
472
+ },
473
+ }
474
+
475
+ bindings["resources"].append(resource_entry)
476
+ continue
477
+
478
+ resource_name = component.get("name", "")
479
+ folder_path = component.get("folder", None)
480
+ method_name = component.get("method", "Unknown")
481
+
482
+ name = resource_name
483
+
484
+ is_expression = name.startswith("EXPR$")
485
+ is_folder_path_expression = folder_path and folder_path.startswith("EXPR$")
486
+ name = name.replace("EXPR$", "")
487
+ folder_path = folder_path.replace("EXPR$", "") if folder_path else None
488
+ key = name
489
+ if folder_path:
490
+ key = f"{folder_path}.{name}"
491
+ resource_entry = {
492
+ "resource": service_name_resource_mapping[resource_type],
493
+ "key": key,
494
+ "value": {
495
+ "name": {
496
+ "defaultValue": name,
497
+ "isExpression": is_expression,
498
+ "displayName": "Name",
499
+ }
500
+ },
501
+ "metadata": {
502
+ "ActivityName": method_name,
503
+ "BindingsVersion": "2.1",
504
+ "DisplayLabel": "FullName",
505
+ },
506
+ }
507
+
508
+ if folder_path:
509
+ resource_entry["value"]["folderPath"] = {
510
+ "defaultValue": folder_path,
511
+ "isExpression": is_folder_path_expression,
512
+ "displayName": "Folder Path",
513
+ }
514
+
515
+ bindings["resources"].append(resource_entry)
516
+
517
+ return bindings
518
+
519
+
520
+ def generate_bindings_json(file_path: str) -> str:
521
+ """Generate bindings JSON from a Python file.
522
+
523
+ Args:
524
+ file_path: Path to the Python file to analyze
525
+
526
+ Returns:
527
+ JSON string representation of the bindings
528
+ """
529
+ try:
530
+ with open(file_path, "r") as f:
531
+ source_code = f.read()
532
+
533
+ # Get the base directory for resolving imports
534
+ base_dir = os.path.dirname(os.path.abspath(file_path))
535
+
536
+ sdk_usage = parse_sdk_usage(source_code, base_dir)
537
+ bindings = convert_to_bindings_format(sdk_usage)
538
+
539
+ return bindings
540
+
541
+ except Exception as e:
542
+ raise Exception(f"Error generating bindings JSON: {e}") from e
@@ -0,0 +1,97 @@
1
+ # type: ignore
2
+ import json
3
+ import os
4
+ import socket
5
+ import webbrowser
6
+
7
+ import click
8
+ from dotenv import load_dotenv
9
+
10
+ from ._auth._auth_server import HTTPSServer
11
+ from ._auth._oidc_utils import get_auth_config, get_auth_url
12
+ from ._auth._portal_service import PortalService, select_tenant
13
+ from ._auth._utils import update_auth_file, update_env_file
14
+ from ._utils._common import environment_options
15
+
16
+ load_dotenv()
17
+
18
+
19
+ def is_port_in_use(port: int) -> bool:
20
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
21
+ try:
22
+ s.bind(("localhost", port))
23
+ s.close()
24
+ return False
25
+ except socket.error:
26
+ return True
27
+
28
+
29
+ def set_port():
30
+ auth_config = get_auth_config()
31
+ port = auth_config.get("port", 8104)
32
+ port_option_one = auth_config.get("portOptionOne", 8104)
33
+ port_option_two = auth_config.get("portOptionTwo", 8055)
34
+ port_option_three = auth_config.get("portOptionThree", 42042)
35
+ if is_port_in_use(port):
36
+ if is_port_in_use(port_option_one):
37
+ if is_port_in_use(port_option_two):
38
+ if is_port_in_use(port_option_three):
39
+ raise RuntimeError(
40
+ "All configured ports are in use. Please close applications using ports or configure different ports."
41
+ )
42
+ else:
43
+ port = port_option_three
44
+ else:
45
+ port = port_option_two
46
+ else:
47
+ port = port_option_one
48
+ auth_config["port"] = port
49
+ with open(
50
+ os.path.join(os.path.dirname(__file__), "..", "auth_config.json"), "w"
51
+ ) as f:
52
+ json.dump(auth_config, f)
53
+
54
+
55
+ @click.command()
56
+ @environment_options
57
+ def auth(domain="alpha"):
58
+ """Authenticate with UiPath Cloud Platform."""
59
+ portal_service = PortalService(domain)
60
+ if (
61
+ os.getenv("UIPATH_URL")
62
+ and os.getenv("UIPATH_TENANT_ID")
63
+ and os.getenv("UIPATH_ORGANIZATION_ID")
64
+ ):
65
+ try:
66
+ portal_service.ensure_valid_token()
67
+ click.echo("Authentication successful")
68
+ return
69
+ except Exception:
70
+ click.echo(
71
+ "Authentication not found or expired. Please authenticate again."
72
+ )
73
+
74
+ auth_url, code_verifier, state = get_auth_url(domain)
75
+
76
+ webbrowser.open(auth_url, 1)
77
+ auth_config = get_auth_config()
78
+
79
+ print(
80
+ "If a browser window did not open, please open the following URL in your browser:"
81
+ )
82
+ print(auth_url)
83
+ server = HTTPSServer(port=auth_config["port"])
84
+ token_data = server.start(state, code_verifier, domain)
85
+ try:
86
+ if token_data:
87
+ portal_service.update_token_data(token_data)
88
+ update_auth_file(token_data)
89
+ access_token = token_data["access_token"]
90
+ update_env_file({"UIPATH_ACCESS_TOKEN": access_token})
91
+
92
+ tenants_and_organizations = portal_service.get_tenants_and_organizations()
93
+ select_tenant(domain, tenants_and_organizations)
94
+ else:
95
+ click.echo("Authentication failed")
96
+ except Exception as e:
97
+ click.echo(f"Authentication failed: {e}")
@@ -0,0 +1,13 @@
1
+ # type: ignore
2
+ import click
3
+
4
+ from .cli_pack import pack
5
+ from .cli_publish import publish
6
+
7
+
8
+ @click.command()
9
+ @click.argument("root", type=str, default="./")
10
+ def deploy(root):
11
+ ctx = click.get_current_context()
12
+ ctx.invoke(pack, root=root)
13
+ ctx.invoke(publish)