Added CLI test project and tests for 'm4g init' command
This commit is contained in:
parent
4f322e56c7
commit
f676f236b1
19
.dockerignore
Normal file
19
.dockerignore
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# directories
|
||||||
|
**/bin/
|
||||||
|
**/obj/
|
||||||
|
**/out/
|
||||||
|
.git
|
||||||
|
.idea
|
||||||
|
docs
|
||||||
|
.gitignore
|
||||||
|
.dockerignore
|
||||||
|
MycroForge.sln.DotSettings.user
|
||||||
|
nuget.docker-compose.yml
|
||||||
|
README.md
|
||||||
|
|
||||||
|
# files
|
||||||
|
Dockerfile*
|
||||||
|
**/*.md
|
||||||
|
|
||||||
|
#MycroForge.PluginTemplate
|
||||||
|
#MycroForge.PluginTemplate.Package
|
30
Dockerfile
Normal file
30
Dockerfile
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim
|
||||||
|
|
||||||
|
# Copy the files to the /tool directory.
|
||||||
|
WORKDIR /tool
|
||||||
|
COPY . .
|
||||||
|
# Manually add a reference to MycroForge.Core in the MycroForge.PluginTemplate project,
|
||||||
|
# otherwise it will try to fetch it from a nuget repository.
|
||||||
|
RUN dotnet add MycroForge.PluginTemplate reference MycroForge.Core
|
||||||
|
|
||||||
|
# Install the tools required for testing
|
||||||
|
RUN apt update -y && \
|
||||||
|
apt upgrade -y && \
|
||||||
|
apt install -y git && \
|
||||||
|
apt install -y bash && \
|
||||||
|
apt install -y python3 && \
|
||||||
|
apt install -y python3-pip && \
|
||||||
|
apt install -y python3-venv
|
||||||
|
|
||||||
|
# Publish the CLI as a global tool and add the .dotnet/tools folder the the PATH variable.
|
||||||
|
WORKDIR /tool/MycroForge.CLI
|
||||||
|
RUN ./scripts/publish-tool.sh
|
||||||
|
ENV PATH="$PATH:/root/.dotnet/tools"
|
||||||
|
|
||||||
|
WORKDIR /test
|
||||||
|
|
||||||
|
SHELL ["/bin/bash", "-c"]
|
||||||
|
|
||||||
|
ENV PATH="$PATH:/root/.dotnet/tools"
|
||||||
|
|
||||||
|
CMD ["sleep", "infinity"]
|
@ -0,0 +1,11 @@
|
|||||||
|
using DotNet.Testcontainers.Containers;
|
||||||
|
|
||||||
|
namespace MycroForge.CLI.Tests.Extensions;
|
||||||
|
|
||||||
|
internal static class ContainerInterfaceExtensions
|
||||||
|
{
|
||||||
|
public static Task<byte[]> ReadFileFromRootAsync(this IContainer container, string file)
|
||||||
|
{
|
||||||
|
return container.ReadFileAsync($"/test/todo/{file}");
|
||||||
|
}
|
||||||
|
}
|
1
MycroForge.CLI.Tests/GlobalUsings.cs
Normal file
1
MycroForge.CLI.Tests/GlobalUsings.cs
Normal file
@ -0,0 +1 @@
|
|||||||
|
global using NUnit.Framework;
|
222
MycroForge.CLI.Tests/InitCommandTests.cs
Normal file
222
MycroForge.CLI.Tests/InitCommandTests.cs
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using DotNet.Testcontainers.Builders;
|
||||||
|
using DotNet.Testcontainers.Containers;
|
||||||
|
using DotNet.Testcontainers.Images;
|
||||||
|
using MycroForge.CLI.Tests.Extensions;
|
||||||
|
using MycroForge.Core;
|
||||||
|
|
||||||
|
namespace MycroForge.CLI.Tests;
|
||||||
|
|
||||||
|
public class InitCommandTests
|
||||||
|
{
|
||||||
|
private IFutureDockerImage Image = null!;
|
||||||
|
private IContainer Container = null!;
|
||||||
|
|
||||||
|
private async Task CreateImage()
|
||||||
|
{
|
||||||
|
Image = new ImageFromDockerfileBuilder()
|
||||||
|
.WithDockerfileDirectory(CommonDirectoryPath.GetSolutionDirectory(), string.Empty)
|
||||||
|
.WithDockerfile("Dockerfile")
|
||||||
|
.WithCleanUp(true)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
await Image.CreateAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CreateContainer()
|
||||||
|
{
|
||||||
|
Container = new ContainerBuilder()
|
||||||
|
.WithImage(Image)
|
||||||
|
.WithCleanUp(true)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
await Container.StartAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
[OneTimeSetUp]
|
||||||
|
public async Task SetupOnce()
|
||||||
|
{
|
||||||
|
await CreateImage();
|
||||||
|
|
||||||
|
await CreateContainer();
|
||||||
|
|
||||||
|
await Container.ExecAsync(["m4g", "init", "todo"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Creates_m4g_json()
|
||||||
|
{
|
||||||
|
var bytes = await Container.ReadFileFromRootAsync("m4g.json");
|
||||||
|
using var stream = new MemoryStream(bytes);
|
||||||
|
var config = await JsonSerializer.DeserializeAsync<ProjectConfig>(stream, DefaultJsonSerializerOptions.Default);
|
||||||
|
|
||||||
|
Assert.That(config, Is.Not.Null);
|
||||||
|
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(config!.Api, Is.Not.Null);
|
||||||
|
Assert.That(config.Api.Port, Is.EqualTo(8000));
|
||||||
|
Assert.That(config.Db, Is.Not.Null);
|
||||||
|
Assert.That(config.Db.DbhPort, Is.EqualTo(5050));
|
||||||
|
Assert.That(config.Db.DbuPort, Is.EqualTo(5051));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Creates_main_py()
|
||||||
|
{
|
||||||
|
var bytes = await Container.ReadFileFromRootAsync("main.py");
|
||||||
|
var text = Encoding.UTF8.GetString(bytes);
|
||||||
|
var lines = text.Split('\n');
|
||||||
|
|
||||||
|
TestContext.WriteLine(text);
|
||||||
|
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(text, Is.Not.Empty);
|
||||||
|
Assert.That(lines, Does.Contain("from fastapi import FastAPI"));
|
||||||
|
Assert.That(lines, Does.Contain("from api.routers import hello"));
|
||||||
|
Assert.That(lines, Does.Contain("app = FastAPI()"));
|
||||||
|
Assert.That(lines, Does.Contain("app.include_router(prefix=\"/hello\", router=hello.router)"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Creates_gitignore()
|
||||||
|
{
|
||||||
|
var bytes = await Container.ReadFileFromRootAsync(".gitignore");
|
||||||
|
var text = Encoding.UTF8.GetString(bytes);
|
||||||
|
var lines = text.Split('\n');
|
||||||
|
|
||||||
|
TestContext.WriteLine(text);
|
||||||
|
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(text, Is.Not.Empty);
|
||||||
|
Assert.That(lines, Does.Contain(".venv"));
|
||||||
|
Assert.That(lines, Does.Contain("__pycache__/"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Creates_alembic_ini()
|
||||||
|
{
|
||||||
|
var bytes = await Container.ReadFileFromRootAsync("alembic.ini");
|
||||||
|
var text = Encoding.UTF8.GetString(bytes);
|
||||||
|
var lines = text.Split('\n');
|
||||||
|
|
||||||
|
TestContext.WriteLine(text);
|
||||||
|
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(text, Is.Not.Empty);
|
||||||
|
Assert.That(lines, Does.Contain("[alembic]"));
|
||||||
|
Assert.That(lines, Does.Contain("sqlalchemy.url = driver://user:pass@localhost/dbname"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Creates_db_docker_compose_yml()
|
||||||
|
{
|
||||||
|
var bytes = await Container.ReadFileFromRootAsync("db.docker-compose.yml");
|
||||||
|
var text = Encoding.UTF8.GetString(bytes);
|
||||||
|
var lines = text.Split('\n');
|
||||||
|
|
||||||
|
TestContext.WriteLine(text);
|
||||||
|
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(text, Is.Not.Empty);
|
||||||
|
Assert.That(lines, Does.Contain(" todo_mariadb:"));
|
||||||
|
Assert.That(lines, Does.Contain(" container_name: 'todo_mariadb'"));
|
||||||
|
Assert.That(lines, Does.Contain(" - '${DBH_PORT}:3306'"));
|
||||||
|
Assert.That(lines, Does.Contain(" MYSQL_DATABASE: 'todo'"));
|
||||||
|
Assert.That(lines, Does.Contain(" - 'todo_mariadb:/var/lib/mysql'"));
|
||||||
|
Assert.That(lines, Does.Contain(" todo_phpmyadmin:"));
|
||||||
|
Assert.That(lines, Does.Contain(" container_name: todo_phpmyadmin"));
|
||||||
|
Assert.That(lines, Does.Contain(" PMA_HOST: todo_mariadb"));
|
||||||
|
Assert.That(lines, Does.Contain(" - todo_mariadb"));
|
||||||
|
Assert.That(lines, Does.Contain(" todo_mariadb:"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Creates_api__router_hello_py()
|
||||||
|
{
|
||||||
|
var bytes = await Container.ReadFileFromRootAsync("api/routers/hello.py");
|
||||||
|
var text = Encoding.UTF8.GetString(bytes);
|
||||||
|
var lines = text.Split('\n');
|
||||||
|
|
||||||
|
TestContext.WriteLine(text);
|
||||||
|
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(text, Is.Not.Empty);
|
||||||
|
Assert.That(lines, Does.Contain("from fastapi import APIRouter"));
|
||||||
|
Assert.That(lines, Does.Contain("from fastapi.responses import JSONResponse"));
|
||||||
|
Assert.That(lines, Does.Contain("from fastapi.encoders import jsonable_encoder"));
|
||||||
|
Assert.That(lines, Does.Contain("router = APIRouter()"));
|
||||||
|
Assert.That(lines, Does.Contain("@router.get(\"/{name}\")"));
|
||||||
|
Assert.That(lines, Does.Contain("async def hello(name: str):"));
|
||||||
|
Assert.That(lines, Does.Contain("\treturn JSONResponse(status_code=200, content=jsonable_encoder({'greeting': f\"Hello, {name}!\"}))"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Creates_db__engine__async_session_py()
|
||||||
|
{
|
||||||
|
var bytes = await Container.ReadFileFromRootAsync("db/engine/async_session.py");
|
||||||
|
var text = Encoding.UTF8.GetString(bytes);
|
||||||
|
var lines = text.Split('\n');
|
||||||
|
|
||||||
|
TestContext.WriteLine(text);
|
||||||
|
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(text, Is.Not.Empty);
|
||||||
|
Assert.That(lines, Does.Contain("from sqlalchemy.ext.asyncio import create_async_engine, AsyncEngine, AsyncSession"));
|
||||||
|
Assert.That(lines, Does.Contain("from db.settings import DbSettings"));
|
||||||
|
Assert.That(lines, Does.Contain("async_engine: AsyncEngine = create_async_engine(DbSettings.get_connectionstring())"));
|
||||||
|
Assert.That(lines, Does.Contain("def async_session() -> AsyncSession:"));
|
||||||
|
Assert.That(lines, Does.Contain("\treturn AsyncSession(async_engine, expire_on_commit=False)"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Creates_db__entities__entity_base_py()
|
||||||
|
{
|
||||||
|
var bytes = await Container.ReadFileFromRootAsync("db/entities/entity_base.py");
|
||||||
|
var text = Encoding.UTF8.GetString(bytes);
|
||||||
|
var lines = text.Split('\n');
|
||||||
|
|
||||||
|
TestContext.WriteLine(text);
|
||||||
|
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(text, Is.Not.Empty);
|
||||||
|
Assert.That(lines, Does.Contain("from sqlalchemy.orm import DeclarativeBase"));
|
||||||
|
Assert.That(lines, Does.Contain("class EntityBase(DeclarativeBase):"));
|
||||||
|
Assert.That(lines, Does.Contain("\tpass"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Creates_db__settings_py()
|
||||||
|
{
|
||||||
|
var bytes = await Container.ReadFileFromRootAsync("db/settings.py");
|
||||||
|
var text = Encoding.UTF8.GetString(bytes);
|
||||||
|
var lines = text.Split('\n');
|
||||||
|
|
||||||
|
TestContext.WriteLine(text);
|
||||||
|
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(text, Is.Not.Empty);
|
||||||
|
Assert.That(lines, Does.Contain("class DbSettings:"));
|
||||||
|
Assert.That(lines, Does.Contain("\tdef get_connectionstring() -> str:"));
|
||||||
|
Assert.That(lines, Does.Contain("\t\tconnectionstring = \"mysql+asyncmy://root:password@localhost:5050/todo\""));
|
||||||
|
Assert.That(lines, Does.Contain("\t\treturn connectionstring"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
25
MycroForge.CLI.Tests/MycroForge.CLI.Tests.csproj
Normal file
25
MycroForge.CLI.Tests/MycroForge.CLI.Tests.csproj
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<IsTestProject>true</IsTestProject>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0"/>
|
||||||
|
<PackageReference Include="NUnit" Version="3.13.3"/>
|
||||||
|
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1"/>
|
||||||
|
<PackageReference Include="NUnit.Analyzers" Version="3.6.1"/>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
|
||||||
|
<PackageReference Include="Testcontainers" Version="3.10.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\MycroForge.Core\MycroForge.Core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
dotnet pack -v d
|
dotnet pack -v d
|
||||||
|
|
||||||
|
17
MycroForge.Core/DefaultJsonSerializerOptions.cs
Normal file
17
MycroForge.Core/DefaultJsonSerializerOptions.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace MycroForge.Core;
|
||||||
|
|
||||||
|
public static class DefaultJsonSerializerOptions
|
||||||
|
{
|
||||||
|
public static readonly JsonSerializerOptions Default = new()
|
||||||
|
{
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly JsonSerializerOptions CamelCasePrettyPrint = new()
|
||||||
|
{
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||||
|
WriteIndented = true
|
||||||
|
};
|
||||||
|
}
|
@ -4,15 +4,12 @@ namespace MycroForge.Core.Extensions;
|
|||||||
|
|
||||||
public static class ObjectStreamExtensions
|
public static class ObjectStreamExtensions
|
||||||
{
|
{
|
||||||
public static async Task<string> SerializeAsync(
|
public static async Task<string> SerializeAsync(this object @object, JsonSerializerOptions? options = null)
|
||||||
this object @object,
|
|
||||||
JsonSerializerOptions? jsonSerializerOptions = null
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
using var stream = new MemoryStream();
|
using var stream = new MemoryStream();
|
||||||
using var reader = new StreamReader(stream);
|
using var reader = new StreamReader(stream);
|
||||||
var options = jsonSerializerOptions ?? Serialization.DefaultJsonSerializerOptions.Default;
|
options ??= DefaultJsonSerializerOptions.Default;
|
||||||
|
|
||||||
await JsonSerializer.SerializeAsync(stream, @object, options);
|
await JsonSerializer.SerializeAsync(stream, @object, options);
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
return await reader.ReadToEndAsync();
|
return await reader.ReadToEndAsync();
|
||||||
|
@ -21,8 +21,8 @@ public class ProjectContext
|
|||||||
}
|
}
|
||||||
|
|
||||||
var config = await JsonSerializer.DeserializeAsync<ProjectConfig>(
|
var config = await JsonSerializer.DeserializeAsync<ProjectConfig>(
|
||||||
File.OpenRead(ConfigPath),
|
File.OpenRead(ConfigPath),
|
||||||
Serialization.DefaultJsonSerializerOptions.CamelCasePrettyPrint
|
DefaultJsonSerializerOptions.CamelCasePrettyPrint
|
||||||
);
|
);
|
||||||
|
|
||||||
if (config is null)
|
if (config is null)
|
||||||
@ -116,7 +116,7 @@ public class ProjectContext
|
|||||||
|
|
||||||
public async Task SaveConfig(ProjectConfig config)
|
public async Task SaveConfig(ProjectConfig config)
|
||||||
{
|
{
|
||||||
var json = await config.SerializeAsync(Serialization.DefaultJsonSerializerOptions.CamelCasePrettyPrint);
|
var json = await config.SerializeAsync(DefaultJsonSerializerOptions.CamelCasePrettyPrint);
|
||||||
await File.WriteAllTextAsync(ConfigPath, json);
|
await File.WriteAllTextAsync(ConfigPath, json);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,20 +0,0 @@
|
|||||||
using System.Text.Json;
|
|
||||||
|
|
||||||
namespace MycroForge.Core;
|
|
||||||
|
|
||||||
public static class Serialization
|
|
||||||
{
|
|
||||||
public static class DefaultJsonSerializerOptions
|
|
||||||
{
|
|
||||||
public static readonly JsonSerializerOptions Default = new()
|
|
||||||
{
|
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
|
||||||
};
|
|
||||||
|
|
||||||
public static readonly JsonSerializerOptions CamelCasePrettyPrint = new()
|
|
||||||
{
|
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
||||||
WriteIndented = true
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -8,6 +8,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MycroForge.PluginTemplate",
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MycroForge.PluginTemplate.Package", "MycroForge.PluginTemplate.Package\MycroForge.PluginTemplate.Package.csproj", "{1C5C5B9A-3C90-4FE7-A1AC-2F46C3CD0D69}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MycroForge.PluginTemplate.Package", "MycroForge.PluginTemplate.Package\MycroForge.PluginTemplate.Package.csproj", "{1C5C5B9A-3C90-4FE7-A1AC-2F46C3CD0D69}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MycroForge.CLI.Tests", "MycroForge.CLI.Tests\MycroForge.CLI.Tests.csproj", "{71A7EA9D-3C12-4FDE-BA4F-BDD1961DDA1B}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -30,5 +32,9 @@ Global
|
|||||||
{1C5C5B9A-3C90-4FE7-A1AC-2F46C3CD0D69}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{1C5C5B9A-3C90-4FE7-A1AC-2F46C3CD0D69}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{1C5C5B9A-3C90-4FE7-A1AC-2F46C3CD0D69}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{1C5C5B9A-3C90-4FE7-A1AC-2F46C3CD0D69}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{1C5C5B9A-3C90-4FE7-A1AC-2F46C3CD0D69}.Release|Any CPU.Build.0 = Release|Any CPU
|
{1C5C5B9A-3C90-4FE7-A1AC-2F46C3CD0D69}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{71A7EA9D-3C12-4FDE-BA4F-BDD1961DDA1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{71A7EA9D-3C12-4FDE-BA4F-BDD1961DDA1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{71A7EA9D-3C12-4FDE-BA4F-BDD1961DDA1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{71A7EA9D-3C12-4FDE-BA4F-BDD1961DDA1B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
Loading…
Reference in New Issue
Block a user