Ejemplo n.º 1
0
        internal async Task <ProcessResult> RunDotNetPublishAsync(IDictionary <string, string> packageOptions = null, string additionalArgs = null, bool noRestore = true)
        {
            Output.WriteLine("Publishing ASP.NET Core application...");

            // Avoid restoring as part of build or publish. These projects should have already restored as part of running dotnet new. Explicitly disabling restore
            // should avoid any global contention and we can execute a build or publish in a lock-free way

            var restoreArgs = noRestore ? "--no-restore" : null;

            using var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), $"publish {restoreArgs} -c Release /bl {additionalArgs}", packageOptions);
            await result.Exited;

            CaptureBinLogOnFailure(result);
            return(new ProcessResult(result));
        }
Ejemplo n.º 2
0
        public AspNetProcess(
            ITestOutputHelper output,
            string workingDirectory,
            string dllPath,
            IDictionary <string, string> environmentVariables,
            bool published       = true,
            bool hasListeningUri = true,
            ILogger logger       = null)
        {
            _output     = output;
            _httpClient = new HttpClient(new HttpClientHandler()
            {
                AllowAutoRedirect = true,
                UseCookies        = true,
                CookieContainer   = new CookieContainer(),
                ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator,
            })
            {
                Timeout = TimeSpan.FromMinutes(2)
            };

            _certificatePath = Path.Combine(workingDirectory, $"{Guid.NewGuid()}.pfx");

            EnsureDevelopmentCertificates();

            output.WriteLine("Running ASP.NET application...");

            var arguments = published ? $"exec {dllPath}" : "run";

            logger?.LogInformation($"AspNetProcess - process: {DotNetMuxer.MuxerPathOrDefault()} arguments: {arguments}");

            var finalEnvironmentVariables = new Dictionary <string, string>(environmentVariables)
            {
                ["ASPNETCORE_KESTREL__CERTIFICATES__DEFAULT__PATH"]     = _certificatePath,
                ["ASPNETCORE_KESTREL__CERTIFICATES__DEFAULT__PASSWORD"] = _certificatePassword
            };

            Process = ProcessEx.Run(output, workingDirectory, DotNetMuxer.MuxerPathOrDefault(), arguments, envVars: finalEnvironmentVariables);

            logger?.LogInformation("AspNetProcess - process started");

            if (hasListeningUri)
            {
                logger?.LogInformation("AspNetProcess - Getting listening uri");
                ListeningUri = GetListeningUri(output) ?? throw new InvalidOperationException("Couldn't find the listening URL.");
                logger?.LogInformation($"AspNetProcess - Got {ListeningUri.ToString()}");
            }
        }
Ejemplo n.º 3
0
        protected void Scaffold(string[] args, string testProjectPath)
        {
            var thisAssembly = GetType().GetTypeInfo().Assembly.GetName().Name;
            var muxerPath    = DotNetMuxer.MuxerPathOrDefault();

            Output.WriteLine($"Executing {muxerPath} {string.Join(" ", args)}");
            var exitCode = Command.Create(muxerPath, args.Concat(new [] { "--no-build" }))
                           .WithEnvironmentVariable("DOTNET_SKIP_FIRST_TIME_EXPERIENCE", "true")
                           .InWorkingDirectory(testProjectPath)
                           .OnOutputLine(l => Output.WriteLine(l))
                           .OnErrorLine(l => Output.WriteLine(l))
                           .Execute()
                           .ExitCode;

            Assert.True(0 == exitCode, $"Scaffold command failed with exit code {exitCode}");
        }
Ejemplo n.º 4
0
        public AspNetProcess(
            ITestOutputHelper output,
            string workingDirectory,
            string dllPath,
            IDictionary <string, string> environmentVariables,
            bool published       = true,
            bool hasListeningUri = true,
            ILogger logger       = null)
        {
            _certificatePath = Path.Combine(workingDirectory, $"{Guid.NewGuid()}.pfx");
            EnsureDevelopmentCertificates();

            _output     = output;
            _httpClient = new HttpClient(new HttpClientHandler()
            {
                AllowAutoRedirect = true,
                UseCookies        = true,
                CookieContainer   = new CookieContainer(),
                ServerCertificateCustomValidationCallback = (request, certificate, chain, errors) => (certificate.Subject != "CN=localhost" && errors == SslPolicyErrors.None) || certificate?.Thumbprint == _certificateThumbprint,
            })
            {
                Timeout = TimeSpan.FromMinutes(2)
            };

            output.WriteLine("Running ASP.NET application...");

            var arguments = published ? $"exec {dllPath}" : "run";

            logger?.LogInformation($"AspNetProcess - process: {DotNetMuxer.MuxerPathOrDefault()} arguments: {arguments}");

            var finalEnvironmentVariables = new Dictionary <string, string>(environmentVariables)
            {
                ["ASPNETCORE_Kestrel__Certificates__Default__Path"]     = _certificatePath,
                ["ASPNETCORE_Kestrel__Certificates__Default__Password"] = _certificatePassword
            };

            Process = ProcessEx.Run(output, workingDirectory, DotNetMuxer.MuxerPathOrDefault(), arguments, envVars: finalEnvironmentVariables);

            logger?.LogInformation("AspNetProcess - process started");

            if (hasListeningUri)
            {
                logger?.LogInformation("AspNetProcess - Getting listening uri");
                ListeningUri = ResolveListeningUrl(output);
                logger?.LogInformation($"AspNetProcess - Got {ListeningUri}");
            }
        }
