diff --git a/src/Common/CustomAttributes/CmdletDeprecationAttribute.cs b/src/Common/CustomAttributes/CmdletDeprecationAttribute.cs index 87b4f9cac0..922d9921ca 100644 --- a/src/Common/CustomAttributes/CmdletDeprecationAttribute.cs +++ b/src/Common/CustomAttributes/CmdletDeprecationAttribute.cs @@ -21,6 +21,7 @@ namespace Microsoft.WindowsAzure.Commands.Common.CustomAttributes { + [Obsolete("CmdletDeprecationAttribute is deprecated. Please use CmdletDeprecationWithVersionAttribute instead to ensure that version information is included in the deprecation message.", false)] [AttributeUsage( AttributeTargets.Class, AllowMultiple = true)] diff --git a/src/Common/CustomAttributes/CmdletDeprecationWithVersionAttribute.cs b/src/Common/CustomAttributes/CmdletDeprecationWithVersionAttribute.cs new file mode 100644 index 0000000000..53c35b3046 --- /dev/null +++ b/src/Common/CustomAttributes/CmdletDeprecationWithVersionAttribute.cs @@ -0,0 +1,49 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using Microsoft.WindowsAzure.Commands.Common.Properties; +using System; + +namespace Microsoft.WindowsAzure.Commands.Common.CustomAttributes +{ + [AttributeUsage( + AttributeTargets.Class, + AllowMultiple = true)] + public class CmdletDeprecationWithVersionAttribute : GenericBreakingChangeAttribute + { + public string ReplacementCmdletName { get; set; } + + public CmdletDeprecationWithVersionAttribute(string deprecateByVersion) : + base(string.Empty, deprecateByVersion) + { + } + + public CmdletDeprecationWithVersionAttribute(string deprecateByVersion, string changeInEffectByDate) : + base(string.Empty, deprecateByVersion, changeInEffectByDate) + { + } + + protected override string GetAttributeSpecificMessage() + { + if (string.IsNullOrWhiteSpace(ReplacementCmdletName)) + { + return Resources.BreakingChangesAttributesCmdLetDeprecationMessageNoReplacement; + } + else + { + return string.Format(Resources.BreakingChangesAttributesCmdLetDeprecationMessageWithReplacement, ReplacementCmdletName); + } + } + } +} diff --git a/src/Common/CustomAttributes/CmdletOutputBreakingChangeAttribute.cs b/src/Common/CustomAttributes/CmdletOutputBreakingChangeAttribute.cs index 84798ef267..f31c71bd05 100644 --- a/src/Common/CustomAttributes/CmdletOutputBreakingChangeAttribute.cs +++ b/src/Common/CustomAttributes/CmdletOutputBreakingChangeAttribute.cs @@ -21,6 +21,7 @@ namespace Microsoft.WindowsAzure.Commands.Common.CustomAttributes { + [Obsolete("CmdletOutputBreakingChangeAttribute is deprecated. Please use CmdletOutputBreakingChangeWithVersionAttribute instead to ensure that version information is included in the breaking change message.", false)] [AttributeUsage( AttributeTargets.Class, AllowMultiple = true)] diff --git a/src/Common/CustomAttributes/CmdletOutputBreakingChangeWithVersionAttribute.cs b/src/Common/CustomAttributes/CmdletOutputBreakingChangeWithVersionAttribute.cs new file mode 100644 index 0000000000..694048c882 --- /dev/null +++ b/src/Common/CustomAttributes/CmdletOutputBreakingChangeWithVersionAttribute.cs @@ -0,0 +1,90 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using Microsoft.WindowsAzure.Commands.Common.Properties; +using System; +using System.Text; + +namespace Microsoft.WindowsAzure.Commands.Common.CustomAttributes +{ + [AttributeUsage( + AttributeTargets.Class, + AllowMultiple = true)] + public class CmdletOutputBreakingChangeWithVersionAttribute : GenericBreakingChangeWithVersionAttribute + { + public Type DeprecatedCmdLetOutputType { get; } + + //This is still a String instead of a Type as this + //might be undefined at the time of adding the attribute + public string ReplacementCmdletOutputTypeName { get; set; } + + public string[] DeprecatedOutputProperties { get; set; } + + public string[] NewOutputProperties { get; set; } + + + public CmdletOutputBreakingChangeWithVersionAttribute(Type deprecatedCmdletOutputTypeName, string deprecateByVersion) : + base(string.Empty, deprecateByVersion) + { + this.DeprecatedCmdLetOutputType = deprecatedCmdletOutputTypeName; + } + + public CmdletOutputBreakingChangeWithVersionAttribute(Type deprecatedCmdletOutputTypeName, string deprecateByVersion, string changeInEfectByDate) : + base(string.Empty, deprecateByVersion, changeInEfectByDate) + { + this.DeprecatedCmdLetOutputType = deprecatedCmdletOutputTypeName; + } + + protected override string GetAttributeSpecificMessage() + { + StringBuilder message = new StringBuilder(); + + //check for the deprecation scenario + if (string.IsNullOrWhiteSpace(ReplacementCmdletOutputTypeName) && NewOutputProperties == null && DeprecatedOutputProperties == null && string.IsNullOrWhiteSpace(ChangeDescription)) + { + message.Append(string.Format(Resources.BreakingChangesAttributesCmdLetOutputTypeDeprecated, DeprecatedCmdLetOutputType.FullName)); + } + else + { + if (!string.IsNullOrWhiteSpace(ReplacementCmdletOutputTypeName)) + { + message.Append(string.Format(Resources.BreakingChangesAttributesCmdLetOutputChange1, DeprecatedCmdLetOutputType.FullName, ReplacementCmdletOutputTypeName)); + } + else + { + message.Append(string.Format(Resources.BreakingChangesAttributesCmdLetOutputChange2, DeprecatedCmdLetOutputType.FullName)); + } + + if (DeprecatedOutputProperties != null && DeprecatedOutputProperties.Length > 0) + { + message.Append(Resources.BreakingChangesAttributesCmdLetOutputPropertiesRemoved); + foreach (string property in DeprecatedOutputProperties) + { + message.Append(" '" + property + "'"); + } + } + + if (NewOutputProperties != null && NewOutputProperties.Length > 0) + { + message.Append(Resources.BreakingChangesAttributesCmdLetOutputPropertiesAdded); + foreach (string property in NewOutputProperties) + { + message.Append(" '" + property + "'"); + } + } + } + return message.ToString(); + } + } +} diff --git a/src/Common/CustomAttributes/CmdletParameterBreakingChangeAttribute.cs b/src/Common/CustomAttributes/CmdletParameterBreakingChangeAttribute.cs index 7db08eff30..f9bb7101e6 100644 --- a/src/Common/CustomAttributes/CmdletParameterBreakingChangeAttribute.cs +++ b/src/Common/CustomAttributes/CmdletParameterBreakingChangeAttribute.cs @@ -22,6 +22,7 @@ namespace Microsoft.WindowsAzure.Commands.Common.CustomAttributes { + [Obsolete("CmdletParameterBreakingChangeAttribute is deprecated. Please use CmdletParameterBreakingChangeWithVersionAttribute instead to ensure that version information is included in the breaking change message.", false)] [AttributeUsage( AttributeTargets.Property | AttributeTargets.Field, @@ -80,7 +81,7 @@ protected override string GetAttributeSpecificMessage() } } - //See if the type of the param is changing + //See if the type of the param is changing if (OldParamaterType != null && !string.IsNullOrWhiteSpace(NewParameterTypeName)) { message.Append(string.Format(Resources.BreakingChangeAttributeParameterTypeChange, OldParamaterType.FullName, NewParameterTypeName)); @@ -90,7 +91,7 @@ protected override string GetAttributeSpecificMessage() /// /// See if the bound parameters contain the current parameter, if they do - /// then the attribbute is applicable + /// then the attribute is applicable /// If the invocationInfo is null we return true /// /// diff --git a/src/Common/CustomAttributes/CmdletParameterBreakingChangeWithVersionAttribute.cs b/src/Common/CustomAttributes/CmdletParameterBreakingChangeWithVersionAttribute.cs new file mode 100644 index 0000000000..03776bed97 --- /dev/null +++ b/src/Common/CustomAttributes/CmdletParameterBreakingChangeWithVersionAttribute.cs @@ -0,0 +1,98 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using Microsoft.WindowsAzure.Commands.Common.Properties; +using System; +using System.Linq; +using System.Text; +using System.Management.Automation; +namespace Microsoft.WindowsAzure.Commands.Common.CustomAttributes +{ + [AttributeUsage( + AttributeTargets.Property | + AttributeTargets.Field, + AllowMultiple = true)] + public class CmdletParameterBreakingChangeWithVersionAttribute : GenericBreakingChangeWithVersionAttribute + { + public string NameOfParameterChanging { get; } + + public string ReplaceMentCmdletParameterName { get; set; } = null; + + public bool IsBecomingMandatory { get; set; } = false; + + public Type OldParamaterType { get; set; } + + public String NewParameterTypeName { get; set; } + + + public CmdletParameterBreakingChangeWithVersionAttribute(string nameOfParameterChanging, string deprecateByVersion) : + base(string.Empty, deprecateByVersion) + { + this.NameOfParameterChanging = nameOfParameterChanging; + } + + public CmdletParameterBreakingChangeWithVersionAttribute(string nameOfParameterChanging, string deprecateByVersion, string changeInEffectByDate) : + base(string.Empty, deprecateByVersion, changeInEffectByDate) + { + this.NameOfParameterChanging = nameOfParameterChanging; + } + + protected override string GetAttributeSpecificMessage() + { + StringBuilder message = new StringBuilder(); + if (!string.IsNullOrWhiteSpace(ReplaceMentCmdletParameterName)) + { + if (IsBecomingMandatory) + { + message.Append(string.Format(Resources.BreakingChangeAttributeParameterReplacedMandatory, NameOfParameterChanging, ReplaceMentCmdletParameterName)); + } + else + { + message.Append(string.Format(Resources.BreakingChangeAttributeParameterReplaced, NameOfParameterChanging, ReplaceMentCmdletParameterName)); + } + } + else + { + if (IsBecomingMandatory) + { + message.Append(string.Format(Resources.BreakingChangeAttributeParameterMandatoryNow, NameOfParameterChanging)); + } + else + { + message.Append(string.Format(Resources.BreakingChangeAttributeParameterChanging, NameOfParameterChanging)); + } + } + + //See if the type of the param is changing + if (OldParamaterType != null && !string.IsNullOrWhiteSpace(NewParameterTypeName)) + { + message.Append(string.Format(Resources.BreakingChangeAttributeParameterTypeChange, OldParamaterType.FullName, NewParameterTypeName)); + } + return message.ToString(); + } + + /// + /// See if the bound parameters contain the current parameter, if they do + /// then the attribute is applicable + /// If the invocationInfo is null we return true + /// + /// + /// bool + public override bool IsApplicableToInvocation(InvocationInfo invocationInfo) + { + bool? applicable = invocationInfo == null ? true : invocationInfo.BoundParameters?.Keys?.Contains(this.NameOfParameterChanging); + return applicable.HasValue ? applicable.Value : false; + } + } +} diff --git a/src/Common/CustomAttributes/GenericBreakingChangeAttribute.cs b/src/Common/CustomAttributes/GenericBreakingChangeAttribute.cs index 396a49ec9c..8e1602358d 100644 --- a/src/Common/CustomAttributes/GenericBreakingChangeAttribute.cs +++ b/src/Common/CustomAttributes/GenericBreakingChangeAttribute.cs @@ -23,6 +23,7 @@ namespace Microsoft.WindowsAzure.Commands.Common.CustomAttributes { + [Obsolete("GenericBreakingChangeAttribute is deprecated. Please use GenericBreakingChangeWithVersionAttribute instead to ensure that version information is included in the breaking change message.", false)] [AttributeUsage( AttributeTargets.Class | AttributeTargets.Field | @@ -35,7 +36,7 @@ namespace Microsoft.WindowsAzure.Commands.Common.CustomAttributes public class GenericBreakingChangeAttribute : System.Attribute { private string _message; - //A dexcription of what the change is about, non mandatory + //A description of what the change is about, non mandatory public string ChangeDescription { get; set; } = null; //The version the change is effective from, non mandatory @@ -83,9 +84,9 @@ public DateTime getInEffectByDate() /** * This function returns the breaking change text for the attribute - * If the withCmdletName is true we return the message with the cmdlet name in it otherwse not + * If the withCmdletName is true we return the message with the cmdlet name in it otherwise not * - * We get the cmdlet name from the passed in Type (it is expected to have the CMdlet attribute decorated on the class) + * We get the cmdlet name from the passed in Type (it is expected to have the Cmdlet attribute decorated on the class) */ public string GetBreakingChangeTextFromAttribute(Type type, bool withCmdletName) { @@ -128,7 +129,7 @@ public string GetBreakingChangeTextFromAttribute(Type type, bool withCmdletName) * If the "withCmdletName" is specified, the message is printed out with the cmdlet name in it * otherwise not * - * We get the cmdlet name from the passed in Type (it is expected to have the CMdlet attribute decorated on the class) + * We get the cmdlet name from the passed in Type (it is expected to have the Cmdlet attribute decorated on the class) * */ public void PrintCustomAttributeInfo(Type type, bool withCmdletName, Action writeOutput) { diff --git a/src/Common/CustomAttributes/GenericBreakingChangeWithVersionAttribute.cs b/src/Common/CustomAttributes/GenericBreakingChangeWithVersionAttribute.cs new file mode 100644 index 0000000000..545b06a480 --- /dev/null +++ b/src/Common/CustomAttributes/GenericBreakingChangeWithVersionAttribute.cs @@ -0,0 +1,176 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using Microsoft.WindowsAzure.Commands.Common.Properties; +using System; +using System.Globalization; +using System.Management.Automation; +using System.Text; + +namespace Microsoft.WindowsAzure.Commands.Common.CustomAttributes +{ + [AttributeUsage( + AttributeTargets.Class | + AttributeTargets.Field | + AttributeTargets.Property, + AllowMultiple = true)] + + /* + * This class acts as the base + */ + public class GenericBreakingChangeWithVersionAttribute : System.Attribute + { + private string _message; + //A description of what the change is about, non mandatory + public string ChangeDescription { get; set; } = null; + + //The version the change is effective from, non mandatory + public string DeprecateByVersion { get; } + public bool DeprecateByVersionSet { get; } = false; + + //The date on which the change comes in effect + public DateTime ChangeInEffectByDate { get; } + public bool ChangeInEffectByDateSet { get; } = false; + + //Old way of calling the cmdlet + public string OldWay { get; set; } + //New way fo calling the cmdlet + public string NewWay { get; set; } + + public GenericBreakingChangeWithVersionAttribute(string message, string deprecateByVersion) + { + _message = message; + this.DeprecateByVersion = deprecateByVersion; + this.DeprecateByVersionSet = true; + } + + public GenericBreakingChangeWithVersionAttribute(string message, string deprecateByVersion, string changeInEffectByDate) + { + _message = message; + this.DeprecateByVersion = deprecateByVersion; + this.DeprecateByVersionSet = true; + + if (DateTime.TryParse(changeInEffectByDate, new CultureInfo("en-US"), DateTimeStyles.None, out DateTime result)) + { + this.ChangeInEffectByDate = result; + this.ChangeInEffectByDateSet = true; + } + } + + public DateTime getInEffectByDate() + { + return this.ChangeInEffectByDate.Date; + } + + /** + * This function returns the breaking change text for the attribute + * If the withCmdletName is true we return the message with the cmdlet name in it otherwise not + * + * We get the cmdlet name from the passed in Type (it is expected to have the Cmdlet attribute decorated on the class) + */ + public string GetBreakingChangeTextFromAttribute(Type type, bool withCmdletName) + { + StringBuilder breakingChangeMessage = new StringBuilder(); + + if (!withCmdletName) + { + breakingChangeMessage.Append(string.Format(Resources.BreakingChangesAttributesDeclarationMessage, GetAttributeSpecificMessage())); + } + else + { + + breakingChangeMessage.Append(string.Format(Resources.BreakingChangesAttributesDeclarationMessageWithCmdletName, Utilities.GetNameFromCmdletType(type), GetAttributeSpecificMessage())); + } + + if (!string.IsNullOrWhiteSpace(ChangeDescription)) + { + breakingChangeMessage.Append(string.Format(Resources.BreakingChangesAttributesChangeDescriptionMessage, this.ChangeDescription)); + } + + if (ChangeInEffectByDateSet) + { + breakingChangeMessage.Append(string.Format(Resources.BreakingChangesAttributesInEffectByDateMessage, this.ChangeInEffectByDate)); + } + + if (DeprecateByVersionSet) + { + breakingChangeMessage.Append(string.Format(Resources.BreakingChangesAttributesInEffectByVersion, this.DeprecateByVersion)); + } + + if (!string.IsNullOrWhiteSpace(OldWay) && !string.IsNullOrWhiteSpace(NewWay)) + { + breakingChangeMessage.Append(string.Format(Resources.BreakingChangesAttributesUsageChangeMessage, OldWay, NewWay)); + } + + return breakingChangeMessage.ToString(); + } + + /** + * This function prints out the breaking change message for the attribute on the cmdline + * If the "withCmdletName" is specified, the message is printed out with the cmdlet name in it + * otherwise not + * + * We get the cmdlet name from the passed in Type (it is expected to have the Cmdlet attribute decorated on the class) + * */ + public void PrintCustomAttributeInfo(Type type, bool withCmdletName, Action writeOutput) + { + if (!withCmdletName) + { + if (!GetAttributeSpecificMessage().StartsWith(Environment.NewLine)) + { + writeOutput(Environment.NewLine); + } + writeOutput(string.Format(Resources.BreakingChangesAttributesDeclarationMessage, GetAttributeSpecificMessage())); + } + else + { + writeOutput(string.Format(Resources.BreakingChangesAttributesDeclarationMessageWithCmdletName, Utilities.GetNameFromCmdletType(type), GetAttributeSpecificMessage())); + } + + if (!string.IsNullOrWhiteSpace(ChangeDescription)) + { + writeOutput(string.Format(Resources.BreakingChangesAttributesChangeDescriptionMessage, this.ChangeDescription)); + } + + if (ChangeInEffectByDateSet) + { + writeOutput(string.Format(Resources.BreakingChangesAttributesInEffectByDateMessage, this.ChangeInEffectByDate)); + } + + if (DeprecateByVersionSet) + { + writeOutput(string.Format(Resources.BreakingChangesAttributesInEffectByVersion, this.DeprecateByVersion)); + } + + if (OldWay != null && NewWay != null) + { + writeOutput(string.Format(Resources.BreakingChangesAttributesUsageChangeMessageConsole, OldWay, NewWay)); + } + } + + public virtual bool IsApplicableToInvocation(InvocationInfo invocation) + { + return true; + } + + protected virtual string GetAttributeSpecificMessage() + { + return _message; + } + protected virtual string GetAttributeSpecificVersion() + { + return DeprecateByVersion; + } + } +}