Skip to content

Latest commit

 

History

History
488 lines (429 loc) · 15.5 KB

breaking-changes-attribute-help.md

File metadata and controls

488 lines (429 loc) · 15.5 KB

Breaking Changes Attribute Help

Below is description of the various types of Breaking Change Attributes (custom attributes) that can be used to decorate the cmdlet or its paramters to call out various types of breaking changes.

The different types of attributes

Common aspects and properties

GenericBreakingChangeAttribute

The base attibute which provides the core functionality is called "GenericBreakingChange" All the remaining attrbutes derive from it and provide functionality that makes sense for the scenarios they handle.

The generic attribute is the most free form of them all and can be used to call out breaking changes that do not fall into the more specialized categories.

Common behavioral aspects

All of the attributes have the following common traits:

  • The attribute (when added to the cmdlet/parameter of the cmdlet) is used for the following purposes
    • At runtime, if the cmdlet is used, we will print out a message for each breaking change attribute present in the cmdlet and its properties.
    • We use these attributes to generate the breaking change document for the cmdlet.

Common Properties

Constructor arguments

  • Each attribute has two additional constructors thet take the following params in addition to the ones the attribute mentions:
    • The "deprecatedByVersion" is the version number the breaking change is going to be done in.
    • The "changeInEfectByDate" is the date the breaking change is goind to go in effet on. The string formati is "mm/dd/yyyy", as an example : "02/25/2018"

Properties by name

  • Each attribute accepts the following properties by name (all of them are optional) :
    • "ChangeDescription" : This is a free form text field that can be used to describe the breaking change.
    • Usage changes (you cant have one or the other, you need to speciffy both for the usage message to be generated) :
      • "OldWay" : The way to call the cmdlet before the breaking change takes effect
      • "NewWay" : If there is a workaround to the breaking change, or if the same functionality can be achieved in another manner

The properties "deprecatedByVersion" and "changeInEfectByDate" are infotmation only (for the end user) as of now.

  • If the user desires to not see the warning messages generated by the attirbutes at runtime, they can set the env variable "SuppressAzurePowerShellBreakingChangeWarnings" to "true".

NOTE :

  • The only time you will see the output (at runtime) of an attribute applied to a parameter (property or field) is if the parameter is actually invoked on the cmdline. The breaking change attributes to all parameters that are not invoked are ignored.

Examples (with GenericBreakingChangeAttribute)

With a simple message

    [GenericBreakingChange("Message 1")]
    [Cmdlet(VerbsCommon.Get, "SomeObject0"), OutputType(typeof(Foo))]
    class GetSomeObject0 : AzureRMCmdlet
    {

    }
Effects at runtime:
Get-SomeObject0 <parms here>
...
Breaking changes in the cmdlet : Get-SomeObject0
 - Message 1

With "GenericBreakingChange"

    [GenericBreakingChange("Message 1", "5.0.0.0")]
    [Cmdlet(VerbsCommon.Get, "SomeObjectA"), OutputType(typeof(Foo))]
    class GetSomeObjectA : AzureRMCmdlet
    {

    }
Effects at runtime:
Get-SomeObjectA <parms here>
...
Breaking changes in the cmdlet : Get-SomeObjectA
 - Message 1
    The change is expected to take effect from the version : 5.0.0.0

With "deprecatedByVersion" and "changeInEfectByDate"

    [GenericBreakingChange("Message2", "5.0.0.0", "02/13/2018")]
    [Cmdlet(VerbsCommon.Get, "SomeObjectB"), OutputType(typeof(Foo))]
    class GetSomeObjectB : AzureRMCmdlet

    }
Effects at runtime:
Get-SomeObjectB <parms here>
...
Breaking changes in the cmdlet : Get-SomeObjectB
 - Message 2
    NOTE : This change will take effect on '02/13/2018'
    The change is expected to take effect from the version : 5.0.0.0

