/// <summary>
        /// Checks if an alias to a cmdlet has been removed.
        /// </summary>
        /// <param name="oldCmdlet">The cmdlet metadata from the old (serialized) assembly.</param>
        /// <param name="newCmdlet">The cmdlet metadata from the new assembly.</param>
        /// <param name="issueLogger">ReportLogger that will keep track of issues found.</param>
        private void CheckForRemovedCmdletAlias(
            CmdletBreakingChangeMetadata oldCmdlet,
            CmdletBreakingChangeMetadata newCmdlet,
            ReportLogger <BreakingChangeIssue> issueLogger)
        {
            // This set will contain all of the aliases in the new metadata
            HashSet <string> aliasSet = new HashSet <string>();

            // Add each alias to the set
            foreach (var newAlias in newCmdlet.AliasList)
            {
                aliasSet.Add(newAlias);
            }

            // For each alias in the old metadata, check to see
            // if it exists in the new metadata
            foreach (var oldAlias in oldCmdlet.AliasList)
            {
                // If the alias cannot be found, log an issue
                if (!aliasSet.Contains(oldAlias))
                {
                    issueLogger.LogBreakingChangeIssue(
                        cmdlet: oldCmdlet,
                        severity: 0,
                        problemId: ProblemIds.BreakingChangeProblemId.RemovedCmdletAlias,
                        description: string.Format(Properties.Resources.RemovedCmdletAliasDescription,
                                                   oldCmdlet.Name, oldAlias),
                        remediation: string.Format(Properties.Resources.RemovedCmdletAliasRemediation,
                                                   oldAlias, oldCmdlet.Name));
                }
            }
        }
示例#2
0
        /// <summary>
        /// Check if the type of the generic is the same for two generics. If not, log an issue.
        /// </summary>
        /// <param name="cmdlet">The cmdlet metadata currently being checked.</param>
        /// <param name="oldTypeMetadata">The type metadata from the old (serialized) assembly.</param>
        /// <param name="newTypeMetadata">The type metadata from the new assembly.</param>
        /// <param name="target">Target of the generic type breaking change..</param>
        /// <param name="issueLogger">ReportLogger that will keep track of issues found.</param>
        private bool HasSameGenericType(
            CmdletBreakingChangeMetadata cmdlet,
            TypeMetadata oldTypeMetadata,
            TypeMetadata newTypeMetadata,
            string target,
            ReportLogger <BreakingChangeIssue> issueLogger)
        {
            // If the type of the generics are the same, return true
            if (oldTypeMetadata.Name.Equals(newTypeMetadata.Name, StringComparison.OrdinalIgnoreCase))
            {
                return(true);
            }

            // Otherwise, log an issue and return false
            issueLogger.LogBreakingChangeIssue(
                cmdlet: cmdlet,
                severity: 0,
                problemId: ProblemIds.BreakingChangeProblemId.ChangedGenericType,
                description: string.Format(Properties.Resources.ChangedGenericTypeDescription,
                                           target, oldTypeMetadata.Name, newTypeMetadata.Name),
                remediation: string.Format(Properties.Resources.ChangedGenericTypeRemediation,
                                           target, oldTypeMetadata.Name));

            return(false);
        }
示例#3
0
        /// <summary>
        /// Check if the argument size for the generics are the same. If they are not, log an issue.
        /// </summary>
        /// <param name="cmdlet">The cmdlet metadata currently being checked.</param>
        /// <param name="oldTypeMetadata">The type metadata from the old (serialized) assembly.</param>
        /// <param name="newTypeMetadata">The type metadata from the new assembly.</param>
        /// <param name="target">Target of the generic type breaking change.</param>
        /// <param name="issueLogger">ReportLogger that will keep track of issues found.</param>
        /// <returns></returns>
        private bool HasSameGenericArgumentSize(
            CmdletBreakingChangeMetadata cmdlet,
            TypeMetadata oldTypeMetadata,
            TypeMetadata newTypeMetadata,
            string target,
            ReportLogger <BreakingChangeIssue> issueLogger)
        {
            // If the arguments are the same size, return true
            if (oldTypeMetadata.GenericTypeArguments.Count == newTypeMetadata.GenericTypeArguments.Count)
            {
                return(true);
            }

            // Otherwise, log an issue and return false
            issueLogger.LogBreakingChangeIssue(
                cmdlet: cmdlet,
                severity: 0,
                problemId: ProblemIds.BreakingChangeProblemId.DifferentGenericTypeArgumentSize,
                description: string.Format(Properties.Resources.DifferentGenericTypeArgumentSizeDescription,
                                           oldTypeMetadata.Name, target, oldTypeMetadata.GenericTypeArguments.Count,
                                           newTypeMetadata.GenericTypeArguments.Count),
                remediation: string.Format(Properties.Resources.DifferentGenericTypeArgumentSizeRemediation,
                                           oldTypeMetadata.Name, oldTypeMetadata.GenericTypeArguments.Count));

            return(false);
        }
示例#4
0
        /// <summary>
        /// Checks if the type of the output is an array or a generic, and makes sure there are no breaking changes.
        /// If the type is not an array or a generic, it proceeds with the normal type checking with CompareTypeMetadata.
        /// </summary>
        /// <param name="cmdlet">The cmdlet whose output metadata is being checked for breaking changes.</param>
        /// <param name="oldTypeMetadata">The type metadata from the old (serialized) assembly.</param>
        /// <param name="newTypeMetadata">The type metadata from the new assembly.</param>
        /// <param name="issueLogger">ReportLogger that will keep track of issues found.</param>
        public void CheckOutputType(
            CmdletBreakingChangeMetadata cmdlet,
            TypeMetadata oldTypeMetadata,
            TypeMetadata newTypeMetadata,
            ReportLogger <BreakingChangeIssue> issueLogger)
        {
            int    problemId   = ProblemIds.BreakingChangeProblemId.ChangedOutputElementType;
            string description = string.Format(Properties.Resources.ChangedOutputElementTypeDescription,
                                               oldTypeMetadata.ElementType, newTypeMetadata.ElementType);
            string remediation = string.Format(Properties.Resources.ChangedOutputElementTypeRemediation,
                                               oldTypeMetadata.ElementType);

            // If the type is an array, check for any breaking changes
            if (IsElementType(cmdlet, oldTypeMetadata, newTypeMetadata, problemId, description, remediation, issueLogger))
            {
                return;
            }

            string target = "output type";

            if (IsGenericType(cmdlet, oldTypeMetadata, newTypeMetadata, target, issueLogger))
            {
                return;
            }

            CompareTypeMetadata(cmdlet, oldTypeMetadata, newTypeMetadata, issueLogger);
        }
示例#5
0
        /// <summary>
        /// Check for any values that were removed from a validation set of a parameter.
        /// </summary>
        /// <param name="cmdlet">The cmdlet whose parameter metadata is currently being checked.</param>
        /// <param name="oldParameter">The parameter metadata from the old (serialized) assembly.</param>
        /// <param name="newParameter">The parameter metadata from new assembly</param>
        /// <param name="issueLogger">ReportLogger that will keep track of issues found.</param>
        private void CheckParameterValidationSets(
            CmdletBreakingChangeMetadata cmdlet,
            ParameterMetadata oldParameter,
            ParameterMetadata newParameter,
            ReportLogger <BreakingChangeIssue> issueLogger)
        {
            var oldValidateSet = oldParameter.ValidateSet;
            var newValidateSet = newParameter.ValidateSet;

            // If there is no validate set in the new assembly, return
            if (newValidateSet.Count == 0)
            {
                return;
            }

            // If there was no validate set in the old assembly, but there is
            // one in the new assembly, log an issue
            if (oldValidateSet.Count == 0 && newValidateSet.Count > 0)
            {
                issueLogger.LogBreakingChangeIssue(
                    cmdlet: cmdlet,
                    severity: 0,
                    problemId: ProblemIds.BreakingChangeProblemId.AddedValidateSet,
                    description: string.Format(Properties.Resources.AddedValidateSetDescription,
                                               oldParameter.Name, cmdlet.Name),
                    remediation: string.Format(Properties.Resources.AddedValidateSetRemediation,
                                               oldParameter.Name));

                return;
            }

            // This set will contain all of the values in the validate set from the new metadata
            HashSet <string> valueSet = new HashSet <string>();

            // Add each value in the validate set from the new metadata to the set
            foreach (var newValue in newValidateSet)
            {
                valueSet.Add(newValue);
            }

            // For each value in the validate set from the old metadata, check if
            // it exists in the new metadata
            foreach (var oldValue in oldValidateSet)
            {
                // If the value cannot be found, log an issue
                if (!valueSet.Contains(oldValue))
                {
                    issueLogger.LogBreakingChangeIssue(
                        cmdlet: cmdlet,
                        severity: 0,
                        problemId: ProblemIds.BreakingChangeProblemId.RemovedValidateSetValue,
                        description: string.Format(Properties.Resources.RemovedValidateSetValueDescription,
                                                   oldParameter.Name, cmdlet.Name, oldValue),
                        remediation: string.Format(Properties.Resources.RemovedValidateSetValueRemediation,
                                                   oldValue, oldParameter.Name));
                }
            }
        }
