Skip to content

Commit 2f72252

Browse files
author
Henry Dai
committed
Fix custom
1 parent 94890e9 commit 2f72252

14 files changed

Lines changed: 2424 additions & 756 deletions

File tree

src/azure-changesafety/README.md

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Azure CLI Change Safety Extension
2-
Azure CLI extension for managing Change Safety `ChangeRecord` resources. A ChangeRecord describes a planned change to one or more Azure resources, enabling coordination, tracking, and safe deployment across your environment.
2+
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.
33

44
## Installation
55
```bash
@@ -9,16 +9,47 @@ az extension add --name azure-changesafety
99
```
1010

1111
## Commands
12+
13+
### ChangeRecord
1214
```bash
1315
az changesafety changerecord create # Create a ChangeRecord for one or more targets.
1416
az changesafety changerecord update # Update metadata, rollout configuration, or target definitions.
1517
az changesafety changerecord delete # Delete a ChangeRecord resource.
1618
az changesafety changerecord show # Display details for a ChangeRecord resource.
19+
az changesafety changerecord list # List ChangeRecord resources.
20+
```
21+
22+
### StageMap
23+
```bash
24+
az changesafety stagemap create # Create a StageMap defining rollout stages.
25+
az changesafety stagemap update # Update StageMap stages.
26+
az changesafety stagemap delete # Delete a StageMap resource.
27+
az changesafety stagemap show # Display details for a StageMap resource.
28+
az changesafety stagemap list # List StageMap resources.
29+
```
30+
31+
### StageProgression
32+
```bash
33+
az changesafety stageprogression create # Create a StageProgression to track stage execution.
34+
az changesafety stageprogression update # Update StageProgression status or comments.
35+
az changesafety stageprogression delete # Delete a StageProgression resource.
36+
az changesafety stageprogression show # Display details for a StageProgression resource.
37+
az changesafety stageprogression list # List StageProgression resources for a ChangeRecord.
1738
```
1839

19-
Run `az changesafety changerecord -h` to see full parameter details and examples.
40+
Run `az changesafety -h` to see full command groups and examples.
2041

2142
## Examples
43+
44+
### StageMap Examples
45+
Create a two-stage StageMap for rollout:
46+
```bash
47+
az changesafety stagemap create \
48+
--stage-map-name rolloutStageMap \
49+
--stages "[{name:Canary,sequence:1},{name:Production,sequence:2}]"
50+
```
51+
52+
### ChangeRecord Examples
2253
Create a ChangeRecord for a manual touch operation (e.g., delete a Traffic Manager profile):
2354
```bash
2455
az changesafety changerecord create \
@@ -38,7 +69,7 @@ az changesafety changerecord create \
3869
--change-type AppDeployment \
3970
--rollout-type Normal \
4071
--targets "resourceId=/subscriptions/<subId>/resourceGroups/MyResourceGroup/providers/Microsoft.Web/sites/myApp,operation=PUT" \
41-
--stage-map "{resource-id:/subscriptions/<subId>/resourceGroups/MyResourceGroup/providers/Microsoft.ChangeSafety/stageMaps/rolloutStageMap}" \
72+
--stagemap-name rolloutStageMap \
4273
--links name=Runbook uri=https://contoso.com/runbook
4374
```
4475