With OldWay/NewWay

    [GenericBreakingChange("Added new required param to Get-SomeObjectC", OldWay = "Get-SomeObjectC -Param1=\"blah\"", NewWay = "Get-SomeObjectC -Param1=\"blah\" -Param2=\"Yo Yo\"")]
    [Cmdlet(VerbsCommon.Get, "SomeObjectC"), OutputType(typeof(Foo))]
    class GetSomeObjectC : AzureRMCmdlet

    }
Effects at runtime
Get-SomeObjectC <parms here>
...
Breaking changes in the cmdlet : Get-SomeObjectC
 - Added new required param to Get-SomeObjectC
Cmdlet invocation changes :
    Old Way : Get-SomeObjectC -Param1="blah"
    New Way : Get-SomeObjectC -Param1="blah" -Param2="Yo Yo"

With ChangeDescription property and multiple attributes in the cmdlet

    [GenericBreakingChange("Message5")]
    [Cmdlet(VerbsCommon.Get, "SomeObjectD"), OutputType(typeof(Foo))]
    class GetSomeObjectD : AzureRMCmdlet
        //This is just as an example, to call out a param change we would not use the generic attribute. Use "CmdletParameterBreakingChangeMarker" instead
        [GenericBreakingChange("Param1 changes coming", ChangeDescription = "The param is changing from a List<String> to HashSet<String>")]
        [Parameter(Mandatory = false)]
        public List<String> Param1;
        [Parameter(Mandatory = false)]
        public List<String> Param2;
    }
Effects at runtime when the param with an attribute is used
Get-SomeObjectC -Param1=...
...
Breaking changes in the cmdlet : Get-SomeObjectD
 - Message5
 - Param1 changes coming
    Change description : The param is changing from a List<String> to HashSet<String>"
Effects at runtime when the param with an attribute is not used
Get-SomeObjectC -Param2=...
...
Breaking changes in the cmdlet : Get-SomeObjectD
- Message5

CmdletDeprecationAttribute

This attribute marks a cmdlet for deprecation.

Usage

Constructor Arguments

None, other than the two inherited from GenericBreakingChangeAttribute

When there is a replacement cmdlet

[CmdletDeprecation(ReplacementCmdletName = "Get-SomeObjectC")]
[Cmdlet(VerbsCommon.Get, "SomeObjectA"), OutputType(typeof(Foo))]
public class GetSomeObjectA : AzureRMCmdlet
{
    protected override void BeginProcessing()
    {
        // cmdlet logic
    }
}
Effect at runtime
Get-SomeObjectA <parms here>
...
Breaking changes in the cmdlet : Get-SomeObjectA
The cmdlet 'Get-SomeObjectC' is replacing this cmdlet

When there is no replacement cmdlet

[CmdletDeprecation()]
[Cmdlet(VerbsCommon.Get, "SomeObjectB"), OutputType(typeof(Foo))]
public class GetSomeObjectB : AzureRMCmdlet
{
    protected override void BeginProcessing()
    {
        // cmdlet logic
    }
}
Effect at runtime
Get-SomeObjectB <params here>
...
Breaking changes in the cmdlet : Get-SomeObjectB
The cmdlet is being deprecated. There will be no replacement for it.

CmdletOutputBreakingChangeAttribute

This attribute is used to call out the breakigng changes with the output of a cmdlet. A few examples are :

  • The type of the output is changing
  • The Output type is being deprecated
  • Some internal properties in the putput type are being deprecated
  • New properties are being introduced to the output type

Note :

  • It is possible to mix the above, as in you can have a case where a type is being replaced and we want to call out the change to internal properties, as in list te old ones deprecating with the old type and the new ones being introduced in the new type

Usage

Constructor Arguments

  • deprecatedCmdletOutputTypeName : String, represents the type of the existing output type,
  • The two inherited from GenericBreakingChangeAttribute

The output return type is being dropped

[CmdletOutputBreakingChange(typeof(Foo))]
[Cmdlet(VerbsCommon.Get, "SomeObjectA"), OutputType(typeof(Foo))]
public class GetSomeObjectA : AzureRMCmdlet
{
    protected override void BeginProcessing()
    {
        // cmdlet logic
    }
}
Effect at runtime
Get-SomeObjectA <parms here>
...
Breaking changes in the cmdlet : Get-SomeObjectA
 - The output type 'Foo' is being deprecated without a replacement.

