public async Task <List <RepositoryDependency> > ReadAsync(string owner, string name, string branch, DateTime?asOf)
        {
            var dependencies = new List <RepositoryDependency>();

            var files = await repositorySourceManager.ReadFilesAsync(owner, name, branch, asOf).ConfigureAwait(false);

            var packageJsonFiles = files.Where(file => file.Name == "package.json");

            if (packageJsonFiles != null)
            {
                foreach (var packageJsonFile in packageJsonFiles)
                {
                    var packageJsonContent = await repositorySourceManager.ReadFileContentAsync(owner, name, branch, packageJsonFile.FullPath, asOf).ConfigureAwait(false);

                    JObject jObject = null;
                    try
                    {
                        jObject = JObject.Parse(packageJsonContent);
                    }
                    catch (Exception ex)
                    {
                        var exceptionMessage = $"Error parsing JSON from {owner} - {name} - {packageJsonFile.FullPath}";
                        throw new ArgumentException(exceptionMessage, ex);
                    }

                    var npmProdDependencies = jObject["dependencies"];

                    if (npmProdDependencies != null)
                    {
                        foreach (var token in npmProdDependencies)
                        {
                            var property = token as JProperty;

                            var dependency = new RepositoryDependency();
                            dependency.Environment = "Production";
                            dependency.Source      = "npm";
                            dependency.Name        = property.Name;
                            var cleansedVersionMatch = Regex.Match(property.Value.ToString(), @"[\d\.]+");
                            dependency.Version      = cleansedVersionMatch.Value;
                            dependency.MajorVersion = Regex.Match(dependency.Version, @"\d+").Value;

                            dependencies.Add(dependency);
                        }
                    }

                    var npmDevDependencies = jObject["devDependencies"];


                    if (npmDevDependencies != null)
                    {
                        foreach (var token in npmDevDependencies)
                        {
                            var property = token as JProperty;

                            var dependency = new RepositoryDependency();
                            dependency.Environment = "Development";
                            dependency.Source      = "npm";
                            dependency.Name        = property.Name;
                            var cleansedVersionMatch = Regex.Match(property.Value.ToString(), @"[\d\.]+");
                            dependency.Version      = cleansedVersionMatch.Value;
                            dependency.MajorVersion = Regex.Match(dependency.Version, @"\d+").Value;

                            dependencies.Add(dependency);
                        }
                    }
                }
            }

            return(dependencies);
        }
