Exemple #1
0
        /// <summary>
        /// Serialize the cmdlets so they can be compared to change modules later
        /// </summary>
        /// <param name="fileName">Name of the file cmdlets are being serialized to.</param>
        /// <param name="cmdlets">List of cmdlets that are to be serialized.</param>
        private void SerializeCmdlets(string fileName, ModuleMetadata moduleMetadata)
        {
            var json = JsonConvert.SerializeObject(moduleMetadata, Formatting.Indented);

            File.WriteAllText(fileName, json);
        }
        /// <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);
        }
Exemple #3
0
        /// <summary>
        /// Given a set of directory paths containing PowerShell module folders,
        /// analyze the breaking changes in the modules and report any issues
        ///
        /// Filters can be added to find breaking changes for specific modules
        /// </summary>
        /// <param name="cmdletProbingDirs">Set of directory paths containing PowerShell module folders to be checked for breaking changes.</param>
        /// <param name="directoryFilter">Function that filters the directory paths to be checked.</param>
        /// <param name="cmdletFilter">Function that filters the cmdlets to be checked.</param>
        public void Analyze(
            IEnumerable <string> cmdletProbingDirs,
            Func <IEnumerable <string>, IEnumerable <string> > directoryFilter,
            Func <string, bool> cmdletFilter,
            IEnumerable <string> modulesToAnalyze)
        {
            var processedHelpFiles = new List <string>();
            var issueLogger        = Logger.CreateLogger <BreakingChangeIssue>("BreakingChangeIssues.csv");

            if (directoryFilter != null)
            {
                cmdletProbingDirs = directoryFilter(cmdletProbingDirs);
            }

            foreach (var baseDirectory in cmdletProbingDirs.Where(s => !s.Contains("ServiceManagement") &&
                                                                  !ModuleFilter.IsAzureStackModule(s) && Directory.Exists(Path.GetFullPath(s))))
            {
                SharedAssemblyLoader.Load(baseDirectory);
                var probingDirectories = new List <string> {
                    baseDirectory
                };

                // Add current directory for probing
                probingDirectories.AddRange(Directory.EnumerateDirectories(Path.GetFullPath(baseDirectory)));

                foreach (var directory in probingDirectories)
                {
                    if (modulesToAnalyze != null &&
                        modulesToAnalyze.Any() &&
                        !modulesToAnalyze.Any(m => directory.EndsWith(m)))
                    {
                        continue;
                    }

                    var service = Path.GetFileName(directory);

                    var manifestFiles = Directory.EnumerateFiles(directory, "*.psd1").ToList();

                    if (manifestFiles.Count > 1)
                    {
                        manifestFiles = manifestFiles.Where(f => Path.GetFileName(f).IndexOf(service) >= 0).ToList();
                    }

                    if (manifestFiles.Count == 0)
                    {
                        continue;
                    }

                    var psd1            = manifestFiles.FirstOrDefault();
                    var parentDirectory = Directory.GetParent(psd1).FullName;
                    var psd1FileName    = Path.GetFileName(psd1);

                    string moduleName = psd1FileName.Replace(".psd1", "");

                    Console.WriteLine(directory);
                    Directory.SetCurrentDirectory(directory);

                    issueLogger.Decorator.AddDecorator(a => a.AssemblyFileName = moduleName, "AssemblyFileName");
                    processedHelpFiles.Add(moduleName);

                    var newModuleMetadata = MetadataLoader.GetModuleMetadata(moduleName);
                    var fileName          = $"{moduleName}.json";
                    var executingPath     = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).AbsolutePath);

                    var filePath = Path.Combine(executingPath, "SerializedCmdlets", fileName);

                    if (!File.Exists(filePath))
                    {
                        continue;
                    }

                    var oldModuleMetadata = ModuleMetadata.DeserializeCmdlets(filePath);

                    if (cmdletFilter != null)
                    {
                        var output = string.Format("Before filter\nOld module cmdlet count: {0}\nNew module cmdlet count: {1}",
                                                   oldModuleMetadata.Cmdlets.Count, newModuleMetadata.Cmdlets.Count);

                        output += string.Format("\nCmdlet file: {0}", moduleName);

                        oldModuleMetadata.FilterCmdlets(cmdletFilter);
                        newModuleMetadata.FilterCmdlets(cmdletFilter);

                        output += string.Format("After filter\nOld module cmdlet count: {0}\nNew module cmdlet count: {1}",
                                                oldModuleMetadata.Cmdlets.Count, newModuleMetadata.Cmdlets.Count);

                        foreach (var cmdlet in oldModuleMetadata.Cmdlets)
                        {
                            output += string.Format("\n\tOld cmdlet - {0}", cmdlet.Name);
                        }

                        foreach (var cmdlet in newModuleMetadata.Cmdlets)
                        {
                            output += string.Format("\n\tNew cmdlet - {0}", cmdlet.Name);
                        }

                        issueLogger.WriteMessage(output + Environment.NewLine);
                    }

                    RunBreakingChangeChecks(oldModuleMetadata, newModuleMetadata, issueLogger);
                }
            }
        }
        public TypeMetadata(Type inputType)
        {
            Namespace             = inputType.Namespace;
            Name                  = inputType.Name;
            AssemblyQualifiedName = inputType.AssemblyQualifiedName;

            // Get the properties of the type
            var properties = inputType.GetProperties();

            // Sort the properties by name to retain ordering when loading cmdlets
            Array.Sort(properties, delegate(PropertyInfo p1, PropertyInfo p2)
            {
                return(p1.Name.CompareTo(p2.Name));
            });

            ModuleMetadata moduleMetadata = CmdletBreakingChangeLoader.ModuleMetadata;

            // If the type is an array
            if (inputType.HasElementType)
            {
                // Get the element type of the array
                ElementType = inputType.GetElementType().ToString();

                // If the element type is not in the type dictionary,
                // add it and check its properties
                if (!moduleMetadata.TypeDictionary.ContainsKey(ElementType))
                {
                    moduleMetadata.TypeDictionary.Add(ElementType, null);
                    var typeMetadata = new TypeMetadata(inputType.GetElementType());
                    moduleMetadata.TypeDictionary[ElementType] = typeMetadata;
                }

                return;
            }

            // If the type is a generic
            if (inputType.IsGenericType)
            {
                // Get the generic type name
                Name = inputType.Name.Substring(0, inputType.Name.IndexOf('`'));

                // Get the argument types
                var genericTypeArguments = inputType.GetGenericArguments();

                // For each of the arguments, add them to the list of arguments
                // and check if the type is in the type dictionary
                foreach (var arg in genericTypeArguments)
                {
                    _genericTypeArguments.Add(arg.ToString());

                    if (!moduleMetadata.TypeDictionary.ContainsKey(arg.ToString()))
                    {
                        moduleMetadata.TypeDictionary.Add(arg.ToString(), null);
                        var typeMetadata = new TypeMetadata(arg);
                        moduleMetadata.TypeDictionary[arg.ToString()] = typeMetadata;
                    }
                }

                return;
            }

            // If the type is in the System namespace, don't look at any of its properties
            if (Namespace.StartsWith("System"))
            {
                return;
            }

            // For each property, check to see if we have already processed its type before,
            // and if not, we will add it to the global dictionary and process the TypeMetadata.
            foreach (var property in properties)
            {
                // Get the property type
                var propertyType = property.PropertyType;

                // If the type has not been seen before, we will map it to a null value in the
                // global dictionary so we don't repeat the computation, and then create the
                // TypeMetadata object associated with it, and finally set it as the value
                // associated with the type name key in the dictionary.
                if (!moduleMetadata.TypeDictionary.ContainsKey(propertyType.ToString()))
                {
                    moduleMetadata.TypeDictionary.Add(propertyType.ToString(), null);
                    var typeMetadata = new TypeMetadata(propertyType);
                    moduleMetadata.TypeDictionary[propertyType.ToString()] = typeMetadata;
                }

                // Add the property to the dictionary
                if (!_properties.ContainsKey(property.Name))
                {
                    _properties.Add(property.Name, propertyType.ToString());
                }
            }
        }