Ejemplo n.º 5
0
        internal async Task <ProcessEx> RunDotNetNewAsync(string templateName, string auth = null, string language = null, bool useLocalDB = false, bool noHttps = false)
        {
            var hiveArg = $"--debug:custom-hive \"{TemplatePackageInstaller.CustomHivePath}\"";
            var args    = $"new {templateName} {hiveArg}";

            if (!string.IsNullOrEmpty(auth))
            {
                args += $" --auth {auth}";
            }

            if (!string.IsNullOrEmpty(language))
            {
                args += $" -lang {language}";
            }

            if (useLocalDB)
            {
                args += $" --use-local-db";
            }

            if (noHttps)
            {
                args += $" --no-https";
            }

            // Save a copy of the arguments used for better diagnostic error messages later.
            // We omit the hive argument and the template output dir as they are not relevant and add noise.
            ProjectArguments = args.Replace(hiveArg, "");

            args += $" -o {TemplateOutputDir}";

            // Only run one instance of 'dotnet new' at once, as a workaround for
            // https://github.com/aspnet/templating/issues/63

            await DotNetNewLock.WaitAsync();

            try
            {
                var execution = ProcessEx.Run(Output, AppContext.BaseDirectory, DotNetMuxer.MuxerPathOrDefault(), args);
                await execution.Exited;
                return(execution);
            }
            finally
            {
                DotNetNewLock.Release();
            }
        }
Ejemplo n.º 6
0
        private async Task <int> MainInternalAsync(
            IReporter reporter,
            string project,
            ICollection <string> args,
            CancellationToken cancellationToken)
        {
            // TODO multiple projects should be easy enough to add here
            string projectFile;

            try
            {
                projectFile = MsBuildProjectFinder.FindMsBuildProject(_workingDirectory, project);
            }
            catch (FileNotFoundException ex)
            {
                reporter.Error(ex.Message);
                return(1);
            }

            var watchOptions = DotNetWatchOptions.Default;

            var fileSetFactory = new MsBuildFileSetFactory(reporter,
                                                           watchOptions,
                                                           projectFile,
                                                           waitOnError: true,
                                                           trace: false);
            var processInfo = new ProcessSpec
            {
                Executable           = DotNetMuxer.MuxerPathOrDefault(),
                WorkingDirectory     = Path.GetDirectoryName(projectFile),
                Arguments            = args,
                EnvironmentVariables =
                {
                    ["DOTNET_WATCH"] = "1"
                },
            };

            if (CommandLineOptions.IsPollingEnabled)
            {
                _reporter.Output("Polling file watcher is enabled");
            }

            await using var watcher = new DotNetWatcher(reporter, fileSetFactory, watchOptions);
            await watcher.WatchAsync(processInfo, cancellationToken);

            return(0);
        }
Ejemplo n.º 7
0
        protected void RunDotNetEfCreateMigration(string migrationName)
        {
            var assembly = typeof(TemplateTestBase).Assembly;

            var dotNetEfFullPath = assembly.GetCustomAttributes <AssemblyMetadataAttribute>()
                                   .First(attribute => attribute.Key == "DotNetEfFullPath")
                                   .Value;

            var args = $"\"{dotNetEfFullPath}\" --verbose migrations add {migrationName}";

            // Only run one instance of 'dotnet new' at once, as a workaround for
            // https://github.com/aspnet/templating/issues/63
            lock (DotNetNewLock)
            {
                ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), args).WaitForExit(assertSuccess: true);
            }
        }
Ejemplo n.º 8
0
        public static async Task <MSBuildResult> RunProcessAsync(
            ProjectDirectory project,
            string arguments,
            TimeSpan?timeout = null,
            MSBuildProcessKind msBuildProcessKind = MSBuildProcessKind.Dotnet,
            string localPackageCache = null)
        {
            var processStartInfo = new ProcessStartInfo()
            {
                WorkingDirectory       = project.DirectoryPath,
                UseShellExecute        = false,
                RedirectStandardError  = true,
                RedirectStandardOutput = true,
            };

            if (localPackageCache != null)
            {
                processStartInfo.Environment.Add("NUGET_PACKAGES", localPackageCache);
            }

            if (msBuildProcessKind == MSBuildProcessKind.Desktop)
            {
                if (string.IsNullOrEmpty(BuildVariables.MSBuildPath))
                {
                    throw new ArgumentException("Unable to locate MSBuild.exe to run desktop tests. " +
                                                "MSBuild.exe is located using state created as part of running build[cmd|sh] at the root of the repository. Run build /t:Prepare to set this up if this hasn't been done.");
                }

                processStartInfo.FileName  = BuildVariables.MSBuildPath;
                processStartInfo.Arguments = arguments;
            }
            else
            {
                processStartInfo.FileName  = DotNetMuxer.MuxerPathOrDefault();
                processStartInfo.Arguments = $"msbuild {arguments}";

                // Suppresses the 'Welcome to .NET Core!' output that times out tests and causes locked file issues.
                // When using dotnet we're not guarunteed to run in an environment where the dotnet.exe has had its first run experience already invoked.
                processStartInfo.EnvironmentVariables["DOTNET_SKIP_FIRST_TIME_EXPERIENCE"] = "true";
            }

            var processResult = await RunProcessCoreAsync(processStartInfo, timeout);

            return(new MSBuildResult(project, processResult.FileName, processResult.Arguments, processResult.ExitCode, processResult.Output));
        }
Ejemplo n.º 9
0
        public async Task ExpandEnvironmentVariableInWebConfig()
        {
#if NET461
            // use the dotnet on PATH
            var dotnetLocation = "dotnet";
#else
            var dotnetLocation = DotNetMuxer.MuxerPathOrDefault();
#endif
            using (StartLog(out var loggerFactory))
            {
                var logger = loggerFactory.CreateLogger("HelloWorldTest");

                var deploymentParameters = GetBaseDeploymentParameters();

                // Point to dotnet installed in user profile.
                deploymentParameters.EnvironmentVariables["DotnetPath"] = dotnetLocation;

                using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory))
                {
                    var deploymentResult = await deployer.DeployAsync();

                    Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", "%DotnetPath%");

                    // Request to base address and check if various parts of the body are rendered & measure the cold startup time.
                    var response = await RetryHelper.RetryRequest(() =>
                    {
                        return(deploymentResult.HttpClient.GetAsync("HelloWorld"));
                    }, logger, deploymentResult.HostShutdownToken, retryCount : 30);

                    var responseText = await response.Content.ReadAsStringAsync();

                    try
                    {
                        Assert.Equal("Hello World", responseText);
                    }
                    catch (XunitException)
                    {
                        logger.LogWarning(response.ToString());
                        logger.LogWarning(responseText);
                        throw;
                    }
                }
            }
        }
