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)); }
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()}"); } }
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}"); }
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}"); } }
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(); } }
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); }
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); } }
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)); }
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; } } } }
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(); } }
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)); }
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); }
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()}"); } }
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); }
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(); } }
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; }
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); } } }
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); } }
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)); }
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); } }
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); }
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}"); } }
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); }
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); } } }
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)); }
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}"); } }
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); }