示例#6
0
 /// <summary>
 /// Check if the type for a parameter has been changed, or if any of the
 /// type's properties have been removed or changed.
 /// </summary>
 /// <param name="cmdlet">The cmdlet whose parameter metadata is currently being checked.</param>
 /// <param name="oldParameter">The parameter metadata from the old (serialized) assembly.</param>
 /// <param name="newParameter">The parameter metadata from new assembly</param>
 /// <param name="issueLogger">ReportLogger that will keep track of issues found.</param>
 private void CheckForChangedParameterType(
     CmdletBreakingChangeMetadata cmdlet,
     ParameterMetadata oldParameter,
     ParameterMetadata newParameter,
     ReportLogger <BreakingChangeIssue> issueLogger)
 {
     // Recursively look at the properties of each type and their
     // types to see if there are any breaking changes
     _typeMetadataHelper.CheckParameterType(cmdlet, oldParameter, oldParameter.Type, newParameter.Type, issueLogger);
 }
        /// <summary>
        /// Check if the default parameter set has changed, and if so, make sure
        /// that the parameters are the same
        /// </summary>
        /// <param name="oldCmdlet">The cmdlet metadata from the old (serialized) assembly.</param>
        /// <param name="newCmdlet">The cmdlet metadata from the new assembly.</param>
        /// <param name="issueLogger">ReportLogger that will keep track of issues found.</param>
        private void CheckDefaultParameterName(
            CmdletBreakingChangeMetadata oldCmdlet,
            CmdletBreakingChangeMetadata newCmdlet,
            ReportLogger <BreakingChangeIssue> issueLogger)
        {
            // If the default parameter name hasn't changed, or if there wasn't a
            // default parameter set defined before, return
            if (oldCmdlet.DefaultParameterSetName.Equals(newCmdlet.DefaultParameterSetName) ||
                oldCmdlet.DefaultParameterSetName.Equals("__AllParameterSets"))
            {
                return;
            }

            // Get the metadata for the old default parameter set
            ParameterSetMetadata oldDefaultParameterSet = oldCmdlet.ParameterSets
                                                          .First(p => p.Name.Equals(oldCmdlet.DefaultParameterSetName, StringComparison.OrdinalIgnoreCase));
            // Get the metadata for the new default parameter set
            ParameterSetMetadata newDefaultParameterSet = newCmdlet.ParameterSets
                                                          .First(p => p.Name.Equals(newCmdlet.DefaultParameterSetName, StringComparison.OrdinalIgnoreCase));

            // This dictionary will map a parameter name and aliases to the corresponding Parameter object
            Dictionary <string, Parameter> parameterDictionary = new Dictionary <string, Parameter>();

            // Add each parameter name and aliases to the dictionary
            foreach (var newParameter in newDefaultParameterSet.Parameters)
            {
                parameterDictionary.Add(newParameter.ParameterMetadata.Name, newParameter);

                foreach (var alias in newParameter.ParameterMetadata.AliasList)
                {
                    parameterDictionary.Add(alias, newParameter);
                }
            }

            // For each parameter in the old default parameter set, check if it
            // exists in the new default parameter set
            foreach (var oldParameter in oldDefaultParameterSet.Parameters)
            {
                // If the parameter cannot be found, log an issue
                if (!parameterDictionary.ContainsKey(oldParameter.ParameterMetadata.Name))
                {
                    issueLogger.LogBreakingChangeIssue(
                        cmdlet: oldCmdlet,
                        severity: 0,
                        problemId: ProblemIds.BreakingChangeProblemId.ChangeDefaultParameter,
                        description: string.Format(Properties.Resources.ChangeDefaultParameterDescription,
                                                   oldCmdlet.DefaultParameterSetName, oldCmdlet.Name),
                        remediation: string.Format(Properties.Resources.ChangeDefaultParameterRemediation,
                                                   oldCmdlet.Name, oldCmdlet.DefaultParameterSetName));
                }
            }
        }
示例#8
0
 public static void LogBreakingChangeIssue(
     this ReportLogger <BreakingChangeIssue> issueLogger, CmdletBreakingChangeMetadata cmdlet,
     string description, string remediation, int severity, int problemId)
 {
     issueLogger.LogRecord(new BreakingChangeIssue
     {
         ClassName   = cmdlet.ClassName,
         Target      = cmdlet.Name,
         Description = description,
         Remediation = remediation,
         Severity    = severity,
         ProblemId   = problemId
     });
 }
示例#9
0
        /// <summary>
        /// Check if the parameter gained a validation range for values, or if the
        /// existing validation range for values excludes values previously accepted.
        /// </summary>
        /// <param name="cmdlet">The cmdlet whose parameter metadata is currently being checked.</param>
        /// <param name="oldParameter">The parameter metadata from the old (serialized) assembly.</param>
        /// <param name="newParameter">The parameter metadata from new assembly.</param>
        /// <param name="issueLogger">ReportLogger that will keep track of the issues found.</param>
        private void CheckParameterValidateRange(
            CmdletBreakingChangeMetadata cmdlet,
            ParameterMetadata oldParameter,
            ParameterMetadata newParameter,
            ReportLogger <BreakingChangeIssue> issueLogger)
        {
            if (newParameter.ValidateRangeMin != null && newParameter.ValidateRangeMax != null)
            {
                // If the old parameter had no validation range, but the new parameter does, log an issue
                if (oldParameter.ValidateRangeMin == null && oldParameter.ValidateRangeMax == null)
                {
                    issueLogger.LogBreakingChangeIssue(
                        cmdlet: cmdlet,
                        severity: 0,
                        problemId: ProblemIds.BreakingChangeProblemId.AddedValidateRange,
                        description: string.Format(Properties.Resources.AddedValidateRangeDescription,
                                                   oldParameter.Name, cmdlet.Name),
                        remediation: string.Format(Properties.Resources.AddedValidateRangeRemediation,
                                                   oldParameter.Name));
                }
                else
                {
                    // If the minimum value of the range has increased, log an issue
                    if (oldParameter.ValidateRangeMin < newParameter.ValidateRangeMin)
                    {
                        issueLogger.LogBreakingChangeIssue(
                            cmdlet: cmdlet,
                            severity: 0,
                            problemId: ProblemIds.BreakingChangeProblemId.ChangedValidateRangeMinimum,
                            description: string.Format(Properties.Resources.ChangedValidateRangeMinimumDescription,
                                                       oldParameter.Name, oldParameter.ValidateRangeMin, newParameter.ValidateRangeMin),
                            remediation: string.Format(Properties.Resources.ChangedValidateRangeMinimumRemediation,
                                                       oldParameter.Name, oldParameter.ValidateRangeMin));
                    }

                    // If the maximum value of the range has decreased, log an issue
                    if (oldParameter.ValidateRangeMax > newParameter.ValidateRangeMax)
                    {
                        issueLogger.LogBreakingChangeIssue(
                            cmdlet: cmdlet,
                            severity: 0,
                            problemId: ProblemIds.BreakingChangeProblemId.ChangedValidateRangeMaximum,
                            description: string.Format(Properties.Resources.ChangedValidateRangeMaximumDescription,
                                                       oldParameter.Name, oldParameter.ValidateRangeMax, newParameter.ValidateRangeMax),
                            remediation: string.Format(Properties.Resources.ChangedValidateRangeMaximumRemediation,
                                                       oldParameter.Name, oldParameter.ValidateRangeMax));
                    }
                }
            }
        }
