Skip to content

Commit eb9abd0

Browse files
authored
Merge pull request #42 from derek10cloud/generic-to-named-export
feat: Support named export
2 parents 076b2fc + e76b6fb commit eb9abd0

File tree

5 files changed

+70
-21
lines changed

5 files changed

+70
-21
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 1.7.5 (2024-10-02)
4+
5+
- Allowing a `list of objects` in the form of `exported_variable (key)` and `renamed_assigned_exported_variable (value)`
6+
37
## 1.7.4 (2024-09-19)
48

59
- Colorizing the headings in `stack-deploy info` to green

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
setup(
1212
name='stackql-deploy',
13-
version='1.7.4',
13+
version='1.7.5',
1414
description='Model driven resource provisioning and deployment framework using StackQL.',
1515
long_description=readme,
1616
long_description_content_type='text/x-rst',

stackql_deploy/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '1.7.4'
1+
__version__ = '1.7.5'

stackql_deploy/cmd/base.py

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from ..lib.utils import perform_retries, run_stackql_command, catch_error_and_exit, run_stackql_query, export_vars, show_query, get_type
1+
from ..lib.utils import perform_retries, run_stackql_command, catch_error_and_exit, run_stackql_query, export_vars, show_query, get_type, check_all_dicts
22
from ..lib.config import setup_environment, load_manifest, get_global_context_and_providers, get_full_context
33
from ..lib.templating import get_queries
44

@@ -17,11 +17,24 @@ def __init__(self, stackql, vars, logger, stack_dir, stack_env):
1717
def process_exports(self, resource, exports_query, exports_retries, exports_retry_delay, dry_run, show_queries,ignore_missing_exports=False):
1818
expected_exports = resource.get('exports', [])
1919

20+
# Check if all items in expected_exports are dictionaries
21+
all_dicts = check_all_dicts(expected_exports, self.logger)
22+
2023
if len(expected_exports) > 0:
2124
protected_exports = resource.get('protected', [])
22-
2325
if dry_run:
24-
export_data = {key: "<evaluated>" for key in expected_exports}
26+
export_data = {}
27+
if all_dicts:
28+
for item in expected_exports:
29+
for _, val in item.items():
30+
# when item is a dictionary,
31+
# val(expected_exports) is the key to be exported
32+
export_data[val] = "<evaluated>"
33+
else:
34+
# when item is not a dictionary,
35+
# item is the key to be exported
36+
for item in expected_exports:
37+
export_data[item] = "<evaluated>"
2538
export_vars(self, resource, export_data, expected_exports, protected_exports)
2639
self.logger.info(f"📦 dry run exports query for [{resource['name']}]:\n\n/* exports query */\n{exports_query}\n")
2740
else:
@@ -44,16 +57,31 @@ def process_exports(self, resource, exports_query, exports_retries, exports_retr
4457

4558
export = exports[0]
4659
if len(exports) == 0:
47-
export = {key: '' for key in expected_exports}
60+
export_data = {}
61+
if all_dicts:
62+
for item in expected_exports:
63+
for key, val in item.items():
64+
export_data[val] = ''
65+
else:
66+
export_data[item] = ''
4867
else:
4968
export_data = {}
50-
for key in expected_exports:
51-
if isinstance(export.get(key), dict) and 'String' in export[key]:
52-
export_data[key] = export[key]['String']
69+
for item in expected_exports:
70+
if all_dicts:
71+
for key, val in item.items():
72+
# when item is a dictionary,
73+
# compare key(expected_exports) with key(export)
74+
# set val(expected_exports) as key and export[key] as value in export_data
75+
if isinstance(export.get(key), dict) and 'String' in export[key]:
76+
export_data[val] = export[key]['String']
77+
else:
78+
export_data[val] = export.get(key, '')
5379
else:
54-
export_data[key] = export.get(key, '')
55-
56-
export_vars(self, resource, export_data, expected_exports, protected_exports)
80+
if isinstance(export.get(item), dict) and 'String' in export[item]:
81+
export_data[item] = export[item]['String']
82+
else:
83+
export_data[item] = export.get(item, '')
84+
export_vars(self, resource, export_data, expected_exports, all_dicts, protected_exports)
5785

5886
def check_if_resource_exists(self, resource_exists, resource, exists_query, exists_retries, exists_retry_delay, dry_run, show_queries, delete_test=False):
5987
check_type = 'exists'

stackql_deploy/lib/utils.py

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -181,18 +181,21 @@ def perform_retries(resource, query, retries, delay, stackql, logger, delete_tes
181181
elapsed = time.time() - start_time # Calculate total elapsed time
182182
return False
183183

184-
def export_vars(self, resource, export, expected_exports, protected_exports):
185-
for key in expected_exports:
186-
if key not in export:
187-
catch_error_and_exit(f"(utils.export_vars) exported key '{key}' not found in exports for {resource['name']}.", self.logger)
188-
184+
def export_vars(self, resource, export, expected_exports, expected_exports_all_dicts, protected_exports):
185+
for item in expected_exports:
186+
# check if all items are dictionaries
187+
if expected_exports_all_dicts:
188+
if list(item.values())[0] not in export:
189+
catch_error_and_exit(f"(utils.export_vars) exported item '{list(item.values())[0]}' not found in exports for {resource['name']}.", self.logger)
190+
else:
191+
if item not in export:
192+
catch_error_and_exit(f"(utils.export_vars) exported item '{item}' not found in exports for {resource['name']}.", self.logger)
189193
for key, value in export.items():
190194
if key in protected_exports:
191195
mask = '*' * len(str(value))
192-
self.logger.info(f"🔒 set protected variable [{key}] to [{mask}] in exports")
196+
self.logger.info(f"🔒 set protected variable [{key}] to [{mask}] in exports")
193197
else:
194-
self.logger.info(f"➡️ set [{key}] to [{value}] in exports")
195-
198+
self.logger.info(f"📤 set [{key}] to [{value}] in exports")
196199
self.global_context[key] = value # Update global context with exported values
197200

198201
def run_ext_script(cmd, logger, exports=None):
@@ -220,4 +223,18 @@ def run_ext_script(cmd, logger, exports=None):
220223
return exported_vars
221224
except json.JSONDecodeError:
222225
catch_error_and_exit(f"(utils.run_ext_script) external scripts must return a valid JSON object {result.stdout}", logger)
223-
return None
226+
return None
227+
228+
def check_all_dicts(items, logger):
229+
""" Check if all items(list) are of the same type (either all dicts or all non-dicts).
230+
"""
231+
all_dicts = all(isinstance(item, dict) for item in items)
232+
no_dicts = all(not isinstance(item, dict) for item in items)
233+
234+
if not all_dicts and not no_dicts:
235+
catch_error_and_exit(f"type inconsistency: all items({items}) must be either dicts or non-dicts", logger)
236+
237+
if all_dicts:
238+
return True
239+
else:
240+
return False

0 commit comments

Comments
 (0)