From 4e9e42063642b0294db4738aae8bec12cf92fb95 Mon Sep 17 00:00:00 2001 From: dingmeng-xue Date: Mon, 16 Mar 2020 14:55:47 +0800 Subject: [PATCH 1/4] Add experimentation attribute --- src/Common/AzurePSCmdlet.cs | 1 + .../CmdletExperimentationAttribute.cs | 48 ++++++++++ .../ExperimentationAttributeHelper.cs | 87 +++++++++++++++++++ src/Common/Properties/Resources.Designer.cs | 13 +++ src/Common/Properties/Resources.resx | 3 + 5 files changed, 152 insertions(+) create mode 100644 src/Common/CustomAttributes/CmdletExperimentationAttribute.cs create mode 100644 src/Common/CustomAttributes/ExperimentationAttributeHelper.cs diff --git a/src/Common/AzurePSCmdlet.cs b/src/Common/AzurePSCmdlet.cs index 26743c995b..5431560e2c 100644 --- a/src/Common/AzurePSCmdlet.cs +++ b/src/Common/AzurePSCmdlet.cs @@ -368,6 +368,7 @@ protected override void BeginProcessing() //Now see if the cmdlet has any Breaking change attributes on it and process them if it does //This will print any breaking change attribute messages that are applied to the cmdlet BreakingChangeAttributeHelper.ProcessCustomAttributesAtRuntime(this.GetType(), this.MyInvocation, WriteWarning); + ExperimentationAttributeHelper.ProcessCustomAttributesAtRuntime(this.GetType(), this.MyInvocation, WriteWarning); } /// diff --git a/src/Common/CustomAttributes/CmdletExperimentationAttribute.cs b/src/Common/CustomAttributes/CmdletExperimentationAttribute.cs new file mode 100644 index 0000000000..0cd422851e --- /dev/null +++ b/src/Common/CustomAttributes/CmdletExperimentationAttribute.cs @@ -0,0 +1,48 @@ +// ---------------------------------------------------------------------------------- +// +// 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.Management.Automation; + +namespace Microsoft.WindowsAzure.Commands.Common.CustomAttributes +{ + [AttributeUsage( + AttributeTargets.Class, + AllowMultiple = true)] + public class CmdletExperimentationAttribute : System.Attribute + { + public string _message; + + public CmdletExperimentationAttribute() + { + this._message = Resources.ExperimentalCmdletMessage; + } + + public CmdletExperimentationAttribute(string message) + { + this._message = message; + } + + public void PrintCustomAttributeInfo(Action writeOutput) + { + writeOutput(this._message); + } + + public virtual bool IsApplicableToInvocation(InvocationInfo invocation) + { + return true; + } + } +} diff --git a/src/Common/CustomAttributes/ExperimentationAttributeHelper.cs b/src/Common/CustomAttributes/ExperimentationAttributeHelper.cs new file mode 100644 index 0000000000..dc2e0ab8bf --- /dev/null +++ b/src/Common/CustomAttributes/ExperimentationAttributeHelper.cs @@ -0,0 +1,87 @@ +// ---------------------------------------------------------------------------------- +// +// 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 System; +using System.Collections.Generic; +using System.Linq; +using System.Management.Automation; +using System.Reflection; + +namespace Microsoft.WindowsAzure.Commands.Common.CustomAttributes +{ + public class ExperimentationAttributeHelper + { + public const string SUPPRESS_ERROR_OR_WARNING_MESSAGE_ENV_VARIABLE_NAME = "SuppressAzurePowerShellBreakingChangeWarnings"; + + /// + /// Process CmdletExperimentation attribute in runtime + /// + /// + /// + /// + public static void ProcessCustomAttributesAtRuntime(Type type, InvocationInfo invocationInfo, Action writeOutput) + { + bool supressWarningOrError = false; + + try + { + supressWarningOrError = bool.Parse(System.Environment.GetEnvironmentVariable(SUPPRESS_ERROR_OR_WARNING_MESSAGE_ENV_VARIABLE_NAME)); + } + catch (Exception) + { + //no action + } + + if (supressWarningOrError) + { + //Do not process the attributes at runtime... The env variable to override the warning messages is set + return; + } + + List attributes = new List(GetAllAttributesInType(type, invocationInfo)); + + if (attributes != null && attributes.Count > 0) + { + foreach (CmdletExperimentationAttribute attribute in attributes) + { + attribute.PrintCustomAttributeInfo(writeOutput); + } + } + } + + private static IEnumerable GetAllAttributesInType(Type type, InvocationInfo invocationInfo) + { + List attributeList = new List(); + + attributeList.AddRange(type.GetCustomAttributes(typeof(CmdletExperimentationAttribute), false).Cast()); + + foreach (MethodInfo m in type.GetRuntimeMethods()) + { + attributeList.AddRange((m.GetCustomAttributes(typeof(CmdletExperimentationAttribute), false).Cast())); + } + + foreach (FieldInfo f in type.GetRuntimeFields()) + { + attributeList.AddRange(f.GetCustomAttributes(typeof(CmdletExperimentationAttribute), false).Cast()); + } + + foreach (PropertyInfo p in type.GetRuntimeProperties()) + { + attributeList.AddRange(p.GetCustomAttributes(typeof(CmdletExperimentationAttribute), false).Cast()); + } + + return invocationInfo == null ? attributeList : attributeList.Where(e => e.IsApplicableToInvocation(invocationInfo)); + } + } +} diff --git a/src/Common/Properties/Resources.Designer.cs b/src/Common/Properties/Resources.Designer.cs index d011b64710..aa5a0aa400 100644 --- a/src/Common/Properties/Resources.Designer.cs +++ b/src/Common/Properties/Resources.Designer.cs @@ -635,7 +635,20 @@ public static string BreakingChangesAttributesUsageChangeMessageConsole { return ResourceManager.GetString("BreakingChangesAttributesUsageChangeMessageConsole", resourceCulture); } } + + /// + /// The cmdlet is in experimental stage. The function may not be enabled in current subscription. + /// + public static string ExperimentalCmdletMessage + { + get + { + return ResourceManager.GetString("ExperimentalCmdletMessage", resourceCulture); + } + } + + /// /// Looks up a localized string similar to CACHERUNTIMEURL. /// diff --git a/src/Common/Properties/Resources.resx b/src/Common/Properties/Resources.resx index 542096fc92..b3a870ad67 100644 --- a/src/Common/Properties/Resources.resx +++ b/src/Common/Properties/Resources.resx @@ -1728,4 +1728,7 @@ Use the Enable-AzureDataCollection cmdlet to turn the feature On. The cmdlet can NOTE : Go to {0} for steps to suppress this breaking change warning, and other information on breaking changes in Azure PowerShell. + + The cmdlet is in experimental stage. The function may not be enabled in current subscription. + From b549c077fa69ec18a55b1d5a4970b2a853dd2887 Mon Sep 17 00:00:00 2001 From: dingmeng-xue Date: Thu, 19 Mar 2020 22:29:20 +0800 Subject: [PATCH 2/4] Add message for preview cmdlet --- src/Common/AzurePSCmdlet.cs | 4 ++-- ...nAttribute.cs => CmdletPreviewAttribute.cs} | 8 ++++---- ...buteHelper.cs => PreviewAttributeHelper.cs} | 18 +++++++++--------- src/Common/Properties/Resources.Designer.cs | 12 ++++++++++++ src/Common/Properties/Resources.resx | 8 ++++---- 5 files changed, 31 insertions(+), 19 deletions(-) rename src/Common/CustomAttributes/{CmdletExperimentationAttribute.cs => CmdletPreviewAttribute.cs} (85%) rename src/Common/CustomAttributes/{ExperimentationAttributeHelper.cs => PreviewAttributeHelper.cs} (77%) diff --git a/src/Common/AzurePSCmdlet.cs b/src/Common/AzurePSCmdlet.cs index 5431560e2c..9a72165971 100644 --- a/src/Common/AzurePSCmdlet.cs +++ b/src/Common/AzurePSCmdlet.cs @@ -368,7 +368,7 @@ protected override void BeginProcessing() //Now see if the cmdlet has any Breaking change attributes on it and process them if it does //This will print any breaking change attribute messages that are applied to the cmdlet BreakingChangeAttributeHelper.ProcessCustomAttributesAtRuntime(this.GetType(), this.MyInvocation, WriteWarning); - ExperimentationAttributeHelper.ProcessCustomAttributesAtRuntime(this.GetType(), this.MyInvocation, WriteWarning); + PreviewAttributeHelper.ProcessCustomAttributesAtRuntime(this.GetType(), this.MyInvocation, WriteDebug); } /// @@ -407,8 +407,8 @@ protected bool IsVerbose() _qosEvent.Exception = errorRecord.Exception; _qosEvent.IsSuccess = false; } - base.WriteError(errorRecord); + PreviewAttributeHelper.ProcessCustomAttributesAtRuntime(this.GetType(), this.MyInvocation, WriteWarning); } protected new void ThrowTerminatingError(ErrorRecord errorRecord) diff --git a/src/Common/CustomAttributes/CmdletExperimentationAttribute.cs b/src/Common/CustomAttributes/CmdletPreviewAttribute.cs similarity index 85% rename from src/Common/CustomAttributes/CmdletExperimentationAttribute.cs rename to src/Common/CustomAttributes/CmdletPreviewAttribute.cs index 0cd422851e..2618247e95 100644 --- a/src/Common/CustomAttributes/CmdletExperimentationAttribute.cs +++ b/src/Common/CustomAttributes/CmdletPreviewAttribute.cs @@ -21,16 +21,16 @@ namespace Microsoft.WindowsAzure.Commands.Common.CustomAttributes [AttributeUsage( AttributeTargets.Class, AllowMultiple = true)] - public class CmdletExperimentationAttribute : System.Attribute + public class CmdletPreviewAttribute : System.Attribute { public string _message; - public CmdletExperimentationAttribute() + public CmdletPreviewAttribute() { - this._message = Resources.ExperimentalCmdletMessage; + this._message = Resources.PreviewCmdletMessage; } - public CmdletExperimentationAttribute(string message) + public CmdletPreviewAttribute(string message) { this._message = message; } diff --git a/src/Common/CustomAttributes/ExperimentationAttributeHelper.cs b/src/Common/CustomAttributes/PreviewAttributeHelper.cs similarity index 77% rename from src/Common/CustomAttributes/ExperimentationAttributeHelper.cs rename to src/Common/CustomAttributes/PreviewAttributeHelper.cs index dc2e0ab8bf..f54c02d8f6 100644 --- a/src/Common/CustomAttributes/ExperimentationAttributeHelper.cs +++ b/src/Common/CustomAttributes/PreviewAttributeHelper.cs @@ -20,7 +20,7 @@ namespace Microsoft.WindowsAzure.Commands.Common.CustomAttributes { - public class ExperimentationAttributeHelper + public class PreviewAttributeHelper { public const string SUPPRESS_ERROR_OR_WARNING_MESSAGE_ENV_VARIABLE_NAME = "SuppressAzurePowerShellBreakingChangeWarnings"; @@ -49,36 +49,36 @@ public static void ProcessCustomAttributesAtRuntime(Type type, InvocationInfo in return; } - List attributes = new List(GetAllAttributesInType(type, invocationInfo)); + List attributes = new List(GetAllAttributesInType(type, invocationInfo)); if (attributes != null && attributes.Count > 0) { - foreach (CmdletExperimentationAttribute attribute in attributes) + foreach (CmdletPreviewAttribute attribute in attributes) { attribute.PrintCustomAttributeInfo(writeOutput); } } } - private static IEnumerable GetAllAttributesInType(Type type, InvocationInfo invocationInfo) + private static IEnumerable GetAllAttributesInType(Type type, InvocationInfo invocationInfo) { - List attributeList = new List(); + List attributeList = new List(); - attributeList.AddRange(type.GetCustomAttributes(typeof(CmdletExperimentationAttribute), false).Cast()); + attributeList.AddRange(type.GetCustomAttributes(typeof(CmdletPreviewAttribute), false).Cast()); foreach (MethodInfo m in type.GetRuntimeMethods()) { - attributeList.AddRange((m.GetCustomAttributes(typeof(CmdletExperimentationAttribute), false).Cast())); + attributeList.AddRange((m.GetCustomAttributes(typeof(CmdletPreviewAttribute), false).Cast())); } foreach (FieldInfo f in type.GetRuntimeFields()) { - attributeList.AddRange(f.GetCustomAttributes(typeof(CmdletExperimentationAttribute), false).Cast()); + attributeList.AddRange(f.GetCustomAttributes(typeof(CmdletPreviewAttribute), false).Cast()); } foreach (PropertyInfo p in type.GetRuntimeProperties()) { - attributeList.AddRange(p.GetCustomAttributes(typeof(CmdletExperimentationAttribute), false).Cast()); + attributeList.AddRange(p.GetCustomAttributes(typeof(CmdletPreviewAttribute), false).Cast()); } return invocationInfo == null ? attributeList : attributeList.Where(e => e.IsApplicableToInvocation(invocationInfo)); diff --git a/src/Common/Properties/Resources.Designer.cs b/src/Common/Properties/Resources.Designer.cs index aa5a0aa400..2ae56c2b09 100644 --- a/src/Common/Properties/Resources.Designer.cs +++ b/src/Common/Properties/Resources.Designer.cs @@ -2560,7 +2560,19 @@ public static string PortalInstructionsGit { return ResourceManager.GetString("PortalInstructionsGit", resourceCulture); } } + + /// + /// Looks up a localized string similar to This cmdlet is in preview. The functionality may not be available in the selected subscription. + /// + public static string PreviewCmdletMessage + { + get + { + return ResourceManager.GetString("PreviewCmdletMessage", resourceCulture); + } + } + /// /// Looks up a localized string similar to A value for the Primary Peer Subnet has to be provided.. /// diff --git a/src/Common/Properties/Resources.resx b/src/Common/Properties/Resources.resx index b3a870ad67..47406987a7 100644 --- a/src/Common/Properties/Resources.resx +++ b/src/Common/Properties/Resources.resx @@ -1727,8 +1727,8 @@ Use the Enable-AzureDataCollection cmdlet to turn the feature On. The cmdlet can NOTE : Go to {0} for steps to suppress this breaking change warning, and other information on breaking changes in Azure PowerShell. - - - The cmdlet is in experimental stage. The function may not be enabled in current subscription. - + + + This cmdlet is in preview. The functionality may not be available in the selected subscription. + From d13d43c2fa7058893b704010c9d8176153c183d0 Mon Sep 17 00:00:00 2001 From: dingmeng-xue Date: Fri, 20 Mar 2020 10:55:21 +0800 Subject: [PATCH 3/4] Revise code according to review --- src/Common/CustomAttributes/CmdletPreviewAttribute.cs | 2 +- src/Common/CustomAttributes/PreviewAttributeHelper.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Common/CustomAttributes/CmdletPreviewAttribute.cs b/src/Common/CustomAttributes/CmdletPreviewAttribute.cs index 2618247e95..f36b2930a4 100644 --- a/src/Common/CustomAttributes/CmdletPreviewAttribute.cs +++ b/src/Common/CustomAttributes/CmdletPreviewAttribute.cs @@ -20,7 +20,7 @@ namespace Microsoft.WindowsAzure.Commands.Common.CustomAttributes { [AttributeUsage( AttributeTargets.Class, - AllowMultiple = true)] + AllowMultiple = false)] public class CmdletPreviewAttribute : System.Attribute { public string _message; diff --git a/src/Common/CustomAttributes/PreviewAttributeHelper.cs b/src/Common/CustomAttributes/PreviewAttributeHelper.cs index f54c02d8f6..2614bc911e 100644 --- a/src/Common/CustomAttributes/PreviewAttributeHelper.cs +++ b/src/Common/CustomAttributes/PreviewAttributeHelper.cs @@ -20,7 +20,7 @@ namespace Microsoft.WindowsAzure.Commands.Common.CustomAttributes { - public class PreviewAttributeHelper + internal class PreviewAttributeHelper { public const string SUPPRESS_ERROR_OR_WARNING_MESSAGE_ENV_VARIABLE_NAME = "SuppressAzurePowerShellBreakingChangeWarnings"; From 3648dee77ee33a51de374295638042c5e8b7f078 Mon Sep 17 00:00:00 2001 From: dingmeng-xue Date: Sat, 21 Mar 2020 20:42:51 +0800 Subject: [PATCH 4/4] Add handler in constructor --- src/Common/AzureRest/AzureRestClient.cs | 4 ++-- src/Common/AzureRest/AzureRestOperations.cs | 2 +- src/Common/AzureRest/IAzureRestClient.cs | 2 +- src/Common/AzureRest/IAzureRestOperations.cs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Common/AzureRest/AzureRestClient.cs b/src/Common/AzureRest/AzureRestClient.cs index 968e0ebe06..aa214a0c02 100644 --- a/src/Common/AzureRest/AzureRestClient.cs +++ b/src/Common/AzureRest/AzureRestClient.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Net.Http; -namespace Microsoft.WindowsAzure.Commands.Common.AzureRest +namespace Microsoft.Azure.Internal.Common { public partial class AzureRestClient : ServiceClient, IAzureRestClient, IAzureClient { @@ -33,7 +33,7 @@ public partial class AzureRestClient : ServiceClient, IAzureRes public bool EndsWithSlash { get; private set; } - protected AzureRestClient(params DelegatingHandler[] handlers) + protected AzureRestClient(params DelegatingHandler[] handlers) : base(handlers) { Initialize(); } diff --git a/src/Common/AzureRest/AzureRestOperations.cs b/src/Common/AzureRest/AzureRestOperations.cs index 2de9cdf238..62bc61f6e7 100644 --- a/src/Common/AzureRest/AzureRestOperations.cs +++ b/src/Common/AzureRest/AzureRestOperations.cs @@ -8,7 +8,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Microsoft.WindowsAzure.Commands.Common.AzureRest +namespace Microsoft.Azure.Internal.Common { internal partial class AzureRestOperations : IServiceOperations, IAzureRestOperations { diff --git a/src/Common/AzureRest/IAzureRestClient.cs b/src/Common/AzureRest/IAzureRestClient.cs index 108bf258da..a0a2986194 100644 --- a/src/Common/AzureRest/IAzureRestClient.cs +++ b/src/Common/AzureRest/IAzureRestClient.cs @@ -1,6 +1,6 @@ using System; -namespace Microsoft.WindowsAzure.Commands.Common.AzureRest +namespace Microsoft.Azure.Internal.Common { public partial interface IAzureRestClient : IDisposable { diff --git a/src/Common/AzureRest/IAzureRestOperations.cs b/src/Common/AzureRest/IAzureRestOperations.cs index 79c3108411..b41afa6333 100644 --- a/src/Common/AzureRest/IAzureRestOperations.cs +++ b/src/Common/AzureRest/IAzureRestOperations.cs @@ -5,7 +5,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Microsoft.WindowsAzure.Commands.Common.AzureRest +namespace Microsoft.Azure.Internal.Common { /// /// AzureRest operations.