launchpy 0.4.7.post1__tar.gz → 0.4.9__tar.gz

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 (34) hide show
  1. {launchpy-0.4.7.post1/launchpy.egg-info → launchpy-0.4.9}/PKG-INFO +10 -9
  2. {launchpy-0.4.7.post1 → launchpy-0.4.9}/docs/cli.md +24 -3
  3. {launchpy-0.4.7.post1 → launchpy-0.4.9}/docs/releases.md +15 -1
  4. {launchpy-0.4.7.post1 → launchpy-0.4.9}/docs/synchronizer.md +36 -10
  5. {launchpy-0.4.7.post1 → launchpy-0.4.9}/launchpy/__init__.py +23 -3
  6. launchpy-0.4.9/launchpy/__version__.py +1 -0
  7. {launchpy-0.4.7.post1 → launchpy-0.4.9}/launchpy/cli/__main__.py +76 -23
  8. {launchpy-0.4.7.post1 → launchpy-0.4.9}/launchpy/config.py +0 -2
  9. {launchpy-0.4.7.post1 → launchpy-0.4.9}/launchpy/configs.py +7 -37
  10. {launchpy-0.4.7.post1 → launchpy-0.4.9}/launchpy/connector.py +0 -2
  11. {launchpy-0.4.7.post1 → launchpy-0.4.9}/launchpy/library.py +24 -7
  12. {launchpy-0.4.7.post1 → launchpy-0.4.9}/launchpy/property.py +10 -0
  13. {launchpy-0.4.7.post1 → launchpy-0.4.9}/launchpy/synchronizer.py +198 -39
  14. {launchpy-0.4.7.post1 → launchpy-0.4.9/launchpy.egg-info}/PKG-INFO +10 -9
  15. {launchpy-0.4.7.post1 → launchpy-0.4.9}/launchpy.egg-info/requires.txt +2 -2
  16. {launchpy-0.4.7.post1 → launchpy-0.4.9}/pyproject.toml +9 -9
  17. {launchpy-0.4.7.post1 → launchpy-0.4.9}/requirements.txt +4 -5
  18. launchpy-0.4.7.post1/launchpy/__version__.py +0 -1
  19. {launchpy-0.4.7.post1 → launchpy-0.4.9}/LICENSE +0 -0
  20. {launchpy-0.4.7.post1 → launchpy-0.4.9}/README.md +0 -0
  21. {launchpy-0.4.7.post1 → launchpy-0.4.9}/docs/admin.md +0 -0
  22. {launchpy-0.4.7.post1 → launchpy-0.4.9}/docs/getstarted.md +0 -0
  23. {launchpy-0.4.7.post1 → launchpy-0.4.9}/docs/library.md +0 -0
  24. {launchpy-0.4.7.post1 → launchpy-0.4.9}/docs/main.md +0 -0
  25. {launchpy-0.4.7.post1 → launchpy-0.4.9}/docs/property.md +0 -0
  26. {launchpy-0.4.7.post1 → launchpy-0.4.9}/docs/translator.md +0 -0
  27. {launchpy-0.4.7.post1 → launchpy-0.4.9}/launchpy/admin.py +0 -0
  28. {launchpy-0.4.7.post1 → launchpy-0.4.9}/launchpy/cli/__init__.py +0 -0
  29. {launchpy-0.4.7.post1 → launchpy-0.4.9}/launchpy/launchpy.py +0 -0
  30. {launchpy-0.4.7.post1 → launchpy-0.4.9}/launchpy.egg-info/SOURCES.txt +0 -0
  31. {launchpy-0.4.7.post1 → launchpy-0.4.9}/launchpy.egg-info/dependency_links.txt +0 -0
  32. {launchpy-0.4.7.post1 → launchpy-0.4.9}/launchpy.egg-info/entry_points.txt +0 -0
  33. {launchpy-0.4.7.post1 → launchpy-0.4.9}/launchpy.egg-info/top_level.txt +0 -0
  34. {launchpy-0.4.7.post1 → launchpy-0.4.9}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: launchpy
3
- Version: 0.4.7.post1
3
+ Version: 0.4.9
4
4
  Summary: Adobe Launch API wrapper
5
5
  Author-email: Julien Piccini <piccini.julien@gmail.com>
6
6
  License: Apache License 2.0
@@ -8,26 +8,27 @@ Project-URL: homepage, https://github.com/pitchmuc/launchpy
8
8
  Project-URL: changelog, https://github.com/pitchmuc/launchpy/blob/master/docs/releases.md
9
9
  Keywords: adobe,analytics,API,python
10
10
  Classifier: Intended Audience :: Developers
11
- Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
11
+ Classifier: License :: OSI Approved :: Apache Software License
12
12
  Classifier: Operating System :: OS Independent
13
13
  Classifier: Programming Language :: Python
14
14
  Classifier: Topic :: Scientific/Engineering :: Information Analysis
15
- Classifier: Programming Language :: Python :: 3.6
16
- Classifier: Programming Language :: Python :: 3.7
17
- Classifier: Programming Language :: Python :: 3.8
18
- Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
19
20
  Classifier: Development Status :: 4 - Beta