Ejemplo n.º 10
0
        internal async Task <ProcessEx> RunDotNetEfUpdateDatabaseAsync()
        {
            var args = $"\"{DotNetEfFullPath}\" --verbose --no-build database update";

            // Only run one instance of 'dotnet new' at once, as a workaround for
            // https://github.com/aspnet/templating/issues/63
            await DotNetNewLock.WaitAsync();

            try
            {
                var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), args);
                await result.Exited;
                return(result);
            }
            finally
            {
                DotNetNewLock.Release();
            }
        }
Ejemplo n.º 11
0
    internal async Task <ProcessResult> RunDotNetEfUpdateDatabaseAsync()
    {
        var args = "--verbose --no-build database update";

        var command = DotNetMuxer.MuxerPathOrDefault();

        if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DotNetEfFullPath")))
        {
            args = $"\"{DotNetEfFullPath}\" " + args;
        }
        else
        {
            command = "dotnet-ef";
        }

        using var result = ProcessEx.Run(Output, TemplateOutputDir, command, args);
        await result.Exited;

        return(new ProcessResult(result));
    }
Ejemplo n.º 12
0
    internal async Task <ProcessResult> RunDotNetBuildAsync(IDictionary <string, string> packageOptions = null, string additionalArgs = null, bool errorOnBuildWarning = true)
    {
        Output.WriteLine("Building ASP.NET Core application...");

        // Avoid restoring as part of build or publish. These projects should have already restored as part of running dotnet new. Explicitly disabling restore
        // should avoid any global contention and we can execute a build or publish in a lock-free way

        using var execution = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), $"build --no-restore -c Debug /bl {additionalArgs}", packageOptions);
        await execution.Exited;

        var result = new ProcessResult(execution);

        // Fail if there were build warnings
        if (errorOnBuildWarning && (execution.Output.Contains(": warning") || execution.Error.Contains(": warning")))
        {
            result.ExitCode = -1;
        }

        CaptureBinLogOnFailure(execution);
        return(result);
    }
Ejemplo n.º 13
0
        internal async Task <ProcessEx> RunDotNetBuildAsync(bool takeNodeLock = false)
        {
            Output.WriteLine("Building ASP.NET application...");

            // This is going to trigger a build, so we need to acquire the lock like in the other cases.
            // We want to take the node lock as some builds run NPM as part of the build and we want to make sure
            // it's run without interruptions.
            var effectiveLock = takeNodeLock ? new OrderedLock(NodeLock, DotNetNewLock) : new OrderedLock(nodeLock: null, DotNetNewLock);
            await effectiveLock.WaitAsync();

            try
            {
                var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), "build -c Debug");
                await result.Exited;
                return(result);
            }
            finally
            {
                effectiveLock.Release();
            }
        }
        public AspNetProcess(
            ITestOutputHelper output,
            string workingDirectory,
            string dllPath,
            IDictionary <string, string> environmentVariables,
            bool published       = true,
            bool hasListeningUri = true,
            ILogger logger       = null)
        {
            _output     = output;
            _httpClient = new HttpClient(new HttpClientHandler()
            {
                AllowAutoRedirect = true,
                UseCookies        = true,
                CookieContainer   = new CookieContainer(),
                ServerCertificateCustomValidationCallback = (m, c, ch, p) => true,
            })
            {
                Timeout = TimeSpan.FromMinutes(2)
            };

            EnsureDevelopmentCertificates();

            output.WriteLine("Running ASP.NET application...");

            var arguments = published ? $"exec {dllPath}" : "run";

            logger?.LogInformation($"AspNetProcess - process: {DotNetMuxer.MuxerPathOrDefault()} arguments: {arguments}");

            Process = ProcessEx.Run(output, workingDirectory, DotNetMuxer.MuxerPathOrDefault(), arguments, envVars: environmentVariables);

            logger?.LogInformation("AspNetProcess - process started");

            if (hasListeningUri)
            {
                logger?.LogInformation("AspNetProcess - Getting listening uri");
                ListeningUri = GetListeningUri(output) ?? throw new InvalidOperationException("Couldn't find the listening URL.");
                logger?.LogInformation($"AspNetProcess - Got {ListeningUri.ToString()}");
            }
        }
Ejemplo n.º 15
0
        private (ProcessEx, string url) RunPublishedStandaloneBlazorProject(Project project)
        {
            var publishDir = Path.Combine(project.TemplatePublishDir, "wwwroot");

            Output.WriteLine("Running dotnet serve on published output...");
            var developmentCertificate = DevelopmentCertificate.Create(project.TemplateOutputDir);
            var args = $"-S --pfx \"{developmentCertificate.CertificatePath}\" --pfx-pwd \"{developmentCertificate.CertificatePassword}\" --port 0";
            var command = DotNetMuxer.MuxerPathOrDefault();
            if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("HELIX_DIR")))
            {
                args = $"serve " + args;
            }
            else
            {
                command = "dotnet-serve";
                args = "--roll-forward LatestMajor " + args; // dotnet-serve targets net5.0 by default
            }

            var serveProcess = ProcessEx.Run(TestOutputHelper, publishDir, command, args);
            var listeningUri = ResolveListeningUrl(serveProcess);
            return (serveProcess, listeningUri);
        }
