diff --git a/src/azure-changesafety/HISTORY.rst b/src/azure-changesafety/HISTORY.rst new file mode 100644 index 00000000000..abbff5a61a7 --- /dev/null +++ b/src/azure-changesafety/HISTORY.rst @@ -0,0 +1,8 @@ +.. :changelog: + +Release History +=============== + +1.0.0b1 +++++++ +* Initial release. \ No newline at end of file diff --git a/src/azure-changesafety/README.md b/src/azure-changesafety/README.md new file mode 100644 index 00000000000..0e3a83a8371 --- /dev/null +++ b/src/azure-changesafety/README.md @@ -0,0 +1,115 @@ +# Azure CLI Change Safety Extension +Azure CLI extension for managing Change Safety resources. This includes `ChangeRecord`, `StageMap`, and `StageProgression` resources for coordinating, tracking, and safely deploying changes across your Azure environment. + +## Installation +```bash +az extension add --source --yes +# or install the latest published build +az extension add --name azure-changesafety +``` + +## Commands + +### ChangeRecord +```bash +az changesafety changerecord create # Create a ChangeRecord for one or more targets. +az changesafety changerecord update # Update metadata, rollout configuration, or target definitions. +az changesafety changerecord delete # Delete a ChangeRecord resource. +az changesafety changerecord show # Display details for a ChangeRecord resource. +az changesafety changerecord list # List ChangeRecord resources. +``` + +### StageMap +```bash +az changesafety stagemap create # Create a StageMap defining rollout stages. +az changesafety stagemap update # Update StageMap stages. +az changesafety stagemap delete # Delete a StageMap resource. +az changesafety stagemap show # Display details for a StageMap resource. +az changesafety stagemap list # List StageMap resources. +``` + +### StageProgression +```bash +az changesafety stageprogression create # Create a StageProgression to track stage execution. +az changesafety stageprogression update # Update StageProgression status or comments. +az changesafety stageprogression delete # Delete a StageProgression resource. +az changesafety stageprogression show # Display details for a StageProgression resource. +az changesafety stageprogression list # List StageProgression resources for a ChangeRecord. +``` + +Run `az changesafety -h` to see full command groups and examples. + +## Examples + +### StageMap Examples +Create a two-stage StageMap for rollout: +```bash +az changesafety stagemap create \ + --stage-map-name rolloutStageMap \ + --stages "[{name:Canary,sequence:1},{name:Production,sequence:2}]" +``` + +Create a StageMap with configurable parameters: +```bash +# Parameters use AAZ shorthand: paramName.{string|number|array|object}.property=value +# Use --parameters paramName.string="??" to explore available properties +az changesafety stagemap create \ + --stage-map-name parameterized-rollout \ + --stages "[{name:Canary,sequence:1},{name:Production,sequence:2}]" \ + --parameters region.string.default-value=westus batchSize.number.default-value=10 +``` + +### ChangeRecord Examples +Create a ChangeRecord for a manual touch operation (e.g., delete a Traffic Manager profile): +```bash +az changesafety changerecord create \ + -g MyResourceGroup \ + -n changerecord-delete-tm \ + --change-type ManualTouch \ + --rollout-type Hotfix \ + --targets "resourceId=/subscriptions//resourceGroups/MyResourceGroup/providers/Microsoft.Network/trafficManagerProfiles/myProfile,operation=DELETE" \ + --description "Delete Traffic Manager profile for maintenance" +``` + +Create a ChangeRecord for an app deployment with a StageMap reference: +```bash +az changesafety changerecord create \ + -g MyResourceGroup \ + -n changerecord-webapp-rollout \ + --change-type AppDeployment \ + --rollout-type Normal \ + --targets "resourceId=/subscriptions//resourceGroups/MyResourceGroup/providers/Microsoft.Web/sites/myApp,operation=PUT" \ + --stagemap-name rolloutStageMap \ + --links name=Runbook uri=https://contoso.com/runbook +``` + +Update the ChangeRecord and add a comment: +```bash +az changesafety changerecord update \ + -g MyResourceGroup \ + -n changerecord-webapp-rollout \ + --comments "Deployment validated in canary region" +``` + +### StageProgression Examples +Create a StageProgression for the Canary stage: +```bash +az changesafety stageprogression create \ + --change-record-name changerecord-webapp-rollout \ + -n canary-progression \ + --stage-reference Canary \ + --status InProgress +``` + +Update StageProgression to mark stage as completed: +```bash +az changesafety stageprogression update \ + --change-record-name changerecord-webapp-rollout \ + -n canary-progression \ + --status Completed \ + --comments "Canary validation passed" +``` + +## Additional Information +- View command documentation: `az changesafety -h` +- Remove the extension when no longer needed: `az extension remove --name azure-changesafety` diff --git a/src/azure-changesafety/azext_changesafety/__init__.py b/src/azure-changesafety/azext_changesafety/__init__.py new file mode 100644 index 00000000000..ef81dcb0076 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/__init__.py @@ -0,0 +1,44 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +from azure.cli.core import AzCommandsLoader +from azext_changesafety._help import helps # pylint: disable=unused-import +# Import custom to apply AZ_HELP patches for StageMap commands +from azext_changesafety import custom as _custom # pylint: disable=unused-import + + +class ChangeRecordCommandsLoader(AzCommandsLoader): + + def __init__(self, cli_ctx=None): + from azure.cli.core.commands import CliCommandType + custom_command_type = CliCommandType( + operations_tmpl='azext_changesafety.custom#{}') + super().__init__(cli_ctx=cli_ctx, + custom_command_type=custom_command_type) + + def load_command_table(self, args): + from azext_changesafety.commands import load_command_table + from azure.cli.core.aaz import load_aaz_command_table + try: + from . import aaz + except ImportError: + aaz = None + if aaz: + load_aaz_command_table( + loader=self, + aaz_pkg_name=aaz.__name__, + args=args + ) + load_command_table(self, args) + return self.command_table + + def load_arguments(self, command): + from azext_changesafety._params import load_arguments + load_arguments(self, command) + + +COMMAND_LOADER_CLS = ChangeRecordCommandsLoader diff --git a/src/azure-changesafety/azext_changesafety/_help.py b/src/azure-changesafety/azext_changesafety/_help.py new file mode 100644 index 00000000000..11d109de84a --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/_help.py @@ -0,0 +1,199 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: disable=line-too-long +# pylint: disable=too-many-lines + +from knack.help_files import helps # pylint: disable=unused-import + +helps['changesafety'] = """ + type: group + short-summary: Manage Change Safety resources. +""" + +helps['changesafety changerecord'] = """ + type: group + short-summary: Manage ChangeRecord resources that describe planned changes across targets. +""" + +helps['changesafety changerecord create'] = """ + type: command + short-summary: Create a ChangeRecord resource. + long-summary: > + Provide at least one target definition to describe which resources or operations the ChangeRecord + will affect. Targets are expressed as comma or semicolon separated key=value pairs such as + resourceId=RESOURCE_ID,operation=DELETE. The command is also available through the alias + `az changesafety changerecord`. If you omit scheduling flags, the anticipated start time + defaults to now and the anticipated end time defaults to eight hours later (UTC). + parameters: + - name: --targets + short-summary: > + One or more target definitions expressed as key=value pairs (for example + resourceId=RESOURCE_ID,operation=DELETE,resourceType=Microsoft.Compute/virtualMachines). + - name: --description + short-summary: A description of the change being performed. + - name: --anticipated-start-time + short-summary: Expected start time in ISO 8601 format. Defaults to current UTC time when omitted. + - name: --anticipated-end-time + short-summary: Expected completion time in ISO 8601 format. Defaults to eight hours after the anticipated start time when omitted. + - name: --change-type + short-summary: Classify the change such as AppDeployment, Config, ManualTouch, or PolicyDeployment. + - name: --rollout-type + short-summary: Specify the rollout type (Normal, Hotfix, or Emergency). + - name: --stage-map-name --stagemap-name + short-summary: StageMap name in the current subscription scope; the resource ID is built for you. + - name: --stage-map + short-summary: Reference an existing StageMap resource using resource-id=RESOURCE_ID and optional parameters key=value pairs. + - name: --links + short-summary: Add supporting links by repeating --links name=NAME uri=URL [description=TEXT]. + examples: + - name: Create with StageMap reference and status link + text: |- + az changesafety changerecord create -g MyResourceGroup -n changerecord002 --change-type ManualTouch --rollout-type Normal --stage-map "{resource-id:/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MyResourceGroup/providers/Microsoft.ChangeSafety/stageMaps/rolloutStageMap}" --targets "resourceId=/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MyResourceGroup/providers/Microsoft.Compute/virtualMachines/myVm,operation=PATCH" --links "[{name:status,uri:'https://contoso.com/change/rollout-002'}]" + az changesafety changerecord delete -g MyResourceGroup -n changerecord002 --yes + - name: Create a ChangeRecord for a VM rollout + text: |- + az changesafety changerecord create -g MyResourceGroup -n changerecord001 --change-type AppDeployment --rollout-type Normal --targets "resourceId=/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MyResourceGroup/providers/Microsoft.Compute/virtualMachines/myVm,operation=PUT" + - name: Create a ChangeRecord for deleting a Traffic Manager profile + text: |- + az changesafety changerecord create -g MyResourceGroup -n delete-trafficmanager --change-type ManualTouch --rollout-type Hotfix --targets "resourceId=/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MyResourceGroup/providers/Microsoft.Network/trafficManagerProfiles/myProfile,operation=DELETE" --description "Delete Traffic Manager profile" + - name: Create with staging rollout configuration + text: |- + az changesafety changerecord create -g MyResourceGroup -n changerecord-ops01 --change-type AppDeployment --rollout-type Hotfix --targets "resourceId=/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MyResourceGroup/providers/Microsoft.Web/sites/myApp,operation=POST" + - name: Reference a StageMap by name + text: |- + az changesafety changerecord create -g MyResourceGroup -n changerecord003 --change-type ManualTouch --rollout-type Normal --stagemap-name rolloutStageMap --targets "resourceId=/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MyResourceGroup/providers/Microsoft.Compute/virtualMachines/myVm,operation=DELETE" +""" + +helps['changesafety changerecord update'] = """ + type: command + short-summary: Update an existing ChangeRecord resource. + long-summary: > + Use this command to modify descriptive metadata, rollout settings, or scheduling for an + existing ChangeRecord. Note: The changeDefinition (targets) cannot be modified after creation. + parameters: + - name: --stage-map-name --stagemap-name + short-summary: StageMap name in the current subscription scope; the resource ID is built for you. + - name: --stage-map + short-summary: Reference an existing StageMap resource using resource-id=RESOURCE_ID and optional parameters key=value pairs. + - name: --comments + short-summary: Provide notes about the latest update to the ChangeRecord. + - name: --description + short-summary: Update the description of the change. + - name: --anticipated-start-time + short-summary: Update the expected start time in ISO 8601 format. If omitted, the current value is preserved. + - name: --anticipated-end-time + short-summary: Update the expected completion time in ISO 8601 format. If omitted, the current value is preserved. + examples: + - name: Adjust rollout type and add a comment + text: |- + az changesafety changerecord update -g MyResourceGroup -n changerecord001 --rollout-type Emergency --comments "Escalated to emergency rollout" + - name: Update scheduling window + text: |- + az changesafety changerecord update -g MyResourceGroup -n changerecord001 --anticipated-start-time "2024-09-01T08:00:00Z" --anticipated-end-time "2024-09-01T12:00:00Z" + - name: Update description + text: |- + az changesafety changerecord update -g MyResourceGroup -n changerecord001 --description "Updated rollout for production deployment" +""" + +helps['changesafety changerecord delete'] = """ + type: command + short-summary: Delete a ChangeRecord resource. + examples: + - name: Delete a ChangeRecord without confirmation + text: |- + az changesafety changerecord delete -g MyResourceGroup -n changerecord001 --yes +""" + +helps['changesafety changerecord show'] = """ + type: command + short-summary: Show details for a ChangeRecord resource. + examples: + - name: Show a ChangeRecord + text: |- + az changesafety changerecord show -g MyResourceGroup -n changerecord001 +""" + +helps['changesafety stagemap'] = """ + type: group + short-summary: Manage StageMap resources that define rollout stages for orchestrated changes. +""" + +helps['changesafety stagemap create'] = """ + type: command + short-summary: Create a StageMap resource. + long-summary: > + A StageMap defines the stages through which a change progresses during rollout. + Each stage has a name and sequence number. Stages are executed in order of their + sequence values. StageMap resources can be referenced by ChangeRecord resources + to enforce staged rollout patterns. + parameters: + - name: --stage-map-name + short-summary: The name of the StageMap resource to create. + - name: --stages + short-summary: > + Array of stage definitions. Each stage requires a name and sequence number. + Use shorthand syntax or JSON format. + - name: --parameters + short-summary: > + Optional parameters schema for the StageMap. Define parameters that can be + passed when referencing this StageMap from a ChangeRecord. Use AAZ shorthand + syntax: paramName.{string|number|array|object}.default-value=value. + Run with --parameters paramName.string="??" to see available properties. + examples: + - name: Create a simple two-stage StageMap + text: |- + az changesafety stagemap create --subscription 00000000-0000-0000-0000-000000000000 --stage-map-name rolloutStageMap --stages "[{name:Canary,sequence:1},{name:Production,sequence:2}]" + - name: Create a StageMap with three stages + text: |- + az changesafety stagemap create --subscription 00000000-0000-0000-0000-000000000000 --stage-map-name regional-rollout --stages "[{name:WestUS,sequence:1},{name:EastUS,sequence:2},{name:Global,sequence:3}]" + - name: Create a StageMap with parameters + text: |- + az changesafety stagemap create --subscription 00000000-0000-0000-0000-000000000000 --stage-map-name parameterized-rollout --stages "[{name:Canary,sequence:1},{name:Production,sequence:2}]" --parameters region.string.default-value=westus batchSize.number.default-value=10 +""" + +helps['changesafety stagemap update'] = """ + type: command + short-summary: Update an existing StageMap resource. + long-summary: > + Modify the stages defined in a StageMap. When updating, provide the complete + list of stages as the update replaces the existing stages array. + examples: + - name: Add a new stage to an existing StageMap + text: |- + az changesafety stagemap update --subscription 00000000-0000-0000-0000-000000000000 --stage-map-name rolloutStageMap --stages "[{name:Canary,sequence:1},{name:Pilot,sequence:2},{name:Production,sequence:3}]" +""" + +helps['changesafety stagemap show'] = """ + type: command + short-summary: Get details for a StageMap resource. + examples: + - name: Show a StageMap + text: |- + az changesafety stagemap show --subscription 00000000-0000-0000-0000-000000000000 --stage-map-name rolloutStageMap +""" + +helps['changesafety stagemap delete'] = """ + type: command + short-summary: Delete a StageMap resource. + long-summary: > + Delete a StageMap that is no longer needed. Note that StageMap resources + that are currently referenced by active ChangeRecord resources cannot be deleted. + examples: + - name: Delete a StageMap + text: |- + az changesafety stagemap delete --subscription 00000000-0000-0000-0000-000000000000 --stage-map-name rolloutStageMap --yes +""" + +helps['changesafety stagemap list'] = """ + type: command + short-summary: List StageMap resources in a subscription. + examples: + - name: List all StageMaps in the subscription + text: |- + az changesafety stagemap list --subscription 00000000-0000-0000-0000-000000000000 +""" diff --git a/src/azure-changesafety/azext_changesafety/_params.py b/src/azure-changesafety/azext_changesafety/_params.py new file mode 100644 index 00000000000..cfcec717c9c --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/_params.py @@ -0,0 +1,13 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: disable=too-many-lines +# pylint: disable=too-many-statements + + +def load_arguments(self, _): # pylint: disable=unused-argument + pass diff --git a/src/azure-changesafety/azext_changesafety/aaz/__init__.py b/src/azure-changesafety/azext_changesafety/aaz/__init__.py new file mode 100644 index 00000000000..5757aea3175 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/__init__.py b/src/azure-changesafety/azext_changesafety/aaz/latest/__init__.py new file mode 100644 index 00000000000..f6acc11aa4e --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/__init__.py @@ -0,0 +1,10 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/__cmd_group.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/__cmd_group.py new file mode 100644 index 00000000000..e989d427e63 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/__cmd_group.py @@ -0,0 +1,23 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command_group( + "changesafety", +) +class __CMDGroup(AAZCommandGroup): + """Manage Changesafety + """ + pass + + +__all__ = ["__CMDGroup"] diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/__init__.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/__init__.py new file mode 100644 index 00000000000..5a9d61963d6 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/__init__.py @@ -0,0 +1,11 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from .__cmd_group import * diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/__cmd_group.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/__cmd_group.py new file mode 100644 index 00000000000..31dc53638cc --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/__cmd_group.py @@ -0,0 +1,23 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command_group( + "changesafety changerecord", +) +class __CMDGroup(AAZCommandGroup): + """Manage Change Record + """ + pass + + +__all__ = ["__CMDGroup"] diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/__init__.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/__init__.py new file mode 100644 index 00000000000..c401f439385 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/__init__.py @@ -0,0 +1,16 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from .__cmd_group import * +from ._create import * +from ._delete import * +from ._list import * +from ._show import * +from ._update import * diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/_create.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/_create.py new file mode 100644 index 00000000000..d3785d855fe --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/_create.py @@ -0,0 +1,1068 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "changesafety changerecord create", +) +class Create(AAZCommand): + """Create a ChangeRecord + """ + + _aaz_info = { + "version": "2026-01-01-preview", + "resources": [ + ["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/changerecords/{}", "2026-01-01-preview"], + ["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.changesafety/changerecords/{}", "2026-01-01-preview"], + ] + } + + def _handler(self, command_args): + super()._handler(command_args) + self._execute_operations() + return self._output() + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.change_record_name = AAZStrArg( + options=["-n", "--name", "--change-record-name"], + help="The name of the ChangeRecord resource.", + required=True, + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-]{3,100}$", + max_length=100, + min_length=3, + ), + ) + _args_schema.resource_group = AAZResourceGroupNameArg() + + # define Arg Group "Properties" + + _args_schema = cls._args_schema + _args_schema.additional_data = AAZObjectArg( + options=["--additional-data"], + arg_group="Properties", + help="Additional metadata for the change required for various orchestration tools.", + blank={}, + ) + _args_schema.anticipated_end_time = AAZDateTimeArg( + options=["--anticipated-end-time"], + arg_group="Properties", + help="Expected completion time when the change should be finished, in ISO 8601 format.", + fmt=AAZDateTimeFormat( + protocol="iso", + ), + ) + _args_schema.anticipated_start_time = AAZDateTimeArg( + options=["--anticipated-start-time"], + arg_group="Properties", + help="Expected start time when the change execution should begin, in ISO 8601 format.", + fmt=AAZDateTimeFormat( + protocol="iso", + ), + ) + _args_schema.change_definition = AAZObjectArg( + options=["--change-definition"], + arg_group="Properties", + help="Change request body and/or resource selection criteria used to identify the targeted resources.", + ) + _args_schema.change_type = AAZStrArg( + options=["--change-type"], + arg_group="Properties", + help="Describes the nature of the change.", + enum={"AppDeployment": "AppDeployment", "Config": "Config", "ManualTouch": "ManualTouch", "PolicyDeployment": "PolicyDeployment"}, + ) + _args_schema.comments = AAZStrArg( + options=["--comments"], + arg_group="Properties", + help="Comments about the last update to the ChangeRecord resource.", + fmt=AAZStrArgFormat( + max_length=2000, + ), + ) + _args_schema.description = AAZStrArg( + options=["--description"], + arg_group="Properties", + help="Brief description about the change.", + fmt=AAZStrArgFormat( + max_length=2000, + ), + ) + _args_schema.links = AAZListArg( + options=["--links"], + arg_group="Properties", + help="Collection of related links for the change.", + ) + _args_schema.orchestration_tool = AAZStrArg( + options=["--orchestration-tool"], + arg_group="Properties", + help="Tool used for deployment orchestration of this change.", + ) + _args_schema.parameters = AAZDictArg( + options=["--parameters"], + arg_group="Properties", + help="Schema of parameters that will be provided for each stageProgression.", + ) + _args_schema.release_label = AAZStrArg( + options=["--release-label"], + arg_group="Properties", + help="Label for the release associated with this change.", + ) + _args_schema.rollout_type = AAZStrArg( + options=["--rollout-type"], + arg_group="Properties", + help="Describes the type of the rollout used for the change.", + enum={"Emergency": "Emergency", "Hotfix": "Hotfix", "Normal": "Normal"}, + ) + _args_schema.stage_map = AAZObjectArg( + options=["--stage-map"], + arg_group="Properties", + help="Reference to the StageMap, defining progression.", + ) + + change_definition = cls._args_schema.change_definition + change_definition.details = AAZObjectArg( + options=["details"], + help="Free form object containing additional details for the change definition.", + required=True, + blank={}, + ) + change_definition.kind = AAZStrArg( + options=["kind"], + help="Kind of the change definition.", + required=True, + enum={"ApiOperations": "ApiOperations", "Targets": "Targets"}, + ) + change_definition.name = AAZStrArg( + options=["name"], + help="Name of the change definition.", + required=True, + ) + + links = cls._args_schema.links + links.Element = AAZObjectArg() + + _element = cls._args_schema.links.Element + _element.description = AAZStrArg( + options=["description"], + help="Description or note about the link.", + fmt=AAZStrArgFormat( + max_length=2000, + ), + ) + _element.name = AAZStrArg( + options=["name"], + help="name of the link.", + required=True, + ) + _element.uri = AAZStrArg( + options=["uri"], + help="URL or comma separated URLs for the link.", + required=True, + ) + + parameters = cls._args_schema.parameters + parameters.Element = AAZObjectArg() + + _element = cls._args_schema.parameters.Element + _element.array = AAZObjectArg( + options=["array"], + ) + _element.metadata = AAZDictArg( + options=["metadata"], + help="user-specified parameter metadata", + ) + _element.number = AAZObjectArg( + options=["number"], + ) + _element.object = AAZObjectArg( + options=["object"], + ) + _element.string = AAZObjectArg( + options=["string"], + ) + + array = cls._args_schema.parameters.Element.array + array.allowed_values = AAZListArg( + options=["allowed-values"], + help="Allowed list of the values for the parameter.", + ) + array.default_value = AAZListArg( + options=["default-value"], + help="Default value for the parameter.", + ) + + allowed_values = cls._args_schema.parameters.Element.array.allowed_values + allowed_values.Element = AAZAnyTypeArg() + + default_value = cls._args_schema.parameters.Element.array.default_value + default_value.Element = AAZAnyTypeArg() + + metadata = cls._args_schema.parameters.Element.metadata + metadata.Element = AAZStrArg() + + number = cls._args_schema.parameters.Element.number + number.allowed_values = AAZListArg( + options=["allowed-values"], + help="Allowed list of the values for the parameter.", + ) + number.default_value = AAZIntArg( + options=["default-value"], + help="Default value for the parameter.", + ) + + allowed_values = cls._args_schema.parameters.Element.number.allowed_values + allowed_values.Element = AAZIntArg() + + object = cls._args_schema.parameters.Element.object + object.allowed_values = AAZListArg( + options=["allowed-values"], + help="Allowed list of the values for the parameter.", + ) + object.default_value = AAZObjectArg( + options=["default-value"], + help="Default value for the parameter.", + blank={}, + ) + + allowed_values = cls._args_schema.parameters.Element.object.allowed_values + allowed_values.Element = AAZDictArg() + + _element = cls._args_schema.parameters.Element.object.allowed_values.Element + _element.Element = AAZAnyTypeArg() + + string = cls._args_schema.parameters.Element.string + string.allowed_values = AAZListArg( + options=["allowed-values"], + help="Allowed list of the values for the parameter.", + ) + string.default_value = AAZStrArg( + options=["default-value"], + help="Default value for the parameter.", + ) + + allowed_values = cls._args_schema.parameters.Element.string.allowed_values + allowed_values.Element = AAZStrArg() + + stage_map = cls._args_schema.stage_map + stage_map.parameters = AAZDictArg( + options=["parameters"], + help="Key value pairs of parameter names & their values for the stageMap referenced by the resourceId field.", + ) + stage_map.resource_id = AAZStrArg( + options=["resource-id"], + help="ARM resource ID for the nested stagemap resource.", + ) + + parameters = cls._args_schema.stage_map.parameters + parameters.Element = AAZAnyTypeArg() + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + condition_0 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.subscription_id) and has_value(self.ctx.args.resource_group) is not True + condition_1 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.args.resource_group) and has_value(self.ctx.subscription_id) + if condition_0: + self.ChangeRecordsCreateOrUpdateAtSubscriptionLevel(ctx=self.ctx)() + if condition_1: + self.ChangeRecordsCreateOrUpdate(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + def _output(self, *args, **kwargs): + result = self.deserialize_output(self.ctx.vars.instance, client_flatten=True) + return result + + class ChangeRecordsCreateOrUpdateAtSubscriptionLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200, 201]: + return self.on_200_201(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}", + **self.url_parameters + ) + + @property + def method(self): + return "PUT" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Content-Type", "application/json", + ), + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + @property + def content(self): + _content_value, _builder = self.new_content_builder( + self.ctx.args, + typ=AAZObjectType, + typ_kwargs={"flags": {"required": True, "client_flatten": True}} + ) + _builder.set_prop("properties", AAZObjectType) + + properties = _builder.get(".properties") + if properties is not None: + properties.set_prop("additionalData", AAZObjectType, ".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}}) + properties.set_prop("changeType", AAZStrType, ".change_type", typ_kwargs={"flags": {"required": True}}) + properties.set_prop("comments", AAZStrType, ".comments") + properties.set_prop("description", AAZStrType, ".description") + properties.set_prop("links", AAZListType, ".links") + properties.set_prop("orchestrationTool", AAZStrType, ".orchestration_tool") + properties.set_prop("parameters", AAZDictType, ".parameters") + properties.set_prop("releaseLabel", AAZStrType, ".release_label") + properties.set_prop("rolloutType", AAZStrType, ".rollout_type", typ_kwargs={"flags": {"required": True}}) + properties.set_prop("stageMap", AAZObjectType, ".stage_map") + + 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("kind", AAZStrType, ".kind", typ_kwargs={"flags": {"required": True}}) + change_definition.set_prop("name", AAZStrType, ".name", typ_kwargs={"flags": {"required": True}}) + + links = _builder.get(".properties.links") + if links is not None: + links.set_elements(AAZObjectType, ".") + + _elements = _builder.get(".properties.links[]") + if _elements is not None: + _elements.set_prop("description", AAZStrType, ".description") + _elements.set_prop("name", AAZStrType, ".name", typ_kwargs={"flags": {"required": True}}) + _elements.set_prop("uri", AAZStrType, ".uri", typ_kwargs={"flags": {"required": True}}) + + parameters = _builder.get(".properties.parameters") + if parameters is not None: + parameters.set_elements(AAZObjectType, ".") + + _elements = _builder.get(".properties.parameters{}") + if _elements is not None: + _elements.set_prop("metadata", AAZDictType, ".metadata") + _elements.set_const("type", "array", AAZStrType, ".array", typ_kwargs={"flags": {"required": True}}) + _elements.set_const("type", "number", AAZStrType, ".number", typ_kwargs={"flags": {"required": True}}) + _elements.set_const("type", "object", AAZStrType, ".object", typ_kwargs={"flags": {"required": True}}) + _elements.set_const("type", "string", AAZStrType, ".string", typ_kwargs={"flags": {"required": True}}) + _elements.discriminate_by("type", "array") + _elements.discriminate_by("type", "number") + _elements.discriminate_by("type", "object") + _elements.discriminate_by("type", "string") + + metadata = _builder.get(".properties.parameters{}.metadata") + if metadata is not None: + metadata.set_elements(AAZStrType, ".") + + disc_array = _builder.get(".properties.parameters{}{type:array}") + if disc_array is not None: + disc_array.set_prop("allowedValues", AAZListType, ".array.allowed_values") + disc_array.set_prop("defaultValue", AAZListType, ".array.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:array}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZAnyType, ".") + + default_value = _builder.get(".properties.parameters{}{type:array}.defaultValue") + if default_value is not None: + default_value.set_elements(AAZAnyType, ".") + + disc_number = _builder.get(".properties.parameters{}{type:number}") + if disc_number is not None: + disc_number.set_prop("allowedValues", AAZListType, ".number.allowed_values") + disc_number.set_prop("defaultValue", AAZIntType, ".number.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:number}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZIntType, ".") + + disc_object = _builder.get(".properties.parameters{}{type:object}") + if disc_object is not None: + disc_object.set_prop("allowedValues", AAZListType, ".object.allowed_values") + disc_object.set_prop("defaultValue", AAZObjectType, ".object.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:object}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZDictType, ".") + + _elements = _builder.get(".properties.parameters{}{type:object}.allowedValues[]") + if _elements is not None: + _elements.set_elements(AAZAnyType, ".") + + disc_string = _builder.get(".properties.parameters{}{type:string}") + if disc_string is not None: + disc_string.set_prop("allowedValues", AAZListType, ".string.allowed_values") + disc_string.set_prop("defaultValue", AAZStrType, ".string.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:string}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZStrType, ".") + + stage_map = _builder.get(".properties.stageMap") + if stage_map is not None: + stage_map.set_prop("parameters", AAZDictType, ".parameters") + stage_map.set_prop("resourceId", AAZStrType, ".resource_id") + + parameters = _builder.get(".properties.stageMap.parameters") + if parameters is not None: + parameters.set_elements(AAZAnyType, ".") + + return self.serialize_content(_content_value) + + def on_200_201(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200_201 + ) + + _schema_on_200_201 = None + + @classmethod + def _build_schema_on_200_201(cls): + if cls._schema_on_200_201 is not None: + return cls._schema_on_200_201 + + cls._schema_on_200_201 = AAZObjectType() + + _schema_on_200_201 = cls._schema_on_200_201 + _schema_on_200_201.id = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200_201.name = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200_201.properties = AAZObjectType() + _schema_on_200_201.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _schema_on_200_201.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200_201.properties + properties.additional_data = AAZObjectType( + serialized_name="additionalData", + ) + properties.anticipated_end_time = AAZStrType( + serialized_name="anticipatedEndTime", + flags={"required": True}, + ) + properties.anticipated_start_time = AAZStrType( + serialized_name="anticipatedStartTime", + flags={"required": True}, + ) + properties.change_definition = AAZObjectType( + serialized_name="changeDefinition", + flags={"required": True}, + ) + properties.change_type = AAZStrType( + serialized_name="changeType", + flags={"required": True}, + ) + properties.comments = AAZStrType() + properties.description = AAZStrType() + properties.links = AAZListType() + properties.orchestration_tool = AAZStrType( + serialized_name="orchestrationTool", + ) + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.release_label = AAZStrType( + serialized_name="releaseLabel", + ) + properties.rollout_type = AAZStrType( + serialized_name="rolloutType", + flags={"required": True}, + ) + properties.stage_map = AAZObjectType( + serialized_name="stageMap", + ) + properties.stage_map_snapshot = AAZListType( + serialized_name="stageMapSnapshot", + flags={"read_only": True}, + ) + properties.status = AAZStrType( + flags={"read_only": True}, + ) + + change_definition = cls._schema_on_200_201.properties.change_definition + change_definition.details = AAZObjectType( + flags={"required": True}, + ) + change_definition.kind = AAZStrType( + flags={"required": True}, + ) + change_definition.name = AAZStrType( + flags={"required": True}, + ) + + links = cls._schema_on_200_201.properties.links + links.Element = AAZObjectType() + + _element = cls._schema_on_200_201.properties.links.Element + _element.description = AAZStrType() + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.uri = AAZStrType( + flags={"required": True}, + ) + + parameters = cls._schema_on_200_201.properties.parameters + parameters.Element = AAZObjectType() + + _element = cls._schema_on_200_201.properties.parameters.Element + _element.metadata = AAZDictType() + _element.type = AAZStrType( + flags={"required": True}, + ) + + metadata = cls._schema_on_200_201.properties.parameters.Element.metadata + metadata.Element = AAZStrType() + + disc_array = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "array") + disc_array.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_array.default_value = AAZListType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "array").allowed_values + allowed_values.Element = AAZAnyType() + + default_value = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "array").default_value + default_value.Element = AAZAnyType() + + disc_number = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "number") + disc_number.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_number.default_value = AAZIntType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "number").allowed_values + allowed_values.Element = AAZIntType() + + disc_object = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "object") + disc_object.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_object.default_value = AAZObjectType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "object").allowed_values + allowed_values.Element = AAZDictType() + + _element = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "object").allowed_values.Element + _element.Element = AAZAnyType() + + disc_string = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "string") + disc_string.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_string.default_value = AAZStrType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "string").allowed_values + allowed_values.Element = AAZStrType() + + stage_map = cls._schema_on_200_201.properties.stage_map + stage_map.parameters = AAZDictType() + stage_map.resource_id = AAZStrType( + serialized_name="resourceId", + ) + + parameters = cls._schema_on_200_201.properties.stage_map.parameters + parameters.Element = AAZAnyType() + + stage_map_snapshot = cls._schema_on_200_201.properties.stage_map_snapshot + stage_map_snapshot.Element = AAZAnyType() + + system_data = cls._schema_on_200_201.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200_201 + + class ChangeRecordsCreateOrUpdate(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200, 201]: + return self.on_200_201(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}", + **self.url_parameters + ) + + @property + def method(self): + return "PUT" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "resourceGroupName", self.ctx.args.resource_group, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Content-Type", "application/json", + ), + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + @property + def content(self): + _content_value, _builder = self.new_content_builder( + self.ctx.args, + typ=AAZObjectType, + typ_kwargs={"flags": {"required": True, "client_flatten": True}} + ) + _builder.set_prop("properties", AAZObjectType) + + properties = _builder.get(".properties") + if properties is not None: + properties.set_prop("additionalData", AAZObjectType, ".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}}) + properties.set_prop("changeType", AAZStrType, ".change_type", typ_kwargs={"flags": {"required": True}}) + properties.set_prop("comments", AAZStrType, ".comments") + properties.set_prop("description", AAZStrType, ".description") + properties.set_prop("links", AAZListType, ".links") + properties.set_prop("orchestrationTool", AAZStrType, ".orchestration_tool") + properties.set_prop("parameters", AAZDictType, ".parameters") + properties.set_prop("releaseLabel", AAZStrType, ".release_label") + properties.set_prop("rolloutType", AAZStrType, ".rollout_type", typ_kwargs={"flags": {"required": True}}) + properties.set_prop("stageMap", AAZObjectType, ".stage_map") + + 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("kind", AAZStrType, ".kind", typ_kwargs={"flags": {"required": True}}) + change_definition.set_prop("name", AAZStrType, ".name", typ_kwargs={"flags": {"required": True}}) + + links = _builder.get(".properties.links") + if links is not None: + links.set_elements(AAZObjectType, ".") + + _elements = _builder.get(".properties.links[]") + if _elements is not None: + _elements.set_prop("description", AAZStrType, ".description") + _elements.set_prop("name", AAZStrType, ".name", typ_kwargs={"flags": {"required": True}}) + _elements.set_prop("uri", AAZStrType, ".uri", typ_kwargs={"flags": {"required": True}}) + + parameters = _builder.get(".properties.parameters") + if parameters is not None: + parameters.set_elements(AAZObjectType, ".") + + _elements = _builder.get(".properties.parameters{}") + if _elements is not None: + _elements.set_prop("metadata", AAZDictType, ".metadata") + _elements.set_const("type", "array", AAZStrType, ".array", typ_kwargs={"flags": {"required": True}}) + _elements.set_const("type", "number", AAZStrType, ".number", typ_kwargs={"flags": {"required": True}}) + _elements.set_const("type", "object", AAZStrType, ".object", typ_kwargs={"flags": {"required": True}}) + _elements.set_const("type", "string", AAZStrType, ".string", typ_kwargs={"flags": {"required": True}}) + _elements.discriminate_by("type", "array") + _elements.discriminate_by("type", "number") + _elements.discriminate_by("type", "object") + _elements.discriminate_by("type", "string") + + metadata = _builder.get(".properties.parameters{}.metadata") + if metadata is not None: + metadata.set_elements(AAZStrType, ".") + + disc_array = _builder.get(".properties.parameters{}{type:array}") + if disc_array is not None: + disc_array.set_prop("allowedValues", AAZListType, ".array.allowed_values") + disc_array.set_prop("defaultValue", AAZListType, ".array.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:array}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZAnyType, ".") + + default_value = _builder.get(".properties.parameters{}{type:array}.defaultValue") + if default_value is not None: + default_value.set_elements(AAZAnyType, ".") + + disc_number = _builder.get(".properties.parameters{}{type:number}") + if disc_number is not None: + disc_number.set_prop("allowedValues", AAZListType, ".number.allowed_values") + disc_number.set_prop("defaultValue", AAZIntType, ".number.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:number}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZIntType, ".") + + disc_object = _builder.get(".properties.parameters{}{type:object}") + if disc_object is not None: + disc_object.set_prop("allowedValues", AAZListType, ".object.allowed_values") + disc_object.set_prop("defaultValue", AAZObjectType, ".object.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:object}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZDictType, ".") + + _elements = _builder.get(".properties.parameters{}{type:object}.allowedValues[]") + if _elements is not None: + _elements.set_elements(AAZAnyType, ".") + + disc_string = _builder.get(".properties.parameters{}{type:string}") + if disc_string is not None: + disc_string.set_prop("allowedValues", AAZListType, ".string.allowed_values") + disc_string.set_prop("defaultValue", AAZStrType, ".string.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:string}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZStrType, ".") + + stage_map = _builder.get(".properties.stageMap") + if stage_map is not None: + stage_map.set_prop("parameters", AAZDictType, ".parameters") + stage_map.set_prop("resourceId", AAZStrType, ".resource_id") + + parameters = _builder.get(".properties.stageMap.parameters") + if parameters is not None: + parameters.set_elements(AAZAnyType, ".") + + return self.serialize_content(_content_value) + + def on_200_201(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200_201 + ) + + _schema_on_200_201 = None + + @classmethod + def _build_schema_on_200_201(cls): + if cls._schema_on_200_201 is not None: + return cls._schema_on_200_201 + + cls._schema_on_200_201 = AAZObjectType() + + _schema_on_200_201 = cls._schema_on_200_201 + _schema_on_200_201.id = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200_201.name = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200_201.properties = AAZObjectType() + _schema_on_200_201.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _schema_on_200_201.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200_201.properties + properties.additional_data = AAZObjectType( + serialized_name="additionalData", + ) + properties.anticipated_end_time = AAZStrType( + serialized_name="anticipatedEndTime", + flags={"required": True}, + ) + properties.anticipated_start_time = AAZStrType( + serialized_name="anticipatedStartTime", + flags={"required": True}, + ) + properties.change_definition = AAZObjectType( + serialized_name="changeDefinition", + flags={"required": True}, + ) + properties.change_type = AAZStrType( + serialized_name="changeType", + flags={"required": True}, + ) + properties.comments = AAZStrType() + properties.description = AAZStrType() + properties.links = AAZListType() + properties.orchestration_tool = AAZStrType( + serialized_name="orchestrationTool", + ) + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.release_label = AAZStrType( + serialized_name="releaseLabel", + ) + properties.rollout_type = AAZStrType( + serialized_name="rolloutType", + flags={"required": True}, + ) + properties.stage_map = AAZObjectType( + serialized_name="stageMap", + ) + properties.stage_map_snapshot = AAZListType( + serialized_name="stageMapSnapshot", + flags={"read_only": True}, + ) + properties.status = AAZStrType( + flags={"read_only": True}, + ) + + change_definition = cls._schema_on_200_201.properties.change_definition + change_definition.details = AAZObjectType( + flags={"required": True}, + ) + change_definition.kind = AAZStrType( + flags={"required": True}, + ) + change_definition.name = AAZStrType( + flags={"required": True}, + ) + + links = cls._schema_on_200_201.properties.links + links.Element = AAZObjectType() + + _element = cls._schema_on_200_201.properties.links.Element + _element.description = AAZStrType() + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.uri = AAZStrType( + flags={"required": True}, + ) + + parameters = cls._schema_on_200_201.properties.parameters + parameters.Element = AAZObjectType() + + _element = cls._schema_on_200_201.properties.parameters.Element + _element.metadata = AAZDictType() + _element.type = AAZStrType( + flags={"required": True}, + ) + + metadata = cls._schema_on_200_201.properties.parameters.Element.metadata + metadata.Element = AAZStrType() + + disc_array = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "array") + disc_array.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_array.default_value = AAZListType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "array").allowed_values + allowed_values.Element = AAZAnyType() + + default_value = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "array").default_value + default_value.Element = AAZAnyType() + + disc_number = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "number") + disc_number.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_number.default_value = AAZIntType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "number").allowed_values + allowed_values.Element = AAZIntType() + + disc_object = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "object") + disc_object.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_object.default_value = AAZObjectType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "object").allowed_values + allowed_values.Element = AAZDictType() + + _element = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "object").allowed_values.Element + _element.Element = AAZAnyType() + + disc_string = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "string") + disc_string.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_string.default_value = AAZStrType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "string").allowed_values + allowed_values.Element = AAZStrType() + + stage_map = cls._schema_on_200_201.properties.stage_map + stage_map.parameters = AAZDictType() + stage_map.resource_id = AAZStrType( + serialized_name="resourceId", + ) + + parameters = cls._schema_on_200_201.properties.stage_map.parameters + parameters.Element = AAZAnyType() + + stage_map_snapshot = cls._schema_on_200_201.properties.stage_map_snapshot + stage_map_snapshot.Element = AAZAnyType() + + system_data = cls._schema_on_200_201.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200_201 + + +class _CreateHelper: + """Helper class for Create""" + + +__all__ = ["Create"] diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/_delete.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/_delete.py new file mode 100644 index 00000000000..93c9535ae7a --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/_delete.py @@ -0,0 +1,248 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "changesafety changerecord delete", + confirmation="Are you sure you want to perform this operation?", +) +class Delete(AAZCommand): + """Delete a ChangeRecord + """ + + _aaz_info = { + "version": "2026-01-01-preview", + "resources": [ + ["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/changerecords/{}", "2026-01-01-preview"], + ["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.changesafety/changerecords/{}", "2026-01-01-preview"], + ] + } + + def _handler(self, command_args): + super()._handler(command_args) + return self.build_lro_poller(self._execute_operations, None) + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.change_record_name = AAZStrArg( + options=["-n", "--name", "--change-record-name"], + help="The name of the ChangeRecord resource.", + required=True, + id_part="name", + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-]{3,100}$", + max_length=100, + min_length=3, + ), + ) + _args_schema.resource_group = AAZResourceGroupNameArg() + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + condition_0 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.subscription_id) and has_value(self.ctx.args.resource_group) is not True + condition_1 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.args.resource_group) and has_value(self.ctx.subscription_id) + if condition_0: + yield self.ChangeRecordsDeleteAtSubscriptionLevel(ctx=self.ctx)() + if condition_1: + yield self.ChangeRecordsDelete(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + class ChangeRecordsDeleteAtSubscriptionLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [202]: + return self.client.build_lro_polling( + False, + session, + self.on_200_201, + self.on_error, + lro_options={"final-state-via": "location"}, + path_format_arguments=self.url_parameters, + ) + if session.http_response.status_code in [204]: + return self.client.build_lro_polling( + False, + session, + self.on_204, + self.on_error, + lro_options={"final-state-via": "location"}, + path_format_arguments=self.url_parameters, + ) + if session.http_response.status_code in [200, 201]: + return self.client.build_lro_polling( + False, + session, + self.on_200_201, + self.on_error, + lro_options={"final-state-via": "location"}, + path_format_arguments=self.url_parameters, + ) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}", + **self.url_parameters + ) + + @property + def method(self): + return "DELETE" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + def on_204(self, session): + pass + + def on_200_201(self, session): + pass + + class ChangeRecordsDelete(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [202]: + return self.client.build_lro_polling( + False, + session, + self.on_200_201, + self.on_error, + lro_options={"final-state-via": "location"}, + path_format_arguments=self.url_parameters, + ) + if session.http_response.status_code in [204]: + return self.client.build_lro_polling( + False, + session, + self.on_204, + self.on_error, + lro_options={"final-state-via": "location"}, + path_format_arguments=self.url_parameters, + ) + if session.http_response.status_code in [200, 201]: + return self.client.build_lro_polling( + False, + session, + self.on_200_201, + self.on_error, + lro_options={"final-state-via": "location"}, + path_format_arguments=self.url_parameters, + ) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}", + **self.url_parameters + ) + + @property + def method(self): + return "DELETE" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "resourceGroupName", self.ctx.args.resource_group, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + def on_204(self, session): + pass + + def on_200_201(self, session): + pass + + +class _DeleteHelper: + """Helper class for Delete""" + + +__all__ = ["Delete"] diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/_list.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/_list.py new file mode 100644 index 00000000000..b9ee25f4a83 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/_list.py @@ -0,0 +1,615 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "changesafety changerecord list", +) +class List(AAZCommand): + """List ChangeRecord resources by subscription ID + """ + + _aaz_info = { + "version": "2026-01-01-preview", + "resources": [ + ["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/changerecords", "2026-01-01-preview"], + ["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.changesafety/changerecords", "2026-01-01-preview"], + ] + } + + AZ_SUPPORT_PAGINATION = True + + def _handler(self, command_args): + super()._handler(command_args) + return self.build_paging(self._execute_operations, self._output) + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.resource_group = AAZResourceGroupNameArg() + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + condition_0 = has_value(self.ctx.subscription_id) and has_value(self.ctx.args.resource_group) is not True + condition_1 = has_value(self.ctx.args.resource_group) and has_value(self.ctx.subscription_id) + if condition_0: + self.ChangeRecordsListBySubscription(ctx=self.ctx)() + if condition_1: + self.ChangeRecordsListByResourceGroup(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + def _output(self, *args, **kwargs): + result = self.deserialize_output(self.ctx.vars.instance.value, client_flatten=True) + next_link = self.deserialize_output(self.ctx.vars.instance.next_link) + return result, next_link + + class ChangeRecordsListBySubscription(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/changeRecords", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + + _schema_on_200 = cls._schema_on_200 + _schema_on_200.next_link = AAZStrType( + serialized_name="nextLink", + ) + _schema_on_200.value = AAZListType( + flags={"required": True}, + ) + + value = cls._schema_on_200.value + value.Element = AAZObjectType() + + _element = cls._schema_on_200.value.Element + _element.id = AAZStrType( + flags={"read_only": True}, + ) + _element.name = AAZStrType( + flags={"read_only": True}, + ) + _element.properties = AAZObjectType() + _element.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _element.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200.value.Element.properties + properties.additional_data = AAZObjectType( + serialized_name="additionalData", + ) + properties.anticipated_end_time = AAZStrType( + serialized_name="anticipatedEndTime", + flags={"required": True}, + ) + properties.anticipated_start_time = AAZStrType( + serialized_name="anticipatedStartTime", + flags={"required": True}, + ) + properties.change_definition = AAZObjectType( + serialized_name="changeDefinition", + flags={"required": True}, + ) + properties.change_type = AAZStrType( + serialized_name="changeType", + flags={"required": True}, + ) + properties.comments = AAZStrType() + properties.description = AAZStrType() + properties.links = AAZListType() + properties.orchestration_tool = AAZStrType( + serialized_name="orchestrationTool", + ) + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.release_label = AAZStrType( + serialized_name="releaseLabel", + ) + properties.rollout_type = AAZStrType( + serialized_name="rolloutType", + flags={"required": True}, + ) + properties.stage_map = AAZObjectType( + serialized_name="stageMap", + ) + properties.stage_map_snapshot = AAZListType( + serialized_name="stageMapSnapshot", + flags={"read_only": True}, + ) + properties.status = AAZStrType( + flags={"read_only": True}, + ) + + change_definition = cls._schema_on_200.value.Element.properties.change_definition + change_definition.details = AAZObjectType( + flags={"required": True}, + ) + change_definition.kind = AAZStrType( + flags={"required": True}, + ) + change_definition.name = AAZStrType( + flags={"required": True}, + ) + + links = cls._schema_on_200.value.Element.properties.links + links.Element = AAZObjectType() + + _element = cls._schema_on_200.value.Element.properties.links.Element + _element.description = AAZStrType() + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.uri = AAZStrType( + flags={"required": True}, + ) + + parameters = cls._schema_on_200.value.Element.properties.parameters + parameters.Element = AAZObjectType() + + _element = cls._schema_on_200.value.Element.properties.parameters.Element + _element.metadata = AAZDictType() + _element.type = AAZStrType( + flags={"required": True}, + ) + + metadata = cls._schema_on_200.value.Element.properties.parameters.Element.metadata + metadata.Element = AAZStrType() + + disc_array = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "array") + disc_array.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_array.default_value = AAZListType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "array").allowed_values + allowed_values.Element = AAZAnyType() + + default_value = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "array").default_value + default_value.Element = AAZAnyType() + + disc_number = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "number") + disc_number.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_number.default_value = AAZIntType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "number").allowed_values + allowed_values.Element = AAZIntType() + + disc_object = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "object") + disc_object.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_object.default_value = AAZObjectType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "object").allowed_values + allowed_values.Element = AAZDictType() + + _element = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "object").allowed_values.Element + _element.Element = AAZAnyType() + + disc_string = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "string") + disc_string.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_string.default_value = AAZStrType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "string").allowed_values + allowed_values.Element = AAZStrType() + + stage_map = cls._schema_on_200.value.Element.properties.stage_map + stage_map.parameters = AAZDictType() + stage_map.resource_id = AAZStrType( + serialized_name="resourceId", + ) + + parameters = cls._schema_on_200.value.Element.properties.stage_map.parameters + parameters.Element = AAZAnyType() + + stage_map_snapshot = cls._schema_on_200.value.Element.properties.stage_map_snapshot + stage_map_snapshot.Element = AAZAnyType() + + system_data = cls._schema_on_200.value.Element.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200 + + class ChangeRecordsListByResourceGroup(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ChangeSafety/changeRecords", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "resourceGroupName", self.ctx.args.resource_group, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + + _schema_on_200 = cls._schema_on_200 + _schema_on_200.next_link = AAZStrType( + serialized_name="nextLink", + ) + _schema_on_200.value = AAZListType( + flags={"required": True}, + ) + + value = cls._schema_on_200.value + value.Element = AAZObjectType() + + _element = cls._schema_on_200.value.Element + _element.id = AAZStrType( + flags={"read_only": True}, + ) + _element.name = AAZStrType( + flags={"read_only": True}, + ) + _element.properties = AAZObjectType() + _element.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _element.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200.value.Element.properties + properties.additional_data = AAZObjectType( + serialized_name="additionalData", + ) + properties.anticipated_end_time = AAZStrType( + serialized_name="anticipatedEndTime", + flags={"required": True}, + ) + properties.anticipated_start_time = AAZStrType( + serialized_name="anticipatedStartTime", + flags={"required": True}, + ) + properties.change_definition = AAZObjectType( + serialized_name="changeDefinition", + flags={"required": True}, + ) + properties.change_type = AAZStrType( + serialized_name="changeType", + flags={"required": True}, + ) + properties.comments = AAZStrType() + properties.description = AAZStrType() + properties.links = AAZListType() + properties.orchestration_tool = AAZStrType( + serialized_name="orchestrationTool", + ) + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.release_label = AAZStrType( + serialized_name="releaseLabel", + ) + properties.rollout_type = AAZStrType( + serialized_name="rolloutType", + flags={"required": True}, + ) + properties.stage_map = AAZObjectType( + serialized_name="stageMap", + ) + properties.stage_map_snapshot = AAZListType( + serialized_name="stageMapSnapshot", + flags={"read_only": True}, + ) + properties.status = AAZStrType( + flags={"read_only": True}, + ) + + change_definition = cls._schema_on_200.value.Element.properties.change_definition + change_definition.details = AAZObjectType( + flags={"required": True}, + ) + change_definition.kind = AAZStrType( + flags={"required": True}, + ) + change_definition.name = AAZStrType( + flags={"required": True}, + ) + + links = cls._schema_on_200.value.Element.properties.links + links.Element = AAZObjectType() + + _element = cls._schema_on_200.value.Element.properties.links.Element + _element.description = AAZStrType() + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.uri = AAZStrType( + flags={"required": True}, + ) + + parameters = cls._schema_on_200.value.Element.properties.parameters + parameters.Element = AAZObjectType() + + _element = cls._schema_on_200.value.Element.properties.parameters.Element + _element.metadata = AAZDictType() + _element.type = AAZStrType( + flags={"required": True}, + ) + + metadata = cls._schema_on_200.value.Element.properties.parameters.Element.metadata + metadata.Element = AAZStrType() + + disc_array = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "array") + disc_array.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_array.default_value = AAZListType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "array").allowed_values + allowed_values.Element = AAZAnyType() + + default_value = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "array").default_value + default_value.Element = AAZAnyType() + + disc_number = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "number") + disc_number.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_number.default_value = AAZIntType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "number").allowed_values + allowed_values.Element = AAZIntType() + + disc_object = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "object") + disc_object.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_object.default_value = AAZObjectType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "object").allowed_values + allowed_values.Element = AAZDictType() + + _element = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "object").allowed_values.Element + _element.Element = AAZAnyType() + + disc_string = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "string") + disc_string.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_string.default_value = AAZStrType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "string").allowed_values + allowed_values.Element = AAZStrType() + + stage_map = cls._schema_on_200.value.Element.properties.stage_map + stage_map.parameters = AAZDictType() + stage_map.resource_id = AAZStrType( + serialized_name="resourceId", + ) + + parameters = cls._schema_on_200.value.Element.properties.stage_map.parameters + parameters.Element = AAZAnyType() + + stage_map_snapshot = cls._schema_on_200.value.Element.properties.stage_map_snapshot + stage_map_snapshot.Element = AAZAnyType() + + system_data = cls._schema_on_200.value.Element.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200 + + +class _ListHelper: + """Helper class for List""" + + +__all__ = ["List"] diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/_show.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/_show.py new file mode 100644 index 00000000000..43e37cae04b --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/_show.py @@ -0,0 +1,610 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "changesafety changerecord show", +) +class Show(AAZCommand): + """Get a ChangeRecord + """ + + _aaz_info = { + "version": "2026-01-01-preview", + "resources": [ + ["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/changerecords/{}", "2026-01-01-preview"], + ["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.changesafety/changerecords/{}", "2026-01-01-preview"], + ] + } + + def _handler(self, command_args): + super()._handler(command_args) + self._execute_operations() + return self._output() + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.change_record_name = AAZStrArg( + options=["-n", "--name", "--change-record-name"], + help="The name of the ChangeRecord resource.", + required=True, + id_part="name", + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-]{3,100}$", + max_length=100, + min_length=3, + ), + ) + _args_schema.resource_group = AAZResourceGroupNameArg() + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + condition_0 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.subscription_id) and has_value(self.ctx.args.resource_group) is not True + condition_1 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.args.resource_group) and has_value(self.ctx.subscription_id) + if condition_0: + self.ChangeRecordsGetAtSubscriptionLevel(ctx=self.ctx)() + if condition_1: + self.ChangeRecordsGet(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + def _output(self, *args, **kwargs): + result = self.deserialize_output(self.ctx.vars.instance, client_flatten=True) + return result + + class ChangeRecordsGetAtSubscriptionLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + + _schema_on_200 = cls._schema_on_200 + _schema_on_200.id = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200.name = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200.properties = AAZObjectType() + _schema_on_200.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _schema_on_200.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200.properties + properties.additional_data = AAZObjectType( + serialized_name="additionalData", + ) + properties.anticipated_end_time = AAZStrType( + serialized_name="anticipatedEndTime", + flags={"required": True}, + ) + properties.anticipated_start_time = AAZStrType( + serialized_name="anticipatedStartTime", + flags={"required": True}, + ) + properties.change_definition = AAZObjectType( + serialized_name="changeDefinition", + flags={"required": True}, + ) + properties.change_type = AAZStrType( + serialized_name="changeType", + flags={"required": True}, + ) + properties.comments = AAZStrType() + properties.description = AAZStrType() + properties.links = AAZListType() + properties.orchestration_tool = AAZStrType( + serialized_name="orchestrationTool", + ) + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.release_label = AAZStrType( + serialized_name="releaseLabel", + ) + properties.rollout_type = AAZStrType( + serialized_name="rolloutType", + flags={"required": True}, + ) + properties.stage_map = AAZObjectType( + serialized_name="stageMap", + ) + properties.stage_map_snapshot = AAZListType( + serialized_name="stageMapSnapshot", + flags={"read_only": True}, + ) + properties.status = AAZStrType( + flags={"read_only": True}, + ) + + change_definition = cls._schema_on_200.properties.change_definition + change_definition.details = AAZObjectType( + flags={"required": True}, + ) + change_definition.kind = AAZStrType( + flags={"required": True}, + ) + change_definition.name = AAZStrType( + flags={"required": True}, + ) + + links = cls._schema_on_200.properties.links + links.Element = AAZObjectType() + + _element = cls._schema_on_200.properties.links.Element + _element.description = AAZStrType() + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.uri = AAZStrType( + flags={"required": True}, + ) + + parameters = cls._schema_on_200.properties.parameters + parameters.Element = AAZObjectType() + + _element = cls._schema_on_200.properties.parameters.Element + _element.metadata = AAZDictType() + _element.type = AAZStrType( + flags={"required": True}, + ) + + metadata = cls._schema_on_200.properties.parameters.Element.metadata + metadata.Element = AAZStrType() + + disc_array = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "array") + disc_array.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_array.default_value = AAZListType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "array").allowed_values + allowed_values.Element = AAZAnyType() + + default_value = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "array").default_value + default_value.Element = AAZAnyType() + + disc_number = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "number") + disc_number.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_number.default_value = AAZIntType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "number").allowed_values + allowed_values.Element = AAZIntType() + + disc_object = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "object") + disc_object.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_object.default_value = AAZObjectType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "object").allowed_values + allowed_values.Element = AAZDictType() + + _element = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "object").allowed_values.Element + _element.Element = AAZAnyType() + + disc_string = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "string") + disc_string.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_string.default_value = AAZStrType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "string").allowed_values + allowed_values.Element = AAZStrType() + + stage_map = cls._schema_on_200.properties.stage_map + stage_map.parameters = AAZDictType() + stage_map.resource_id = AAZStrType( + serialized_name="resourceId", + ) + + parameters = cls._schema_on_200.properties.stage_map.parameters + parameters.Element = AAZAnyType() + + stage_map_snapshot = cls._schema_on_200.properties.stage_map_snapshot + stage_map_snapshot.Element = AAZAnyType() + + system_data = cls._schema_on_200.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200 + + class ChangeRecordsGet(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "resourceGroupName", self.ctx.args.resource_group, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + + _schema_on_200 = cls._schema_on_200 + _schema_on_200.id = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200.name = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200.properties = AAZObjectType() + _schema_on_200.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _schema_on_200.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200.properties + properties.additional_data = AAZObjectType( + serialized_name="additionalData", + ) + properties.anticipated_end_time = AAZStrType( + serialized_name="anticipatedEndTime", + flags={"required": True}, + ) + properties.anticipated_start_time = AAZStrType( + serialized_name="anticipatedStartTime", + flags={"required": True}, + ) + properties.change_definition = AAZObjectType( + serialized_name="changeDefinition", + flags={"required": True}, + ) + properties.change_type = AAZStrType( + serialized_name="changeType", + flags={"required": True}, + ) + properties.comments = AAZStrType() + properties.description = AAZStrType() + properties.links = AAZListType() + properties.orchestration_tool = AAZStrType( + serialized_name="orchestrationTool", + ) + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.release_label = AAZStrType( + serialized_name="releaseLabel", + ) + properties.rollout_type = AAZStrType( + serialized_name="rolloutType", + flags={"required": True}, + ) + properties.stage_map = AAZObjectType( + serialized_name="stageMap", + ) + properties.stage_map_snapshot = AAZListType( + serialized_name="stageMapSnapshot", + flags={"read_only": True}, + ) + properties.status = AAZStrType( + flags={"read_only": True}, + ) + + change_definition = cls._schema_on_200.properties.change_definition + change_definition.details = AAZObjectType( + flags={"required": True}, + ) + change_definition.kind = AAZStrType( + flags={"required": True}, + ) + change_definition.name = AAZStrType( + flags={"required": True}, + ) + + links = cls._schema_on_200.properties.links + links.Element = AAZObjectType() + + _element = cls._schema_on_200.properties.links.Element + _element.description = AAZStrType() + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.uri = AAZStrType( + flags={"required": True}, + ) + + parameters = cls._schema_on_200.properties.parameters + parameters.Element = AAZObjectType() + + _element = cls._schema_on_200.properties.parameters.Element + _element.metadata = AAZDictType() + _element.type = AAZStrType( + flags={"required": True}, + ) + + metadata = cls._schema_on_200.properties.parameters.Element.metadata + metadata.Element = AAZStrType() + + disc_array = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "array") + disc_array.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_array.default_value = AAZListType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "array").allowed_values + allowed_values.Element = AAZAnyType() + + default_value = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "array").default_value + default_value.Element = AAZAnyType() + + disc_number = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "number") + disc_number.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_number.default_value = AAZIntType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "number").allowed_values + allowed_values.Element = AAZIntType() + + disc_object = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "object") + disc_object.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_object.default_value = AAZObjectType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "object").allowed_values + allowed_values.Element = AAZDictType() + + _element = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "object").allowed_values.Element + _element.Element = AAZAnyType() + + disc_string = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "string") + disc_string.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_string.default_value = AAZStrType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "string").allowed_values + allowed_values.Element = AAZStrType() + + stage_map = cls._schema_on_200.properties.stage_map + stage_map.parameters = AAZDictType() + stage_map.resource_id = AAZStrType( + serialized_name="resourceId", + ) + + parameters = cls._schema_on_200.properties.stage_map.parameters + parameters.Element = AAZAnyType() + + stage_map_snapshot = cls._schema_on_200.properties.stage_map_snapshot + stage_map_snapshot.Element = AAZAnyType() + + system_data = cls._schema_on_200.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200 + + +class _ShowHelper: + """Helper class for Show""" + + +__all__ = ["Show"] diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/_update.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/_update.py new file mode 100644 index 00000000000..33313c3191c --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/changerecord/_update.py @@ -0,0 +1,1040 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "changesafety changerecord update", +) +class Update(AAZCommand): + """Update a ChangeRecord + """ + + _aaz_info = { + "version": "2026-01-01-preview", + "resources": [ + ["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/changerecords/{}", "2026-01-01-preview"], + ["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.changesafety/changerecords/{}", "2026-01-01-preview"], + ] + } + + AZ_SUPPORT_GENERIC_UPDATE = True + + def _handler(self, command_args): + super()._handler(command_args) + self._execute_operations() + return self._output() + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.change_record_name = AAZStrArg( + options=["-n", "--name", "--change-record-name"], + help="The name of the ChangeRecord resource.", + required=True, + id_part="name", + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-]{3,100}$", + max_length=100, + min_length=3, + ), + ) + _args_schema.resource_group = AAZResourceGroupNameArg() + + # define Arg Group "Properties" + + _args_schema = cls._args_schema + _args_schema.additional_data = AAZObjectArg( + options=["--additional-data"], + arg_group="Properties", + help="Additional metadata for the change required for various orchestration tools.", + nullable=True, + blank={}, + ) + _args_schema.anticipated_end_time = AAZDateTimeArg( + options=["--anticipated-end-time"], + arg_group="Properties", + help="Expected completion time when the change should be finished, in ISO 8601 format.", + fmt=AAZDateTimeFormat( + protocol="iso", + ), + ) + _args_schema.anticipated_start_time = AAZDateTimeArg( + options=["--anticipated-start-time"], + arg_group="Properties", + help="Expected start time when the change execution should begin, in ISO 8601 format.", + fmt=AAZDateTimeFormat( + protocol="iso", + ), + ) + _args_schema.change_definition = AAZObjectArg( + options=["--change-definition"], + arg_group="Properties", + help="Change request body and/or resource selection criteria used to identify the targeted resources.", + ) + _args_schema.change_type = AAZStrArg( + options=["--change-type"], + arg_group="Properties", + help="Describes the nature of the change.", + enum={"AppDeployment": "AppDeployment", "Config": "Config", "ManualTouch": "ManualTouch", "PolicyDeployment": "PolicyDeployment"}, + ) + _args_schema.comments = AAZStrArg( + options=["--comments"], + arg_group="Properties", + help="Comments about the last update to the ChangeRecord resource.", + nullable=True, + fmt=AAZStrArgFormat( + max_length=2000, + ), + ) + _args_schema.description = AAZStrArg( + options=["--description"], + arg_group="Properties", + help="Brief description about the change.", + nullable=True, + fmt=AAZStrArgFormat( + max_length=2000, + ), + ) + _args_schema.links = AAZListArg( + options=["--links"], + arg_group="Properties", + help="Collection of related links for the change.", + nullable=True, + ) + _args_schema.orchestration_tool = AAZStrArg( + options=["--orchestration-tool"], + arg_group="Properties", + help="Tool used for deployment orchestration of this change.", + nullable=True, + ) + _args_schema.parameters = AAZDictArg( + options=["--parameters"], + arg_group="Properties", + help="Schema of parameters that will be provided for each stageProgression.", + nullable=True, + ) + _args_schema.release_label = AAZStrArg( + options=["--release-label"], + arg_group="Properties", + help="Label for the release associated with this change.", + nullable=True, + ) + _args_schema.rollout_type = AAZStrArg( + options=["--rollout-type"], + arg_group="Properties", + help="Describes the type of the rollout used for the change.", + enum={"Emergency": "Emergency", "Hotfix": "Hotfix", "Normal": "Normal"}, + ) + _args_schema.stage_map = AAZObjectArg( + options=["--stage-map"], + arg_group="Properties", + help="Reference to the StageMap, defining progression.", + nullable=True, + ) + + change_definition = cls._args_schema.change_definition + change_definition.details = AAZObjectArg( + options=["details"], + help="Free form object containing additional details for the change definition.", + blank={}, + ) + change_definition.kind = AAZStrArg( + options=["kind"], + help="Kind of the change definition.", + enum={"ApiOperations": "ApiOperations", "Targets": "Targets"}, + ) + change_definition.name = AAZStrArg( + options=["name"], + help="Name of the change definition.", + ) + + links = cls._args_schema.links + links.Element = AAZObjectArg( + nullable=True, + ) + + _element = cls._args_schema.links.Element + _element.description = AAZStrArg( + options=["description"], + help="Description or note about the link.", + nullable=True, + fmt=AAZStrArgFormat( + max_length=2000, + ), + ) + _element.name = AAZStrArg( + options=["name"], + help="name of the link.", + ) + _element.uri = AAZStrArg( + options=["uri"], + help="URL or comma separated URLs for the link.", + ) + + parameters = cls._args_schema.parameters + parameters.Element = AAZObjectArg( + nullable=True, + ) + + _element = cls._args_schema.parameters.Element + _element.array = AAZObjectArg( + options=["array"], + ) + _element.metadata = AAZDictArg( + options=["metadata"], + help="user-specified parameter metadata", + nullable=True, + ) + _element.number = AAZObjectArg( + options=["number"], + ) + _element.object = AAZObjectArg( + options=["object"], + ) + _element.string = AAZObjectArg( + options=["string"], + ) + + array = cls._args_schema.parameters.Element.array + array.allowed_values = AAZListArg( + options=["allowed-values"], + help="Allowed list of the values for the parameter.", + nullable=True, + ) + array.default_value = AAZListArg( + options=["default-value"], + help="Default value for the parameter.", + nullable=True, + ) + + allowed_values = cls._args_schema.parameters.Element.array.allowed_values + allowed_values.Element = AAZAnyTypeArg( + nullable=True, + ) + + default_value = cls._args_schema.parameters.Element.array.default_value + default_value.Element = AAZAnyTypeArg( + nullable=True, + ) + + metadata = cls._args_schema.parameters.Element.metadata + metadata.Element = AAZStrArg( + nullable=True, + ) + + number = cls._args_schema.parameters.Element.number + number.allowed_values = AAZListArg( + options=["allowed-values"], + help="Allowed list of the values for the parameter.", + nullable=True, + ) + number.default_value = AAZIntArg( + options=["default-value"], + help="Default value for the parameter.", + nullable=True, + ) + + allowed_values = cls._args_schema.parameters.Element.number.allowed_values + allowed_values.Element = AAZIntArg( + nullable=True, + ) + + object = cls._args_schema.parameters.Element.object + object.allowed_values = AAZListArg( + options=["allowed-values"], + help="Allowed list of the values for the parameter.", + nullable=True, + ) + object.default_value = AAZObjectArg( + options=["default-value"], + help="Default value for the parameter.", + nullable=True, + blank={}, + ) + + allowed_values = cls._args_schema.parameters.Element.object.allowed_values + allowed_values.Element = AAZDictArg( + nullable=True, + ) + + _element = cls._args_schema.parameters.Element.object.allowed_values.Element + _element.Element = AAZAnyTypeArg( + nullable=True, + ) + + string = cls._args_schema.parameters.Element.string + string.allowed_values = AAZListArg( + options=["allowed-values"], + help="Allowed list of the values for the parameter.", + nullable=True, + ) + string.default_value = AAZStrArg( + options=["default-value"], + help="Default value for the parameter.", + nullable=True, + ) + + allowed_values = cls._args_schema.parameters.Element.string.allowed_values + allowed_values.Element = AAZStrArg( + nullable=True, + ) + + stage_map = cls._args_schema.stage_map + stage_map.parameters = AAZDictArg( + options=["parameters"], + help="Key value pairs of parameter names & their values for the stageMap referenced by the resourceId field.", + nullable=True, + ) + stage_map.resource_id = AAZStrArg( + options=["resource-id"], + help="ARM resource ID for the nested stagemap resource.", + nullable=True, + ) + + parameters = cls._args_schema.stage_map.parameters + parameters.Element = AAZAnyTypeArg( + nullable=True, + ) + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + condition_0 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.subscription_id) and has_value(self.ctx.args.resource_group) is not True + condition_1 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.args.resource_group) and has_value(self.ctx.subscription_id) + condition_2 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.subscription_id) and has_value(self.ctx.args.resource_group) is not True + condition_3 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.args.resource_group) and has_value(self.ctx.subscription_id) + if condition_0: + self.ChangeRecordsGetAtSubscriptionLevel(ctx=self.ctx)() + if condition_1: + self.ChangeRecordsGet(ctx=self.ctx)() + self.pre_instance_update(self.ctx.vars.instance) + self.InstanceUpdateByJson(ctx=self.ctx)() + self.InstanceUpdateByGeneric(ctx=self.ctx)() + self.post_instance_update(self.ctx.vars.instance) + if condition_2: + self.ChangeRecordsCreateOrUpdateAtSubscriptionLevel(ctx=self.ctx)() + if condition_3: + self.ChangeRecordsCreateOrUpdate(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + @register_callback + def pre_instance_update(self, instance): + pass + + @register_callback + def post_instance_update(self, instance): + pass + + def _output(self, *args, **kwargs): + result = self.deserialize_output(self.ctx.vars.instance, client_flatten=True) + return result + + class ChangeRecordsGetAtSubscriptionLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + _UpdateHelper._build_schema_change_record_read(cls._schema_on_200) + + return cls._schema_on_200 + + class ChangeRecordsGet(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "resourceGroupName", self.ctx.args.resource_group, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + _UpdateHelper._build_schema_change_record_read(cls._schema_on_200) + + return cls._schema_on_200 + + class ChangeRecordsCreateOrUpdateAtSubscriptionLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200, 201]: + return self.on_200_201(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}", + **self.url_parameters + ) + + @property + def method(self): + return "PUT" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Content-Type", "application/json", + ), + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + @property + def content(self): + _content_value, _builder = self.new_content_builder( + self.ctx.args, + value=self.ctx.vars.instance, + ) + + return self.serialize_content(_content_value) + + def on_200_201(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200_201 + ) + + _schema_on_200_201 = None + + @classmethod + def _build_schema_on_200_201(cls): + if cls._schema_on_200_201 is not None: + return cls._schema_on_200_201 + + cls._schema_on_200_201 = AAZObjectType() + _UpdateHelper._build_schema_change_record_read(cls._schema_on_200_201) + + return cls._schema_on_200_201 + + class ChangeRecordsCreateOrUpdate(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200, 201]: + return self.on_200_201(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}", + **self.url_parameters + ) + + @property + def method(self): + return "PUT" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "resourceGroupName", self.ctx.args.resource_group, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Content-Type", "application/json", + ), + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + @property + def content(self): + _content_value, _builder = self.new_content_builder( + self.ctx.args, + value=self.ctx.vars.instance, + ) + + return self.serialize_content(_content_value) + + def on_200_201(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200_201 + ) + + _schema_on_200_201 = None + + @classmethod + def _build_schema_on_200_201(cls): + if cls._schema_on_200_201 is not None: + return cls._schema_on_200_201 + + cls._schema_on_200_201 = AAZObjectType() + _UpdateHelper._build_schema_change_record_read(cls._schema_on_200_201) + + return cls._schema_on_200_201 + + class InstanceUpdateByJson(AAZJsonInstanceUpdateOperation): + + def __call__(self, *args, **kwargs): + self._update_instance(self.ctx.vars.instance) + + def _update_instance(self, instance): + _instance_value, _builder = self.new_content_builder( + self.ctx.args, + value=instance, + typ=AAZObjectType + ) + _builder.set_prop("properties", AAZObjectType) + + properties = _builder.get(".properties") + if properties is not None: + properties.set_prop("additionalData", AAZObjectType, ".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}}) + properties.set_prop("changeType", AAZStrType, ".change_type", typ_kwargs={"flags": {"required": True}}) + properties.set_prop("comments", AAZStrType, ".comments") + properties.set_prop("description", AAZStrType, ".description") + properties.set_prop("links", AAZListType, ".links") + properties.set_prop("orchestrationTool", AAZStrType, ".orchestration_tool") + properties.set_prop("parameters", AAZDictType, ".parameters") + properties.set_prop("releaseLabel", AAZStrType, ".release_label") + properties.set_prop("rolloutType", AAZStrType, ".rollout_type", typ_kwargs={"flags": {"required": True}}) + properties.set_prop("stageMap", AAZObjectType, ".stage_map") + + 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("kind", AAZStrType, ".kind", typ_kwargs={"flags": {"required": True}}) + change_definition.set_prop("name", AAZStrType, ".name", typ_kwargs={"flags": {"required": True}}) + + links = _builder.get(".properties.links") + if links is not None: + links.set_elements(AAZObjectType, ".") + + _elements = _builder.get(".properties.links[]") + if _elements is not None: + _elements.set_prop("description", AAZStrType, ".description") + _elements.set_prop("name", AAZStrType, ".name", typ_kwargs={"flags": {"required": True}}) + _elements.set_prop("uri", AAZStrType, ".uri", typ_kwargs={"flags": {"required": True}}) + + parameters = _builder.get(".properties.parameters") + if parameters is not None: + parameters.set_elements(AAZObjectType, ".") + + _elements = _builder.get(".properties.parameters{}") + if _elements is not None: + _elements.set_prop("metadata", AAZDictType, ".metadata") + _elements.set_const("type", "array", AAZStrType, ".array", typ_kwargs={"flags": {"required": True}}) + _elements.set_const("type", "number", AAZStrType, ".number", typ_kwargs={"flags": {"required": True}}) + _elements.set_const("type", "object", AAZStrType, ".object", typ_kwargs={"flags": {"required": True}}) + _elements.set_const("type", "string", AAZStrType, ".string", typ_kwargs={"flags": {"required": True}}) + _elements.discriminate_by("type", "array") + _elements.discriminate_by("type", "number") + _elements.discriminate_by("type", "object") + _elements.discriminate_by("type", "string") + + metadata = _builder.get(".properties.parameters{}.metadata") + if metadata is not None: + metadata.set_elements(AAZStrType, ".") + + disc_array = _builder.get(".properties.parameters{}{type:array}") + if disc_array is not None: + disc_array.set_prop("allowedValues", AAZListType, ".array.allowed_values") + disc_array.set_prop("defaultValue", AAZListType, ".array.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:array}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZAnyType, ".") + + default_value = _builder.get(".properties.parameters{}{type:array}.defaultValue") + if default_value is not None: + default_value.set_elements(AAZAnyType, ".") + + disc_number = _builder.get(".properties.parameters{}{type:number}") + if disc_number is not None: + disc_number.set_prop("allowedValues", AAZListType, ".number.allowed_values") + disc_number.set_prop("defaultValue", AAZIntType, ".number.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:number}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZIntType, ".") + + disc_object = _builder.get(".properties.parameters{}{type:object}") + if disc_object is not None: + disc_object.set_prop("allowedValues", AAZListType, ".object.allowed_values") + disc_object.set_prop("defaultValue", AAZObjectType, ".object.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:object}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZDictType, ".") + + _elements = _builder.get(".properties.parameters{}{type:object}.allowedValues[]") + if _elements is not None: + _elements.set_elements(AAZAnyType, ".") + + disc_string = _builder.get(".properties.parameters{}{type:string}") + if disc_string is not None: + disc_string.set_prop("allowedValues", AAZListType, ".string.allowed_values") + disc_string.set_prop("defaultValue", AAZStrType, ".string.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:string}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZStrType, ".") + + stage_map = _builder.get(".properties.stageMap") + if stage_map is not None: + stage_map.set_prop("parameters", AAZDictType, ".parameters") + stage_map.set_prop("resourceId", AAZStrType, ".resource_id") + + parameters = _builder.get(".properties.stageMap.parameters") + if parameters is not None: + parameters.set_elements(AAZAnyType, ".") + + return _instance_value + + class InstanceUpdateByGeneric(AAZGenericInstanceUpdateOperation): + + def __call__(self, *args, **kwargs): + self._update_instance_by_generic( + self.ctx.vars.instance, + self.ctx.generic_update_args + ) + + +class _UpdateHelper: + """Helper class for Update""" + + _schema_change_record_read = None + + @classmethod + def _build_schema_change_record_read(cls, _schema): + if cls._schema_change_record_read is not None: + _schema.id = cls._schema_change_record_read.id + _schema.name = cls._schema_change_record_read.name + _schema.properties = cls._schema_change_record_read.properties + _schema.system_data = cls._schema_change_record_read.system_data + _schema.type = cls._schema_change_record_read.type + return + + cls._schema_change_record_read = _schema_change_record_read = AAZObjectType() + + change_record_read = _schema_change_record_read + change_record_read.id = AAZStrType( + flags={"read_only": True}, + ) + change_record_read.name = AAZStrType( + flags={"read_only": True}, + ) + change_record_read.properties = AAZObjectType() + change_record_read.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + change_record_read.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = _schema_change_record_read.properties + properties.additional_data = AAZObjectType( + serialized_name="additionalData", + ) + properties.anticipated_end_time = AAZStrType( + serialized_name="anticipatedEndTime", + flags={"required": True}, + ) + properties.anticipated_start_time = AAZStrType( + serialized_name="anticipatedStartTime", + flags={"required": True}, + ) + properties.change_definition = AAZObjectType( + serialized_name="changeDefinition", + flags={"required": True}, + ) + properties.change_type = AAZStrType( + serialized_name="changeType", + flags={"required": True}, + ) + properties.comments = AAZStrType() + properties.description = AAZStrType() + properties.links = AAZListType() + properties.orchestration_tool = AAZStrType( + serialized_name="orchestrationTool", + ) + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.release_label = AAZStrType( + serialized_name="releaseLabel", + ) + properties.rollout_type = AAZStrType( + serialized_name="rolloutType", + flags={"required": True}, + ) + properties.stage_map = AAZObjectType( + serialized_name="stageMap", + ) + properties.stage_map_snapshot = AAZListType( + serialized_name="stageMapSnapshot", + flags={"read_only": True}, + ) + properties.status = AAZStrType( + flags={"read_only": True}, + ) + + change_definition = _schema_change_record_read.properties.change_definition + change_definition.details = AAZObjectType( + flags={"required": True}, + ) + change_definition.kind = AAZStrType( + flags={"required": True}, + ) + change_definition.name = AAZStrType( + flags={"required": True}, + ) + + links = _schema_change_record_read.properties.links + links.Element = AAZObjectType() + + _element = _schema_change_record_read.properties.links.Element + _element.description = AAZStrType() + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.uri = AAZStrType( + flags={"required": True}, + ) + + parameters = _schema_change_record_read.properties.parameters + parameters.Element = AAZObjectType() + + _element = _schema_change_record_read.properties.parameters.Element + _element.metadata = AAZDictType() + _element.type = AAZStrType( + flags={"required": True}, + ) + + metadata = _schema_change_record_read.properties.parameters.Element.metadata + metadata.Element = AAZStrType() + + disc_array = _schema_change_record_read.properties.parameters.Element.discriminate_by("type", "array") + disc_array.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_array.default_value = AAZListType( + serialized_name="defaultValue", + ) + + allowed_values = _schema_change_record_read.properties.parameters.Element.discriminate_by("type", "array").allowed_values + allowed_values.Element = AAZAnyType() + + default_value = _schema_change_record_read.properties.parameters.Element.discriminate_by("type", "array").default_value + default_value.Element = AAZAnyType() + + disc_number = _schema_change_record_read.properties.parameters.Element.discriminate_by("type", "number") + disc_number.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_number.default_value = AAZIntType( + serialized_name="defaultValue", + ) + + allowed_values = _schema_change_record_read.properties.parameters.Element.discriminate_by("type", "number").allowed_values + allowed_values.Element = AAZIntType() + + disc_object = _schema_change_record_read.properties.parameters.Element.discriminate_by("type", "object") + disc_object.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_object.default_value = AAZObjectType( + serialized_name="defaultValue", + ) + + allowed_values = _schema_change_record_read.properties.parameters.Element.discriminate_by("type", "object").allowed_values + allowed_values.Element = AAZDictType() + + _element = _schema_change_record_read.properties.parameters.Element.discriminate_by("type", "object").allowed_values.Element + _element.Element = AAZAnyType() + + disc_string = _schema_change_record_read.properties.parameters.Element.discriminate_by("type", "string") + disc_string.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_string.default_value = AAZStrType( + serialized_name="defaultValue", + ) + + allowed_values = _schema_change_record_read.properties.parameters.Element.discriminate_by("type", "string").allowed_values + allowed_values.Element = AAZStrType() + + stage_map = _schema_change_record_read.properties.stage_map + stage_map.parameters = AAZDictType() + stage_map.resource_id = AAZStrType( + serialized_name="resourceId", + ) + + parameters = _schema_change_record_read.properties.stage_map.parameters + parameters.Element = AAZAnyType() + + stage_map_snapshot = _schema_change_record_read.properties.stage_map_snapshot + stage_map_snapshot.Element = AAZAnyType() + + system_data = _schema_change_record_read.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + _schema.id = cls._schema_change_record_read.id + _schema.name = cls._schema_change_record_read.name + _schema.properties = cls._schema_change_record_read.properties + _schema.system_data = cls._schema_change_record_read.system_data + _schema.type = cls._schema_change_record_read.type + + +__all__ = ["Update"] diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/__cmd_group.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/__cmd_group.py new file mode 100644 index 00000000000..0af235ba459 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/__cmd_group.py @@ -0,0 +1,23 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command_group( + "changesafety stagemap", +) +class __CMDGroup(AAZCommandGroup): + """Manage Stage Map + """ + pass + + +__all__ = ["__CMDGroup"] diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/__init__.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/__init__.py new file mode 100644 index 00000000000..c401f439385 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/__init__.py @@ -0,0 +1,16 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from .__cmd_group import * +from ._create import * +from ._delete import * +from ._list import * +from ._show import * +from ._update import * diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/_create.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/_create.py new file mode 100644 index 00000000000..e9466c3f7fa --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/_create.py @@ -0,0 +1,880 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "changesafety stagemap create", +) +class Create(AAZCommand): + """Create a StageMap + """ + + _aaz_info = { + "version": "2026-01-01-preview", + "resources": [ + ["mgmt-plane", "/managementgroups/{}/providers/microsoft.changesafety/stagemaps/{}", "2026-01-01-preview"], + ["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/stagemaps/{}", "2026-01-01-preview"], + ] + } + + def _handler(self, command_args): + super()._handler(command_args) + self._execute_operations() + return self._output() + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.management_group_name = AAZStrArg( + options=["--management-group-name"], + help="The name of the management group. The name is case insensitive.", + fmt=AAZStrArgFormat( + max_length=90, + min_length=1, + ), + ) + _args_schema.stage_map_name = AAZStrArg( + options=["--stage-map-name"], + help="The name of the StageMap", + required=True, + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-]{3,100}$", + max_length=100, + min_length=3, + ), + ) + + # define Arg Group "Properties" + + _args_schema = cls._args_schema + _args_schema.parameters = AAZDictArg( + options=["--parameters"], + arg_group="Properties", + help="StageMap parameters schema for each stage.", + ) + _args_schema.stages = AAZListArg( + options=["--stages"], + arg_group="Properties", + help="Array of stages objects.", + ) + + parameters = cls._args_schema.parameters + parameters.Element = AAZObjectArg() + + _element = cls._args_schema.parameters.Element + _element.array = AAZObjectArg( + options=["array"], + ) + _element.metadata = AAZDictArg( + options=["metadata"], + help="user-specified parameter metadata", + ) + _element.number = AAZObjectArg( + options=["number"], + ) + _element.object = AAZObjectArg( + options=["object"], + ) + _element.string = AAZObjectArg( + options=["string"], + ) + + array = cls._args_schema.parameters.Element.array + array.allowed_values = AAZListArg( + options=["allowed-values"], + help="Allowed list of the values for the parameter.", + ) + array.default_value = AAZListArg( + options=["default-value"], + help="Default value for the parameter.", + ) + + allowed_values = cls._args_schema.parameters.Element.array.allowed_values + allowed_values.Element = AAZAnyTypeArg() + + default_value = cls._args_schema.parameters.Element.array.default_value + default_value.Element = AAZAnyTypeArg() + + metadata = cls._args_schema.parameters.Element.metadata + metadata.Element = AAZStrArg() + + number = cls._args_schema.parameters.Element.number + number.allowed_values = AAZListArg( + options=["allowed-values"], + help="Allowed list of the values for the parameter.", + ) + number.default_value = AAZIntArg( + options=["default-value"], + help="Default value for the parameter.", + ) + + allowed_values = cls._args_schema.parameters.Element.number.allowed_values + allowed_values.Element = AAZIntArg() + + object = cls._args_schema.parameters.Element.object + object.allowed_values = AAZListArg( + options=["allowed-values"], + help="Allowed list of the values for the parameter.", + ) + object.default_value = AAZObjectArg( + options=["default-value"], + help="Default value for the parameter.", + blank={}, + ) + + allowed_values = cls._args_schema.parameters.Element.object.allowed_values + allowed_values.Element = AAZDictArg() + + _element = cls._args_schema.parameters.Element.object.allowed_values.Element + _element.Element = AAZAnyTypeArg() + + string = cls._args_schema.parameters.Element.string + string.allowed_values = AAZListArg( + options=["allowed-values"], + help="Allowed list of the values for the parameter.", + ) + string.default_value = AAZStrArg( + options=["default-value"], + help="Default value for the parameter.", + ) + + allowed_values = cls._args_schema.parameters.Element.string.allowed_values + allowed_values.Element = AAZStrArg() + + stages = cls._args_schema.stages + stages.Element = AAZObjectArg() + + _element = cls._args_schema.stages.Element + _element.name = AAZStrArg( + options=["name"], + help="Name of the individual stage.", + required=True, + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-]{3,100}$", + max_length=100, + min_length=3, + ), + ) + _element.nested_stage_map = AAZObjectArg( + options=["nested-stage-map"], + help="Nested stage map details.", + ) + _element.sequence = AAZIntArg( + options=["sequence"], + help="Positive integer defining the orchestration order of the stages.", + required=True, + fmt=AAZIntArgFormat( + minimum=1, + ), + ) + _element.stage_variables = AAZDictArg( + options=["stage-variables"], + help="Variables to apply on the change of that stage. Key value pairs supporting any JSON values.", + ) + + nested_stage_map = cls._args_schema.stages.Element.nested_stage_map + nested_stage_map.parameters = AAZDictArg( + options=["parameters"], + help="Key value pairs of parameter names & their values for the stageMap referenced by the resourceId field.", + ) + nested_stage_map.resource_id = AAZStrArg( + options=["resource-id"], + help="ARM resource ID for the nested stagemap resource.", + ) + + parameters = cls._args_schema.stages.Element.nested_stage_map.parameters + parameters.Element = AAZAnyTypeArg() + + stage_variables = cls._args_schema.stages.Element.stage_variables + stage_variables.Element = AAZAnyTypeArg() + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + condition_0 = has_value(self.ctx.args.management_group_name) and has_value(self.ctx.args.stage_map_name) + condition_1 = has_value(self.ctx.args.stage_map_name) and has_value(self.ctx.subscription_id) + if condition_0: + self.StageMapsCreateOrUpdateAtManagementGroupLevel(ctx=self.ctx)() + if condition_1: + self.StageMapsCreateOrUpdateAtSubscriptionLevel(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + def _output(self, *args, **kwargs): + result = self.deserialize_output(self.ctx.vars.instance, client_flatten=True) + return result + + class StageMapsCreateOrUpdateAtManagementGroupLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200, 201]: + return self.on_200_201(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/managementGroups/{managementGroupName}/providers/Microsoft.ChangeSafety/stageMaps/{stageMapName}", + **self.url_parameters + ) + + @property + def method(self): + return "PUT" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "managementGroupName", self.ctx.args.management_group_name, + required=True, + ), + **self.serialize_url_param( + "stageMapName", self.ctx.args.stage_map_name, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Content-Type", "application/json", + ), + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + @property + def content(self): + _content_value, _builder = self.new_content_builder( + self.ctx.args, + typ=AAZObjectType, + typ_kwargs={"flags": {"required": True, "client_flatten": True}} + ) + _builder.set_prop("properties", AAZObjectType) + + properties = _builder.get(".properties") + if properties is not None: + properties.set_prop("parameters", AAZDictType, ".parameters") + properties.set_prop("stages", AAZListType, ".stages", typ_kwargs={"flags": {"required": True}}) + + parameters = _builder.get(".properties.parameters") + if parameters is not None: + parameters.set_elements(AAZObjectType, ".") + + _elements = _builder.get(".properties.parameters{}") + if _elements is not None: + _elements.set_prop("metadata", AAZDictType, ".metadata") + _elements.set_const("type", "array", AAZStrType, ".array", typ_kwargs={"flags": {"required": True}}) + _elements.set_const("type", "number", AAZStrType, ".number", typ_kwargs={"flags": {"required": True}}) + _elements.set_const("type", "object", AAZStrType, ".object", typ_kwargs={"flags": {"required": True}}) + _elements.set_const("type", "string", AAZStrType, ".string", typ_kwargs={"flags": {"required": True}}) + _elements.discriminate_by("type", "array") + _elements.discriminate_by("type", "number") + _elements.discriminate_by("type", "object") + _elements.discriminate_by("type", "string") + + metadata = _builder.get(".properties.parameters{}.metadata") + if metadata is not None: + metadata.set_elements(AAZStrType, ".") + + disc_array = _builder.get(".properties.parameters{}{type:array}") + if disc_array is not None: + disc_array.set_prop("allowedValues", AAZListType, ".array.allowed_values") + disc_array.set_prop("defaultValue", AAZListType, ".array.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:array}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZAnyType, ".") + + default_value = _builder.get(".properties.parameters{}{type:array}.defaultValue") + if default_value is not None: + default_value.set_elements(AAZAnyType, ".") + + disc_number = _builder.get(".properties.parameters{}{type:number}") + if disc_number is not None: + disc_number.set_prop("allowedValues", AAZListType, ".number.allowed_values") + disc_number.set_prop("defaultValue", AAZIntType, ".number.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:number}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZIntType, ".") + + disc_object = _builder.get(".properties.parameters{}{type:object}") + if disc_object is not None: + disc_object.set_prop("allowedValues", AAZListType, ".object.allowed_values") + disc_object.set_prop("defaultValue", AAZObjectType, ".object.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:object}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZDictType, ".") + + _elements = _builder.get(".properties.parameters{}{type:object}.allowedValues[]") + if _elements is not None: + _elements.set_elements(AAZAnyType, ".") + + disc_string = _builder.get(".properties.parameters{}{type:string}") + if disc_string is not None: + disc_string.set_prop("allowedValues", AAZListType, ".string.allowed_values") + disc_string.set_prop("defaultValue", AAZStrType, ".string.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:string}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZStrType, ".") + + stages = _builder.get(".properties.stages") + if stages is not None: + stages.set_elements(AAZObjectType, ".") + + _elements = _builder.get(".properties.stages[]") + if _elements is not None: + _elements.set_prop("name", AAZStrType, ".name", typ_kwargs={"flags": {"required": True}}) + _elements.set_prop("nestedStageMap", AAZObjectType, ".nested_stage_map") + _elements.set_prop("sequence", AAZIntType, ".sequence", typ_kwargs={"flags": {"required": True}}) + _elements.set_prop("stageVariables", AAZDictType, ".stage_variables") + + nested_stage_map = _builder.get(".properties.stages[].nestedStageMap") + if nested_stage_map is not None: + nested_stage_map.set_prop("parameters", AAZDictType, ".parameters") + nested_stage_map.set_prop("resourceId", AAZStrType, ".resource_id") + + parameters = _builder.get(".properties.stages[].nestedStageMap.parameters") + if parameters is not None: + parameters.set_elements(AAZAnyType, ".") + + stage_variables = _builder.get(".properties.stages[].stageVariables") + if stage_variables is not None: + stage_variables.set_elements(AAZAnyType, ".") + + return self.serialize_content(_content_value) + + def on_200_201(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200_201 + ) + + _schema_on_200_201 = None + + @classmethod + def _build_schema_on_200_201(cls): + if cls._schema_on_200_201 is not None: + return cls._schema_on_200_201 + + cls._schema_on_200_201 = AAZObjectType() + + _schema_on_200_201 = cls._schema_on_200_201 + _schema_on_200_201.id = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200_201.name = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200_201.properties = AAZObjectType() + _schema_on_200_201.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _schema_on_200_201.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200_201.properties + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.stages = AAZListType( + flags={"required": True}, + ) + + parameters = cls._schema_on_200_201.properties.parameters + parameters.Element = AAZObjectType() + + _element = cls._schema_on_200_201.properties.parameters.Element + _element.metadata = AAZDictType() + _element.type = AAZStrType( + flags={"required": True}, + ) + + metadata = cls._schema_on_200_201.properties.parameters.Element.metadata + metadata.Element = AAZStrType() + + disc_array = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "array") + disc_array.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_array.default_value = AAZListType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "array").allowed_values + allowed_values.Element = AAZAnyType() + + default_value = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "array").default_value + default_value.Element = AAZAnyType() + + disc_number = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "number") + disc_number.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_number.default_value = AAZIntType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "number").allowed_values + allowed_values.Element = AAZIntType() + + disc_object = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "object") + disc_object.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_object.default_value = AAZObjectType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "object").allowed_values + allowed_values.Element = AAZDictType() + + _element = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "object").allowed_values.Element + _element.Element = AAZAnyType() + + disc_string = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "string") + disc_string.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_string.default_value = AAZStrType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "string").allowed_values + allowed_values.Element = AAZStrType() + + stages = cls._schema_on_200_201.properties.stages + stages.Element = AAZObjectType() + + _element = cls._schema_on_200_201.properties.stages.Element + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.nested_stage_map = AAZObjectType( + serialized_name="nestedStageMap", + ) + _element.sequence = AAZIntType( + flags={"required": True}, + ) + _element.stage_variables = AAZDictType( + serialized_name="stageVariables", + ) + + nested_stage_map = cls._schema_on_200_201.properties.stages.Element.nested_stage_map + nested_stage_map.parameters = AAZDictType() + nested_stage_map.resource_id = AAZStrType( + serialized_name="resourceId", + ) + + parameters = cls._schema_on_200_201.properties.stages.Element.nested_stage_map.parameters + parameters.Element = AAZAnyType() + + stage_variables = cls._schema_on_200_201.properties.stages.Element.stage_variables + stage_variables.Element = AAZAnyType() + + system_data = cls._schema_on_200_201.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200_201 + + class StageMapsCreateOrUpdateAtSubscriptionLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200, 201]: + return self.on_200_201(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/stageMaps/{stageMapName}", + **self.url_parameters + ) + + @property + def method(self): + return "PUT" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "stageMapName", self.ctx.args.stage_map_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Content-Type", "application/json", + ), + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + @property + def content(self): + _content_value, _builder = self.new_content_builder( + self.ctx.args, + typ=AAZObjectType, + typ_kwargs={"flags": {"required": True, "client_flatten": True}} + ) + _builder.set_prop("properties", AAZObjectType) + + properties = _builder.get(".properties") + if properties is not None: + properties.set_prop("parameters", AAZDictType, ".parameters") + properties.set_prop("stages", AAZListType, ".stages", typ_kwargs={"flags": {"required": True}}) + + parameters = _builder.get(".properties.parameters") + if parameters is not None: + parameters.set_elements(AAZObjectType, ".") + + _elements = _builder.get(".properties.parameters{}") + if _elements is not None: + _elements.set_prop("metadata", AAZDictType, ".metadata") + _elements.set_const("type", "array", AAZStrType, ".array", typ_kwargs={"flags": {"required": True}}) + _elements.set_const("type", "number", AAZStrType, ".number", typ_kwargs={"flags": {"required": True}}) + _elements.set_const("type", "object", AAZStrType, ".object", typ_kwargs={"flags": {"required": True}}) + _elements.set_const("type", "string", AAZStrType, ".string", typ_kwargs={"flags": {"required": True}}) + _elements.discriminate_by("type", "array") + _elements.discriminate_by("type", "number") + _elements.discriminate_by("type", "object") + _elements.discriminate_by("type", "string") + + metadata = _builder.get(".properties.parameters{}.metadata") + if metadata is not None: + metadata.set_elements(AAZStrType, ".") + + disc_array = _builder.get(".properties.parameters{}{type:array}") + if disc_array is not None: + disc_array.set_prop("allowedValues", AAZListType, ".array.allowed_values") + disc_array.set_prop("defaultValue", AAZListType, ".array.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:array}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZAnyType, ".") + + default_value = _builder.get(".properties.parameters{}{type:array}.defaultValue") + if default_value is not None: + default_value.set_elements(AAZAnyType, ".") + + disc_number = _builder.get(".properties.parameters{}{type:number}") + if disc_number is not None: + disc_number.set_prop("allowedValues", AAZListType, ".number.allowed_values") + disc_number.set_prop("defaultValue", AAZIntType, ".number.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:number}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZIntType, ".") + + disc_object = _builder.get(".properties.parameters{}{type:object}") + if disc_object is not None: + disc_object.set_prop("allowedValues", AAZListType, ".object.allowed_values") + disc_object.set_prop("defaultValue", AAZObjectType, ".object.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:object}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZDictType, ".") + + _elements = _builder.get(".properties.parameters{}{type:object}.allowedValues[]") + if _elements is not None: + _elements.set_elements(AAZAnyType, ".") + + disc_string = _builder.get(".properties.parameters{}{type:string}") + if disc_string is not None: + disc_string.set_prop("allowedValues", AAZListType, ".string.allowed_values") + disc_string.set_prop("defaultValue", AAZStrType, ".string.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:string}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZStrType, ".") + + stages = _builder.get(".properties.stages") + if stages is not None: + stages.set_elements(AAZObjectType, ".") + + _elements = _builder.get(".properties.stages[]") + if _elements is not None: + _elements.set_prop("name", AAZStrType, ".name", typ_kwargs={"flags": {"required": True}}) + _elements.set_prop("nestedStageMap", AAZObjectType, ".nested_stage_map") + _elements.set_prop("sequence", AAZIntType, ".sequence", typ_kwargs={"flags": {"required": True}}) + _elements.set_prop("stageVariables", AAZDictType, ".stage_variables") + + nested_stage_map = _builder.get(".properties.stages[].nestedStageMap") + if nested_stage_map is not None: + nested_stage_map.set_prop("parameters", AAZDictType, ".parameters") + nested_stage_map.set_prop("resourceId", AAZStrType, ".resource_id") + + parameters = _builder.get(".properties.stages[].nestedStageMap.parameters") + if parameters is not None: + parameters.set_elements(AAZAnyType, ".") + + stage_variables = _builder.get(".properties.stages[].stageVariables") + if stage_variables is not None: + stage_variables.set_elements(AAZAnyType, ".") + + return self.serialize_content(_content_value) + + def on_200_201(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200_201 + ) + + _schema_on_200_201 = None + + @classmethod + def _build_schema_on_200_201(cls): + if cls._schema_on_200_201 is not None: + return cls._schema_on_200_201 + + cls._schema_on_200_201 = AAZObjectType() + + _schema_on_200_201 = cls._schema_on_200_201 + _schema_on_200_201.id = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200_201.name = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200_201.properties = AAZObjectType() + _schema_on_200_201.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _schema_on_200_201.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200_201.properties + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.stages = AAZListType( + flags={"required": True}, + ) + + parameters = cls._schema_on_200_201.properties.parameters + parameters.Element = AAZObjectType() + + _element = cls._schema_on_200_201.properties.parameters.Element + _element.metadata = AAZDictType() + _element.type = AAZStrType( + flags={"required": True}, + ) + + metadata = cls._schema_on_200_201.properties.parameters.Element.metadata + metadata.Element = AAZStrType() + + disc_array = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "array") + disc_array.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_array.default_value = AAZListType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "array").allowed_values + allowed_values.Element = AAZAnyType() + + default_value = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "array").default_value + default_value.Element = AAZAnyType() + + disc_number = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "number") + disc_number.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_number.default_value = AAZIntType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "number").allowed_values + allowed_values.Element = AAZIntType() + + disc_object = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "object") + disc_object.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_object.default_value = AAZObjectType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "object").allowed_values + allowed_values.Element = AAZDictType() + + _element = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "object").allowed_values.Element + _element.Element = AAZAnyType() + + disc_string = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "string") + disc_string.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_string.default_value = AAZStrType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200_201.properties.parameters.Element.discriminate_by("type", "string").allowed_values + allowed_values.Element = AAZStrType() + + stages = cls._schema_on_200_201.properties.stages + stages.Element = AAZObjectType() + + _element = cls._schema_on_200_201.properties.stages.Element + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.nested_stage_map = AAZObjectType( + serialized_name="nestedStageMap", + ) + _element.sequence = AAZIntType( + flags={"required": True}, + ) + _element.stage_variables = AAZDictType( + serialized_name="stageVariables", + ) + + nested_stage_map = cls._schema_on_200_201.properties.stages.Element.nested_stage_map + nested_stage_map.parameters = AAZDictType() + nested_stage_map.resource_id = AAZStrType( + serialized_name="resourceId", + ) + + parameters = cls._schema_on_200_201.properties.stages.Element.nested_stage_map.parameters + parameters.Element = AAZAnyType() + + stage_variables = cls._schema_on_200_201.properties.stages.Element.stage_variables + stage_variables.Element = AAZAnyType() + + system_data = cls._schema_on_200_201.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200_201 + + +class _CreateHelper: + """Helper class for Create""" + + +__all__ = ["Create"] diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/_delete.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/_delete.py new file mode 100644 index 00000000000..b6c4811162e --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/_delete.py @@ -0,0 +1,205 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "changesafety stagemap delete", + confirmation="Are you sure you want to perform this operation?", +) +class Delete(AAZCommand): + """Delete a StageMap + """ + + _aaz_info = { + "version": "2026-01-01-preview", + "resources": [ + ["mgmt-plane", "/managementgroups/{}/providers/microsoft.changesafety/stagemaps/{}", "2026-01-01-preview"], + ["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/stagemaps/{}", "2026-01-01-preview"], + ] + } + + def _handler(self, command_args): + super()._handler(command_args) + self._execute_operations() + return None + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.management_group_name = AAZStrArg( + options=["--management-group-name"], + help="The name of the management group. The name is case insensitive.", + fmt=AAZStrArgFormat( + max_length=90, + min_length=1, + ), + ) + _args_schema.stage_map_name = AAZStrArg( + options=["--stage-map-name"], + help="The name of the StageMap", + required=True, + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-]{3,100}$", + max_length=100, + min_length=3, + ), + ) + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + condition_0 = has_value(self.ctx.args.management_group_name) and has_value(self.ctx.args.stage_map_name) + condition_1 = has_value(self.ctx.args.stage_map_name) and has_value(self.ctx.subscription_id) + if condition_0: + self.StageMapsDeleteAtManagementGroupLevel(ctx=self.ctx)() + if condition_1: + self.StageMapsDeleteAtSubscriptionLevel(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + class StageMapsDeleteAtManagementGroupLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + if session.http_response.status_code in [204]: + return self.on_204(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/managementGroups/{managementGroupName}/providers/Microsoft.ChangeSafety/stageMaps/{stageMapName}", + **self.url_parameters + ) + + @property + def method(self): + return "DELETE" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "managementGroupName", self.ctx.args.management_group_name, + required=True, + ), + **self.serialize_url_param( + "stageMapName", self.ctx.args.stage_map_name, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + def on_200(self, session): + pass + + def on_204(self, session): + pass + + class StageMapsDeleteAtSubscriptionLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + if session.http_response.status_code in [204]: + return self.on_204(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/stageMaps/{stageMapName}", + **self.url_parameters + ) + + @property + def method(self): + return "DELETE" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "stageMapName", self.ctx.args.stage_map_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + def on_200(self, session): + pass + + def on_204(self, session): + pass + + +class _DeleteHelper: + """Helper class for Delete""" + + +__all__ = ["Delete"] diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/_list.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/_list.py new file mode 100644 index 00000000000..2975a8f9cd1 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/_list.py @@ -0,0 +1,528 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "changesafety stagemap list", +) +class List(AAZCommand): + """List StageMap resources by resource group + """ + + _aaz_info = { + "version": "2026-01-01-preview", + "resources": [ + ["mgmt-plane", "/managementgroups/{}/providers/microsoft.changesafety/stagemaps", "2026-01-01-preview"], + ["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/stagemaps", "2026-01-01-preview"], + ] + } + + AZ_SUPPORT_PAGINATION = True + + def _handler(self, command_args): + super()._handler(command_args) + return self.build_paging(self._execute_operations, self._output) + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.management_group_name = AAZStrArg( + options=["--management-group-name"], + help="The name of the management group. The name is case insensitive.", + fmt=AAZStrArgFormat( + max_length=90, + min_length=1, + ), + ) + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + condition_0 = has_value(self.ctx.args.management_group_name) + condition_1 = has_value(self.ctx.subscription_id) + if condition_0: + self.StageMapsListByManagementGroup(ctx=self.ctx)() + if condition_1: + self.StageMapsListBySubscription(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + def _output(self, *args, **kwargs): + result = self.deserialize_output(self.ctx.vars.instance.value, client_flatten=True) + next_link = self.deserialize_output(self.ctx.vars.instance.next_link) + return result, next_link + + class StageMapsListByManagementGroup(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/managementGroups/{managementGroupName}/providers/Microsoft.ChangeSafety/stageMaps", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "managementGroupName", self.ctx.args.management_group_name, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + + _schema_on_200 = cls._schema_on_200 + _schema_on_200.next_link = AAZStrType( + serialized_name="nextLink", + ) + _schema_on_200.value = AAZListType( + flags={"required": True}, + ) + + value = cls._schema_on_200.value + value.Element = AAZObjectType() + + _element = cls._schema_on_200.value.Element + _element.id = AAZStrType( + flags={"read_only": True}, + ) + _element.name = AAZStrType( + flags={"read_only": True}, + ) + _element.properties = AAZObjectType() + _element.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _element.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200.value.Element.properties + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.stages = AAZListType( + flags={"required": True}, + ) + + parameters = cls._schema_on_200.value.Element.properties.parameters + parameters.Element = AAZObjectType() + + _element = cls._schema_on_200.value.Element.properties.parameters.Element + _element.metadata = AAZDictType() + _element.type = AAZStrType( + flags={"required": True}, + ) + + metadata = cls._schema_on_200.value.Element.properties.parameters.Element.metadata + metadata.Element = AAZStrType() + + disc_array = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "array") + disc_array.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_array.default_value = AAZListType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "array").allowed_values + allowed_values.Element = AAZAnyType() + + default_value = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "array").default_value + default_value.Element = AAZAnyType() + + disc_number = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "number") + disc_number.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_number.default_value = AAZIntType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "number").allowed_values + allowed_values.Element = AAZIntType() + + disc_object = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "object") + disc_object.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_object.default_value = AAZObjectType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "object").allowed_values + allowed_values.Element = AAZDictType() + + _element = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "object").allowed_values.Element + _element.Element = AAZAnyType() + + disc_string = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "string") + disc_string.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_string.default_value = AAZStrType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "string").allowed_values + allowed_values.Element = AAZStrType() + + stages = cls._schema_on_200.value.Element.properties.stages + stages.Element = AAZObjectType() + + _element = cls._schema_on_200.value.Element.properties.stages.Element + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.nested_stage_map = AAZObjectType( + serialized_name="nestedStageMap", + ) + _element.sequence = AAZIntType( + flags={"required": True}, + ) + _element.stage_variables = AAZDictType( + serialized_name="stageVariables", + ) + + nested_stage_map = cls._schema_on_200.value.Element.properties.stages.Element.nested_stage_map + nested_stage_map.parameters = AAZDictType() + nested_stage_map.resource_id = AAZStrType( + serialized_name="resourceId", + ) + + parameters = cls._schema_on_200.value.Element.properties.stages.Element.nested_stage_map.parameters + parameters.Element = AAZAnyType() + + stage_variables = cls._schema_on_200.value.Element.properties.stages.Element.stage_variables + stage_variables.Element = AAZAnyType() + + system_data = cls._schema_on_200.value.Element.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200 + + class StageMapsListBySubscription(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/stageMaps", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + + _schema_on_200 = cls._schema_on_200 + _schema_on_200.next_link = AAZStrType( + serialized_name="nextLink", + ) + _schema_on_200.value = AAZListType( + flags={"required": True}, + ) + + value = cls._schema_on_200.value + value.Element = AAZObjectType() + + _element = cls._schema_on_200.value.Element + _element.id = AAZStrType( + flags={"read_only": True}, + ) + _element.name = AAZStrType( + flags={"read_only": True}, + ) + _element.properties = AAZObjectType() + _element.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _element.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200.value.Element.properties + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.stages = AAZListType( + flags={"required": True}, + ) + + parameters = cls._schema_on_200.value.Element.properties.parameters + parameters.Element = AAZObjectType() + + _element = cls._schema_on_200.value.Element.properties.parameters.Element + _element.metadata = AAZDictType() + _element.type = AAZStrType( + flags={"required": True}, + ) + + metadata = cls._schema_on_200.value.Element.properties.parameters.Element.metadata + metadata.Element = AAZStrType() + + disc_array = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "array") + disc_array.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_array.default_value = AAZListType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "array").allowed_values + allowed_values.Element = AAZAnyType() + + default_value = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "array").default_value + default_value.Element = AAZAnyType() + + disc_number = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "number") + disc_number.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_number.default_value = AAZIntType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "number").allowed_values + allowed_values.Element = AAZIntType() + + disc_object = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "object") + disc_object.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_object.default_value = AAZObjectType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "object").allowed_values + allowed_values.Element = AAZDictType() + + _element = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "object").allowed_values.Element + _element.Element = AAZAnyType() + + disc_string = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "string") + disc_string.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_string.default_value = AAZStrType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.value.Element.properties.parameters.Element.discriminate_by("type", "string").allowed_values + allowed_values.Element = AAZStrType() + + stages = cls._schema_on_200.value.Element.properties.stages + stages.Element = AAZObjectType() + + _element = cls._schema_on_200.value.Element.properties.stages.Element + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.nested_stage_map = AAZObjectType( + serialized_name="nestedStageMap", + ) + _element.sequence = AAZIntType( + flags={"required": True}, + ) + _element.stage_variables = AAZDictType( + serialized_name="stageVariables", + ) + + nested_stage_map = cls._schema_on_200.value.Element.properties.stages.Element.nested_stage_map + nested_stage_map.parameters = AAZDictType() + nested_stage_map.resource_id = AAZStrType( + serialized_name="resourceId", + ) + + parameters = cls._schema_on_200.value.Element.properties.stages.Element.nested_stage_map.parameters + parameters.Element = AAZAnyType() + + stage_variables = cls._schema_on_200.value.Element.properties.stages.Element.stage_variables + stage_variables.Element = AAZAnyType() + + system_data = cls._schema_on_200.value.Element.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200 + + +class _ListHelper: + """Helper class for List""" + + +__all__ = ["List"] diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/_show.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/_show.py new file mode 100644 index 00000000000..d6bb7b1e65b --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/_show.py @@ -0,0 +1,522 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "changesafety stagemap show", +) +class Show(AAZCommand): + """Get a StageMap + """ + + _aaz_info = { + "version": "2026-01-01-preview", + "resources": [ + ["mgmt-plane", "/managementgroups/{}/providers/microsoft.changesafety/stagemaps/{}", "2026-01-01-preview"], + ["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/stagemaps/{}", "2026-01-01-preview"], + ] + } + + def _handler(self, command_args): + super()._handler(command_args) + self._execute_operations() + return self._output() + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.management_group_name = AAZStrArg( + options=["--management-group-name"], + help="The name of the management group. The name is case insensitive.", + fmt=AAZStrArgFormat( + max_length=90, + min_length=1, + ), + ) + _args_schema.stage_map_name = AAZStrArg( + options=["--stage-map-name"], + help="The name of the StageMap", + required=True, + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-]{3,100}$", + max_length=100, + min_length=3, + ), + ) + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + condition_0 = has_value(self.ctx.args.management_group_name) and has_value(self.ctx.args.stage_map_name) + condition_1 = has_value(self.ctx.args.stage_map_name) and has_value(self.ctx.subscription_id) + if condition_0: + self.StageMapsGetAtManagementGroupLevel(ctx=self.ctx)() + if condition_1: + self.StageMapsGetAtSubscriptionLevel(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + def _output(self, *args, **kwargs): + result = self.deserialize_output(self.ctx.vars.instance, client_flatten=True) + return result + + class StageMapsGetAtManagementGroupLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/managementGroups/{managementGroupName}/providers/Microsoft.ChangeSafety/stageMaps/{stageMapName}", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "managementGroupName", self.ctx.args.management_group_name, + required=True, + ), + **self.serialize_url_param( + "stageMapName", self.ctx.args.stage_map_name, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + + _schema_on_200 = cls._schema_on_200 + _schema_on_200.id = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200.name = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200.properties = AAZObjectType() + _schema_on_200.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _schema_on_200.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200.properties + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.stages = AAZListType( + flags={"required": True}, + ) + + parameters = cls._schema_on_200.properties.parameters + parameters.Element = AAZObjectType() + + _element = cls._schema_on_200.properties.parameters.Element + _element.metadata = AAZDictType() + _element.type = AAZStrType( + flags={"required": True}, + ) + + metadata = cls._schema_on_200.properties.parameters.Element.metadata + metadata.Element = AAZStrType() + + disc_array = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "array") + disc_array.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_array.default_value = AAZListType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "array").allowed_values + allowed_values.Element = AAZAnyType() + + default_value = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "array").default_value + default_value.Element = AAZAnyType() + + disc_number = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "number") + disc_number.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_number.default_value = AAZIntType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "number").allowed_values + allowed_values.Element = AAZIntType() + + disc_object = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "object") + disc_object.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_object.default_value = AAZObjectType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "object").allowed_values + allowed_values.Element = AAZDictType() + + _element = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "object").allowed_values.Element + _element.Element = AAZAnyType() + + disc_string = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "string") + disc_string.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_string.default_value = AAZStrType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "string").allowed_values + allowed_values.Element = AAZStrType() + + stages = cls._schema_on_200.properties.stages + stages.Element = AAZObjectType() + + _element = cls._schema_on_200.properties.stages.Element + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.nested_stage_map = AAZObjectType( + serialized_name="nestedStageMap", + ) + _element.sequence = AAZIntType( + flags={"required": True}, + ) + _element.stage_variables = AAZDictType( + serialized_name="stageVariables", + ) + + nested_stage_map = cls._schema_on_200.properties.stages.Element.nested_stage_map + nested_stage_map.parameters = AAZDictType() + nested_stage_map.resource_id = AAZStrType( + serialized_name="resourceId", + ) + + parameters = cls._schema_on_200.properties.stages.Element.nested_stage_map.parameters + parameters.Element = AAZAnyType() + + stage_variables = cls._schema_on_200.properties.stages.Element.stage_variables + stage_variables.Element = AAZAnyType() + + system_data = cls._schema_on_200.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200 + + class StageMapsGetAtSubscriptionLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/stageMaps/{stageMapName}", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "stageMapName", self.ctx.args.stage_map_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + + _schema_on_200 = cls._schema_on_200 + _schema_on_200.id = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200.name = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200.properties = AAZObjectType() + _schema_on_200.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _schema_on_200.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200.properties + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.stages = AAZListType( + flags={"required": True}, + ) + + parameters = cls._schema_on_200.properties.parameters + parameters.Element = AAZObjectType() + + _element = cls._schema_on_200.properties.parameters.Element + _element.metadata = AAZDictType() + _element.type = AAZStrType( + flags={"required": True}, + ) + + metadata = cls._schema_on_200.properties.parameters.Element.metadata + metadata.Element = AAZStrType() + + disc_array = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "array") + disc_array.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_array.default_value = AAZListType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "array").allowed_values + allowed_values.Element = AAZAnyType() + + default_value = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "array").default_value + default_value.Element = AAZAnyType() + + disc_number = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "number") + disc_number.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_number.default_value = AAZIntType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "number").allowed_values + allowed_values.Element = AAZIntType() + + disc_object = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "object") + disc_object.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_object.default_value = AAZObjectType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "object").allowed_values + allowed_values.Element = AAZDictType() + + _element = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "object").allowed_values.Element + _element.Element = AAZAnyType() + + disc_string = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "string") + disc_string.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_string.default_value = AAZStrType( + serialized_name="defaultValue", + ) + + allowed_values = cls._schema_on_200.properties.parameters.Element.discriminate_by("type", "string").allowed_values + allowed_values.Element = AAZStrType() + + stages = cls._schema_on_200.properties.stages + stages.Element = AAZObjectType() + + _element = cls._schema_on_200.properties.stages.Element + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.nested_stage_map = AAZObjectType( + serialized_name="nestedStageMap", + ) + _element.sequence = AAZIntType( + flags={"required": True}, + ) + _element.stage_variables = AAZDictType( + serialized_name="stageVariables", + ) + + nested_stage_map = cls._schema_on_200.properties.stages.Element.nested_stage_map + nested_stage_map.parameters = AAZDictType() + nested_stage_map.resource_id = AAZStrType( + serialized_name="resourceId", + ) + + parameters = cls._schema_on_200.properties.stages.Element.nested_stage_map.parameters + parameters.Element = AAZAnyType() + + stage_variables = cls._schema_on_200.properties.stages.Element.stage_variables + stage_variables.Element = AAZAnyType() + + system_data = cls._schema_on_200.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200 + + +class _ShowHelper: + """Helper class for Show""" + + +__all__ = ["Show"] diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/_update.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/_update.py new file mode 100644 index 00000000000..dbafa71b2f5 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stagemap/_update.py @@ -0,0 +1,903 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "changesafety stagemap update", +) +class Update(AAZCommand): + """Update a StageMap + """ + + _aaz_info = { + "version": "2026-01-01-preview", + "resources": [ + ["mgmt-plane", "/managementgroups/{}/providers/microsoft.changesafety/stagemaps/{}", "2026-01-01-preview"], + ["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/stagemaps/{}", "2026-01-01-preview"], + ] + } + + AZ_SUPPORT_GENERIC_UPDATE = True + + def _handler(self, command_args): + super()._handler(command_args) + self._execute_operations() + return self._output() + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.management_group_name = AAZStrArg( + options=["--management-group-name"], + help="The name of the management group. The name is case insensitive.", + fmt=AAZStrArgFormat( + max_length=90, + min_length=1, + ), + ) + _args_schema.stage_map_name = AAZStrArg( + options=["--stage-map-name"], + help="The name of the StageMap", + required=True, + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-]{3,100}$", + max_length=100, + min_length=3, + ), + ) + + # define Arg Group "Properties" + + _args_schema = cls._args_schema + _args_schema.parameters = AAZDictArg( + options=["--parameters"], + arg_group="Properties", + help="StageMap parameters schema for each stage.", + nullable=True, + ) + _args_schema.stages = AAZListArg( + options=["--stages"], + arg_group="Properties", + help="Array of stages objects.", + ) + + parameters = cls._args_schema.parameters + parameters.Element = AAZObjectArg( + nullable=True, + ) + + _element = cls._args_schema.parameters.Element + _element.array = AAZObjectArg( + options=["array"], + ) + _element.metadata = AAZDictArg( + options=["metadata"], + help="user-specified parameter metadata", + nullable=True, + ) + _element.number = AAZObjectArg( + options=["number"], + ) + _element.object = AAZObjectArg( + options=["object"], + ) + _element.string = AAZObjectArg( + options=["string"], + ) + + array = cls._args_schema.parameters.Element.array + array.allowed_values = AAZListArg( + options=["allowed-values"], + help="Allowed list of the values for the parameter.", + nullable=True, + ) + array.default_value = AAZListArg( + options=["default-value"], + help="Default value for the parameter.", + nullable=True, + ) + + allowed_values = cls._args_schema.parameters.Element.array.allowed_values + allowed_values.Element = AAZAnyTypeArg( + nullable=True, + ) + + default_value = cls._args_schema.parameters.Element.array.default_value + default_value.Element = AAZAnyTypeArg( + nullable=True, + ) + + metadata = cls._args_schema.parameters.Element.metadata + metadata.Element = AAZStrArg( + nullable=True, + ) + + number = cls._args_schema.parameters.Element.number + number.allowed_values = AAZListArg( + options=["allowed-values"], + help="Allowed list of the values for the parameter.", + nullable=True, + ) + number.default_value = AAZIntArg( + options=["default-value"], + help="Default value for the parameter.", + nullable=True, + ) + + allowed_values = cls._args_schema.parameters.Element.number.allowed_values + allowed_values.Element = AAZIntArg( + nullable=True, + ) + + object = cls._args_schema.parameters.Element.object + object.allowed_values = AAZListArg( + options=["allowed-values"], + help="Allowed list of the values for the parameter.", + nullable=True, + ) + object.default_value = AAZObjectArg( + options=["default-value"], + help="Default value for the parameter.", + nullable=True, + blank={}, + ) + + allowed_values = cls._args_schema.parameters.Element.object.allowed_values + allowed_values.Element = AAZDictArg( + nullable=True, + ) + + _element = cls._args_schema.parameters.Element.object.allowed_values.Element + _element.Element = AAZAnyTypeArg( + nullable=True, + ) + + string = cls._args_schema.parameters.Element.string + string.allowed_values = AAZListArg( + options=["allowed-values"], + help="Allowed list of the values for the parameter.", + nullable=True, + ) + string.default_value = AAZStrArg( + options=["default-value"], + help="Default value for the parameter.", + nullable=True, + ) + + allowed_values = cls._args_schema.parameters.Element.string.allowed_values + allowed_values.Element = AAZStrArg( + nullable=True, + ) + + stages = cls._args_schema.stages + stages.Element = AAZObjectArg( + nullable=True, + ) + + _element = cls._args_schema.stages.Element + _element.name = AAZStrArg( + options=["name"], + help="Name of the individual stage.", + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-]{3,100}$", + max_length=100, + min_length=3, + ), + ) + _element.nested_stage_map = AAZObjectArg( + options=["nested-stage-map"], + help="Nested stage map details.", + nullable=True, + ) + _element.sequence = AAZIntArg( + options=["sequence"], + help="Positive integer defining the orchestration order of the stages.", + fmt=AAZIntArgFormat( + minimum=1, + ), + ) + _element.stage_variables = AAZDictArg( + options=["stage-variables"], + help="Variables to apply on the change of that stage. Key value pairs supporting any JSON values.", + nullable=True, + ) + + nested_stage_map = cls._args_schema.stages.Element.nested_stage_map + nested_stage_map.parameters = AAZDictArg( + options=["parameters"], + help="Key value pairs of parameter names & their values for the stageMap referenced by the resourceId field.", + nullable=True, + ) + nested_stage_map.resource_id = AAZStrArg( + options=["resource-id"], + help="ARM resource ID for the nested stagemap resource.", + nullable=True, + ) + + parameters = cls._args_schema.stages.Element.nested_stage_map.parameters + parameters.Element = AAZAnyTypeArg( + nullable=True, + ) + + stage_variables = cls._args_schema.stages.Element.stage_variables + stage_variables.Element = AAZAnyTypeArg( + nullable=True, + ) + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + condition_0 = has_value(self.ctx.args.management_group_name) and has_value(self.ctx.args.stage_map_name) + condition_1 = has_value(self.ctx.args.stage_map_name) and has_value(self.ctx.subscription_id) + condition_2 = has_value(self.ctx.args.management_group_name) and has_value(self.ctx.args.stage_map_name) + condition_3 = has_value(self.ctx.args.stage_map_name) and has_value(self.ctx.subscription_id) + if condition_0: + self.StageMapsGetAtManagementGroupLevel(ctx=self.ctx)() + if condition_1: + self.StageMapsGetAtSubscriptionLevel(ctx=self.ctx)() + self.pre_instance_update(self.ctx.vars.instance) + self.InstanceUpdateByJson(ctx=self.ctx)() + self.InstanceUpdateByGeneric(ctx=self.ctx)() + self.post_instance_update(self.ctx.vars.instance) + if condition_2: + self.StageMapsCreateOrUpdateAtManagementGroupLevel(ctx=self.ctx)() + if condition_3: + self.StageMapsCreateOrUpdateAtSubscriptionLevel(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + @register_callback + def pre_instance_update(self, instance): + pass + + @register_callback + def post_instance_update(self, instance): + pass + + def _output(self, *args, **kwargs): + result = self.deserialize_output(self.ctx.vars.instance, client_flatten=True) + return result + + class StageMapsGetAtManagementGroupLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/managementGroups/{managementGroupName}/providers/Microsoft.ChangeSafety/stageMaps/{stageMapName}", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "managementGroupName", self.ctx.args.management_group_name, + required=True, + ), + **self.serialize_url_param( + "stageMapName", self.ctx.args.stage_map_name, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + _UpdateHelper._build_schema_stage_map_read(cls._schema_on_200) + + return cls._schema_on_200 + + class StageMapsGetAtSubscriptionLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/stageMaps/{stageMapName}", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "stageMapName", self.ctx.args.stage_map_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + _UpdateHelper._build_schema_stage_map_read(cls._schema_on_200) + + return cls._schema_on_200 + + class StageMapsCreateOrUpdateAtManagementGroupLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200, 201]: + return self.on_200_201(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/managementGroups/{managementGroupName}/providers/Microsoft.ChangeSafety/stageMaps/{stageMapName}", + **self.url_parameters + ) + + @property + def method(self): + return "PUT" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "managementGroupName", self.ctx.args.management_group_name, + required=True, + ), + **self.serialize_url_param( + "stageMapName", self.ctx.args.stage_map_name, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Content-Type", "application/json", + ), + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + @property + def content(self): + _content_value, _builder = self.new_content_builder( + self.ctx.args, + value=self.ctx.vars.instance, + ) + + return self.serialize_content(_content_value) + + def on_200_201(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200_201 + ) + + _schema_on_200_201 = None + + @classmethod + def _build_schema_on_200_201(cls): + if cls._schema_on_200_201 is not None: + return cls._schema_on_200_201 + + cls._schema_on_200_201 = AAZObjectType() + _UpdateHelper._build_schema_stage_map_read(cls._schema_on_200_201) + + return cls._schema_on_200_201 + + class StageMapsCreateOrUpdateAtSubscriptionLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200, 201]: + return self.on_200_201(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/stageMaps/{stageMapName}", + **self.url_parameters + ) + + @property + def method(self): + return "PUT" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "stageMapName", self.ctx.args.stage_map_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Content-Type", "application/json", + ), + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + @property + def content(self): + _content_value, _builder = self.new_content_builder( + self.ctx.args, + value=self.ctx.vars.instance, + ) + + return self.serialize_content(_content_value) + + def on_200_201(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200_201 + ) + + _schema_on_200_201 = None + + @classmethod + def _build_schema_on_200_201(cls): + if cls._schema_on_200_201 is not None: + return cls._schema_on_200_201 + + cls._schema_on_200_201 = AAZObjectType() + _UpdateHelper._build_schema_stage_map_read(cls._schema_on_200_201) + + return cls._schema_on_200_201 + + class InstanceUpdateByJson(AAZJsonInstanceUpdateOperation): + + def __call__(self, *args, **kwargs): + self._update_instance(self.ctx.vars.instance) + + def _update_instance(self, instance): + _instance_value, _builder = self.new_content_builder( + self.ctx.args, + value=instance, + typ=AAZObjectType + ) + _builder.set_prop("properties", AAZObjectType) + + properties = _builder.get(".properties") + if properties is not None: + properties.set_prop("parameters", AAZDictType, ".parameters") + properties.set_prop("stages", AAZListType, ".stages", typ_kwargs={"flags": {"required": True}}) + + parameters = _builder.get(".properties.parameters") + if parameters is not None: + parameters.set_elements(AAZObjectType, ".") + + _elements = _builder.get(".properties.parameters{}") + if _elements is not None: + _elements.set_prop("metadata", AAZDictType, ".metadata") + _elements.set_const("type", "array", AAZStrType, ".array", typ_kwargs={"flags": {"required": True}}) + _elements.set_const("type", "number", AAZStrType, ".number", typ_kwargs={"flags": {"required": True}}) + _elements.set_const("type", "object", AAZStrType, ".object", typ_kwargs={"flags": {"required": True}}) + _elements.set_const("type", "string", AAZStrType, ".string", typ_kwargs={"flags": {"required": True}}) + _elements.discriminate_by("type", "array") + _elements.discriminate_by("type", "number") + _elements.discriminate_by("type", "object") + _elements.discriminate_by("type", "string") + + metadata = _builder.get(".properties.parameters{}.metadata") + if metadata is not None: + metadata.set_elements(AAZStrType, ".") + + disc_array = _builder.get(".properties.parameters{}{type:array}") + if disc_array is not None: + disc_array.set_prop("allowedValues", AAZListType, ".array.allowed_values") + disc_array.set_prop("defaultValue", AAZListType, ".array.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:array}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZAnyType, ".") + + default_value = _builder.get(".properties.parameters{}{type:array}.defaultValue") + if default_value is not None: + default_value.set_elements(AAZAnyType, ".") + + disc_number = _builder.get(".properties.parameters{}{type:number}") + if disc_number is not None: + disc_number.set_prop("allowedValues", AAZListType, ".number.allowed_values") + disc_number.set_prop("defaultValue", AAZIntType, ".number.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:number}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZIntType, ".") + + disc_object = _builder.get(".properties.parameters{}{type:object}") + if disc_object is not None: + disc_object.set_prop("allowedValues", AAZListType, ".object.allowed_values") + disc_object.set_prop("defaultValue", AAZObjectType, ".object.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:object}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZDictType, ".") + + _elements = _builder.get(".properties.parameters{}{type:object}.allowedValues[]") + if _elements is not None: + _elements.set_elements(AAZAnyType, ".") + + disc_string = _builder.get(".properties.parameters{}{type:string}") + if disc_string is not None: + disc_string.set_prop("allowedValues", AAZListType, ".string.allowed_values") + disc_string.set_prop("defaultValue", AAZStrType, ".string.default_value") + + allowed_values = _builder.get(".properties.parameters{}{type:string}.allowedValues") + if allowed_values is not None: + allowed_values.set_elements(AAZStrType, ".") + + stages = _builder.get(".properties.stages") + if stages is not None: + stages.set_elements(AAZObjectType, ".") + + _elements = _builder.get(".properties.stages[]") + if _elements is not None: + _elements.set_prop("name", AAZStrType, ".name", typ_kwargs={"flags": {"required": True}}) + _elements.set_prop("nestedStageMap", AAZObjectType, ".nested_stage_map") + _elements.set_prop("sequence", AAZIntType, ".sequence", typ_kwargs={"flags": {"required": True}}) + _elements.set_prop("stageVariables", AAZDictType, ".stage_variables") + + nested_stage_map = _builder.get(".properties.stages[].nestedStageMap") + if nested_stage_map is not None: + nested_stage_map.set_prop("parameters", AAZDictType, ".parameters") + nested_stage_map.set_prop("resourceId", AAZStrType, ".resource_id") + + parameters = _builder.get(".properties.stages[].nestedStageMap.parameters") + if parameters is not None: + parameters.set_elements(AAZAnyType, ".") + + stage_variables = _builder.get(".properties.stages[].stageVariables") + if stage_variables is not None: + stage_variables.set_elements(AAZAnyType, ".") + + return _instance_value + + class InstanceUpdateByGeneric(AAZGenericInstanceUpdateOperation): + + def __call__(self, *args, **kwargs): + self._update_instance_by_generic( + self.ctx.vars.instance, + self.ctx.generic_update_args + ) + + +class _UpdateHelper: + """Helper class for Update""" + + _schema_stage_map_read = None + + @classmethod + def _build_schema_stage_map_read(cls, _schema): + if cls._schema_stage_map_read is not None: + _schema.id = cls._schema_stage_map_read.id + _schema.name = cls._schema_stage_map_read.name + _schema.properties = cls._schema_stage_map_read.properties + _schema.system_data = cls._schema_stage_map_read.system_data + _schema.type = cls._schema_stage_map_read.type + return + + cls._schema_stage_map_read = _schema_stage_map_read = AAZObjectType() + + stage_map_read = _schema_stage_map_read + stage_map_read.id = AAZStrType( + flags={"read_only": True}, + ) + stage_map_read.name = AAZStrType( + flags={"read_only": True}, + ) + stage_map_read.properties = AAZObjectType() + stage_map_read.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + stage_map_read.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = _schema_stage_map_read.properties + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.stages = AAZListType( + flags={"required": True}, + ) + + parameters = _schema_stage_map_read.properties.parameters + parameters.Element = AAZObjectType() + + _element = _schema_stage_map_read.properties.parameters.Element + _element.metadata = AAZDictType() + _element.type = AAZStrType( + flags={"required": True}, + ) + + metadata = _schema_stage_map_read.properties.parameters.Element.metadata + metadata.Element = AAZStrType() + + disc_array = _schema_stage_map_read.properties.parameters.Element.discriminate_by("type", "array") + disc_array.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_array.default_value = AAZListType( + serialized_name="defaultValue", + ) + + allowed_values = _schema_stage_map_read.properties.parameters.Element.discriminate_by("type", "array").allowed_values + allowed_values.Element = AAZAnyType() + + default_value = _schema_stage_map_read.properties.parameters.Element.discriminate_by("type", "array").default_value + default_value.Element = AAZAnyType() + + disc_number = _schema_stage_map_read.properties.parameters.Element.discriminate_by("type", "number") + disc_number.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_number.default_value = AAZIntType( + serialized_name="defaultValue", + ) + + allowed_values = _schema_stage_map_read.properties.parameters.Element.discriminate_by("type", "number").allowed_values + allowed_values.Element = AAZIntType() + + disc_object = _schema_stage_map_read.properties.parameters.Element.discriminate_by("type", "object") + disc_object.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_object.default_value = AAZObjectType( + serialized_name="defaultValue", + ) + + allowed_values = _schema_stage_map_read.properties.parameters.Element.discriminate_by("type", "object").allowed_values + allowed_values.Element = AAZDictType() + + _element = _schema_stage_map_read.properties.parameters.Element.discriminate_by("type", "object").allowed_values.Element + _element.Element = AAZAnyType() + + disc_string = _schema_stage_map_read.properties.parameters.Element.discriminate_by("type", "string") + disc_string.allowed_values = AAZListType( + serialized_name="allowedValues", + ) + disc_string.default_value = AAZStrType( + serialized_name="defaultValue", + ) + + allowed_values = _schema_stage_map_read.properties.parameters.Element.discriminate_by("type", "string").allowed_values + allowed_values.Element = AAZStrType() + + stages = _schema_stage_map_read.properties.stages + stages.Element = AAZObjectType() + + _element = _schema_stage_map_read.properties.stages.Element + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.nested_stage_map = AAZObjectType( + serialized_name="nestedStageMap", + ) + _element.sequence = AAZIntType( + flags={"required": True}, + ) + _element.stage_variables = AAZDictType( + serialized_name="stageVariables", + ) + + nested_stage_map = _schema_stage_map_read.properties.stages.Element.nested_stage_map + nested_stage_map.parameters = AAZDictType() + nested_stage_map.resource_id = AAZStrType( + serialized_name="resourceId", + ) + + parameters = _schema_stage_map_read.properties.stages.Element.nested_stage_map.parameters + parameters.Element = AAZAnyType() + + stage_variables = _schema_stage_map_read.properties.stages.Element.stage_variables + stage_variables.Element = AAZAnyType() + + system_data = _schema_stage_map_read.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + _schema.id = cls._schema_stage_map_read.id + _schema.name = cls._schema_stage_map_read.name + _schema.properties = cls._schema_stage_map_read.properties + _schema.system_data = cls._schema_stage_map_read.system_data + _schema.type = cls._schema_stage_map_read.type + + +__all__ = ["Update"] diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/__cmd_group.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/__cmd_group.py new file mode 100644 index 00000000000..ac53d653455 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/__cmd_group.py @@ -0,0 +1,23 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command_group( + "changesafety stageprogression", +) +class __CMDGroup(AAZCommandGroup): + """Manage Stage Progression + """ + pass + + +__all__ = ["__CMDGroup"] diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/__init__.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/__init__.py new file mode 100644 index 00000000000..c401f439385 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/__init__.py @@ -0,0 +1,16 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from .__cmd_group import * +from ._create import * +from ._delete import * +from ._list import * +from ._show import * +from ._update import * diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/_create.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/_create.py new file mode 100644 index 00000000000..48009803213 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/_create.py @@ -0,0 +1,581 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "changesafety stageprogression create", +) +class Create(AAZCommand): + """Create a StageProgression + """ + + _aaz_info = { + "version": "2026-01-01-preview", + "resources": [ + ["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/changerecords/{}/stageprogressions/{}", "2026-01-01-preview"], + ["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.changesafety/changerecords/{}/stageprogressions/{}", "2026-01-01-preview"], + ] + } + + def _handler(self, command_args): + super()._handler(command_args) + self._execute_operations() + return self._output() + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.change_record_name = AAZStrArg( + options=["--change-record-name"], + help="The name of the ChangeRecord resource.", + required=True, + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-]{3,100}$", + max_length=100, + min_length=3, + ), + ) + _args_schema.resource_group = AAZResourceGroupNameArg() + _args_schema.stage_progression_name = AAZStrArg( + options=["-n", "--name", "--stage-progression-name"], + help="Name of the stageProgression", + required=True, + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-|]{3,100}$", + max_length=100, + min_length=3, + ), + ) + + # define Arg Group "Properties" + + _args_schema = cls._args_schema + _args_schema.additional_data = AAZObjectArg( + options=["--additional-data"], + arg_group="Properties", + help="Additional metadata for the stageProgression resource.", + blank={}, + ) + _args_schema.comments = AAZStrArg( + options=["--comments"], + arg_group="Properties", + help="Comments about the update to the resource.", + fmt=AAZStrArgFormat( + max_length=2000, + ), + ) + _args_schema.links = AAZListArg( + options=["--links"], + arg_group="Properties", + help="Collection of related links for the change.", + ) + _args_schema.parameters = AAZDictArg( + options=["--parameters"], + arg_group="Properties", + help="Stage specific key value pairs of parameter names & their values for the current Stage, If any.", + ) + _args_schema.stage_reference = AAZStrArg( + options=["--stage-reference"], + arg_group="Properties", + help="Stage name relevant to hierarchical StageMap.", + fmt=AAZStrArgFormat( + max_length=200, + min_length=3, + ), + ) + _args_schema.stage_variables = AAZDictArg( + options=["--stage-variables"], + arg_group="Properties", + help="Variables to apply on the change of that stage. Key value pairs supporting any JSON values.", + ) + _args_schema.status = AAZStrArg( + options=["--status"], + arg_group="Properties", + help="StageProgression resource status.", + enum={"Cancelled": "Cancelled", "Completed": "Completed", "Failed": "Failed", "InProgress": "InProgress", "Initialized": "Initialized", "Paused": "Paused", "Skipped": "Skipped"}, + ) + + links = cls._args_schema.links + links.Element = AAZObjectArg() + + _element = cls._args_schema.links.Element + _element.description = AAZStrArg( + options=["description"], + help="Description or note about the link.", + fmt=AAZStrArgFormat( + max_length=2000, + ), + ) + _element.name = AAZStrArg( + options=["name"], + help="name of the link.", + required=True, + ) + _element.uri = AAZStrArg( + options=["uri"], + help="URL or comma separated URLs for the link.", + required=True, + ) + + parameters = cls._args_schema.parameters + parameters.Element = AAZAnyTypeArg() + + stage_variables = cls._args_schema.stage_variables + stage_variables.Element = AAZAnyTypeArg() + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + condition_0 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.args.stage_progression_name) and has_value(self.ctx.subscription_id) and has_value(self.ctx.args.resource_group) is not True + condition_1 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.args.resource_group) and has_value(self.ctx.args.stage_progression_name) and has_value(self.ctx.subscription_id) + if condition_0: + self.ChangeRecordStageProgressionsCreateOrUpdateAtSubscriptionLevel(ctx=self.ctx)() + if condition_1: + self.ChangeRecordStageProgressionsCreateOrUpdate(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + def _output(self, *args, **kwargs): + result = self.deserialize_output(self.ctx.vars.instance, client_flatten=True) + return result + + class ChangeRecordStageProgressionsCreateOrUpdateAtSubscriptionLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200, 201]: + return self.on_200_201(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}/stageProgressions/{stageProgressionName}", + **self.url_parameters + ) + + @property + def method(self): + return "PUT" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "stageProgressionName", self.ctx.args.stage_progression_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Content-Type", "application/json", + ), + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + @property + def content(self): + _content_value, _builder = self.new_content_builder( + self.ctx.args, + typ=AAZObjectType, + typ_kwargs={"flags": {"required": True, "client_flatten": True}} + ) + _builder.set_prop("properties", AAZObjectType) + + properties = _builder.get(".properties") + if properties is not None: + properties.set_prop("additionalData", AAZObjectType, ".additional_data") + properties.set_prop("comments", AAZStrType, ".comments") + properties.set_prop("links", AAZListType, ".links") + properties.set_prop("parameters", AAZDictType, ".parameters") + properties.set_prop("stageReference", AAZStrType, ".stage_reference", typ_kwargs={"flags": {"required": True}}) + properties.set_prop("stageVariables", AAZDictType, ".stage_variables") + properties.set_prop("status", AAZStrType, ".status", typ_kwargs={"flags": {"required": True}}) + + links = _builder.get(".properties.links") + if links is not None: + links.set_elements(AAZObjectType, ".") + + _elements = _builder.get(".properties.links[]") + if _elements is not None: + _elements.set_prop("description", AAZStrType, ".description") + _elements.set_prop("name", AAZStrType, ".name", typ_kwargs={"flags": {"required": True}}) + _elements.set_prop("uri", AAZStrType, ".uri", typ_kwargs={"flags": {"required": True}}) + + parameters = _builder.get(".properties.parameters") + if parameters is not None: + parameters.set_elements(AAZAnyType, ".") + + stage_variables = _builder.get(".properties.stageVariables") + if stage_variables is not None: + stage_variables.set_elements(AAZAnyType, ".") + + return self.serialize_content(_content_value) + + def on_200_201(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200_201 + ) + + _schema_on_200_201 = None + + @classmethod + def _build_schema_on_200_201(cls): + if cls._schema_on_200_201 is not None: + return cls._schema_on_200_201 + + cls._schema_on_200_201 = AAZObjectType() + + _schema_on_200_201 = cls._schema_on_200_201 + _schema_on_200_201.id = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200_201.name = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200_201.properties = AAZObjectType() + _schema_on_200_201.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _schema_on_200_201.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200_201.properties + properties.additional_data = AAZObjectType( + serialized_name="additionalData", + ) + properties.comments = AAZStrType() + properties.links = AAZListType() + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.sequence = AAZIntType( + flags={"read_only": True}, + ) + properties.stage_reference = AAZStrType( + serialized_name="stageReference", + flags={"required": True}, + ) + properties.stage_variables = AAZDictType( + serialized_name="stageVariables", + ) + properties.status = AAZStrType( + flags={"required": True}, + ) + + links = cls._schema_on_200_201.properties.links + links.Element = AAZObjectType() + + _element = cls._schema_on_200_201.properties.links.Element + _element.description = AAZStrType() + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.uri = AAZStrType( + flags={"required": True}, + ) + + parameters = cls._schema_on_200_201.properties.parameters + parameters.Element = AAZAnyType() + + stage_variables = cls._schema_on_200_201.properties.stage_variables + stage_variables.Element = AAZAnyType() + + system_data = cls._schema_on_200_201.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200_201 + + class ChangeRecordStageProgressionsCreateOrUpdate(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200, 201]: + return self.on_200_201(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}/stageProgressions/{stageProgressionName}", + **self.url_parameters + ) + + @property + def method(self): + return "PUT" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "resourceGroupName", self.ctx.args.resource_group, + required=True, + ), + **self.serialize_url_param( + "stageProgressionName", self.ctx.args.stage_progression_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Content-Type", "application/json", + ), + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + @property + def content(self): + _content_value, _builder = self.new_content_builder( + self.ctx.args, + typ=AAZObjectType, + typ_kwargs={"flags": {"required": True, "client_flatten": True}} + ) + _builder.set_prop("properties", AAZObjectType) + + properties = _builder.get(".properties") + if properties is not None: + properties.set_prop("additionalData", AAZObjectType, ".additional_data") + properties.set_prop("comments", AAZStrType, ".comments") + properties.set_prop("links", AAZListType, ".links") + properties.set_prop("parameters", AAZDictType, ".parameters") + properties.set_prop("stageReference", AAZStrType, ".stage_reference", typ_kwargs={"flags": {"required": True}}) + properties.set_prop("stageVariables", AAZDictType, ".stage_variables") + properties.set_prop("status", AAZStrType, ".status", typ_kwargs={"flags": {"required": True}}) + + links = _builder.get(".properties.links") + if links is not None: + links.set_elements(AAZObjectType, ".") + + _elements = _builder.get(".properties.links[]") + if _elements is not None: + _elements.set_prop("description", AAZStrType, ".description") + _elements.set_prop("name", AAZStrType, ".name", typ_kwargs={"flags": {"required": True}}) + _elements.set_prop("uri", AAZStrType, ".uri", typ_kwargs={"flags": {"required": True}}) + + parameters = _builder.get(".properties.parameters") + if parameters is not None: + parameters.set_elements(AAZAnyType, ".") + + stage_variables = _builder.get(".properties.stageVariables") + if stage_variables is not None: + stage_variables.set_elements(AAZAnyType, ".") + + return self.serialize_content(_content_value) + + def on_200_201(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200_201 + ) + + _schema_on_200_201 = None + + @classmethod + def _build_schema_on_200_201(cls): + if cls._schema_on_200_201 is not None: + return cls._schema_on_200_201 + + cls._schema_on_200_201 = AAZObjectType() + + _schema_on_200_201 = cls._schema_on_200_201 + _schema_on_200_201.id = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200_201.name = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200_201.properties = AAZObjectType() + _schema_on_200_201.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _schema_on_200_201.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200_201.properties + properties.additional_data = AAZObjectType( + serialized_name="additionalData", + ) + properties.comments = AAZStrType() + properties.links = AAZListType() + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.sequence = AAZIntType( + flags={"read_only": True}, + ) + properties.stage_reference = AAZStrType( + serialized_name="stageReference", + flags={"required": True}, + ) + properties.stage_variables = AAZDictType( + serialized_name="stageVariables", + ) + properties.status = AAZStrType( + flags={"required": True}, + ) + + links = cls._schema_on_200_201.properties.links + links.Element = AAZObjectType() + + _element = cls._schema_on_200_201.properties.links.Element + _element.description = AAZStrType() + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.uri = AAZStrType( + flags={"required": True}, + ) + + parameters = cls._schema_on_200_201.properties.parameters + parameters.Element = AAZAnyType() + + stage_variables = cls._schema_on_200_201.properties.stage_variables + stage_variables.Element = AAZAnyType() + + system_data = cls._schema_on_200_201.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200_201 + + +class _CreateHelper: + """Helper class for Create""" + + +__all__ = ["Create"] diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/_delete.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/_delete.py new file mode 100644 index 00000000000..3b971b1196c --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/_delete.py @@ -0,0 +1,222 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "changesafety stageprogression delete", + confirmation="Are you sure you want to perform this operation?", +) +class Delete(AAZCommand): + """Delete a StageProgression + """ + + _aaz_info = { + "version": "2026-01-01-preview", + "resources": [ + ["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/changerecords/{}/stageprogressions/{}", "2026-01-01-preview"], + ["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.changesafety/changerecords/{}/stageprogressions/{}", "2026-01-01-preview"], + ] + } + + def _handler(self, command_args): + super()._handler(command_args) + self._execute_operations() + return None + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.change_record_name = AAZStrArg( + options=["--change-record-name"], + help="The name of the ChangeRecord resource.", + required=True, + id_part="name", + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-]{3,100}$", + max_length=100, + min_length=3, + ), + ) + _args_schema.resource_group = AAZResourceGroupNameArg() + _args_schema.stage_progression_name = AAZStrArg( + options=["-n", "--name", "--stage-progression-name"], + help="Name of the stageProgression", + required=True, + id_part="child_name_1", + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-|]{3,100}$", + max_length=100, + min_length=3, + ), + ) + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + condition_0 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.args.stage_progression_name) and has_value(self.ctx.subscription_id) and has_value(self.ctx.args.resource_group) is not True + condition_1 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.args.resource_group) and has_value(self.ctx.args.stage_progression_name) and has_value(self.ctx.subscription_id) + if condition_0: + self.ChangeRecordStageProgressionsDeleteAtSubscriptionLevel(ctx=self.ctx)() + if condition_1: + self.ChangeRecordStageProgressionsDelete(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + class ChangeRecordStageProgressionsDeleteAtSubscriptionLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + if session.http_response.status_code in [204]: + return self.on_204(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}/stageProgressions/{stageProgressionName}", + **self.url_parameters + ) + + @property + def method(self): + return "DELETE" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "stageProgressionName", self.ctx.args.stage_progression_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + def on_200(self, session): + pass + + def on_204(self, session): + pass + + class ChangeRecordStageProgressionsDelete(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + if session.http_response.status_code in [204]: + return self.on_204(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}/stageProgressions/{stageProgressionName}", + **self.url_parameters + ) + + @property + def method(self): + return "DELETE" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "resourceGroupName", self.ctx.args.resource_group, + required=True, + ), + **self.serialize_url_param( + "stageProgressionName", self.ctx.args.stage_progression_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + def on_200(self, session): + pass + + def on_204(self, session): + pass + + +class _DeleteHelper: + """Helper class for Delete""" + + +__all__ = ["Delete"] diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/_list.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/_list.py new file mode 100644 index 00000000000..790dc494f4e --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/_list.py @@ -0,0 +1,427 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "changesafety stageprogression list", +) +class List(AAZCommand): + """List StageProgression resources by ChangeRecord + """ + + _aaz_info = { + "version": "2026-01-01-preview", + "resources": [ + ["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/changerecords/{}/stageprogressions", "2026-01-01-preview"], + ["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.changesafety/changerecords/{}/stageprogressions", "2026-01-01-preview"], + ] + } + + AZ_SUPPORT_PAGINATION = True + + def _handler(self, command_args): + super()._handler(command_args) + return self.build_paging(self._execute_operations, self._output) + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.change_record_name = AAZStrArg( + options=["--change-record-name"], + help="The name of the ChangeRecord resource.", + required=True, + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-]{3,100}$", + max_length=100, + min_length=3, + ), + ) + _args_schema.resource_group = AAZResourceGroupNameArg() + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + condition_0 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.subscription_id) and has_value(self.ctx.args.resource_group) is not True + condition_1 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.args.resource_group) and has_value(self.ctx.subscription_id) + if condition_0: + self.ChangeRecordStageProgressionsListByParentAtSubscriptionLevel(ctx=self.ctx)() + if condition_1: + self.ChangeRecordStageProgressionsListByParent(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + def _output(self, *args, **kwargs): + result = self.deserialize_output(self.ctx.vars.instance.value, client_flatten=True) + next_link = self.deserialize_output(self.ctx.vars.instance.next_link) + return result, next_link + + class ChangeRecordStageProgressionsListByParentAtSubscriptionLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}/stageProgressions", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + + _schema_on_200 = cls._schema_on_200 + _schema_on_200.next_link = AAZStrType( + serialized_name="nextLink", + ) + _schema_on_200.value = AAZListType( + flags={"required": True}, + ) + + value = cls._schema_on_200.value + value.Element = AAZObjectType() + + _element = cls._schema_on_200.value.Element + _element.id = AAZStrType( + flags={"read_only": True}, + ) + _element.name = AAZStrType( + flags={"read_only": True}, + ) + _element.properties = AAZObjectType() + _element.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _element.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200.value.Element.properties + properties.additional_data = AAZObjectType( + serialized_name="additionalData", + ) + properties.comments = AAZStrType() + properties.links = AAZListType() + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.sequence = AAZIntType( + flags={"read_only": True}, + ) + properties.stage_reference = AAZStrType( + serialized_name="stageReference", + flags={"required": True}, + ) + properties.stage_variables = AAZDictType( + serialized_name="stageVariables", + ) + properties.status = AAZStrType( + flags={"required": True}, + ) + + links = cls._schema_on_200.value.Element.properties.links + links.Element = AAZObjectType() + + _element = cls._schema_on_200.value.Element.properties.links.Element + _element.description = AAZStrType() + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.uri = AAZStrType( + flags={"required": True}, + ) + + parameters = cls._schema_on_200.value.Element.properties.parameters + parameters.Element = AAZAnyType() + + stage_variables = cls._schema_on_200.value.Element.properties.stage_variables + stage_variables.Element = AAZAnyType() + + system_data = cls._schema_on_200.value.Element.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200 + + class ChangeRecordStageProgressionsListByParent(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}/stageProgressions", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "resourceGroupName", self.ctx.args.resource_group, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + + _schema_on_200 = cls._schema_on_200 + _schema_on_200.next_link = AAZStrType( + serialized_name="nextLink", + ) + _schema_on_200.value = AAZListType( + flags={"required": True}, + ) + + value = cls._schema_on_200.value + value.Element = AAZObjectType() + + _element = cls._schema_on_200.value.Element + _element.id = AAZStrType( + flags={"read_only": True}, + ) + _element.name = AAZStrType( + flags={"read_only": True}, + ) + _element.properties = AAZObjectType() + _element.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _element.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200.value.Element.properties + properties.additional_data = AAZObjectType( + serialized_name="additionalData", + ) + properties.comments = AAZStrType() + properties.links = AAZListType() + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.sequence = AAZIntType( + flags={"read_only": True}, + ) + properties.stage_reference = AAZStrType( + serialized_name="stageReference", + flags={"required": True}, + ) + properties.stage_variables = AAZDictType( + serialized_name="stageVariables", + ) + properties.status = AAZStrType( + flags={"required": True}, + ) + + links = cls._schema_on_200.value.Element.properties.links + links.Element = AAZObjectType() + + _element = cls._schema_on_200.value.Element.properties.links.Element + _element.description = AAZStrType() + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.uri = AAZStrType( + flags={"required": True}, + ) + + parameters = cls._schema_on_200.value.Element.properties.parameters + parameters.Element = AAZAnyType() + + stage_variables = cls._schema_on_200.value.Element.properties.stage_variables + stage_variables.Element = AAZAnyType() + + system_data = cls._schema_on_200.value.Element.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200 + + +class _ListHelper: + """Helper class for List""" + + +__all__ = ["List"] diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/_show.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/_show.py new file mode 100644 index 00000000000..5eea4109963 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/_show.py @@ -0,0 +1,423 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "changesafety stageprogression show", +) +class Show(AAZCommand): + """Get a StageProgression + """ + + _aaz_info = { + "version": "2026-01-01-preview", + "resources": [ + ["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/changerecords/{}/stageprogressions/{}", "2026-01-01-preview"], + ["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.changesafety/changerecords/{}/stageprogressions/{}", "2026-01-01-preview"], + ] + } + + def _handler(self, command_args): + super()._handler(command_args) + self._execute_operations() + return self._output() + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.change_record_name = AAZStrArg( + options=["--change-record-name"], + help="The name of the ChangeRecord resource.", + required=True, + id_part="name", + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-]{3,100}$", + max_length=100, + min_length=3, + ), + ) + _args_schema.resource_group = AAZResourceGroupNameArg() + _args_schema.stage_progression_name = AAZStrArg( + options=["-n", "--name", "--stage-progression-name"], + help="Name of the stageProgression", + required=True, + id_part="child_name_1", + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-|]{3,100}$", + max_length=100, + min_length=3, + ), + ) + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + condition_0 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.args.stage_progression_name) and has_value(self.ctx.subscription_id) and has_value(self.ctx.args.resource_group) is not True + condition_1 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.args.resource_group) and has_value(self.ctx.args.stage_progression_name) and has_value(self.ctx.subscription_id) + if condition_0: + self.ChangeRecordStageProgressionsGetAtSubscriptionLevel(ctx=self.ctx)() + if condition_1: + self.ChangeRecordStageProgressionsGet(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + def _output(self, *args, **kwargs): + result = self.deserialize_output(self.ctx.vars.instance, client_flatten=True) + return result + + class ChangeRecordStageProgressionsGetAtSubscriptionLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}/stageProgressions/{stageProgressionName}", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "stageProgressionName", self.ctx.args.stage_progression_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + + _schema_on_200 = cls._schema_on_200 + _schema_on_200.id = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200.name = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200.properties = AAZObjectType() + _schema_on_200.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _schema_on_200.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200.properties + properties.additional_data = AAZObjectType( + serialized_name="additionalData", + ) + properties.comments = AAZStrType() + properties.links = AAZListType() + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.sequence = AAZIntType( + flags={"read_only": True}, + ) + properties.stage_reference = AAZStrType( + serialized_name="stageReference", + flags={"required": True}, + ) + properties.stage_variables = AAZDictType( + serialized_name="stageVariables", + ) + properties.status = AAZStrType( + flags={"required": True}, + ) + + links = cls._schema_on_200.properties.links + links.Element = AAZObjectType() + + _element = cls._schema_on_200.properties.links.Element + _element.description = AAZStrType() + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.uri = AAZStrType( + flags={"required": True}, + ) + + parameters = cls._schema_on_200.properties.parameters + parameters.Element = AAZAnyType() + + stage_variables = cls._schema_on_200.properties.stage_variables + stage_variables.Element = AAZAnyType() + + system_data = cls._schema_on_200.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200 + + class ChangeRecordStageProgressionsGet(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}/stageProgressions/{stageProgressionName}", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "resourceGroupName", self.ctx.args.resource_group, + required=True, + ), + **self.serialize_url_param( + "stageProgressionName", self.ctx.args.stage_progression_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + + _schema_on_200 = cls._schema_on_200 + _schema_on_200.id = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200.name = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200.properties = AAZObjectType() + _schema_on_200.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _schema_on_200.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200.properties + properties.additional_data = AAZObjectType( + serialized_name="additionalData", + ) + properties.comments = AAZStrType() + properties.links = AAZListType() + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.sequence = AAZIntType( + flags={"read_only": True}, + ) + properties.stage_reference = AAZStrType( + serialized_name="stageReference", + flags={"required": True}, + ) + properties.stage_variables = AAZDictType( + serialized_name="stageVariables", + ) + properties.status = AAZStrType( + flags={"required": True}, + ) + + links = cls._schema_on_200.properties.links + links.Element = AAZObjectType() + + _element = cls._schema_on_200.properties.links.Element + _element.description = AAZStrType() + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.uri = AAZStrType( + flags={"required": True}, + ) + + parameters = cls._schema_on_200.properties.parameters + parameters.Element = AAZAnyType() + + stage_variables = cls._schema_on_200.properties.stage_variables + stage_variables.Element = AAZAnyType() + + system_data = cls._schema_on_200.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200 + + +class _ShowHelper: + """Helper class for Show""" + + +__all__ = ["Show"] diff --git a/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/_update.py b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/_update.py new file mode 100644 index 00000000000..842b1532800 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/_update.py @@ -0,0 +1,717 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "changesafety stageprogression update", +) +class Update(AAZCommand): + """Update a StageProgression + """ + + _aaz_info = { + "version": "2026-01-01-preview", + "resources": [ + ["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/changerecords/{}/stageprogressions/{}", "2026-01-01-preview"], + ["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.changesafety/changerecords/{}/stageprogressions/{}", "2026-01-01-preview"], + ] + } + + AZ_SUPPORT_GENERIC_UPDATE = True + + def _handler(self, command_args): + super()._handler(command_args) + self._execute_operations() + return self._output() + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.change_record_name = AAZStrArg( + options=["--change-record-name"], + help="The name of the ChangeRecord resource.", + required=True, + id_part="name", + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-]{3,100}$", + max_length=100, + min_length=3, + ), + ) + _args_schema.resource_group = AAZResourceGroupNameArg() + _args_schema.stage_progression_name = AAZStrArg( + options=["-n", "--name", "--stage-progression-name"], + help="Name of the stageProgression", + required=True, + id_part="child_name_1", + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9-|]{3,100}$", + max_length=100, + min_length=3, + ), + ) + + # define Arg Group "Properties" + + _args_schema = cls._args_schema + _args_schema.additional_data = AAZObjectArg( + options=["--additional-data"], + arg_group="Properties", + help="Additional metadata for the stageProgression resource.", + nullable=True, + blank={}, + ) + _args_schema.comments = AAZStrArg( + options=["--comments"], + arg_group="Properties", + help="Comments about the update to the resource.", + nullable=True, + fmt=AAZStrArgFormat( + max_length=2000, + ), + ) + _args_schema.links = AAZListArg( + options=["--links"], + arg_group="Properties", + help="Collection of related links for the change.", + nullable=True, + ) + _args_schema.parameters = AAZDictArg( + options=["--parameters"], + arg_group="Properties", + help="Stage specific key value pairs of parameter names & their values for the current Stage, If any.", + nullable=True, + ) + _args_schema.stage_reference = AAZStrArg( + options=["--stage-reference"], + arg_group="Properties", + help="Stage name relevant to hierarchical StageMap.", + fmt=AAZStrArgFormat( + max_length=200, + min_length=3, + ), + ) + _args_schema.stage_variables = AAZDictArg( + options=["--stage-variables"], + arg_group="Properties", + help="Variables to apply on the change of that stage. Key value pairs supporting any JSON values.", + nullable=True, + ) + _args_schema.status = AAZStrArg( + options=["--status"], + arg_group="Properties", + help="StageProgression resource status.", + enum={"Cancelled": "Cancelled", "Completed": "Completed", "Failed": "Failed", "InProgress": "InProgress", "Initialized": "Initialized", "Paused": "Paused", "Skipped": "Skipped"}, + ) + + links = cls._args_schema.links + links.Element = AAZObjectArg( + nullable=True, + ) + + _element = cls._args_schema.links.Element + _element.description = AAZStrArg( + options=["description"], + help="Description or note about the link.", + nullable=True, + fmt=AAZStrArgFormat( + max_length=2000, + ), + ) + _element.name = AAZStrArg( + options=["name"], + help="name of the link.", + ) + _element.uri = AAZStrArg( + options=["uri"], + help="URL or comma separated URLs for the link.", + ) + + parameters = cls._args_schema.parameters + parameters.Element = AAZAnyTypeArg( + nullable=True, + ) + + stage_variables = cls._args_schema.stage_variables + stage_variables.Element = AAZAnyTypeArg( + nullable=True, + ) + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + condition_0 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.args.stage_progression_name) and has_value(self.ctx.subscription_id) and has_value(self.ctx.args.resource_group) is not True + condition_1 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.args.resource_group) and has_value(self.ctx.args.stage_progression_name) and has_value(self.ctx.subscription_id) + condition_2 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.args.stage_progression_name) and has_value(self.ctx.subscription_id) and has_value(self.ctx.args.resource_group) is not True + condition_3 = has_value(self.ctx.args.change_record_name) and has_value(self.ctx.args.resource_group) and has_value(self.ctx.args.stage_progression_name) and has_value(self.ctx.subscription_id) + if condition_0: + self.ChangeRecordStageProgressionsGetAtSubscriptionLevel(ctx=self.ctx)() + if condition_1: + self.ChangeRecordStageProgressionsGet(ctx=self.ctx)() + self.pre_instance_update(self.ctx.vars.instance) + self.InstanceUpdateByJson(ctx=self.ctx)() + self.InstanceUpdateByGeneric(ctx=self.ctx)() + self.post_instance_update(self.ctx.vars.instance) + if condition_2: + self.ChangeRecordStageProgressionsCreateOrUpdateAtSubscriptionLevel(ctx=self.ctx)() + if condition_3: + self.ChangeRecordStageProgressionsCreateOrUpdate(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + @register_callback + def pre_instance_update(self, instance): + pass + + @register_callback + def post_instance_update(self, instance): + pass + + def _output(self, *args, **kwargs): + result = self.deserialize_output(self.ctx.vars.instance, client_flatten=True) + return result + + class ChangeRecordStageProgressionsGetAtSubscriptionLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}/stageProgressions/{stageProgressionName}", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "stageProgressionName", self.ctx.args.stage_progression_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + _UpdateHelper._build_schema_change_record_stage_progression_read(cls._schema_on_200) + + return cls._schema_on_200 + + class ChangeRecordStageProgressionsGet(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}/stageProgressions/{stageProgressionName}", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "resourceGroupName", self.ctx.args.resource_group, + required=True, + ), + **self.serialize_url_param( + "stageProgressionName", self.ctx.args.stage_progression_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + _UpdateHelper._build_schema_change_record_stage_progression_read(cls._schema_on_200) + + return cls._schema_on_200 + + class ChangeRecordStageProgressionsCreateOrUpdateAtSubscriptionLevel(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200, 201]: + return self.on_200_201(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}/stageProgressions/{stageProgressionName}", + **self.url_parameters + ) + + @property + def method(self): + return "PUT" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "stageProgressionName", self.ctx.args.stage_progression_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Content-Type", "application/json", + ), + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + @property + def content(self): + _content_value, _builder = self.new_content_builder( + self.ctx.args, + value=self.ctx.vars.instance, + ) + + return self.serialize_content(_content_value) + + def on_200_201(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200_201 + ) + + _schema_on_200_201 = None + + @classmethod + def _build_schema_on_200_201(cls): + if cls._schema_on_200_201 is not None: + return cls._schema_on_200_201 + + cls._schema_on_200_201 = AAZObjectType() + _UpdateHelper._build_schema_change_record_stage_progression_read(cls._schema_on_200_201) + + return cls._schema_on_200_201 + + class ChangeRecordStageProgressionsCreateOrUpdate(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200, 201]: + return self.on_200_201(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}/stageProgressions/{stageProgressionName}", + **self.url_parameters + ) + + @property + def method(self): + return "PUT" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "changeRecordName", self.ctx.args.change_record_name, + required=True, + ), + **self.serialize_url_param( + "resourceGroupName", self.ctx.args.resource_group, + required=True, + ), + **self.serialize_url_param( + "stageProgressionName", self.ctx.args.stage_progression_name, + required=True, + ), + **self.serialize_url_param( + "subscriptionId", self.ctx.subscription_id, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2026-01-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Content-Type", "application/json", + ), + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + @property + def content(self): + _content_value, _builder = self.new_content_builder( + self.ctx.args, + value=self.ctx.vars.instance, + ) + + return self.serialize_content(_content_value) + + def on_200_201(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200_201 + ) + + _schema_on_200_201 = None + + @classmethod + def _build_schema_on_200_201(cls): + if cls._schema_on_200_201 is not None: + return cls._schema_on_200_201 + + cls._schema_on_200_201 = AAZObjectType() + _UpdateHelper._build_schema_change_record_stage_progression_read(cls._schema_on_200_201) + + return cls._schema_on_200_201 + + class InstanceUpdateByJson(AAZJsonInstanceUpdateOperation): + + def __call__(self, *args, **kwargs): + self._update_instance(self.ctx.vars.instance) + + def _update_instance(self, instance): + _instance_value, _builder = self.new_content_builder( + self.ctx.args, + value=instance, + typ=AAZObjectType + ) + _builder.set_prop("properties", AAZObjectType) + + properties = _builder.get(".properties") + if properties is not None: + properties.set_prop("additionalData", AAZObjectType, ".additional_data") + properties.set_prop("comments", AAZStrType, ".comments") + properties.set_prop("links", AAZListType, ".links") + properties.set_prop("parameters", AAZDictType, ".parameters") + properties.set_prop("stageReference", AAZStrType, ".stage_reference", typ_kwargs={"flags": {"required": True}}) + properties.set_prop("stageVariables", AAZDictType, ".stage_variables") + properties.set_prop("status", AAZStrType, ".status", typ_kwargs={"flags": {"required": True}}) + + links = _builder.get(".properties.links") + if links is not None: + links.set_elements(AAZObjectType, ".") + + _elements = _builder.get(".properties.links[]") + if _elements is not None: + _elements.set_prop("description", AAZStrType, ".description") + _elements.set_prop("name", AAZStrType, ".name", typ_kwargs={"flags": {"required": True}}) + _elements.set_prop("uri", AAZStrType, ".uri", typ_kwargs={"flags": {"required": True}}) + + parameters = _builder.get(".properties.parameters") + if parameters is not None: + parameters.set_elements(AAZAnyType, ".") + + stage_variables = _builder.get(".properties.stageVariables") + if stage_variables is not None: + stage_variables.set_elements(AAZAnyType, ".") + + return _instance_value + + class InstanceUpdateByGeneric(AAZGenericInstanceUpdateOperation): + + def __call__(self, *args, **kwargs): + self._update_instance_by_generic( + self.ctx.vars.instance, + self.ctx.generic_update_args + ) + + +class _UpdateHelper: + """Helper class for Update""" + + _schema_change_record_stage_progression_read = None + + @classmethod + def _build_schema_change_record_stage_progression_read(cls, _schema): + if cls._schema_change_record_stage_progression_read is not None: + _schema.id = cls._schema_change_record_stage_progression_read.id + _schema.name = cls._schema_change_record_stage_progression_read.name + _schema.properties = cls._schema_change_record_stage_progression_read.properties + _schema.system_data = cls._schema_change_record_stage_progression_read.system_data + _schema.type = cls._schema_change_record_stage_progression_read.type + return + + cls._schema_change_record_stage_progression_read = _schema_change_record_stage_progression_read = AAZObjectType() + + change_record_stage_progression_read = _schema_change_record_stage_progression_read + change_record_stage_progression_read.id = AAZStrType( + flags={"read_only": True}, + ) + change_record_stage_progression_read.name = AAZStrType( + flags={"read_only": True}, + ) + change_record_stage_progression_read.properties = AAZObjectType() + change_record_stage_progression_read.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + change_record_stage_progression_read.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = _schema_change_record_stage_progression_read.properties + properties.additional_data = AAZObjectType( + serialized_name="additionalData", + ) + properties.comments = AAZStrType() + properties.links = AAZListType() + properties.parameters = AAZDictType() + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.sequence = AAZIntType( + flags={"read_only": True}, + ) + properties.stage_reference = AAZStrType( + serialized_name="stageReference", + flags={"required": True}, + ) + properties.stage_variables = AAZDictType( + serialized_name="stageVariables", + ) + properties.status = AAZStrType( + flags={"required": True}, + ) + + links = _schema_change_record_stage_progression_read.properties.links + links.Element = AAZObjectType() + + _element = _schema_change_record_stage_progression_read.properties.links.Element + _element.description = AAZStrType() + _element.name = AAZStrType( + flags={"required": True}, + ) + _element.uri = AAZStrType( + flags={"required": True}, + ) + + parameters = _schema_change_record_stage_progression_read.properties.parameters + parameters.Element = AAZAnyType() + + stage_variables = _schema_change_record_stage_progression_read.properties.stage_variables + stage_variables.Element = AAZAnyType() + + system_data = _schema_change_record_stage_progression_read.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + _schema.id = cls._schema_change_record_stage_progression_read.id + _schema.name = cls._schema_change_record_stage_progression_read.name + _schema.properties = cls._schema_change_record_stage_progression_read.properties + _schema.system_data = cls._schema_change_record_stage_progression_read.system_data + _schema.type = cls._schema_change_record_stage_progression_read.type + + +__all__ = ["Update"] diff --git a/src/azure-changesafety/azext_changesafety/azext_metadata.json b/src/azure-changesafety/azext_changesafety/azext_metadata.json new file mode 100644 index 00000000000..71889bb136b --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/azext_metadata.json @@ -0,0 +1,4 @@ +{ + "azext.isPreview": true, + "azext.minCliCoreVersion": "2.75.0" +} \ No newline at end of file diff --git a/src/azure-changesafety/azext_changesafety/commands.py b/src/azure-changesafety/azext_changesafety/commands.py new file mode 100644 index 00000000000..c9322712e93 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/commands.py @@ -0,0 +1,22 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: disable=too-many-lines +# pylint: disable=too-many-statements + +def load_command_table(self, _): # pylint: disable=unused-argument + from .custom import ChangeRecordCreate, ChangeRecordUpdate, ChangeRecordDelete, ChangeRecordShow + + create_command = ChangeRecordCreate(loader=self) + update_command = ChangeRecordUpdate(loader=self) + delete_command = ChangeRecordDelete(loader=self) + show_command = ChangeRecordShow(loader=self) + + self.command_table['changesafety changerecord create'] = create_command + self.command_table['changesafety changerecord update'] = update_command + self.command_table['changesafety changerecord delete'] = delete_command + self.command_table['changesafety changerecord show'] = show_command diff --git a/src/azure-changesafety/azext_changesafety/custom.py b/src/azure-changesafety/azext_changesafety/custom.py new file mode 100644 index 00000000000..c13f4d0791d --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/custom.py @@ -0,0 +1,954 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: disable=line-too-long + +"""Custom command overrides for azure-changesafety CLI extension. + +This module provides customizations for ChangeRecord CRUD operations: +- ChangeRecordCreate: Custom --targets parsing, --stagemap-name shortcut, schedule defaults +- ChangeRecordUpdate: Preserves changeDefinition during GET+PUT cycle (AAZ schema workaround) +- ChangeRecordShow: Custom schema to expose details.targets array +- ChangeRecordDelete: Help examples only +""" + +import datetime +from argparse import SUPPRESS + +from knack.log import get_logger +from azure.cli.core.aaz import ( + has_value, + AAZAnyType, + AAZAnyTypeArg, + AAZListArg, + AAZStrArg, + AAZObjectType, + AAZStrType, + AAZListType, +) +from azure.cli.core.aaz._arg_action import ( # pylint: disable=protected-access + AAZArgActionOperations, + AAZPromptInputOperation, + _ELEMENT_APPEND_KEY, +) +from azure.cli.core.azclierror import InvalidArgumentValueError +from azext_changesafety.aaz.latest.changesafety.changerecord import ( + Create as _ChangeRecordCreate, + Update as _ChangeRecordUpdate, + Show as _ChangeRecordShow, + Delete as _ChangeRecordDelete, +) +# Import for schema building - used by _build_custom_show_schema +from azext_changesafety.aaz.latest.changesafety.changerecord._show import ( + Show as _GeneratedShow, +) + + +logger = get_logger(__name__) + +# ----------------------------------------------------------------------------- +# Constants +# ----------------------------------------------------------------------------- +CHANGE_DEFINITION_KIND_TARGETS = "Targets" +CHANGE_DEFINITION_KIND_API_OPERATIONS = "ApiOperations" + +# Mapping of user-friendly key names to API field names for --targets parsing +TARGET_KEY_MAPPING = { + 'resourceid': 'resourceId', + 'subscriptionid': 'subscriptionId', + 'resourcegroupname': 'resourceGroupName', + 'resourcegroup': 'resourceGroupName', + 'rg': 'resourceGroupName', + 'resourcetype': 'resourceType', + 'resourcename': 'resourceName', + 'httpmethod': 'httpMethod', + 'method': 'httpMethod', + 'operation': 'httpMethod', +} + + +# ----------------------------------------------------------------------------- +# Helper Functions +# ----------------------------------------------------------------------------- + +def _build_any_type(): + """Return an AAZAnyType instance for schema_builder callbacks. + + This is needed because schema_builder expects a callable that returns a schema type. + Using a function instead of a lambda keeps linters happy. + """ + return AAZAnyType() + + +def _apply_stage_map_shortcut(ctx): + """Translate --stagemap-name into the stage_map resourceId payload. + + This shared helper allows users to specify just the StageMap name instead of + the full resource ID. It builds the resource ID using the current subscription. + + Args: + ctx: The AAZ command context containing args and subscription_id. + + Raises: + InvalidArgumentValueError: If both --stage-map and --stagemap-name are provided, + or if subscription_id is not available. + """ + stage_map_arg = getattr(ctx.args, "stage_map", None) + stage_map_name_arg = getattr(ctx.args, "stagemap_name", None) + has_stage_map = has_value(stage_map_arg) + has_stage_map_name = has_value(stage_map_name_arg) + + if has_stage_map and has_stage_map_name: + raise InvalidArgumentValueError( + "Use either --stage-map or --stagemap-name/--stage-map-name, not both." + ) + + if not has_stage_map_name: + return + + subscription_id = getattr(ctx, "subscription_id", None) + if not subscription_id: + raise InvalidArgumentValueError( + "A subscription is required to resolve the StageMap scope." + ) + + resource_id = ( + f"/subscriptions/{subscription_id}/providers/" + f"Microsoft.ChangeSafety/stageMaps/{stage_map_name_arg.to_serialized_data()}" + ) + logger.debug("Resolved StageMap resourceId from name: %s", resource_id) + ctx.args.stage_map = {"resource_id": resource_id} + + +def _inject_change_definition_into_content(content, ctx): + """Attach the computed changeDefinition payload to the serialized request content.""" + change_definition_value = getattr(ctx.vars, "change_definition", None) + if change_definition_value is None: + return content + + change_definition = change_definition_value.to_serialized_data() + if not change_definition: + return content + + if content is None: + content = {} + properties = content.setdefault("properties", {}) + properties["changeDefinition"] = change_definition + return content + + +def _preserve_change_definition_in_content(content, ctx): + """Preserve the original changeDefinition from GET response in the update request. + + The changeDefinition cannot be modified after creation, so we must preserve + the original value from the GET response to avoid sending an empty/invalid + changeDefinition in the PUT request. + """ + if content is None: + return content + + # Get the original changeDefinition captured from the raw GET response + original_change_definition = getattr(ctx, "_original_change_definition", None) + + if original_change_definition is not None: + properties = content.get("properties") + if properties is not None: + # Replace the corrupted changeDefinition with the original from the GET response + properties["changeDefinition"] = original_change_definition + logger.debug("Preserved original changeDefinition in update request") + + return content + + +def _normalize_targets_arg(raw_targets): # pylint: disable=too-many-branches + """Return a list of raw target strings from the parsed CLI argument.""" + if raw_targets is None: + return [] + + if isinstance(raw_targets, AAZArgActionOperations): + return _normalize_aaz_operations(raw_targets) + + if hasattr(raw_targets, 'to_serialized_data'): + values = raw_targets.to_serialized_data() + elif isinstance(raw_targets, list): + values = raw_targets + else: + values = [raw_targets] + + return [str(v).strip() for v in values if v is not None and str(v).strip()] + + +def _normalize_aaz_operations(raw_targets): + """Process AAZArgActionOperations to extract target strings.""" + elements = [] + for keys, data in raw_targets._ops: # pylint: disable=protected-access + logger.debug("Processing target op keys=%s data=%s", keys, data) + if isinstance(data, AAZPromptInputOperation): + data = data() + + normalized_value = _normalize_data_value(data) + idx, key_name = _extract_index_and_key(keys, len(elements)) + + if key_name: + # AAZ parsed "key=value,..." - reconstruct the full target string + full_target = f"{key_name}={normalized_value}" if normalized_value else key_name + _append_or_set_element(elements, idx, full_target) + else: + _append_or_set_element(elements, idx, normalized_value) + + return [value for value in elements if value] + + +def _normalize_data_value(data): + """Convert data to a normalized string value.""" + if isinstance(data, (list, tuple)): + return ','.join(str(v) for v in data if v is not None) + return str(data) if data is not None else '' + + +def _extract_index_and_key(keys, current_length): + """Extract index and key name from AAZ operation keys.""" + idx = None + key_name = None + for key in keys: + if key == _ELEMENT_APPEND_KEY: + idx = current_length + elif isinstance(key, int): + idx = key + elif isinstance(key, str): + key_name = key + return idx, key_name + + +def _append_or_set_element(elements, idx, value): + """Append or set an element in the list at the given index.""" + if idx is not None: + while len(elements) <= idx: + elements.append('') + elements[idx] = value + else: + elements.append(value) + + +def _inject_targets_into_result(data, targets): + """Ensure changeDefinition.details.targets is present in the command output.""" + if not targets or data is None: + return + + def process(item): + if not isinstance(item, dict): + return + containers = [] + if isinstance(item.get('properties'), dict): + containers.append(item['properties']) + containers.append(item) + for container in containers: + change_def = container.get('changeDefinition') + if isinstance(change_def, dict): + details = change_def.setdefault('details', {}) + if isinstance(details, dict) and not details.get('targets'): + details['targets'] = targets + + if isinstance(data, list): + for entry in data: + process(entry) + else: + process(data) + + +def _build_custom_show_schema(): + """Build a custom schema for Show command that includes details.targets. + + The generated AAZ schema doesn't know about the free-form 'details' object + structure, so we extend it to properly deserialize the targets array. + + Returns: + AAZObjectType: The extended schema with targets array definition. + """ + # Get the base schema from the generated code + # pylint: disable-next=protected-access + base_schema = _GeneratedShow.ChangeRecordsGet._build_schema_on_200() + + # Inject schema for details.targets - the generated code doesn't know this structure + change_definition = base_schema.properties.change_definition + details = change_definition.details + details.targets = AAZListType(flags={"read_only": True}) + details.targets.Element = AAZObjectType() + details.targets.Element.resourceId = AAZStrType() + details.targets.Element.subscriptionId = AAZStrType() + details.targets.Element.resourceGroupName = AAZStrType() + details.targets.Element.resourceType = AAZStrType() + details.targets.Element.resourceName = AAZStrType() + details.targets.Element.httpMethod = AAZStrType() + + return base_schema + + +# ----------------------------------------------------------------------------- +# Command Classes +# ----------------------------------------------------------------------------- + +class ChangeRecordCreate(_ChangeRecordCreate): + """Custom Create command with --targets parsing and --stagemap-name shortcut.""" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._raw_targets = [] + self._parsed_targets = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + schema = super()._build_arguments_schema(*args, **kwargs) + if not hasattr(schema, "change_definition"): + schema.change_definition = AAZAnyTypeArg( # type: ignore[attr-defined] + options=["--change-definition"], + arg_group="Properties", + help=SUPPRESS, + nullable=True, + blank={}, + ) + if not hasattr(schema, "stagemap_name"): + schema.stagemap_name = AAZStrArg( # type: ignore[attr-defined] + options=["--stagemap-name", "--stage-map-name"], + arg_group="Properties", + help=( + "StageMap name in the current subscription scope. Automatically builds " + "the stage map resource ID." + ), + ) + if not hasattr(schema, "targets"): + schema.targets = AAZListArg( + options=["--targets"], + help=( + "Target definitions expressed as key=value pairs separated by commas or semicolons. " + "Example: --targets \"resourceId=RESOURCE_ID,operation=delete\"" + ), + ) + schema.targets.Element = AAZStrArg() + return schema + + def _handler(self, command_args): + # Extract targets before calling parent handler so we can accept flexible input formats. + self._raw_targets = [] + self._parsed_targets = None + command_args = dict(command_args) if command_args else {} + raw_targets = command_args.pop('targets', None) + if raw_targets is not None: + self._raw_targets = _normalize_targets_arg(raw_targets) + return super()._handler(command_args) + + def pre_operations(self): + super().pre_operations() + self._ensure_schedule_defaults() + _apply_stage_map_shortcut(self.ctx) + + 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'] + if has_value(change_definition_arg): + change_definition_value = self._parse_change_definition_arg(change_definition_arg) + if self._raw_targets: + raise InvalidArgumentValueError("Use either --change-definition or --targets, not both.") + + if change_definition_value is None and not self._raw_targets: + raise InvalidArgumentValueError('--targets is required unless you provide --change-definition JSON.') + + # Build and set the changeDefinition with targets + change_definition = change_definition_value or self._build_change_definition() + logger.debug("Final changeDefinition for create: %s", change_definition) + self.ctx.set_var( + 'change_definition', + change_definition, + schema_builder=_build_any_type, + ) + + def _ensure_schedule_defaults(self): + """Populate anticipated start/end time defaults when the user omits them.""" + now = datetime.datetime.now(datetime.timezone.utc) + start_arg = getattr(self.ctx.args, "anticipated_start_time", None) + end_arg = getattr(self.ctx.args, "anticipated_end_time", None) + start_dt = self._parse_datetime_value(start_arg) if has_value(start_arg) else None + if start_dt is None: + start_dt = now + self.ctx.args.anticipated_start_time = self._to_iso8601(start_dt) + if not has_value(end_arg): + self.ctx.args.anticipated_end_time = self._to_iso8601(start_dt + datetime.timedelta(hours=8)) + + @staticmethod + def _to_iso8601(value): + serialized = value.isoformat(timespec="seconds") + return serialized.replace("+00:00", "Z") + + @staticmethod + def _parse_datetime_value(value): + text = None + if value is None: + return None + if hasattr(value, "to_serialized_data"): + text = value.to_serialized_data() + elif isinstance(value, str): + text = value + if not text: + return None + try: + return datetime.datetime.fromisoformat(str(text).replace("Z", "+00:00")) + except ValueError: + return None + + def _parse_change_definition_arg(self, change_definition_arg): + data = change_definition_arg.to_serialized_data() + if data is None: + return None + if not isinstance(data, dict): + raise InvalidArgumentValueError("--change-definition must be valid JSON object.") + return data + + def _build_change_definition(self): + """Build the changeDefinition object with targets""" + targets = self._parse_targets(self._raw_targets) + self._parsed_targets = targets + change_arg = self.ctx.args.change_record_name + change_name = ( + change_arg.to_serialized_data() + if has_value(change_arg) + else "Change Definition" + ) + + return { + 'kind': CHANGE_DEFINITION_KIND_TARGETS, + 'name': change_name, + 'details': { + 'targets': targets + } + } + + @staticmethod + def _parse_key_value_segment(segment): + """Parse a single key=value segment and return (mapped_key, value).""" + if '=' not in segment: + raise InvalidArgumentValueError('Each --targets entry must be in key=value format.') + key, value = segment.split('=', 1) + key = key.strip() + value = value.strip() + if not key or not value: + raise InvalidArgumentValueError('Each --targets entry must include a non-empty key and value.') + normalized_key = key.lower() + if normalized_key in TARGET_KEY_MAPPING: + mapped_key = TARGET_KEY_MAPPING[normalized_key] + if mapped_key == 'httpMethod' and value: + value = value.upper() + return mapped_key, value + return key, value + + @staticmethod + def _tokenize_target(token): + """Split a target token into segments, handling both ; and , delimiters.""" + if token is None: + return [] + segments = [] + for part in str(token).split(';'): + segments.extend(segment.strip() for segment in part.split(',') if segment.strip()) + return segments + + @staticmethod + def _parse_targets(raw_targets): + if not raw_targets: + raise InvalidArgumentValueError('--targets is required and must include key=value pairs.') + parsed_targets = [] + for token in raw_targets: + segments = ChangeRecordCreate._tokenize_target(token) + if not segments: + continue + target_entry = {} + for segment in segments: + mapped_key, value = ChangeRecordCreate._parse_key_value_segment(segment) + target_entry[mapped_key] = value + if target_entry: + parsed_targets.append(target_entry) + if not parsed_targets: + raise InvalidArgumentValueError('--targets must include at least one key=value pair.') + return parsed_targets + + def _output(self, *args, **kwargs): + result = super()._output(*args, **kwargs) + _inject_targets_into_result(result, self._parsed_targets) + return result + + class ChangeRecordsCreateOrUpdateAtSubscriptionLevel( + _ChangeRecordCreate.ChangeRecordsCreateOrUpdateAtSubscriptionLevel): + """Override PUT at subscription level to inject custom changeDefinition.""" + + @property + def content(self): + content = super().content + return _inject_change_definition_into_content(content, self.ctx) + + class ChangeRecordsCreateOrUpdate( + _ChangeRecordCreate.ChangeRecordsCreateOrUpdate): + """Override PUT at resource group level to inject custom changeDefinition.""" + + @property + def content(self): + content = super().content + return _inject_change_definition_into_content(content, self.ctx) + + +class ChangeRecordUpdate(_ChangeRecordUpdate): + """Custom update command that preserves changeDefinition from GET response. + + The changeDefinition cannot be modified after creation due to API constraints. + This class works around an AAZ framework limitation where the GET+PUT update + pattern corrupts the free-form 'details' object (it becomes empty {}). + + Solution: We capture the raw changeDefinition from the GET HTTP response before + the AAZ schema loses the details, then restore it in the PUT request content. + """ + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + schema = super()._build_arguments_schema(*args, **kwargs) + # Hide --change-definition since it cannot be updated after creation + if hasattr(schema, "change_definition"): + setattr(schema.change_definition, '_registered', False) # pylint: disable=protected-access + if not hasattr(schema, "stagemap_name"): + schema.stagemap_name = AAZStrArg( # type: ignore[attr-defined] + options=["--stagemap-name", "--stage-map-name"], + arg_group="Properties", + help=( + "StageMap name in the current subscription scope. Automatically builds " + "the stage map resource ID." + ), + ) + return schema + + def pre_operations(self): + super().pre_operations() + _apply_stage_map_shortcut(self.ctx) + + class ChangeRecordsGetAtSubscriptionLevel( + _ChangeRecordUpdate.ChangeRecordsGetAtSubscriptionLevel): + """Override GET at subscription level to capture original changeDefinition.""" + + def on_200(self, session): + # Capture raw changeDefinition from HTTP response before schema loses details + data = self.deserialize_http_content(session) + if data and "properties" in data and "changeDefinition" in data["properties"]: + # pylint: disable-next=protected-access + self.ctx._original_change_definition = data["properties"]["changeDefinition"] + logger.debug("Captured raw changeDefinition from GET response: %s", + self.ctx._original_change_definition) # pylint: disable=protected-access + return super().on_200(session) + + class ChangeRecordsGet(_ChangeRecordUpdate.ChangeRecordsGet): + """Override GET at resource group level to capture original changeDefinition.""" + + def on_200(self, session): + # Capture raw changeDefinition from HTTP response before schema loses details + data = self.deserialize_http_content(session) + if data and "properties" in data and "changeDefinition" in data["properties"]: + # pylint: disable-next=protected-access + self.ctx._original_change_definition = data["properties"]["changeDefinition"] + logger.debug("Captured raw changeDefinition from GET response: %s", + self.ctx._original_change_definition) # pylint: disable=protected-access + return super().on_200(session) + + class ChangeRecordsCreateOrUpdateAtSubscriptionLevel( + _ChangeRecordUpdate.ChangeRecordsCreateOrUpdateAtSubscriptionLevel): + """Override PUT at subscription level to preserve original changeDefinition.""" + + @property + def content(self): + content = super().content + # Preserve original changeDefinition - it cannot be updated + return _preserve_change_definition_in_content(content, self.ctx) + + class ChangeRecordsCreateOrUpdate( + _ChangeRecordUpdate.ChangeRecordsCreateOrUpdate): + """Override PUT at resource group level to preserve original changeDefinition.""" + + @property + def content(self): + content = super().content + # Preserve original changeDefinition - it cannot be updated + return _preserve_change_definition_in_content(content, self.ctx) + + +class ChangeRecordShow(_ChangeRecordShow): + """Custom Show command with extended schema for details.targets.""" + + class ChangeRecordsGetAtSubscriptionLevel(_ChangeRecordShow.ChangeRecordsGetAtSubscriptionLevel): + """Override to use custom schema that includes targets array.""" + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=_build_custom_show_schema + ) + + class ChangeRecordsGet(_ChangeRecordShow.ChangeRecordsGet): + """Override to use custom schema that includes targets array.""" + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=_build_custom_show_schema + ) + + +class ChangeRecordDelete(_ChangeRecordDelete): + """Delete command - only customized for help examples.""" + + +ChangeRecordCreate.AZ_HELP = { + **ChangeRecordCreate.AZ_HELP, + "examples": [ + { + "name": "Create a ChangeRecord for deleting a Traffic Manager profile", + "text": ( + "az changesafety changerecord create -g MyResourceGroup -n delete-trafficmanager " + "--change-type ManualTouch --rollout-type Hotfix " + "--targets \"resourceId=/subscriptions/00000000-0000-0000-0000-000000000000/" + "resourceGroups/MyResourceGroup/providers/Microsoft.Network/" + "trafficManagerProfiles/myProfile,operation=DELETE\" " + "--description \"Delete Traffic Manager profile\"" + ), + }, + { + "name": "Create with StageMap reference and status link", + "text": ( + "az changesafety changerecord create -g MyResourceGroup -n changerecord002 " + "--change-type ManualTouch --rollout-type Normal " + "--stage-map \"{resource-id:/subscriptions/00000000-0000-0000-0000-000000000000/" + "resourceGroups/MyResourceGroup/providers/Microsoft.ChangeSafety/stageMaps/rolloutStageMap}\" " + "--targets \"resourceId=/subscriptions/00000000-0000-0000-0000-000000000000/" + "resourceGroups/MyResourceGroup/providers/Microsoft.Compute/virtualMachines/myVm,operation=PATCH\" " + "--links \"[{name:status,uri:'https://contoso.com/change/rollout-002'}]\"\n" + ), + }, + { + "name": "Create a ChangeRecord for a VM rollout", + "text": ( + "az changesafety changerecord create -g MyResourceGroup -n changerecord001 " + "--change-type AppDeployment --rollout-type Normal " + "--targets \"resourceId=/subscriptions/00000000-0000-0000-0000-000000000000/" + "resourceGroups/MyResourceGroup/providers/Microsoft.Compute/virtualMachines/myVm,operation=PUT\"" + ), + }, + { + "name": "Create with StageMap name and default schedule", + "text": ( + "az changesafety changerecord create -g MyResourceGroup -n changerecord003 " + "--change-type ManualTouch --rollout-type Normal --stagemap-name rolloutStageMap " + "--targets \"resourceId=/subscriptions/00000000-0000-0000-0000-000000000000/" + "resourceGroups/MyResourceGroup/providers/Microsoft.Compute/virtualMachines/myVm,operation=DELETE\"" + ), + }, + { + "name": "Create targeting an entire subscription (broad scope)", + "text": ( + "az changesafety changerecord create -g MyResourceGroup -n subscription-wide-change " + "--change-type ManualTouch --rollout-type Normal " + "--targets \"subscriptionId=00000000-0000-0000-0000-000000000000,operation=PUT\"" + ), + }, + { + "name": "Create targeting a resource group (medium scope)", + "text": ( + "az changesafety changerecord create -g MyResourceGroup -n rg-level-change " + "--change-type ManualTouch --rollout-type Normal " + "--targets \"subscriptionId=00000000-0000-0000-0000-000000000000," + "resourceGroupName=MyResourceGroup,operation=DELETE\"" + ), + }, + { + "name": "Create with multiple targets at different scopes", + "text": ( + "az changesafety changerecord create -g MyResourceGroup -n multi-scope-change " + "--change-type ManualTouch --rollout-type Normal " + "--targets \"subscriptionId=00000000-0000-0000-0000-000000000000,operation=PUT\" " + "--targets \"subscriptionId=00000000-0000-0000-0000-000000000000," + "resourceGroupName=MyResourceGroup,operation=DELETE\" " + "--targets \"resourceId=/subscriptions/00000000-0000-0000-0000-000000000000/" + "resourceGroups/MyResourceGroup/providers/Microsoft.Compute/" + "virtualMachines/myVm,operation=PATCH\"" + ), + }, + ], +} + +ChangeRecordUpdate.AZ_HELP = { + **ChangeRecordUpdate.AZ_HELP, + "examples": [ + { + "name": "Adjust rollout type and add a comment", + "text": ( + "az changesafety changerecord update -g MyResourceGroup -n changerecord001 " + "--rollout-type Emergency --comments \"Escalated to emergency rollout\"" + ), + }, + { + "name": "Update scheduling window", + "text": ( + "az changesafety changerecord update -g MyResourceGroup -n changerecord001 " + "--anticipated-start-time \"2024-09-01T08:00:00Z\" " + "--anticipated-end-time \"2024-09-01T12:00:00Z\"" + ), + }, + { + "name": "Update description", + "text": ( + "az changesafety changerecord update -g MyResourceGroup -n changerecord001 " + "--description \"Updated rollout for production deployment\"" + ), + }, + ], +} + +ChangeRecordDelete.AZ_HELP = { + **ChangeRecordDelete.AZ_HELP, + "examples": [ + { + "name": "Delete a ChangeRecord without confirmation", + "text": "az changesafety changerecord delete -g MyResourceGroup -n changerecord001 --yes", + }, + ], +} + +ChangeRecordShow.AZ_HELP = { + **ChangeRecordShow.AZ_HELP, + "examples": [ + { + "name": "Show a ChangeRecord", + "text": "az changesafety changerecord show -g MyResourceGroup -n changerecord001", + }, + ], +} + + +# ----------------------------------------------------------------------------- +# StageMap Help Examples +# ----------------------------------------------------------------------------- +# pylint: disable=wrong-import-position +from azext_changesafety.aaz.latest.changesafety.stagemap import ( # noqa: E402 + Create as _StageMapCreate, + Show as _StageMapShow, + Update as _StageMapUpdate, + Delete as _StageMapDelete, + List as _StageMapList, +) + +_StageMapCreate.AZ_HELP = { + **_StageMapCreate.AZ_HELP, + "short-summary": "Create a StageMap resource.", + "long-summary": ( + "A StageMap defines the stages through which a change progresses during rollout. " + "Each stage has a name and sequence number. Stages are executed in order of their " + "sequence values." + ), + "examples": [ + { + "name": "Create a simple two-stage StageMap", + "text": ( + "az changesafety stagemap create --subscription 00000000-0000-0000-0000-000000000000 " + "--stage-map-name rolloutStageMap " + "--stages \"[{name:Canary,sequence:1},{name:Production,sequence:2}]\"" + ), + }, + { + "name": "Create a StageMap with three regional stages", + "text": ( + "az changesafety stagemap create --subscription 00000000-0000-0000-0000-000000000000 " + "--stage-map-name regional-rollout " + "--stages \"[{name:WestUS,sequence:1},{name:EastUS,sequence:2},{name:Global,sequence:3}]\"" + ), + }, + ], +} + +_StageMapShow.AZ_HELP = { + **_StageMapShow.AZ_HELP, + "short-summary": "Get details for a StageMap resource.", + "examples": [ + { + "name": "Show a StageMap", + "text": ( + "az changesafety stagemap show --subscription 00000000-0000-0000-0000-000000000000 " + "--stage-map-name rolloutStageMap" + ), + }, + ], +} + +_StageMapUpdate.AZ_HELP = { + **_StageMapUpdate.AZ_HELP, + "short-summary": "Update an existing StageMap resource.", + "long-summary": ( + "Modify the stages defined in a StageMap. When updating, provide the complete " + "list of stages as the update replaces the existing stages array." + ), + "examples": [ + { + "name": "Add a new stage to an existing StageMap", + "text": ( + "az changesafety stagemap update --subscription 00000000-0000-0000-0000-000000000000 " + "--stage-map-name rolloutStageMap " + "--stages \"[{name:Canary,sequence:1},{name:Pilot,sequence:2},{name:Production,sequence:3}]\"" + ), + }, + ], +} + +_StageMapDelete.AZ_HELP = { + **_StageMapDelete.AZ_HELP, + "short-summary": "Delete a StageMap resource.", + "long-summary": ( + "Delete a StageMap that is no longer needed. Note that StageMap resources " + "that are currently referenced by active ChangeRecord resources cannot be deleted." + ), + "examples": [ + { + "name": "Delete a StageMap", + "text": ( + "az changesafety stagemap delete --subscription 00000000-0000-0000-0000-000000000000 " + "--stage-map-name rolloutStageMap --yes" + ), + }, + ], +} + +_StageMapList.AZ_HELP = { + **_StageMapList.AZ_HELP, + "short-summary": "List StageMap resources in a subscription.", + "examples": [ + { + "name": "List all StageMaps in the subscription", + "text": "az changesafety stagemap list --subscription 00000000-0000-0000-0000-000000000000", + }, + ], +} + + +# ----------------------------------------------------------------------------- +# StageProgression Help Examples +# ----------------------------------------------------------------------------- +# pylint: disable=wrong-import-position +from azext_changesafety.aaz.latest.changesafety.stageprogression import ( # noqa: E402 + Create as _StageProgressionCreate, + Show as _StageProgressionShow, + Update as _StageProgressionUpdate, + Delete as _StageProgressionDelete, + List as _StageProgressionList, +) + +_StageProgressionCreate.AZ_HELP = { + **_StageProgressionCreate.AZ_HELP, + "short-summary": "Create a StageProgression to track stage progress.", + "long-summary": ( + "A StageProgression records the execution status of a specific stage defined " + "in a StageMap. Use this to track which stages have started, completed, or failed " + "during a change rollout." + ), + "examples": [ + { + "name": "Create a StageProgression for the Canary stage", + "text": ( + "az changesafety stageprogression create " + "--subscription 00000000-0000-0000-0000-000000000000 " + "--change-record-name myChangeRecord " + "-n canary-progression " + "--stage-reference Canary " + "--status InProgress" + ), + }, + { + "name": "Create a StageProgression with comments", + "text": ( + "az changesafety stageprogression create " + "--subscription 00000000-0000-0000-0000-000000000000 " + "--change-record-name myChangeRecord " + "-n prod-stage " + "--stage-reference Production " + "--status InProgress " + "--comments \"Starting production rollout\"" + ), + }, + ], +} + +_StageProgressionShow.AZ_HELP = { + **_StageProgressionShow.AZ_HELP, + "short-summary": "Get details for a StageProgression.", + "examples": [ + { + "name": "Show a StageProgression", + "text": ( + "az changesafety stageprogression show " + "--subscription 00000000-0000-0000-0000-000000000000 " + "--change-record-name myChangeRecord " + "-n canary-progression" + ), + }, + ], +} + +_StageProgressionUpdate.AZ_HELP = { + **_StageProgressionUpdate.AZ_HELP, + "short-summary": "Update a StageProgression status or comments.", + "long-summary": ( + "Update the status of a StageProgression to reflect the current state of " + "the stage execution. Common status transitions are InProgress -> Completed " + "or InProgress -> Failed." + ), + "examples": [ + { + "name": "Mark a stage as completed", + "text": ( + "az changesafety stageprogression update " + "--subscription 00000000-0000-0000-0000-000000000000 " + "--change-record-name myChangeRecord " + "-n canary-progression " + "--status Completed " + "--comments \"Canary validation passed\"" + ), + } + ], +} + +_StageProgressionDelete.AZ_HELP = { + **_StageProgressionDelete.AZ_HELP, + "short-summary": "Delete a StageProgression.", + "examples": [ + { + "name": "Delete a StageProgression", + "text": ( + "az changesafety stageprogression delete " + "--subscription 00000000-0000-0000-0000-000000000000 " + "--change-record-name myChangeRecord " + "-n canary-progression --yes" + ), + }, + ], +} + +_StageProgressionList.AZ_HELP = { + **_StageProgressionList.AZ_HELP, + "short-summary": "List all StageProgressions for a ChangeRecord.", + "examples": [ + { + "name": "List StageProgressions for a ChangeRecord", + "text": ( + "az changesafety stageprogression list " + "--subscription 00000000-0000-0000-0000-000000000000 " + "--change-record-name myChangeRecord" + ), + }, + ], +} diff --git a/src/azure-changesafety/azext_changesafety/tests/__init__.py b/src/azure-changesafety/azext_changesafety/tests/__init__.py new file mode 100644 index 00000000000..5757aea3175 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/tests/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- diff --git a/src/azure-changesafety/azext_changesafety/tests/latest/__init__.py b/src/azure-changesafety/azext_changesafety/tests/latest/__init__.py new file mode 100644 index 00000000000..5757aea3175 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/tests/latest/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- diff --git a/src/azure-changesafety/azext_changesafety/tests/latest/recordings/test_changesafety_full_scenario.yaml b/src/azure-changesafety/azext_changesafety/tests/latest/recordings/test_changesafety_full_scenario.yaml new file mode 100644 index 00000000000..6de1f892933 --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/tests/latest/recordings/test_changesafety_full_scenario.yaml @@ -0,0 +1,735 @@ +interactions: +- request: + body: '{"properties": {"stages": [{"name": "Canary", "sequence": 1}, {"name": + "Production", "sequence": 2}]}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - changesafety stagemap create + Connection: + - keep-alive + Content-Length: + - '102' + Content-Type: + - application/json + ParameterSetName: + - --stage-map-name --stages + User-Agent: + - AZURECLI/2.82.0 azsdk-python-core/1.37.0 Python/3.11.9 (Windows-10-10.0.26200-SP0) + method: PUT + uri: https://centraluseuap.management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001?api-version=2026-01-01-preview + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001","name":"stgmap000001","type":"microsoft.changesafety/stagemaps","systemData":{"createdBy":"henrydai@microsoft.com","createdByType":"User","createdAt":"2026-01-30T23:57:16.4783953Z","lastModifiedBy":"henrydai@microsoft.com","lastModifiedByType":"User","lastModifiedAt":"2026-01-30T23:57:16.4783953Z"},"properties":{"parameters":null,"stages":[{"name":"Canary","sequence":1,"stageVariables":null,"nestedStageMap":null},{"name":"Production","sequence":2,"stageVariables":null,"nestedStageMap":null}],"provisioningState":"Succeeded"}}' + headers: + cache-control: + - no-cache + content-length: + - '646' + content-type: + - application/json; charset=utf-8 + date: + - Fri, 30 Jan 2026 23:57:16 GMT + etag: + - '"0700d98d-0000-0600-0000-697d455c0000"' + expires: + - '-1' + mise-correlation-id: + - 02a93635-22eb-46ec-8e9c-c092b71d7ecc + pragma: + - no-cache + request-context: + - appId=cid-v1:0b4319bc-3dec-4ac3-88c8-c1b86ec8e1cf + set-cookie: + - ARRAffinity=a1dd3bd4b2e949edd11f1ea24dd6378e16e4ac0eff19d14c7d7df3c670446536;Path=/;HttpOnly;Secure;Domain=canary.changecontrol.changesafety.msft.net + - ARRAffinitySameSite=a1dd3bd4b2e949edd11f1ea24dd6378e16e4ac0eff19d14c7d7df3c670446536;Path=/;HttpOnly;SameSite=None;Secure;Domain=canary.changecontrol.changesafety.msft.net + strict-transport-security: + - max-age=31536000; includeSubDomains + vary: + - Accept-Encoding + x-cache: + - CONFIG_NOCACHE + x-content-type-options: + - nosniff + x-ms-operation-identifier: + - tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47,objectId=bfa18db0-78d5-4d4d-8796-642151886af4/centraluseuap/6ccbacd0-16a6-4748-b796-8d541c5cde41 + x-ms-providerhub-traffic: + - 'True' + x-ms-ratelimit-remaining-subscription-writes: + - '799' + x-ms-throttling-version: + - v2 + x-msedge-ref: + - 'Ref A: E7D8906C0FE045E08924890D8267EE25 Ref B: BY1AA1072319062 Ref C: 2026-01-30T23:57:16Z' + x-powered-by: + - ASP.NET + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - changesafety stagemap show + Connection: + - keep-alive + ParameterSetName: + - --stage-map-name + User-Agent: + - AZURECLI/2.82.0 azsdk-python-core/1.37.0 Python/3.11.9 (Windows-10-10.0.26200-SP0) + method: GET + uri: https://centraluseuap.management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001?api-version=2026-01-01-preview + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001","name":"stgmap000001","type":"microsoft.changesafety/stagemaps","systemData":{"createdBy":"henrydai@microsoft.com","createdByType":"User","createdAt":"2026-01-30T23:57:16.4783953Z","lastModifiedBy":"henrydai@microsoft.com","lastModifiedByType":"User","lastModifiedAt":"2026-01-30T23:57:16.4783953Z"},"properties":{"parameters":null,"stages":[{"name":"Canary","sequence":1,"stageVariables":null,"nestedStageMap":null},{"name":"Production","sequence":2,"stageVariables":null,"nestedStageMap":null}],"provisioningState":"Succeeded"}}' + headers: + cache-control: + - no-cache + content-length: + - '646' + content-type: + - application/json; charset=utf-8 + date: + - Fri, 30 Jan 2026 23:57:17 GMT + etag: + - '"0700d98d-0000-0600-0000-697d455c0000"' + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + x-cache: + - CONFIG_NOCACHE + x-content-type-options: + - nosniff + x-ms-operation-identifier: + - tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47,objectId=bfa18db0-78d5-4d4d-8796-642151886af4/centraluseuap/d3bb5cfe-e466-47cc-ab3a-51816bf86506 + x-ms-providerhub-traffic: + - 'True' + x-ms-throttling-version: + - v2 + x-msedge-ref: + - 'Ref A: 6BA4DCBBB3A744CBBDEA42CB2E2B7539 Ref B: BY1AA1072317031 Ref C: 2026-01-30T23:57:17Z' + status: + code: 200 + message: OK +- request: + body: '{"properties": {"anticipatedEndTime": "2026-01-31T07:57:17Z", "anticipatedStartTime": + "2026-01-30T23:57:17Z", "changeType": "AppDeployment", "rolloutType": "Normal", + "stageMap": {"resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001"}, + "changeDefinition": {"kind": "Targets", "name": "cr000002", "details": {"targets": + [{"subscriptionId": "$(az account show --query id -o tsv)"}]}}}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - changesafety changerecord create + Connection: + - keep-alive + Content-Length: + - '452' + Content-Type: + - application/json + ParameterSetName: + - -n --change-type --rollout-type --stagemap-name --targets + User-Agent: + - AZURECLI/2.82.0 azsdk-python-core/1.37.0 Python/3.11.9 (Windows-10-10.0.26200-SP0) + method: PUT + uri: https://centraluseuap.management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/changeRecords/cr000002?api-version=2026-01-01-preview + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/changeRecords/cr000002","name":"cr000002","type":"microsoft.changesafety/changerecords","systemData":{"createdBy":"henrydai@microsoft.com","createdByType":"User","createdAt":"2026-01-30T23:57:18.6736676Z","lastModifiedBy":"henrydai@microsoft.com","lastModifiedByType":"User","lastModifiedAt":"2026-01-30T23:57:18.6736676Z"},"properties":{"changeType":"AppDeployment","rolloutType":"Normal","description":null,"stageMap":{"resourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001","parameters":null},"parameters":null,"comments":null,"changeDefinition":{"name":"cr000002","kind":"Targets","details":{"targets":[{"subscriptionId":"$(az + account show --query id -o tsv)"}]}},"releaseLabel":null,"anticipatedStartTime":"2026-01-30T23:57:17Z","anticipatedEndTime":"2026-01-31T07:57:17Z","orchestrationTool":null,"links":null,"additionalData":null,"stageMapSnapshot":[{"key":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001","value":{"properties":{"parameters":null,"stages":[{"name":"Canary","sequence":1,"stageVariables":null,"nestedStageMap":null},{"name":"Production","sequence":2,"stageVariables":null,"nestedStageMap":null}]},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001","name":"stgmap000001","type":"microsoft.changesafety/stagemaps"}}],"status":"Initialized","provisioningState":"Succeeded"}}' + headers: + cache-control: + - no-cache + content-length: + - '1579' + content-type: + - application/json; charset=utf-8 + date: + - Fri, 30 Jan 2026 23:57:18 GMT + etag: + - '"01008f92-0000-0600-0000-697d455f0000"' + expires: + - '-1' + mise-correlation-id: + - 6f2c6588-e397-4df7-81cf-002300a56cf6 + pragma: + - no-cache + request-context: + - appId=cid-v1:0b4319bc-3dec-4ac3-88c8-c1b86ec8e1cf + set-cookie: + - ARRAffinity=1fef50c7b13f746942d4dbd0dbb97673928df1f977cb37e394a2ffeda3575190;Path=/;HttpOnly;Secure;Domain=canary.changecontrol.changesafety.msft.net + - ARRAffinitySameSite=1fef50c7b13f746942d4dbd0dbb97673928df1f977cb37e394a2ffeda3575190;Path=/;HttpOnly;SameSite=None;Secure;Domain=canary.changecontrol.changesafety.msft.net + strict-transport-security: + - max-age=31536000; includeSubDomains + vary: + - Accept-Encoding + x-cache: + - CONFIG_NOCACHE + x-content-type-options: + - nosniff + x-ms-operation-identifier: + - tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47,objectId=bfa18db0-78d5-4d4d-8796-642151886af4/centraluseuap/0aa62c13-fed2-422c-98d0-02a4e7250e1e + x-ms-providerhub-traffic: + - 'True' + x-ms-ratelimit-remaining-subscription-writes: + - '799' + x-ms-throttling-version: + - v2 + x-msedge-ref: + - 'Ref A: AAC31D799D4740EF902A0CCC627F1760 Ref B: SJC211051204025 Ref C: 2026-01-30T23:57:18Z' + x-powered-by: + - ASP.NET + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - changesafety changerecord show + Connection: + - keep-alive + ParameterSetName: + - -n + User-Agent: + - AZURECLI/2.82.0 azsdk-python-core/1.37.0 Python/3.11.9 (Windows-10-10.0.26200-SP0) + method: GET + uri: https://centraluseuap.management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/changeRecords/cr000002?api-version=2026-01-01-preview + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/changeRecords/cr000002","name":"cr000002","type":"microsoft.changesafety/changerecords","systemData":{"createdBy":"henrydai@microsoft.com","createdByType":"User","createdAt":"2026-01-30T23:57:18.6736676Z","lastModifiedBy":"henrydai@microsoft.com","lastModifiedByType":"User","lastModifiedAt":"2026-01-30T23:57:18.6736676Z"},"properties":{"changeType":"AppDeployment","rolloutType":"Normal","description":null,"stageMap":{"resourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001","parameters":null},"parameters":null,"comments":null,"changeDefinition":{"name":"cr000002","kind":"Targets","details":{"targets":[{"subscriptionId":"$(az + account show --query id -o tsv)"}]}},"releaseLabel":null,"anticipatedStartTime":"2026-01-30T23:57:17Z","anticipatedEndTime":"2026-01-31T07:57:17Z","orchestrationTool":null,"links":null,"additionalData":null,"stageMapSnapshot":[{"key":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001","value":{"properties":{"parameters":null,"stages":[{"name":"Canary","sequence":1,"stageVariables":null,"nestedStageMap":null},{"name":"Production","sequence":2,"stageVariables":null,"nestedStageMap":null}]},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001","name":"stgmap000001","type":"microsoft.changesafety/stagemaps"}}],"status":"Initialized","provisioningState":"Succeeded"}}' + headers: + cache-control: + - no-cache + content-length: + - '1579' + content-type: + - application/json; charset=utf-8 + date: + - Fri, 30 Jan 2026 23:57:19 GMT + etag: + - '"01008f92-0000-0600-0000-697d455f0000"' + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + x-cache: + - CONFIG_NOCACHE + x-content-type-options: + - nosniff + x-ms-operation-identifier: + - tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47,objectId=bfa18db0-78d5-4d4d-8796-642151886af4/centraluseuap/833ca244-4b27-4cb1-8b4a-d1a719e30d36 + x-ms-providerhub-traffic: + - 'True' + x-ms-throttling-version: + - v2 + x-msedge-ref: + - 'Ref A: 8BD8E929C7A6401EA8E1E8B445131E1C Ref B: SJC211051203039 Ref C: 2026-01-30T23:57:20Z' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - changesafety changerecord update + Connection: + - keep-alive + ParameterSetName: + - -n --rollout-type --comments + User-Agent: + - AZURECLI/2.82.0 azsdk-python-core/1.37.0 Python/3.11.9 (Windows-10-10.0.26200-SP0) + method: GET + uri: https://centraluseuap.management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/changeRecords/cr000002?api-version=2026-01-01-preview + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/changeRecords/cr000002","name":"cr000002","type":"microsoft.changesafety/changerecords","systemData":{"createdBy":"henrydai@microsoft.com","createdByType":"User","createdAt":"2026-01-30T23:57:18.6736676Z","lastModifiedBy":"henrydai@microsoft.com","lastModifiedByType":"User","lastModifiedAt":"2026-01-30T23:57:18.6736676Z"},"properties":{"changeType":"AppDeployment","rolloutType":"Normal","description":null,"stageMap":{"resourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001","parameters":null},"parameters":null,"comments":null,"changeDefinition":{"name":"cr000002","kind":"Targets","details":{"targets":[{"subscriptionId":"$(az + account show --query id -o tsv)"}]}},"releaseLabel":null,"anticipatedStartTime":"2026-01-30T23:57:17Z","anticipatedEndTime":"2026-01-31T07:57:17Z","orchestrationTool":null,"links":null,"additionalData":null,"stageMapSnapshot":[{"key":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001","value":{"properties":{"parameters":null,"stages":[{"name":"Canary","sequence":1,"stageVariables":null,"nestedStageMap":null},{"name":"Production","sequence":2,"stageVariables":null,"nestedStageMap":null}]},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001","name":"stgmap000001","type":"microsoft.changesafety/stagemaps"}}],"status":"Initialized","provisioningState":"Succeeded"}}' + headers: + cache-control: + - no-cache + content-length: + - '1579' + content-type: + - application/json; charset=utf-8 + date: + - Fri, 30 Jan 2026 23:57:20 GMT + etag: + - '"01008f92-0000-0600-0000-697d455f0000"' + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + x-cache: + - CONFIG_NOCACHE + x-content-type-options: + - nosniff + x-ms-operation-identifier: + - tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47,objectId=bfa18db0-78d5-4d4d-8796-642151886af4/centraluseuap/9e5b9843-4d8a-483e-87dd-a72943bdb81a + x-ms-providerhub-traffic: + - 'True' + x-ms-throttling-version: + - v2 + x-msedge-ref: + - 'Ref A: F14C0102D53E438581AE5243388258BF Ref B: BY1AA1072320062 Ref C: 2026-01-30T23:57:20Z' + status: + code: 200 + message: OK +- request: + body: '{"properties": {"anticipatedEndTime": "2026-01-31T07:57:17Z", "anticipatedStartTime": + "2026-01-30T23:57:17Z", "changeDefinition": {"name": "cr000002", "kind": "Targets", + "details": {"targets": [{"subscriptionId": "$(az account show --query id -o + tsv)"}]}}, "changeType": "AppDeployment", "comments": "Escalated", "rolloutType": + "Emergency", "stageMap": {"resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001"}}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - changesafety changerecord update + Connection: + - keep-alive + Content-Length: + - '480' + Content-Type: + - application/json + ParameterSetName: + - -n --rollout-type --comments + User-Agent: + - AZURECLI/2.82.0 azsdk-python-core/1.37.0 Python/3.11.9 (Windows-10-10.0.26200-SP0) + method: PUT + uri: https://centraluseuap.management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/changeRecords/cr000002?api-version=2026-01-01-preview + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/changeRecords/cr000002","name":"cr000002","type":"microsoft.changesafety/changerecords","systemData":{"createdBy":"henrydai@microsoft.com","createdByType":"User","createdAt":"2026-01-30T23:57:18.6736676Z","lastModifiedBy":"henrydai@microsoft.com","lastModifiedByType":"User","lastModifiedAt":"2026-01-30T23:57:21.736435Z"},"properties":{"changeType":"AppDeployment","rolloutType":"Emergency","description":null,"stageMap":{"resourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001","parameters":null},"parameters":null,"comments":"Escalated","changeDefinition":{"name":"cr000002","kind":"Targets","details":{"targets":[{"subscriptionId":"$(az + account show --query id -o tsv)"}]}},"releaseLabel":null,"anticipatedStartTime":"2026-01-30T23:57:17Z","anticipatedEndTime":"2026-01-31T07:57:17Z","orchestrationTool":null,"links":null,"additionalData":null,"stageMapSnapshot":[{"key":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001","value":{"properties":{"parameters":null,"stages":[{"name":"Canary","sequence":1,"stageVariables":null,"nestedStageMap":null},{"name":"Production","sequence":2,"stageVariables":null,"nestedStageMap":null}]},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001","name":"stgmap000001","type":"microsoft.changesafety/stagemaps"}}],"status":"Initialized","provisioningState":"Succeeded"}}' + headers: + cache-control: + - no-cache + content-length: + - '1588' + content-type: + - application/json; charset=utf-8 + date: + - Fri, 30 Jan 2026 23:57:21 GMT + etag: + - '"01009292-0000-0600-0000-697d45620000"' + expires: + - '-1' + mise-correlation-id: + - 5ab41fa4-e0cb-4fd1-b2fb-d1f0a255187d + pragma: + - no-cache + request-context: + - appId=cid-v1:0b4319bc-3dec-4ac3-88c8-c1b86ec8e1cf + set-cookie: + - ARRAffinity=1fef50c7b13f746942d4dbd0dbb97673928df1f977cb37e394a2ffeda3575190;Path=/;HttpOnly;Secure;Domain=canary.changecontrol.changesafety.msft.net + - ARRAffinitySameSite=1fef50c7b13f746942d4dbd0dbb97673928df1f977cb37e394a2ffeda3575190;Path=/;HttpOnly;SameSite=None;Secure;Domain=canary.changecontrol.changesafety.msft.net + strict-transport-security: + - max-age=31536000; includeSubDomains + vary: + - Accept-Encoding + x-cache: + - CONFIG_NOCACHE + x-content-type-options: + - nosniff + x-ms-operation-identifier: + - tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47,objectId=bfa18db0-78d5-4d4d-8796-642151886af4/centraluseuap/7c7c4a42-c057-4bff-8be3-5bb3e675fe44 + x-ms-providerhub-traffic: + - 'True' + x-ms-ratelimit-remaining-subscription-writes: + - '798' + x-ms-throttling-version: + - v2 + x-msedge-ref: + - 'Ref A: 48E5E9B82C2A4954AC28D8AFF37CB1EE Ref B: SJC211051204049 Ref C: 2026-01-30T23:57:21Z' + x-powered-by: + - ASP.NET + status: + code: 200 + message: OK +- request: + body: '{"properties": {"stageReference": "Canary", "status": "InProgress"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - changesafety stageprogression create + Connection: + - keep-alive + Content-Length: + - '68' + Content-Type: + - application/json + ParameterSetName: + - --change-record-name -n --stage-reference --status + User-Agent: + - AZURECLI/2.82.0 azsdk-python-core/1.37.0 Python/3.11.9 (Windows-10-10.0.26200-SP0) + method: PUT + uri: https://centraluseuap.management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/changeRecords/cr000002/stageProgressions/prog000003?api-version=2026-01-01-preview + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/changeRecords/cr000002/stageProgressions/prog000003","name":"prog000003","type":"microsoft.changesafety/changerecords/stageprogressions","systemData":{"createdBy":"henrydai@microsoft.com","createdByType":"User","createdAt":"2026-01-30T23:57:23.0985529Z","lastModifiedBy":"henrydai@microsoft.com","lastModifiedByType":"User","lastModifiedAt":"2026-01-30T23:57:23.0985529Z"},"properties":{"stageReference":"Canary","sequence":1,"status":"InProgress","comments":null,"stageVariables":{},"links":null,"additionalData":null,"parameters":null,"provisioningState":"Succeeded"}}' + headers: + cache-control: + - no-cache + content-length: + - '662' + content-type: + - application/json; charset=utf-8 + date: + - Fri, 30 Jan 2026 23:57:23 GMT + etag: + - '"0100cf36-0000-0600-0000-697d45640000"' + expires: + - '-1' + mise-correlation-id: + - 21315742-e793-4da9-b429-126bf08952e4 + pragma: + - no-cache + request-context: + - appId=cid-v1:0b4319bc-3dec-4ac3-88c8-c1b86ec8e1cf + set-cookie: + - ARRAffinity=1fef50c7b13f746942d4dbd0dbb97673928df1f977cb37e394a2ffeda3575190;Path=/;HttpOnly;Secure;Domain=canary.changecontrol.changesafety.msft.net + - ARRAffinitySameSite=1fef50c7b13f746942d4dbd0dbb97673928df1f977cb37e394a2ffeda3575190;Path=/;HttpOnly;SameSite=None;Secure;Domain=canary.changecontrol.changesafety.msft.net + strict-transport-security: + - max-age=31536000; includeSubDomains + vary: + - Accept-Encoding + x-cache: + - CONFIG_NOCACHE + x-content-type-options: + - nosniff + x-ms-operation-identifier: + - tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47,objectId=bfa18db0-78d5-4d4d-8796-642151886af4/centraluseuap/ee4a3223-66da-41a1-a160-ddd37e0606ad + x-ms-providerhub-traffic: + - 'True' + x-ms-ratelimit-remaining-subscription-writes: + - '799' + x-ms-throttling-version: + - v2 + x-msedge-ref: + - 'Ref A: AC7C7262D2294BC8BDE6C93ADE14FED0 Ref B: SJC211051205029 Ref C: 2026-01-30T23:57:22Z' + x-powered-by: + - ASP.NET + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - changesafety stageprogression show + Connection: + - keep-alive + ParameterSetName: + - --change-record-name -n + User-Agent: + - AZURECLI/2.82.0 azsdk-python-core/1.37.0 Python/3.11.9 (Windows-10-10.0.26200-SP0) + method: GET + uri: https://centraluseuap.management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/changeRecords/cr000002/stageProgressions/prog000003?api-version=2026-01-01-preview + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/changeRecords/cr000002/stageProgressions/prog000003","name":"prog000003","type":"microsoft.changesafety/changerecords/stageprogressions","systemData":{"createdBy":"henrydai@microsoft.com","createdByType":"User","createdAt":"2026-01-30T23:57:23.0985529Z","lastModifiedBy":"henrydai@microsoft.com","lastModifiedByType":"User","lastModifiedAt":"2026-01-30T23:57:23.0985529Z"},"properties":{"stageReference":"Canary","sequence":1,"status":"InProgress","comments":null,"stageVariables":{},"links":null,"additionalData":null,"parameters":null,"provisioningState":"Succeeded"}}' + headers: + cache-control: + - no-cache + content-length: + - '662' + content-type: + - application/json; charset=utf-8 + date: + - Fri, 30 Jan 2026 23:57:24 GMT + etag: + - '"0100cf36-0000-0600-0000-697d45640000"' + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + x-cache: + - CONFIG_NOCACHE + x-content-type-options: + - nosniff + x-ms-operation-identifier: + - tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47,objectId=bfa18db0-78d5-4d4d-8796-642151886af4/centraluseuap/4d267494-c0e0-4a53-a422-59e8348c9c33 + x-ms-providerhub-traffic: + - 'True' + x-ms-throttling-version: + - v2 + x-msedge-ref: + - 'Ref A: 152AD7AF2C604838BB8C00DF3798C2A6 Ref B: BY1AA1072317052 Ref C: 2026-01-30T23:57:24Z' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - changesafety stageprogression update + Connection: + - keep-alive + ParameterSetName: + - --change-record-name -n --status --comments + User-Agent: + - AZURECLI/2.82.0 azsdk-python-core/1.37.0 Python/3.11.9 (Windows-10-10.0.26200-SP0) + method: GET + uri: https://centraluseuap.management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/changeRecords/cr000002/stageProgressions/prog000003?api-version=2026-01-01-preview + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/changeRecords/cr000002/stageProgressions/prog000003","name":"prog000003","type":"microsoft.changesafety/changerecords/stageprogressions","systemData":{"createdBy":"henrydai@microsoft.com","createdByType":"User","createdAt":"2026-01-30T23:57:23.0985529Z","lastModifiedBy":"henrydai@microsoft.com","lastModifiedByType":"User","lastModifiedAt":"2026-01-30T23:57:23.0985529Z"},"properties":{"stageReference":"Canary","sequence":1,"status":"InProgress","comments":null,"stageVariables":{},"links":null,"additionalData":null,"parameters":null,"provisioningState":"Succeeded"}}' + headers: + cache-control: + - no-cache + content-length: + - '662' + content-type: + - application/json; charset=utf-8 + date: + - Fri, 30 Jan 2026 23:57:25 GMT + etag: + - '"0100cf36-0000-0600-0000-697d45640000"' + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + x-cache: + - CONFIG_NOCACHE + x-content-type-options: + - nosniff + x-ms-operation-identifier: + - tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47,objectId=bfa18db0-78d5-4d4d-8796-642151886af4/centraluseuap/2f69979d-5b21-47c4-9cf1-86fcde22b471 + x-ms-providerhub-traffic: + - 'True' + x-ms-throttling-version: + - v2 + x-msedge-ref: + - 'Ref A: 4E3F60CE46794D0CA380EF0F53F76118 Ref B: BY1AA1072317029 Ref C: 2026-01-30T23:57:25Z' + status: + code: 200 + message: OK +- request: + body: '{"properties": {"comments": "Canary passed", "stageReference": "Canary", + "stageVariables": {}, "status": "Completed"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - changesafety stageprogression update + Connection: + - keep-alive + Content-Length: + - '118' + Content-Type: + - application/json + ParameterSetName: + - --change-record-name -n --status --comments + User-Agent: + - AZURECLI/2.82.0 azsdk-python-core/1.37.0 Python/3.11.9 (Windows-10-10.0.26200-SP0) + method: PUT + uri: https://centraluseuap.management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/changeRecords/cr000002/stageProgressions/prog000003?api-version=2026-01-01-preview + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/changeRecords/cr000002/stageProgressions/prog000003","name":"prog000003","type":"microsoft.changesafety/changerecords/stageprogressions","systemData":{"createdBy":"henrydai@microsoft.com","createdByType":"User","createdAt":"2026-01-30T23:57:23.0985529Z","lastModifiedBy":"henrydai@microsoft.com","lastModifiedByType":"User","lastModifiedAt":"2026-01-30T23:57:26.5050099Z"},"properties":{"stageReference":"Canary","sequence":1,"status":"Completed","comments":"Canary + passed","stageVariables":{},"links":null,"additionalData":null,"parameters":null,"provisioningState":"Succeeded"}}' + headers: + cache-control: + - no-cache + content-length: + - '672' + content-type: + - application/json; charset=utf-8 + date: + - Fri, 30 Jan 2026 23:57:26 GMT + etag: + - '"0100d636-0000-0600-0000-697d45670000"' + expires: + - '-1' + mise-correlation-id: + - e7ec8798-0e74-4e56-836b-14b263179d07 + pragma: + - no-cache + request-context: + - appId=cid-v1:0b4319bc-3dec-4ac3-88c8-c1b86ec8e1cf + set-cookie: + - ARRAffinity=1fef50c7b13f746942d4dbd0dbb97673928df1f977cb37e394a2ffeda3575190;Path=/;HttpOnly;Secure;Domain=canary.changecontrol.changesafety.msft.net + - ARRAffinitySameSite=1fef50c7b13f746942d4dbd0dbb97673928df1f977cb37e394a2ffeda3575190;Path=/;HttpOnly;SameSite=None;Secure;Domain=canary.changecontrol.changesafety.msft.net + strict-transport-security: + - max-age=31536000; includeSubDomains + vary: + - Accept-Encoding + x-cache: + - CONFIG_NOCACHE + x-content-type-options: + - nosniff + x-ms-operation-identifier: + - tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47,objectId=bfa18db0-78d5-4d4d-8796-642151886af4/centraluseuap/0971d18a-c831-4e07-ab10-b82042bb1687 + x-ms-providerhub-traffic: + - 'True' + x-ms-ratelimit-remaining-subscription-writes: + - '799' + x-ms-throttling-version: + - v2 + x-msedge-ref: + - 'Ref A: 5FBEF40650D64B8D92791CA299F3B0BE Ref B: BY1AA1072317054 Ref C: 2026-01-30T23:57:26Z' + x-powered-by: + - ASP.NET + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + CommandName: + - changesafety stageprogression delete + Connection: + - keep-alive + Content-Length: + - '0' + ParameterSetName: + - --change-record-name -n --yes + User-Agent: + - AZURECLI/2.82.0 azsdk-python-core/1.37.0 Python/3.11.9 (Windows-10-10.0.26200-SP0) + method: DELETE + uri: https://centraluseuap.management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/changeRecords/cr000002/stageProgressions/prog000003?api-version=2026-01-01-preview + response: + body: + string: '' + headers: + cache-control: + - no-cache + content-length: + - '0' + date: + - Fri, 30 Jan 2026 23:57:28 GMT + expires: + - '-1' + mise-correlation-id: + - ce63e030-75ec-4f6d-94ca-604304b1bf28 + pragma: + - no-cache + request-context: + - appId=cid-v1:0b4319bc-3dec-4ac3-88c8-c1b86ec8e1cf + set-cookie: + - ARRAffinity=a1dd3bd4b2e949edd11f1ea24dd6378e16e4ac0eff19d14c7d7df3c670446536;Path=/;HttpOnly;Secure;Domain=canary.changecontrol.changesafety.msft.net + - ARRAffinitySameSite=a1dd3bd4b2e949edd11f1ea24dd6378e16e4ac0eff19d14c7d7df3c670446536;Path=/;HttpOnly;SameSite=None;Secure;Domain=canary.changecontrol.changesafety.msft.net + strict-transport-security: + - max-age=31536000; includeSubDomains + x-cache: + - CONFIG_NOCACHE + x-content-type-options: + - nosniff + x-ms-operation-identifier: + - tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47,objectId=bfa18db0-78d5-4d4d-8796-642151886af4/centraluseuap/1e9ff96c-7ab2-44fe-bcef-d2f59833500b + x-ms-providerhub-traffic: + - 'True' + x-ms-ratelimit-remaining-subscription-deletes: + - '799' + x-ms-throttling-version: + - v2 + x-msedge-ref: + - 'Ref A: 65C659F6A60D4FFCB01C954F5F794CC9 Ref B: BY1AA1072316060 Ref C: 2026-01-30T23:57:28Z' + x-powered-by: + - ASP.NET + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + CommandName: + - changesafety stagemap delete + Connection: + - keep-alive + Content-Length: + - '0' + ParameterSetName: + - --stage-map-name --yes + User-Agent: + - AZURECLI/2.82.0 azsdk-python-core/1.37.0 Python/3.11.9 (Windows-10-10.0.26200-SP0) + method: DELETE + uri: https://centraluseuap.management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ChangeSafety/stageMaps/stgmap000001?api-version=2026-01-01-preview + response: + body: + string: '' + headers: + cache-control: + - no-cache + content-length: + - '0' + date: + - Fri, 30 Jan 2026 23:57:28 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + x-cache: + - CONFIG_NOCACHE + x-content-type-options: + - nosniff + x-ms-operation-identifier: + - tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47,objectId=bfa18db0-78d5-4d4d-8796-642151886af4/centraluseuap/f1530df3-c537-48cc-8684-c584eb160025 + x-ms-providerhub-traffic: + - 'True' + x-ms-ratelimit-remaining-subscription-deletes: + - '799' + x-ms-throttling-version: + - v2 + x-msedge-ref: + - 'Ref A: 8FA563CFF1054372AC560B958933804F Ref B: BY1AA1072317054 Ref C: 2026-01-30T23:57:29Z' + status: + code: 200 + message: OK +version: 1 diff --git a/src/azure-changesafety/azext_changesafety/tests/latest/test_changesafety.py b/src/azure-changesafety/azext_changesafety/tests/latest/test_changesafety.py new file mode 100644 index 00000000000..5d00644a84f --- /dev/null +++ b/src/azure-changesafety/azext_changesafety/tests/latest/test_changesafety.py @@ -0,0 +1,1136 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +""" +Unit tests for azure-changesafety CLI extension. + +Tests cover ChangeRecord, StageMap, and StageProgression commands. +""" + +import copy +import datetime +import sys +import types +from types import SimpleNamespace +from unittest import mock + +from azure.cli.testsdk import ScenarioTest, JMESPathCheck + +from azext_changesafety.custom import ( + _inject_change_definition_into_content, + _inject_targets_into_result, + _normalize_targets_arg, +) +from azure.cli.core.aaz import AAZAnyType, has_value +from azure.cli.core.aaz._arg_action import AAZArgActionOperations, _ELEMENT_APPEND_KEY + + +# ============================================================================= +# ChangeRecord Tests +# ============================================================================= + + +class ChangeRecordScenario(ScenarioTest): + """Test scenarios for ChangeRecord CRUD operations.""" + + FAKE_SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" + _SCENARIO_STATE = {} + + class _DummyPoller: # pylint: disable=too-few-public-methods + """Mock poller for LRO operations.""" + + def result(self, timeout=None): # pylint: disable=unused-argument + return None + + def wait(self, timeout=None): # pylint: disable=unused-argument + return None + + def done(self): + return True + + def add_done_callback(self, func): + if func: + func(self) + + @staticmethod + def _dummy_ctx_with_change_definition(payload): + """Create a dummy context with change_definition variable.""" + dummy = SimpleNamespace() + dummy.to_serialized_data = lambda: payload + return SimpleNamespace(vars=SimpleNamespace(change_definition=dummy)) + + @classmethod + def _ensure_msrestazure_stub(cls): + """Ensure msrestazure stub is available for tests.""" + if 'msrestazure' in sys.modules: + return + + msrestazure = types.ModuleType('msrestazure') + azure_operation = types.ModuleType('msrestazure.azure_operation') + + class AzureOperationPoller: # pylint: disable=too-few-public-methods + def _delay(self, *args, **kwargs): # pylint: disable=unused-argument + return + + azure_operation.AzureOperationPoller = AzureOperationPoller + arm_polling = types.ModuleType('msrestazure.polling.arm_polling') + + class ARMPolling: # pylint: disable=too-few-public-methods + def _delay(self, *args, **kwargs): # pylint: disable=unused-argument + return + + arm_polling.ARMPolling = ARMPolling + polling = types.ModuleType('msrestazure.polling') + polling.arm_polling = arm_polling + + msrestazure.azure_operation = azure_operation + msrestazure.polling = polling + + sys.modules['msrestazure'] = msrestazure + sys.modules['msrestazure.azure_operation'] = azure_operation + sys.modules['msrestazure.polling'] = polling + sys.modules['msrestazure.polling.arm_polling'] = arm_polling + + @staticmethod + def _get_arg_value(cmd, arg_name, default=None): + """Get argument value from command context.""" + arg = getattr(cmd.ctx.args, arg_name, None) + if arg is None or not has_value(arg): + return default + return arg.to_serialized_data() + + @staticmethod + def _build_mock_instance( + name, + resource_group, + subscription_id, + change_type, + rollout_type, + targets, + comments=None, + change_definition=None, + stage_map=None, + anticipated_start_time=None, + anticipated_end_time=None): + """Build a mock ChangeRecord instance.""" + return { + "id": f"/subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.ChangeSafety/changeRecords/{name}", + "name": name, + "type": "Microsoft.ChangeSafety/changeRecords", + "location": "eastus", + "properties": { + "changeType": change_type, + "rolloutType": rollout_type, + "comments": comments, + "anticipatedStartTime": anticipated_start_time, + "anticipatedEndTime": anticipated_end_time, + "stageMap": stage_map, + "changeDefinition": change_definition or { + "kind": "Targets", + "name": name, + "details": { + "targets": targets or [] + } + } + } + } + + @staticmethod + def _mock_create_execute(cmd): + """Mock execute for ChangeRecordCreate.""" + cls = ChangeRecordScenario + cmd.pre_operations() + name = cls._get_arg_value(cmd, "change_record_name", "mock-change") + resource_group = cls._get_arg_value(cmd, "resource_group", "mock-rg") + subscription_id = cmd.ctx.subscription_id or cls.FAKE_SUBSCRIPTION_ID + change_type = cls._get_arg_value(cmd, "change_type", "ManualTouch") + rollout_type = cls._get_arg_value(cmd, "rollout_type", "Normal") + comments = cls._get_arg_value(cmd, "comments") + targets = copy.deepcopy(cmd._parsed_targets or []) + change_definition_var = getattr(cmd.ctx.vars, "change_definition", None) + change_definition_value = change_definition_var.to_serialized_data() if change_definition_var else None + stage_map_arg = getattr(cmd.ctx.args, "stage_map", None) + stage_map_value = None + if stage_map_arg is not None: + if hasattr(stage_map_arg, "to_serialized_data") and has_value(stage_map_arg): + stage_map_value = stage_map_arg.to_serialized_data() + elif isinstance(stage_map_arg, dict): + stage_map_value = stage_map_arg + if isinstance(stage_map_value, dict) and "resource_id" in stage_map_value and "resourceId" not in stage_map_value: + stage_map_value = {**stage_map_value} + stage_map_value["resourceId"] = stage_map_value.pop("resource_id") + start_time = cls._get_arg_value(cmd, "anticipated_start_time") + end_time = cls._get_arg_value(cmd, "anticipated_end_time") + instance = cls._build_mock_instance( + name=name, + resource_group=resource_group, + subscription_id=subscription_id, + change_type=change_type, + rollout_type=rollout_type, + targets=targets, + comments=comments, + change_definition=change_definition_value, + stage_map=stage_map_value, + anticipated_start_time=start_time, + anticipated_end_time=end_time, + ) + cls._SCENARIO_STATE["instance"] = copy.deepcopy(instance) + cmd.ctx.set_var("instance", copy.deepcopy(instance), schema_builder=lambda: AAZAnyType()) + cmd.post_operations() + return iter(()) + + @staticmethod + def _mock_update_execute(cmd): + """Mock execute for ChangeRecordUpdate.""" + cls = ChangeRecordScenario + cmd._parsed_targets = getattr(cmd, '_parsed_targets', None) or [] # pylint: disable=protected-access + cmd.pre_operations() + current = copy.deepcopy(cls._SCENARIO_STATE.get("instance")) + if current is None: + name = cls._get_arg_value(cmd, "change_record_name", "mock-change") + resource_group = cls._get_arg_value(cmd, "resource_group", "mock-rg") + subscription_id = cmd.ctx.subscription_id or cls.FAKE_SUBSCRIPTION_ID + current = cls._build_mock_instance( + name=name, + resource_group=resource_group, + subscription_id=subscription_id, + change_type="ManualTouch", + rollout_type="Normal", + targets=[], + ) + new_change_type = cls._get_arg_value(cmd, "change_type") + new_rollout = cls._get_arg_value(cmd, "rollout_type") + new_comments = cls._get_arg_value(cmd, "comments") + new_start = cls._get_arg_value(cmd, "anticipated_start_time") + new_end = cls._get_arg_value(cmd, "anticipated_end_time") + stage_map_arg = getattr(cmd.ctx.args, "stage_map", None) + stage_map_value = None + if stage_map_arg is not None: + if hasattr(stage_map_arg, "to_serialized_data") and has_value(stage_map_arg): + stage_map_value = stage_map_arg.to_serialized_data() + elif isinstance(stage_map_arg, dict): + stage_map_value = stage_map_arg + if isinstance(stage_map_value, dict) and "resource_id" in stage_map_value and "resourceId" not in stage_map_value: + stage_map_value = {**stage_map_value} + stage_map_value["resourceId"] = stage_map_value.pop("resource_id") + change_definition_var = getattr(cmd.ctx.vars, "change_definition", None) + change_definition_value = change_definition_var.to_serialized_data() if change_definition_var else None + if new_change_type: + current["properties"]["changeType"] = new_change_type + if new_rollout: + current["properties"]["rolloutType"] = new_rollout + if new_comments is not None: + current["properties"]["comments"] = new_comments + if new_start is not None: + current["properties"]["anticipatedStartTime"] = new_start + if new_end is not None: + current["properties"]["anticipatedEndTime"] = new_end + if stage_map_value is not None: + current["properties"]["stageMap"] = stage_map_value + if change_definition_value is not None: + current["properties"]["changeDefinition"] = change_definition_value + elif cmd._parsed_targets: # pylint: disable=protected-access + current["properties"]["changeDefinition"]["details"]["targets"] = copy.deepcopy(cmd._parsed_targets) # pylint: disable=protected-access + cls._SCENARIO_STATE["instance"] = copy.deepcopy(current) + cmd.ctx.set_var("instance", copy.deepcopy(current), schema_builder=lambda: AAZAnyType()) + cmd.post_operations() + return iter(()) + + @staticmethod + def _mock_show_execute(cmd): + """Mock execute for ChangeRecordShow.""" + cls = ChangeRecordScenario + cmd.pre_operations() + instance = copy.deepcopy(cls._SCENARIO_STATE.get("instance")) + cmd.ctx.set_var("instance", instance, schema_builder=lambda: AAZAnyType()) + cmd.post_operations() + return iter(()) + + @staticmethod + def _mock_delete_execute(cmd): + """Mock execute for ChangeRecordDelete.""" + cls = ChangeRecordScenario + cmd.pre_operations() + cls._SCENARIO_STATE.pop("instance", None) + cmd.post_operations() + return iter(()) + + @staticmethod + def _mock_build_lro_poller(cmd, executor, extract_result): # pylint: disable=unused-argument + """Mock LRO poller builder.""" + executor() + return ChangeRecordScenario._DummyPoller() + + def setUp(self): + type(self)._ensure_msrestazure_stub() + super().setUp() + type(self)._SCENARIO_STATE.clear() + self._patchers = [ + mock.patch('azext_changesafety.custom.ChangeRecordCreate._execute_operations', new=type(self)._mock_create_execute), + mock.patch('azext_changesafety.custom.ChangeRecordUpdate._execute_operations', new=type(self)._mock_update_execute), + mock.patch('azext_changesafety.custom.ChangeRecordShow._execute_operations', new=type(self)._mock_show_execute), + mock.patch('azext_changesafety.custom.ChangeRecordDelete._execute_operations', new=type(self)._mock_delete_execute), + mock.patch('azext_changesafety.custom.ChangeRecordDelete.build_lro_poller', new=type(self)._mock_build_lro_poller), + ] + for patcher in self._patchers: + patcher.start() + self.addCleanup(patcher.stop) + + # ------------------------------------------------------------------------- + # Unit Tests for Helper Functions + # ------------------------------------------------------------------------- + + def test_normalize_targets_from_operations(self): + """Test _normalize_targets_arg with AAZArgActionOperations.""" + operations = AAZArgActionOperations.__new__(AAZArgActionOperations) + operations._ops = [ # pylint: disable=protected-access + ((_ELEMENT_APPEND_KEY,), "env=prod"), + ((0, "resourceId"), "/subscriptions/000/resourceGroups/rg/providers/Microsoft.Web/sites/app"), + ((0, "operation"), "delete"), + ((1,), "subscriptionId=00000000-0000-0000-0000-000000000000"), + ] + + normalized = _normalize_targets_arg(operations) + + assert normalized == [ + "env=prod,resourceId=/subscriptions/000/resourceGroups/rg/providers/Microsoft.Web/sites/app,operation=delete", + "subscriptionId=00000000-0000-0000-0000-000000000000", + ] + + def test_normalize_targets_from_serializable_value(self): + """Test _normalize_targets_arg with serializable value.""" + class DummySerializable: + def to_serialized_data(self): + return ["rg=my-rg", None, "", "operation=show"] + + normalized = _normalize_targets_arg(DummySerializable()) + + assert normalized == ["rg=my-rg", "operation=show"] + + def test_normalize_targets_from_list_of_strings(self): + """Test _normalize_targets_arg with list of strings.""" + raw_targets = [" resourceId=/foo ", "", "operation=PUT", None] + + normalized = _normalize_targets_arg(raw_targets) + + assert normalized == ["resourceId=/foo", "operation=PUT"] + + def test_normalize_targets_with_none_returns_empty(self): + """Test _normalize_targets_arg with None returns empty list.""" + assert _normalize_targets_arg(None) == [] + + def test_inject_change_definition_into_content_adds_properties(self): + """Test _inject_change_definition_into_content adds to properties.""" + ctx = self._dummy_ctx_with_change_definition({"details": {"targets": []}}) + content = {"properties": {"existing": "value"}} + + result = _inject_change_definition_into_content(content, ctx) + + assert result["properties"]["existing"] == "value" + assert result["properties"]["changeDefinition"] == {"details": {"targets": []}} + + def test_inject_change_definition_with_empty_payload_noop(self): + """Test _inject_change_definition_into_content with empty payload is no-op.""" + ctx = self._dummy_ctx_with_change_definition({}) + original = {"properties": {"foo": "bar"}} + + result = _inject_change_definition_into_content(original.copy(), ctx) + + assert result == original + + def test_inject_targets_into_result_updates_nested_properties(self): + """Test _inject_targets_into_result updates nested properties.""" + data = {"properties": {"changeDefinition": {"details": {}}}} + targets = [{"resourceId": "/foo"}] + + _inject_targets_into_result(data, targets) + + assert data["properties"]["changeDefinition"]["details"]["targets"] == targets + + def test_inject_targets_does_not_override_existing(self): + """Test _inject_targets_into_result does not override existing targets.""" + existing = [{"resourceId": "/existing"}] + data = {"changeDefinition": {"details": {"targets": existing.copy()}}} + new_targets = [{"resourceId": "/new"}] + + _inject_targets_into_result(data, new_targets) + + assert data["changeDefinition"]["details"]["targets"] == existing + + # ------------------------------------------------------------------------- + # Integration Tests for ChangeRecord Commands + # ------------------------------------------------------------------------- + + def test_default_schedule_times_applied_on_create(self): + """Test that default schedule times are applied on create.""" + resource_group = "rgScheduleDefaults" + change_record_name = self.create_random_name('chg', 12) + target_resource = ( + f"/subscriptions/{self.FAKE_SUBSCRIPTION_ID}/resourceGroups/{resource_group}/" + "providers/Microsoft.Compute/virtualMachines/myVm" + ) + self.kwargs.update({ + "rg": resource_group, + "name": change_record_name, + "change_type": "ManualTouch", + "rollout_type": "Normal", + "targets": f"resourceId={target_resource},operation=PATCH", + }) + + result = self.cmd( + 'az changesafety changerecord create -g {rg} -n {name} ' + '--change-type {change_type} --rollout-type {rollout_type} ' + '--targets "{targets}"', + ).get_output_in_json() + + start = datetime.datetime.fromisoformat(result['properties']['anticipatedStartTime'].replace('Z', '+00:00')) + end = datetime.datetime.fromisoformat(result['properties']['anticipatedEndTime'].replace('Z', '+00:00')) + delta_seconds = abs((end - start).total_seconds() - 8 * 3600) + self.assertLessEqual(delta_seconds, 5) + + def test_stage_map_name_shortcut(self): + """Test --stagemap-name shortcut is expanded to full resource ID.""" + resource_group = "rgStageMapShortcut" + change_record_name = self.create_random_name('chg', 12) + stage_map_name = "rollout-plan" + target_resource = ( + f"/subscriptions/{self.FAKE_SUBSCRIPTION_ID}/resourceGroups/{resource_group}/" + "providers/Microsoft.Storage/storageAccounts/demo" + ) + expected_stage_map = f"/subscriptions/{self.FAKE_SUBSCRIPTION_ID}/providers/Microsoft.ChangeSafety/stageMaps/{stage_map_name}" + self.kwargs.update({ + "rg": resource_group, + "name": change_record_name, + "change_type": "ManualTouch", + "rollout_type": "Normal", + "targets": f"resourceId={target_resource},operation=PATCH", + "stage_map_name": stage_map_name, + "subscription": self.FAKE_SUBSCRIPTION_ID, + }) + + result = self.cmd( + 'az changesafety changerecord create -g {rg} -n {name} ' + '--change-type {change_type} --rollout-type {rollout_type} ' + '--targets "{targets}" --stagemap-name {stage_map_name} --subscription {subscription}', + ).get_output_in_json() + + self.assertEqual(result["properties"]["stageMap"]["resourceId"], expected_stage_map) + + def test_change_record_crud_scenario(self): + """Test full CRUD scenario for ChangeRecord.""" + resource_group = "rgChangeSafetyScenario" + change_record_name = self.create_random_name('chg', 12) + target_resource = ( + f"/subscriptions/{self.FAKE_SUBSCRIPTION_ID}/resourceGroups/{resource_group}/" + "providers/Microsoft.Compute/virtualMachines/myVm" + ) + self.kwargs.update({ + "rg": resource_group, + "name": change_record_name, + "change_type": "ManualTouch", + "rollout_type": "Normal", + "updated_rollout": "Emergency", + "targets": f"resourceId={target_resource},operation=PATCH", + }) + + # Create + create_checks = [ + JMESPathCheck('name', change_record_name), + JMESPathCheck('properties.changeType', 'ManualTouch'), + JMESPathCheck('properties.rolloutType', 'Normal'), + JMESPathCheck('properties.changeDefinition.details.targets[0].resourceId', target_resource), + JMESPathCheck('properties.changeDefinition.details.targets[0].httpMethod', 'PATCH'), + ] + self.cmd( + 'az changesafety changerecord create -g {rg} -n {name} ' + '--change-type {change_type} --rollout-type {rollout_type} ' + '--targets "{targets}" --comments "Initial deployment"', + checks=create_checks, + ) + + # Update + update_checks = [ + JMESPathCheck('properties.rolloutType', 'Emergency'), + JMESPathCheck('properties.comments', 'Escalated rollout'), + ] + self.cmd( + 'az changesafety changerecord update -g {rg} -n {name} ' + '--rollout-type {updated_rollout} --comments "Escalated rollout"', + checks=update_checks, + ) + + # Show + self.cmd( + 'az changesafety changerecord show -g {rg} -n {name}', + checks=[ + JMESPathCheck('properties.comments', 'Escalated rollout'), + JMESPathCheck('properties.changeDefinition.details.targets[0].resourceId', target_resource), + ], + ) + + # Delete + self.cmd('az changesafety changerecord delete -g {rg} -n {name} -y') + self.assertNotIn("instance", type(self)._SCENARIO_STATE) + + +# ============================================================================= +# StageMap Tests +# ============================================================================= + + +class StageMapScenario(ScenarioTest): + """Test scenarios for StageMap CRUD operations.""" + + FAKE_SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" + _SCENARIO_STATE = {} + + class _DummyPoller: # pylint: disable=too-few-public-methods + """Mock poller for LRO operations.""" + + def result(self, timeout=None): # pylint: disable=unused-argument + return None + + def wait(self, timeout=None): # pylint: disable=unused-argument + return None + + def done(self): + return True + + def add_done_callback(self, func): + if func: + func(self) + + @staticmethod + def _build_mock_stagemap(name, subscription_id, stages=None): + """Build a mock StageMap instance.""" + return { + "id": f"/subscriptions/{subscription_id}/providers/Microsoft.ChangeSafety/stageMaps/{name}", + "name": name, + "type": "Microsoft.ChangeSafety/stageMaps", + "properties": { + "stages": stages or [ + {"name": "Stage1", "sequence": 1}, + {"name": "Stage2", "sequence": 2}, + ] + } + } + + @staticmethod + def _mock_create_execute(cmd): + """Mock execute for StageMap Create.""" + cls = StageMapScenario + cmd.pre_operations() + name_arg = getattr(cmd.ctx.args, "stage_map_name", None) + name = name_arg.to_serialized_data() if name_arg and has_value(name_arg) else "mock-stagemap" + subscription_id = cmd.ctx.subscription_id or cls.FAKE_SUBSCRIPTION_ID + stages_arg = getattr(cmd.ctx.args, "stages", None) + stages = stages_arg.to_serialized_data() if stages_arg and has_value(stages_arg) else None + instance = cls._build_mock_stagemap(name, subscription_id, stages) + cls._SCENARIO_STATE["stagemap"] = copy.deepcopy(instance) + cmd.ctx.set_var("instance", copy.deepcopy(instance), schema_builder=lambda: AAZAnyType()) + cmd.post_operations() + return iter(()) + + @staticmethod + def _mock_show_execute(cmd): + """Mock execute for StageMap Show.""" + cls = StageMapScenario + cmd.pre_operations() + instance = copy.deepcopy(cls._SCENARIO_STATE.get("stagemap")) + cmd.ctx.set_var("instance", instance, schema_builder=lambda: AAZAnyType()) + cmd.post_operations() + return iter(()) + + @staticmethod + def _mock_update_execute(cmd): + """Mock execute for StageMap Update.""" + cls = StageMapScenario + cmd.pre_operations() + current = copy.deepcopy(cls._SCENARIO_STATE.get("stagemap")) + if current is None: + name_arg = getattr(cmd.ctx.args, "stage_map_name", None) + name = name_arg.to_serialized_data() if name_arg and has_value(name_arg) else "mock-stagemap" + subscription_id = cmd.ctx.subscription_id or cls.FAKE_SUBSCRIPTION_ID + current = cls._build_mock_stagemap(name, subscription_id) + stages_arg = getattr(cmd.ctx.args, "stages", None) + if stages_arg and has_value(stages_arg): + current["properties"]["stages"] = stages_arg.to_serialized_data() + cls._SCENARIO_STATE["stagemap"] = copy.deepcopy(current) + cmd.ctx.set_var("instance", copy.deepcopy(current), schema_builder=lambda: AAZAnyType()) + cmd.post_operations() + return iter(()) + + @staticmethod + def _mock_delete_execute(cmd): + """Mock execute for StageMap Delete.""" + cls = StageMapScenario + cmd.pre_operations() + cls._SCENARIO_STATE.pop("stagemap", None) + cmd.post_operations() + return iter(()) + + @staticmethod + def _mock_list_execute(cmd): + """Mock execute for StageMap List.""" + cls = StageMapScenario + cmd.pre_operations() + stagemap = cls._SCENARIO_STATE.get("stagemap") + result = [stagemap] if stagemap else [] + cmd.ctx.set_var("instance", {"value": result}, schema_builder=lambda: AAZAnyType()) + cmd.post_operations() + return iter(()) + + @staticmethod + def _mock_build_lro_poller(cmd, executor, extract_result): # pylint: disable=unused-argument + """Mock LRO poller builder.""" + executor() + return StageMapScenario._DummyPoller() + + def setUp(self): + super().setUp() + type(self)._SCENARIO_STATE.clear() + self._patchers = [ + mock.patch('azext_changesafety.aaz.latest.changesafety.stagemap._create.Create._execute_operations', new=type(self)._mock_create_execute), + mock.patch('azext_changesafety.aaz.latest.changesafety.stagemap._show.Show._execute_operations', new=type(self)._mock_show_execute), + mock.patch('azext_changesafety.aaz.latest.changesafety.stagemap._update.Update._execute_operations', new=type(self)._mock_update_execute), + mock.patch('azext_changesafety.aaz.latest.changesafety.stagemap._delete.Delete._execute_operations', new=type(self)._mock_delete_execute), + mock.patch('azext_changesafety.aaz.latest.changesafety.stagemap._list.List._execute_operations', new=type(self)._mock_list_execute), + mock.patch('azext_changesafety.aaz.latest.changesafety.stagemap._delete.Delete.build_lro_poller', new=type(self)._mock_build_lro_poller), + ] + for patcher in self._patchers: + patcher.start() + self.addCleanup(patcher.stop) + + def test_stagemap_create(self): + """Test StageMap create command.""" + stagemap_name = self.create_random_name('stgmap', 12) + self.kwargs.update({ + "name": stagemap_name, + "subscription": self.FAKE_SUBSCRIPTION_ID, + }) + + result = self.cmd( + 'az changesafety stagemap create --stage-map-name {name} ' + '--stages "[{{name:Stage1,sequence:1}},{{name:Stage2,sequence:2}}]" ' + '--subscription {subscription}', + ).get_output_in_json() + + self.assertEqual(result["name"], stagemap_name) + self.assertIn("stages", result["properties"]) + + def test_stagemap_show(self): + """Test StageMap show command.""" + stagemap_name = self.create_random_name('stgmap', 12) + self.kwargs.update({ + "name": stagemap_name, + "subscription": self.FAKE_SUBSCRIPTION_ID, + }) + + # Create first + self.cmd( + 'az changesafety stagemap create --stage-map-name {name} ' + '--stages "[{{name:Stage1,sequence:1}}]" ' + '--subscription {subscription}', + ) + + # Show + result = self.cmd( + 'az changesafety stagemap show --stage-map-name {name} ' + '--subscription {subscription}', + ).get_output_in_json() + + self.assertEqual(result["name"], stagemap_name) + + def test_stagemap_delete(self): + """Test StageMap delete command.""" + stagemap_name = self.create_random_name('stgmap', 12) + self.kwargs.update({ + "name": stagemap_name, + "subscription": self.FAKE_SUBSCRIPTION_ID, + }) + + # Create first + self.cmd( + 'az changesafety stagemap create --stage-map-name {name} ' + '--stages "[{{name:Stage1,sequence:1}}]" ' + '--subscription {subscription}', + ) + + # Delete + self.cmd( + 'az changesafety stagemap delete --stage-map-name {name} ' + '--subscription {subscription} --yes', + ) + + self.assertNotIn("stagemap", type(self)._SCENARIO_STATE) + + +# ============================================================================= +# StageProgression Tests +# ============================================================================= + + +class StageProgressionScenario(ScenarioTest): + """Test scenarios for StageProgression CRUD operations.""" + + FAKE_SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" + _SCENARIO_STATE = {} + + class _DummyPoller: # pylint: disable=too-few-public-methods + """Mock poller for LRO operations.""" + + def result(self, timeout=None): # pylint: disable=unused-argument + return None + + def wait(self, timeout=None): # pylint: disable=unused-argument + return None + + def done(self): + return True + + def add_done_callback(self, func): + if func: + func(self) + + @staticmethod + def _build_mock_stageprogression(name, change_record_name, subscription_id, stage_reference, status="InProgress", comments=None): + """Build a mock StageProgression instance.""" + return { + "id": f"/subscriptions/{subscription_id}/providers/Microsoft.ChangeSafety/changeRecords/{change_record_name}/stageProgressions/{name}", + "name": name, + "type": "Microsoft.ChangeSafety/changeRecords/stageProgressions", + "properties": { + "stageReference": stage_reference, + "status": status, + "comments": comments, + } + } + + @staticmethod + def _mock_create_execute(cmd): + """Mock execute for StageProgression Create.""" + cls = StageProgressionScenario + cmd.pre_operations() + name_arg = getattr(cmd.ctx.args, "stage_progression_name", None) + name = name_arg.to_serialized_data() if name_arg and has_value(name_arg) else "mock-progression" + cr_arg = getattr(cmd.ctx.args, "change_record_name", None) + change_record_name = cr_arg.to_serialized_data() if cr_arg and has_value(cr_arg) else "mock-changerecord" + subscription_id = cmd.ctx.subscription_id or cls.FAKE_SUBSCRIPTION_ID + stage_ref_arg = getattr(cmd.ctx.args, "stage_reference", None) + stage_reference = stage_ref_arg.to_serialized_data() if stage_ref_arg and has_value(stage_ref_arg) else "Stage1" + status_arg = getattr(cmd.ctx.args, "status", None) + status = status_arg.to_serialized_data() if status_arg and has_value(status_arg) else "InProgress" + comments_arg = getattr(cmd.ctx.args, "comments", None) + comments = comments_arg.to_serialized_data() if comments_arg and has_value(comments_arg) else None + instance = cls._build_mock_stageprogression(name, change_record_name, subscription_id, stage_reference, status, comments) + cls._SCENARIO_STATE["stageprogression"] = copy.deepcopy(instance) + cmd.ctx.set_var("instance", copy.deepcopy(instance), schema_builder=lambda: AAZAnyType()) + cmd.post_operations() + return iter(()) + + @staticmethod + def _mock_show_execute(cmd): + """Mock execute for StageProgression Show.""" + cls = StageProgressionScenario + cmd.pre_operations() + instance = copy.deepcopy(cls._SCENARIO_STATE.get("stageprogression")) + cmd.ctx.set_var("instance", instance, schema_builder=lambda: AAZAnyType()) + cmd.post_operations() + return iter(()) + + @staticmethod + def _mock_update_execute(cmd): + """Mock execute for StageProgression Update.""" + cls = StageProgressionScenario + cmd.pre_operations() + current = copy.deepcopy(cls._SCENARIO_STATE.get("stageprogression")) + if current is None: + name_arg = getattr(cmd.ctx.args, "stage_progression_name", None) + name = name_arg.to_serialized_data() if name_arg and has_value(name_arg) else "mock-progression" + cr_arg = getattr(cmd.ctx.args, "change_record_name", None) + change_record_name = cr_arg.to_serialized_data() if cr_arg and has_value(cr_arg) else "mock-changerecord" + subscription_id = cmd.ctx.subscription_id or cls.FAKE_SUBSCRIPTION_ID + current = cls._build_mock_stageprogression(name, change_record_name, subscription_id, "Stage1") + status_arg = getattr(cmd.ctx.args, "status", None) + if status_arg and has_value(status_arg): + current["properties"]["status"] = status_arg.to_serialized_data() + comments_arg = getattr(cmd.ctx.args, "comments", None) + if comments_arg and has_value(comments_arg): + current["properties"]["comments"] = comments_arg.to_serialized_data() + cls._SCENARIO_STATE["stageprogression"] = copy.deepcopy(current) + cmd.ctx.set_var("instance", copy.deepcopy(current), schema_builder=lambda: AAZAnyType()) + cmd.post_operations() + return iter(()) + + @staticmethod + def _mock_delete_execute(cmd): + """Mock execute for StageProgression Delete.""" + cls = StageProgressionScenario + cmd.pre_operations() + cls._SCENARIO_STATE.pop("stageprogression", None) + cmd.post_operations() + return iter(()) + + @staticmethod + def _mock_list_execute(cmd): + """Mock execute for StageProgression List.""" + cls = StageProgressionScenario + cmd.pre_operations() + progression = cls._SCENARIO_STATE.get("stageprogression") + result = [progression] if progression else [] + cmd.ctx.set_var("instance", {"value": result}, schema_builder=lambda: AAZAnyType()) + cmd.post_operations() + return iter(()) + + @staticmethod + def _mock_build_lro_poller(cmd, executor, extract_result): # pylint: disable=unused-argument + """Mock LRO poller builder.""" + executor() + return StageProgressionScenario._DummyPoller() + + def setUp(self): + super().setUp() + type(self)._SCENARIO_STATE.clear() + self._patchers = [ + mock.patch('azext_changesafety.aaz.latest.changesafety.stageprogression._create.Create._execute_operations', new=type(self)._mock_create_execute), + mock.patch('azext_changesafety.aaz.latest.changesafety.stageprogression._show.Show._execute_operations', new=type(self)._mock_show_execute), + mock.patch('azext_changesafety.aaz.latest.changesafety.stageprogression._update.Update._execute_operations', new=type(self)._mock_update_execute), + mock.patch('azext_changesafety.aaz.latest.changesafety.stageprogression._delete.Delete._execute_operations', new=type(self)._mock_delete_execute), + mock.patch('azext_changesafety.aaz.latest.changesafety.stageprogression._list.List._execute_operations', new=type(self)._mock_list_execute), + mock.patch('azext_changesafety.aaz.latest.changesafety.stageprogression._delete.Delete.build_lro_poller', new=type(self)._mock_build_lro_poller), + ] + for patcher in self._patchers: + patcher.start() + self.addCleanup(patcher.stop) + + def test_stageprogression_create(self): + """Test StageProgression create command.""" + progression_name = self.create_random_name('prog', 12) + change_record_name = "test-changerecord" + self.kwargs.update({ + "name": progression_name, + "change_record": change_record_name, + "subscription": self.FAKE_SUBSCRIPTION_ID, + }) + + result = self.cmd( + 'az changesafety stageprogression create -n {name} ' + '--change-record-name {change_record} ' + '--stage-reference Stage1 --status InProgress ' + '--subscription {subscription}', + ).get_output_in_json() + + self.assertEqual(result["name"], progression_name) + self.assertEqual(result["properties"]["stageReference"], "Stage1") + self.assertEqual(result["properties"]["status"], "InProgress") + + def test_stageprogression_show(self): + """Test StageProgression show command.""" + progression_name = self.create_random_name('prog', 12) + change_record_name = "test-changerecord" + self.kwargs.update({ + "name": progression_name, + "change_record": change_record_name, + "subscription": self.FAKE_SUBSCRIPTION_ID, + }) + + # Create first + self.cmd( + 'az changesafety stageprogression create -n {name} ' + '--change-record-name {change_record} ' + '--stage-reference Stage1 --status InProgress ' + '--subscription {subscription}', + ) + + # Show + result = self.cmd( + 'az changesafety stageprogression show -n {name} ' + '--change-record-name {change_record} ' + '--subscription {subscription}', + ).get_output_in_json() + + self.assertEqual(result["name"], progression_name) + + def test_stageprogression_update(self): + """Test StageProgression update command.""" + progression_name = self.create_random_name('prog', 12) + change_record_name = "test-changerecord" + self.kwargs.update({ + "name": progression_name, + "change_record": change_record_name, + "subscription": self.FAKE_SUBSCRIPTION_ID, + }) + + # Create first + self.cmd( + 'az changesafety stageprogression create -n {name} ' + '--change-record-name {change_record} ' + '--stage-reference Stage1 --status InProgress ' + '--subscription {subscription}', + ) + + # Update + result = self.cmd( + 'az changesafety stageprogression update -n {name} ' + '--change-record-name {change_record} ' + '--status Completed --comments "Stage completed successfully" ' + '--subscription {subscription}', + ).get_output_in_json() + + self.assertEqual(result["properties"]["status"], "Completed") + self.assertEqual(result["properties"]["comments"], "Stage completed successfully") + + def test_stageprogression_delete(self): + """Test StageProgression delete command.""" + progression_name = self.create_random_name('prog', 12) + change_record_name = "test-changerecord" + self.kwargs.update({ + "name": progression_name, + "change_record": change_record_name, + "subscription": self.FAKE_SUBSCRIPTION_ID, + }) + + # Create first + self.cmd( + 'az changesafety stageprogression create -n {name} ' + '--change-record-name {change_record} ' + '--stage-reference Stage1 --status InProgress ' + '--subscription {subscription}', + ) + + # Delete + self.cmd( + 'az changesafety stageprogression delete -n {name} ' + '--change-record-name {change_record} ' + '--subscription {subscription} --yes', + ) + + self.assertNotIn("stageprogression", type(self)._SCENARIO_STATE) + + def test_stageprogression_crud_scenario(self): + """Test full CRUD scenario for StageProgression.""" + progression_name = self.create_random_name('prog', 12) + change_record_name = "deployment-cr" + self.kwargs.update({ + "name": progression_name, + "change_record": change_record_name, + "subscription": self.FAKE_SUBSCRIPTION_ID, + }) + + # Create + self.cmd( + 'az changesafety stageprogression create -n {name} ' + '--change-record-name {change_record} ' + '--stage-reference Stage1 --status InProgress ' + '--subscription {subscription}', + checks=[ + JMESPathCheck('name', progression_name), + JMESPathCheck('properties.stageReference', 'Stage1'), + JMESPathCheck('properties.status', 'InProgress'), + ], + ) + + # Update + self.cmd( + 'az changesafety stageprogression update -n {name} ' + '--change-record-name {change_record} ' + '--status Completed --comments "Finished stage 1" ' + '--subscription {subscription}', + checks=[ + JMESPathCheck('properties.status', 'Completed'), + JMESPathCheck('properties.comments', 'Finished stage 1'), + ], + ) + + # Show + self.cmd( + 'az changesafety stageprogression show -n {name} ' + '--change-record-name {change_record} ' + '--subscription {subscription}', + checks=[ + JMESPathCheck('properties.status', 'Completed'), + ], + ) + + # Delete + self.cmd( + 'az changesafety stageprogression delete -n {name} ' + '--change-record-name {change_record} ' + '--subscription {subscription} --yes', + ) + self.assertNotIn("stageprogression", type(self)._SCENARIO_STATE) + + +# ============================================================================= +# Live Tests for Recordings (Run with: azdev test azure-changesafety --live) +# ============================================================================= + + +def _ensure_msrestazure_stub(): + """Ensure msrestazure stub is available for tests.""" + if 'msrestazure' in sys.modules: + return + msrestazure = types.ModuleType('msrestazure') + azure_operation = types.ModuleType('msrestazure.azure_operation') + + class AzureOperationPoller: # pylint: disable=too-few-public-methods + def _delay(self, *args, **kwargs): # pylint: disable=unused-argument + return + + azure_operation.AzureOperationPoller = AzureOperationPoller + arm_polling = types.ModuleType('msrestazure.polling.arm_polling') + + class ARMPolling: # pylint: disable=too-few-public-methods + def _delay(self, *args, **kwargs): # pylint: disable=unused-argument + return + + arm_polling.ARMPolling = ARMPolling + polling = types.ModuleType('msrestazure.polling') + polling.arm_polling = arm_polling + msrestazure.azure_operation = azure_operation + msrestazure.polling = polling + sys.modules['msrestazure'] = msrestazure + sys.modules['msrestazure.azure_operation'] = azure_operation + sys.modules['msrestazure.polling'] = polling + sys.modules['msrestazure.polling.arm_polling'] = arm_polling + + +# Ensure stub is loaded before test collection +_ensure_msrestazure_stub() + + +class ChangeSafetyLiveScenario(ScenarioTest): + """Live test scenarios for generating recordings. + + Run with: azdev test azure-changesafety --live + Or: pytest test_changesafety.py::ChangeSafetyLiveScenario --live + + These tests make actual API calls and generate YAML recordings. + """ + + def test_changesafety_full_scenario(self): + """Full CRUD scenario for ChangeRecord, StageMap, and StageProgression.""" + # Use random names to avoid conflicts + stagemap_name = self.create_random_name('stgmap', 15) + change_record_name = self.create_random_name('cr', 15) + progression_name = self.create_random_name('prog', 15) + + self.kwargs.update({ + 'stagemap_name': stagemap_name, + 'cr_name': change_record_name, + 'prog_name': progression_name, + }) + + # ================================================================= + # StageMap CRUD + # ================================================================= + + # Create StageMap + self.cmd( + 'az changesafety stagemap create ' + '--stage-map-name {stagemap_name} ' + '--stages "[{{name:Canary,sequence:1}},{{name:Production,sequence:2}}]"', + checks=[ + JMESPathCheck('name', stagemap_name), + JMESPathCheck('properties.stages[0].name', 'Canary'), + JMESPathCheck('properties.stages[1].name', 'Production'), + ] + ) + + # Show StageMap + self.cmd( + 'az changesafety stagemap show --stage-map-name {stagemap_name}', + checks=[ + JMESPathCheck('name', stagemap_name), + ] + ) + + # Note: List commands skipped - response too large for recording + + # ================================================================= + # ChangeRecord CRUD + # ================================================================= + + # Create ChangeRecord with StageMap reference + self.cmd( + 'az changesafety changerecord create ' + '-n {cr_name} ' + '--change-type AppDeployment ' + '--rollout-type Normal ' + '--stagemap-name {stagemap_name} ' + '--targets "subscriptionId=$(az account show --query id -o tsv)"', + checks=[ + JMESPathCheck('name', change_record_name), + JMESPathCheck('properties.changeType', 'AppDeployment'), + ] + ) + + # Show ChangeRecord + self.cmd( + 'az changesafety changerecord show -n {cr_name}', + checks=[ + JMESPathCheck('name', change_record_name), + ] + ) + + # Update ChangeRecord + self.cmd( + 'az changesafety changerecord update -n {cr_name} ' + '--rollout-type Emergency --comments "Escalated"', + checks=[ + JMESPathCheck('properties.rolloutType', 'Emergency'), + JMESPathCheck('properties.comments', 'Escalated'), + ] + ) + + # ================================================================= + # StageProgression CRUD + # ================================================================= + + # Create StageProgression + self.cmd( + 'az changesafety stageprogression create ' + '--change-record-name {cr_name} ' + '-n {prog_name} ' + '--stage-reference Canary ' + '--status InProgress', + checks=[ + JMESPathCheck('name', progression_name), + JMESPathCheck('properties.stageReference', 'Canary'), + JMESPathCheck('properties.status', 'InProgress'), + ] + ) + + # Show StageProgression + self.cmd( + 'az changesafety stageprogression show ' + '--change-record-name {cr_name} -n {prog_name}', + checks=[ + JMESPathCheck('name', progression_name), + ] + ) + + # Update StageProgression + self.cmd( + 'az changesafety stageprogression update ' + '--change-record-name {cr_name} -n {prog_name} ' + '--status Completed --comments "Canary passed"', + checks=[ + JMESPathCheck('properties.status', 'Completed'), + ] + ) + + # Delete StageProgression + self.cmd('az changesafety stageprogression delete ' + '--change-record-name {cr_name} -n {prog_name} --yes') + + # ================================================================= + # Cleanup + # ================================================================= + + # Note: ChangeRecord may need to be in terminal state to delete + # Delete StageMap (if not referenced) + self.cmd('az changesafety stagemap delete --stage-map-name {stagemap_name} --yes') + diff --git a/src/azure-changesafety/setup.cfg b/src/azure-changesafety/setup.cfg new file mode 100644 index 00000000000..2fdd96e5d39 --- /dev/null +++ b/src/azure-changesafety/setup.cfg @@ -0,0 +1 @@ +#setup.cfg \ No newline at end of file diff --git a/src/azure-changesafety/setup.py b/src/azure-changesafety/setup.py new file mode 100644 index 00000000000..0e68f9c4516 --- /dev/null +++ b/src/azure-changesafety/setup.py @@ -0,0 +1,49 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +from codecs import open +from setuptools import setup, find_packages + + +# HISTORY.rst entry. +VERSION = '1.0.0b1' + +# The full list of classifiers is available at +# https://pypi.python.org/pypi?%3Aaction=list_classifiers +CLASSIFIERS = [ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'Intended Audience :: System Administrators', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'License :: OSI Approved :: MIT License', +] + +DEPENDENCIES = [] + +with open('README.md', 'r', encoding='utf-8') as f: + README = f.read() +with open('HISTORY.rst', 'r', encoding='utf-8') as f: + HISTORY = f.read() + +setup( + name='azure-changesafety', + version=VERSION, + description='Microsoft Azure Command-Line Tools ChangeSafety Extension.', + long_description=README + '\n\n' + HISTORY, + license='MIT', + author='Microsoft Corporation', + author_email='azpycli@microsoft.com', + url='https://github.com/Azure/azure-cli-extensions/tree/main/src/azure-changesafety', + classifiers=CLASSIFIERS, + packages=find_packages(exclude=["tests", "build", "build.*"]), + package_data={'azext_changesafety': ['azext_metadata.json']}, + install_requires=DEPENDENCIES +) diff --git a/src/service_name.json b/src/service_name.json index 24283c09b6f..e489cc04a02 100644 --- a/src/service_name.json +++ b/src/service_name.json @@ -978,5 +978,10 @@ "Command": "az migrate", "AzureServiceName": "Azure Migrate", "URL": "https://learn.microsoft.com/azure/migrate" + }, + { + "Command": "az changesafety", + "AzureServiceName": "ChangeSafety", + "URL": "" } ]