20
- Requires-Python: >=3.7
21
+ Requires-Python: >=3.10
21
22
  Description-Content-Type: text/markdown
22
23
  License-File: LICENSE
23
24
  Requires-Dist: pandas
24
25
  Requires-Dist: requests
25
- Requires-Dist: PyJWT
26
- Requires-Dist: PyJWT[crypto]
27
26
  Requires-Dist: pathlib2
28
27
  Requires-Dist: pathlib
29
28
  Requires-Dist: aepp
30
29
  Requires-Dist: rich
30
+ Requires-Dist: deprecated
31
+ Requires-Dist: httpx
31
32
  Dynamic: license-file
32
33
 
33
34
  # Launchpy
@@ -43,6 +43,7 @@ This document provides an overview of the command line interface (CLI) for `laun
43
43
  - [get\_base\_libraries](#get_base_libraries)
44
44
  - [get\_base\_library](#get_base_library)
45
45
  - [sync\_from\_library](#sync_from_library)
46
+ - [Behaviors for sync\_from\_library](#behaviors-for-sync_from_library)
46
47
  - [create\_libraries](#create_libraries)
47
48
 
48
49
 
@@ -479,8 +480,23 @@ synchronizer:Base_Property_Name> get_base_library -n "Library Name"
479
480
  #### sync_from_library
480
481
  This command allows you to synchronize a library from the base property to the target properties.\
481
482
  **IMPORTANT**:By default it will use the published version of the elements that are part of the library.
482
- `-n`, `--name`: The name of the library to sync from. This is a required parameter.
483
- `-id`, `--id`: The ID of the library to sync from (overrides name if both provided). This is an optional parameter.
483
+ * `-n`, `--name`: Name of the library to sync from. This is a required parameter.
484
+ * `-id`, `--id`: ID of the library to sync from (overrides name if both provided). This is an optional parameter.
485
+ * `-c`, `--create`: Boolean. Create the component if it does not exist. Default `False`. Possible values: True, False
486
+ * `-ll`, `--library_linked`: Boolean. Whether to use library linked components or not. If set to True, the sync will be done using the library linked components. If set to False, the sync will be done using the component IDs in the library. Default `True`. Possible values: True, False
487
+ * `-p`, `--published`: Boolean. Sync the latest published version of the component instead of the current version. Default `False`. Possible values: True, False
488
+ * `-dr`, `--dry_run`: Boolean. If set to True, will only check the sync status of the components without actually syncing them. Default `False`. Possible values: True, False
489
+
490
+ ```bash
491
+ synchronizer:Base_Property_Name> sync_from_library -id "LibraryId" -ll False -p True -dr True
492
+ ```
493
+
494
+
495
+ ### Behaviors for sync_from_library
496
+ By default, the method will sync the components present in the library as they are in the library.
497
+ If the `published` is set to True, it will try to sync the version that has been published in the base property to the targets.\
498
+ If the `library_linked` is set to `False` and the `published` is set to `False` (default), it will try to sync the latest version of the components present in the base property library to the targets.\
499
+
484
500
 
485
501
  ```bash
486
502
  synchronizer:Base_Property_Name> sync_from_library -n "Library Name"
@@ -490,9 +506,14 @@ synchronizer:Base_Property_Name> sync_from_library -n "Library Name"
490
506
  This command allows you to create a library in the destination properties with the elements you have sync.\
491
507
  Arguments:
492
508
  `name`: Name for the new library to be created in the destination properties. This is a required parameter.
493
- `-env`, `--environment`: Boolean. Try to find an empty environment to build the library. Default False. Possible values: `True`, `False`
509
+ `-env`, `--environment`: String. If set to `True`, it will try to find a free environment and assign it to the library. If none is available, it will not assign any environment to the library. If the name of the environment is provided, it will try to assign it to that library. If the environment is already used in a Library, it will remove that association and assign it to the new library. Default False. Possible values: `True`, `False` or a `string` which is the (partial) name of the environment you want to assign to the library.
494
510
 
495
511
  ```bash
496
512
  synchronizer:Base_Property_Name> create_library "Library Name" -env True
497
513
  ```
514
+
515
+ ```bash
516
+ synchronizer:Base_Property_Name> create_library "Library Name" -env "Environment Name
517
+
518
+ ```
498
519
 
@@ -3,8 +3,22 @@
3
3
  This page gathered the changes made between version of the launchpy module.\
4
4
  This has been started after the 0.3.0 release.\
5
5
 