示例#10
0
        /// <summary>
        /// Compares the metadata of parameters with the same name (or alias) for any breaking changes.
        ///
        /// Breaking changes for parameters include
        ///   - Removing a parameter
        ///   - Removing an alias to a parameter
        ///   - Type (or any of its properties) of parameter has changed
        ///   - A value in the validate set of a parameter has been removed
        ///   - ValidateNotNullOrEmpty attribute has been added to a parameter
        /// </summary>
        /// <param name="cmdlet">Reference to the cmdlet whose parameters are being checked.</param>
        /// <param name="oldParameters">The list of parameters from the old cmdlet metadata.</param>
        /// <param name="newParameters">The list of parameters from the new cmdlet metadata.</param>
        /// <param name="issueLogger">ReportLogger that will keep track of the issues found.</param>
        public void CompareParameterMetadata(
            CmdletBreakingChangeMetadata cmdlet,
            List <ParameterMetadata> oldParameters,
            List <ParameterMetadata> newParameters,
            ReportLogger <BreakingChangeIssue> issueLogger)
        {
            // This dictionary will map a parameter name (or alias) to the corresponding metadata
            Dictionary <string, ParameterMetadata> parameterDictionary = new Dictionary <string, ParameterMetadata>();

            // For each parameter, add its name (and aliases) to the dictionary
            foreach (var newParameter in newParameters)
            {
                parameterDictionary.Add(newParameter.Name, newParameter);

                foreach (var alias in newParameter.AliasList)
                {
                    parameterDictionary.Add(alias, newParameter);
                }
            }

            // For each parameter in the old metadata, see if it has been
            // added to the dictionary (exists in the new metadata)
            foreach (var oldParameter in oldParameters)
            {
                if (parameterDictionary.ContainsKey(oldParameter.Name))
                {
                    var newParameter = parameterDictionary[oldParameter.Name];

                    // Go through all of the breaking change checks for parameters
                    CheckForChangedParameterType(cmdlet, oldParameter, newParameter, issueLogger);
                    CheckForRemovedParameterAlias(cmdlet, oldParameter, newParameter, issueLogger);
                    CheckParameterValidationSets(cmdlet, oldParameter, newParameter, issueLogger);
                    CheckForValidateNotNullOrEmpty(cmdlet, oldParameter, newParameter, issueLogger);
                    CheckParameterValidateRange(cmdlet, oldParameter, newParameter, issueLogger);
                }
                // If the parameter cannot be found, log an issue
                else
                {
                    issueLogger.LogBreakingChangeIssue(
                        cmdlet: cmdlet,
                        severity: 0,
                        problemId: ProblemIds.BreakingChangeProblemId.RemovedParameter,
                        description: string.Format(Properties.Resources.RemovedParameterDescription,
                                                   cmdlet.Name, oldParameter.Name),
                        remediation: string.Format(Properties.Resources.RemovedParameterRemediation,
                                                   oldParameter.Name, cmdlet.Name));
                }
            }
        }
示例#11
0
        /// <summary>
        /// Check if the given types are generics, and if so, see if their generic properties are the same. If not, log an issue.
        /// </summary>
        /// <param name="cmdlet">The cmdlet metadata currently being checked.</param>
        /// <param name="oldTypeMetadata">The type metadata from the old (serialized) assembly.</param>
        /// <param name="newTypeMetadata">The type metadata from the new assembly.</param>
        /// <param name="target">Target of the generic type breaking change.</param>
        /// <param name="issueLogger">ReportLogger that will keep track of issues found.</param>
        /// <returns></returns>
        private bool IsGenericType(
            CmdletBreakingChangeMetadata cmdlet,
            TypeMetadata oldTypeMetadata,
            TypeMetadata newTypeMetadata,
            string target,
            ReportLogger <BreakingChangeIssue> issueLogger)
        {
            // If the type is a generic, check for any breaking changes
            if (oldTypeMetadata.GenericTypeArguments.Count > 0 && newTypeMetadata.GenericTypeArguments.Count > 0)
            {
                // Check if the generic type has changed
                if (HasSameGenericType(cmdlet, oldTypeMetadata, newTypeMetadata, target, issueLogger))
                {
                    // Check if the number of generic type arguments is the same
                    if (HasSameGenericArgumentSize(cmdlet, oldTypeMetadata, newTypeMetadata, target, issueLogger))
                    {
                        // For each element in the generic type arguments list,
                        // make sure that the types are the same
                        for (int idx = 0; idx < oldTypeMetadata.GenericTypeArguments.Count; idx++)
                        {
                            var oldArgument = oldTypeMetadata.GenericTypeArguments[idx];
                            var newArgument = newTypeMetadata.GenericTypeArguments[idx];

                            if (CheckGenericTypeArguments(cmdlet, oldArgument, newArgument, target, issueLogger))
                            {
                                // If we have not previously seen this generic type argument,
                                // run this method on the type
                                if (!_typeSet.Contains(oldArgument))
                                {
                                    _typeSet.Add(oldArgument);

                                    var oldElementType = _oldTypeDictionary[oldArgument];
                                    var newElementType = _newTypeDictionary[newArgument];

                                    CompareTypeMetadata(cmdlet, oldElementType, newElementType, issueLogger);
                                }
                            }
                        }
                    }
                }

                return(true);
            }



            return(false);
        }
 /// <summary>
 /// Check if a cmdlet no longer implements SupportsPaging.
 /// </summary>
 /// <param name="oldCmdlet">The cmdlet metadata from the old (serialized) assembly.</param>
 /// <param name="newCmdlet">The cmdlet metadata from the new assembly.</param>
 /// <param name="issueLogger">ReportLogger that will keep track of issues found.</param>
 private void CheckForRemovedSupportsPaging(
     CmdletBreakingChangeMetadata oldCmdlet,
     CmdletBreakingChangeMetadata newCmdlet,
     ReportLogger <BreakingChangeIssue> issueLogger)
 {
     // If the old cmdlet implements SupportsPaging and the new cmdlet does not, log an issue
     if (oldCmdlet.SupportsPaging && !newCmdlet.SupportsPaging)
     {
         issueLogger.LogBreakingChangeIssue(
             cmdlet: oldCmdlet,
             severity: 0,
             problemId: ProblemIds.BreakingChangeProblemId.RemovedPaging,
             description: string.Format(Properties.Resources.RemovedPagingDescription, oldCmdlet.Name),
             remediation: string.Format(Properties.Resources.RemovedPagingRemediation, oldCmdlet.Name));
     }
 }