Ejemplo n.º 16
0
        internal async Task <ProcessEx> RunDotNetPublishAsync(bool takeNodeLock = false, IDictionary <string, string> packageOptions = null, string additionalArgs = null)
        {
            Output.WriteLine("Publishing ASP.NET application...");

            // This is going to trigger a build, so we need to acquire the lock like in the other cases.
            // We want to take the node lock as some builds run NPM as part of the build and we want to make sure
            // it's run without interruptions.
            var effectiveLock = takeNodeLock ? new OrderedLock(NodeLock, DotNetNewLock) : new OrderedLock(nodeLock: null, DotNetNewLock);
            await effectiveLock.WaitAsync();

            try
            {
                var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), $"publish -c Release /bl {additionalArgs}", packageOptions);
                await result.Exited;
                CaptureBinLogOnFailure(result);
                return(result);
            }
            finally
            {
                effectiveLock.Release();
            }
        }
Ejemplo n.º 17
0
        internal async Task PackAsync(ITestOutputHelper output)
        {
            if (_packed)
            {
                return;
            }

            var projectsToPack = GetProjectsToPack();

            foreach (var project in projectsToPack)
            {
                output.WriteLine(project);
            }

            foreach (var project in projectsToPack)
            {
                var psi = new ProcessStartInfo
                {
                    FileName = DotNetMuxer.MuxerPathOrDefault(),
#if DEBUG
                    Arguments = "msbuild /t:Restore;Pack /p:Configuration=Debug",
#else
                    Arguments = "msbuild /t:Restore;Pack /p:Configuration=Release",
#endif
                    WorkingDirectory       = project,
                    RedirectStandardOutput = true,
                    RedirectStandardError  = true
                };

                var result = await MSBuildProcessManager.RunProcessCoreAsync(
                    psi,
                    TimeSpan.FromMinutes(2));

                output.WriteLine(result.Output);
                Assert.Equal(0, result.ExitCode);
            }

            _packed = true;
        }
Ejemplo n.º 18
0
    private static async Task <string> LaunchAndGetUrl(IServiceProvider serviceProvider, string devToolsHost)
    {
        var tcs = new TaskCompletionSource <string>();

        var environment    = serviceProvider.GetRequiredService <IWebHostEnvironment>();
        var executablePath = LocateDebugProxyExecutable(environment);
        var muxerPath      = DotNetMuxer.MuxerPathOrDefault();
        var ownerPid       = Environment.ProcessId;

        var processStartInfo = new ProcessStartInfo
        {
            FileName               = muxerPath,
            Arguments              = $"exec \"{executablePath}\" --OwnerPid {ownerPid} --DevToolsUrl {devToolsHost}",
            UseShellExecute        = false,
            RedirectStandardOutput = true,
        };

        RemoveUnwantedEnvironmentVariables(processStartInfo.Environment);

        var debugProxyProcess = Process.Start(processStartInfo);

        if (debugProxyProcess is null)
        {
            tcs.TrySetException(new InvalidOperationException("Unable to start debug proxy process."));
        }
        else
        {
            PassThroughConsoleOutput(debugProxyProcess);
            CompleteTaskWhenServerIsReady(debugProxyProcess, tcs);

            new CancellationTokenSource(DebugProxyLaunchTimeout).Token.Register(() =>
            {
                tcs.TrySetException(new TimeoutException($"Failed to start the debug proxy within the timeout period of {DebugProxyLaunchTimeout.TotalSeconds} seconds."));
            });
        }

        return(await tcs.Task);
    }
        private static void ReinstallTemplatePackages(ITestOutputHelper output)
        {
            // Remove any previous or prebundled version of the template packages
            foreach (var packageName in _templatePackages)
            {
                var proc = ProcessEx.Run(
                    output,
                    AppContext.BaseDirectory,
                    DotNetMuxer.MuxerPathOrDefault(),
                    $"new --uninstall {packageName}");

                // We don't need this command to succeed, because we'll verify next that
                // uninstallation had the desired effect. This command is expected to fail
                // in the case where the package wasn't previously installed.
                proc.WaitForExit(assertSuccess: false);
            }

            VerifyCannotFindTemplate(output, "ASP.NET Core Empty");

            // Locate the artifacts directory containing the built template packages
            var solutionDir   = FindAncestorDirectoryContaining("Templating.sln");
            var artifactsDir  = Path.Combine(solutionDir, "artifacts", "build");
            var builtPackages = Directory.GetFiles(artifactsDir, "*.nupkg");

            foreach (var packagePath in builtPackages)
            {
                if (_templatePackages.Any(name => Path.GetFileName(packagePath).StartsWith(name, StringComparison.OrdinalIgnoreCase)))
                {
                    output.WriteLine($"Installing templates package {packagePath}...");
                    var proc = ProcessEx.Run(
                        output,
                        AppContext.BaseDirectory,
                        DotNetMuxer.MuxerPathOrDefault(),
                        $"new --install \"{packagePath}\"");
                    proc.WaitForExit(assertSuccess: true);
                }
            }
        }
Ejemplo n.º 20
0
        protected void RunDotNetNew(string templateName, string targetFrameworkOverride, string auth = null, string language = null, bool useLocalDB = false, bool noHttps = false)
        {
            SetAfterDirectoryBuildPropsContents();

            var args = $"new {templateName}";

            if (!string.IsNullOrEmpty(targetFrameworkOverride))
            {
                args += $" --target-framework-override {targetFrameworkOverride}";
            }

            if (!string.IsNullOrEmpty(auth))
            {
                args += $" -au {auth}";
            }

            if (!string.IsNullOrEmpty(language))
            {
                args += $" -lang {language}";
            }

            if (useLocalDB)
            {
                args += $" -uld";
            }

            if (noHttps)
            {
                args += $" --no-https";
            }

            // Only run one instance of 'dotnet new' at once, as a workaround for
            // https://github.com/aspnet/templating/issues/63
            lock (DotNetNewLock)
            {
                ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), args).WaitForExit(assertSuccess: true);
            }
        }