6
+ ## 0.4.9
7
+ * fixing httpx dependency requirement
8
+ * extractProperty will now also extract Data Elements and Extensions configurations in separate folders.
9
+ * fix the argument handling for linkedLibrary in CLI.
10
+ * Change of the `force` parameter to `create` in the synchronizer CLI for better understanding of the action. `create` is now default to `False`. The synchronizer module keeps its long name `forceCreation` for backward compatibility and better understanding of the action. Also turning it to `False` by default.
11
+
12
+ ## 0.4.8
13
+ * Adding the `clear` method in CLI
14
+ * Adding `syncFromLibrary` in synchronizer[doc](./synchronizer.md#syncFromLibrary).
15
+ * Adding `sync_from_library` command in CLI[doc](./cli.md#sync_from_library-command).
16
+ * Cleaning the JWT components and requirements
17
+ * Adding the `definition` attribute in the Library class
18
+ * Adding capability to define a specific environment name when creating a library in synchronizer.
19
+
6
20
  ## 0.4.7
7
- * modify `getRuleComponents` to `getRulesComponents` as it can return all the rules components if no rule is specified. Kept `getRuleComponents` as an alias for backward compatibility and also provide a single rule components retrieval.
21
+ * Modify `getRuleComponents` to `getRulesComponents` as it can return all the rules components if no rule is specified. Kept `getRuleComponents` as an alias for backward compatibility and also provide a single rule components retrieval.
8
22
  * Adding the `CLI` layer. [Documentation to CLI](cli.md)
9
23
 
10
24
  ## 0.4.6
@@ -6,6 +6,16 @@ You can recreate a (more advanced) version that supports additional methods or e
6
6
 
7
7
  The Synchronizer will allow you to specify a template property and target property **within the same organization** in order to sync these properties rules and data elements.
8
8
 
9
+ ## Menu
10
+
11
+ [MENUI](#menu)
12
+ [Pre Requisite](#pre-requisite)
13
+ [Instantiation](#instantiation)
14
+ [SyncComponent Method](#syncComponent-Method)
15
+ [SyncComponents](#syncComponents)
16
+ [SyncFromLibrary](#syncFromLibrary)
17
+ [createTargetsLibrary](#createTargetsLibrary)
18
+ [renameComponent](#renameComponent)
9
19
 
10
20
 
11
21
  ## PRE REQUISITE
@@ -85,7 +95,6 @@ synchronizor = lp.Synchronizer(base=base,targets=['another Property Name to sync
85
95
 
86
96
  ```
87
97
 
88
-
89
98
  ### Additional options
90
99
  There is a possibility to setup some rules so you can filter when migrating from one property to another. See [dynamic Filtering](#dynamic-component-filter)
91
100
 
@@ -122,7 +131,7 @@ The method will delete all rule components existing in the Target property for t
122
131
  It will then copy all template rule component existing in that base property to the target properties.\
123
132
  No history is saved from the existing rule component, which will make revision check very hard.
124
133
 
125
- ## SyncComponents Method
134
+ ## SyncComponents
126
135
 
127
136
  You can pass down a list of component names or componentIds.\
128
137
  It takes 3 arguments:\
@@ -131,10 +140,28 @@ Arguments:
131
140
  * componentsId : REQUIRED : The list of component ID to sync*
132
141
  * publishedVersion : OPTIONAL : if you want to take the version that has been published
133
142
 
143
+ ## syncFromLibrary
144
+
145
+ This method allows you to take a library in your base property and sync all of the components in that library to the target properties.
146
+ Arguments:
147
+ * library : REQUIRED : the name or the ID of the library to sync from.
148
+ * state : OPTIONAL : the state of the library to sync from. Default: 'published', possible states: "development", "submitted", "approved", "rejected", "published"
149
+ * create : OPTIONAL : If set to True, it will create the element sync if it does not exist in the target property. Set to `False`, it will prevent that behavior. Default: `False`.
150
+ * libraryLinked : OPTIONAL : If set to True, it will use library linked components for comparison. Default: `True`.
151
+ * publishedVersion : OPTIONAL : If set to True, it will compare the components to the published version in the target properties. Default: `False`.
152
+ * dryRun : OPTIONAL : If set to True, will only check the sync status of the components without actually syncing them. Default `False`. Possible values: `True`, `False`
153
+
154
+ **Note**: A library is not created automatically, so you will need to create a new one via the `createTargetsLibrary` method.
155
+
156
+ ### Behaviors for syncFromLibrary
157
+ By default, the method will sync the components present in the library as they are in the library.
158
+ If the `publishedVersion` is set to True, it will try to sync the version that has been published in the base property to the targets.\
159
+ If the `libraryLinked` is set to `False` and the `publishedVersion` is set to `False` (default), it will try to sync the latest version of the components present in the base property library to the targets.\
160
+
134
161
  ## createTargetsLibrary
135
162
 
136
163
  The synchronizer will automatically track the component that has been updated via the module.\
137
- When you are done synchronizing your components, you can run this method to create a library, that will contain all of your elements you synchronized.\
164
+ When you are done synchronizing your components, you can run this method to create a library, that will contain all the elements you synchronized.\
138
165
  The library will be available within all of your synch properties.
139
166
 
140
167
  You can pass a name to define the library name that is created.\
@@ -142,7 +169,10 @@ The name is then used to match if a library already exist with that name, in the
142
169
  Note that the match looked for is using regular expression (`re.search`) to find a match in the existing libraries name.\
143
170
  Arguments:
144
171
  * name : REQUIRED : Name of the library to create or to use.
145
- * assignEnv : OPTIONAL : If you want to automatically assign an environment to the library and build it. Default False. Possible values: `True`, `False`
172
+ * assignEnv : OPTIONAL : If you want to automatically assign an environment to the library and build it. Default False.
173
+ Possible values: `True`, `False` or a `string` which is the name of the environment you want to assign to the library.\
174
+ If `True`, it will try to find a free environment and assign it to the library. If none is available, it will not assign any environment to the library.\
175
+ If the name of the environment is provided, it will try to assign it to that library. If the environment is already used in a Library, it will remove that association and assign it to the new library. (A print statement will be printed to warn about that change of association)
146
176
 
147
177
  ## renameComponent
148
178
 
@@ -198,14 +228,10 @@ For Data Elements:
198
228
 
199
229
  #### Additional elements
200
230
  On top of the different properties check, additional information will be provided for the base component:
201
- * `base-publihsed`: If the current component check is published.\
231
+ * `base-published`: If the current component check is published.\
202
232
  **IMPORTANT NOTE**: When you using the `publishedVersion` parameter set to True, most of the element will be set to Published. In reverse, it is not because the component current version is not published that it has never been published. Use the `publishedVersion` to ensure this.
203
233
  * `base-enabled`: If the current component check is enabled.
204
- * `base-state`:
205
- * `Latest`: If the component retrieved is the latest latest version
206
- * `Unknown`: If the component retrieved cannot be evaluated to know if it is the latest.
207
- * `Draft` : If the component retrieved is not the latest and it has not yet been published
208
- * `Edited`: If the component retrieved is not the latest and has been published before.
234
+
209
235
 
210
236
  #### Similar vs Same
211
237
  The idea of checking the similarity of 2 components is partially done as not everything can be tested during the check.\
@@ -9,7 +9,7 @@ from launchpy.library import Library
9
9
  from launchpy.admin import Admin
10
10
  from launchpy.property import Property
11
11
  from launchpy.synchronizer import Synchronizer
12
- import re
12
+ import re,json
13
13
  from pathlib import Path
14
14
  import httpx, asyncio
15
15
 
@@ -48,10 +48,18 @@ async def process_all_rules(rules_list, folder, header):
48
48
  async with httpx.AsyncClient(timeout=timeout, limits=limits) as client:
49
49
  # Create a list of "tasks" to run
50
50
  tasks = [__extractRuleComponents__(rule, client, folder, header) for rule in rules_list]
51
-
52
51
  # 'gather' runs them all concurrently
53
52
  await asyncio.gather(*tasks)
54
53
 
54
+
55
+ async def write_all_data_elements(data_elements_list, folder, header):
56
+ for data_element in data_elements_list:
57
+ data_element_name = __safe_name__(data_element['attributes']['name'])
58
+ file_path = Path(folder) / f"{data_element_name}.json"
59
+ with open(file_path, "w") as f:
60
+ json.dump(data_element, f, indent=4)
61
+
62
+
55
63
  def extractProperty(property: dict | Property):
56
64
  if property is None:
57
65
  raise ValueError("Property is None")
@@ -63,4 +71,16 @@ def extractProperty(property: dict | Property):
63
71
  folder = __safe_name__(property.name)
64
72
  Path(folder).mkdir(parents=True, exist_ok=True)
65
73
  rules = property.getRules()
66
- asyncio.run(process_all_rules(rules, folder, property.header))
74
+ asyncio.run(process_all_rules(rules, folder, property.header))
75
+ dataElements = property.getDataElements()
76
+ dataElements_folder = Path(folder) / "data_elements"
77
+ Path(dataElements_folder).mkdir(parents=True, exist_ok=True)
78
+ asyncio.run(write_all_data_elements(dataElements, dataElements_folder, property.header))
79
+ extension_folder = Path(folder) / "extensions"
80
+ extension_folder.mkdir(parents=True, exist_ok=True)
81
+ extensions = property.getExtensions()
82
+ for extension in extensions:
83
+ extension_name = __safe_name__(extension['attributes']['name'])
84
+ file_path = extension_folder / f"{extension_name}.json"
85
+ with open(file_path, "w") as f:
86
+ json.dump(extension, f, indent=4)
@@ -0,0 +1 @@
1
+ __version__ = "0.4.9"
@@ -1,5 +1,4 @@
1
- from rich import rule
2
- import launchpy
1
+ import launchpy
3
2
  import argparse, cmd, shlex, json
4
3
  from functools import wraps
5
4
  from rich.console import Console
@@ -10,6 +9,17 @@ import pandas as pd
10
9
  from datetime import datetime, timedelta
11
10
  from typing import Any, Concatenate, ParamSpec, ParamSpecKwargs
12
11
  from collections.abc import Callable
12
+ import os
13
+
14
+ def str2bool(v):
15
+ if isinstance(v, bool):
16
+ return v
17
+ if v.lower() in ('yes', 'true', 't', 'y', '1'):
18
+ return True
19
+ elif v.lower() in ('no', 'false', 'f', 'n', '0'):
20
+ return False
21
+ else:
22
+ raise argparse.ArgumentTypeError('Boolean value expected.')
13
23
 
14
24
  P = ParamSpec("P")
15
25
 
@@ -33,6 +43,11 @@ def login_required(f:Callable[Concatenate["MainShell", P], None]) -> Callable[Co
33
43
  return f(self, *args, **kwargs)
34
44
  return wrapper
35
45
 
46
+ def clear_terminal():
47
+ """Clears the terminal screen based on the OS."""
48
+ # os.name is 'nt' for Windows, 'posix' for Mac/Linux
49
+ os.system('cls' if os.name == 'nt' else 'clear')
50
+
36
51
  console = Console()
37
52
 
38
53
  class PropertyCLI(cmd.Cmd):
@@ -48,7 +63,7 @@ class PropertyCLI(cmd.Cmd):
48
63
  def do_get_extensions(self, arg):
49
64
  """Get all extensions in the property and list them."""
50
65
  parser = argparse.ArgumentParser(prog='get_extensions', add_help=True)
51
- parser.add_argument("-s", "--save", help="Boolean. Save extensions to a CSV file. Default False. Possible values: True, False", type=bool, default=False)
66
+ parser.add_argument("-s", "--save", help="Boolean. Save extensions to a CSV file. Default False. Possible values: True, False", type=str2bool, nargs="?", const=True, default=False)
52
67
  try:
53
68
  args = parser.parse_args(shlex.split(arg))
54
69
  extensions = self.property.getExtensions()
@@ -82,7 +97,7 @@ class PropertyCLI(cmd.Cmd):
82
97
  """Get details for a specific extension by name."""
83
98
  parser = argparse.ArgumentParser(prog='get_extension', add_help=True)
84
99
  parser.add_argument("name", help="Name of the extension to get details for", type=str)
85
- parser.add_argument("-s", "--save", help="Boolean. Save extension details to a JSON file. Default False. Possible values: True, False", type=bool, default=False)
100
+ parser.add_argument("-s", "--save", help="Boolean. Save extension details to a JSON file. Default False. Possible values: True, False", type=str2bool, nargs="?", const=True, default=False)
86
101
  try:
87
102
  args = parser.parse_args(shlex.split(args))
88
103
  extensions = self.property.getExtensions()
@@ -107,7 +122,7 @@ class PropertyCLI(cmd.Cmd):
107
122
  """Get all rules for the property."""
108
123
  parser = argparse.ArgumentParser(prog='get_rules', add_help=True)
109
124
  parser.add_argument("-n", "--name", help="Filter rules by name (partial match, non-case sensitive)", type=str, default=None)
110
- parser.add_argument("-s", "--save", help="Boolean. Save rules to a CSV file. Default False. Possible values: True, False", type=bool, default=False)
125
+ parser.add_argument("-s", "--save", help="Boolean. Save rules to a CSV file. Default False. Possible values: True, False", type=str2bool, nargs="?", const=True, default=False)
111
126
  try:
112
127
  args = parser.parse_args(shlex.split(arg))
113
128
  rules = self.property.getRules()
@@ -143,7 +158,7 @@ class PropertyCLI(cmd.Cmd):
143
158
  parser = argparse.ArgumentParser(prog='get_rule', add_help=True)
144
159
  parser.add_argument("-n", "--name", help="Name of the rule to get details for", type=str)
145
160
  parser.add_argument("-id", "--id", help="ID of the rule to get details for (overrides name if both provided)", type=str)
146
- parser.add_argument("-s", "--save", help="Boolean. Save rule details to a JSON file. Default False. Possible values: True, False", type=bool, default=False)
161
+ parser.add_argument("-s", "--save", help="Boolean. Save rule details to a JSON file. Default False. Possible values: True, False", type=str2bool, nargs="?", const=True, default=False)
147
162
  try:
148
163
  args = parser.parse_args(shlex.split(arg))
149
164
  if self.rules is None:
@@ -180,7 +195,7 @@ class PropertyCLI(cmd.Cmd):
180
195
  parser = argparse.ArgumentParser(prog='get_rules_components', add_help=True)
181
196
  parser.add_argument("-rn", "--rule_name", help="(Partial) Name of the rule to get components for", type=str,default=None)
182
197
  parser.add_argument("-rid", "--rule_id", help="ID of the rule to get components for (overrides rule_name if both provided)", type=str, default=None)
183
- parser.add_argument("-s", "--save", help="Boolean. Save components to a CSV file. Default False. Possible values: True, False", type=bool, default=False)
198
+ parser.add_argument("-s", "--save", help="Boolean. Save components to a CSV file. Default False. Possible values: True, False", type=str2bool, nargs="?", const=True, default=False)
184
199
  try:
185
200
  args = parser.parse_args(shlex.split(arg))
186
201
  if self.rules_components is None:
@@ -244,7 +259,7 @@ class PropertyCLI(cmd.Cmd):
244
259
  parser = argparse.ArgumentParser(prog='get_rule_components', add_help=True)
245
260
  parser.add_argument("-rn", "--rule_name", help="(Partial) Name of the rule to get components for", type=str, default=None)
246
261
  parser.add_argument("-rid", "--rule_id", help="ID of the rule to get components for (overrides rule_name if both provided)", type=str, default=None)
247
- parser.add_argument("-s", "--save", help="Boolean. Save components to a JSON file. Default False. Possible values: True, False", type=bool, default=False)
262
+ parser.add_argument("-s", "--save", help="Boolean. Save components to a JSON file. Default False. Possible values: True, False", type=str2bool, nargs="?", const=True, default=False)
248
263
  try:
249
264
  args = parser.parse_args(shlex.split(arg))
250
265
  rule = None ## fallback
@@ -285,7 +300,7 @@ class PropertyCLI(cmd.Cmd):
285
300
  """Get all data elements, or only the ones matching a name filter, for the property. Can save them in CSV file."""
286
301
  parser = argparse.ArgumentParser(prog='get_data_elements', add_help=True)
287
302
  parser.add_argument("-n", "--name", help="Filter data elements by name (partial match, non-case sensitive)", type=str, default=None)
288
- parser.add_argument("-s", "--save", help="Boolean. Save data elements to a CSV file. Default False. Possible values: True, False", type=bool, default=False)
303
+ parser.add_argument("-s", "--save", help="Boolean. Save data elements to a CSV file. Default False. Possible values: True, False", type=str2bool, nargs="?", const=True, default=False)
289
304
  try:
290
305
  args = parser.parse_args(shlex.split(args))
291
306
  des = self.property.getDataElements()
@@ -320,7 +335,7 @@ class PropertyCLI(cmd.Cmd):
320
335
  """Get details for a specific data element by name."""
321
336
  parser = argparse.ArgumentParser(prog='get_data_element', add_help=True)
322
337
  parser.add_argument("name", help="Name of the data element to get details for", type=str)
323
- parser.add_argument("-s", "--save", help="Boolean. Save data element details to a JSON file. Default False. Possible values: True, False", type=bool, default=False)
338
+ parser.add_argument("-s", "--save", help="Boolean. Save data element details to a JSON file. Default False. Possible values: True, False", type=str2bool, nargs="?", const=True, default=False)
324
339
  try:
325
340
  args = parser.parse_args(shlex.split(args))
326
341
  if self.data_elements is None:
@@ -349,7 +364,7 @@ class PropertyCLI(cmd.Cmd):
349
364
  parser = argparse.ArgumentParser(prog='get_latest_published_version', add_help=True)
350
365
  parser.add_argument("-n", "--name", help="Name of the component to get the latest published version for", type=str, default=None)
351
366
  parser.add_argument("-t", "--type", help="Type of the component (e.g. 'rule', 'data_element', 'extension') to get the latest published version for. Default None", type=str, default=None)
352
- parser.add_argument("-s", "--save", help="Boolean. Save the latest published version details to a JSON file. Default False. Possible values: True, False", type=bool, default=False)
367
+ parser.add_argument("-s", "--save", help="Boolean. Save the latest published version details to a JSON file. Default False. Possible values: True, False", type=str2bool, nargs="?", const=True, default=False)
353
368
  try:
354
369
  args = parser.parse_args(shlex.split(arg))
355
370
  if args.type and args.name is None:
@@ -419,7 +434,7 @@ class PropertyCLI(cmd.Cmd):
419
434
  def do_get_libraries(self, arg: Any):
420
435
  """Get all libraries for the property."""
421
436
  parser = argparse.ArgumentParser(prog='get_libraries', add_help=True)
422
- parser.add_argument("-s", "--save", help="Boolean. Save libraries to a CSV file. Default False. Possible values: True, False", type=bool, default=False)
437
+ parser.add_argument("-s", "--save", help="Boolean. Save libraries to a CSV file. Default False. Possible values: True, False", type=str2bool, nargs="?", const=True, default=False)
423
438
  parser.add_argument("-st", "--state", help="Filter by library state. Possible values: 'development' (default), 'submitted', 'approved', 'rejected', 'published'", type=str, default="development")
424
439
  try:
425
440
  args = parser.parse_args(shlex.split(arg))
@@ -507,6 +522,10 @@ class PropertyCLI(cmd.Cmd):
507
522
  except SystemExit:
508
523
  return
509
524
 
525
+ def do_clear(self, arg) -> None:
526
+ """Clear the terminal screen."""
527
+ clear_terminal()
528
+
510
529
  def do_exit(self, arg):
511
530
  """Return to the main menu."""
512
531
  console.print(Panel("Returning to main menu..."),style="blue")
@@ -529,7 +548,7 @@ class SynchronizerCLI(cmd.Cmd):
529
548
  parser = argparse.ArgumentParser(prog='check_component', add_help=True)
530
549
  parser.add_argument("-n", "--name", help="Name of the component to check", type=str)
531
550
  parser.add_argument("-id", "--id", help="ID of the component to check (overrides name if both provided)", type=str)
532
- parser.add_argument("-p", "--published", help="Boolean. Check the latest published version of the component instead of the current version. Default False. Possible values: True, False", type=bool, default=False)
551
+ parser.add_argument("-p", "--published", help="Boolean. Check the latest published version of the component instead of the current version. Default False. Possible values: True, False", type=str2bool, nargs="?", const=True, default=False)
533
552
  try:
534
553
  args = parser.parse_args(shlex.split(ars))
535
554
  if args.id is not None:
@@ -548,14 +567,14 @@ class SynchronizerCLI(cmd.Cmd):
548
567
  parser = argparse.ArgumentParser(prog='sync', add_help=True)
549
568
  parser.add_argument("-n", "--name", help="Name of the component to sync", type=str)
550
569
  parser.add_argument("-id", "--id", help="ID of the component to sync (overrides name if both provided)", type=str)
551
- parser.add_argument("-p", "--published", help="Boolean. Sync the latest published version of the component instead of the current version. Default False. Possible values: True, False", type=bool, default=False)
552
- parser.add_argument("-f", "--force", help="Boolean. Create the component if it does not exist. Default True. Possible values: True, False", type=bool, default=True)
570
+ parser.add_argument("-p", "--published", help="Boolean. Sync the latest published version of the component instead of the current version. Default False. Possible values: True, False", type=str2bool, nargs="?", const=True, default=False)
571
+ parser.add_argument("-c", "--create", help="Boolean. Create the component if it does not exist. Default True. Possible values: True, False", type=str2bool, default=True)
553
572
  try:
554
573
  args = parser.parse_args(shlex.split(args))
555
574
  if args.id is not None:
556
- result = self.synchronizer.syncComponent(componentId=args.id, publishedVersion=args.published, forceCreation=args.force)
575
+ result = self.synchronizer.syncComponent(componentId=args.id, publishedVersion=args.published, forceCreation=args.create)
557
576
  else:
558
- result = self.synchronizer.syncComponent(componentName=args.name, publishedVersion=args.published, forceCreation=args.force)
577
+ result = self.synchronizer.syncComponent(componentName=args.name, publishedVersion=args.published, forceCreation=args.create)
559
578
  console.print(f"Component '{args.name or args.id}' synced successfully.", style="green")
560
579
  except Exception as e:
561
580
  console.print(f"(!) Error: {str(e)}", style="red")
@@ -741,12 +760,22 @@ class SynchronizerCLI(cmd.Cmd):
741
760
  return
742
761
 
743
762
  def do_sync_from_library(self,args:Any):
744
- """Sync all components from a base library in the source property to the destination properties. Rules and data elements will be the latest published one"""
763
+ """Sync all components from a base library in the source property to the destination properties.
764
+ Rules and data elements will be the library version by default. Can be changed with --ll parameter."""
745
765
  parser = argparse.ArgumentParser(prog='sync_from_library', add_help=True)
746
766
  parser.add_argument("-n", "--name", help="Name of the library to sync from", type=str)
747
767
  parser.add_argument("-id", "--id", help="ID of the library to sync from (overrides name if both provided)", type=str)
768
+ parser.add_argument("-c", "--create", help="Boolean. Create the component if it does not exist. Default True. Possible values: True, False", type=str2bool, default=False)
769
+ parser.add_argument("-ll", "--library_linked", help="Boolean. Whether to use library linked components or not. If set to True, the sync will be done using the library linked components. If set to False, the sync will be done using the component IDs in the library. Default True. Possible values: True, False", type=str2bool, default=True)
770
+ parser.add_argument("-p", "--published", help="Boolean. Sync the latest published version of the component instead of the current version. Default False. Possible values: True, False", type=str2bool, nargs="?", const=True, default=False,)
771
+ parser.add_argument("-dr", "--dry_run", help="Boolean. If set to True, will only check the sync status of the components without actually syncing them. Default False. Possible values: True, False", type=str2bool, nargs="?", const=True, default=False,)
748
772
  try:
749
773
  args = parser.parse_args(shlex.split(args))
774
+ publishedVersion = args.published # default False
775
+ libraryLinked = args.library_linked # default True
776
+ if args.published:
777
+ publishedVersion = True
778
+ libraryLinked = False
750
779
  if args.id is not None:
751
780
  lib = self.synchronizer.base["api"].getLibrary(args.id, return_class=True)
752
781
  else:
@@ -756,6 +785,10 @@ class SynchronizerCLI(cmd.Cmd):
756
785
  console.print(f"Library '{args.name}' not found in this property.", style="red")
757
786
  return
758
787
  lib = self.synchronizer.base["api"].getLibrary(matching_libs[0]['id'], return_class=True)
788
+ if args.dry_run:
789
+ results = self.synchronizer.__checkLibrarySync__(library=lib.id, state=lib.state, excludeSimilar=False,libraryLinked=libraryLinked,publishedVersion=publishedVersion)
790
+ console.print_json(json.dumps(results, indent=4))
791
+ return
759
792
  rules = lib.getRules()
760
793
  dataelements = lib.getDataElements()
761
794
  extensions = lib.getExtensions()
@@ -771,7 +804,11 @@ class SynchronizerCLI(cmd.Cmd):
771
804
  console.print(f"Syncing {len(rules)} rule{'s' if len(rules) > 1 else ''} from library '{lib.name}'...", style="blue")
772
805
  for rule in rules:
773
806
  try:
774
- self.synchronizer.syncComponent(componentId=rule['id'], publishedVersion=True, forceCreation=True)
807
+ if args.library_linked:
808
+ ruleId = rule['links']['self'].split('/').pop()
809
+ else:
810
+ ruleId = rule['id']
811
+ self.synchronizer.syncComponent(componentId=ruleId, publishedVersion=publishedVersion, forceCreation=args.create,libraryLinked=libraryLinked)
775
812
  console.print(f"Rule '{rule['attributes']['name']}' synced successfully.", style="green")
776
813
  except Exception as e:
777
814
  console.print(f"(!) Error syncing rule '{rule['attributes']['name']}': {str(e)}", style="red")
@@ -779,7 +816,11 @@ class SynchronizerCLI(cmd.Cmd):
779
816
  console.print(f"Syncing {len(dataelements)} data element{'s' if len(dataelements) > 1 else ''} from library '{lib.name}'...", style="blue")
780
817
  for de in dataelements:
781
818
  try:
782
- self.synchronizer.syncComponent(componentId=de['id'], publishedVersion=True, forceCreation=True)
819
+ if args.library_linked:
820
+ deId = de['links']['self'].split('/').pop()
821
+ else:
822
+ deId = de['id']
823
+ self.synchronizer.syncComponent(componentId=deId, publishedVersion=publishedVersion, forceCreation=args.create,libraryLinked=libraryLinked)
783
824
  console.print(f"Data element '{de['attributes']['name']}' synced successfully.", style="green")
784
825
  except Exception as e:
785
826
  console.print(f"(!) Error syncing data element '{de['attributes']['name']}': {str(e)}", style="red")
@@ -793,9 +834,13 @@ class SynchronizerCLI(cmd.Cmd):
793
834
  """Create libraries in the destination property based on the libraries in the source property that are selected for synchronization."""
794
835
  parser = argparse.ArgumentParser(prog='create_libraries', add_help=True)
795
836
  parser.add_argument("name",help="Name for the new library to be created in the destination properties", type=str)
796
- parser.add_argument("-env",'--environment',help='Boolean. try to find an empty environment to build the library. Default False.',type=bool,default=False)
837
+ parser.add_argument("-env",'--environment',help='Set to True to try to assign an available environment. Set a string with name of an environment to set a specific environment. Default False',type=str,default=False)
797
838
  try:
798
839
  args = parser.parse_args(shlex.split(args))
840
+ if args.environment == "True":
841
+ args.environment = True
842
+ if args.environment == "False":
843
+ args.environment = False
799
844
  res = self.synchronizer.createTargetsLibrary(name=args.name,assignEnv=args.environment)
800
845
  console.print_json(json.dumps(res, indent=4))
801
846
  except Exception as e:
@@ -804,6 +849,10 @@ class SynchronizerCLI(cmd.Cmd):
804
849
  except SystemExit:
805
850
  return
806
851
 
852
+ def do_clear(self, arg) -> None:
853
+ """Clear the terminal screen."""
854
+ clear_terminal()
855
+
807
856
  def do_exit(self, arg):
808
857
  """Return to the main menu."""
809
858
  console.print(Panel("Returning to main menu...", style="blue"))
@@ -965,7 +1014,7 @@ class MainShell(cmd.Cmd):
965
1014
  """List all properties available in the connected AEP instance."""
966
1015
  parser = argparse.ArgumentParser(prog='get_properties', add_help=True)
967
1016
  parser.add_argument("-n", "--name", help="Filter properties by name (partial match, non-case sensitive)", type=str, default=None)
968
- parser.add_argument("-s", "--save", help="Boolean. Save properties to a CSV file. Default False. Possible values: True, False", type=bool, default=False)
1017
+ parser.add_argument("-s", "--save", help="Boolean. Save properties to a CSV file. Default False. Possible values: True, False", type=str2bool, nargs="?", const=True, default=False)
969
1018
  try:
970
1019
  args = parser.parse_args(shlex.split(arg))
971
1020
  properties = self.admin.getProperties(self.cid)
@@ -1094,7 +1143,7 @@ class MainShell(cmd.Cmd):
1094
1143
  def do_get_extensions(self, arg:Any) -> None:
1095
1144
  """List all available extensions in the connected Adobe Launch organization."""
1096
1145
  parser = argparse.ArgumentParser(prog='get_extensions', add_help=True)
1097
- parser.add_argument("-s", "--save", help="Boolean. Save extensions to a JSON file. Default False. Possible values: True, False", type=bool, default=False)
1146
+ parser.add_argument("-s", "--save", help="Boolean. Save extensions to a JSON file. Default False. Possible values: True, False", type=str2bool, nargs="?", const=True, default=False)
1098
1147
  try:
1099
1148
  args = parser.parse_args(shlex.split(arg))
1100
1149
  extensions = self.admin.getExtensionsCatalogue()
@@ -1144,6 +1193,10 @@ class MainShell(cmd.Cmd):
1144
1193
  except SystemExit:
1145
1194
  return
1146
1195
 
1196
+ def do_clear(self, arg:Any) -> None:
1197
+ """Clear the terminal screen."""
1198
+ clear_terminal()
1199
+
1147
1200
  def do_exit(self, arg:Any) -> bool:
1148
1201
  """Exit the application."""
1149
1202
  console.print(Panel("Exiting...", style="blue"))
@@ -3,9 +3,7 @@ token = ""
3
3
  config_object = {
4
4
  "org_id": "",
5
5
  "api_key": "",
6
- "pathToKey": "",
7
6
  "secret": "",
8
- "jwtTokenEndpoint" : "https://ims-na1.adobelogin.com/ims/exchange/jwt",
9
7
  "oauthTokenEndpointV2" : "https://ims-na1.adobelogin.com/ims/token/v2",
10
8
  "date_limit" : 0,
11
9
  "scope_admin" : "https://ims-na1.adobelogin.com/s/ent_reactor_admin_sdk",