예제 #1
0
        public void SuccessfulDotNetRunnerExecution_ReturnsDependencyGraph()
        {
            var mockFileSystem = new MockFileSystem(new Dictionary <string, MockFileData>());

            // Arrange
            var dotNetRunner = new Mock <IDotNetRunner>();

            dotNetRunner.Setup(runner => runner.Run(It.IsAny <string>(), It.IsAny <string[]>()))
            .Returns(new RunStatus(string.Empty, string.Empty, 0))
            .Callback((string directory, string[] arguments) =>
            {
                // Grab the temp filename that was passed...
                string tempFileName = arguments[3].Replace("/p:RestoreGraphOutputPath=", string.Empty).Trim('"');

                // ... and stuff it with our dummy dependency graph
                mockFileSystem.AddFileFromEmbeddedResource(tempFileName, GetType().Assembly, "DotNetOutdated.Tests.TestData.test.dg");
            });

            var graphService = new DependencyGraphService(dotNetRunner.Object, mockFileSystem);

            // Act
            var dependencyGraph = graphService.GenerateDependencyGraph(Path);

            // Assert
            Assert.NotNull(dependencyGraph);
        }
        public void EmptySolution_ReturnsEmptyDependencyGraph()
        {
            var mockFileSystem = new MockFileSystem(new Dictionary <string, MockFileData>());

            // Arrange
            var dotNetRunner = new Mock <IDotNetRunner>();

            dotNetRunner.Setup(runner => runner.Run(It.IsAny <string>(), It.Is <string[]>(a => a[0] == "msbuild" && a[2] == "/t:Restore,GenerateRestoreGraphFile")))
            .Returns(new RunStatus(string.Empty, string.Empty, 0))
            .Callback((string directory, string[] arguments) =>
            {
                // Grab the temp filename that was passed...
                string tempFileName = arguments[3].Replace("/p:RestoreGraphOutputPath=", string.Empty).Trim('"');

                // ... and stuff it with our dummy dependency graph
                mockFileSystem.AddFileFromEmbeddedResource(tempFileName, GetType().Assembly, "DotNetOutdated.Tests.TestData.empty.dg");
            });;

            var graphService = new DependencyGraphService(dotNetRunner.Object, mockFileSystem);

            // Act
            var dependencyGraph = graphService.GenerateDependencyGraph(_solutionPath);

            // Assert
            Assert.NotNull(dependencyGraph);
            Assert.Equal(0, dependencyGraph.Projects.Count);

            dotNetRunner.Verify(runner => runner.Run(_path, It.Is <string[]>(a => a[0] == "msbuild" && a[1] == '\"' + _solutionPath + '\"' && a[2] == "/t:Restore,GenerateRestoreGraphFile")));
        }
예제 #3
0
        public void UnsuccessfulDotNetRunnerExecution_Throws()
        {
            var mockFileSystem = new MockFileSystem(new Dictionary <string, MockFileData>());

            // Arrange
            var dotNetRunner = new Mock <IDotNetRunner>();

            dotNetRunner.Setup(runner => runner.Run(It.IsAny <string>(), It.IsAny <string[]>()))
            .Returns(new RunStatus(string.Empty, string.Empty, 1));

            var graphService = new DependencyGraphService(dotNetRunner.Object, mockFileSystem);

            // Assert
            Assert.Throws <CommandValidationException>(() => graphService.GenerateDependencyGraph(Path));
        }