Ejemplo n.º 21
0
        public static async Task <MSBuildResult> RunProcessAsync(
            ProjectDirectory project,
            string arguments,
            TimeSpan?timeout = null)
        {
            var processStartInfo = new ProcessStartInfo()
            {
                WorkingDirectory       = project.DirectoryPath,
                UseShellExecute        = false,
                RedirectStandardError  = true,
                RedirectStandardOutput = true,
            };

            processStartInfo.FileName  = DotNetMuxer.MuxerPathOrDefault();
            processStartInfo.Arguments = $"msbuild {arguments}";

            // Suppresses the 'Welcome to .NET Core!' output that times out tests and causes locked file issues.
            // When using dotnet we're not guarunteed to run in an environment where the dotnet.exe has had its first run experience already invoked.
            processStartInfo.EnvironmentVariables["DOTNET_SKIP_FIRST_TIME_EXPERIENCE"] = "true";

            var processResult = await RunProcessCoreAsync(processStartInfo, timeout);

            return(new MSBuildResult(project, processResult.FileName, processResult.Arguments, processResult.ExitCode, processResult.Output));
        }
Ejemplo n.º 22
0
        public override bool Execute()
        {
            string outputPath = Path.Combine(OutputPath, "extensions.json");

            if (SourcePath.EndsWith("\\"))
            {
                SourcePath = Path.GetDirectoryName(SourcePath);
            }

            Assembly taskAssembly = typeof(GenerateFunctionsExtensionsMetadata).Assembly;

            var info = new ProcessStartInfo
            {
                UseShellExecute        = false,
                CreateNoWindow         = true,
                RedirectStandardError  = true,
                RedirectStandardOutput = true,
                WorkingDirectory       = Path.Combine(Path.GetDirectoryName(taskAssembly.Location), "..", "netstandard2.0", "generator"),
                FileName  = DotNetMuxer.MuxerPathOrDefault(),
                Arguments = $"Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator.Console.dll \"{SourcePath}\" \"{outputPath}\""
            };

            Log.LogMessage(MessageImportance.Low, $"Extensions generator working directory: '{info.WorkingDirectory}'");
            Log.LogMessage(MessageImportance.Low, $"Extensions generator path: '{info.FileName}'");
            Log.LogCommandLine(MessageImportance.Low, info.Arguments);

            using (var process = new Process {
                StartInfo = info
            })
            {
                process.EnableRaisingEvents = true;

                StringBuilder errorString = new StringBuilder();
                process.ErrorDataReceived += (s, e) =>
                {
                    if (e.Data != null)
                    {
                        Log.LogWarning(e.Data);
                        errorString.Append(e.Data);
                    }
                };

                StringBuilder outputString = new StringBuilder();
                process.OutputDataReceived += (s, e) =>
                {
                    if (e.Data != null)
                    {
                        // These debug logs will only appear in builds with detailed or higher verbosity.
                        Log.LogMessage(MessageImportance.Low, e.Data);
                        outputString.AppendLine(e.Data);
                    }
                };

                process.Start();
                process.BeginErrorReadLine();
                process.BeginOutputReadLine();
                process.WaitForExit();

                if (process.ExitCode != 0)
                {
                    // Dump any debug output if there is an error. This may have been hidden due to the msbuild verbosity level.
                    Log.LogMessage(MessageImportance.High, "Debug output from extension.json generator:");
                    Log.LogMessage(MessageImportance.High, outputString.ToString());
                    Log.LogError($"Metadata generation failed. Exit code: '{process.ExitCode}' Error: '{errorString}'");
                    return(false);
                }

                return(true);
            }
        }
Ejemplo n.º 23
0
        internal virtual Task ProcessExtensionsProject(string projectFolder)
        {
            string dotnetPath = DotNetMuxer.MuxerPathOrDefault();
            var    logBuilder = new StringBuilder();

            var tcs = new TaskCompletionSource <object>();

            _logger.LogInformation("Restoring extension packages");

            try
            {
                string runtimeIdentifierParameter = GetRuntimeIdentifierParameter();
                var    startInfo = new ProcessStartInfo
                {
                    FileName = dotnetPath,
                    RedirectStandardOutput = true,
                    RedirectStandardError  = true,
                    CreateNoWindow         = true,
                    UseShellExecute        = false,
                    ErrorDialog            = false,
                    WorkingDirectory       = projectFolder,
                    Arguments = $"build \"{ExtensionsProjectFileName}\" -o bin --force --no-incremental {runtimeIdentifierParameter}"
                };

                string nugetPath = Path.Combine(Path.GetDirectoryName(ProjectPath), "nuget.config");
                if (File.Exists(nugetPath))
                {
                    startInfo.Arguments += $" --configfile \"{nugetPath}\"";
                }

                if (ScriptSettingsManager.Instance.IsAzureEnvironment)
                {
                    string nugetCacheLocation = Path.Combine(ScriptSettingsManager.Instance.GetSetting(EnvironmentSettingNames.AzureWebsiteHomePath), ".nuget");

                    startInfo.Arguments += $" --packages \"{nugetCacheLocation}\"";
                }

                SetupProcessEnvironment(startInfo);
                ApplyNugetFallbackFolderConfiguration(startInfo);

                var process = new Process {
                    StartInfo = startInfo
                };
                process.ErrorDataReceived  += (s, e) => logBuilder.Append(e.Data);
                process.OutputDataReceived += (s, e) => logBuilder.Append(e.Data);
                process.EnableRaisingEvents = true;

                process.Exited += (s, e) =>
                {
                    int exitCode = process.ExitCode;
                    process.Close();

                    if (exitCode != 0)
                    {
                        tcs.SetException(CreateRestoreException(logBuilder));
                    }
                    else
                    {
                        ProcessReults(projectFolder)
                        .ContinueWith(t =>
                        {
                            if (t.IsFaulted)
                            {
                                tcs.SetException(CreateRestoreException(logBuilder, t.Exception));
                            }
                            else
                            {
                                tcs.SetResult(null);
                                _logger.LogInformation("Extensions packages restore succeeded.");
                            }
                        });
                    }
                };

                process.Start();

                process.BeginErrorReadLine();
                process.BeginOutputReadLine();
            }
            catch (Exception exc)
            {
                // Trace errors...
                tcs.SetException(CreateRestoreException(logBuilder, exc));
            }

            return(tcs.Task);
        }