The output return type is changing

[CmdletOutputBreakingChange(typeof(List<Foo>), ReplacementCmdletOutputTypeName = "Dictionary<String, Foo>")]
[Cmdlet(VerbsCommon.Get, "SomeObjectA"), OutputType(typeof(List<Foo>))]
public class GetSomeObjectA : AzureRMCmdlet
{
    protected override void BeginProcessing()
    {
        // cmdlet logic
    }
}
Effect at runtime
Get-SomeObjectA <parms here>
...
Breaking changes in the cmdlet : Get-SomeObjectA
 - The output type is changing from the existing type :'List<Foo>' to the new type :'Dictionary<String, Foo>'

A few properties in the output type are being deprecated

[CmdletOutputBreakingChange(typeof(Foo), DeprecatedOutputProperties = new String[] {"Prop1", "Prop2"})]
[Cmdlet(VerbsCommon.Get, "SomeObjectB"), OutputType(typeof(Foo))]
public class GetSomeObjectB : AzureRMCmdlet
{
    protected override void BeginProcessing()
    {
        // cmdlet logic
    }
}
Effect at runtime
Get-SomeObjectB <parms here>
...
Breaking changes in the cmdlet : Get-SomeObjectB
 - The output type 'Foo' is changing
 - The following properties in the output type are being deprecated :
    'Prop1' 'Prop2'

A few new properties are bing added to the output type

[CmdletOutputBreakingChange(typeof(Foo), NewOutputProperties = new String[] {"Prop1", "Prop2"})]
[Cmdlet(VerbsCommon.Get, "SomeObjectC"), OutputType(typeof(Foo))]
public class GetSomeObjectC : AzureRMCmdlet
{
    protected override void BeginProcessing()
    {
        // cmdlet logic
    }
}
Effect at runtime
Get-SomeObjectC <parms here>
...
Breaking changes in the cmdlet : Get-SomeObjectC
 - The output type 'Foo' is changing
 - The following properties are being added to the output type :
    'Prop1' 'Prop2'

A mixed example

[CmdletOutputBreakingChange(typeof(Foo), ReplacementCmdletOutputTypeName = "Foo1",
DeprecatedOutputProperties = new String[] {"Prop1", "Prop2"},
NewOutputProperties = new String[] {"Prop3", "Prop4"})]
[Cmdlet(VerbsCommon.Get, "SomeObjectD"), OutputType(typeof(Foo))]
public class GetSomeObjectD : AzureRMCmdlet
{
    protected override void BeginProcessing()
    {
        // cmdlet logic
    }
}
Effect at runtime
Get-SomeObjectD <parms here>
...
Breaking changes in the cmdlet : Get-SomeObjectD
 - The output type is changing from the existing type :'Foo' to the new type :'Foo1'
 - The following properties in the output type are being deprecated :
    'Prop1' 'Prop2'
 - The following properties are being added to the output type :
    'Prop3' 'Prop4'

CmdletParameterBreakingChangeAttribute

This attribute is used to call out the breakigng changes relating to a parameter of a cmdlet. A few examples are :

  • A parameter is being deprecated
  • A parameter is being replaced
  • A parameter is becoming mandatory
  • A non mandatory parameter is being replaced by a mandatory parameter

NOTE :

  • The only time you will see the output (at runtime) of an attribute applied to a parameter (property or field) is if the parameter is actually invoked on the cmdline. The breaking change attributes to all parameters that are not invoked are ignored.

Usage

Constructor Arguments

  • nameOfParameterChanging : String, represents the name of the existing parameter,
  • The two inherited from GenericBreakingChangeAttribute

Generic change in a parameter