Ejemplo n.º 2
0
        public async Task <List <RepositoryDependency> > ReadAsync(string owner, string name, string branch, DateTime?asOf)
        {
            var dependencies = new List <RepositoryDependency>();

            var files = await repositorySourceManager.ReadFilesAsync(owner, name, branch, asOf).ConfigureAwait(false);

            // Check for .NET framework NuGet packages
            var packageConfigFiles = files.Where(file => file.Name == "packages.config");

            if (packageConfigFiles != null)
            {
                foreach (var packageConfigFile in packageConfigFiles)
                {
                    var packageConfigContent = await repositorySourceManager.ReadFileContentAsync(owner, name, branch, packageConfigFile.FullPath, asOf).ConfigureAwait(false);

                    if (!string.IsNullOrWhiteSpace(packageConfigContent))
                    {
                        string byteOrderMarkUtf8 = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
                        if (packageConfigContent.StartsWith(byteOrderMarkUtf8))
                        {
                            packageConfigContent = packageConfigContent.Remove(0, byteOrderMarkUtf8.Length);

                            // For some reason removing the UTF preamble sometimes removes the first XML character
                            if (!packageConfigContent.StartsWith("<"))
                            {
                                packageConfigContent = $"<{packageConfigContent}";
                            }
                        }

                        var xdoc = XDocument.Parse(packageConfigContent);

                        foreach (var descendant in xdoc.Elements().First().Descendants())
                        {
                            var dependency = new RepositoryDependency();

                            dependency.RepoPath = packageConfigFile.FullPath;
                            dependency.Source   = "NuGet";
                            dependency.Name     = descendant.Attribute("id").Value;
                            var versionString = descendant.Attribute("version").Value;

                            var preReleaseSemanticVersionMatch = Regex.Match(versionString, @"-.*?\Z");

                            if (preReleaseSemanticVersionMatch.Success)
                            {
                                versionString = versionString.TrimEnd(preReleaseSemanticVersionMatch.Value.ToCharArray());
                                dependency.PreReleaseSemanticVersion = preReleaseSemanticVersionMatch.Value.TrimStart('-');
                            }

                            dependency.Version      = versionString;
                            dependency.MajorVersion = Regex.Match(dependency.Version, @"\d+").Value;

                            dependencies.Add(dependency);
                        }
                    }
                }
            }

            // Check for Nuget packaes defined in project files from .NET Standard/Core projects OR from .NET Standard/Framework
            // dual targeted projects
            var dotNetProjectFiles = files.Where(file => file.Name.EndsWith(".csproj") || file.Name.EndsWith(".vbproj"));

            if (dotNetProjectFiles != null && dotNetProjectFiles.Any())
            {
                foreach (var dotNetProjectFile in dotNetProjectFiles)
                {
                    var projectFileContent = await repositorySourceManager.ReadFileContentAsync(owner, name, branch, dotNetProjectFile.FullPath, asOf).ConfigureAwait(false);

                    if (!string.IsNullOrWhiteSpace(projectFileContent))
                    {
                        string byteOrderMarkUtf8 = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
                        if (projectFileContent.StartsWith(byteOrderMarkUtf8))
                        {
                            projectFileContent = projectFileContent.Remove(0, byteOrderMarkUtf8.Length);

                            // For some reason removing the UTF preamble sometimes removes the first XML character
                            if (!projectFileContent.StartsWith("<"))
                            {
                                projectFileContent = $"<{projectFileContent}";
                            }
                        }

                        var xDoc = XDocument.Parse(projectFileContent);

                        var packageReferenceElements = xDoc.Descendants().Where(descendant => descendant.Name.LocalName == "PackageReference");

                        if (packageReferenceElements != null)
                        {
                            foreach (var packageReferenceElement in packageReferenceElements)
                            {
                                var dependency = new RepositoryDependency();

                                dependency.RepoPath = dotNetProjectFile.FullPath;
                                dependency.Source   = "NuGet";
                                dependency.Name     = packageReferenceElement.FirstAttribute.Value;

                                string versionString = null;

                                // Figure out if this is a refernce from a .NET Standard/Core project file
                                if (packageReferenceElement.Attributes().Count() == 2 && packageReferenceElement.LastAttribute.Name == "Version")
                                {
                                    versionString = packageReferenceElement.LastAttribute.Value;
                                }
                                // Figure out if this is a refernce from a .NET Framework project file that has been dual targeted with .NET standard
                                else if (packageReferenceElement.Attributes().Count() == 1 && packageReferenceElement.HasElements && packageReferenceElement.Elements().First().Name.LocalName == "Version")
                                {
                                    versionString = packageReferenceElement.Elements().First().Value;
                                }

                                dependency.Version = versionString;

                                // Some project dependencies like "Microsoft.AspNetCore.App" do not have version elements
                                // TODO: Move this parsing logic in to the dependency manager class maybe?
                                if (dependency.Version != null)
                                {
                                    var preReleaseSemanticVersionMatch = Regex.Match(versionString, @"-.*?\Z");

                                    if (preReleaseSemanticVersionMatch.Success)
                                    {
                                        versionString = versionString.TrimEnd(preReleaseSemanticVersionMatch.Value.ToCharArray());
                                        dependency.PreReleaseSemanticVersion = preReleaseSemanticVersionMatch.Value.TrimStart('-');
                                    }

                                    dependency.MajorVersion = Regex.Match(dependency.Version, @"\d+").Value;
                                }

                                dependencies.Add(dependency);
                            }
                        }
                    }
                }
            }

            return(dependencies);
        }
        public async Task CreateAsync(RepositoryAnalysis repositoryAnalysis)
        {
            var parsedRepoUrl = ParseRepositoryUrl();

            // maybe change the name of this var to reflect how it's different than the repositoryAnalysis.repsoitoryId?
            var repositoryId = $"{parsedRepoUrl.Host}|{parsedRepoUrl.Owner}|{parsedRepoUrl.Name}";

            var repository = await repositoryManager.ReadAsync(repositoryId, repositoryAnalysis.AsOf).ConfigureAwait(false);

            DateTime?repositoryLastUpdatedOn = null;

            // If a last updated time for the repo was provided, use that to hopefully save an API call
            if (repositoryAnalysis.RepositoryLastUpdatedOn.HasValue)
            {
                repositoryLastUpdatedOn = repositoryAnalysis.RepositoryLastUpdatedOn.Value;
            }
            else
            {
                var repositorySummary = await repositorySourceManager.ReadRepositorySummaryAsync(parsedRepoUrl.Owner, parsedRepoUrl.Name).ConfigureAwait(false);

                repositoryLastUpdatedOn = repositorySummary.UpdatedAt;
            }

            if (repositoryAnalysis.ForceCompleteRefresh || repository == null || repositoryLastUpdatedOn > repository.CurrentState.RepositoryLastUpdatedOn)
            {
                // Do repository summary call to get the commit Id of the latest commit and the date that commit was pushed for the snapshot
                // populate the snapshot date with the corresponding manager calls (E.G. ScrapeDependenciesAsync)
                // Do full repository read to get all the current state stuff (including calls to get derived data like devops integrations)
                var sourceRepository = await repositorySourceManager.ReadRepositoryAsync(parsedRepoUrl.Owner, parsedRepoUrl.Name).ConfigureAwait(false);

                var repositoryCurrentState = new RepositoryCurrentState();
                repositoryCurrentState.Id                      = repositoryId;
                repositoryCurrentState.Name                    = sourceRepository.Name;
                repositoryCurrentState.Owner                   = parsedRepoUrl.Owner;
                repositoryCurrentState.DefaultBranch           = sourceRepository.DefaultBranchName;
                repositoryCurrentState.HasIssues               = sourceRepository.IssueCount > 0;
                repositoryCurrentState.HasProjects             = sourceRepository.ProjectCount > 0;
                repositoryCurrentState.HasPullRequests         = sourceRepository.PullRequestCount > 0;
                repositoryCurrentState.RepositoryCreatedOn     = sourceRepository.CreatedAt;
                repositoryCurrentState.RepositoryLastUpdatedOn = sourceRepository.PushedAt;

                repositoryCurrentState.Teams  = sourceRepository.Teams;
                repositoryCurrentState.Topics = sourceRepository.TopicNames?.Select(name => new RepositoryTopic {
                    Name = name
                }).ToList();
                repositoryCurrentState.DevOpsIntegrations = await ScrapeDevOpsIntegrations(repositoryCurrentState.Name).ConfigureAwait(false);

                // Need to pick a branch for the snapshot stuff
                string branchName = null;

                if (sourceRepository.BranchNames.Contains("master"))
                {
                    branchName = "master";
                }
                else if (sourceRepository.BranchNames.Contains("development"))
                {
                    branchName = "development";
                }
                else if (!string.IsNullOrWhiteSpace(sourceRepository.DefaultBranchName))
                {
                    branchName = sourceRepository.DefaultBranchName;
                }

                RepositorySnapshot repositorySnapshot = null;
                repositorySnapshot = new RepositorySnapshot();
                // Have to set the windows in the manager
                repositorySnapshot.RepositoryCurrentStateRepositoryId = repositoryCurrentState.Id;
                repositorySnapshot.TakenOn    = DateTime.Now;
                repositorySnapshot.BranchUsed = branchName;

                if (branchName != null)
                {
                    repositorySnapshot.Dependencies = await ScrapeDependenciesAsync(parsedRepoUrl.Owner, parsedRepoUrl.Name, branchName, repositoryAnalysis.AsOf).ConfigureAwait(false);

                    repositorySnapshot.Files = await repositorySourceManager.ReadFilesAsync(parsedRepoUrl.Owner, parsedRepoUrl.Name, branchName, repositoryAnalysis.AsOf).ConfigureAwait(false);
                }
                else
                {
                    repositorySnapshot.Dependencies = new List <RepositoryDependency>();
                    repositorySnapshot.Files        = new List <RepositoryFile>();
                }

                repositorySnapshot.TypesAndImplementations = await ScrapeRepositoryTypeAndImplementation(
                    parsedRepoUrl.Name,
                    repositorySnapshot.Files,
                    repositorySnapshot.Dependencies,
                    repositoryCurrentState.Topics?.Select(topic => topic.Name),
                    new BacklogInfo { HasIssues = repositoryCurrentState.HasIssues ?? false },
                    repositoryAnalysis.AsOf).ConfigureAwait(false);

                var updatedRepository = new Repository
                {
                    CurrentState = repositoryCurrentState,
                    Snapshot     = repositorySnapshot
                };

                await repositoryManager.UpsertAsync(updatedRepository, repositoryAnalysis.AsOf).ConfigureAwait(false);
            }

            (string Owner, string Name, string Host) ParseRepositoryUrl()
            {
                var repositoryUri = new Uri(repositoryAnalysis.RepositoryId);
                var owner         = repositoryUri.Segments[1].TrimEnd('/');
                var name          = repositoryUri.Segments[2].TrimEnd('/');
                var host          = repositoryUri.Host;

                return(owner, name, host);
            }
        }