Ejemplo n.º 24
0
        private void RestoreAndBuild(string path, ITestOutputHelper output)
        {
            var result = Command.CreateDotNet("restore",
                                              new string[] { })
                         .WithEnvironmentVariable("DOTNET_SKIP_FIRST_TIME_EXPERIENCE", "true")
                         .InWorkingDirectory(path)
                         .OnErrorLine(l => output.WriteLine(l))
                         .OnOutputLine(l => output.WriteLine(l))
                         .Execute();

            if (result.ExitCode != 0)
            {
                throw new InvalidOperationException($"Restore failed with exit code: {result.ExitCode} :: Dotnet path: {DotNetMuxer.MuxerPathOrDefault()}");
            }

            result = Command.CreateDotNet("build", new string[] { "-c", Configuration })
                     .WithEnvironmentVariable("DOTNET_SKIP_FIRST_TIME_EXPERIENCE", "true")
                     .InWorkingDirectory(path)
                     .OnErrorLine(l => output.WriteLine(l))
                     .OnOutputLine(l => output.WriteLine(l))
                     .Execute();

            if (result.ExitCode != 0)
            {
                throw new InvalidOperationException($"Build failed with exit code: {result.ExitCode}");
            }
        }
Ejemplo n.º 25
0
        protected override int Execute()
        {
            var thisPath = Path.GetFullPath(Path.GetDirectoryName(typeof(InvokeCommand).Assembly.Location));

            var projectName     = _projectOptions.ProjectName.Value();
            var assemblyPath    = _projectOptions.AssemblyPath.Value();
            var targetDirectory = Path.GetDirectoryName(assemblyPath);

            string executable        = null;
            var    cleanupExecutable = false;

            try
            {
                string toolsDirectory;
                var    args            = new List <string>();
                var    targetFramework = new FrameworkName(_projectOptions.TargetFramework.Value());
                switch (targetFramework.Identifier)
                {
                case ".NETFramework":
                    cleanupExecutable = true;
                    toolsDirectory    = Path.Combine(
                        thisPath,
                        _projectOptions.Platform.Value() == "x86" ? "net461-x86" : "net461");

                    var executableSource = Path.Combine(toolsDirectory, InsideManName + ".exe");
                    executable = Path.Combine(targetDirectory, InsideManName + ".exe");
                    File.Copy(executableSource, executable, overwrite: true);

                    var configPath = assemblyPath + ".config";
                    if (File.Exists(configPath))
                    {
                        File.Copy(configPath, executable + ".config", overwrite: true);
                    }
                    break;

                case ".NETCoreApp":
                    if (targetFramework.Version < new Version(2, 1))
                    {
                        throw new CommandException(Resources.FormatOldNETCoreAppProject(
                                                       projectName,
                                                       targetFramework.Version));
                    }

                    executable     = DotNetMuxer.MuxerPathOrDefault();
                    toolsDirectory = Path.Combine(thisPath, "netcoreapp2.1");

                    args.Add("exec");
                    args.Add("--depsFile");
                    args.Add(Path.ChangeExtension(assemblyPath, ".deps.json"));

                    var projectAssetsFile = _projectOptions.AssetsFile.Value();
                    if (!string.IsNullOrEmpty(projectAssetsFile) && File.Exists(projectAssetsFile))
                    {
                        using var reader = new JsonTextReader(File.OpenText(projectAssetsFile));
                        var projectAssets  = JToken.ReadFrom(reader);
                        var packageFolders = projectAssets["packageFolders"]
                                             .Children <JProperty>()
                                             .Select(p => p.Name);

                        foreach (var packageFolder in packageFolders)
                        {
                            args.Add("--additionalProbingPath");
                            args.Add(packageFolder.TrimEnd(Path.DirectorySeparatorChar));
                        }
                    }

                    var runtimeConfigPath = Path.ChangeExtension(assemblyPath, ".runtimeconfig.json");
                    if (File.Exists(runtimeConfigPath))
                    {
                        args.Add("--runtimeConfig");
                        args.Add(runtimeConfigPath);
                    }
                    else
                    {
                        var runtimeFrameworkVersion = _projectOptions.RuntimeFrameworkVersion.Value();
                        if (!string.IsNullOrEmpty(runtimeFrameworkVersion))
                        {
                            args.Add("--fx-version");
                            args.Add(runtimeFrameworkVersion);
                        }
                    }

                    args.Add(Path.Combine(toolsDirectory, InsideManName + ".dll"));
                    break;

                case ".NETStandard":
                    throw new CommandException(Resources.FormatNETStandardProject(projectName));

                default:
                    throw new CommandException(
                              Resources.FormatUnsupportedFramework(projectName, targetFramework.Identifier));
                }

                args.AddRange(_args);
                args.Add("--assembly");
                args.Add(assemblyPath);
                args.Add("--project");
                args.Add(projectName);
                args.Add("--tools-directory");
                args.Add(toolsDirectory);

                if (ReporterExtensions.PrefixOutput)
                {
                    args.Add("--prefix-output");
                }

                if (IsQuiet)
                {
                    args.Add("--quiet");
                }

                if (IsVerbose)
                {
                    args.Add("--verbose");
                }

                return(Exe.Run(executable, args, Reporter));
            }
            finally
            {
                if (cleanupExecutable && !string.IsNullOrEmpty(executable))
                {
                    // Ignore errors about in-use files. Should still be marked for delete after process cleanup.
                    try
                    {
                        File.Delete(executable);
                    }
                    catch (UnauthorizedAccessException)
                    {
                    }

                    try
                    {
                        File.Delete(executable + ".config");
                    }
                    catch (UnauthorizedAccessException)
                    {
                    }
                }
            }
        }
        private static (string, string) ResolveCommand(string fileName, IEnumerable <string> searchPaths, bool waitForExit)
        {
            string appName = Path.ChangeExtension(fileName, null);

            string command     = null;
            string commandArgs = null;

            foreach (string searchPath in searchPaths)
            {
                string testPath = Path.GetFullPath(Path.Combine(searchPath, appName));

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    string windowsTestPath = Path.ChangeExtension(testPath, "exe");
                    if (File.Exists(windowsTestPath))
                    {
                        command = windowsTestPath;
                        break;
                    }
                }
                else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                {
                    string macTestPath = Path.ChangeExtension(testPath, "app");
                    if (waitForExit)
                    {
                        // If waitForExit, get the executable out of the app bundle.
                        macTestPath = Path.Combine(macTestPath, "Contents", "MacOS", appName);
                        if (File.Exists(macTestPath))
                        {
                            command = macTestPath;
                            break;
                        }
                    }
                    else
                    {
                        // Otherwise use the .app itself.
                        if (Directory.Exists(macTestPath))
                        {
                            command     = "open";
                            commandArgs = $"-n \"{macTestPath}\" --args";
                            break;
                        }
                    }
                }
                else
                {
                    string linuxTestPath = Path.ChangeExtension(testPath, null);
                    if (File.Exists(linuxTestPath))
                    {
                        command = linuxTestPath;
                        break;
                    }
                }

                string dotnetTestPath = Path.ChangeExtension(testPath, "dll");
                if (File.Exists(dotnetTestPath))
                {
                    command     = DotNetMuxer.MuxerPathOrDefault();
                    commandArgs = $"\"{dotnetTestPath}\"";
                    break;
                }
            }

            if (command == null)
            {
                throw new FileNotFoundException($"{appName} is not in the search path!");
            }

            return(command, commandArgs);
        }
