diff --git a/src/Microsoft.Tye.Core/DockerContainerBuilder.cs b/src/Microsoft.Tye.Core/DockerContainerBuilder.cs index e7260e42..c5829d13 100644 --- a/src/Microsoft.Tye.Core/DockerContainerBuilder.cs +++ b/src/Microsoft.Tye.Core/DockerContainerBuilder.cs @@ -34,55 +34,93 @@ namespace Microsoft.Tye throw new ArgumentNullException(nameof(container)); } - using var tempFile = TempFile.Create(); - + string contextDirectory; var dockerFilePath = Path.Combine(project.ProjectFile.DirectoryName, "Dockerfile"); - if (File.Exists(dockerFilePath)) - { - output.WriteDebugLine($"Using existing Dockerfile '{dockerFilePath}'."); - } - else - { - await DockerfileGenerator.WriteDockerfileAsync(output, application, project, container, tempFile.FilePath); - dockerFilePath = tempFile.FilePath; - } - // We need to know if this is a single-phase or multi-phase Dockerfile because the context directory will be - // different depending on that choice. - string contextDirectory; - if (container.UseMultiphaseDockerfile ?? true) - { - contextDirectory = "."; - } - else + TempFile? tempFile = null; + TempDirectory? tempDirectory = null; + + try { - var publishOutput = project.Outputs.OfType().FirstOrDefault(); - if (publishOutput is null) + // We need to know if this is a single-phase or multi-phase Dockerfile because the context directory will be + // different depending on that choice. + // + // For the cases where generate a Dockerfile, we have the constraint that we need + // to place it on the same drive (Windows) as the docker context. + if (container.UseMultiphaseDockerfile ?? true) + { + // For a multi-phase Docker build, the context is always the project directory. + contextDirectory = "."; + + if (File.Exists(dockerFilePath)) + { + output.WriteDebugLine($"Using existing Dockerfile '{dockerFilePath}'."); + } + else + { + // We need to write the file, let's stick it under obj. + Directory.CreateDirectory(Path.Combine(project.ProjectFile.DirectoryName, "obj")); + dockerFilePath = Path.Combine(project.ProjectFile.DirectoryName, "obj", "Dockerfile"); + + // Clean up file when done building image + tempFile = new TempFile(dockerFilePath); + + await DockerfileGenerator.WriteDockerfileAsync(output, application, project, container, tempFile.FilePath); + } + } + else + { + // For a single-phase Docker build the context is always the directory containing the publish + // output. We need to put the Dockerfile in the context directory so it's on the same drive (Windows). + var publishOutput = project.Outputs.OfType().FirstOrDefault(); + if (publishOutput is null) + { + throw new InvalidOperationException("We should have published the project for a single-phase Dockerfile."); + } + + contextDirectory = publishOutput.Directory.FullName; + + // Clean up directory when done building image + tempDirectory = new TempDirectory(publishOutput.Directory); + + if (File.Exists(dockerFilePath) & container.UseMultiphaseDockerfile == false) + { + output.WriteDebugLine($"Using existing Dockerfile '{dockerFilePath}'."); + File.Copy(dockerFilePath, Path.Combine(contextDirectory, "Dockerfile")); + dockerFilePath = Path.Combine(contextDirectory, "Dockerfile"); + } + else + { + // No need to clean up, it's in a directory we're already cleaning up. + dockerFilePath = Path.Combine(contextDirectory, "Dockerfile"); + await DockerfileGenerator.WriteDockerfileAsync(output, application, project, container, dockerFilePath); + } + } + + output.WriteDebugLine("Running 'docker build'."); + output.WriteCommandLine("docker", $"build \"{contextDirectory}\" -t {container.ImageName}:{container.ImageTag} -f \"{dockerFilePath}\""); + var capture = output.Capture(); + var exitCode = await Process.ExecuteAsync( + $"docker", + $"build \"{contextDirectory}\" -t {container.ImageName}:{container.ImageTag} -f \"{dockerFilePath}\"", + project.ProjectFile.DirectoryName, + stdOut: capture.StdOut, + stdErr: capture.StdErr); + + output.WriteDebugLine($"Done running 'docker build' exit code: {exitCode}"); + if (exitCode != 0) { - throw new InvalidOperationException("We should have published the project for a single-phase Dockerfile."); + throw new CommandException("'docker build' failed."); } - contextDirectory = publishOutput.Directory.FullName; + output.WriteInfoLine($"Created Docker Image: '{container.ImageName}:{container.ImageTag}'"); + project.Outputs.Add(new DockerImageOutput(container.ImageName!, container.ImageTag!)); } - - output.WriteDebugLine("Running 'docker build'."); - output.WriteCommandLine("docker", $"build \"{contextDirectory}\" -t {container.ImageName}:{container.ImageTag} -f \"{dockerFilePath}\""); - var capture = output.Capture(); - var exitCode = await Process.ExecuteAsync( - $"docker", - $"build \"{contextDirectory}\" -t {container.ImageName}:{container.ImageTag} -f \"{dockerFilePath}\"", - project.ProjectFile.DirectoryName, - stdOut: capture.StdOut, - stdErr: capture.StdErr); - - output.WriteDebugLine($"Done running 'docker build' exit code: {exitCode}"); - if (exitCode != 0) + finally { - throw new CommandException("'docker build' failed."); + tempDirectory?.Dispose(); + tempFile?.Dispose(); } - - output.WriteInfoLine($"Created Docker Image: '{container.ImageName}:{container.ImageTag}'"); - project.Outputs.Add(new DockerImageOutput(container.ImageName!, container.ImageTag!)); } } } diff --git a/src/Microsoft.Tye.Core/PublishProjectStep.cs b/src/Microsoft.Tye.Core/PublishProjectStep.cs index 27a49598..ffae13ab 100644 --- a/src/Microsoft.Tye.Core/PublishProjectStep.cs +++ b/src/Microsoft.Tye.Core/PublishProjectStep.cs @@ -30,14 +30,16 @@ namespace Microsoft.Tye return; } - var outputDirectory = Path.Combine(project.ProjectFile.DirectoryName, "bin", "Release", project.TargetFramework, "publish"); + // NOTE: we're intentionally not cleaning up here. It's the responsibility of whomever consumes + // the publish output to do cleanup. + var outputDirectory = TempDirectory.Create(); output.WriteDebugLine("Running 'dotnet publish'."); - output.WriteCommandLine("dotnet", $"publish \"{project.ProjectFile.FullName}\" -c Release -o \"{outputDirectory}\""); + output.WriteCommandLine("dotnet", $"publish \"{project.ProjectFile.FullName}\" -c Release -o \"{outputDirectory.DirectoryPath}\""); var capture = output.Capture(); var exitCode = await Process.ExecuteAsync( $"dotnet", - $"publish \"{project.ProjectFile.FullName}\" -c Release -o \"{outputDirectory}\"", + $"publish \"{project.ProjectFile.FullName}\" -c Release -o \"{outputDirectory.DirectoryPath}\"", project.ProjectFile.DirectoryName, stdOut: capture.StdOut, stdErr: capture.StdErr); @@ -45,11 +47,12 @@ namespace Microsoft.Tye output.WriteDebugLine($"Done running 'dotnet publish' exit code: {exitCode}"); if (exitCode != 0) { + outputDirectory.Dispose(); throw new CommandException("'dotnet publish' failed."); } - output.WriteInfoLine($"Created Publish Output: '{outputDirectory}'"); - service.Outputs.Add(new ProjectPublishOutput(new DirectoryInfo(outputDirectory))); + output.WriteDebugLine($"Created Publish Output: '{outputDirectory}'"); + service.Outputs.Add(new ProjectPublishOutput(outputDirectory.DirectoryInfo)); } } } diff --git a/src/shared/TempDirectory.cs b/src/shared/TempDirectory.cs index ad87d47f..6e1af1ab 100644 --- a/src/shared/TempDirectory.cs +++ b/src/shared/TempDirectory.cs @@ -20,20 +20,21 @@ namespace Microsoft.Tye var directoryPath = Path.Combine(baseDirectory, Path.GetRandomFileName()); var directoryInfo = Directory.CreateDirectory(directoryPath); - return new TempDirectory(directoryPath, directoryInfo); + return new TempDirectory(directoryInfo); } else { var directoryPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); var directoryInfo = Directory.CreateDirectory(directoryPath); - return new TempDirectory(directoryPath, directoryInfo); + return new TempDirectory(directoryInfo); } } - private TempDirectory(string directoryPath, DirectoryInfo directoryInfo) + internal TempDirectory(DirectoryInfo directoryInfo) { - DirectoryPath = directoryPath; DirectoryInfo = directoryInfo; + + DirectoryPath = directoryInfo.FullName; } public string DirectoryPath { get; } diff --git a/src/shared/TempFile.cs b/src/shared/TempFile.cs index 4adec12c..590e34a5 100644 --- a/src/shared/TempFile.cs +++ b/src/shared/TempFile.cs @@ -19,7 +19,7 @@ namespace Microsoft.Tye File.Delete(FilePath); } - private TempFile(string filePath) + public TempFile(string filePath) { FilePath = filePath; } diff --git a/test/E2ETest/E2ETest.csproj b/test/E2ETest/E2ETest.csproj index 0df1fa54..978c309f 100644 --- a/test/E2ETest/E2ETest.csproj +++ b/test/E2ETest/E2ETest.csproj @@ -31,6 +31,7 @@ + diff --git a/test/E2ETest/TestHelpers.cs b/test/E2ETest/TestHelpers.cs index 0e59d6dd..8d85b551 100644 --- a/test/E2ETest/TestHelpers.cs +++ b/test/E2ETest/TestHelpers.cs @@ -6,6 +6,8 @@ using System; using System.Collections.Generic; using System.IO; using System.Text; +using Microsoft.Tye; +using Xunit; namespace E2ETest { @@ -33,5 +35,34 @@ namespace E2ETest throw new Exception($"Solution file {solution}.sln could not be found in {applicationBasePath} or its parent directories."); } + + public static DirectoryInfo GetTestAssetsDirectory() + { + return new DirectoryInfo(Path.Combine( + TestHelpers.GetSolutionRootDirectory("tye"), + "test", + "E2ETest", + "testassets")); + } + + public static DirectoryInfo GetTestProjectDirectory(string projectName) + { + var directory = new DirectoryInfo(Path.Combine( + TestHelpers.GetSolutionRootDirectory("tye"), + "test", + "E2ETest", + "testassets", + "projects", + projectName)); + Assert.True(directory.Exists, $"Project {projectName} not found."); + return directory; + } + + internal static TempDirectory CopyTestProjectDirectory(string projectName) + { + var temp = TempDirectory.Create(); + DirectoryCopy.Copy(GetTestProjectDirectory(projectName).FullName, temp.DirectoryPath); + return temp; + } } } diff --git a/test/E2ETest/TyeBuildTests.Dockerfile.cs b/test/E2ETest/TyeBuildTests.Dockerfile.cs new file mode 100644 index 00000000..a09ee169 --- /dev/null +++ b/test/E2ETest/TyeBuildTests.Dockerfile.cs @@ -0,0 +1,89 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Tye; +using Xunit; +using static E2ETest.TestHelpers; + +namespace E2ETest +{ + // Tests permutations of our Dockerfile-related behaviors. + public partial class TyeBuildTests + { + [ConditionalFact] + [SkipIfDockerNotRunning] + public async Task TyeBuild_SinglePhase_GeneratedDockerfile() + { + var projectName = "single-phase-dockerfile"; + var environment = "production"; + var imageName = "test/single-phase-dockerfile"; + + await DockerAssert.DeleteDockerImagesAsync(output, imageName); + + using var projectDirectory = CopyTestProjectDirectory(projectName); + File.Delete(Path.Combine(projectDirectory.DirectoryPath, "Dockerfile")); + Assert.False(File.Exists(Path.Combine(projectDirectory.DirectoryPath, "Dockerfile")), "Dockerfile should be gone."); + + var projectFile = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye.yaml")); + + var outputContext = new OutputContext(sink, Verbosity.Debug); + var application = await ApplicationFactory.CreateAsync(outputContext, projectFile); + + application.Registry = new ContainerRegistry("test"); + + try + { + await BuildHost.ExecuteBuildAsync(outputContext, application, environment, interactive: false); + + var publishOutput = Assert.Single(application.Services.Single().Outputs.OfType()); + Assert.False(Directory.Exists(publishOutput.Directory.FullName), $"Directory {publishOutput.Directory.FullName} should be deleted."); + + await DockerAssert.AssertImageExistsAsync(output, imageName); + } + finally + { + await DockerAssert.DeleteDockerImagesAsync(output, imageName); + } + } + + [ConditionalFact] + [SkipIfDockerNotRunning] + public async Task TyeBuild_SinglePhase_ExistingDockerfile() + { + var projectName = "single-phase-dockerfile"; + var environment = "production"; + var imageName = "test/single-phase-dockerfile"; + + await DockerAssert.DeleteDockerImagesAsync(output, imageName); + + using var projectDirectory = CopyTestProjectDirectory(projectName); + Assert.True(File.Exists(Path.Combine(projectDirectory.DirectoryPath, "Dockerfile")), "Dockerfile should exist."); + + + var projectFile = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye.yaml")); + + var outputContext = new OutputContext(sink, Verbosity.Debug); + var application = await ApplicationFactory.CreateAsync(outputContext, projectFile); + + application.Registry = new ContainerRegistry("test"); + + try + { + await BuildHost.ExecuteBuildAsync(outputContext, application, environment, interactive: false); + + var publishOutput = Assert.Single(application.Services.Single().Outputs.OfType()); + Assert.False(Directory.Exists(publishOutput.Directory.FullName), $"Directory {publishOutput.Directory.FullName} should be deleted."); + + await DockerAssert.AssertImageExistsAsync(output, imageName); + } + finally + { + await DockerAssert.DeleteDockerImagesAsync(output, imageName); + } + } + } +} diff --git a/test/E2ETest/TyeBuildTests.cs b/test/E2ETest/TyeBuildTests.cs index 16420b59..43065786 100644 --- a/test/E2ETest/TyeBuildTests.cs +++ b/test/E2ETest/TyeBuildTests.cs @@ -9,7 +9,7 @@ using Xunit.Abstractions; namespace E2ETest { - public class TyeBuildTests + public partial class TyeBuildTests { private readonly ITestOutputHelper output; private readonly TestOutputLogEventSink sink; diff --git a/test/E2ETest/TyeRunTests.cs b/test/E2ETest/TyeRunTests.cs index 99e5db7f..2d5df720 100644 --- a/test/E2ETest/TyeRunTests.cs +++ b/test/E2ETest/TyeRunTests.cs @@ -226,7 +226,7 @@ namespace E2ETest await host.StartAsync(); try { - // Make sure we're runningn containers + // Make sure we're running containers Assert.True(host.Application.Services.All(s => s.Value.Description.RunInfo is DockerRunInfo)); var handler = new HttpClientHandler diff --git a/test/E2ETest/testassets/projects/multi-phase-dockerfile/Program.cs b/test/E2ETest/testassets/projects/multi-phase-dockerfile/Program.cs new file mode 100644 index 00000000..6950fd53 --- /dev/null +++ b/test/E2ETest/testassets/projects/multi-phase-dockerfile/Program.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace multi_phase_dockerfile +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + } +} diff --git a/test/E2ETest/testassets/projects/multi-phase-dockerfile/Properties/launchSettings.json b/test/E2ETest/testassets/projects/multi-phase-dockerfile/Properties/launchSettings.json new file mode 100644 index 00000000..167686a9 --- /dev/null +++ b/test/E2ETest/testassets/projects/multi-phase-dockerfile/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:39765", + "sslPort": 44389 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "multi_phase_dockerfile": { + "commandName": "Project", + "launchBrowser": true, + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/test/E2ETest/testassets/projects/multi-phase-dockerfile/Startup.cs b/test/E2ETest/testassets/projects/multi-phase-dockerfile/Startup.cs new file mode 100644 index 00000000..a45414dd --- /dev/null +++ b/test/E2ETest/testassets/projects/multi-phase-dockerfile/Startup.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace multi_phase_dockerfile +{ + public class Startup + { + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapGet("/", async context => + { + await context.Response.WriteAsync("Hello World!"); + }); + }); + } + } +} diff --git a/test/E2ETest/testassets/projects/multi-phase-dockerfile/appsettings.Development.json b/test/E2ETest/testassets/projects/multi-phase-dockerfile/appsettings.Development.json new file mode 100644 index 00000000..dba68eb1 --- /dev/null +++ b/test/E2ETest/testassets/projects/multi-phase-dockerfile/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/test/E2ETest/testassets/projects/multi-phase-dockerfile/appsettings.json b/test/E2ETest/testassets/projects/multi-phase-dockerfile/appsettings.json new file mode 100644 index 00000000..81ff8777 --- /dev/null +++ b/test/E2ETest/testassets/projects/multi-phase-dockerfile/appsettings.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*" +} diff --git a/test/E2ETest/testassets/projects/multi-phase-dockerfile/multi-phase-dockerfile.csproj b/test/E2ETest/testassets/projects/multi-phase-dockerfile/multi-phase-dockerfile.csproj new file mode 100644 index 00000000..d1161572 --- /dev/null +++ b/test/E2ETest/testassets/projects/multi-phase-dockerfile/multi-phase-dockerfile.csproj @@ -0,0 +1,8 @@ + + + + netcoreapp3.1 + multi_phase_dockerfile + + + diff --git a/test/E2ETest/testassets/projects/multi-phase-dockerfile/tye.yaml b/test/E2ETest/testassets/projects/multi-phase-dockerfile/tye.yaml new file mode 100644 index 00000000..1eeab778 --- /dev/null +++ b/test/E2ETest/testassets/projects/multi-phase-dockerfile/tye.yaml @@ -0,0 +1,10 @@ +# tye application configuration file +# read all about it at https://github.com/dotnet/tye +# +# when you've given us a try, we'd love to know what you think: +# https://aka.ms/AA7q20u +# +name: multi-phase-dockerfile +services: +- name: multi-phase-dockerfile + project: multi-phase-dockerfile.csproj diff --git a/test/E2ETest/testassets/projects/single-phase-dockerfile/Dockerfile b/test/E2ETest/testassets/projects/single-phase-dockerfile/Dockerfile new file mode 100644 index 00000000..b4df7438 --- /dev/null +++ b/test/E2ETest/testassets/projects/single-phase-dockerfile/Dockerfile @@ -0,0 +1,4 @@ +FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 +WORKDIR /app +COPY . /app +ENTRYPOINT ["dotnet", "single-phase-dockerfile.dll"] \ No newline at end of file diff --git a/test/E2ETest/testassets/projects/single-phase-dockerfile/Program.cs b/test/E2ETest/testassets/projects/single-phase-dockerfile/Program.cs new file mode 100644 index 00000000..2824375e --- /dev/null +++ b/test/E2ETest/testassets/projects/single-phase-dockerfile/Program.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace single_phase_dockerfile +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + } +} diff --git a/test/E2ETest/testassets/projects/single-phase-dockerfile/Properties/launchSettings.json b/test/E2ETest/testassets/projects/single-phase-dockerfile/Properties/launchSettings.json new file mode 100644 index 00000000..f82f1a7c --- /dev/null +++ b/test/E2ETest/testassets/projects/single-phase-dockerfile/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:15313", + "sslPort": 44306 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "single_phase_dockerfile": { + "commandName": "Project", + "launchBrowser": true, + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/test/E2ETest/testassets/projects/single-phase-dockerfile/Startup.cs b/test/E2ETest/testassets/projects/single-phase-dockerfile/Startup.cs new file mode 100644 index 00000000..7ef502a4 --- /dev/null +++ b/test/E2ETest/testassets/projects/single-phase-dockerfile/Startup.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace single_phase_dockerfile +{ + public class Startup + { + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapGet("/", async context => + { + await context.Response.WriteAsync("Hello World!"); + }); + }); + } + } +} diff --git a/test/E2ETest/testassets/projects/single-phase-dockerfile/appsettings.Development.json b/test/E2ETest/testassets/projects/single-phase-dockerfile/appsettings.Development.json new file mode 100644 index 00000000..dba68eb1 --- /dev/null +++ b/test/E2ETest/testassets/projects/single-phase-dockerfile/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/test/E2ETest/testassets/projects/single-phase-dockerfile/appsettings.json b/test/E2ETest/testassets/projects/single-phase-dockerfile/appsettings.json new file mode 100644 index 00000000..81ff8777 --- /dev/null +++ b/test/E2ETest/testassets/projects/single-phase-dockerfile/appsettings.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*" +} diff --git a/test/E2ETest/testassets/projects/single-phase-dockerfile/single-phase-dockerfile.csproj b/test/E2ETest/testassets/projects/single-phase-dockerfile/single-phase-dockerfile.csproj new file mode 100644 index 00000000..d6978acf --- /dev/null +++ b/test/E2ETest/testassets/projects/single-phase-dockerfile/single-phase-dockerfile.csproj @@ -0,0 +1,8 @@ + + + + netcoreapp3.1 + single_phase_dockerfile + + + diff --git a/test/E2ETest/testassets/projects/single-phase-dockerfile/tye.yaml b/test/E2ETest/testassets/projects/single-phase-dockerfile/tye.yaml new file mode 100644 index 00000000..c82a2a20 --- /dev/null +++ b/test/E2ETest/testassets/projects/single-phase-dockerfile/tye.yaml @@ -0,0 +1,10 @@ +# tye application configuration file +# read all about it at https://github.com/dotnet/tye +# +# when you've given us a try, we'd love to know what you think: +# https://aka.ms/AA7q20u +# +name: single-phase-dockerfile +services: +- name: single-phase-dockerfile + project: single-phase-dockerfile.csproj