Ejemplo n.º 4
0
        public async Task <List <RepositoryDependency> > ReadAsync(string owner, string name, string branch, DateTime?asOf)
        {
            var dependencies = new List <RepositoryDependency>();

            var files = await repositorySourceManager.ReadFilesAsync(owner, name, branch, asOf).ConfigureAwait(false);

            var dotNetProjectFiles = files.Where(file => file.Name.EndsWith(".csproj") || file.Name.EndsWith(".vbproj"));

            if (dotNetProjectFiles != null && dotNetProjectFiles.Any())
            {
                foreach (var dotNetProjectFile in dotNetProjectFiles)
                {
                    var projectFileContent = await this.repositorySourceManager.ReadFileContentAsync(owner, name, branch, dotNetProjectFile.FullPath, asOf).ConfigureAwait(false);

                    if (!string.IsNullOrWhiteSpace(projectFileContent))
                    {
                        string byteOrderMarkUtf8 = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
                        if (projectFileContent.StartsWith(byteOrderMarkUtf8))
                        {
                            projectFileContent = projectFileContent.Remove(0, byteOrderMarkUtf8.Length);

                            // For some reason removing the UTF preamble sometimes removes the first XML character
                            if (!projectFileContent.StartsWith("<"))
                            {
                                projectFileContent = $"<{projectFileContent}";
                            }
                        }

                        var xDoc = XDocument.Parse(projectFileContent);

                        // Look for a .NET framework element
                        var targetFrameworkVersionElement = xDoc.Descendants().FirstOrDefault(descendant => descendant.Name.LocalName == "TargetFrameworkVersion");

                        if (targetFrameworkVersionElement != null)
                        {
                            var dotNetFrameworkVersion = targetFrameworkVersionElement.Value.TrimStart('v');

                            var dotNetFrameworkDependency = new RepositoryDependency();
                            dotNetFrameworkDependency.Name         = ".NET Framework";
                            dotNetFrameworkDependency.Version      = dotNetFrameworkVersion;
                            dotNetFrameworkDependency.MajorVersion = Regex.Match(dotNetFrameworkDependency.Version, @"\d+").Value;
                            dotNetFrameworkDependency.Environment  = "Production";
                            dotNetFrameworkDependency.Source       = "Visual Studio Project File";
                            dotNetFrameworkDependency.RepoPath     = dotNetProjectFile.FullPath;

                            dependencies.Add(dotNetFrameworkDependency);
                        }
                        else
                        {
                            // Look for a .NET core / standard element
                            var targetFrameworkElement = xDoc.Descendants().FirstOrDefault(descendant => descendant.Name.LocalName == "TargetFramework");

                            if (targetFrameworkElement != null)
                            {
                                // AFAIK only these two names are used in this element
                                //netstandard
                                //netcoreapp

                                var match = Regex.Match(targetFrameworkElement.Value, @"([A-z]+)([\d|\.]+)");

                                var appType = match.Groups[1].Value;
                                var version = match.Groups[2].Value;

                                var netCoreStandardDependency = new RepositoryDependency();
                                if (appType.ToLower() == "netstandard")
                                {
                                    netCoreStandardDependency.Name = ".NET Standard";
                                }
                                else if (appType.ToLower() == "netcoreapp")
                                {
                                    netCoreStandardDependency.Name = ".NET Core";
                                }
                                else
                                {
                                    throw new ArgumentException($"Unrecognized .NET application type of {appType}");
                                }

                                netCoreStandardDependency.Version      = version;
                                netCoreStandardDependency.MajorVersion = Regex.Match(netCoreStandardDependency.Version, @"\d+").Value;
                                netCoreStandardDependency.Source       = "Visual Studio Project File";
                                netCoreStandardDependency.RepoPath     = dotNetProjectFile.FullPath;

                                dependencies.Add(netCoreStandardDependency);
                            }
                        }
                    }
                }
            }

            return(dependencies);
        }