[Cmdlet(VerbsCommon.Get, "SomeObjectA0"), OutputType(typeof(Foo))]
public class GetSomeObjectA0 : AzureRMCmdlet
{
        public const String ChangeDesc = "Change description Foo bar";
        [CmdletParameterBreakingChange("Param1", ChangeDescription = ChangeDesc)]
        [Parameter(Mandatory = false)]
        public String Param1;
    protected override void BeginProcessing()
    {
        // cmdlet logic
    }
}
Effect at runtime
Get-SomeObjectA0 -Param1=...
...
Breaking changes in the cmdlet : Get-SomeObjectA0
 - The parameter 'Param1' is changing
    Change description : Change description Foo bar

A Parameter is being deprecated

[Cmdlet(VerbsCommon.Get, "SomeObjectA"), OutputType(typeof(Foo))]
public class GetSomeObjectA : AzureRMCmdlet
{
        public const String ChangeDesc = "Parameter is being deprecated without being replaced";
        [CmdletParameterBreakingChange("Param1", ChangeDescription = ChangeDesc)]
        [Parameter(Mandatory = false)]
        public String Param1;
    protected override void BeginProcessing()
    {
        // cmdlet logic
    }
}
Effect at runtime
Get-SomeObjectA -Param1=...
...
Breaking changes in the cmdlet : Get-SomeObjectA
 - The parameter 'Param1' is changing
    Change description : Parameter is being deprecated without being replaced

A Parameter is changing its type

[Cmdlet(VerbsCommon.Get, "SomeObjectA1"), OutputType(typeof(Foo))]
public class GetSomeObjectA1 : AzureRMCmdlet
{
        [CmdletParameterBreakingChange("Param1", OldParameterType = typeof(String), NewParameterTypeName="FooBar")]
        [Parameter(Mandatory = false)]
        public String Param1;
    protected override void BeginProcessing()
    {
        // cmdlet logic
    }
}
Effect at runtime
Get-SomeObjectA1 -Param1=...
...
Breaking changes in the cmdlet : Get-SomeObjectA1
 - The parameter 'Param1' is changing
    The type of the parameter is changing from 'String' to 'FooBar'.

A Parameter is being replaced

[Cmdlet(VerbsCommon.Get, "SomeObjectB"), OutputType(typeof(Foo))]
public class GetSomeObjectB : AzureRMCmdlet
{
        [CmdletParameterBreakingChange("Param1", ReplaceMentCmdletParameterName = "ParamX")]
        [Parameter(Mandatory = false)]
        public String Param1;
    protected override void BeginProcessing()
    {
        // cmdlet logic
    }
}
Effect at runtime
Get-SomeObjectB -Param1=...
...
Breaking changes in the cmdlet : Get-SomeObjectB
 - The parameter 'Param1' is  being replaced by parameter "ParamX"

A non mandatory parameter is being replaced by a mandatory param

[Cmdlet(VerbsCommon.Get, "SomeObjectC"), OutputType(typeof(Foo))]
public class GetSomeObjectC : AzureRMCmdlet
{
        [CmdletParameterBreakingChange("Param1", ReplaceMentCmdletParameterName = "ParamX",
        IsBecomingMandatory=true)]
        [Parameter(Mandatory = false)]
        public String Param1;
    protected override void BeginProcessing()
    {
        // cmdlet logic
    }
}
Effect at runtime
Get-SomeObjectC -Param1=...
...
Breaking changes in the cmdlet : Get-SomeObjectB
 - The parameter 'Param1' is  being replaced by mandatory parameter "ParamX"

A Parameter is becoming mandatory

[Cmdlet(VerbsCommon.Get, "SomeObjectA"), OutputType(typeof(Foo))]
public class GetSomeObjectA : AzureRMCmdlet
{
        [CmdletParameterBreakingChange("Param1", IsBecomingMandatory=truec)]
        [Parameter(Mandatory = false)]
        public String Param1;
    protected override void BeginProcessing()
    {
        // cmdlet logic
    }
}
Effect at runtime
Get-SomeObjectA -Param1=...
...
Breaking changes in the cmdlet : Get-SomeObjectA
 - The parameter 'Param1' is becoming mandatory