Ejemplo n.º 27
0
        public async Task <IFileSet> CreateAsync(CancellationToken cancellationToken)
        {
            var watchList = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());

            try
            {
                var projectDir = Path.GetDirectoryName(_projectFile);

                while (true)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    var capture = _outputSink.StartCapture();
                    // TODO adding files doesn't currently work. Need to provide a way to detect new files
                    // find files
                    var processSpec = new ProcessSpec
                    {
                        Executable       = DotNetMuxer.MuxerPathOrDefault(),
                        WorkingDirectory = projectDir,
                        Arguments        = new[]
                        {
                            "msbuild",
                            _projectFile,
                            $"/p:_DotNetWatchListFile={watchList}"
                        }.Concat(_buildFlags),
                        OutputCapture = capture
                    };

                    _reporter.Verbose($"Running MSBuild target '{TargetName}' on '{_projectFile}'");

                    var exitCode = await _processRunner.RunAsync(processSpec, cancellationToken);

                    if (exitCode == 0 && File.Exists(watchList))
                    {
                        var fileset = new FileSet(
                            File.ReadAllLines(watchList)
                            .Select(l => l?.Trim())
                            .Where(l => !string.IsNullOrEmpty(l)));

                        _reporter.Verbose($"Watching {fileset.Count} file(s) for changes");
#if DEBUG
                        foreach (var file in fileset)
                        {
                            _reporter.Verbose($"  -> {file}");
                        }

                        Debug.Assert(fileset.All(Path.IsPathRooted), "All files should be rooted paths");
#endif

                        return(fileset);
                    }

                    _reporter.Error($"Error(s) finding watch items project file '{Path.GetFileName(_projectFile)}'");

                    _reporter.Output($"MSBuild output from target '{TargetName}':");
                    _reporter.Output(string.Empty);

                    foreach (var line in capture.Lines)
                    {
                        _reporter.Output($"   {line}");
                    }

                    _reporter.Output(string.Empty);

                    if (!_waitOnError)
                    {
                        return(null);
                    }
                    else
                    {
                        _reporter.Warn("Fix the error to continue or press Ctrl+C to exit.");

                        var fileSet = new FileSet(new[] { _projectFile });

                        using (var watcher = new FileSetWatcher(fileSet, _reporter))
                        {
                            await watcher.GetChangedFileAsync(cancellationToken);

                            _reporter.Output($"File changed: {_projectFile}");
                        }
                    }
                }
            }
            finally
            {
                if (File.Exists(watchList))
                {
                    File.Delete(watchList);
                }
            }
        }