Ejemplo n.º 5
0
        public async Task <List <RepositoryDependency> > ReadAsync(string owner, string name, string branch, DateTime?asOf)
        {
            var dependencies = new List <RepositoryDependency>();

            var files = await repositorySourceManager.ReadFilesAsync(owner, name, branch, asOf).ConfigureAwait(false);

            var mavenFiles = files.Where(file => file.Name == "pom.xml");

            if (mavenFiles != null)
            {
                foreach (var mavenFile in mavenFiles)
                {
                    var mavenFileContent = await repositorySourceManager.ReadFileContentAsync(owner, name, branch, mavenFile.FullPath, asOf).ConfigureAwait(false);

                    if (!string.IsNullOrWhiteSpace(mavenFileContent))
                    {
                        string byteOrderMarkUtf8 = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
                        if (mavenFileContent.StartsWith(byteOrderMarkUtf8))
                        {
                            mavenFileContent = mavenFileContent.Remove(0, byteOrderMarkUtf8.Length);

                            // For some reason removing the UTF preamble sometimes removes the first XML character
                            if (!mavenFileContent.StartsWith("<"))
                            {
                                mavenFileContent = $"<{mavenFileContent}";
                            }
                        }

                        var xDoc = XDocument.Parse(mavenFileContent);

                        var propertiesElement        = xDoc.Descendants().FirstOrDefault(descendant => descendant.Name.LocalName == "properties");
                        var propertiesNameToValueMap = new Dictionary <string, string>();

                        if (propertiesElement != null)
                        {
                            foreach (var propertyElement in propertiesElement.Elements())
                            {
                                propertiesNameToValueMap.Add(propertyElement.Name.LocalName, propertyElement.Value);
                            }

                            // Replace any property names in the property values
                            foreach (var key in propertiesNameToValueMap.Keys.ToList())
                            {
                                var value = propertiesNameToValueMap[key];

                                var match = Regex.Match(value, @"\${(.*)}");

                                if (match.Success)
                                {
                                    propertiesNameToValueMap[key] = Regex.Replace(value, @"\${.*}", propertiesNameToValueMap[match.Groups[1].Value]);
                                }
                            }
                        }

                        var dependencyElements = xDoc.Descendants().Where(descendant => descendant.Name.LocalName == "dependency");

                        foreach (var dependencyElement in dependencyElements)
                        {
                            var repositoryDependency = new RepositoryDependency();

                            repositoryDependency.Name = dependencyElement.Elements().First(element => element.Name.LocalName == "artifactId").Value;

                            var match = Regex.Match(repositoryDependency.Name, @"\${(.*)}");

                            if (match.Success)
                            {
                                var propertyName = match.Groups[1].Value;
                                repositoryDependency.Name = Regex.Replace(repositoryDependency.Name, @"\${.*}", propertiesNameToValueMap[propertyName]);
                            }

                            repositoryDependency.Version = dependencyElement.Elements().First(element => element.Name.LocalName == "version").Value;

                            match = Regex.Match(repositoryDependency.Version, @"\${(.*)}");

                            if (match.Success)
                            {
                                var propertyName = match.Groups[1].Value;
                                repositoryDependency.Version = Regex.Replace(repositoryDependency.Version, @"\${.*}", propertiesNameToValueMap[propertyName]);
                            }

                            repositoryDependency.MajorVersion = Regex.Match(repositoryDependency.Version, @"\A\d+").Value;
                            repositoryDependency.RepoPath     = mavenFile.FullPath;
                            repositoryDependency.Source       = "Maven";

                            if (!dependencies.Any(
                                    dependency => dependency.Name == repositoryDependency.Name &&
                                    dependency.Version == repositoryDependency.Version &&
                                    dependency.RepoPath == repositoryDependency.RepoPath))
                            {
                                dependencies.Add(repositoryDependency);
                            }
                        }
                    }
                }
            }

            return(dependencies);
        }