예제 #4
0
        public void UnsuccessfulDotNetRunnerExecution_ReturnsNull()
        {
            var mockFileSystem = new MockFileSystem(new Dictionary <string, MockFileData>());

            // Arrange
            var dotNetRunner = new Mock <IDotNetRunner>();

            dotNetRunner.Setup(runner => runner.Run(It.IsAny <string>(), It.IsAny <string[]>()))
            .Returns(new RunStatus(string.Empty, string.Empty, 1));

            var graphService = new DependencyGraphService(dotNetRunner.Object, mockFileSystem);

            // Act
            var dependencyGraph = graphService.GenerateDependencyGraph(Path);

            // Assert
            Assert.Null(dependencyGraph);
        }
        public void SolutionPath_ReturnsDependencyGraphForAllProjects()
        {
            var mockFileSystem = new MockFileSystem(new Dictionary <string, MockFileData>());

            // Arrange
            var dotNetRunner = new Mock <IDotNetRunner>();

            string solutionProjects = string.Join(Environment.NewLine, "Project(s)", "-----------", _project1Path, _project2Path);

            dotNetRunner.Setup(runner => runner.Run(It.IsAny <string>(), It.Is <string[]>(a => a[0] == "sln")))
            .Returns(new RunStatus(solutionProjects, string.Empty, 0));

            dotNetRunner.Setup(runner => runner.Run(It.IsAny <string>(), It.Is <string[]>(a => a[0] == "msbuild")))
            .Returns(new RunStatus(string.Empty, string.Empty, 0))
            .Callback((string directory, string[] arguments) =>
            {
                // Grab the temp filename that was passed...
                string tempFileName = arguments[3].Replace("/p:RestoreGraphOutputPath=", string.Empty).Trim('"');

                // ... and stuff it with our dummy dependency graph
                string dependencyGraphFile = arguments[1] == '\"' + _project1Path + '\"' ? "test.dg" : "empty.dg";
                mockFileSystem.AddFileFromEmbeddedResource(tempFileName, GetType().Assembly, "DotNetOutdated.Tests.TestData." + dependencyGraphFile);
            });

            mockFileSystem.AddFileFromEmbeddedResource(_project1Path, GetType().Assembly, "DotNetOutdated.Tests.TestData.MicrosoftSdk.xml");
            mockFileSystem.AddFileFromEmbeddedResource(_project2Path, GetType().Assembly, "DotNetOutdated.Tests.TestData.MicrosoftSdk.xml");

            var graphService = new DependencyGraphService(dotNetRunner.Object, mockFileSystem);

            // Act
            var dependencyGraph = graphService.GenerateDependencyGraph(_solutionPath);

            // Assert
            Assert.NotNull(dependencyGraph);
            Assert.Equal(4, dependencyGraph.Projects.Count);

            dotNetRunner.Verify(runner => runner.Run(_path, It.Is <string[]>(a => a[0] == "sln" && a[2] == "list" && a[1] == '\"' + _solutionPath + '\"')));
            dotNetRunner.Verify(runner => runner.Run(XFS.Path(@"c:\path\proj1"), It.Is <string[]>(a => a[0] == "msbuild" && a[1] == '\"' + _project1Path + '\"')));
            dotNetRunner.Verify(runner => runner.Run(XFS.Path(@"c:\path\proj2"), It.Is <string[]>(a => a[0] == "msbuild" && a[1] == '\"' + _project2Path + '\"')));
        }
        public void EmptySolution_ReturnsEmptyDependencyGraph()
        {
            var mockFileSystem = new MockFileSystem(new Dictionary <string, MockFileData>());

            // Arrange
            var dotNetRunner = new Mock <IDotNetRunner>();

            string solutionProjects = string.Join(Environment.NewLine, "Project(s)", "-----------");

            dotNetRunner.Setup(runner => runner.Run(It.IsAny <string>(), It.Is <string[]>(a => a[0] == "sln")))
            .Returns(new RunStatus(solutionProjects, string.Empty, 0));

            var graphService = new DependencyGraphService(dotNetRunner.Object, mockFileSystem);

            // Act
            var dependencyGraph = graphService.GenerateDependencyGraph(_solutionPath);

            // Assert
            Assert.NotNull(dependencyGraph);
            Assert.Equal(0, dependencyGraph.Projects.Count);

            dotNetRunner.Verify(runner => runner.Run(_path, It.Is <string[]>(a => a[0] == "sln" && a[2] == "list" && a[1] == '\"' + _solutionPath + '\"')));
            dotNetRunner.Verify(runner => runner.Run(It.IsAny <string>(), It.Is <string[]>(a => a[0] == "msbuild")), Times.Never());
        }
