parent
1b2010768e
commit
cfcffd8251
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"files.associations": {
|
||||
"*.*proj": "xml",
|
||||
"*.props": "xml",
|
||||
"*.targets": "xml",
|
||||
"*.tasks": "xml"
|
||||
}
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"files.associations": {
|
||||
"*.*proj": "xml",
|
||||
"*.props": "xml",
|
||||
"*.targets": "xml",
|
||||
"*.tasks": "xml"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
<!-- These projects are meant to be executed by tests. -->
|
||||
<ProjectToExclude Include="
|
||||
$(RepoRoot)src\Tools\dotnet-watch\test\TestProjects\**\*.csproj;
|
||||
$(RepoRoot)src\Tools\Tests.Common\TestProjects\**\*.csproj;
|
||||
$(RepoRoot)src\Razor\Razor.Design\test\testassets\**\*.*proj;
|
||||
$(RepoRoot)src\submodules\**\*.*proj;
|
||||
$(RepoRoot)src\Installers\**\*.*proj;
|
||||
|
|
|
|||
|
|
@ -149,7 +149,9 @@ and are generated based on the last package release.
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup Label="MSBuild">
|
||||
<LatestPackageReference Include="Microsoft.Build" Version="$(MicrosoftBuildPackageVersion)" />
|
||||
<LatestPackageReference Include="Microsoft.Build.Framework" Version="$(MicrosoftBuildFrameworkPackageVersion)" />
|
||||
<LatestPackageReference Include="Microsoft.Build.Locator" Version="$(MicrosoftBuildLocatorPackageVersion)" />
|
||||
<LatestPackageReference Include="Microsoft.Build.Utilities.Core" Version="$(MicrosoftBuildUtilitiesCorePackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
@ -172,6 +174,7 @@ and are generated based on the last package release.
|
|||
<LatestPackageReference Include="Moq" Version="$(MoqPackageVersion)" />
|
||||
<LatestPackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonPackageVersion)" />
|
||||
<LatestPackageReference Include="Newtonsoft.Json.Bson" Version="$(NewtonsoftJsonBsonPackageVersion)" />
|
||||
<LatestPackageReference Include="NSwag.ApiDescription.Client" Version="$(NSwagApiDescriptionClientPackageVersion)" />
|
||||
<LatestPackageReference Include="Selenium.Support" Version="$(SeleniumSupportPackageVersion)" />
|
||||
<LatestPackageReference Include="Selenium.WebDriver" Version="$(SeleniumWebDriverPackageVersion)" />
|
||||
<LatestPackageReference Include="Selenium.WebDriver.ChromeDriver" Version="$(SeleniumWebDriverChromeDriverPackageVersion)" />
|
||||
|
|
|
|||
|
|
@ -97,6 +97,12 @@
|
|||
<_DotNetFilesToExclude Include="$(RedistNetCorePath)dotnet.exe" CertificateName="None" />
|
||||
<FileSignInfo Include="@(_DotNetFilesToExclude->'%(FileName)%(Extension)'->Distinct())" CertificateName="None" />
|
||||
|
||||
<!--
|
||||
We include the Microsoft.Build.Locator.dll assembly in our global tool 'Microsoft.dotnet-openapi'.
|
||||
It is already signed by that team, so we don't need to sign it.
|
||||
-->
|
||||
<FileSignInfo Include="Microsoft.Build.Locator.dll" CertificateName="None" />
|
||||
|
||||
<!--
|
||||
We include the Microsoft.Data.SqlClient.dll assembly in our global tool 'dotnet-sql-cache'.
|
||||
It is already signed by that team, so we don't need to sign it.
|
||||
|
|
|
|||
|
|
@ -196,7 +196,9 @@
|
|||
<!-- Partner teams -->
|
||||
<MicrosoftAzureKeyVaultPackageVersion>2.3.2</MicrosoftAzureKeyVaultPackageVersion>
|
||||
<MicrosoftAzureStorageBlobPackageVersion>10.0.1</MicrosoftAzureStorageBlobPackageVersion>
|
||||
<MicrosoftBuildPackageVersion>15.8.166</MicrosoftBuildPackageVersion>
|
||||
<MicrosoftBuildFrameworkPackageVersion>15.8.166</MicrosoftBuildFrameworkPackageVersion>
|
||||
<MicrosoftBuildLocatorPackageVersion>1.2.6</MicrosoftBuildLocatorPackageVersion>
|
||||
<MicrosoftBuildUtilitiesCorePackageVersion>15.8.166</MicrosoftBuildUtilitiesCorePackageVersion>
|
||||
<MicrosoftCodeAnalysisCommonPackageVersion>3.0.0</MicrosoftCodeAnalysisCommonPackageVersion>
|
||||
<MicrosoftCodeAnalysisCSharpPackageVersion>3.0.0</MicrosoftCodeAnalysisCSharpPackageVersion>
|
||||
|
|
@ -232,6 +234,7 @@
|
|||
<MonoCecilPackageVersion>0.10.1</MonoCecilPackageVersion>
|
||||
<NewtonsoftJsonBsonPackageVersion>1.0.2</NewtonsoftJsonBsonPackageVersion>
|
||||
<NewtonsoftJsonPackageVersion>12.0.1</NewtonsoftJsonPackageVersion>
|
||||
<NSwagApiDescriptionClientPackageVersion>13.0.4</NSwagApiDescriptionClientPackageVersion>
|
||||
<SeleniumSupportPackageVersion>3.12.1</SeleniumSupportPackageVersion>
|
||||
<SeleniumWebDriverMicrosoftDriverPackageVersion>17.17134.0</SeleniumWebDriverMicrosoftDriverPackageVersion>
|
||||
<SeleniumWebDriverChromeDriverPackageVersion>2.43.0</SeleniumWebDriverChromeDriverPackageVersion>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
|
@ -41,42 +42,56 @@ namespace Microsoft.Extensions.Internal
|
|||
|
||||
private static void GetAllChildIdsUnix(int parentId, ISet<int> children, TimeSpan timeout)
|
||||
{
|
||||
RunProcessAndWaitForExit(
|
||||
"pgrep",
|
||||
$"-P {parentId}",
|
||||
timeout,
|
||||
out var stdout);
|
||||
|
||||
if (!string.IsNullOrEmpty(stdout))
|
||||
try
|
||||
{
|
||||
using (var reader = new StringReader(stdout))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var text = reader.ReadLine();
|
||||
if (text == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
RunProcessAndWaitForExit(
|
||||
"pgrep",
|
||||
$"-P {parentId}",
|
||||
timeout,
|
||||
out var stdout);
|
||||
|
||||
if (int.TryParse(text, out var id))
|
||||
if (!string.IsNullOrEmpty(stdout))
|
||||
{
|
||||
using (var reader = new StringReader(stdout))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
children.Add(id);
|
||||
// Recursively get the children
|
||||
GetAllChildIdsUnix(id, children, timeout);
|
||||
var text = reader.ReadLine();
|
||||
if (text == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (int.TryParse(text, out var id))
|
||||
{
|
||||
children.Add(id);
|
||||
// Recursively get the children
|
||||
GetAllChildIdsUnix(id, children, timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Win32Exception ex) when (ex.Message.Contains("No such file or directory"))
|
||||
{
|
||||
// This probably means that pgrep isn't installed. Nothing to be done?
|
||||
}
|
||||
}
|
||||
|
||||
private static void KillProcessUnix(int processId, TimeSpan timeout)
|
||||
{
|
||||
RunProcessAndWaitForExit(
|
||||
"kill",
|
||||
$"-TERM {processId}",
|
||||
timeout,
|
||||
out var stdout);
|
||||
try
|
||||
{
|
||||
RunProcessAndWaitForExit(
|
||||
"kill",
|
||||
$"-TERM {processId}",
|
||||
timeout,
|
||||
out var stdout);
|
||||
}
|
||||
catch (Win32Exception ex) when (ex.Message.Contains("No such file or directory"))
|
||||
{
|
||||
// This probably means that the process is already dead
|
||||
}
|
||||
}
|
||||
|
||||
private static void RunProcessAndWaitForExit(string fileName, string arguments, TimeSpan timeout, out string stdout)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
# Microsoft.dotnet-openapi
|
||||
|
||||
`Microsoft.dotnet-openapi` is a tool for managing OpenAPI references within your project.
|
||||
|
||||
## Commands
|
||||
|
||||
### Add Commands
|
||||
|
||||
<!-- TODO: Restore after https://github.com/aspnet/AspNetCore/issues/12738
|
||||
#### Add Project
|
||||
|
||||
##### Options
|
||||
|
||||
| Short option | Long option | Description | Example |
|
||||
|-------|------|-------|---------|
|
||||
| -v|--verbose | Show verbose output. |dotnet openapi add project *-v* ../Ref/ProjRef.csproj |
|
||||
| -p|--project | The project to operate on. |dotnet openapi add project *--project .\Ref.csproj* ../Ref/ProjRef.csproj |
|
||||
|
||||
##### Arguments
|
||||
|
||||
| Argument | Description | Example |
|
||||
|-------------|-------------|---------|
|
||||
| source-file | The source to create a reference from. Must be a project file. |dotnet openapi add project *../Ref/ProjRef.csproj* | -->
|
||||
|
||||
#### Add File
|
||||
|
||||
##### Options
|
||||
|
||||
| Short option| Long option| Description | Example |
|
||||
|-------|------|-------|---------|
|
||||
| -v|--verbose | Show verbose output. |dotnet openapi add file *-v* .\OpenAPI.json |
|
||||
| -p|--updateProject | The project to operate on. |dotnet openapi add file *--updateProject .\Ref.csproj* .\OpenAPI.json |
|
||||
|
||||
##### Arguments
|
||||
|
||||
| Argument | Description | Example |
|
||||
|-------------|-------------|---------|
|
||||
| source-file | The source to create a reference from. Must be an OpenAPI file. |dotnet openapi add file *.\OpenAPI.json* |
|
||||
|
||||
#### Add URL
|
||||
|
||||
##### Options
|
||||
|
||||
| Short option| Long option| Description | Example |
|
||||
|-------|------|-------------|---------|
|
||||
| -v|--verbose | Show verbose output. |dotnet openapi add url *-v* <http://contoso.com/openapi.json> |
|
||||
| -p|--updateProject | The project to operate on. |dotnet openapi add url *--updateProject .\Ref.csproj* <http://contoso.com/openapi.json> |
|
||||
| -o|--output-file | Where to place the local copy of the OpenAPI file. |dotnet openapi add url <https://contoso.com/openapi.json> *--output-file myclient.json* |
|
||||
|
||||
##### Arguments
|
||||
|
||||
| Argument | Description | Example |
|
||||
|-------------|-------------|---------|
|
||||
| source-file | The source to create a reference from. Must be a URL. |dotnet openapi add url <https://contoso.com/openapi.json> |
|
||||
|
||||
### Remove
|
||||
|
||||
##### Options
|
||||
|
||||
| Short option| Long option| Description| Example |
|
||||
|-------|------|------------|---------|
|
||||
| -v|--verbose | Show verbose output. |dotnet openapi remove *-v*|
|
||||
| -p|--updateProject | The project to operate on. |dotnet openapi remove *--updateProject .\Ref.csproj* .\OpenAPI.json |
|
||||
|
||||
#### Arguments
|
||||
|
||||
| Argument | Description| Example |
|
||||
| ------------|------------|---------|
|
||||
| source-file | The source to remove the reference to. |dotnet openapi remove *.\OpenAPI.json* |
|
||||
|
||||
### Refresh
|
||||
|
||||
#### Options
|
||||
|
||||
| Short option| Long option| Description | Example |
|
||||
|-------|------|-------------|---------|
|
||||
| -v|--verbose | Show verbose output. | dotnet openapi refresh *-v* <https://contoso.com/openapi.json> |
|
||||
| -p|--updateProject | The project to operate on. | dotnet openapi refresh *--updateProject .\Ref.csproj* <https://contoso.com/openapi.json> |
|
||||
|
||||
#### Arguments
|
||||
|
||||
| Argument | Description | Example |
|
||||
| ------------|-------------|---------|
|
||||
| source-file | The URL to refresh the reference from. | dotnet openapi refresh *<https://contoso.com/openapi.json>* |
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Microsoft.Build.Locator;
|
||||
using Microsoft.DotNet.Openapi.Tools;
|
||||
using Microsoft.DotNet.OpenApi.Commands;
|
||||
using Microsoft.Extensions.CommandLineUtils;
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi
|
||||
{
|
||||
internal class Application : CommandLineApplication
|
||||
{
|
||||
static Application()
|
||||
{
|
||||
MSBuildLocator.RegisterDefaults();
|
||||
}
|
||||
|
||||
public Application(
|
||||
string workingDirectory,
|
||||
IHttpClientWrapper httpClient,
|
||||
TextWriter output = null,
|
||||
TextWriter error = null)
|
||||
{
|
||||
Out = output ?? Out;
|
||||
Error = error ?? Error;
|
||||
|
||||
WorkingDirectory = workingDirectory;
|
||||
|
||||
Name = "openapi";
|
||||
FullName = "OpenApi reference management tool";
|
||||
Description = "OpenApi reference management operations.";
|
||||
ShortVersionGetter = GetInformationalVersion;
|
||||
|
||||
Help = HelpOption("-?|-h|--help");
|
||||
Help.Inherited = true;
|
||||
|
||||
Invoke = () =>
|
||||
{
|
||||
ShowHelp();
|
||||
return 0;
|
||||
};
|
||||
|
||||
Commands.Add(new AddCommand(this, httpClient));
|
||||
Commands.Add(new RemoveCommand(this, httpClient));
|
||||
Commands.Add(new RefreshCommand(this, httpClient));
|
||||
}
|
||||
|
||||
public string WorkingDirectory { get; }
|
||||
|
||||
public CommandOption Help { get; }
|
||||
|
||||
public new int Execute(params string[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
return base.Execute(args);
|
||||
}
|
||||
catch (AggregateException ex) when (ex.InnerException != null)
|
||||
{
|
||||
foreach (var innerException in ex.InnerExceptions)
|
||||
{
|
||||
Error.WriteLine(ex.InnerException.Message);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
// Don't show a call stack when we have unneeded arguments, just print the error message.
|
||||
// The code that throws this exception will print help, so no need to do it here.
|
||||
Error.WriteLine(ex.Message);
|
||||
return 1;
|
||||
}
|
||||
catch (CommandParsingException ex)
|
||||
{
|
||||
// Don't show a call stack when we have unneeded arguments, just print the error message.
|
||||
// The code that throws this exception will print help, so no need to do it here.
|
||||
Error.WriteLine(ex.Message);
|
||||
return 1;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// This is a cancellation, not a failure.
|
||||
Error.WriteLine("Cancelled");
|
||||
return 1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Error.WriteLine(ex);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private string GetInformationalVersion()
|
||||
{
|
||||
var assembly = typeof(Application).GetTypeInfo().Assembly;
|
||||
var attribute = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
|
||||
return attribute.InformationalVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi
|
||||
{
|
||||
public enum CodeGenerator
|
||||
{
|
||||
NSwagCSharp,
|
||||
NSwagTypeScript
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.DotNet.Openapi.Tools;
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi.Commands
|
||||
{
|
||||
internal class AddCommand : BaseCommand
|
||||
{
|
||||
private const string CommandName = "add";
|
||||
|
||||
public AddCommand(Application parent, IHttpClientWrapper httpClient)
|
||||
: base(parent, CommandName, httpClient)
|
||||
{
|
||||
Commands.Add(new AddFileCommand(this, httpClient));
|
||||
//TODO: Add AddprojectComand here: https://github.com/aspnet/AspNetCore/issues/12738
|
||||
Commands.Add(new AddURLCommand(this, httpClient));
|
||||
}
|
||||
|
||||
internal new Application Parent => (Application)base.Parent;
|
||||
|
||||
protected override Task<int> ExecuteCoreAsync()
|
||||
{
|
||||
ShowHelp();
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
protected override bool ValidateArguments()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.DotNet.Openapi.Tools;
|
||||
using Microsoft.Extensions.CommandLineUtils;
|
||||
using Microsoft.Extensions.Tools.Internal;
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi.Commands
|
||||
{
|
||||
internal class AddFileCommand : BaseCommand
|
||||
{
|
||||
private const string CommandName = "file";
|
||||
|
||||
private const string SourceFileArgName = "source-file";
|
||||
|
||||
public AddFileCommand(AddCommand parent, IHttpClientWrapper httpClient)
|
||||
: base(parent, CommandName, httpClient)
|
||||
{
|
||||
_codeGeneratorOption = Option("-c|--code-generator", "The code generator to use. Defaults to 'NSwagCSharp'.", CommandOptionType.SingleValue);
|
||||
_sourceFileArg = Argument(SourceFileArgName, $"The OpenAPI file to add. This must be a path to local OpenAPI file(s)", multipleValues: true);
|
||||
}
|
||||
|
||||
internal readonly CommandArgument _sourceFileArg;
|
||||
internal readonly CommandOption _codeGeneratorOption;
|
||||
|
||||
private readonly string[] ApprovedExtensions = new[] { ".json", ".yaml", ".yml" };
|
||||
|
||||
protected override async Task<int> ExecuteCoreAsync()
|
||||
{
|
||||
var projectFilePath = ResolveProjectFile(ProjectFileOption);
|
||||
|
||||
Ensure.NotNullOrEmpty(_sourceFileArg.Value, SourceFileArgName);
|
||||
var codeGenerator = GetCodeGenerator(_codeGeneratorOption);
|
||||
|
||||
foreach (var sourceFile in _sourceFileArg.Values)
|
||||
{
|
||||
if (!ApprovedExtensions.Any(e => sourceFile.EndsWith(e)))
|
||||
{
|
||||
await Warning.WriteLineAsync($"The extension for the given file '{sourceFile}' should have been one of: {string.Join(",", ApprovedExtensions)}.");
|
||||
await Warning.WriteLineAsync($"The reference has been added, but may fail at build-time if the format is not correct.");
|
||||
}
|
||||
await AddOpenAPIReference(OpenApiReference, projectFilePath, sourceFile, codeGenerator);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private bool IsLocalFile(string file)
|
||||
{
|
||||
return File.Exists(GetFullPath(file));
|
||||
}
|
||||
|
||||
protected override bool ValidateArguments()
|
||||
{
|
||||
ValidateCodeGenerator(_codeGeneratorOption);
|
||||
|
||||
try
|
||||
{
|
||||
Ensure.NotNullOrEmpty(_sourceFileArg.Value, SourceFileArgName);
|
||||
}
|
||||
catch(ArgumentException ex)
|
||||
{
|
||||
Error.Write(ex.Message);
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var sourceFile in _sourceFileArg.Values)
|
||||
{
|
||||
if (!IsLocalFile(sourceFile))
|
||||
{
|
||||
Error.Write($"{SourceFileArgName} of '{sourceFile}' could not be found.");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.DotNet.Openapi.Tools;
|
||||
using Microsoft.Extensions.CommandLineUtils;
|
||||
using Microsoft.Extensions.Tools.Internal;
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi.Commands
|
||||
{
|
||||
internal class AddProjectCommand : BaseCommand
|
||||
{
|
||||
private const string CommandName = "project";
|
||||
|
||||
private const string SourceProjectArgName = "source-project";
|
||||
|
||||
public AddProjectCommand(BaseCommand parent, IHttpClientWrapper httpClient)
|
||||
: base(parent, CommandName, httpClient)
|
||||
{
|
||||
_codeGeneratorOption = Option("-c|--code-generator", "The code generator to use. Defaults to 'NSwagCSharp'.", CommandOptionType.SingleValue);
|
||||
_sourceProjectArg = Argument(SourceProjectArgName, $"The OpenAPI project to add. This must be the path to project file(s) containing OpenAPI endpoints", multipleValues: true);
|
||||
}
|
||||
|
||||
internal readonly CommandArgument _sourceProjectArg;
|
||||
internal readonly CommandOption _codeGeneratorOption;
|
||||
|
||||
protected override async Task<int> ExecuteCoreAsync()
|
||||
{
|
||||
var projectFilePath = ResolveProjectFile(ProjectFileOption);
|
||||
|
||||
var codeGenerator = GetCodeGenerator(_codeGeneratorOption);
|
||||
|
||||
foreach (var sourceFile in _sourceProjectArg.Values)
|
||||
{
|
||||
await AddOpenAPIReference(OpenApiProjectReference, projectFilePath, sourceFile, codeGenerator);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override bool ValidateArguments()
|
||||
{
|
||||
ValidateCodeGenerator(_codeGeneratorOption);
|
||||
foreach (var sourceFile in _sourceProjectArg.Values)
|
||||
{
|
||||
if (!IsProjectFile(sourceFile))
|
||||
{
|
||||
throw new ArgumentException($"{SourceProjectArgName} of '{sourceFile}' was not valid. Valid values must be project file(s)");
|
||||
}
|
||||
}
|
||||
|
||||
Ensure.NotNullOrEmpty(_sourceProjectArg.Value, SourceProjectArgName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.DotNet.Openapi.Tools;
|
||||
using Microsoft.Extensions.CommandLineUtils;
|
||||
using Microsoft.Extensions.Tools.Internal;
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi.Commands
|
||||
{
|
||||
internal class AddURLCommand : BaseCommand
|
||||
{
|
||||
private const string CommandName = "url";
|
||||
|
||||
private const string OutputFileName = "--output-file";
|
||||
private const string SourceUrlArgName = "source-URL";
|
||||
|
||||
public AddURLCommand(AddCommand parent, IHttpClientWrapper httpClient)
|
||||
: base(parent, CommandName, httpClient)
|
||||
{
|
||||
_codeGeneratorOption = Option("-c|--code-generator", "The code generator to use. Defaults to 'NSwagCSharp'.", CommandOptionType.SingleValue);
|
||||
_outputFileOption = Option(OutputFileName, "The destination to download the remote OpenAPI file to.", CommandOptionType.SingleValue);
|
||||
_sourceFileArg = Argument(SourceUrlArgName, $"The OpenAPI file to add. This must be a URL to a remote OpenAPI file.", multipleValues: true);
|
||||
}
|
||||
|
||||
internal readonly CommandOption _outputFileOption;
|
||||
|
||||
internal readonly CommandArgument _sourceFileArg;
|
||||
internal readonly CommandOption _codeGeneratorOption;
|
||||
|
||||
protected override async Task<int> ExecuteCoreAsync()
|
||||
{
|
||||
var projectFilePath = ResolveProjectFile(ProjectFileOption);
|
||||
|
||||
var sourceFile = Ensure.NotNullOrEmpty(_sourceFileArg.Value, SourceUrlArgName);
|
||||
var codeGenerator = GetCodeGenerator(_codeGeneratorOption);
|
||||
|
||||
// We have to download the file from that URL, save it to a local file, then create a OpenApiReference
|
||||
var outputFile = await DownloadGivenOption(sourceFile, _outputFileOption);
|
||||
|
||||
await AddOpenAPIReference(OpenApiReference, projectFilePath, outputFile, codeGenerator, sourceFile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override bool ValidateArguments()
|
||||
{
|
||||
ValidateCodeGenerator(_codeGeneratorOption);
|
||||
var sourceFile = Ensure.NotNullOrEmpty(_sourceFileArg.Value, SourceUrlArgName);
|
||||
if (!IsUrl(sourceFile))
|
||||
{
|
||||
Error.Write($"{SourceUrlArgName} was not valid. Valid values are URLs");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,538 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Build.Evaluation;
|
||||
using Microsoft.DotNet.Openapi.Tools;
|
||||
using Microsoft.DotNet.Openapi.Tools.Internal;
|
||||
using Microsoft.Extensions.CommandLineUtils;
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi.Commands
|
||||
{
|
||||
internal abstract class BaseCommand : CommandLineApplication
|
||||
{
|
||||
protected string WorkingDirectory;
|
||||
|
||||
protected readonly IHttpClientWrapper _httpClient;
|
||||
|
||||
public const string OpenApiReference = "OpenApiReference";
|
||||
public const string OpenApiProjectReference = "OpenApiProjectReference";
|
||||
protected const string SourceUrlAttrName = "SourceUrl";
|
||||
|
||||
public const string ContentDispositionHeaderName = "Content-Disposition";
|
||||
private const string CodeGeneratorAttrName = "CodeGenerator";
|
||||
private const string DefaultExtension = ".json";
|
||||
|
||||
internal const string PackageVersionUrl = "https://go.microsoft.com/fwlink/?linkid=2099561";
|
||||
|
||||
public BaseCommand(CommandLineApplication parent, string name, IHttpClientWrapper httpClient)
|
||||
{
|
||||
Parent = parent;
|
||||
Name = name;
|
||||
Out = parent.Out ?? Out;
|
||||
Error = parent.Error ?? Error;
|
||||
_httpClient = httpClient;
|
||||
|
||||
ProjectFileOption = Option("-p|--updateProject", "The project file update.", CommandOptionType.SingleValue);
|
||||
|
||||
if (Parent is Application)
|
||||
{
|
||||
WorkingDirectory = ((Application)Parent).WorkingDirectory;
|
||||
}
|
||||
else
|
||||
{
|
||||
WorkingDirectory = ((Application)Parent.Parent).WorkingDirectory;
|
||||
}
|
||||
|
||||
OnExecute(ExecuteAsync);
|
||||
}
|
||||
|
||||
public CommandOption ProjectFileOption { get; }
|
||||
|
||||
public TextWriter Warning
|
||||
{
|
||||
get { return Out; }
|
||||
}
|
||||
|
||||
protected abstract Task<int> ExecuteCoreAsync();
|
||||
|
||||
protected abstract bool ValidateArguments();
|
||||
|
||||
private async Task<int> ExecuteAsync()
|
||||
{
|
||||
if (GetApplication().Help.HasValue())
|
||||
{
|
||||
ShowHelp();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ValidateArguments())
|
||||
{
|
||||
ShowHelp();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return await ExecuteCoreAsync();
|
||||
}
|
||||
|
||||
private Application GetApplication()
|
||||
{
|
||||
var parent = Parent;
|
||||
while(!(parent is Application))
|
||||
{
|
||||
parent = parent.Parent;
|
||||
}
|
||||
return (Application)parent;
|
||||
}
|
||||
|
||||
internal FileInfo ResolveProjectFile(CommandOption projectOption)
|
||||
{
|
||||
string project;
|
||||
if (projectOption.HasValue())
|
||||
{
|
||||
project = projectOption.Value();
|
||||
project = GetFullPath(project);
|
||||
if (!File.Exists(project))
|
||||
{
|
||||
throw new ArgumentException($"The project '{project}' does not exist.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var projects = Directory.GetFiles(WorkingDirectory, "*.csproj", SearchOption.TopDirectoryOnly);
|
||||
if (projects.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("No project files were found in the current directory. Either move to a new directory or provide the project explicitly");
|
||||
}
|
||||
if (projects.Length > 1)
|
||||
{
|
||||
throw new ArgumentException("More than one project was found in this directory, either remove a duplicate or explicitly provide the project.");
|
||||
}
|
||||
|
||||
project = projects[0];
|
||||
}
|
||||
|
||||
return new FileInfo(project);
|
||||
}
|
||||
|
||||
protected Project LoadProject(FileInfo projectFile)
|
||||
{
|
||||
var project = ProjectCollection.GlobalProjectCollection.LoadProject(
|
||||
projectFile.FullName,
|
||||
globalProperties: null,
|
||||
toolsVersion: null);
|
||||
project.ReevaluateIfNecessary();
|
||||
return project;
|
||||
}
|
||||
|
||||
internal bool IsProjectFile(string file)
|
||||
{
|
||||
return File.Exists(Path.GetFullPath(file)) && file.EndsWith(".csproj");
|
||||
}
|
||||
|
||||
internal bool IsUrl(string file)
|
||||
{
|
||||
return Uri.TryCreate(file, UriKind.Absolute, out var _) && file.StartsWith("http");
|
||||
}
|
||||
|
||||
internal async Task AddOpenAPIReference(
|
||||
string tagName,
|
||||
FileInfo projectFile,
|
||||
string sourceFile,
|
||||
CodeGenerator? codeGenerator,
|
||||
string sourceUrl = null)
|
||||
{
|
||||
// EnsurePackagesInProjectAsync MUST happen before LoadProject, because otherwise the global state set by ProjectCollection doesn't pick up the nuget edits, and we end up losing them.
|
||||
await EnsurePackagesInProjectAsync(projectFile, codeGenerator);
|
||||
var project = LoadProject(projectFile);
|
||||
var items = project.GetItems(tagName);
|
||||
var fileItems = items.Where(i => string.Equals(GetFullPath(i.EvaluatedInclude), GetFullPath(sourceFile), StringComparison.Ordinal));
|
||||
|
||||
if (fileItems.Count() > 0)
|
||||
{
|
||||
Warning.Write($"One or more references to {sourceFile} already exist in '{project.FullPath}'. Duplicate references could lead to unexpected behavior.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sourceUrl != null)
|
||||
{
|
||||
if (items.Any(i => string.Equals(i.GetMetadataValue(SourceUrlAttrName), sourceUrl)))
|
||||
{
|
||||
Warning.Write($"A reference to '{sourceUrl}' already exists in '{project.FullPath}'.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var metadata = new Dictionary<string, string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(sourceUrl))
|
||||
{
|
||||
metadata[SourceUrlAttrName] = sourceUrl;
|
||||
}
|
||||
|
||||
if (codeGenerator != null)
|
||||
{
|
||||
metadata[CodeGeneratorAttrName] = codeGenerator.ToString();
|
||||
}
|
||||
|
||||
project.AddElementWithAttributes(tagName, sourceFile, metadata);
|
||||
project.Save();
|
||||
}
|
||||
|
||||
private async Task EnsurePackagesInProjectAsync(FileInfo projectFile, CodeGenerator? codeGenerator)
|
||||
{
|
||||
var urlPackages = await LoadPackageVersionsFromURLAsync();
|
||||
var attributePackages = GetServicePackages(codeGenerator);
|
||||
|
||||
foreach (var kvp in attributePackages)
|
||||
{
|
||||
var packageId = kvp.Key;
|
||||
var version = urlPackages != null && urlPackages.ContainsKey(packageId) ? urlPackages[packageId] : kvp.Value;
|
||||
|
||||
var args = new[] {
|
||||
"add",
|
||||
"package",
|
||||
packageId,
|
||||
"--version",
|
||||
version,
|
||||
"--no-restore"
|
||||
};
|
||||
|
||||
var muxer = DotNetMuxer.MuxerPathOrDefault();
|
||||
if (string.IsNullOrEmpty(muxer))
|
||||
{
|
||||
throw new ArgumentException($"dotnet was not found on the path.");
|
||||
}
|
||||
|
||||
var startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = muxer,
|
||||
Arguments = string.Join(" ", args),
|
||||
WorkingDirectory = projectFile.Directory.FullName,
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardOutput = true,
|
||||
};
|
||||
|
||||
var process = Process.Start(startInfo);
|
||||
|
||||
var timeout = 20;
|
||||
if (!process.WaitForExit(timeout * 1000))
|
||||
{
|
||||
throw new ArgumentException($"Adding package `{packageId}` to `{projectFile.Directory}` took longer than {timeout} seconds.");
|
||||
}
|
||||
|
||||
if (process.ExitCode != 0)
|
||||
{
|
||||
Out.Write(process.StandardOutput.ReadToEnd());
|
||||
Error.Write(process.StandardError.ReadToEnd());
|
||||
throw new ArgumentException($"Could not add package `{packageId}` to `{projectFile.Directory}`");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task DownloadToFileAsync(string url, string destinationPath, bool overwrite)
|
||||
{
|
||||
using var response = await _httpClient.GetResponseAsync(url);
|
||||
await WriteToFileAsync(await response.Stream, destinationPath, overwrite);
|
||||
}
|
||||
|
||||
internal async Task<string> DownloadGivenOption(string url, CommandOption fileOption)
|
||||
{
|
||||
using var response = await _httpClient.GetResponseAsync(url);
|
||||
|
||||
if (response.IsSuccessCode())
|
||||
{
|
||||
string destinationPath;
|
||||
if (fileOption.HasValue())
|
||||
{
|
||||
destinationPath = fileOption.Value();
|
||||
}
|
||||
else
|
||||
{
|
||||
var fileName = GetFileNameFromResponse(response, url);
|
||||
var fullPath = GetFullPath(fileName);
|
||||
var directory = Path.GetDirectoryName(fullPath);
|
||||
destinationPath = GetUniqueFileName(directory, Path.GetFileNameWithoutExtension(fileName), Path.GetExtension(fileName));
|
||||
}
|
||||
await WriteToFileAsync(await response.Stream, GetFullPath(destinationPath), overwrite: false);
|
||||
|
||||
return destinationPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"The given url returned '{response.StatusCode}', indicating failure. The url might be wrong, or there might be a networking issue.");
|
||||
}
|
||||
}
|
||||
|
||||
private string GetUniqueFileName(string directory, string fileName, string extension)
|
||||
{
|
||||
var uniqueName = fileName;
|
||||
|
||||
var filePath = Path.Combine(directory, fileName + extension);
|
||||
var exists = true;
|
||||
var count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
exists = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
count++;
|
||||
uniqueName = fileName + count;
|
||||
filePath = Path.Combine(directory, uniqueName + extension);
|
||||
}
|
||||
}
|
||||
while (exists);
|
||||
|
||||
return uniqueName + extension;
|
||||
}
|
||||
|
||||
private string GetFileNameFromResponse(IHttpResponseMessageWrapper response, string url)
|
||||
{
|
||||
var contentDisposition = response.ContentDisposition();
|
||||
string result;
|
||||
if (contentDisposition != null && contentDisposition.FileName != null)
|
||||
{
|
||||
var fileName = Path.GetFileName(contentDisposition.FileName);
|
||||
if (!Path.HasExtension(fileName))
|
||||
{
|
||||
fileName += DefaultExtension;
|
||||
}
|
||||
|
||||
result = fileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
var uri = new Uri(url);
|
||||
if (uri.Segments.Count() > 0 && uri.Segments.Last() != "/")
|
||||
{
|
||||
var lastSegment = uri.Segments.Last();
|
||||
if (!Path.HasExtension(lastSegment))
|
||||
{
|
||||
lastSegment += DefaultExtension;
|
||||
}
|
||||
|
||||
result = lastSegment;
|
||||
}
|
||||
else
|
||||
{
|
||||
var parts = uri.Host.Split('.');
|
||||
|
||||
// There's no segment, use the domain name.
|
||||
string domain;
|
||||
switch (parts.Length)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
// It's localhost if 1, no www if 2
|
||||
domain = parts.First();
|
||||
break;
|
||||
case 3:
|
||||
domain = parts[1];
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException("We don't handle the case that the Host has more than three segments");
|
||||
}
|
||||
|
||||
result = domain + DefaultExtension;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CodeGenerator? GetCodeGenerator(CommandOption codeGeneratorOption)
|
||||
{
|
||||
CodeGenerator? codeGenerator;
|
||||
if (codeGeneratorOption.HasValue())
|
||||
{
|
||||
codeGenerator = Enum.Parse<CodeGenerator>(codeGeneratorOption.Value());
|
||||
}
|
||||
else
|
||||
{
|
||||
codeGenerator = null;
|
||||
}
|
||||
|
||||
return codeGenerator;
|
||||
}
|
||||
|
||||
internal void ValidateCodeGenerator(CommandOption codeGeneratorOption)
|
||||
{
|
||||
if (codeGeneratorOption.HasValue())
|
||||
{
|
||||
var value = codeGeneratorOption.Value();
|
||||
if (!Enum.TryParse(value, out CodeGenerator _))
|
||||
{
|
||||
throw new ArgumentException($"Invalid value '{value}' given as code generator.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal string GetFullPath(string path)
|
||||
{
|
||||
return Path.IsPathFullyQualified(path)
|
||||
? path
|
||||
: Path.GetFullPath(path, WorkingDirectory);
|
||||
}
|
||||
|
||||
private async Task<IDictionary<string, string>> LoadPackageVersionsFromURLAsync()
|
||||
{
|
||||
/* Example Json content
|
||||
{
|
||||
"Version" : "1.0",
|
||||
"Packages" : {
|
||||
"Microsoft.Azure.SignalR": "1.1.0-preview1-10442",
|
||||
"Grpc.AspNetCore.Server": "0.1.22-pre2",
|
||||
"Grpc.Net.ClientFactory": "0.1.22-pre2",
|
||||
"Google.Protobuf": "3.8.0",
|
||||
"Grpc.Tools": "1.22.0",
|
||||
"NSwag.ApiDescription.Client": "13.0.3",
|
||||
"Microsoft.Extensions.ApiDescription.Client": "0.3.0-preview7.19365.7",
|
||||
"Newtonsoft.Json": "12.0.2"
|
||||
}
|
||||
}*/
|
||||
try
|
||||
{
|
||||
using var packageVersionStream = await (await _httpClient.GetResponseAsync(PackageVersionUrl)).Stream;
|
||||
using var packageVersionDocument = await JsonDocument.ParseAsync(packageVersionStream);
|
||||
var packageVersionsElement = packageVersionDocument.RootElement.GetProperty("Packages");
|
||||
var packageVersionsDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (var packageVersion in packageVersionsElement.EnumerateObject())
|
||||
{
|
||||
packageVersionsDictionary[packageVersion.Name] = packageVersion.Value.GetString();
|
||||
}
|
||||
|
||||
return packageVersionsDictionary;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// TODO (johluo): Consider logging a message indicating what went wrong and actions, if any, to be taken to resolve possible issues.
|
||||
// Currently not logging anything since the fwlink is not published yet.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static IDictionary<string, string> GetServicePackages(CodeGenerator? type)
|
||||
{
|
||||
CodeGenerator generator = type ?? CodeGenerator.NSwagCSharp;
|
||||
var name = Enum.GetName(typeof(CodeGenerator), generator);
|
||||
var attributes = typeof(Program).Assembly.GetCustomAttributes<OpenApiDependencyAttribute>();
|
||||
|
||||
var packages = attributes.Where(a => a.CodeGenerators.Contains(generator));
|
||||
var result = new Dictionary<string, string>();
|
||||
if (packages != null)
|
||||
{
|
||||
foreach (var package in packages)
|
||||
{
|
||||
result[package.Name] = package.Version;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static byte[] GetHash(Stream stream)
|
||||
{
|
||||
SHA256 algorithm;
|
||||
try
|
||||
{
|
||||
algorithm = SHA256.Create();
|
||||
}
|
||||
catch (TargetInvocationException)
|
||||
{
|
||||
// SHA256.Create is documented to throw this exception on FIPS-compliant machines. See
|
||||
// https://msdn.microsoft.com/en-us/library/z08hz7ad Fall back to a FIPS-compliant SHA256 algorithm.
|
||||
algorithm = new SHA256CryptoServiceProvider();
|
||||
}
|
||||
|
||||
using (algorithm)
|
||||
{
|
||||
return algorithm.ComputeHash(stream);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task WriteToFileAsync(Stream content, string destinationPath, bool overwrite)
|
||||
{
|
||||
if (content.CanSeek)
|
||||
{
|
||||
content.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
destinationPath = GetFullPath(destinationPath);
|
||||
var destinationExists = File.Exists(destinationPath);
|
||||
if (destinationExists && !overwrite)
|
||||
{
|
||||
throw new ArgumentException($"File '{destinationPath}' already exists. Aborting to avoid conflicts. Provide the '--output-file' argument with an unused file to resolve.");
|
||||
}
|
||||
|
||||
await Out.WriteLineAsync($"Downloading to '{destinationPath}'.");
|
||||
var reachedCopy = false;
|
||||
try
|
||||
{
|
||||
if (destinationExists)
|
||||
{
|
||||
// Check hashes before using the downloaded information.
|
||||
var downloadHash = GetHash(content);
|
||||
|
||||
byte[] destinationHash;
|
||||
using (var destinationStream = File.OpenRead(destinationPath))
|
||||
{
|
||||
destinationHash = GetHash(destinationStream);
|
||||
}
|
||||
|
||||
var sameHashes = downloadHash.Length == destinationHash.Length;
|
||||
for (var i = 0; sameHashes && i < downloadHash.Length; i++)
|
||||
{
|
||||
sameHashes = downloadHash[i] == destinationHash[i];
|
||||
}
|
||||
|
||||
if (sameHashes)
|
||||
{
|
||||
await Out.WriteLineAsync($"Not overwriting existing and matching file '{destinationPath}'.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// May need to create directory to hold the file.
|
||||
var destinationDirectory = Path.GetDirectoryName(destinationPath);
|
||||
if (!string.IsNullOrEmpty(destinationDirectory) && !Directory.Exists(destinationDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(destinationDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
// Create or overwrite the destination file.
|
||||
reachedCopy = true;
|
||||
using var fileStream = new FileStream(destinationPath, FileMode.OpenOrCreate, FileAccess.Write);
|
||||
fileStream.Seek(0, SeekOrigin.Begin);
|
||||
if (content.CanSeek)
|
||||
{
|
||||
content.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
await content.CopyToAsync(fileStream);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Error.WriteLineAsync($"Downloading failed.");
|
||||
await Error.WriteLineAsync(ex.ToString());
|
||||
if (reachedCopy)
|
||||
{
|
||||
File.Delete(destinationPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Build.Evaluation;
|
||||
using Microsoft.DotNet.Openapi.Tools;
|
||||
using Microsoft.Extensions.CommandLineUtils;
|
||||
using Microsoft.Extensions.Tools.Internal;
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi.Commands
|
||||
{
|
||||
internal class RefreshCommand : BaseCommand
|
||||
{
|
||||
private const string CommandName = "refresh";
|
||||
|
||||
private const string SourceURLArgName = "source-URL";
|
||||
|
||||
public RefreshCommand(Application parent, IHttpClientWrapper httpClient) : base(parent, CommandName, httpClient)
|
||||
{
|
||||
_sourceFileArg = Argument(SourceURLArgName, $"The OpenAPI reference to refresh.");
|
||||
}
|
||||
|
||||
internal readonly CommandArgument _sourceFileArg;
|
||||
|
||||
protected override async Task<int> ExecuteCoreAsync()
|
||||
{
|
||||
var projectFile = ResolveProjectFile(ProjectFileOption);
|
||||
|
||||
var sourceFile = Ensure.NotNullOrEmpty(_sourceFileArg.Value, SourceURLArgName);
|
||||
|
||||
var destination = FindReferenceFromUrl(projectFile, sourceFile);
|
||||
await DownloadToFileAsync(sourceFile, destination, overwrite: true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private string FindReferenceFromUrl(FileInfo projectFile, string url)
|
||||
{
|
||||
var project = LoadProject(projectFile);
|
||||
var openApiReferenceItems = project.GetItems(OpenApiReference);
|
||||
|
||||
foreach (ProjectItem item in openApiReferenceItems)
|
||||
{
|
||||
var attrUrl = item.GetMetadataValue(SourceUrlAttrName);
|
||||
if (string.Equals(attrUrl, url, StringComparison.Ordinal))
|
||||
{
|
||||
return item.EvaluatedInclude;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArgumentException("There was no OpenAPI reference to refresh with the given URL.");
|
||||
}
|
||||
|
||||
protected override bool ValidateArguments()
|
||||
{
|
||||
var sourceFile = Ensure.NotNullOrEmpty(_sourceFileArg.Value, SourceURLArgName);
|
||||
if (!IsUrl(sourceFile))
|
||||
{
|
||||
throw new ArgumentException($"'dotnet openapi refresh' must be given a URL");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Build.Evaluation;
|
||||
using Microsoft.DotNet.Openapi.Tools;
|
||||
using Microsoft.Extensions.CommandLineUtils;
|
||||
using Microsoft.Extensions.Tools.Internal;
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi.Commands
|
||||
{
|
||||
internal class RemoveCommand : BaseCommand
|
||||
{
|
||||
private const string CommandName = "remove";
|
||||
|
||||
private const string SourceArgName = "soruce";
|
||||
|
||||
public RemoveCommand(Application parent, IHttpClientWrapper httpClient) : base(parent, CommandName, httpClient)
|
||||
{
|
||||
_sourceProjectArg = Argument(SourceArgName, $"The OpenAPI reference to remove. Must represent a reference which is already in this project", multipleValues: true);
|
||||
}
|
||||
|
||||
internal readonly CommandArgument _sourceProjectArg;
|
||||
|
||||
protected override Task<int> ExecuteCoreAsync()
|
||||
{
|
||||
var projectFile = ResolveProjectFile(ProjectFileOption);
|
||||
|
||||
var sourceFile = Ensure.NotNullOrEmpty(_sourceProjectArg.Value, SourceArgName);
|
||||
|
||||
if (IsProjectFile(sourceFile))
|
||||
{
|
||||
RemoveServiceReference(OpenApiProjectReference, projectFile, sourceFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
var file = RemoveServiceReference(OpenApiReference, projectFile, sourceFile);
|
||||
|
||||
if (file != null)
|
||||
{
|
||||
File.Delete(GetFullPath(file));
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
private string RemoveServiceReference(string tagName, FileInfo projectFile, string sourceFile)
|
||||
{
|
||||
var project = LoadProject(projectFile);
|
||||
var openApiReferenceItems = project.GetItems(tagName);
|
||||
|
||||
foreach (ProjectItem item in openApiReferenceItems)
|
||||
{
|
||||
var include = item.EvaluatedInclude;
|
||||
var sourceUrl = item.HasMetadata(SourceUrlAttrName) ? item.GetMetadataValue(SourceUrlAttrName) : null;
|
||||
if (string.Equals(include, sourceFile, StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(sourceUrl, sourceFile, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
project.RemoveItem(item);
|
||||
project.Save();
|
||||
return include;
|
||||
}
|
||||
}
|
||||
|
||||
Warning.Write($"No OpenAPI reference was found with the file '{sourceFile}'");
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override bool ValidateArguments()
|
||||
{
|
||||
Ensure.NotNullOrEmpty(_sourceProjectArg.Value, SourceArgName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi
|
||||
{
|
||||
internal static class DebugMode
|
||||
{
|
||||
public static void HandleDebugSwitch(ref string[] args)
|
||||
{
|
||||
if (args.Length > 0 && string.Equals("--debug", args[0], StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
args = args.Skip(1).ToArray();
|
||||
|
||||
Console.WriteLine("Waiting for debugger in pid: {0}", Process.GetCurrentProcess().Id);
|
||||
while (!Debugger.IsAttached)
|
||||
{
|
||||
Thread.Sleep(TimeSpan.FromSeconds(3));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.DotNet.OpenApi;
|
||||
using Microsoft.DotNet.OpenApi.Commands;
|
||||
|
||||
namespace Microsoft.DotNet.Openapi.Tools
|
||||
{
|
||||
public class HttpClientWrapper : IHttpClientWrapper
|
||||
{
|
||||
private readonly HttpClient _client;
|
||||
|
||||
public HttpClientWrapper(HttpClient client)
|
||||
{
|
||||
_client = client;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_client.Dispose();
|
||||
}
|
||||
|
||||
public async Task<IHttpResponseMessageWrapper> GetResponseAsync(string url)
|
||||
{
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
return new HttpResponseMessageWrapper(response);
|
||||
}
|
||||
|
||||
public Task<Stream> GetStreamAsync(string url)
|
||||
{
|
||||
return _client.GetStreamAsync(url);
|
||||
}
|
||||
}
|
||||
|
||||
public class HttpResponseMessageWrapper : IHttpResponseMessageWrapper
|
||||
{
|
||||
private HttpResponseMessage _response;
|
||||
|
||||
public HttpResponseMessageWrapper(HttpResponseMessage response)
|
||||
{
|
||||
_response = response;
|
||||
}
|
||||
|
||||
public Task<Stream> Stream => _response.Content.ReadAsStreamAsync();
|
||||
|
||||
public HttpStatusCode StatusCode => _response.StatusCode;
|
||||
|
||||
public bool IsSuccessCode() => _response.IsSuccessStatusCode;
|
||||
|
||||
public ContentDispositionHeaderValue ContentDisposition()
|
||||
{
|
||||
if (_response.Headers.TryGetValues(BaseCommand.ContentDispositionHeaderName, out var disposition))
|
||||
{
|
||||
return new ContentDispositionHeaderValue(disposition.First());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_response.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.DotNet.OpenApi;
|
||||
|
||||
namespace Microsoft.DotNet.Openapi.Tools
|
||||
{
|
||||
internal interface IHttpClientWrapper : IDisposable
|
||||
{
|
||||
Task<IHttpResponseMessageWrapper> GetResponseAsync(string url);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi
|
||||
{
|
||||
public interface IHttpResponseMessageWrapper : IDisposable
|
||||
{
|
||||
Task<Stream> Stream { get; }
|
||||
ContentDispositionHeaderValue ContentDisposition();
|
||||
HttpStatusCode StatusCode { get; }
|
||||
bool IsSuccessCode();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.DotNet.OpenApi;
|
||||
|
||||
namespace Microsoft.DotNet.Openapi.Tools.Internal
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
|
||||
internal class OpenApiDependencyAttribute : Attribute
|
||||
{
|
||||
public OpenApiDependencyAttribute(string name, string version, string codeGenerators)
|
||||
{
|
||||
Name = name;
|
||||
Version = version;
|
||||
CodeGenerators = codeGenerators.Split(';', StringSplitOptions.RemoveEmptyEntries).Select(c => Enum.Parse<CodeGenerator>(c)).ToArray();
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Version { get; set; }
|
||||
public IEnumerable<CodeGenerator> CodeGenerators { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<OutputType>exe</OutputType>
|
||||
<Description>Command line tool to add an OpenAPI service reference</Description>
|
||||
<RootNamespace>Microsoft.DotNet.Openapi.Tools</RootNamespace>
|
||||
<AssemblyName>dotnet-openapi</AssemblyName>
|
||||
<PackageId>Microsoft.dotnet-openapi</PackageId>
|
||||
<PackAsTool>true</PackAsTool>
|
||||
<!-- This package is for internal use only. It contains a CLI tool. -->
|
||||
<IsShippingPackage>false</IsShippingPackage>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="$(ToolSharedSourceRoot)CommandLine\**\*.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Build" ExcludeAssets="runtime" />
|
||||
<Reference Include="Microsoft.Build.Locator" />
|
||||
<Reference Include="Microsoft.Extensions.CommandLineUtils.Sources" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AssemblyAttribute Include="Microsoft.DotNet.Openapi.Tools.Internal.OpenApiDependencyAttribute">
|
||||
<_Parameter1>NSwag.ApiDescription.Client</_Parameter1>
|
||||
<_Parameter2>$(NSwagApiDescriptionClientPackageVersion)</_Parameter2>
|
||||
<_Parameter3>NSwagCSharp;NSwagTypeScript</_Parameter3>
|
||||
</AssemblyAttribute>
|
||||
<AssemblyAttribute Include="Microsoft.DotNet.Openapi.Tools.Internal.OpenApiDependencyAttribute">
|
||||
<_Parameter1>Newtonsoft.Json</_Parameter1>
|
||||
<_Parameter2>$(NewtonsoftJsonPackageVersion)</_Parameter2>
|
||||
<_Parameter3>NSwagCSharp;NSwagTypeScript</_Parameter3>
|
||||
</AssemblyAttribute>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using Microsoft.DotNet.Openapi.Tools;
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
var outputWriter = new StringWriter();
|
||||
var errorWriter = new StringWriter();
|
||||
|
||||
DebugMode.HandleDebugSwitch(ref args);
|
||||
|
||||
try
|
||||
{
|
||||
using var httpClient = new HttpClientWrapper(new HttpClient());
|
||||
var application = new Application(
|
||||
Directory.GetCurrentDirectory(),
|
||||
httpClient,
|
||||
outputWriter,
|
||||
errorWriter);
|
||||
|
||||
var result = application.Execute(args);
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorWriter.Write("Unexpected error:");
|
||||
errorWriter.WriteLine(ex.ToString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
var output = outputWriter.ToString();
|
||||
var error = errorWriter.ToString();
|
||||
|
||||
outputWriter.Dispose();
|
||||
errorWriter.Dispose();
|
||||
|
||||
Console.WriteLine(output);
|
||||
Console.Error.WriteLine(error);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Build.Evaluation;
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi
|
||||
{
|
||||
public static class ProjectExtensions
|
||||
{
|
||||
public static void AddElementWithAttributes(this Project project, string tagName, string include, IDictionary<string, string> metadata)
|
||||
{
|
||||
var item = project.AddItem(tagName, include).Single();
|
||||
foreach (var kvp in metadata)
|
||||
{
|
||||
item.Xml.AddMetadata(kvp.Key, kvp.Value, expressAsAttribute: true);
|
||||
}
|
||||
|
||||
project.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Microsoft.DotNet.Open.Api.Tools.Tests, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||
|
|
@ -0,0 +1,254 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Microsoft.DotNet.OpenApi.Tests;
|
||||
using Microsoft.Extensions.Internal;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi.Add.Tests
|
||||
{
|
||||
public class OpenApiAddFileTests : OpenApiTestBase
|
||||
{
|
||||
public OpenApiAddFileTests(ITestOutputHelper output) : base(output) { }
|
||||
|
||||
[Fact]
|
||||
public void OpenApi_Empty_ShowsHelp()
|
||||
{
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new string[] { });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
Assert.Contains("Usage: openapi ", _output.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenApi_NoProjectExists()
|
||||
{
|
||||
var app = GetApplication();
|
||||
_tempDir.Create();
|
||||
var run = app.Execute(new string[] { "add", "file", "randomfile.json" });
|
||||
|
||||
Assert.Contains("No project files were found in the current directory", _error.ToString());
|
||||
Assert.Equal(1, run);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenApi_ExplicitProject_Missing()
|
||||
{
|
||||
var app = GetApplication();
|
||||
_tempDir.Create();
|
||||
var csproj = "fake.csproj";
|
||||
var run = app.Execute(new string[] { "add", "file", "--updateProject", csproj, "randomfile.json" });
|
||||
|
||||
Assert.Contains($"The project '{Path.Combine(_tempDir.Root, csproj)}' does not exist.", _error.ToString());
|
||||
Assert.Equal(1, run);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenApi_Add_Empty_ShowsHelp()
|
||||
{
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new string[] { "add" });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
Assert.Contains("Usage: openapi add", _output.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenApi_Add_File_Empty_ShowsHelp()
|
||||
{
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new string[] { "add", "file", "--help" });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
Assert.Contains("Usage: openapi ", _output.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenApi_Add_ReuseItemGroup()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: true);
|
||||
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new[] { "add", "file", project.NSwagJsonFile });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
var secondRun = app.Execute(new[] { "add", "url", FakeOpenApiUrl });
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, secondRun);
|
||||
|
||||
var csproj = new FileInfo(project.Project.Path);
|
||||
string content;
|
||||
using (var csprojStream = csproj.OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains($"<OpenApiReference Include=\"{project.NSwagJsonFile}\"", content);
|
||||
}
|
||||
var projXml = new XmlDocument();
|
||||
projXml.Load(csproj.FullName);
|
||||
|
||||
var openApiRefs = projXml.GetElementsByTagName(Commands.BaseCommand.OpenApiReference);
|
||||
Assert.Same(openApiRefs[0].ParentNode, openApiRefs[1].ParentNode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenApi_Add_File_EquivilentPaths()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: true);
|
||||
var nswagJsonFile = project.NSwagJsonFile;
|
||||
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new[] { "add", "file", nswagJsonFile });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
app = GetApplication();
|
||||
var absolute = Path.GetFullPath(nswagJsonFile, project.Project.Dir().Root);
|
||||
run = app.Execute(new[] { "add", "file", absolute });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
var csproj = new FileInfo(project.Project.Path);
|
||||
var projXml = new XmlDocument();
|
||||
projXml.Load(csproj.FullName);
|
||||
|
||||
var openApiRefs = projXml.GetElementsByTagName(Commands.BaseCommand.OpenApiReference);
|
||||
Assert.Single(openApiRefs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenApi_Add_NSwagTypeScript()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: true);
|
||||
var nswagJsonFile = project.NSwagJsonFile;
|
||||
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new[] { "add", "file", nswagJsonFile, "--code-generator", "NSwagTypeScript" });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
// csproj contents
|
||||
var csproj = new FileInfo(project.Project.Path);
|
||||
using (var csprojStream = csproj.OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains($"<OpenApiReference Include=\"{nswagJsonFile}\" CodeGenerator=\"NSwagTypeScript\" />", content);
|
||||
}
|
||||
|
||||
// Build project and make sure it compiles
|
||||
using var buildProc = ProcessEx.Run(_outputHelper, _tempDir.Root, "dotnet", "build");
|
||||
await buildProc.Exited;
|
||||
Assert.True(buildProc.ExitCode == 0, $"Build failed: {buildProc.Output}");
|
||||
|
||||
|
||||
// Run project and make sure it doesn't crash
|
||||
using var runProc = ProcessEx.Run(_outputHelper, _tempDir.Root, "dotnet", "run");
|
||||
Thread.Sleep(100);
|
||||
Assert.False(runProc.HasExited, $"Run failed with: {runProc.Output}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenApi_Add_FromJson()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: true);
|
||||
var nswagJsonFile = project.NSwagJsonFile;
|
||||
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new[] { "add", "file", nswagJsonFile });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
// csproj contents
|
||||
var csproj = new FileInfo(project.Project.Path);
|
||||
using (var csprojStream = csproj.OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains($"<OpenApiReference Include=\"{nswagJsonFile}\"", content);
|
||||
}
|
||||
|
||||
// Build project and make sure it compiles
|
||||
var buildProc = ProcessEx.Run(_outputHelper, _tempDir.Root, "dotnet", "build");
|
||||
await buildProc.Exited;
|
||||
Assert.True(buildProc.ExitCode == 0, $"Build failed: {buildProc.Output}");
|
||||
|
||||
// Run project and make sure it doesn't crash
|
||||
using var runProc = ProcessEx.Run(_outputHelper, _tempDir.Root, "dotnet", "run");
|
||||
Thread.Sleep(100);
|
||||
Assert.False(runProc.HasExited, $"Run failed with: {runProc.Output}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenApi_Add_File_UseProjectOption()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: true);
|
||||
var nswagJsonFIle = project.NSwagJsonFile;
|
||||
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new[] { "add", "file", "--updateProject", project.Project.Path, nswagJsonFIle });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
// csproj contents
|
||||
var csproj = new FileInfo(project.Project.Path);
|
||||
using var csprojStream = csproj.OpenRead();
|
||||
using var reader = new StreamReader(csprojStream);
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains($"<OpenApiReference Include=\"{nswagJsonFIle}\"", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenApi_Add_MultipleTimes_OnlyOneReference()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: true);
|
||||
var nswagJsonFile = project.NSwagJsonFile;
|
||||
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new[] { "add", "file", nswagJsonFile });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
app = GetApplication();
|
||||
run = app.Execute(new[] { "add", "file", nswagJsonFile });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
// csproj contents
|
||||
var csproj = new FileInfo(project.Project.Path);
|
||||
using var csprojStream = csproj.OpenRead();
|
||||
using var reader = new StreamReader(csprojStream);
|
||||
var content = await reader.ReadToEndAsync();
|
||||
var escapedPkgRef = Regex.Escape("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"");
|
||||
Assert.Single(Regex.Matches(content, escapedPkgRef));
|
||||
var escapedApiRef = Regex.Escape($"<OpenApiReference Include=\"{nswagJsonFile}\"");
|
||||
Assert.Single(Regex.Matches(content, escapedApiRef));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Microsoft.DotNet.OpenApi.Tests;
|
||||
using Microsoft.Extensions.Tools.Internal;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi.Add.Tests
|
||||
{
|
||||
public class OpenApiAddProjectTests : OpenApiTestBase
|
||||
{
|
||||
public OpenApiAddProjectTests(ITestOutputHelper output) : base(output){}
|
||||
|
||||
[Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/12738")]
|
||||
public async Task OpenApi_Add_GlobbingOpenApi()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: true);
|
||||
|
||||
using (var refProj1 = project.Project.Dir().SubDir("refProj1"))
|
||||
using (var refProj2 = project.Project.Dir().SubDir("refProj2"))
|
||||
{
|
||||
var project1 = refProj1.WithCSharpProject("refProj");
|
||||
project1
|
||||
.WithTargetFrameworks("netcoreapp3.0")
|
||||
.Dir()
|
||||
.Create();
|
||||
|
||||
var project2 = refProj2.WithCSharpProject("refProj2");
|
||||
project2
|
||||
.WithTargetFrameworks("netcoreapp3.0")
|
||||
.Dir()
|
||||
.Create();
|
||||
|
||||
var app = GetApplication();
|
||||
|
||||
var run = app.Execute(new[] { "add", "project", project1.Path, project2.Path});
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
// csproj contents
|
||||
using (var csprojStream = new FileInfo(project.Project.Path).OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains($"<OpenApiProjectReference Include=\"{project1.Path}\"", content);
|
||||
Assert.Contains($"<OpenApiProjectReference Include=\"{project2.Path}\"", content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/12738")]
|
||||
public void OpenApi_Add_Project_EquivilentPaths()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: false);
|
||||
|
||||
using (var refProj = new TemporaryDirectory())
|
||||
{
|
||||
var refProjName = "refProj";
|
||||
var csproj = refProj.WithCSharpProject(refProjName);
|
||||
csproj
|
||||
.WithTargetFrameworks("netcoreapp3.0")
|
||||
.Dir()
|
||||
.Create();
|
||||
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new[] { "add", "project", csproj.Path});
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
app = GetApplication();
|
||||
run = app.Execute(new[] { "add", "project", Path.Combine(csproj.Path, "..", "refProj.csproj")});
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
var projXml = new XmlDocument();
|
||||
projXml.Load(project.Project.Path);
|
||||
|
||||
var openApiRefs = projXml.GetElementsByTagName(Commands.BaseCommand.OpenApiProjectReference);
|
||||
Assert.Single(openApiRefs);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/12738")]
|
||||
public async Task OpenApi_Add_FromCsProj()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: false);
|
||||
|
||||
using (var refProj = new TemporaryDirectory())
|
||||
{
|
||||
var refProjName = "refProj";
|
||||
refProj
|
||||
.WithCSharpProject(refProjName)
|
||||
.WithTargetFrameworks("netcoreapp3.0")
|
||||
.Dir()
|
||||
.Create();
|
||||
|
||||
var app = GetApplication();
|
||||
var refProjFile = Path.Join(refProj.Root, $"{refProjName}.csproj");
|
||||
var run = app.Execute(new[] { "add", "project", refProjFile });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
// csproj contents
|
||||
using(var csprojStream = new FileInfo(project.Project.Path).OpenRead())
|
||||
using(var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains($"<OpenApiProjectReference Include=\"{refProjFile}\"", content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,493 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.DotNet.OpenApi.Tests;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi.Add.Tests
|
||||
{
|
||||
public class OpenApiAddURLTests : OpenApiTestBase
|
||||
{
|
||||
public OpenApiAddURLTests(ITestOutputHelper output) : base(output){ }
|
||||
|
||||
[Fact]
|
||||
public async Task OpenApi_Add_Url_WithContentDisposition()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: false);
|
||||
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new[] { "add", "url", FakeOpenApiUrl });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
var expectedJsonName = "filename.json";
|
||||
|
||||
// csproj contents
|
||||
using (var csprojStream = new FileInfo(project.Project.Path).OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains(
|
||||
$@"<OpenApiReference Include=""{expectedJsonName}"" SourceUrl=""{FakeOpenApiUrl}"" />", content);
|
||||
}
|
||||
|
||||
var jsonFile = Path.Combine(_tempDir.Root, expectedJsonName);
|
||||
Assert.True(File.Exists(jsonFile));
|
||||
using (var jsonStream = new FileInfo(jsonFile).OpenRead())
|
||||
using (var reader = new StreamReader(jsonStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Equal(Content, content);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenAPI_Add_Url_NoContentDisposition()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: false);
|
||||
var url = NoDispositionUrl;
|
||||
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new[] { "add", "url", url});
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
var expectedJsonName = "nodisposition.yaml";
|
||||
|
||||
// csproj contents
|
||||
using (var csprojStream = new FileInfo(project.Project.Path).OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains(
|
||||
$@"<OpenApiReference Include=""{expectedJsonName}"" SourceUrl=""{url}"" />", content);
|
||||
}
|
||||
|
||||
var jsonFile = Path.Combine(_tempDir.Root, expectedJsonName);
|
||||
Assert.True(File.Exists(jsonFile));
|
||||
using (var jsonStream = new FileInfo(jsonFile).OpenRead())
|
||||
using (var reader = new StreamReader(jsonStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Equal(Content, content);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenAPI_Add_Url_NoExtension_AssumesJson()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: false);
|
||||
var url = NoExtensionUrl;
|
||||
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new[] { "add", "url", url });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
var expectedJsonName = "filename.json";
|
||||
|
||||
// csproj contents
|
||||
using (var csprojStream = new FileInfo(project.Project.Path).OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains(
|
||||
$@"<OpenApiReference Include=""{expectedJsonName}"" SourceUrl=""{url}"" />", content);
|
||||
}
|
||||
|
||||
var jsonFile = Path.Combine(_tempDir.Root, expectedJsonName);
|
||||
Assert.True(File.Exists(jsonFile));
|
||||
using (var jsonStream = new FileInfo(jsonFile).OpenRead())
|
||||
using (var reader = new StreamReader(jsonStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Equal(Content, content);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenApi_Add_Url_NoSegment()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: false);
|
||||
var url = NoSegmentUrl;
|
||||
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new[] { "add", "url", url });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
var expectedJsonName = "contoso.json";
|
||||
|
||||
// csproj contents
|
||||
using (var csprojStream = new FileInfo(project.Project.Path).OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains(
|
||||
$@"<OpenApiReference Include=""{expectedJsonName}"" SourceUrl=""{url}"" />", content);
|
||||
}
|
||||
|
||||
var jsonFile = Path.Combine(_tempDir.Root, expectedJsonName);
|
||||
Assert.True(File.Exists(jsonFile));
|
||||
using (var jsonStream = new FileInfo(jsonFile).OpenRead())
|
||||
using (var reader = new StreamReader(jsonStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Equal(Content, content);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenApi_Add_Url()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: false);
|
||||
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new[] { "add", "url", FakeOpenApiUrl });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
var expectedJsonName = "filename.json";
|
||||
|
||||
// csproj contents
|
||||
using (var csprojStream = new FileInfo(project.Project.Path).OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains(
|
||||
$@"<OpenApiReference Include=""{expectedJsonName}"" SourceUrl=""{FakeOpenApiUrl}"" />", content);
|
||||
}
|
||||
|
||||
var jsonFile = Path.Combine(_tempDir.Root, expectedJsonName);
|
||||
Assert.True(File.Exists(jsonFile));
|
||||
using (var jsonStream = new FileInfo(jsonFile).OpenRead())
|
||||
using (var reader = new StreamReader(jsonStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Equal(Content, content);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenApi_Add_Url_SameName_UniqueFile()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: false);
|
||||
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new[] { "add", "url", FakeOpenApiUrl });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
var firstExpectedJsonName = "filename.json";
|
||||
|
||||
// csproj contents
|
||||
using (var csprojStream = new FileInfo(project.Project.Path).OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains(
|
||||
$@"<OpenApiReference Include=""{firstExpectedJsonName}"" SourceUrl=""{FakeOpenApiUrl}"" />", content);
|
||||
}
|
||||
|
||||
var firstJsonFile = Path.Combine(_tempDir.Root, firstExpectedJsonName);
|
||||
Assert.True(File.Exists(firstJsonFile));
|
||||
using (var jsonStream = new FileInfo(firstJsonFile).OpenRead())
|
||||
using (var reader = new StreamReader(jsonStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Equal(Content, content);
|
||||
}
|
||||
|
||||
app = GetApplication();
|
||||
run = app.Execute(new[] { "add", "url", NoExtensionUrl });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
var secondExpectedJsonName = "filename1.json";
|
||||
|
||||
// csproj contents
|
||||
using (var csprojStream = new FileInfo(project.Project.Path).OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains(
|
||||
$@"<OpenApiReference Include=""{firstExpectedJsonName}"" SourceUrl=""{FakeOpenApiUrl}"" />", content);
|
||||
Assert.Contains(
|
||||
$@"<OpenApiReference Include=""{secondExpectedJsonName}"" SourceUrl=""{NoExtensionUrl}"" />", content);
|
||||
}
|
||||
|
||||
var secondJsonFile = Path.Combine(_tempDir.Root, secondExpectedJsonName);
|
||||
Assert.True(File.Exists(secondJsonFile));
|
||||
using (var jsonStream = new FileInfo(secondJsonFile).OpenRead())
|
||||
using (var reader = new StreamReader(jsonStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Equal(Content, content);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenApi_Add_Url_NSwagCSharp()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: false);
|
||||
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new[] { "add", "url", FakeOpenApiUrl, "--code-generator", "NSwagCSharp" });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
var expectedJsonName = "filename.json";
|
||||
|
||||
// csproj contents
|
||||
using (var csprojStream = new FileInfo(project.Project.Path).OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains(
|
||||
$@"<OpenApiReference Include=""{expectedJsonName}"" SourceUrl=""{FakeOpenApiUrl}"" CodeGenerator=""NSwagCSharp"" />", content);
|
||||
}
|
||||
|
||||
var resultFile = Path.Combine(_tempDir.Root, expectedJsonName);
|
||||
Assert.True(File.Exists(resultFile));
|
||||
using (var jsonStream = new FileInfo(resultFile).OpenRead())
|
||||
using (var reader = new StreamReader(jsonStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Equal(Content, content);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenApi_Add_Url_NSwagTypeScript()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: false);
|
||||
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new[] { "add", "url", FakeOpenApiUrl, "--code-generator", "NSwagTypeScript" });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
var expectedJsonName = "filename.json";
|
||||
|
||||
// csproj contents
|
||||
using (var csprojStream = new FileInfo(project.Project.Path).OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains(
|
||||
$@"<OpenApiReference Include=""{expectedJsonName}"" SourceUrl=""{FakeOpenApiUrl}"" CodeGenerator=""NSwagTypeScript"" />", content);
|
||||
}
|
||||
|
||||
var resultFile = Path.Combine(_tempDir.Root, expectedJsonName);
|
||||
Assert.True(File.Exists(resultFile));
|
||||
using (var jsonStream = new FileInfo(resultFile).OpenRead())
|
||||
using (var reader = new StreamReader(jsonStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Equal(Content, content);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenApi_Add_Url_OutputFile()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: false);
|
||||
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new[] { "add", "url", FakeOpenApiUrl, "--output-file", Path.Combine("outputdir", "file.yaml") });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
var expectedJsonName = Path.Combine("outputdir", "file.yaml");
|
||||
|
||||
// csproj contents
|
||||
using (var csprojStream = new FileInfo(project.Project.Path).OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains(
|
||||
$@"<OpenApiReference Include=""{expectedJsonName}"" SourceUrl=""{FakeOpenApiUrl}"" />", content);
|
||||
}
|
||||
|
||||
var resultFile = Path.Combine(_tempDir.Root, expectedJsonName);
|
||||
Assert.True(File.Exists(resultFile));
|
||||
using (var jsonStream = new FileInfo(resultFile).OpenRead())
|
||||
using (var reader = new StreamReader(jsonStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Equal(Content, content);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenApi_Add_URL_FileAlreadyExists_Fail()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: false);
|
||||
|
||||
var app = GetApplication();
|
||||
var outputFile = Path.Combine("outputdir", "file.yaml");
|
||||
var run = app.Execute(new[] { "add", "url", FakeOpenApiUrl, "--output-file", outputFile });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
var expectedJsonName = Path.Combine("outputdir", "file.yaml");
|
||||
|
||||
// csproj contents
|
||||
using (var csprojStream = new FileInfo(project.Project.Path).OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains(
|
||||
$@"<OpenApiReference Include=""{expectedJsonName}"" SourceUrl=""{FakeOpenApiUrl}"" />", content);
|
||||
}
|
||||
|
||||
var resultFile = Path.Combine(_tempDir.Root, expectedJsonName);
|
||||
Assert.True(File.Exists(resultFile));
|
||||
using (var jsonStream = new FileInfo(resultFile).OpenRead())
|
||||
using (var reader = new StreamReader(jsonStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Equal(Content, content);
|
||||
}
|
||||
|
||||
// Second reference, same output
|
||||
app = GetApplication();
|
||||
run = app.Execute(new[] { "add", "url", DifferentUrl, "--output-file", outputFile});
|
||||
Assert.Equal(1, run);
|
||||
Assert.True(_error.ToString().Contains("Aborting to avoid conflicts."), $"Should have aborted to avoid conflicts");
|
||||
|
||||
// csproj contents
|
||||
using (var csprojStream = new FileInfo(project.Project.Path).OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains(
|
||||
$@"<OpenApiReference Include=""{expectedJsonName}"" SourceUrl=""{FakeOpenApiUrl}"" />", content);
|
||||
Assert.DoesNotContain(
|
||||
$@"<OpenApiReference Include=""{expectedJsonName}"" SourceUrl=""{DifferentUrl}"" CodeGenerator=""NSwagCSharp"" />", content);
|
||||
}
|
||||
|
||||
using (var jsonStream = new FileInfo(resultFile).OpenRead())
|
||||
using (var reader = new StreamReader(jsonStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Equal(Content, content);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenApi_Add_URL_MultipleTimes_OnlyOneReference()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: false);
|
||||
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new[] { "add", "url", FakeOpenApiUrl });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
app = GetApplication();
|
||||
run = app.Execute(new[] { "add", "url", "--output-file", "openapi.yaml", FakeOpenApiUrl });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
// csproj contents
|
||||
var csproj = new FileInfo(project.Project.Path);
|
||||
using var csprojStream = csproj.OpenRead();
|
||||
using var reader = new StreamReader(csprojStream);
|
||||
var content = reader.ReadToEnd();
|
||||
var escapedPkgRef = Regex.Escape("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"");
|
||||
Assert.Single(Regex.Matches(content, escapedPkgRef));
|
||||
var escapedApiRef = Regex.Escape($"SourceUrl=\"{FakeOpenApiUrl}\"");
|
||||
Assert.Single(Regex.Matches(content, escapedApiRef));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenAPi_Add_URL_InvalidUrl()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: false);
|
||||
|
||||
var app = GetApplication(realHttp: true);
|
||||
var url = BrokenUrl;
|
||||
var run = app.Execute(new[] { "add", "url", url });
|
||||
|
||||
Assert.Equal(_error.ToString(), $"The given url returned 'NotFound', " +
|
||||
"indicating failure. The url might be wrong, or there might be a networking issue."+Environment.NewLine);
|
||||
Assert.Equal(1, run);
|
||||
|
||||
var expectedJsonName = "dingos.json";
|
||||
|
||||
// csproj contents
|
||||
using (var csprojStream = new FileInfo(project.Project.Path).OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.DoesNotContain("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.DoesNotContain($@"<OpenApiReference", content);
|
||||
}
|
||||
|
||||
var jsonFile = Path.Combine(_tempDir.Root, expectedJsonName);
|
||||
Assert.False(File.Exists(jsonFile));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenApi_Add_URL_ActualResponse()
|
||||
{
|
||||
var project = CreateBasicProject(withOpenApi: false);
|
||||
|
||||
var app = GetApplication(realHttp: true);
|
||||
var url = ActualUrl;
|
||||
var run = app.Execute(new[] { "add", "url", url });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
app = GetApplication(realHttp: true);
|
||||
run = app.Execute(new[] { "add", "url", url });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
// csproj contents
|
||||
var csproj = new FileInfo(project.Project.Path);
|
||||
using var csprojStream = csproj.OpenRead();
|
||||
using var reader = new StreamReader(csprojStream);
|
||||
var content = reader.ReadToEnd();
|
||||
var escapedPkgRef = Regex.Escape("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"");
|
||||
Assert.Single(Regex.Matches(content, escapedPkgRef));
|
||||
var escapedApiRef = Regex.Escape($"SourceUrl=\"{url}\"");
|
||||
Assert.Single(Regex.Matches(content, escapedApiRef));
|
||||
Assert.Contains(
|
||||
$@"<OpenApiReference Include=""api-with-examples.yaml"" SourceUrl=""{ActualUrl}"" />", content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.DotNet.OpenApi.Tests;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi.Refresh.Tests
|
||||
{
|
||||
public class OpenApiRefreshTests : OpenApiTestBase
|
||||
{
|
||||
public OpenApiRefreshTests(ITestOutputHelper output) : base(output) { }
|
||||
|
||||
[Fact]
|
||||
public async Task OpenApi_Refresh_Basic()
|
||||
{
|
||||
CreateBasicProject(withOpenApi: false);
|
||||
|
||||
var app = GetApplication();
|
||||
var run = app.Execute(new[] { "add", "url", FakeOpenApiUrl });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
var expectedJsonPath = Path.Combine(_tempDir.Root, "filename.json");
|
||||
var json = await File.ReadAllTextAsync(expectedJsonPath);
|
||||
json += "trash";
|
||||
await File.WriteAllTextAsync(expectedJsonPath, json);
|
||||
|
||||
var firstWriteTime = File.GetLastWriteTime(expectedJsonPath);
|
||||
|
||||
Thread.Sleep(TimeSpan.FromSeconds(1));
|
||||
|
||||
app = GetApplication();
|
||||
run = app.Execute(new[] { "refresh", FakeOpenApiUrl });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
var secondWriteTime = File.GetLastWriteTime(expectedJsonPath);
|
||||
Assert.True(firstWriteTime < secondWriteTime, $"File wasn't updated! {firstWriteTime} {secondWriteTime}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.DotNet.OpenApi.Tests;
|
||||
using Microsoft.Extensions.Tools.Internal;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi.Remove.Tests
|
||||
{
|
||||
public class OpenApiRemoveTests : OpenApiTestBase
|
||||
{
|
||||
public OpenApiRemoveTests(ITestOutputHelper output) : base(output) { }
|
||||
|
||||
[Fact]
|
||||
public async Task OpenApi_Remove_File()
|
||||
{
|
||||
var nswagJsonFile = "openapi.json";
|
||||
_tempDir
|
||||
.WithCSharpProject("testproj")
|
||||
.WithTargetFrameworks("netcoreapp3.0")
|
||||
.Dir()
|
||||
.WithContentFile(nswagJsonFile)
|
||||
.WithContentFile("Startup.cs")
|
||||
.Create();
|
||||
|
||||
var add = GetApplication();
|
||||
var run = add.Execute(new[] { "add", "file", nswagJsonFile });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
// csproj contents
|
||||
var csproj = new FileInfo(Path.Join(_tempDir.Root, "testproj.csproj"));
|
||||
using (var csprojStream = csproj.OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains($"<OpenApiReference Include=\"{nswagJsonFile}\"", content);
|
||||
}
|
||||
|
||||
var remove = GetApplication();
|
||||
var removeRun = remove.Execute(new[] { "remove", nswagJsonFile });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, removeRun);
|
||||
|
||||
// csproj contents
|
||||
csproj = new FileInfo(Path.Join(_tempDir.Root, "testproj.csproj"));
|
||||
using (var csprojStream = csproj.OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
// Don't remove the package reference, they might have taken other dependencies on it
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.DoesNotContain($"<OpenApiReference Include=\"{nswagJsonFile}\"", content);
|
||||
}
|
||||
Assert.False(File.Exists(Path.Combine(_tempDir.Root, nswagJsonFile)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenApi_Remove_ViaUrl()
|
||||
{
|
||||
_tempDir
|
||||
.WithCSharpProject("testproj")
|
||||
.WithTargetFrameworks("netcoreapp3.0")
|
||||
.Dir()
|
||||
.WithContentFile("Startup.cs")
|
||||
.Create();
|
||||
|
||||
var add = GetApplication();
|
||||
var run = add.Execute(new[] { "add", "url", FakeOpenApiUrl });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
// csproj contents
|
||||
var csproj = new FileInfo(Path.Join(_tempDir.Root, "testproj.csproj"));
|
||||
using (var csprojStream = csproj.OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
// Don't remove the package reference, they might have taken other dependencies on it
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
}
|
||||
|
||||
var remove = GetApplication();
|
||||
var removeRun = remove.Execute(new[] { "remove", FakeOpenApiUrl });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, removeRun);
|
||||
|
||||
// csproj contents
|
||||
csproj = new FileInfo(Path.Join(_tempDir.Root, "testproj.csproj"));
|
||||
using var removedCsprojStream = csproj.OpenRead();
|
||||
using var removedReader = new StreamReader(removedCsprojStream);
|
||||
var removedContent = await removedReader.ReadToEndAsync();
|
||||
// Don't remove the package reference, they might have taken other dependencies on it
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", removedContent);
|
||||
Assert.DoesNotContain($"<OpenApiReference", removedContent);
|
||||
}
|
||||
|
||||
[Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/12738")]
|
||||
public async Task OpenApi_Remove_Project()
|
||||
{
|
||||
_tempDir
|
||||
.WithCSharpProject("testproj")
|
||||
.WithTargetFrameworks("netcoreapp3.0")
|
||||
.Dir()
|
||||
.WithContentFile("Startup.cs")
|
||||
.Create();
|
||||
|
||||
using var refProj = new TemporaryDirectory();
|
||||
var refProjName = "refProj";
|
||||
refProj
|
||||
.WithCSharpProject(refProjName)
|
||||
.WithTargetFrameworks("netcoreapp3.0")
|
||||
.Dir()
|
||||
.Create();
|
||||
|
||||
var app = GetApplication();
|
||||
var refProjFile = Path.Join(refProj.Root, $"{refProjName}.csproj");
|
||||
var run = app.Execute(new[] { "add", "project", refProjFile });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
// csproj contents
|
||||
using (var csprojStream = new FileInfo(Path.Join(_tempDir.Root, "testproj.csproj")).OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.Contains($"<OpenApiProjectReference Include=\"{refProjFile}\"", content);
|
||||
}
|
||||
|
||||
var remove = GetApplication();
|
||||
run = app.Execute(new[] { "remove", refProjFile });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
// csproj contents
|
||||
using (var csprojStream = new FileInfo(Path.Join(_tempDir.Root, "testproj.csproj")).OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.DoesNotContain($"<OpenApiProjectReference Include=\"{refProjFile}\"", content);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenApi_Remove_Multiple()
|
||||
{
|
||||
var nswagJsonFile = "openapi.json";
|
||||
var swagFile2 = "swag2.json";
|
||||
_tempDir
|
||||
.WithCSharpProject("testproj")
|
||||
.WithTargetFrameworks("netcoreapp3.0")
|
||||
.Dir()
|
||||
.WithContentFile(nswagJsonFile)
|
||||
.WithFile(swagFile2)
|
||||
.WithContentFile("Startup.cs")
|
||||
.Create();
|
||||
|
||||
var add = GetApplication();
|
||||
var run = add.Execute(new[] { "add", "file", nswagJsonFile });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
add = GetApplication();
|
||||
run = add.Execute(new[] { "add", "file", swagFile2 });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, run);
|
||||
|
||||
var remove = GetApplication();
|
||||
var removeRun = remove.Execute(new[] { "remove", nswagJsonFile, swagFile2 });
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(_error.ToString()), $"Threw error: {_error.ToString()}");
|
||||
Assert.Equal(0, removeRun);
|
||||
|
||||
// csproj contents
|
||||
var csproj = new FileInfo(Path.Join(_tempDir.Root, "testproj.csproj"));
|
||||
using (var csprojStream = csproj.OpenRead())
|
||||
using (var reader = new StreamReader(csprojStream))
|
||||
{
|
||||
var content = await reader.ReadToEndAsync();
|
||||
// Don't remove the package reference, they might have taken other dependencies on it
|
||||
Assert.Contains("<PackageReference Include=\"NSwag.ApiDescription.Client\" Version=\"", content);
|
||||
Assert.DoesNotContain($"<OpenApiReference Include=\"{nswagJsonFile}\"", content);
|
||||
}
|
||||
Assert.False(File.Exists(Path.Combine(_tempDir.Root, nswagJsonFile)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.DotNet.Openapi.Tools;
|
||||
using Microsoft.Extensions.Tools.Internal;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Microsoft.DotNet.OpenApi.Tests
|
||||
{
|
||||
public class OpenApiTestBase : IDisposable
|
||||
{
|
||||
protected readonly TemporaryDirectory _tempDir;
|
||||
protected readonly TextWriter _output = new StringWriter();
|
||||
protected readonly TextWriter _error = new StringWriter();
|
||||
protected readonly ITestOutputHelper _outputHelper;
|
||||
|
||||
protected const string Content = @"{""x-generator"": ""NSwag""}";
|
||||
protected const string ActualUrl = "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v3.0/api-with-examples.yaml";
|
||||
protected const string BrokenUrl = "https://www.microsoft.com/en-us/dingos.json";
|
||||
protected const string FakeOpenApiUrl = "https://contoso.com/openapi.json";
|
||||
protected const string NoDispositionUrl = "https://contoso.com/nodisposition.yaml";
|
||||
protected const string NoExtensionUrl = "https://contoso.com/noextension";
|
||||
protected const string NoSegmentUrl = "https://contoso.com";
|
||||
protected const string DifferentUrl = "https://contoso.com/different.json";
|
||||
protected const string PackageUrl = "https://go.microsoft.com/fwlink/?linkid=2099561";
|
||||
protected const string DifferentUrlContent = @"
|
||||
{
|
||||
""x-generator"": ""NSwag""
|
||||
}";
|
||||
protected const string PackageUrlContent = @"
|
||||
{
|
||||
""Version"" : ""1.0"",
|
||||
""Packages"" : {
|
||||
""Microsoft.Azure.SignalR"": ""1.1.0-preview1-10442"",
|
||||
""Grpc.AspNetCore.Server"": ""0.1.22-pre2"",
|
||||
""Grpc.Net.ClientFactory"": ""0.1.22-pre2"",
|
||||
""Google.Protobuf"": ""3.8.0"",
|
||||
""Grpc.Tools"": ""1.22.0"",
|
||||
""NSwag.ApiDescription.Client"": ""13.0.3"",
|
||||
""Microsoft.Extensions.ApiDescription.Client"": ""0.3.0-preview7.19365.7"",
|
||||
""Newtonsoft.Json"": ""12.0.2""
|
||||
}
|
||||
}";
|
||||
|
||||
public OpenApiTestBase(ITestOutputHelper output)
|
||||
{
|
||||
_tempDir = new TemporaryDirectory();
|
||||
_outputHelper = output;
|
||||
}
|
||||
|
||||
public TemporaryNSwagProject CreateBasicProject(bool withOpenApi)
|
||||
{
|
||||
var nswagJsonFile = "openapi.json";
|
||||
var project = _tempDir
|
||||
.WithCSharpProject("testproj", sdk: "Microsoft.NET.Sdk.Web")
|
||||
.WithTargetFrameworks("netcoreapp3.0");
|
||||
var tmp = project.Dir();
|
||||
|
||||
if (withOpenApi)
|
||||
{
|
||||
tmp = tmp.WithContentFile(nswagJsonFile);
|
||||
}
|
||||
|
||||
tmp.WithContentFile("Startup.cs")
|
||||
.Create();
|
||||
|
||||
return new TemporaryNSwagProject(project, nswagJsonFile);
|
||||
}
|
||||
|
||||
internal Application GetApplication(bool realHttp = false)
|
||||
{
|
||||
IHttpClientWrapper wrapper;
|
||||
if (realHttp)
|
||||
{
|
||||
wrapper = new HttpClientWrapper(new HttpClient());
|
||||
}
|
||||
else
|
||||
{
|
||||
wrapper = new TestHttpClientWrapper(DownloadMock());
|
||||
}
|
||||
return new Application(
|
||||
_tempDir.Root, wrapper, _output, _error);
|
||||
}
|
||||
|
||||
private IDictionary<string, Tuple<string, ContentDispositionHeaderValue>> DownloadMock()
|
||||
{
|
||||
var noExtension = new ContentDispositionHeaderValue("attachment");
|
||||
noExtension.Parameters.Add(new NameValueHeaderValue("filename", "filename"));
|
||||
var extension = new ContentDispositionHeaderValue("attachment");
|
||||
extension.Parameters.Add(new NameValueHeaderValue("filename", "filename.json"));
|
||||
var justAttachments = new ContentDispositionHeaderValue("attachment");
|
||||
|
||||
return new Dictionary<string, Tuple<string, ContentDispositionHeaderValue>> {
|
||||
{ FakeOpenApiUrl, Tuple.Create(Content, extension)},
|
||||
{ DifferentUrl, Tuple.Create<string, ContentDispositionHeaderValue>(DifferentUrlContent, null) },
|
||||
{ PackageUrl, Tuple.Create<string, ContentDispositionHeaderValue>(PackageUrlContent, null) },
|
||||
{ NoDispositionUrl, Tuple.Create<string, ContentDispositionHeaderValue>(Content, null) },
|
||||
{ NoExtensionUrl, Tuple.Create(Content, noExtension) },
|
||||
{ NoSegmentUrl, Tuple.Create(Content, justAttachments) }
|
||||
};
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_outputHelper.WriteLine(_output.ToString());
|
||||
_tempDir.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public class TestHttpClientWrapper : IHttpClientWrapper
|
||||
{
|
||||
private readonly IDictionary<string, Tuple<string, ContentDispositionHeaderValue>> _results;
|
||||
|
||||
public TestHttpClientWrapper(IDictionary<string, Tuple<string, ContentDispositionHeaderValue>> results)
|
||||
{
|
||||
_results = results;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public Task<IHttpResponseMessageWrapper> GetResponseAsync(string url)
|
||||
{
|
||||
var result = _results[url];
|
||||
byte[] byteArray = Encoding.ASCII.GetBytes(result.Item1);
|
||||
var stream = new MemoryStream(byteArray);
|
||||
|
||||
return Task.FromResult<IHttpResponseMessageWrapper>(new TestHttpResponseMessageWrapper(stream, result.Item2));
|
||||
}
|
||||
}
|
||||
|
||||
public class TestHttpResponseMessageWrapper : IHttpResponseMessageWrapper
|
||||
{
|
||||
public Task<Stream> Stream { get; }
|
||||
|
||||
public HttpStatusCode StatusCode { get; } = HttpStatusCode.OK;
|
||||
|
||||
public bool IsSuccessCode()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private ContentDispositionHeaderValue _contentDisposition;
|
||||
|
||||
public TestHttpResponseMessageWrapper(
|
||||
MemoryStream stream,
|
||||
ContentDispositionHeaderValue header)
|
||||
{
|
||||
Stream = Task.FromResult<Stream>(stream);
|
||||
_contentDisposition = header;
|
||||
}
|
||||
|
||||
public ContentDispositionHeaderValue ContentDisposition()
|
||||
{
|
||||
return _contentDisposition;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class TemporaryNSwagProject
|
||||
{
|
||||
public TemporaryNSwagProject(TemporaryCSharpProject project, string jsonFile)
|
||||
{
|
||||
Project = project;
|
||||
NSwagJsonFile = jsonFile;
|
||||
}
|
||||
|
||||
public TemporaryCSharpProject Project { get; set; }
|
||||
public string NSwagJsonFile { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Microsoft.Extensions.Internal
|
||||
{
|
||||
internal class ProcessEx : IDisposable
|
||||
{
|
||||
private readonly ITestOutputHelper _output;
|
||||
private readonly Process _process;
|
||||
private readonly StringBuilder _stderrCapture = new StringBuilder();
|
||||
private readonly StringBuilder _stdoutCapture = new StringBuilder();
|
||||
private readonly object _pipeCaptureLock = new object();
|
||||
private BlockingCollection<string> _stdoutLines = new BlockingCollection<string>();
|
||||
private TaskCompletionSource<int> _exited;
|
||||
|
||||
private ProcessEx(ITestOutputHelper output, Process proc)
|
||||
{
|
||||
_output = output;
|
||||
|
||||
_process = proc;
|
||||
proc.EnableRaisingEvents = true;
|
||||
proc.OutputDataReceived += OnOutputData;
|
||||
proc.ErrorDataReceived += OnErrorData;
|
||||
proc.Exited += OnProcessExited;
|
||||
proc.BeginOutputReadLine();
|
||||
proc.BeginErrorReadLine();
|
||||
|
||||
_exited = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
}
|
||||
|
||||
public Task Exited => _exited.Task;
|
||||
|
||||
public bool HasExited => _process.HasExited;
|
||||
|
||||
public string Output
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_pipeCaptureLock)
|
||||
{
|
||||
return _stdoutCapture.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int ExitCode => _process.ExitCode;
|
||||
|
||||
public static ProcessEx Run(ITestOutputHelper output, string workingDirectory, string command, string args = null, IDictionary<string, string> envVars = null)
|
||||
{
|
||||
var startInfo = new ProcessStartInfo(command, args)
|
||||
{
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
WorkingDirectory = workingDirectory
|
||||
};
|
||||
|
||||
if (envVars != null)
|
||||
{
|
||||
foreach (var envVar in envVars)
|
||||
{
|
||||
startInfo.EnvironmentVariables[envVar.Key] = envVar.Value;
|
||||
}
|
||||
}
|
||||
|
||||
output.WriteLine($"==> {startInfo.FileName} {startInfo.Arguments} [{startInfo.WorkingDirectory}]");
|
||||
var proc = Process.Start(startInfo);
|
||||
|
||||
return new ProcessEx(output, proc);
|
||||
}
|
||||
|
||||
private void OnErrorData(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (e.Data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_pipeCaptureLock)
|
||||
{
|
||||
_stderrCapture.AppendLine(e.Data);
|
||||
}
|
||||
|
||||
_output.WriteLine("[ERROR] " + e.Data);
|
||||
}
|
||||
|
||||
private void OnOutputData(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (e.Data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_pipeCaptureLock)
|
||||
{
|
||||
_stdoutCapture.AppendLine(e.Data);
|
||||
}
|
||||
|
||||
_output.WriteLine(e.Data);
|
||||
|
||||
if (_stdoutLines != null)
|
||||
{
|
||||
_stdoutLines.Add(e.Data);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnProcessExited(object sender, EventArgs e)
|
||||
{
|
||||
_process.WaitForExit();
|
||||
_stdoutLines.CompleteAdding();
|
||||
_stdoutLines = null;
|
||||
_exited.TrySetResult(_process.ExitCode);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_process != null && !_process.HasExited)
|
||||
{
|
||||
_process.KillTree();
|
||||
}
|
||||
|
||||
_process.CancelOutputRead();
|
||||
_process.CancelErrorRead();
|
||||
|
||||
_process.ErrorDataReceived -= OnErrorData;
|
||||
_process.OutputDataReceived -= OnOutputData;
|
||||
_process.Exited -= OnProcessExited;
|
||||
_process.Dispose();
|
||||
|
||||
if(_stdoutLines != null)
|
||||
{
|
||||
_stdoutLines.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Xunit;
|
||||
|
||||
[assembly: CollectionBehavior(DisableTestParallelization = true)]
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace SimpleWebSite
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// Example 1
|
||||
services
|
||||
.AddMvcCore()
|
||||
.AddAuthorization()
|
||||
.AddFormatterMappings(m => m.SetMediaTypeMappingForFormat("js", new MediaTypeHeaderValue("application/json")))
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Latest);
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseMvcWithDefaultRoute();
|
||||
}
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = CreateWebHostBuilder(args)
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
}
|
||||
|
||||
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
|
||||
new WebHostBuilder()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseStartup<Startup>()
|
||||
.UseKestrel()
|
||||
.UseIISIntegration();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,514 @@
|
|||
{
|
||||
"x-generator": "NSwag v11.17.15.0 (NJsonSchema v9.10.53.0 (Newtonsoft.Json v10.0.0.0))",
|
||||
"openapi": "2.0",
|
||||
"info": {
|
||||
"title": "My Title",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"host": "localhost:44370",
|
||||
"schemes": [
|
||||
"https"
|
||||
],
|
||||
"consumes": [
|
||||
"application/json",
|
||||
"application/json-patch+json",
|
||||
"text/json",
|
||||
"application/*+json",
|
||||
"multipart/form-data"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"paths": {
|
||||
"/pet": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Pet"
|
||||
],
|
||||
"operationId": "Pet_AddPet",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "pet",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Pet"
|
||||
},
|
||||
"x-nullable": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": ""
|
||||
},
|
||||
"400": {
|
||||
"x-nullable": true,
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/SerializableError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"tags": [
|
||||
"Pet"
|
||||
],
|
||||
"operationId": "Pet_EditPet",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "pet",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Pet"
|
||||
},
|
||||
"x-nullable": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": ""
|
||||
},
|
||||
"400": {
|
||||
"x-nullable": true,
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/SerializableError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/pet/findByStatus": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Pet"
|
||||
],
|
||||
"operationId": "Pet_FindByStatus",
|
||||
"consumes": [
|
||||
"application/json-patch+json",
|
||||
"application/json",
|
||||
"text/json",
|
||||
"application/*+json"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "status",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"x-nullable": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"x-nullable": true,
|
||||
"description": "",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Pet"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/pet/findByCategory": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Pet"
|
||||
],
|
||||
"operationId": "Pet_FindByCategory",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "category",
|
||||
"in": "query",
|
||||
"required": true,
|
||||
"x-nullable": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"x-nullable": true,
|
||||
"description": "",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Pet"
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"x-nullable": true,
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/SerializableError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/pet/{petId}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Pet"
|
||||
],
|
||||
"operationId": "Pet_FindById",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "petId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"format": "int32",
|
||||
"x-nullable": false
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"x-nullable": true,
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Pet"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"x-nullable": true,
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/SerializableError"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"tags": [
|
||||
"Pet"
|
||||
],
|
||||
"operationId": "Pet_EditPet2",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "petId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"format": "int32",
|
||||
"x-nullable": false
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "Id",
|
||||
"in": "formData",
|
||||
"required": true,
|
||||
"format": "int32",
|
||||
"x-nullable": false
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "Age",
|
||||
"in": "formData",
|
||||
"required": true,
|
||||
"format": "int32",
|
||||
"x-nullable": false
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "Category.Id",
|
||||
"in": "formData",
|
||||
"required": true,
|
||||
"format": "int32",
|
||||
"x-nullable": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "Category.Name",
|
||||
"in": "formData",
|
||||
"required": true,
|
||||
"x-nullable": true
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "HasVaccinations",
|
||||
"in": "formData",
|
||||
"required": true,
|
||||
"x-nullable": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "Name",
|
||||
"in": "formData",
|
||||
"required": true,
|
||||
"x-nullable": true
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"name": "Images",
|
||||
"in": "formData",
|
||||
"required": true,
|
||||
"collectionFormat": "multi",
|
||||
"x-nullable": true,
|
||||
"items": {
|
||||
"$ref": "#/definitions/Image"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"name": "Tags",
|
||||
"in": "formData",
|
||||
"required": true,
|
||||
"collectionFormat": "multi",
|
||||
"x-nullable": true,
|
||||
"items": {
|
||||
"$ref": "#/definitions/Tag"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "Status",
|
||||
"in": "formData",
|
||||
"required": true,
|
||||
"x-nullable": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": ""
|
||||
},
|
||||
"400": {
|
||||
"x-nullable": true,
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/SerializableError"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"Pet"
|
||||
],
|
||||
"operationId": "Pet_DeletePet",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "petId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"format": "int32",
|
||||
"x-nullable": false
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": ""
|
||||
},
|
||||
"400": {
|
||||
"x-nullable": true,
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/SerializableError"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/pet/{petId}/uploadImage": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Pet"
|
||||
],
|
||||
"operationId": "Pet_UploadImage",
|
||||
"consumes": [
|
||||
"multipart/form-data"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "petId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"format": "int32",
|
||||
"x-nullable": false
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"name": "file",
|
||||
"in": "formData",
|
||||
"required": true,
|
||||
"x-nullable": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"x-nullable": true,
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ApiResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"x-nullable": true,
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/SerializableError"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"Pet": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"id",
|
||||
"age",
|
||||
"hasVaccinations",
|
||||
"name",
|
||||
"status"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"age": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"maximum": 150.0,
|
||||
"minimum": 0.0
|
||||
},
|
||||
"category": {
|
||||
"$ref": "#/definitions/Category"
|
||||
},
|
||||
"hasVaccinations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"maxLength": 50,
|
||||
"minLength": 2
|
||||
},
|
||||
"images": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Image"
|
||||
}
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Tag"
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Category": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Image": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Tag": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SerializableError": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"ApiResponse": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"code"
|
||||
],
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<AssemblyName>Microsoft.DotNet.Open.Api.Tools.Tests</AssemblyName>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);TestProjects\**\*</DefaultItemExcludes>
|
||||
<TestGroupName>DotNetAddOpenAPIReferenceToolsTests</TestGroupName>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<OpenAPIToolCSProjPath>..\src\Microsoft.dotnet-openapi.csproj</OpenAPIToolCSProjPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="$(ToolSharedSourceRoot)TestHelpers\**\*.cs" />
|
||||
<Compile Include="$(SharedSourceRoot)test\SkipOnHelixAttribute.cs" />
|
||||
<Content Include="TestContent\*" LinkBase="TestContent\" CopyToOutputDirectory="PreserveNewest" />
|
||||
<Compile Include="$(SharedSourceRoot)Process\ProcessExtensions.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Build" ExcludeAssets="runtime" />
|
||||
<ProjectReference Include="$(OpenAPIToolCSProjPath)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||
<_Parameter1>TestSettings:RestoreSources</_Parameter1>
|
||||
<_Parameter2>$(RestoreSources)</_Parameter2>
|
||||
</AssemblyAttribute>
|
||||
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||
<_Parameter1>TestSettings:RuntimeFrameworkVersion</_Parameter1>
|
||||
<_Parameter2>$(RuntimeFrameworkVersion)</_Parameter2>
|
||||
</AssemblyAttribute>
|
||||
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||
<_Parameter1>RepoRoot</_Parameter1>
|
||||
<_Parameter2>$(RepoRoot)</_Parameter2>
|
||||
</AssemblyAttribute>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="CleanTestProjects" BeforeTargets="CoreCompile">
|
||||
<RemoveDir Directories="$(TargetDir)TestProjects" Condition="Exists('$(TargetDir)TestProjects')" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PublishDotNetOpenApiOnBuild" BeforeTargets="Build" Condition="'$(DotNetBuildFromSource)' != 'true'">
|
||||
<MSBuild Projects="$(OpenAPIToolCSProjPath)" Targets="Publish" Properties="PublishDir=$(OutputPath)\tool\;Configuration=$(Configuration)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PublishDotNetOpenApiOnPublish" BeforeTargets="Publish" Condition="'$(DotNetBuildFromSource)' != 'true'">
|
||||
<MSBuild Projects="$(OpenAPIToolCSProjPath)" Targets="Publish" Properties="PublishDir=$(PublishDir)\tool\;Configuration=$(Configuration)" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"longRunningTestSeconds": 30,
|
||||
"diagnosticMessages": true,
|
||||
"maxParallelThreads": -1
|
||||
}
|
||||
|
|
@ -1,18 +1,24 @@
|
|||
# DotNetTools
|
||||
|
||||
## Projects
|
||||
## Bundled tools
|
||||
|
||||
The folder contains command-line tools for ASP.NET Core that are bundled* in the .NET Core CLI. Follow the links below for more details on each tool.
|
||||
The folder contains command-line tools for ASP.NET Core. The following tools are bundled* in the .NET Core CLI. Follow the links below for more details on each tool.
|
||||
|
||||
- [dotnet-watch](dotnet-watch/README.md)
|
||||
- [dotnet-user-secrets](dotnet-user-secrets/README.md)
|
||||
- [dotnet-sql-cache](dotnet-sql-cache/README.md)
|
||||
- [dotnet-dev-certs](dotnet-dev-certs/README.md)
|
||||
- [dotnet-watch](dotnet-watch/README.md)
|
||||
- [dotnet-user-secrets](dotnet-user-secrets/README.md)
|
||||
- [dotnet-sql-cache](dotnet-sql-cache/README.md)
|
||||
- [dotnet-dev-certs](dotnet-dev-certs/README.md)
|
||||
|
||||
*\*This applies to .NET Core CLI 2.1.300-preview2 and up. For earlier versions of the CLI, these tools must be installed separately.*
|
||||
|
||||
*For 2.0 CLI and earlier, see <https://github.com/aspnet/DotNetTools/tree/rel/2.0.0/README.md> for details.*
|
||||
|
||||
## Non-bundled tools
|
||||
|
||||
The following tools are produced by us but not bundled in the .NET Core CLI. They must be aquired independently.
|
||||
|
||||
- [Microsoft.dotnet-openapi](Microsoft.dotnet-openapi/README.md)
|
||||
|
||||
This folder also contains the infrastructure for our partners' service reference features:
|
||||
|
||||
- [Extensions.ApiDescription.Client](Extensions.ApiDescription.Client/README.md) MSBuild glue for OpenAPI code generation.
|
||||
|
|
@ -29,10 +35,11 @@ dotnet watch
|
|||
dotnet user-secrets
|
||||
dotnet sql-cache
|
||||
dotnet dev-certs
|
||||
dotnet openapi
|
||||
```
|
||||
|
||||
Add `--help` to see more details. For example,
|
||||
|
||||
```
|
||||
```sh
|
||||
dotnet watch --help
|
||||
```
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.Extensions.CommandLineUtils
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
|
@ -6,12 +6,12 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.DotNet.Watcher.Tools.Tests
|
||||
namespace Microsoft.Extensions.Tools.Internal
|
||||
{
|
||||
public class TemporaryCSharpProject
|
||||
{
|
||||
private const string Template =
|
||||
@"<Project Sdk=""Microsoft.NET.Sdk"">
|
||||
@"<Project Sdk=""{2}"">
|
||||
<PropertyGroup>
|
||||
{0}
|
||||
<OutputType>Exe</OutputType>
|
||||
|
|
@ -23,19 +23,22 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
|
|||
|
||||
private readonly string _filename;
|
||||
private readonly TemporaryDirectory _directory;
|
||||
private List<string> _items = new List<string>();
|
||||
private List<string> _properties = new List<string>();
|
||||
private readonly List<string> _items = new List<string>();
|
||||
private readonly List<string> _properties = new List<string>();
|
||||
|
||||
public TemporaryCSharpProject(string name, TemporaryDirectory directory)
|
||||
public TemporaryCSharpProject(string name, TemporaryDirectory directory, string sdk)
|
||||
{
|
||||
Name = name;
|
||||
_filename = name + ".csproj";
|
||||
_directory = directory;
|
||||
Sdk = sdk;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public string Path => System.IO.Path.Combine(_directory.Root, _filename);
|
||||
|
||||
public string Sdk { get; }
|
||||
|
||||
public TemporaryCSharpProject WithTargetFrameworks(params string[] tfms)
|
||||
{
|
||||
Debug.Assert(tfms.Length > 0);
|
||||
|
|
@ -95,7 +98,7 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
|
|||
|
||||
public void Create()
|
||||
{
|
||||
_directory.CreateFile(_filename, string.Format(Template, string.Join("\r\n", _properties), string.Join("\r\n", _items)));
|
||||
_directory.CreateFile(_filename, string.Format(Template, string.Join("\r\n", _properties), string.Join("\r\n", _items), Sdk));
|
||||
}
|
||||
|
||||
public class ItemSpec
|
||||
|
|
@ -5,7 +5,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.DotNet.Watcher.Tools.Tests
|
||||
namespace Microsoft.Extensions.Tools.Internal
|
||||
{
|
||||
public class TemporaryDirectory : IDisposable
|
||||
{
|
||||
|
|
@ -16,7 +16,7 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
|
|||
|
||||
public TemporaryDirectory()
|
||||
{
|
||||
Root = Path.Combine(Path.GetTempPath(), "dotnet-watch-tests", Guid.NewGuid().ToString("N"));
|
||||
Root = Path.Combine(Path.GetTempPath(), "dotnet-tool-tests", Guid.NewGuid().ToString("N"));
|
||||
}
|
||||
|
||||
private TemporaryDirectory(string path, TemporaryDirectory parent)
|
||||
|
|
@ -34,16 +34,16 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
|
|||
|
||||
public string Root { get; }
|
||||
|
||||
public TemporaryCSharpProject WithCSharpProject(string name)
|
||||
public TemporaryCSharpProject WithCSharpProject(string name, string sdk = "Microsoft.NET.Sdk")
|
||||
{
|
||||
var project = new TemporaryCSharpProject(name, this);
|
||||
var project = new TemporaryCSharpProject(name, this, sdk);
|
||||
_projects.Add(project);
|
||||
return project;
|
||||
}
|
||||
|
||||
public TemporaryCSharpProject WithCSharpProject(string name, out TemporaryCSharpProject project)
|
||||
public TemporaryCSharpProject WithCSharpProject(string name, out TemporaryCSharpProject project, string sdk = "Microsoft.NET.Sdk")
|
||||
{
|
||||
project = WithCSharpProject(name);
|
||||
project = WithCSharpProject(name, sdk);
|
||||
return project;
|
||||
}
|
||||
|
||||
|
|
@ -53,6 +53,16 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
|
|||
return this;
|
||||
}
|
||||
|
||||
public TemporaryDirectory WithContentFile(string name)
|
||||
{
|
||||
using (var stream = File.OpenRead(Path.Combine("TestContent", $"{name}.txt")))
|
||||
using (var streamReader = new StreamReader(stream))
|
||||
{
|
||||
_files[name] = streamReader.ReadToEnd();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public TemporaryDirectory Up()
|
||||
{
|
||||
if (_parent == null)
|
||||
|
|
@ -7,13 +7,21 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-watch", "dotnet-watc
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-watch.Tests", "dotnet-watch\test\dotnet-watch.Tests.csproj", "{63F7E822-D1E2-4C41-8ABF-60B9E3A9C54C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-dev-certs", "dotnet-dev-certs\src\dotnet-dev-certs.csproj", "{0D6D5693-7E0C-4FE8-B4AA-21207B2650AA}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E01EE27B-6CF9-4707-9849-5BA2ABA825F2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.DeveloperCertificates.XPlat", "FirstRunCertGenerator\src\Microsoft.AspNetCore.DeveloperCertificates.XPlat.csproj", "{7BBDBDA2-299F-4C36-8338-23C525901DE0}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{2C485EAF-E4DE-4D14-8AE1-330641E17D44}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.DeveloperCertificates.XPlat.Tests", "FirstRunCertGenerator\test\Microsoft.AspNetCore.DeveloperCertificates.XPlat.Tests.csproj", "{1EC6FA27-40A5-433F-8CA1-636E7ED8863E}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-dev-certs", "dotnet-dev-certs\src\dotnet-dev-certs.csproj", "{98550159-E04E-44EB-A969-E5BF12444B94}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-sql-cache", "dotnet-sql-cache\src\dotnet-sql-cache.csproj", "{15FB0E39-1A28-4325-AD3C-76352516C80D}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-sql-cache", "dotnet-sql-cache\src\dotnet-sql-cache.csproj", "{216AF7F1-5B05-477E-B8D3-86F6059F268A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-user-secrets", "dotnet-user-secrets\src\dotnet-user-secrets.csproj", "{5FE62357-2915-4890-813A-D82656BDC4DD}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-user-secrets.Tests", "dotnet-user-secrets\test\dotnet-user-secrets.Tests.csproj", "{25F8DCC4-4571-42F7-BA0F-5C2D5A802297}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.dotnet-openapi", "Microsoft.dotnet-openapi\src\Microsoft.dotnet-openapi.csproj", "{C806041C-30F2-4B27-918A-5FF3576B833B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-microsoft.openapi.Tests", "Microsoft.dotnet-openapi\test\dotnet-microsoft.openapi.Tests.csproj", "{26BBA8A7-0F69-4C5F-B1C2-16B3320FFE3F}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions.ApiDescription.Client", "Extensions.ApiDescription.Client", "{78610083-1FCE-47F5-AB4D-AF0E1313B351}"
|
||||
EndProject
|
||||
|
|
@ -77,6 +85,30 @@ Global
|
|||
{EB63AECB-B898-475D-90F7-FE61F9C1CCC6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EB63AECB-B898-475D-90F7-FE61F9C1CCC6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EB63AECB-B898-475D-90F7-FE61F9C1CCC6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{98550159-E04E-44EB-A969-E5BF12444B94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{98550159-E04E-44EB-A969-E5BF12444B94}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{98550159-E04E-44EB-A969-E5BF12444B94}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{98550159-E04E-44EB-A969-E5BF12444B94}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{216AF7F1-5B05-477E-B8D3-86F6059F268A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{216AF7F1-5B05-477E-B8D3-86F6059F268A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{216AF7F1-5B05-477E-B8D3-86F6059F268A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{216AF7F1-5B05-477E-B8D3-86F6059F268A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5FE62357-2915-4890-813A-D82656BDC4DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5FE62357-2915-4890-813A-D82656BDC4DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5FE62357-2915-4890-813A-D82656BDC4DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5FE62357-2915-4890-813A-D82656BDC4DD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{25F8DCC4-4571-42F7-BA0F-5C2D5A802297}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{25F8DCC4-4571-42F7-BA0F-5C2D5A802297}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{25F8DCC4-4571-42F7-BA0F-5C2D5A802297}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{25F8DCC4-4571-42F7-BA0F-5C2D5A802297}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C806041C-30F2-4B27-918A-5FF3576B833B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C806041C-30F2-4B27-918A-5FF3576B833B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C806041C-30F2-4B27-918A-5FF3576B833B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C806041C-30F2-4B27-918A-5FF3576B833B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{26BBA8A7-0F69-4C5F-B1C2-16B3320FFE3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{26BBA8A7-0F69-4C5F-B1C2-16B3320FFE3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{26BBA8A7-0F69-4C5F-B1C2-16B3320FFE3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{26BBA8A7-0F69-4C5F-B1C2-16B3320FFE3F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -88,6 +120,14 @@ Global
|
|||
{160A445F-7E1F-430D-9403-41F7F6F4A16E} = {4110117E-3C28-4064-A7A3-B112BD6F8CB9}
|
||||
{233119FC-E4C1-421C-89AE-1A445C5A947F} = {4110117E-3C28-4064-A7A3-B112BD6F8CB9}
|
||||
{EB63AECB-B898-475D-90F7-FE61F9C1CCC6} = {4110117E-3C28-4064-A7A3-B112BD6F8CB9}
|
||||
{E16F10C8-5FC3-420B-AB33-D6E5CBE89B75} = {E01EE27B-6CF9-4707-9849-5BA2ABA825F2}
|
||||
{63F7E822-D1E2-4C41-8ABF-60B9E3A9C54C} = {2C485EAF-E4DE-4D14-8AE1-330641E17D44}
|
||||
{98550159-E04E-44EB-A969-E5BF12444B94} = {E01EE27B-6CF9-4707-9849-5BA2ABA825F2}
|
||||
{216AF7F1-5B05-477E-B8D3-86F6059F268A} = {E01EE27B-6CF9-4707-9849-5BA2ABA825F2}
|
||||
{5FE62357-2915-4890-813A-D82656BDC4DD} = {E01EE27B-6CF9-4707-9849-5BA2ABA825F2}
|
||||
{25F8DCC4-4571-42F7-BA0F-5C2D5A802297} = {2C485EAF-E4DE-4D14-8AE1-330641E17D44}
|
||||
{C806041C-30F2-4B27-918A-5FF3576B833B} = {E01EE27B-6CF9-4707-9849-5BA2ABA825F2}
|
||||
{26BBA8A7-0F69-4C5F-B1C2-16B3320FFE3F} = {2C485EAF-E4DE-4D14-8AE1-330641E17D44}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {EC668D8E-97B9-4758-9E5C-2E5DD6B9137B}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
@ECHO OFF
|
||||
SET RepoRoot=%~dp0..\..
|
||||
%RepoRoot%\build.cmd -projects %~dp0\**\*.*proj %*
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
repo_root="$DIR/../.."
|
||||
"$repo_root/build.sh" --projects "$DIR/**/*.*proj" "$@"
|
||||
|
|
@ -104,10 +104,10 @@ namespace Microsoft.AspNetCore.DeveloperCertificates.Tools
|
|||
app.HelpOption("-h|--help");
|
||||
|
||||
app.OnExecute(() =>
|
||||
{
|
||||
app.ShowHelp();
|
||||
return Success;
|
||||
});
|
||||
{
|
||||
app.ShowHelp();
|
||||
return Success;
|
||||
});
|
||||
|
||||
return app.Execute(args);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,18 +11,20 @@ namespace Microsoft.DotNet.Watcher
|
|||
{
|
||||
private object _lock = new object();
|
||||
|
||||
public PrefixConsoleReporter(IConsole console, bool verbose, bool quiet)
|
||||
private readonly string _prefix;
|
||||
|
||||
public PrefixConsoleReporter(string prefix, IConsole console, bool verbose, bool quiet)
|
||||
: base(console, verbose, quiet)
|
||||
{ }
|
||||
{
|
||||
_prefix = prefix;
|
||||
}
|
||||
|
||||
protected override void WriteLine(TextWriter writer, string message, ConsoleColor? color)
|
||||
{
|
||||
const string prefix = "watch : ";
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
writer.Write(prefix);
|
||||
writer.Write(_prefix);
|
||||
Console.ResetColor();
|
||||
|
||||
base.WriteLine(writer, message, color);
|
||||
|
|
|
|||
|
|
@ -15,17 +15,17 @@ namespace Microsoft.DotNet.Watcher
|
|||
public class Program : IDisposable
|
||||
{
|
||||
private readonly IConsole _console;
|
||||
private readonly string _workingDir;
|
||||
private readonly string _workingDirectory;
|
||||
private readonly CancellationTokenSource _cts;
|
||||
private IReporter _reporter;
|
||||
|
||||
public Program(IConsole console, string workingDir)
|
||||
public Program(IConsole console, string workingDirectory)
|
||||
{
|
||||
Ensure.NotNull(console, nameof(console));
|
||||
Ensure.NotNullOrEmpty(workingDir, nameof(workingDir));
|
||||
Ensure.NotNullOrEmpty(workingDirectory, nameof(workingDirectory));
|
||||
|
||||
_console = console;
|
||||
_workingDir = workingDir;
|
||||
_workingDirectory = workingDirectory;
|
||||
_cts = new CancellationTokenSource();
|
||||
_console.CancelKeyPress += OnCancelKeyPress;
|
||||
_reporter = CreateReporter(verbose: true, quiet: false, console: _console);
|
||||
|
|
@ -134,7 +134,7 @@ namespace Microsoft.DotNet.Watcher
|
|||
string projectFile;
|
||||
try
|
||||
{
|
||||
projectFile = MsBuildProjectFinder.FindMsBuildProject(_workingDir, project);
|
||||
projectFile = MsBuildProjectFinder.FindMsBuildProject(_workingDirectory, project);
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
|
|
@ -177,7 +177,7 @@ namespace Microsoft.DotNet.Watcher
|
|||
string projectFile;
|
||||
try
|
||||
{
|
||||
projectFile = MsBuildProjectFinder.FindMsBuildProject(_workingDir, project);
|
||||
projectFile = MsBuildProjectFinder.FindMsBuildProject(_workingDirectory, project);
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
|
|
@ -205,7 +205,7 @@ namespace Microsoft.DotNet.Watcher
|
|||
}
|
||||
|
||||
private static IReporter CreateReporter(bool verbose, bool quiet, IConsole console)
|
||||
=> new PrefixConsoleReporter(console, verbose || CliContext.IsGlobalVerbose(), quiet);
|
||||
=> new PrefixConsoleReporter("watch : ", console, verbose || CliContext.IsGlobalVerbose(), quiet);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="$(SharedSourceRoot)Process\*.cs" />
|
||||
<Compile Include="$(SharedSourceRoot)Process\ProcessExtensions.cs" />
|
||||
<Compile Include="$(ToolSharedSourceRoot)CommandLine\**\*.cs" />
|
||||
<None Include="assets\**\*" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
using Xunit.Sdk;
|
||||
|
||||
namespace Microsoft.DotNet.Watcher.Tools.Tests
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
|
@ -113,17 +113,20 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
|
|||
public async Task MultiTfm()
|
||||
{
|
||||
_tempDir
|
||||
.SubDir("src")
|
||||
.SubDir("Project1")
|
||||
.WithCSharpProject("Project1", out var target)
|
||||
.WithTargetFrameworks("netcoreapp1.0", "net451")
|
||||
.WithProperty("EnableDefaultCompileItems", "false")
|
||||
.WithItem("Compile", "Class1.netcore.cs", "'$(TargetFramework)'=='netcoreapp1.0'")
|
||||
.WithItem("Compile", "Class1.desktop.cs", "'$(TargetFramework)'=='net451'")
|
||||
.Dir()
|
||||
.WithFile("Class1.netcore.cs")
|
||||
.WithFile("Class1.desktop.cs")
|
||||
.WithFile("Class1.notincluded.cs");
|
||||
.SubDir("src")
|
||||
.SubDir("Project1")
|
||||
.WithCSharpProject("Project1", out var target)
|
||||
.WithTargetFrameworks("netcoreapp1.0", "net451")
|
||||
.WithProperty("EnableDefaultCompileItems", "false")
|
||||
.WithItem("Compile", "Class1.netcore.cs", "'$(TargetFramework)'=='netcoreapp1.0'")
|
||||
.WithItem("Compile", "Class1.desktop.cs", "'$(TargetFramework)'=='net451'")
|
||||
.Dir()
|
||||
.WithFile("Class1.netcore.cs")
|
||||
.WithFile("Class1.desktop.cs")
|
||||
.WithFile("Class1.notincluded.cs")
|
||||
.Up()
|
||||
.Up()
|
||||
.Create();
|
||||
|
||||
var fileset = await GetFileSet(target);
|
||||
|
||||
|
|
@ -155,7 +158,10 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
|
|||
.WithTargetFrameworks("netcoreapp1.0", "net451")
|
||||
.WithProjectReference(proj2)
|
||||
.Dir()
|
||||
.WithFile("Class1.cs");
|
||||
.WithFile("Class1.cs")
|
||||
.Up()
|
||||
.Up()
|
||||
.Create();
|
||||
|
||||
var fileset = await GetFileSet(target);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Tools.Internal;
|
||||
|
||||
namespace Microsoft.DotNet.Watcher.Tools.Tests
|
||||
{
|
||||
|
|
@ -10,7 +11,7 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
|
|||
{
|
||||
private readonly TemporaryDirectory _directory;
|
||||
private Action<TemporaryCSharpProject> _onCreate;
|
||||
private Dictionary<string, TemporaryCSharpProject> _projects = new Dictionary<string, TemporaryCSharpProject>();
|
||||
private readonly Dictionary<string, TemporaryCSharpProject> _projects = new Dictionary<string, TemporaryCSharpProject>();
|
||||
public TestProjectGraph(TemporaryDirectory directory)
|
||||
{
|
||||
_directory = directory;
|
||||
|
|
@ -28,8 +29,7 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
|
|||
|
||||
public TemporaryCSharpProject GetOrCreate(string projectName)
|
||||
{
|
||||
TemporaryCSharpProject sourceProj;
|
||||
if (!_projects.TryGetValue(projectName, out sourceProj))
|
||||
if (!_projects.TryGetValue(projectName, out TemporaryCSharpProject sourceProj))
|
||||
{
|
||||
sourceProj = _directory.SubDir(projectName).WithCSharpProject(projectName);
|
||||
_onCreate?.Invoke(sourceProj);
|
||||
|
|
@ -38,4 +38,4 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
|
|||
return sourceProj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
|
|
|
|||
Loading…
Reference in New Issue