Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/azure-changesafety/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
Release History
===============

1.0.0b2
+++++++
* Fix ``--additional-data`` argument to accept free-form nested JSON (e.g., SafeFly payloads).
* Fix ``--change-definition`` details to accept free-form nested JSON (e.g., ApiOperations with operations array).
* Inject ``additionalData`` into request body via content override (AAZ builder workaround).
* Add content injection for ``additionalData`` in both Create and Update commands.

1.0.0b1
+++++++
* Initial release.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def _build_arguments_schema(cls, *args, **kwargs):
# define Arg Group "Properties"

_args_schema = cls._args_schema
_args_schema.additional_data = AAZObjectArg(
_args_schema.additional_data = AAZFreeFormDictArg(
options=["--additional-data"],
arg_group="Properties",
help="Additional metadata for the change required for various orchestration tools.",
Expand Down Expand Up @@ -139,7 +139,7 @@ def _build_arguments_schema(cls, *args, **kwargs):
)

change_definition = cls._args_schema.change_definition
change_definition.details = AAZObjectArg(
change_definition.details = AAZFreeFormDictArg(
options=["details"],
help="Free form object containing additional details for the change definition.",
required=True,
Expand Down Expand Up @@ -371,7 +371,7 @@ def content(self):

properties = _builder.get(".properties")
if properties is not None:
properties.set_prop("additionalData", AAZObjectType, ".additional_data")
properties.set_prop("additionalData", AAZFreeFormDictType, ".additional_data")
properties.set_prop("anticipatedEndTime", AAZStrType, ".anticipated_end_time", typ_kwargs={"flags": {"required": True}})
properties.set_prop("anticipatedStartTime", AAZStrType, ".anticipated_start_time", typ_kwargs={"flags": {"required": True}})
properties.set_prop("changeDefinition", AAZObjectType, ".change_definition", typ_kwargs={"flags": {"required": True}})
Expand All @@ -387,7 +387,7 @@ def content(self):

change_definition = _builder.get(".properties.changeDefinition")
if change_definition is not None:
change_definition.set_prop("details", AAZObjectType, ".details", typ_kwargs={"flags": {"required": True}})
change_definition.set_prop("details", AAZFreeFormDictType, ".details", typ_kwargs={"flags": {"required": True}})
change_definition.set_prop("kind", AAZStrType, ".kind", typ_kwargs={"flags": {"required": True}})
change_definition.set_prop("name", AAZStrType, ".name", typ_kwargs={"flags": {"required": True}})

Expand Down Expand Up @@ -510,7 +510,7 @@ def _build_schema_on_200_201(cls):
)

properties = cls._schema_on_200_201.properties
properties.additional_data = AAZObjectType(
properties.additional_data = AAZFreeFormDictType(
serialized_name="additionalData",
)
properties.anticipated_end_time = AAZStrType(
Expand Down Expand Up @@ -559,7 +559,7 @@ def _build_schema_on_200_201(cls):
)

change_definition = cls._schema_on_200_201.properties.change_definition
change_definition.details = AAZObjectType(
change_definition.details = AAZFreeFormDictType(
flags={"required": True},
)
change_definition.kind = AAZStrType(
Expand Down Expand Up @@ -754,7 +754,7 @@ def content(self):

properties = _builder.get(".properties")
if properties is not None:
properties.set_prop("additionalData", AAZObjectType, ".additional_data")
properties.set_prop("additionalData", AAZFreeFormDictType, ".additional_data")
properties.set_prop("anticipatedEndTime", AAZStrType, ".anticipated_end_time", typ_kwargs={"flags": {"required": True}})
properties.set_prop("anticipatedStartTime", AAZStrType, ".anticipated_start_time", typ_kwargs={"flags": {"required": True}})
properties.set_prop("changeDefinition", AAZObjectType, ".change_definition", typ_kwargs={"flags": {"required": True}})
Expand All @@ -770,7 +770,7 @@ def content(self):

change_definition = _builder.get(".properties.changeDefinition")
if change_definition is not None:
change_definition.set_prop("details", AAZObjectType, ".details", typ_kwargs={"flags": {"required": True}})
change_definition.set_prop("details", AAZFreeFormDictType, ".details", typ_kwargs={"flags": {"required": True}})
change_definition.set_prop("kind", AAZStrType, ".kind", typ_kwargs={"flags": {"required": True}})
change_definition.set_prop("name", AAZStrType, ".name", typ_kwargs={"flags": {"required": True}})

Expand Down Expand Up @@ -893,7 +893,7 @@ def _build_schema_on_200_201(cls):
)

properties = cls._schema_on_200_201.properties
properties.additional_data = AAZObjectType(
properties.additional_data = AAZFreeFormDictType(
serialized_name="additionalData",
)
properties.anticipated_end_time = AAZStrType(
Expand Down Expand Up @@ -942,7 +942,7 @@ def _build_schema_on_200_201(cls):
)

change_definition = cls._schema_on_200_201.properties.change_definition
change_definition.details = AAZObjectType(
change_definition.details = AAZFreeFormDictType(
flags={"required": True},
)
change_definition.kind = AAZStrType(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ def _build_schema_on_200(cls):
)

properties = cls._schema_on_200.value.Element.properties
properties.additional_data = AAZObjectType(
properties.additional_data = AAZFreeFormDictType(
serialized_name="additionalData",
)
properties.anticipated_end_time = AAZStrType(
Expand Down Expand Up @@ -218,7 +218,7 @@ def _build_schema_on_200(cls):
)

change_definition = cls._schema_on_200.value.Element.properties.change_definition
change_definition.details = AAZObjectType(
change_definition.details = AAZFreeFormDictType(
flags={"required": True},
)
change_definition.kind = AAZStrType(
Expand Down Expand Up @@ -440,7 +440,7 @@ def _build_schema_on_200(cls):
)

properties = cls._schema_on_200.value.Element.properties
properties.additional_data = AAZObjectType(
properties.additional_data = AAZFreeFormDictType(
serialized_name="additionalData",
)
properties.anticipated_end_time = AAZStrType(
Expand Down Expand Up @@ -489,7 +489,7 @@ def _build_schema_on_200(cls):
)

change_definition = cls._schema_on_200.value.Element.properties.change_definition
change_definition.details = AAZObjectType(
change_definition.details = AAZFreeFormDictType(
flags={"required": True},
)
change_definition.kind = AAZStrType(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def _build_schema_on_200(cls):
)

properties = cls._schema_on_200.properties
properties.additional_data = AAZObjectType(
properties.additional_data = AAZFreeFormDictType(
serialized_name="additionalData",
)
properties.anticipated_end_time = AAZStrType(
Expand Down Expand Up @@ -220,7 +220,7 @@ def _build_schema_on_200(cls):
)

change_definition = cls._schema_on_200.properties.change_definition
change_definition.details = AAZObjectType(
change_definition.details = AAZFreeFormDictType(
flags={"required": True},
)
change_definition.kind = AAZStrType(
Expand Down Expand Up @@ -435,7 +435,7 @@ def _build_schema_on_200(cls):
)

properties = cls._schema_on_200.properties
properties.additional_data = AAZObjectType(
properties.additional_data = AAZFreeFormDictType(
serialized_name="additionalData",
)
properties.anticipated_end_time = AAZStrType(
Expand Down Expand Up @@ -484,7 +484,7 @@ def _build_schema_on_200(cls):
)

change_definition = cls._schema_on_200.properties.change_definition
change_definition.details = AAZObjectType(
change_definition.details = AAZFreeFormDictType(
flags={"required": True},
)
change_definition.kind = AAZStrType(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def _build_arguments_schema(cls, *args, **kwargs):
# define Arg Group "Properties"

_args_schema = cls._args_schema
_args_schema.additional_data = AAZObjectArg(
_args_schema.additional_data = AAZFreeFormDictArg(
options=["--additional-data"],
arg_group="Properties",
help="Additional metadata for the change required for various orchestration tools.",
Expand Down Expand Up @@ -150,7 +150,7 @@ def _build_arguments_schema(cls, *args, **kwargs):
)

change_definition = cls._args_schema.change_definition
change_definition.details = AAZObjectArg(
change_definition.details = AAZFreeFormDictArg(
options=["details"],
help="Free form object containing additional details for the change definition.",
blank={},
Expand Down Expand Up @@ -717,7 +717,7 @@ def _update_instance(self, instance):

properties = _builder.get(".properties")
if properties is not None:
properties.set_prop("additionalData", AAZObjectType, ".additional_data")
properties.set_prop("additionalData", AAZFreeFormDictType, ".additional_data")
properties.set_prop("anticipatedEndTime", AAZStrType, ".anticipated_end_time", typ_kwargs={"flags": {"required": True}})
properties.set_prop("anticipatedStartTime", AAZStrType, ".anticipated_start_time", typ_kwargs={"flags": {"required": True}})
properties.set_prop("changeDefinition", AAZObjectType, ".change_definition", typ_kwargs={"flags": {"required": True}})
Expand All @@ -733,7 +733,7 @@ def _update_instance(self, instance):

change_definition = _builder.get(".properties.changeDefinition")
if change_definition is not None:
change_definition.set_prop("details", AAZObjectType, ".details", typ_kwargs={"flags": {"required": True}})
change_definition.set_prop("details", AAZFreeFormDictType, ".details", typ_kwargs={"flags": {"required": True}})
change_definition.set_prop("kind", AAZStrType, ".kind", typ_kwargs={"flags": {"required": True}})
change_definition.set_prop("name", AAZStrType, ".name", typ_kwargs={"flags": {"required": True}})

Expand Down Expand Up @@ -865,7 +865,7 @@ def _build_schema_change_record_read(cls, _schema):
)

properties = _schema_change_record_read.properties
properties.additional_data = AAZObjectType(
properties.additional_data = AAZFreeFormDictType(
serialized_name="additionalData",
)
properties.anticipated_end_time = AAZStrType(
Expand Down Expand Up @@ -914,7 +914,7 @@ def _build_schema_change_record_read(cls, _schema):
)

change_definition = _schema_change_record_read.properties.change_definition
change_definition.details = AAZObjectType(
change_definition.details = AAZFreeFormDictType(
flags={"required": True},
)
change_definition.kind = AAZStrType(
Expand Down
72 changes: 62 additions & 10 deletions src/azure-changesafety/azext_changesafety/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,28 @@ def _inject_change_definition_into_content(content, ctx):
return content


def _inject_additional_data_into_content(content, ctx):
"""Inject the parsed additionalData into the serialized request content.

The AAZ content builder cannot serialize AAZFreeFormDictType correctly
(it produces {}), so we capture the raw value in pre_operations and
inject it here — the same pattern used for changeDefinition.
"""
additional_data_value = getattr(ctx.vars, "additional_data", None)
if additional_data_value is None:
return content

additional_data = additional_data_value.to_serialized_data()
if additional_data is None:
return content

if content is None:
content = {}
properties = content.setdefault("properties", {})
properties["additionalData"] = additional_data
return content


def _preserve_change_definition_in_content(content, ctx):
"""Preserve the original changeDefinition from GET response in the update request.

Expand Down Expand Up @@ -356,6 +378,19 @@ def pre_operations(self):
self._ensure_schedule_defaults()
_apply_stage_map_shortcut(self.ctx)

# Capture additional_data for injection into request content.
# The AAZ builder cannot serialize AAZFreeFormDictType, so we
# store the raw value and inject it via the content property.
additional_data_arg = getattr(self.ctx.args, "additional_data", None)
if has_value(additional_data_arg):
additional_data = additional_data_arg.to_serialized_data()
if additional_data is not None:
self.ctx.set_var(
'additional_data',
additional_data,
schema_builder=_build_any_type,
)
Comment on lines +381 to +392

change_definition_arg = getattr(self.ctx.args, "change_definition", None)
change_definition_value = None
self._raw_targets = [t for t in (self._raw_targets or []) if t and str(t) != 'Undefined']
Expand Down Expand Up @@ -490,21 +525,25 @@ def _output(self, *args, **kwargs):

class ChangeRecordsCreateOrUpdateAtSubscriptionLevel(
_ChangeRecordCreate.ChangeRecordsCreateOrUpdateAtSubscriptionLevel):
"""Override PUT at subscription level to inject custom changeDefinition."""
"""Override PUT at subscription level to inject custom payloads."""

@property
def content(self):
content = super().content
return _inject_change_definition_into_content(content, self.ctx)
content = _inject_change_definition_into_content(content, self.ctx)
content = _inject_additional_data_into_content(content, self.ctx)
return content

class ChangeRecordsCreateOrUpdate(
_ChangeRecordCreate.ChangeRecordsCreateOrUpdate):
"""Override PUT at resource group level to inject custom changeDefinition."""
"""Override PUT at resource group level to inject custom payloads."""

@property
def content(self):
content = super().content
return _inject_change_definition_into_content(content, self.ctx)
content = _inject_change_definition_into_content(content, self.ctx)
content = _inject_additional_data_into_content(content, self.ctx)
return content


class ChangeRecordUpdate(_ChangeRecordUpdate):
Expand Down Expand Up @@ -539,6 +578,17 @@ def pre_operations(self):
super().pre_operations()
_apply_stage_map_shortcut(self.ctx)

# Capture additional_data for injection (same pattern as Create)
additional_data_arg = getattr(self.ctx.args, "additional_data", None)
if has_value(additional_data_arg):
additional_data = additional_data_arg.to_serialized_data()
if additional_data is not None:
self.ctx.set_var(
'additional_data',
additional_data,
schema_builder=_build_any_type,
)

class ChangeRecordsGetAtSubscriptionLevel(
_ChangeRecordUpdate.ChangeRecordsGetAtSubscriptionLevel):
"""Override GET at subscription level to capture original changeDefinition."""
Expand Down Expand Up @@ -572,23 +622,25 @@ def on_200(self, session):

class ChangeRecordsCreateOrUpdateAtSubscriptionLevel(
_ChangeRecordUpdate.ChangeRecordsCreateOrUpdateAtSubscriptionLevel):
"""Override PUT at subscription level to preserve original changeDefinition."""
"""Override PUT at subscription level to preserve changeDefinition and inject additionalData."""

@property
def content(self):
content = super().content
# Preserve original changeDefinition - it cannot be updated
return _preserve_change_definition_in_content(content, self.ctx)
content = _preserve_change_definition_in_content(content, self.ctx)
content = _inject_additional_data_into_content(content, self.ctx)
return content
Comment on lines 623 to +632

class ChangeRecordsCreateOrUpdate(
_ChangeRecordUpdate.ChangeRecordsCreateOrUpdate):
"""Override PUT at resource group level to preserve original changeDefinition."""
"""Override PUT at resource group level to preserve changeDefinition and inject additionalData."""

@property
def content(self):
content = super().content
# Preserve original changeDefinition - it cannot be updated
return _preserve_change_definition_in_content(content, self.ctx)
content = _preserve_change_definition_in_content(content, self.ctx)
content = _inject_additional_data_into_content(content, self.ctx)
return content


class ChangeRecordShow(_ChangeRecordShow):
Expand Down
Loading
Loading