예제 #7
0
        // TODO: Should we use framework here
        //
        // 1. Create dgspec.json via .NET Core CLI: GenerateRestoreGraphFile target
        // 2. Load dgspec.json into DependencyGraphSpec instance/object
        // For each SDK project (ProjectStyle.PackageReference) in the graph spec
        // 3. Get assets file (project.assets.json) for the project
        // 4. Construct LockFile from assets file for the project
        static void AnalyzeProject(string projectPath, string framework)
        {
            // Graph input
            var vertices = new HashSet <Node>();
            var edges    = new HashSet <Edge>();

            var rootNuGetFramework = NuGetFramework.ParseFolder(framework); // TODO: optional filter

            // TODO: HACK...kan fjernes
            if (string.IsNullOrEmpty(projectPath))
            {
                var rootPath = GetRepoRootPath();

                //projectPath = Path.Combine(rootPath, "DotnetDependencies.sln");
                projectPath = Path.Combine(
                    Path.Combine(
                        Path.Combine(rootPath, "src"), "Deps.CLI"), "Deps.CLI.csproj");
            }

            // 'package graph' is a better word
            // Load dependency graph via nuget client tools build into msbuild (.NET Core CLI, .NET Core SDK)
            // TODO: opsatning af packageSources
            var dependencyGraphService = new DependencyGraphService();
            var dependencyGraph        = dependencyGraphService.GenerateDependencyGraph(projectPath);

            // We only support MSBuild style <PackageReference> SDK projects, where project.assets.json (lock file) is
            // generated in the RestoreOutputPath folder
            if (dependencyGraph.Projects.Any(p => p.RestoreMetadata.ProjectStyle != ProjectStyle.PackageReference))
            {
                throw new InvalidOperationException("Only SDK projects are supported.");
            }

            PackageSpec projectRoot = dependencyGraph.Projects.Single(p => Path.GetFileName(p.FilePath) == Path.GetFileName(projectPath));

            var rootNode = new ProjectReferenceNode(projectPath, projectRoot.Version.ToString(), rootNuGetFramework);

            vertices.Add(rootNode);

            var projectRootTargetFramework = projectRoot.TargetFrameworks.FirstOrDefault(tf => rootNuGetFramework.Equals(tf.FrameworkName));

            if (projectRootTargetFramework == null)
            {
                throw new InvalidOperationException(
                          $"The root project does not define the TargetFramework {rootNuGetFramework}");
            }

            //Console.WriteLine($"project: {Path.GetFileName(project.FilePath)}");
            //Console.WriteLine($"project.BaseDirectory: {Path.GetFileName(project.BaseDirectory)}");
            //Console.WriteLine($"project.Name: {project.Name}");
            //Console.WriteLine($"project.TargetFrameworks: {string.Join(", ", project.TargetFrameworks.Select(tfm => tfm.FrameworkName.GetShortFolderName()))}");
            //Console.WriteLine($"project.Version: {project.Version}");
            //Console.WriteLine($"project.RestoreMetadata.ProjectName: {project.RestoreMetadata.ProjectName}");
            //Console.WriteLine($"project.RestoreMetadata.Sources: {string.Join(", ", project.RestoreMetadata.Sources)}");
            //Console.WriteLine($"project.Dependencies: {string.Join(", ", project.Dependencies)}");


            // TODO: Path. Unique name etc...
            Console.WriteLine($"Name: {projectRoot.Name}");
            Console.WriteLine($"Version: {projectRoot.Version} ({rootNuGetFramework.GetShortFolderName()})");
            Console.WriteLine($"Framework: {rootNuGetFramework.DotNetFrameworkName}");
            Console.WriteLine($"Framework moniker: {rootNuGetFramework.GetShortFolderName()}");
            Console.WriteLine();

            Console.WriteLine("resolve project reference dependency graph");
            Console.WriteLine();

            // TODO: Path. Unique name etc...
            Console.WriteLine($"{projectRoot.Name}, v{projectRoot.Version} ({rootNuGetFramework.GetShortFolderName()})");

            //
            // First resolve project reference dependency graph
            //

            foreach (ProjectRestoreMetadataFrameworkInfo targetFramework in projectRoot.RestoreMetadata.TargetFrameworks)
            {
                // only want project references defined for the TargetFramework
                if (!rootNuGetFramework.Equals(targetFramework.FrameworkName))
                {
                    continue;
                }

                // project references of a targetFramework
                foreach (var projectRestoreReference in targetFramework.ProjectReferences)
                {
                    // TODO: PrivateAssets, ExcludeAssets, IncludeAssets
                    //dependency.ProjectPath
                    //dependency.ProjectUniqueName
                    PackageSpec projectDependency = dependencyGraph.GetProjectSpec(projectRestoreReference.ProjectUniqueName);

                    //Console.WriteLine($"({project.Name}, {Path.GetFileName(project.FilePath)}) is a project reference of ({projectRoot.Name}, {Path.GetFileName(projectRoot.FilePath)}");

                    NuGetFramework nearest          = projectDependency.GetNearestFrameworkMatching(rootNuGetFramework);
                    var            projectReference = new ProjectReferenceNode(projectDependency.FilePath, projectDependency.Version.ToString(), nearest);

                    vertices.Add(projectReference);

                    edges.Add(new Edge(rootNode, projectReference));

                    ReportProjectReferences(rootNode, projectDependency, rootNuGetFramework, dependencyGraph, 1,
                                            vertices, edges);
                }
            }

            // TODO: What about ProjectReferences...are project references converted to package specs in dgspec file??? YES,
            // and available via dependencyGraph.Projects and dependencyGraph.GetProjectSpec

            // TODO: project Closure is part of graph all ready
            // closure[0] is the root
            // closure[1..m] contains project references
            IReadOnlyList <PackageSpec> projectClosure = dependencyGraph.GetClosure(projectRoot.RestoreMetadata.ProjectUniqueName);

            Debug.Assert(ReferenceEquals(projectRoot, projectClosure[0]));

            //
            // Second, resolve package reference dependency graph of each project
            //

            Console.WriteLine();
            Console.WriteLine("resolve package reference dependency graph");
            Console.WriteLine();

            // for each csproj with PackageReference style (i.e. SDK csproj)
            foreach (PackageSpec project in dependencyGraph.Projects)
            {
                // TODO: Maybe just use the project.assets.json created by .NET Core SDK tooling
                // Generate lock file: A lock file has the package dependency graph for the project/solution/repo
                // that includes both the direct as well as transitive dependencies.
                var      lockFileService = new LockFileService();
                LockFile lockFile        = lockFileService.GetLockFile(project.FilePath, project.RestoreMetadata.OutputPath);

                // TODO: This could change our code...we can get at the project references inside one single loop
                //{
                //    // TODO: For debugging
                //    var projectDirectory = Path.GetDirectoryName(lockFile.PackageSpec.RestoreMetadata.ProjectPath);
                //    // full path to the referenced msbuild files (csproj files)
                //    var projectReferences = lockFile.Libraries
                //        .Where(library => library.MSBuildProject != null)
                //        .Select(library => Path.GetFullPath(Path.Combine(projectDirectory, library.MSBuildProject)))
                //        .ToArray();

                //    if (projectReferences.Length > 0)
                //    {
                //        Console.WriteLine($"project references {string.Join(", ", projectReferences)}");
                //    }
                //}

                NuGetFramework nearest = project.GetNearestFrameworkMatching(rootNuGetFramework);

                TargetFrameworkInformation resolvedTargetFramework =
                    project.TargetFrameworks.Single(tf => nearest.Equals(tf.FrameworkName));

                // for the root should this resolve to the rootNuGetFramework
                Console.WriteLine($"{project.Name}, v{project.Version}, ({resolvedTargetFramework.FrameworkName.GetShortFolderName()})");

                // Find the transitive closure for this tfm
                LockFileTarget lockFileTargetFramework =
                    lockFile.Targets.FirstOrDefault(t => t.TargetFramework.Equals(resolvedTargetFramework.FrameworkName));

                if (lockFileTargetFramework != null)
                {
                    // For each direct dependency
                    foreach (LibraryDependency directDependency in resolvedTargetFramework.Dependencies)
                    {
                        // Find the _resolved_ package reference
                        LockFileTargetLibrary resolvedPackageReference =
                            lockFileTargetFramework.Libraries.FirstOrDefault(library =>
                                                                             library.Name == directDependency.Name);

                        // Show transitive dependencies of this direct dependency
                        ReportLockFilePackageDependencies(resolvedPackageReference, lockFileTargetFramework, 1);
                    }
                }
            }
        }