mirror of https://github.com/dotnet/tye.git
committed by
GitHub
11 changed files with 272 additions and 120 deletions
@ -0,0 +1,112 @@ |
|||
using System; |
|||
using System.CommandLine; |
|||
using System.CommandLine.IO; |
|||
using System.IO; |
|||
using Tye.ConfigModel; |
|||
using YamlDotNet.Serialization; |
|||
using YamlDotNet.Serialization.NamingConventions; |
|||
|
|||
namespace Tye |
|||
{ |
|||
public class InitHost |
|||
{ |
|||
|
|||
public static string CreateTyeFile(FileInfo? path, bool force) |
|||
{ |
|||
var (content, outputFilePath) = CreateTyeFileContent(path, force); |
|||
|
|||
File.WriteAllText(outputFilePath, content); |
|||
|
|||
return outputFilePath; |
|||
} |
|||
|
|||
public static (string, string) CreateTyeFileContent(FileInfo? path, bool force) |
|||
{ |
|||
if (path is FileInfo && path.Exists && !force) |
|||
{ |
|||
ThrowIfTyeFilePresent(path, "tye.yml"); |
|||
ThrowIfTyeFilePresent(path, "tye.yaml"); |
|||
} |
|||
|
|||
var template = @"
|
|||
# tye application configuration file |
|||
# read all about it at https://github.com/dotnet/tye
|
|||
# |
|||
# define global settings here
|
|||
# name: exampleapp # application name |
|||
# registry: exampleuser # dockerhub username or container registry hostname |
|||
|
|||
# define multiple services here
|
|||
services: |
|||
- name: myservice |
|||
# project: app.csproj # msbuild project path (relative to this file) |
|||
# executable: app.exe # path to an executable (relative to this file) |
|||
# args: --arg1=3 # arguments to pass to the process |
|||
# replicas: 5 # number of times to launch the application |
|||
# env: # array of environment variables |
|||
# - name: key |
|||
# value: value |
|||
# bindings: # optional array of bindings (ports, connection strings) |
|||
# - port: 8080 # number port of the binding |
|||
".TrimStart();
|
|||
|
|||
// Output in the current directory unless an input file was provided, then
|
|||
// output next to the input file.
|
|||
var outputFilePath = "tye.yaml"; |
|||
|
|||
if (path is FileInfo && path.Exists) |
|||
{ |
|||
var application = ConfigFactory.FromFile(path); |
|||
var serializer = new SerializerBuilder() |
|||
.WithNamingConvention(CamelCaseNamingConvention.Instance) |
|||
.ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitDefaults) |
|||
.Build(); |
|||
|
|||
var extension = path.Extension.ToLowerInvariant(); |
|||
var directory = path.Directory; |
|||
|
|||
// Clear all bindings if any for solutions and project files
|
|||
if (extension == ".sln" || extension == ".csproj" || extension == ".fsproj") |
|||
{ |
|||
// If the input file is a project or solution then use that as the name
|
|||
application.Name = Path.GetFileNameWithoutExtension(path.Name).ToLowerInvariant(); |
|||
|
|||
foreach (var service in application.Services) |
|||
{ |
|||
service.Bindings = null!; |
|||
service.Configuration = null!; |
|||
service.Project = service.Project!.Substring(directory.FullName.Length).TrimStart('/'); |
|||
} |
|||
|
|||
// If the input file is a sln/project then place the config next to it
|
|||
outputFilePath = Path.Combine(directory.FullName, "tye.yaml"); |
|||
} |
|||
else |
|||
{ |
|||
// If the input file is a yaml, then use the directory name.
|
|||
application.Name = path.Directory.Name.ToLowerInvariant(); |
|||
|
|||
// If the input file is a yaml, then replace it.
|
|||
outputFilePath = path.FullName; |
|||
} |
|||
|
|||
template = @"
|
|||
# tye application configuration file |
|||
# read all about it at https://github.com/dotnet/tye
|
|||
".TrimStart() + serializer.Serialize(application);
|
|||
} |
|||
|
|||
return (template, outputFilePath); |
|||
} |
|||
|
|||
|
|||
private static void ThrowIfTyeFilePresent(FileInfo? path, string yml) |
|||
{ |
|||
var tyeYaml = Path.Combine(path!.DirectoryName, yml); |
|||
if (File.Exists(tyeYaml)) |
|||
{ |
|||
throw new CommandException($"File '{tyeYaml}' already exists. Use --force to override the {yml} file if desired."); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Text; |
|||
|
|||
namespace E2ETest |
|||
{ |
|||
public static class TestHelpers |
|||
{ |
|||
// https://github.com/dotnet/aspnetcore/blob/5a0526dfd991419d5bce0d8ea525b50df2e37b04/src/Testing/src/TestPathUtilities.cs
|
|||
// This can get into a bad pattern for having crazy paths in places. Eventually, especially if we use helix,
|
|||
// we may want to avoid relying on sln position.
|
|||
public static string GetSolutionRootDirectory(string solution) |
|||
{ |
|||
var applicationBasePath = AppContext.BaseDirectory; |
|||
var directoryInfo = new DirectoryInfo(applicationBasePath); |
|||
|
|||
do |
|||
{ |
|||
var projectFileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, $"{solution}.sln")); |
|||
if (projectFileInfo.Exists) |
|||
{ |
|||
return projectFileInfo.DirectoryName; |
|||
} |
|||
|
|||
directoryInfo = directoryInfo.Parent; |
|||
} |
|||
while (directoryInfo.Parent != null); |
|||
|
|||
throw new Exception($"Solution file {solution}.sln could not be found in {applicationBasePath} or its parent directories."); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,84 @@ |
|||
// 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; |
|||
using System.IO; |
|||
using System.Text.Json; |
|||
using Microsoft.Build.Construction; |
|||
using Tye; |
|||
using Tye.ConfigModel; |
|||
using Xunit; |
|||
using Xunit.Abstractions; |
|||
|
|||
namespace E2ETest |
|||
{ |
|||
public class TyeInitTests |
|||
{ |
|||
private readonly ITestOutputHelper output; |
|||
private readonly TestOutputLogEventSink sink; |
|||
|
|||
public TyeInitTests(ITestOutputHelper output) |
|||
{ |
|||
this.output = output; |
|||
sink = new TestOutputLogEventSink(output); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SingleProjectInitTest() |
|||
{ |
|||
var projectDirectory = new DirectoryInfo(Path.Combine(TestHelpers.GetSolutionRootDirectory("tye"), "samples", "single-project", "test-project")); |
|||
using var tempDirectory = TempDirectory.Create(); |
|||
DirectoryCopy.Copy(projectDirectory.FullName, tempDirectory.DirectoryPath); |
|||
|
|||
var projectFile = new FileInfo(Path.Combine(tempDirectory.DirectoryPath, "test-project.csproj")); |
|||
|
|||
var (content, _) = InitHost.CreateTyeFileContent(projectFile, force: false); |
|||
var expectedContent = File.ReadAllText("testassets/init/single-project.yaml"); |
|||
|
|||
output.WriteLine(content); |
|||
|
|||
Assert.Equal(expectedContent, content); |
|||
} |
|||
|
|||
[Fact] |
|||
public void MultiProjectInitTest() |
|||
{ |
|||
var projectDirectory = new DirectoryInfo(Path.Combine(TestHelpers.GetSolutionRootDirectory("tye"), "samples", "multi-project")); |
|||
using var tempDirectory = TempDirectory.Create(); |
|||
DirectoryCopy.Copy(projectDirectory.FullName, tempDirectory.DirectoryPath); |
|||
|
|||
// delete already present yaml
|
|||
File.Delete(Path.Combine(tempDirectory.DirectoryPath, "tye.yaml")); |
|||
|
|||
var projectFile = new FileInfo(Path.Combine(tempDirectory.DirectoryPath, "multi-project.sln")); |
|||
|
|||
var (content, _) = InitHost.CreateTyeFileContent(projectFile, force: false); |
|||
var expectedContent = File.ReadAllText("testassets/init/multi-project.yaml"); |
|||
|
|||
output.WriteLine(content); |
|||
|
|||
Assert.Equal(expectedContent, content); |
|||
} |
|||
|
|||
[Fact] |
|||
public void FrontendBackendTest() |
|||
{ |
|||
var projectDirectory = new DirectoryInfo(Path.Combine(TestHelpers.GetSolutionRootDirectory("tye"), "samples", "frontend-backend")); |
|||
using var tempDirectory = TempDirectory.Create(); |
|||
DirectoryCopy.Copy(projectDirectory.FullName, tempDirectory.DirectoryPath); |
|||
|
|||
// delete already present yaml
|
|||
File.Delete(Path.Combine(tempDirectory.DirectoryPath, "tye.yaml")); |
|||
|
|||
var projectFile = new FileInfo(Path.Combine(tempDirectory.DirectoryPath, "frontend-backend.sln")); |
|||
|
|||
var (content, _) = InitHost.CreateTyeFileContent(projectFile, force: false); |
|||
var expectedContent = File.ReadAllText("testassets/init/frontend-backend.yaml"); |
|||
|
|||
output.WriteLine(content); |
|||
|
|||
Assert.Equal(expectedContent, content); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
# tye application configuration file |
|||
# read all about it at https://github.com/dotnet/tye |
|||
name: frontend-backend |
|||
services: |
|||
- name: backend |
|||
project: backend/backend.csproj |
|||
- name: frontend |
|||
project: frontend/frontend.csproj |
|||
@ -0,0 +1,10 @@ |
|||
# tye application configuration file |
|||
# read all about it at https://github.com/dotnet/tye |
|||
name: multi-project |
|||
services: |
|||
- name: backend |
|||
project: backend/backend.csproj |
|||
- name: frontend |
|||
project: frontend/frontend.csproj |
|||
- name: worker |
|||
project: worker/worker.csproj |
|||
@ -0,0 +1,6 @@ |
|||
# tye application configuration file |
|||
# read all about it at https://github.com/dotnet/tye |
|||
name: test-project |
|||
services: |
|||
- name: test-project |
|||
project: test-project.csproj |
|||
Loading…
Reference in new issue