@@ -51,11 +82,25 @@ az changesafety changerecord update \
5182
--comments "Escalated due to customer impact"
5283
```
5384

54-
Delete a ChangeRecord:
85+
### StageProgression Examples
86+
Create a StageProgression for the Canary stage:
87+
```bash
88+
az changesafety stageprogression create \
89+
--change-record-name changerecord-webapp-rollout \
90+
-n canary-progression \
91+
--stage-reference Canary \
92+
--status InProgress
93+
```
94+
95+
Update StageProgression to mark stage as completed:
5596
```bash
56-
az changesafety changerecord delete -g MyResourceGroup -n changerecord-webapp-rollout --yes
97+
az changesafety stageprogression update \
98+
--change-record-name changerecord-webapp-rollout \
99+
-n canary-progression \
100+
--status Completed \
101+
--comments "Canary validation passed"
57102
```
58103

59104
## Additional Information
60-
- View command documentation: `az changesafety changerecord -h`
105+
- View command documentation: `az changesafety -h`
61106
- Remove the extension when no longer needed: `az extension remove --name azure-changesafety`

src/azure-changesafety/azext_changesafety/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
from azure.cli.core import AzCommandsLoader
99
from azext_changesafety._help import helps # pylint: disable=unused-import
10+
# Import custom to apply AZ_HELP patches for StageMap commands
11+
from azext_changesafety import custom as _custom # pylint: disable=unused-import
1012

1113

1214
class ChangeRecordCommandsLoader(AzCommandsLoader):

src/azure-changesafety/azext_changesafety/_help.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,74 @@
117117
text: |-
118118
az changesafety changerecord show -g MyResourceGroup -n changerecord001
119119
"""
120+
121+
helps['changesafety stagemap'] = """
122+
type: group
123+
short-summary: Manage StageMap resources that define rollout stages for orchestrated changes.
124+
"""
125+
126+
helps['changesafety stagemap create'] = """
127+
type: command
128+
short-summary: Create a StageMap resource.
129+
long-summary: >
130+
A StageMap defines the stages through which a change progresses during rollout.
131+
Each stage has a name and sequence number. Stages are executed in order of their
132+
sequence values. StageMap resources can be referenced by ChangeRecord resources
133+
to enforce staged rollout patterns.
134+
parameters:
135+
- name: --stage-map-name
136+
short-summary: The name of the StageMap resource to create.
137+
- name: --stages
138+
short-summary: >
139+
Array of stage definitions. Each stage requires a name and sequence number.
140+
Use shorthand syntax or JSON format.
141+
examples:
142+
- name: Create a simple two-stage StageMap
143+
text: |-
144+
az changesafety stagemap create --subscription 00000000-0000-0000-0000-000000000000 --stage-map-name rolloutStageMap --stages "[{name:Canary,sequence:1},{name:Production,sequence:2}]"
145+
- name: Create a StageMap with three stages
146+
text: |-
147+
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}]"
148+
"""
149+
150+
helps['changesafety stagemap update'] = """
151+
type: command
152+
short-summary: Update an existing StageMap resource.
153+
long-summary: >
154+
Modify the stages defined in a StageMap. When updating, provide the complete
155+
list of stages as the update replaces the existing stages array.
156+
examples:
157+
- name: Add a new stage to an existing StageMap
158+
text: |-
159+
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}]"
160+
"""
161+
162+
helps['changesafety stagemap show'] = """
163+
type: command
164+
short-summary: Get details for a StageMap resource.
165+
examples:
166+
- name: Show a StageMap
167+
text: |-
168+
az changesafety stagemap show --subscription 00000000-0000-0000-0000-000000000000 --stage-map-name rolloutStageMap
169+
"""
170+
171+
helps['changesafety stagemap delete'] = """
172+
type: command
173+
short-summary: Delete a StageMap resource.
174+
long-summary: >
175+
Delete a StageMap that is no longer needed. Note that StageMap resources
176+
that are currently referenced by active ChangeRecord resources cannot be deleted.
177+
examples:
178+
- name: Delete a StageMap
179+
text: |-
180+
az changesafety stagemap delete --subscription 00000000-0000-0000-0000-000000000000 --stage-map-name rolloutStageMap --yes
181+
"""
182+
183+
helps['changesafety stagemap list'] = """
184+
type: command
185+
short-summary: List StageMap resources in a subscription.
186+
examples:
187+
- name: List all StageMaps in the subscription
188+
text: |-
189+
az changesafety stagemap list --subscription 00000000-0000-0000-0000-000000000000
190+
"""

src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/_create.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ class Create(AAZCommand):
2121
_aaz_info = {
2222
"version": "2026-01-01-preview",
2323
"resources": [
24-
["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/changestates/{}/stageprogressions/{}", "2026-01-01-preview"],
25-
["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.changesafety/changestates/{}/stageprogressions/{}", "2026-01-01-preview"],
24+
["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/changerecords/{}/stageprogressions/{}", "2026-01-01-preview"],
25+
["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.changesafety/changerecords/{}/stageprogressions/{}", "2026-01-01-preview"],
2626
]
2727
}
2828

@@ -42,9 +42,9 @@ def _build_arguments_schema(cls, *args, **kwargs):
4242
# define Arg Group ""
4343

4444
_args_schema = cls._args_schema
45-
_args_schema.change_state_name = AAZStrArg(
46-
options=["--change-state-name"],
47-
help="The name of the ChangeState resource.",
45+
_args_schema.change_record_name = AAZStrArg(
46+
options=["--change-record-name"],
47+
help="The name of the ChangeRecord resource.",
4848
required=True,
4949
fmt=AAZStrArgFormat(
5050
pattern="^[a-zA-Z0-9-]{3,100}$",
@@ -55,7 +55,7 @@ def _build_arguments_schema(cls, *args, **kwargs):
5555
_args_schema.resource_group = AAZResourceGroupNameArg()
5656
_args_schema.stage_progression_name = AAZStrArg(
5757
options=["-n", "--name", "--stage-progression-name"],
58-
help="name of the stageProgression",
58+
help="Name of the stageProgression",
5959
required=True,
6060
fmt=AAZStrArgFormat(
6161
pattern="^[a-zA-Z0-9-|]{3,100}$",
@@ -143,12 +143,12 @@ def _build_arguments_schema(cls, *args, **kwargs):
143143

144144
def _execute_operations(self):
145145
self.pre_operations()
146-
condition_0 = has_value(self.ctx.args.change_state_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
147-
condition_1 = has_value(self.ctx.args.change_state_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)
146+
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
147+
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)
148148
if condition_0:
149-
self.StageProgressionsCreateOrUpdateAtSubscriptionLevel(ctx=self.ctx)()
149+
self.ChangeRecordStageProgressionsCreateOrUpdateAtSubscriptionLevel(ctx=self.ctx)()
150150
if condition_1:
151-
self.StageProgressionsCreateOrUpdate(ctx=self.ctx)()
151+
self.ChangeRecordStageProgressionsCreateOrUpdate(ctx=self.ctx)()
152152
self.post_operations()
153153

154154
@register_callback
@@ -163,7 +163,7 @@ def _output(self, *args, **kwargs):
163163
result = self.deserialize_output(self.ctx.vars.instance, client_flatten=True)
164164
return result
165165

166-
class StageProgressionsCreateOrUpdateAtSubscriptionLevel(AAZHttpOperation):
166+
class ChangeRecordStageProgressionsCreateOrUpdateAtSubscriptionLevel(AAZHttpOperation):
167167
CLIENT_TYPE = "MgmtClient"
168168

169169
def __call__(self, *args, **kwargs):
@@ -177,7 +177,7 @@ def __call__(self, *args, **kwargs):
177177
@property
178178
def url(self):
179179
return self.client.format_url(
180-
"/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/changeStates/{changeStateName}/stageProgressions/{stageProgressionName}",
180+
"/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}/stageProgressions/{stageProgressionName}",
181181
**self.url_parameters
182182
)
183183

@@ -193,7 +193,7 @@ def error_format(self):
193193
def url_parameters(self):
194194
parameters = {
195195
**self.serialize_url_param(
196-
"changeStateName", self.ctx.args.change_state_name,
196+
"changeRecordName", self.ctx.args.change_record_name,
197197
required=True,
198198
),
199199
**self.serialize_url_param(
@@ -366,7 +366,7 @@ def _build_schema_on_200_201(cls):
366366

367367
return cls._schema_on_200_201
368368

369-
class StageProgressionsCreateOrUpdate(AAZHttpOperation):
369+
class ChangeRecordStageProgressionsCreateOrUpdate(AAZHttpOperation):
370370
CLIENT_TYPE = "MgmtClient"
371371

372372
def __call__(self, *args, **kwargs):
@@ -380,7 +380,7 @@ def __call__(self, *args, **kwargs):
380380
@property
381381
def url(self):
382382
return self.client.format_url(
383-
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ChangeSafety/changeStates/{changeStateName}/stageProgressions/{stageProgressionName}",
383+
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}/stageProgressions/{stageProgressionName}",
384384
**self.url_parameters
385385
)
386386

@@ -396,7 +396,7 @@ def error_format(self):
396396
def url_parameters(self):
397397
parameters = {
398398
**self.serialize_url_param(
399-
"changeStateName", self.ctx.args.change_state_name,
399+
"changeRecordName", self.ctx.args.change_record_name,
400400
required=True,
401401
),
402402
**self.serialize_url_param(

src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/_delete.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ class Delete(AAZCommand):
2222
_aaz_info = {
2323
"version": "2026-01-01-preview",
2424
"resources": [
25-
["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/changestates/{}/stageprogressions/{}", "2026-01-01-preview"],
26-
["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.changesafety/changestates/{}/stageprogressions/{}", "2026-01-01-preview"],
25+
["mgmt-plane", "/subscriptions/{}/providers/microsoft.changesafety/changerecords/{}/stageprogressions/{}", "2026-01-01-preview"],
26+
["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.changesafety/changerecords/{}/stageprogressions/{}", "2026-01-01-preview"],
2727
]
2828
}
2929

@@ -43,9 +43,9 @@ def _build_arguments_schema(cls, *args, **kwargs):
4343
# define Arg Group ""
4444

4545
_args_schema = cls._args_schema
46-
_args_schema.change_state_name = AAZStrArg(
47-
options=["--change-state-name"],
48-
help="The name of the ChangeState resource.",
46+
_args_schema.change_record_name = AAZStrArg(
47+
options=["--change-record-name"],
48+
help="The name of the ChangeRecord resource.",
4949
required=True,
5050
id_part="name",
5151
fmt=AAZStrArgFormat(
@@ -57,7 +57,7 @@ def _build_arguments_schema(cls, *args, **kwargs):
5757
_args_schema.resource_group = AAZResourceGroupNameArg()
5858
_args_schema.stage_progression_name = AAZStrArg(
5959
options=["-n", "--name", "--stage-progression-name"],
60-
help="name of the stageProgression",
60+
help="Name of the stageProgression",
6161
required=True,
6262
id_part="child_name_1",
6363
fmt=AAZStrArgFormat(
@@ -70,12 +70,12 @@ def _build_arguments_schema(cls, *args, **kwargs):
7070

7171
def _execute_operations(self):
7272
self.pre_operations()
73-
condition_0 = has_value(self.ctx.args.change_state_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
74-
condition_1 = has_value(self.ctx.args.change_state_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)
73+
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
74+
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)
7575
if condition_0:
76-
self.StageProgressionsDeleteAtSubscriptionLevel(ctx=self.ctx)()
76+
self.ChangeRecordStageProgressionsDeleteAtSubscriptionLevel(ctx=self.ctx)()
7777
if condition_1:
78-
self.StageProgressionsDelete(ctx=self.ctx)()
78+
self.ChangeRecordStageProgressionsDelete(ctx=self.ctx)()
7979
self.post_operations()
8080

8181
@register_callback
@@ -86,7 +86,7 @@ def pre_operations(self):
8686
def post_operations(self):
8787
pass
8888

89-
class StageProgressionsDeleteAtSubscriptionLevel(AAZHttpOperation):
89+
class ChangeRecordStageProgressionsDeleteAtSubscriptionLevel(AAZHttpOperation):
9090
CLIENT_TYPE = "MgmtClient"
9191

9292
def __call__(self, *args, **kwargs):
@@ -102,7 +102,7 @@ def __call__(self, *args, **kwargs):
102102
@property
103103
def url(self):
104104
return self.client.format_url(
105-
"/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/changeStates/{changeStateName}/stageProgressions/{stageProgressionName}",
105+
"/subscriptions/{subscriptionId}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}/stageProgressions/{stageProgressionName}",
106106
**self.url_parameters
107107
)
108108

@@ -118,7 +118,7 @@ def error_format(self):
118118
def url_parameters(self):
119119
parameters = {
120120
**self.serialize_url_param(
121-
"changeStateName", self.ctx.args.change_state_name,
121+
"changeRecordName", self.ctx.args.change_record_name,
122122
required=True,
123123
),
124124
**self.serialize_url_param(
@@ -148,7 +148,7 @@ def on_200(self, session):
148148
def on_204(self, session):
149149
pass
150150

151-
class StageProgressionsDelete(AAZHttpOperation):
151+
class ChangeRecordStageProgressionsDelete(AAZHttpOperation):
152152
CLIENT_TYPE = "MgmtClient"
153153

154154
def __call__(self, *args, **kwargs):
@@ -164,7 +164,7 @@ def __call__(self, *args, **kwargs):
164164
@property
165165
def url(self):
166166
return self.client.format_url(
167-
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ChangeSafety/changeStates/{changeStateName}/stageProgressions/{stageProgressionName}",
167+
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ChangeSafety/changeRecords/{changeRecordName}/stageProgressions/{stageProgressionName}",
168168
**self.url_parameters
169169
)
170170

@@ -180,7 +180,7 @@ def error_format(self):
180180
def url_parameters(self):
181181
parameters = {
182182
**self.serialize_url_param(
183-
"changeStateName", self.ctx.args.change_state_name,
183+
"changeRecordName", self.ctx.args.change_record_name,
184184
required=True,
185185
),
186186
**self.serialize_url_param(

src/azure-changesafety/azext_changesafety/aaz/latest/changesafety/stageprogression/_list.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"changesafety stageprogression list",
1616
)
1717
class List(AAZCommand):
18-
"""List ChangeRecordStageProgression resources by ChangeRecord
18+
"""List StageProgression resources by ChangeRecord
1919
"""
2020

2121
_aaz_info = {

0 commit comments

Comments
 (0)