示例#13
0
        /// <summary>
        /// Checks if the type of the parameter is an array or a generic, and makes sure there are no breaking changes.
        /// If the type is not an array or a generic, it proceeds with the normal type checking with CompareTypeMetadata.
        /// </summary>
        /// <param name="cmdlet">The cmdlet whose parameter metadata is being checked for breaking changes.</param>
        /// <param name="parameter">The parameter whose type metadata is being checked for breaking changes.</param>
        /// <param name="oldTypeMetadata">The type metadata from the old (serialized) assembly.</param>
        /// <param name="newTypeMetadata">The type metadata from the new assembly.</param>
        /// <param name="issueLogger">ReportLogger that will keep track of issues found.</param>
        public void CheckParameterType(
            CmdletBreakingChangeMetadata cmdlet,
            ParameterMetadata parameter,
            TypeMetadata oldTypeMetadata,
            TypeMetadata newTypeMetadata,
            ReportLogger <BreakingChangeIssue> issueLogger)
        {
            int    problemId   = ProblemIds.BreakingChangeProblemId.ChangedParameterElementType;
            string description = string.Format(Properties.Resources.ChangedParameterElementTypeDescription,
                                               parameter.Name, oldTypeMetadata.ElementType, newTypeMetadata.ElementType);
            string remediation = string.Format(Properties.Resources.ChangedParameterElementTypeRemediation,
                                               parameter.Name, oldTypeMetadata.ElementType);

            // If the type is an array, check for any breaking changes
            if (IsElementType(cmdlet, oldTypeMetadata, newTypeMetadata, problemId, description, remediation, issueLogger))
            {
                return;
            }

            string target = string.Format("parameter {0}", parameter.Name);

            // If the type is a generic, check for any breaking changes
            if (IsGenericType(cmdlet, oldTypeMetadata, newTypeMetadata, target, issueLogger))
            {
                return;
            }

            // If the types are different, log an issue
            if (!oldTypeMetadata.Name.Equals(newTypeMetadata.Name, StringComparison.OrdinalIgnoreCase))
            {
                issueLogger.LogBreakingChangeIssue(
                    cmdlet: cmdlet,
                    severity: 0,
                    problemId: ProblemIds.BreakingChangeProblemId.ChangedParameterType,
                    description: string.Format(Properties.Resources.ChangedParameterTypeDescription,
                                               cmdlet.Name, oldTypeMetadata.Name, parameter.Name),
                    remediation: string.Format(Properties.Resources.ChangedParameterTypeRemediation,
                                               parameter.Name, oldTypeMetadata.Name));
            }
            else
            {
                CompareTypeMetadata(cmdlet, oldTypeMetadata, newTypeMetadata, issueLogger);
            }
        }