Ejemplo n.º 28
0
        public static async Task <MSBuildResult> RunProcessAsync(
            ProjectDirectory project,
            string arguments,
            TimeSpan?timeout = null,
            MSBuildProcessKind msBuildProcessKind = MSBuildProcessKind.Dotnet)
        {
            var processStartInfo = new ProcessStartInfo()
            {
                WorkingDirectory       = project.DirectoryPath,
                UseShellExecute        = false,
                RedirectStandardError  = true,
                RedirectStandardOutput = true,
            };

            if (msBuildProcessKind == MSBuildProcessKind.Desktop)
            {
                if (string.IsNullOrEmpty(BuildVariables.MSBuildPath))
                {
                    throw new ArgumentException("Unable to locate MSBuild.exe to run desktop tests. " +
                                                "MSBuild.exe is located using state created as part of running build[cmd|sh] at the root of the repository. Run build /t:Prepare to set this up if this hasn't been done.");
                }

                processStartInfo.FileName  = BuildVariables.MSBuildPath;
                processStartInfo.Arguments = arguments;
            }
            else
            {
                processStartInfo.FileName  = DotNetMuxer.MuxerPathOrDefault();
                processStartInfo.Arguments = $"msbuild {arguments}";

                // Suppresses the 'Welcome to .NET Core!' output that times out tests and causes locked file issues.
                // When using dotnet we're not guarunteed to run in an environment where the dotnet.exe has had its first run experience already invoked.
                processStartInfo.EnvironmentVariables["DOTNET_SKIP_FIRST_TIME_EXPERIENCE"] = "true";
            }

            ProcessResult processResult;

            try
            {
                processResult = await RunProcessCoreAsync(processStartInfo, timeout);
            }
            catch (TimeoutException ex)
            {
                // Copy the binlog to the artifacts directory if executing MSBuild throws.
                // This would help diagnosing failures on the CI.
                var binaryLogFile = Path.Combine(project.ProjectFilePath, "msbuild.binlog");

                var artifactsLogDir = Assembly.GetExecutingAssembly()
                                      .GetCustomAttributes <AssemblyMetadataAttribute>()
                                      .FirstOrDefault(ama => ama.Key == "ArtifactsLogDir")?.Value;

                if (!string.IsNullOrEmpty(artifactsLogDir) && File.Exists(binaryLogFile))
                {
                    var targetPath = Path.Combine(artifactsLogDir, Path.GetFileNameWithoutExtension(project.ProjectFilePath) + "." + Path.GetRandomFileName() + ".binlog");
                    File.Copy(binaryLogFile, targetPath);

                    throw new TimeoutException(ex.Message + $"{Environment.NewLine}Captured binlog at {targetPath}");
                }

                throw;
            }

            return(new MSBuildResult(project, processResult.FileName, processResult.Arguments, processResult.ExitCode, processResult.Output));
        }
Ejemplo n.º 29
0
        public AspNetProcess(
            ITestOutputHelper output,
            string workingDirectory,
            string dllPath,
            IDictionary <string, string> environmentVariables,
            bool published,
            bool hasListeningUri     = true,
            bool usePublishedAppHost = false,
            ILogger logger           = null)
        {
            _developmentCertificate = DevelopmentCertificate.Create(workingDirectory);

            _output     = output;
            _httpClient = new HttpClient(new HttpClientHandler()
            {
                AllowAutoRedirect = true,
                UseCookies        = true,
                CookieContainer   = new CookieContainer(),
                ServerCertificateCustomValidationCallback = (request, certificate, chain, errors) => (certificate.Subject != "CN=localhost" && errors == SslPolicyErrors.None) || certificate?.Thumbprint == _developmentCertificate.CertificateThumbprint,
            })
            {
                Timeout = TimeSpan.FromMinutes(2)
            };

            output.WriteLine("Running ASP.NET Core application...");

            string process;
            string arguments;

            if (published)
            {
                if (usePublishedAppHost)
                {
                    // When publishingu used the app host to run the app. This makes it easy to consistently run for regular and single-file publish
                    process   = Path.ChangeExtension(dllPath, OperatingSystem.IsWindows() ? ".exe" : null);
                    arguments = null;
                }
                else
                {
                    process   = DotNetMuxer.MuxerPathOrDefault();
                    arguments = $"exec {dllPath}";
                }
            }
            else
            {
                process   = DotNetMuxer.MuxerPathOrDefault();
                arguments = "run --no-build";
            }

            logger?.LogInformation($"AspNetProcess - process: {process} arguments: {arguments}");

            var finalEnvironmentVariables = new Dictionary <string, string>(environmentVariables)
            {
                ["ASPNETCORE_Kestrel__Certificates__Default__Path"]     = _developmentCertificate.CertificatePath,
                ["ASPNETCORE_Kestrel__Certificates__Default__Password"] = _developmentCertificate.CertificatePassword,
            };

            Process = ProcessEx.Run(output, workingDirectory, process, arguments, envVars: finalEnvironmentVariables);

            logger?.LogInformation("AspNetProcess - process started");

            if (hasListeningUri)
            {
                logger?.LogInformation("AspNetProcess - Getting listening uri");
                ListeningUri = ResolveListeningUrl(output);
                logger?.LogInformation($"AspNetProcess - Got {ListeningUri}");
            }
        }
Ejemplo n.º 30
0
        public override bool Execute()
        {
            if (string.IsNullOrEmpty(RuleFile) || !File.Exists(RuleFile))
            {
                Log.LogError($"RuleFile '{RuleFile}' does not exist");
                return(false);
            }

            if (string.IsNullOrEmpty(ArtifactDirectory) || !Directory.Exists(ArtifactDirectory))
            {
                Log.LogError($"ArtifactDirectory '{ArtifactDirectory}' does not exist");
                return(false);
            }

            var taskAssemblyFolder = Path.GetDirectoryName(GetType().GetTypeInfo().Assembly.Location);
            var toolPath           = Path.Combine(taskAssemblyFolder, "..", "..", ConsoleAppExe);

            if (!File.Exists(toolPath))
            {
                toolPath = Path.Combine(taskAssemblyFolder, ConsoleAppExe);
            }

            var dotnetMuxer = DotNetMuxer.MuxerPathOrDefault();
            var arguments   = new List <string>
            {
                toolPath,
                "--rule-file",
                RuleFile,
                ArtifactDirectory,
            };

            if (!string.IsNullOrEmpty(SignRequestManifest))
            {
                if (!File.Exists(SignRequestManifest))
                {
                    Log.LogError($"SignRequestManifest file {SignRequestManifest} does not exist.");
                    return(false);
                }

                arguments.Add("--sign-request");
                arguments.Add(SignRequestManifest);
            }

            foreach (var rule in ExcludedRules ?? Enumerable.Empty <string>())
            {
                arguments.Add("--excluded-rule");
                arguments.Add(rule);
            }

            var psi = new ProcessStartInfo
            {
                FileName  = dotnetMuxer,
                Arguments = ArgumentEscaper.EscapeAndConcatenate(arguments),
            };

            Log.LogCommandLine($"Executing '{psi.FileName} {psi.Arguments}'");

            var process = Process.Start(psi);

            process.WaitForExit();
            return(process.ExitCode == 0);
        }