示例#14
0
        /// <summary>
        /// Check if the given types are arrays, and if so, see if their element types are the same. If not, log an issue.
        /// </summary>
        /// <param name="cmdlet">The cmdlet metadata currently being checked.</param>
        /// <param name="oldTypeMetadata">The type metadata from the old (serialized) assembly.</param>
        /// <param name="newTypeMetadata">The type metadata from the new assembly.</param>
        /// <param name="problemId">The problemId used for logging if there is an issue.</param>
        /// <param name="description">The description used for logging if there is an issue.</param>
        /// <param name="remediation">The remediation used for logging if there is an issue.</param>
        /// <param name="issueLogger">ReportLogger that will keep track of issues found.</param>
        private bool IsElementType(
            CmdletBreakingChangeMetadata cmdlet,
            TypeMetadata oldTypeMetadata,
            TypeMetadata newTypeMetadata,
            int problemId,
            string description,
            string remediation,
            ReportLogger <BreakingChangeIssue> issueLogger)
        {
            // Check if the type is an array
            if (oldTypeMetadata.ElementType != null && newTypeMetadata.ElementType != null)
            {
                // Check if the element of the array is the same in the old and new metadata
                if (oldTypeMetadata.ElementType.Equals(newTypeMetadata.ElementType, StringComparison.OrdinalIgnoreCase))
                {
                    // If we have not previously seen this element type,
                    // run this method on the type
                    if (!_typeSet.Contains(oldTypeMetadata.ElementType))
                    {
                        _typeSet.Add(oldTypeMetadata.ElementType);

                        var oldElementType = _oldTypeDictionary[oldTypeMetadata.ElementType];
                        var newElementType = _newTypeDictionary[newTypeMetadata.ElementType];

                        CompareTypeMetadata(cmdlet, oldElementType, newElementType, issueLogger);
                    }
                }
                // If the element type has changed, log an issue
                else
                {
                    issueLogger.LogBreakingChangeIssue(
                        cmdlet: cmdlet,
                        severity: 0,
                        problemId: problemId,
                        description: description,
                        remediation: remediation);
                }

                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Check if the OutputType of the cmdlet has been removed, or if any property
        /// of the OutputType has been removed or changed
        /// </summary>
        /// <param name="oldCmdlet">The cmdlet metadata from the old (serialized) assembly.</param>
        /// <param name="newCmdlet">The cmdlet metadata from the new assembly.</param>
        /// <param name="issueLogger">ReportLogger that will keep track of issues found.</param>
        private void CheckForChangedOutputType(
            CmdletBreakingChangeMetadata oldCmdlet,
            CmdletBreakingChangeMetadata newCmdlet,
            ReportLogger <BreakingChangeIssue> issueLogger)
        {
            // This dictionary will map an output type name to the corresponding type metadata
            Dictionary <string, TypeMetadata> outputDictionary = new Dictionary <string, TypeMetadata>(new TypeNameComparer());

            // Add each output in the new metadata to the dictionary
            foreach (var newOutput in newCmdlet.OutputTypes)
            {
                if (!outputDictionary.ContainsKey(newOutput.Type.Name))
                {
                    outputDictionary.Add(newOutput.Type.Name, newOutput.Type);
                }
            }

            // For each output in the old metadata, see if it
            // exists in the new metadata
            foreach (var oldOutput in oldCmdlet.OutputTypes)
            {
                // If the output can be found, use the TypeMetadataHelper to
                // check the type for any breaking changes
                if (outputDictionary.ContainsKey(oldOutput.Type.Name))
                {
                    var newOutputType = outputDictionary[oldOutput.Type.Name];

                    _typeMetadataHelper.CheckOutputType(oldCmdlet, oldOutput.Type, newOutputType, issueLogger);
                }
                // If the output cannot be found, log an issue
                else
                {
                    issueLogger.LogBreakingChangeIssue(
                        cmdlet: oldCmdlet,
                        severity: 0,
                        problemId: ProblemIds.BreakingChangeProblemId.ChangedOutputType,
                        description: string.Format(Properties.Resources.ChangedOutputTypeDescription,
                                                   oldCmdlet.Name, oldOutput.Type.Name),
                        remediation: string.Format(Properties.Resources.ChangedOutputTypeRemediation,
                                                   oldCmdlet.Name, oldOutput.Type.Name));
                }
            }
        }
示例#16
0
 /// <summary>
 /// Check if the parameter now supports the ValidateNotNullOrEmpty attribute
 /// </summary>
 /// <param name="cmdlet">The cmdlet whose parameter metadata is currently being checked.</param>
 /// <param name="oldParameter">The parameter metadata from the old (serialized) assembly.</param>
 /// <param name="newParameter">The parameter metadata from new assembly</param>
 /// <param name="issueLogger">ReportLogger that will keep track of issues found.</param>
 private void CheckForValidateNotNullOrEmpty(
     CmdletBreakingChangeMetadata cmdlet,
     ParameterMetadata oldParameter,
     ParameterMetadata newParameter,
     ReportLogger <BreakingChangeIssue> issueLogger)
 {
     // If the parameter didn't have the ValidateNotNullOrEmpty attribute in the
     // old assembly, but has it in the new assembly, log an issue
     if (!oldParameter.ValidateNotNullOrEmpty && newParameter.ValidateNotNullOrEmpty)
     {
         issueLogger.LogBreakingChangeIssue(
             cmdlet: cmdlet,
             severity: 0,
             problemId: ProblemIds.BreakingChangeProblemId.AddedValidateNotNullOrEmpty,
             description: string.Format(Properties.Resources.AddedValidateNotNullOrEmptyDescription,
                                        oldParameter.Name, cmdlet.Name),
             remediation: string.Format(Properties.Resources.AddedValidateNotNullOrEmptyRemediation,
                                        oldParameter.Name));
     }
 }
示例#17
0
        /// <summary>
        /// Check if the arguments of a generic type are the same. If they are not, log an issue.
        /// </summary>
        /// <param name="cmdlet">The cmdlet metadata currently being checked.</param>
        /// <param name="oldArgument">The old argument from the generic.</param>
        /// <param name="newArgument">The new argument from the generic</param>
        /// <param name="target">Target of the generic type breaking change.</param>
        /// <param name="issueLogger">ReportLogger that will keep track of issues found.</param>
        private bool CheckGenericTypeArguments(
            CmdletBreakingChangeMetadata cmdlet,
            string oldArgument,
            string newArgument,
            string target,
            ReportLogger <BreakingChangeIssue> issueLogger)
        {
            if (oldArgument.Equals(newArgument, StringComparison.OrdinalIgnoreCase))
            {
                return(true);
            }

            // If the generic type arguments aren't the same, log an issue
            issueLogger.LogBreakingChangeIssue(
                cmdlet: cmdlet,
                severity: 0,
                problemId: ProblemIds.BreakingChangeProblemId.ChangedGenericTypeArgument,
                description: string.Format(Properties.Resources.ChangedGenericTypeArgumentDescription,
                                           target, oldArgument, newArgument),
                remediation: string.Format(Properties.Resources.ChangedGenericTypeArgumentRemediation,
                                           target, oldArgument));

            return(false);
        }
示例#18
0
        /// <summary>
        /// Compares the metadata of parameter sets with the same name for any breaking changes.
        ///
        /// Breaking changes for parameter sets include
        ///   - Removing a parameter set
        ///   - Making an optional parameter mandatory
        ///   - Changing the position of a parameter
        ///   - A parameter that previously could get its value from the pipeline no longer does
        ///   - A parameter that previously could get its value from the pipeline by property name no longer does
        ///   - A parameter has been removed from the parameter set
        /// </summary>
        /// <param name="cmdlet">Reference to the cmdlet whose parameter sets are being checked.</param>
        /// <param name="oldParameterSets">The list of parameter sets from the old (serialized) metadata.</param>
        /// <param name="newParameterSets">The list of parameter sets from the new metadata</param>
        /// <param name="issueLogger">ReportLogger that will keep track of the issues found.</param>
        public void CompareParameterSetMetadata(
            CmdletBreakingChangeMetadata cmdlet,
            List <ParameterSetMetadata> oldParameterSets,
            List <ParameterSetMetadata> newParameterSets,
            ReportLogger <BreakingChangeIssue> issueLogger)
        {
            // This dictionary will map a parameter set name to the corresponding metadata
            Dictionary <string, ParameterSetMetadata> parameterSetDictionary = new Dictionary <string, ParameterSetMetadata>();

            // Add each parameter set to the dictionary
            foreach (var newParameterSet in newParameterSets)
            {
                parameterSetDictionary.Add(newParameterSet.Name, newParameterSet);
            }

            // For each parameter set in the old metadata, see if it has been
            // added to the dictionary (exists in the new metadata)
            foreach (var oldParameterSet in oldParameterSets)
            {
                if (parameterSetDictionary.ContainsKey(oldParameterSet.Name))
                {
                    var newParameterSet = parameterSetDictionary[oldParameterSet.Name];

                    // This dictionary will map a parameter to the corresponding Parameter object
                    Dictionary <string, Parameter> parameterDictionary = new Dictionary <string, Parameter>();

                    // For each parameter in the parameter set, add its name and alias to the dictionary
                    foreach (var newParameter in newParameterSet.Parameters)
                    {
                        if (!parameterDictionary.ContainsKey(newParameter.ParameterMetadata.Name))
                        {
                            parameterDictionary.Add(newParameter.ParameterMetadata.Name, newParameter);
                        }

                        foreach (var alias in newParameter.ParameterMetadata.AliasList)
                        {
                            if (!parameterDictionary.ContainsKey(alias))
                            {
                                parameterDictionary.Add(alias, newParameter);
                            }
                        }
                    }

                    // For each parameter in the old metadata, see if it has been
                    // added to the dictionary (exists in the new metadata)
                    foreach (var oldParameter in oldParameterSet.Parameters)
                    {
                        if (parameterDictionary.ContainsKey(oldParameter.ParameterMetadata.Name))
                        {
                            var newParameter = parameterDictionary[oldParameter.ParameterMetadata.Name];

                            // If the parameter was optional in the old assembly and
                            // mandatory in the new assembly, log an issue
                            if (!oldParameter.Mandatory && newParameter.Mandatory)
                            {
                                issueLogger.LogBreakingChangeIssue(
                                    cmdlet: cmdlet,
                                    severity: 0,
                                    problemId: ProblemIds.BreakingChangeProblemId.MandatoryParameter,
                                    description: string.Format(Properties.Resources.MandatoryParameterDescription,
                                                               oldParameter.ParameterMetadata.Name, oldParameterSet.Name, cmdlet.Name),
                                    remediation: string.Format(Properties.Resources.MandatoryParameterRemediation,
                                                               oldParameter.ParameterMetadata.Name, oldParameterSet.Name));
                            }

                            // If the parameter had a position and it has changed in the
                            // new assembly, log an issue
                            if (oldParameter.Position >= 0 && oldParameter.Position != newParameter.Position)
                            {
                                issueLogger.LogBreakingChangeIssue(
                                    cmdlet: cmdlet,
                                    severity: 0,
                                    problemId: ProblemIds.BreakingChangeProblemId.PositionChange,
                                    description: string.Format(Properties.Resources.PositionChangeDescription,
                                                               oldParameter.ParameterMetadata.Name, oldParameterSet.Name, cmdlet.Name),
                                    remediation: string.Format(Properties.Resources.PositionChangeRemediation,
                                                               oldParameter.ParameterMetadata.Name, oldParameterSet.Name));
                            }

                            // If the parameter can no longer get its value from
                            // the pipeline, log an issue
                            if (oldParameter.ValueFromPipeline && !newParameter.ValueFromPipeline)
                            {
                                issueLogger.LogBreakingChangeIssue(
                                    cmdlet: cmdlet,
                                    severity: 0,
                                    problemId: ProblemIds.BreakingChangeProblemId.ValueFromPipeline,
                                    description: string.Format(Properties.Resources.RemovedValueFromPipelineDescription,
                                                               oldParameter.ParameterMetadata.Name, oldParameterSet.Name, cmdlet.Name),
                                    remediation: string.Format(Properties.Resources.RemovedValueFromPipelineRemediation,
                                                               oldParameter.ParameterMetadata.Name, oldParameterSet.Name));
                            }

                            // If the parameter can no longer get its value from
                            // the pipeline by property name, log an issue
                            if (oldParameter.ValueFromPipelineByPropertyName && !newParameter.ValueFromPipelineByPropertyName)
                            {
                                issueLogger.LogBreakingChangeIssue(
                                    cmdlet: cmdlet,
                                    severity: 0,
                                    problemId: ProblemIds.BreakingChangeProblemId.ValueFromPipelineByPropertyName,
                                    description: string.Format(Properties.Resources.RemovedValueFromPipelineByPropertyNameDescription,
                                                               oldParameter.ParameterMetadata.Name, oldParameterSet.Name, cmdlet.Name),
                                    remediation: string.Format(Properties.Resources.RemovedValueFromPipelineByPropertyNameRemediation,
                                                               oldParameter.ParameterMetadata.Name, oldParameterSet.Name));
                            }
                        }
                        // If the parameter cannot be found, log an issue
                        else
                        {
                            issueLogger.LogBreakingChangeIssue(
                                cmdlet: cmdlet,
                                severity: 0,
                                problemId: ProblemIds.BreakingChangeProblemId.RemovedParameterFromParameterSet,
                                description: string.Format(Properties.Resources.RemovedParameterFromParameterSetDescription,
                                                           oldParameter.ParameterMetadata.Name, cmdlet.Name, oldParameterSet.Name),
                                remediation: string.Format(Properties.Resources.RemovedParameterFromParameterSetRemediation,
                                                           oldParameter.ParameterMetadata.Name, oldParameterSet.Name));
                        }
                    }
                }
                // If the parameter set cannot be found, and the parameter set
                // was not the default (no parameter set) name, log an issue
                else if (!parameterSetDictionary.ContainsKey(oldParameterSet.Name) &&
                         !oldParameterSet.Name.Equals("__AllParameterSets"))
                {
                    issueLogger.LogBreakingChangeIssue(
                        cmdlet: cmdlet,
                        severity: 0,
                        problemId: ProblemIds.BreakingChangeProblemId.RemovedParameterSet,
                        description: string.Format(Properties.Resources.RemovedParameterSetDescription,
                                                   oldParameterSet.Name, cmdlet.Name),
                        remediation: string.Format(Properties.Resources.RemovedParameterSetRemediation,
                                                   oldParameterSet.Name, cmdlet.Name));
                }
            }
        }
        /// <summary>
        /// Compare two types by recursively checking their properties and property
        /// types, making sure that nothing has been removed or changed.
        /// </summary>
        /// <param name="cmdlet">The cmdlet metadata currently being checked.</param>
        /// <param name="oldType">The type metadata from the old (serialized) assembly.</param>
        /// <param name="newType">The type metadata from the new assembly.</param>
        /// <param name="issueLogger">ReportLogger that will keep track of issues found.</param>
        public void CompareTypeMetadata(
            CmdletBreakingChangeMetadata cmdlet,
            TypeMetadata oldType,
            TypeMetadata newType,
            ReportLogger <BreakingChangeIssue> issueLogger)
        {
            // For each property in the old assembly type, find the corresponding
            // property in the new assembly type
            foreach (var oldProperty in oldType.Properties.Keys)
            {
                if (newType.Properties.ContainsKey(oldProperty))
                {
                    var oldPropertyType = oldType.Properties[oldProperty];
                    var newPropertyType = newType.Properties[oldProperty];

                    var oldTypeMetadata = _oldTypeDictionary[oldPropertyType];
                    var newTypeMetadata = _newTypeDictionary[newPropertyType];

                    // Check if the type is an array
                    if (oldTypeMetadata.ElementType != null && newTypeMetadata.ElementType != null)
                    {
                        // Check if the element of the array is the same in the old and new metadata
                        if (oldTypeMetadata.ElementType.Equals(newTypeMetadata.ElementType, StringComparison.OrdinalIgnoreCase))
                        {
                            // If we have not previously seen this element type,
                            // run this method on the type
                            if (!_typeSet.Contains(oldTypeMetadata.ElementType))
                            {
                                _typeSet.Add(oldTypeMetadata.ElementType);

                                var oldElementType = _oldTypeDictionary[oldTypeMetadata.ElementType];
                                var newElementType = _newTypeDictionary[newTypeMetadata.ElementType];

                                CompareTypeMetadata(cmdlet, oldElementType, newElementType, issueLogger);
                            }
                        }
                        // If the element type has changed, log an issue
                        else
                        {
                            issueLogger.LogBreakingChangeIssue(
                                cmdlet: cmdlet,
                                severity: 0,
                                problemId: ProblemIds.BreakingChangeProblemId.ChangedElementType,
                                description: string.Format(Properties.Resources.ChangedElementTypeDescription,
                                                           oldProperty, oldTypeMetadata.ElementType, newTypeMetadata.ElementType),
                                remediation: string.Format(Properties.Resources.ChangedElementTypeRemediation,
                                                           oldProperty, oldTypeMetadata.ElementType));
                        }

                        continue;
                    }

                    // Check if the type is a generic
                    if (oldTypeMetadata.GenericTypeArguments.Count > 0 && newTypeMetadata.GenericTypeArguments.Count > 0)
                    {
                        // Check if the generic type has changed
                        if (oldTypeMetadata.Name.Equals(newTypeMetadata.Name, StringComparison.OrdinalIgnoreCase))
                        {
                            // Check if the number of generic type arguments is the same
                            if (oldTypeMetadata.GenericTypeArguments.Count == newTypeMetadata.GenericTypeArguments.Count)
                            {
                                // For each element in the generic type arguments list, make sure that the types
                                // are the same
                                for (int idx = 0; idx < oldTypeMetadata.GenericTypeArguments.Count; idx++)
                                {
                                    if (oldTypeMetadata.GenericTypeArguments[idx].Equals(newTypeMetadata.GenericTypeArguments[idx], StringComparison.OrdinalIgnoreCase))
                                    {
                                        // If we have not previously seen this generic type argument,
                                        // run this method on the type
                                        if (!_typeSet.Contains(oldTypeMetadata.GenericTypeArguments[idx]))
                                        {
                                            _typeSet.Add(oldTypeMetadata.GenericTypeArguments[idx]);

                                            var oldElementType = _oldTypeDictionary[oldTypeMetadata.GenericTypeArguments[idx]];
                                            var newElementType = _newTypeDictionary[newTypeMetadata.GenericTypeArguments[idx]];

                                            CompareTypeMetadata(cmdlet, oldElementType, newElementType, issueLogger);
                                        }
                                    }
                                    // If the generic type arguments aren't the same, log an issue
                                    else
                                    {
                                        issueLogger.LogBreakingChangeIssue(
                                            cmdlet: cmdlet,
                                            severity: 0,
                                            problemId: ProblemIds.BreakingChangeProblemId.ChangedGenericTypeArgument,
                                            description: string.Format(Properties.Resources.ChangedGenericTypeArgumentDescription,
                                                                       oldProperty, oldTypeMetadata.GenericTypeArguments[idx], newTypeMetadata.GenericTypeArguments[idx]),
                                            remediation: string.Format(Properties.Resources.ChangedGenericTypeArgumentRemediation,
                                                                       oldProperty, oldTypeMetadata.GenericTypeArguments[idx]));
                                    }
                                }
                            }
                            // If the number of generic type arguments is different, log an issue
                            else
                            {
                                issueLogger.LogBreakingChangeIssue(
                                    cmdlet: cmdlet,
                                    severity: 0,
                                    problemId: ProblemIds.BreakingChangeProblemId.DifferentGenericTypeArgumentSize,
                                    description: string.Format(Properties.Resources.DifferentGenericTypeArgumentSizeDescription,
                                                               oldTypeMetadata.Name, oldProperty,
                                                               oldTypeMetadata.GenericTypeArguments.Count, newTypeMetadata.GenericTypeArguments.Count),
                                    remediation: string.Format(Properties.Resources.DifferentGenericTypeArgumentSizeRemediation,
                                                               oldTypeMetadata.Name, oldTypeMetadata.GenericTypeArguments.Count));
                            }
                        }
                        // If the generic type has changed, log an issue
                        else
                        {
                            issueLogger.LogBreakingChangeIssue(
                                cmdlet: cmdlet,
                                severity: 0,
                                problemId: ProblemIds.BreakingChangeProblemId.ChangedGenericType,
                                description: string.Format(Properties.Resources.ChangedGenericTypeDescription,
                                                           oldProperty, oldTypeMetadata.Name, newTypeMetadata.Name),
                                remediation: string.Format(Properties.Resources.ChangedGenericTypeRemediation,
                                                           oldProperty, oldTypeMetadata.Name));
                        }

                        continue;
                    }

                    // If the types are the same, compare their properties
                    if (oldPropertyType.Equals(newPropertyType, StringComparison.OrdinalIgnoreCase))
                    {
                        // If we have not previously seen this type, run this
                        // method on the type
                        if (!_typeSet.Contains(oldPropertyType))
                        {
                            _typeSet.Add(oldPropertyType);

                            CompareTypeMetadata(cmdlet, oldTypeMetadata, newTypeMetadata, issueLogger);
                        }
                    }
                    else
                    {
                        // If the type of the property has been changed, log an issue
                        issueLogger.LogBreakingChangeIssue(
                            cmdlet: cmdlet,
                            severity: 0,
                            problemId: ProblemIds.BreakingChangeProblemId.ChangedPropertyType,
                            description: string.Format(Properties.Resources.ChangedPropertyTypeDescription,
                                                       oldProperty, oldType.Name, oldPropertyType, newPropertyType),
                            remediation: string.Format(Properties.Resources.ChangedPropertyTypeRemediation,
                                                       oldProperty, oldPropertyType));
                    }
                }
                else
                {
                    // If the property has been removed, log an issue
                    issueLogger.LogBreakingChangeIssue(
                        cmdlet: cmdlet,
                        severity: 0,
                        problemId: ProblemIds.BreakingChangeProblemId.RemovedProperty,
                        description: string.Format(Properties.Resources.RemovedPropertyDescription,
                                                   oldProperty, oldType.Name),
                        remediation: string.Format(Properties.Resources.RemovedPropertyRemediation,
                                                   oldProperty, oldType.Name));
                }
            }
        }
        /// <summary>
        /// Checks if the type of the output is an array or a generic, and makes sure there are no breaking changes.
        /// If the type is not an array or a generic, it proceeds with the normal type checking with CompareTypeMetadata.
        /// </summary>
        /// <param name="cmdlet">The cmdlet whose output metadata is being checked for breaking changes.</param>
        /// <param name="oldTypeMetadata">The type metadata from the old (serialized) assembly.</param>
        /// <param name="newTypeMetadata">The type metadata from the new assembly.</param>
        /// <param name="issueLogger">ReportLogger that will keep track of issues found.</param>
        public void CheckOutputType(
            CmdletBreakingChangeMetadata cmdlet,
            TypeMetadata oldTypeMetadata,
            TypeMetadata newTypeMetadata,
            ReportLogger <BreakingChangeIssue> issueLogger)
        {
            // Check if the type is an array
            if (oldTypeMetadata.ElementType != null && newTypeMetadata.ElementType != null)
            {
                // Check if the element of the array is the same in the old and new metadata
                if (oldTypeMetadata.ElementType.Equals(newTypeMetadata.ElementType, StringComparison.OrdinalIgnoreCase))
                {
                    // If we have not previously seen this element type,
                    // run this method on the type
                    if (!_typeSet.Contains(oldTypeMetadata.ElementType))
                    {
                        _typeSet.Add(oldTypeMetadata.ElementType);

                        var oldElementType = _oldTypeDictionary[oldTypeMetadata.ElementType];
                        var newElementType = _newTypeDictionary[newTypeMetadata.ElementType];

                        CompareTypeMetadata(cmdlet, oldElementType, newElementType, issueLogger);
                    }
                }
                // If the element type has changed, log an issue
                else
                {
                    issueLogger.LogBreakingChangeIssue(
                        cmdlet: cmdlet,
                        severity: 0,
                        problemId: ProblemIds.BreakingChangeProblemId.ChangedOutputElementType,
                        description: string.Format(Properties.Resources.ChangedOutputElementTypeDescription,
                                                   oldTypeMetadata.ElementType, newTypeMetadata.ElementType),
                        remediation: string.Format(Properties.Resources.ChangedOutputElementTypeRemediation,
                                                   oldTypeMetadata.ElementType));
                }

                return;
            }

            // Check if the type is a generic
            if (oldTypeMetadata.GenericTypeArguments.Count > 0 && newTypeMetadata.GenericTypeArguments.Count > 0)
            {
                // Check if the generic type has changed
                if (oldTypeMetadata.Name.Equals(newTypeMetadata.Name, StringComparison.OrdinalIgnoreCase))
                {
                    // Check if the number of generic type arguments is the same
                    if (oldTypeMetadata.GenericTypeArguments.Count == newTypeMetadata.GenericTypeArguments.Count)
                    {
                        // For each element in the generic type arguments list, make sure that the types
                        // are the same
                        for (int idx = 0; idx < oldTypeMetadata.GenericTypeArguments.Count; idx++)
                        {
                            if (oldTypeMetadata.GenericTypeArguments[idx].Equals(newTypeMetadata.GenericTypeArguments[idx], StringComparison.OrdinalIgnoreCase))
                            {
                                // If we have not previously seen this generic type argument,
                                // run this method on the type
                                if (!_typeSet.Contains(oldTypeMetadata.GenericTypeArguments[idx]))
                                {
                                    _typeSet.Add(oldTypeMetadata.GenericTypeArguments[idx]);

                                    var oldElementType = _oldTypeDictionary[oldTypeMetadata.GenericTypeArguments[idx]];
                                    var newElementType = _newTypeDictionary[newTypeMetadata.GenericTypeArguments[idx]];

                                    CompareTypeMetadata(cmdlet, oldElementType, newElementType, issueLogger);
                                }
                            }
                            // If the generic type arguments aren't the same, log an issue
                            else
                            {
                                issueLogger.LogBreakingChangeIssue(
                                    cmdlet: cmdlet,
                                    severity: 0,
                                    problemId: ProblemIds.BreakingChangeProblemId.ChangedOutputGenericTypeArgument,
                                    description: string.Format(Properties.Resources.ChangedOutputGenericTypeArgumentDescription,
                                                               oldTypeMetadata.GenericTypeArguments[idx], newTypeMetadata.GenericTypeArguments[idx]),
                                    remediation: string.Format(Properties.Resources.ChangedOutputGenericTypeArgumentRemediation,
                                                               oldTypeMetadata.GenericTypeArguments[idx]));
                            }
                        }
                    }
                    // If the number of generic type arguments is different, log an issue
                    else
                    {
                        issueLogger.LogBreakingChangeIssue(
                            cmdlet: cmdlet,
                            severity: 0,
                            problemId: ProblemIds.BreakingChangeProblemId.DifferentOutputGenericTypeArgumentSize,
                            description: string.Format(Properties.Resources.DifferentOutputGenericTypeArgumentSizeDescription,
                                                       oldTypeMetadata.Name,
                                                       oldTypeMetadata.GenericTypeArguments.Count, newTypeMetadata.GenericTypeArguments.Count),
                            remediation: string.Format(Properties.Resources.DifferentOutputGenericTypeArgumentSizeRemediation,
                                                       oldTypeMetadata.Name, oldTypeMetadata.GenericTypeArguments.Count));
                    }
                }
                // If the generic type has changed, log an issue
                else
                {
                    issueLogger.LogBreakingChangeIssue(
                        cmdlet: cmdlet,
                        severity: 0,
                        problemId: ProblemIds.BreakingChangeProblemId.ChangedOutputGenericType,
                        description: string.Format(Properties.Resources.ChangedOutputGenericTypeDescription,
                                                   oldTypeMetadata.Name, newTypeMetadata.Name),
                        remediation: string.Format(Properties.Resources.ChangedOutputGenericTypeRemediation,
                                                   oldTypeMetadata.Name));
                }

                return;
            }

            CompareTypeMetadata(cmdlet, oldTypeMetadata, newTypeMetadata, issueLogger);
        }
示例#21
0
        /// <summary>
        /// Compare two types by recursively checking their properties and property
        /// types, making sure that nothing has been removed or changed.
        /// </summary>
        /// <param name="cmdlet">The cmdlet metadata currently being checked.</param>
        /// <param name="oldType">The type metadata from the old (serialized) assembly.</param>
        /// <param name="newType">The type metadata from the new assembly.</param>
        /// <param name="issueLogger">ReportLogger that will keep track of issues found.</param>
        public void CompareTypeMetadata(
            CmdletBreakingChangeMetadata cmdlet,
            TypeMetadata oldType,
            TypeMetadata newType,
            ReportLogger <BreakingChangeIssue> issueLogger)
        {
            // For each property in the old assembly type, find the corresponding
            // property in the new assembly type
            foreach (var oldProperty in oldType.Properties.Keys)
            {
                if (newType.Properties.ContainsKey(oldProperty))
                {
                    var oldPropertyType = oldType.Properties[oldProperty];
                    var newPropertyType = newType.Properties[oldProperty];

                    var oldTypeMetadata = _oldTypeDictionary[oldPropertyType];
                    var newTypeMetadata = _newTypeDictionary[newPropertyType];

                    // Define variables for logging
                    int    problemId   = ProblemIds.BreakingChangeProblemId.ChangedElementType;
                    string description = string.Format(Properties.Resources.ChangedElementTypeDescription,
                                                       oldProperty, oldTypeMetadata.ElementType, newTypeMetadata.ElementType);
                    string remediation = string.Format(Properties.Resources.ChangedElementTypeRemediation,
                                                       oldProperty, oldTypeMetadata.ElementType);

                    // If the type is an array, check for any breaking changes
                    if (IsElementType(cmdlet, oldTypeMetadata, newTypeMetadata, problemId, description, remediation, issueLogger))
                    {
                        continue;
                    }

                    string target = string.Format("property {0}", oldProperty);

                    // If the type is a generic, check for any breaking changes
                    if (IsGenericType(cmdlet, oldTypeMetadata, newTypeMetadata, target, issueLogger))
                    {
                        continue;
                    }

                    // If the types are the same, compare their properties
                    if (oldPropertyType.Equals(newPropertyType, StringComparison.OrdinalIgnoreCase))
                    {
                        // If we have not previously seen this type, run this
                        // method on the type
                        if (!_typeSet.Contains(oldPropertyType))
                        {
                            _typeSet.Add(oldPropertyType);

                            CompareTypeMetadata(cmdlet, oldTypeMetadata, newTypeMetadata, issueLogger);
                        }
                    }
                    else
                    {
                        // If the type of the property has been changed, log an issue
                        issueLogger.LogBreakingChangeIssue(
                            cmdlet: cmdlet,
                            severity: 0,
                            problemId: ProblemIds.BreakingChangeProblemId.ChangedPropertyType,
                            description: string.Format(Properties.Resources.ChangedPropertyTypeDescription,
                                                       oldProperty, oldType.Name, oldPropertyType, newPropertyType),
                            remediation: string.Format(Properties.Resources.ChangedPropertyTypeRemediation,
                                                       oldProperty, oldPropertyType));
                    }
                }
                else
                {
                    // If the property has been removed, log an issue
                    issueLogger.LogBreakingChangeIssue(
                        cmdlet: cmdlet,
                        severity: 0,
                        problemId: ProblemIds.BreakingChangeProblemId.RemovedProperty,
                        description: string.Format(Properties.Resources.RemovedPropertyDescription,
                                                   oldProperty, oldType.Name),
                        remediation: string.Format(Properties.Resources.RemovedPropertyRemediation,
                                                   oldProperty, oldType.Name));
                }
            }
        }
        /// <summary>
        /// Get cmdlets from the given assembly
        /// </summary>
        /// <param name="assmeblyPath"></param>
        /// <returns></returns>
        public ModuleMetadata GetModuleMetadata(string assemblyPath)
        {
            List <CmdletBreakingChangeMetadata> results = new List <CmdletBreakingChangeMetadata>();

            ModuleMetadata = new ModuleMetadata();

            try
            {
                var assembly = Assembly.LoadFrom(assemblyPath);
                foreach (var type in assembly.GetCmdletTypes())
                {
                    var cmdlet     = type.GetAttribute <CmdletAttribute>();
                    var outputs    = type.GetAttributes <OutputTypeAttribute>();
                    var parameters = type.GetParameters();

                    var cmdletMetadata = new CmdletBreakingChangeMetadata
                    {
                        VerbName                = cmdlet.VerbName,
                        NounName                = cmdlet.NounName,
                        ConfirmImpact           = cmdlet.ConfirmImpact,
                        SupportsPaging          = cmdlet.SupportsPaging,
                        SupportsShouldProcess   = cmdlet.SupportsShouldProcess,
                        ClassName               = type.FullName,
                        DefaultParameterSetName = cmdlet.DefaultParameterSetName ?? "__AllParameterSets"
                    };

                    if (type.HasAttribute <AliasAttribute>())
                    {
                        var aliases = type.GetAttributes <AliasAttribute>();
                        cmdletMetadata.AliasList.AddRange(
                            aliases.SelectMany(a => a.AliasNames));
                    }

                    foreach (var output in outputs)
                    {
                        foreach (var outputType in output.Type)
                        {
                            var outputMetadata = new OutputMetadata
                            {
                                Type = outputType.Type
                            };
                            outputMetadata.ParameterSets.AddRange(output.ParameterSetName);
                            cmdletMetadata.OutputTypes.Add(outputMetadata);
                        }
                    }

                    List <Parameter> globalParameters = new List <Parameter>();

                    foreach (var parameter in parameters)
                    {
                        var parameterData = new ParameterMetadata
                        {
                            Type = parameter.PropertyType,
                            Name = parameter.Name
                        };

                        if (parameter.HasAttribute <AliasAttribute>())
                        {
                            var aliases = parameter.GetAttributes <AliasAttribute>();
                            parameterData.AliasList.AddRange(
                                aliases.SelectMany(a => a.AliasNames));
                        }

                        if (parameter.HasAttribute <ValidateSetAttribute>())
                        {
                            var validateSet = parameter.GetAttribute <ValidateSetAttribute>();
                            parameterData.ValidateSet.AddRange(validateSet.ValidValues);
                        }

                        if (parameter.HasAttribute <ValidateRangeAttribute>())
                        {
                            var validateRange = parameter.GetAttribute <ValidateRangeAttribute>();
                            parameterData.ValidateRangeMin = Convert.ToInt64(validateRange.MinRange);
                            parameterData.ValidateRangeMax = Convert.ToInt64(validateRange.MaxRange);
                        }

                        parameterData.ValidateNotNullOrEmpty = parameter.HasAttribute <ValidateNotNullOrEmptyAttribute>();

                        cmdletMetadata.Parameters.Add(parameterData);

                        foreach (var parameterSet in parameter.GetAttributes <ParameterAttribute>())
                        {
                            var parameterSetMetadata = cmdletMetadata.ParameterSets.FirstOrDefault(s => s.Name.Equals(parameterSet.ParameterSetName));

                            if (parameterSetMetadata == null)
                            {
                                parameterSetMetadata = new ParameterSetMetadata()
                                {
                                    Name = parameterSet.ParameterSetName ?? "__AllParameterSets"
                                };
                            }

                            Parameter param = new Parameter
                            {
                                ParameterMetadata = parameterData,
                                Mandatory         = parameterSet.Mandatory,
                                Position          = parameterSet.Position,
                                ValueFromPipeline = parameterSet.ValueFromPipeline,
                                ValueFromPipelineByPropertyName = parameterSet.ValueFromPipelineByPropertyName
                            };

                            if (parameterSet.ParameterSetName.Equals("__AllParameterSets"))
                            {
                                globalParameters.Add(param);
                            }

                            parameterSetMetadata.Parameters.Add(param);

                            if (parameterSetMetadata.Parameters.Count == 1)
                            {
                                cmdletMetadata.ParameterSets.Add(parameterSetMetadata);
                            }
                        }
                    }

                    foreach (var parameterSet in cmdletMetadata.ParameterSets)
                    {
                        if (parameterSet.Name.Equals("__AllParameterSets"))
                        {
                            continue;
                        }

                        foreach (var parameter in globalParameters)
                        {
                            var param = parameterSet.Parameters.FirstOrDefault(p => p.ParameterMetadata.Name.Equals(parameter.ParameterMetadata.Name));
                            if (param == null)
                            {
                                parameterSet.Parameters.Add(parameter);
                            }
                        }
                    }

                    if (cmdletMetadata.ParameterSets.Count == 0)
                    {
                        ParameterSetMetadata defaultSet = new ParameterSetMetadata()
                        {
                            Name = cmdletMetadata.DefaultParameterSetName
                        };
                        cmdletMetadata.ParameterSets.Add(defaultSet);
                    }

                    results.Add(cmdletMetadata);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

            ModuleMetadata.Cmdlets = results;
            return(ModuleMetadata);
        }