Skip to content

Commit

Permalink
Merge branch 'master' into drop-dotnet-6
Browse files Browse the repository at this point in the history
  • Loading branch information
martincostello committed Mar 4, 2025
2 parents 73e018f + 48c2982 commit cf81985
Show file tree
Hide file tree
Showing 53 changed files with 912 additions and 2,013 deletions.
26 changes: 13 additions & 13 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,18 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Setup .NET SDKs
uses: actions/setup-dotnet@87b7050bc53ea08284295505d98d2aa94301e852 # v4.2.0
uses: actions/setup-dotnet@3951f0dfe7a07e2313ec93c75700083e2005cbab # v4.3.0
with:
dotnet-version: |
6.0.x
8.0.x
- name: Setup .NET SDK
uses: actions/setup-dotnet@87b7050bc53ea08284295505d98d2aa94301e852 # v4.2.0
uses: actions/setup-dotnet@3951f0dfe7a07e2313ec93c75700083e2005cbab # v4.3.0
id: setup-dotnet

- name: Setup NuGet cache
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.props') }}
Expand All @@ -72,21 +72,21 @@ jobs:
- name: Upload Coverage Reports
if: always()
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
with:
name: coverage-${{ runner.os }}
path: ./artifacts/coverage
if-no-files-found: ignore

- name: Upload coverage to Codecov
uses: codecov/codecov-action@1e68e06f1dbfde0e4cefc87efeba9e4643565303 # v5.1.2
uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # v5.3.1
with:
files: ./artifacts/coverage/coverage.cobertura.xml
flags: ${{ runner.os }}
token: ${{ secrets.CODECOV_TOKEN }}

- name: Attest artifacts
uses: actions/attest-build-provenance@7668571508540a607bdfd90a87a560489fe372eb # v2.1.0
uses: actions/attest-build-provenance@520d128f165991a6c774bcb264f323e3d70747f4 # v2.2.0
if: |
runner.os == 'Windows' &&
github.event.repository.fork == false &&
Expand All @@ -95,7 +95,7 @@ jobs:
subject-path: ./artifacts/package/release/*

- name: Publish NuGet packages
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
with:
name: packages-${{ runner.os }}
path: ./artifacts/package/release
Expand All @@ -115,12 +115,12 @@ jobs:
steps:

- name: Download packages
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4.1.9
with:
name: packages-Windows

- name: Setup .NET SDK
uses: actions/setup-dotnet@87b7050bc53ea08284295505d98d2aa94301e852 # v4.2.0
uses: actions/setup-dotnet@3951f0dfe7a07e2313ec93c75700083e2005cbab # v4.3.0
with:
dotnet-version: ${{ needs.build.outputs.dotnet-sdk-version }}

Expand Down Expand Up @@ -158,12 +158,12 @@ jobs:
steps:

- name: Download packages
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4.1.9
with:
name: packages-Windows

- name: Setup .NET SDK
uses: actions/setup-dotnet@87b7050bc53ea08284295505d98d2aa94301e852 # v4.2.0
uses: actions/setup-dotnet@3951f0dfe7a07e2313ec93c75700083e2005cbab # v4.3.0
with:
dotnet-version: ${{ needs.build.outputs.dotnet-sdk-version }}

Expand All @@ -185,12 +185,12 @@ jobs:
steps:

- name: Download packages
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4.1.9
with:
name: packages-Windows

- name: Setup .NET SDK
uses: actions/setup-dotnet@87b7050bc53ea08284295505d98d2aa94301e852 # v4.2.0
uses: actions/setup-dotnet@3951f0dfe7a07e2313ec93c75700083e2005cbab # v4.3.0
with:
dotnet-version: ${{ needs.build.outputs.dotnet-sdk-version }}

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Initialize CodeQL
uses: github/codeql-action/init@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1
uses: github/codeql-action/init@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
with:
languages: csharp
build-mode: none

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1
uses: github/codeql-action/analyze@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
with:
category: '/language:csharp'
6 changes: 3 additions & 3 deletions .github/workflows/ossf-scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,20 @@ jobs:
persist-credentials: false

- name: Run analysis
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
with:
publish_results: true
results_file: results.sarif
results_format: sarif

- name: Upload artifact
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
with:
name: SARIF
path: results.sarif
retention-days: 5

- name: Upload to code-scanning
uses: github/codeql-action/upload-sarif@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1
uses: github/codeql-action/upload-sarif@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
with:
sarif_file: results.sarif
4 changes: 2 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<PackageReadmeFile>package-readme.md</PackageReadmeFile>
<PackageReleaseNotes>See $(PackageProjectUrl)/releases for details.</PackageReleaseNotes>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<PackageValidationBaselineVersion>7.2.0</PackageValidationBaselineVersion>
<PackageValidationBaselineVersion>7.3.1</PackageValidationBaselineVersion>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>$(PackageProjectUrl).git</RepositoryUrl>
Expand All @@ -45,7 +45,7 @@
<VersionPrefix>8.0.0</VersionPrefix>
<WarnOnPackingNonPackableProject>false</WarnOnPackingNonPackableProject>
</PropertyGroup>
<PropertyGroup Condition=" '$(GITHUB_ACTIONS)' != '' ">
<PropertyGroup Condition=" '$(GITHUB_ACTIONS)' != '' AND '$(DEPENDABOT_JOB_ID)' == '' ">
<VersionSuffix Condition=" '$(VersionSuffix)' == '' AND '$(GITHUB_HEAD_REF)' == '' ">preview.$(GITHUB_RUN_NUMBER)</VersionSuffix>
<VersionSuffix Condition=" '$(VersionSuffix)' == '' AND '$(GITHUB_HEAD_REF)' != '' ">pr.$(GITHUB_REF_NAME.Replace('/merge', '')).$(GITHUB_RUN_NUMBER)</VersionSuffix>
<VersionPrefix Condition=" $(GITHUB_REF.StartsWith(`refs/tags/v`)) ">$(GITHUB_REF.Replace('refs/tags/v', ''))</VersionPrefix>
Expand Down
2 changes: 1 addition & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="NSubstitute" Version="5.3.0" />
<PackageVersion Include="NSwag.MSBuild" Version="14.1.0" />
<PackageVersion Include="NSwag.MSBuild" Version="14.2.0" />
<PackageVersion Include="ReportGenerator" Version="5.4.1" />
<PackageVersion Include="System.Text.Json" Version="4.6.0" />
<PackageVersion Include="Verify.Xunit" Version="28.3.2" />
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Once you have an API that can describe itself in Swagger, you've opened the trea
| Swashbuckle Version | ASP.NET Core | Swagger / OpenAPI Spec. | swagger-ui | Redoc UI |
|----------|----------|----------|----------|----------|
| [CI](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/commits/master/) | >= 2.0.0 | 2.0, 3.0 | [5.x.x](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/src/Swashbuckle.AspNetCore.SwaggerUI/package.json#L6) | [2.x.x](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/src/Swashbuckle.AspNetCore.ReDoc/package.json#L6) |
| [7.2.0](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/tree/v7.2.0) | >= 2.0.0 | 2.0, 3.0 | 5.18.2 | 2.2.0 |
| [7.3.1](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/tree/v7.2.0) | >= 2.0.0 | 2.0, 3.0 | 5.20.0 | 2.4.0 |
| [6.9.0](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/tree/v6.9.0) | >= 2.0.0 | 2.0, 3.0 | 5.17.14 | 2.1.5 |
| [5.6.3](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/tree/v5.6.3) | >= 2.0.0 | 2.0, 3.0 | 3.32.5 | 2.0.0-rc.40 |
| [4.0.0](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/tree/v4.0.0) | >= 2.0.0, < 3.0.0 | 2.0 | 3.19.5 | 1.22.2 |
Expand Down Expand Up @@ -565,8 +565,8 @@ To enhance the generated docs with human-friendly descriptions, you can annotate
[ProducesResponseType(500)]
public Product GetById(int id)
```
4. You can also annotate types with summary and example tags:

4. Annotate your types with summary and example tags, other tags (remarks, para, etc.) are not supported:

```csharp
public class Product
Expand All @@ -582,12 +582,12 @@ To enhance the generated docs with human-friendly descriptions, you can annotate
/// </summary>
/// <example>10</example>
public int AvailableStock { get; set; }

/// <summary>
/// The sizes the product is available in
/// </summary>
/// <example>["Small", "Medium", "Large"]</example>
public List<string> Sizes { get; set; }
public List<string> Sizes { get; set; }
}
```

Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "9.0.102",
"version": "9.0.200",
"allowPrerelease": false,
"rollForward": "latestMajor"
}
Expand Down
138 changes: 105 additions & 33 deletions src/Swashbuckle.AspNetCore.Cli/Program.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -41,29 +43,7 @@ public static int Main(string[] args)

c.OnRun((namedArgs) =>
{
if (!File.Exists(namedArgs["startupassembly"]))
{
throw new FileNotFoundException(namedArgs["startupassembly"]);
}

var depsFile = namedArgs["startupassembly"].Replace(".dll", ".deps.json");
var runtimeConfig = namedArgs["startupassembly"].Replace(".dll", ".runtimeconfig.json");
var commandName = args[0];

var subProcessArguments = new string[args.Length - 1];
if (subProcessArguments.Length > 0)
{
Array.Copy(args, 1, subProcessArguments, 0, subProcessArguments.Length);
}

var subProcessCommandLine = string.Format(
"exec --depsfile {0} --runtimeconfig {1} {2} _{3} {4}", // note the underscore prepended to the command name
EscapePath(depsFile),
EscapePath(runtimeConfig),
EscapePath(typeof(Program).GetTypeInfo().Assembly.Location),
commandName,
string.Join(" ", subProcessArguments.Select(x => EscapePath(x)))
);
string subProcessCommandLine = PrepareCommandLine(args, namedArgs);

var subProcess = Process.Start("dotnet", subProcessCommandLine);

Expand All @@ -84,16 +64,7 @@ public static int Main(string[] args)
c.Option("--yaml", "", true);
c.OnRun((namedArgs) =>
{
// 1) Configure host with provided startupassembly
var startupAssembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(
Path.Combine(Directory.GetCurrentDirectory(), namedArgs["startupassembly"]));

// 2) Build a service container that's based on the startup assembly
var serviceProvider = GetServiceProvider(startupAssembly);

// 3) Retrieve Swagger via configured provider
var swaggerProvider = serviceProvider.GetRequiredService<ISwaggerProvider>();
var swaggerOptions = serviceProvider.GetService<IOptions<SwaggerOptions>>();
SetupAndRetrieveSwaggerProviderAndOptions(namedArgs, out var swaggerProvider, out var swaggerOptions);
var swaggerDocumentSerializer = swaggerOptions?.Value?.CustomDocumentSerializer;
var swagger = swaggerProvider.GetSwagger(
namedArgs["swaggerdoc"],
Expand Down Expand Up @@ -156,9 +127,110 @@ public static int Main(string[] args)
});
});

// > dotnet swagger list
runner.SubCommand("list", "retrieves the list of Swagger document names from a startup assembly", c =>
{
c.Argument("startupassembly", "relative path to the application's startup assembly");
c.Option("--output", "relative path where the document names will be output, defaults to stdout");
c.OnRun((namedArgs) =>
{
string subProcessCommandLine = PrepareCommandLine(args, namedArgs);

var subProcess = Process.Start("dotnet", subProcessCommandLine);

subProcess.WaitForExit();
return subProcess.ExitCode;
});
});

// > dotnet swagger _list ... (* should only be invoked via "dotnet exec")
runner.SubCommand("_list", "", c =>
{
c.Argument("startupassembly", "");
c.Option("--output", "");
c.OnRun((namedArgs) =>
{
SetupAndRetrieveSwaggerProviderAndOptions(namedArgs, out var swaggerProvider, out var swaggerOptions);
IList<string> docNames = new List<string>();

string outputPath = namedArgs.TryGetValue("--output", out var arg1)
? Path.Combine(Directory.GetCurrentDirectory(), arg1)
: null;
bool outputViaConsole = outputPath == null;
if (!string.IsNullOrEmpty(outputPath))
{
string directoryPath = Path.GetDirectoryName(outputPath);
if (!string.IsNullOrEmpty(directoryPath) && !Directory.Exists(directoryPath))
{
Directory.CreateDirectory(directoryPath);
}
}

using Stream stream = outputViaConsole ? Console.OpenStandardOutput() : File.Create(outputPath);
using StreamWriter writer = new(stream, outputViaConsole ? Console.OutputEncoding : Encoding.UTF8);

if (swaggerProvider is not ISwaggerDocumentMetadataProvider docMetaProvider)
{
writer.WriteLine($"The registered {nameof(ISwaggerProvider)} instance does not implement {nameof(ISwaggerDocumentMetadataProvider)}; unable to list the Swagger document names.");
return -1;
}

docNames = docMetaProvider.GetDocumentNames();

foreach (var name in docNames)
{
writer.WriteLine($"\"{name}\"");
}

return 0;
});
});

return runner.Run(args);
}

private static void SetupAndRetrieveSwaggerProviderAndOptions(System.Collections.Generic.IDictionary<string, string> namedArgs, out ISwaggerProvider swaggerProvider, out IOptions<SwaggerOptions> swaggerOptions)
{
// 1) Configure host with provided startupassembly
var startupAssembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(
Path.Combine(Directory.GetCurrentDirectory(), namedArgs["startupassembly"]));

// 2) Build a service container that's based on the startup assembly
var serviceProvider = GetServiceProvider(startupAssembly);

// 3) Retrieve Swagger via configured provider
swaggerProvider = serviceProvider.GetRequiredService<ISwaggerProvider>();
swaggerOptions = serviceProvider.GetService<IOptions<SwaggerOptions>>();
}

private static string PrepareCommandLine(string[] args, System.Collections.Generic.IDictionary<string, string> namedArgs)
{
if (!File.Exists(namedArgs["startupassembly"]))
{
throw new FileNotFoundException(namedArgs["startupassembly"]);
}

var depsFile = namedArgs["startupassembly"].Replace(".dll", ".deps.json");
var runtimeConfig = namedArgs["startupassembly"].Replace(".dll", ".runtimeconfig.json");
var commandName = args[0];

var subProcessArguments = new string[args.Length - 1];
if (subProcessArguments.Length > 0)
{
Array.Copy(args, 1, subProcessArguments, 0, subProcessArguments.Length);
}

var subProcessCommandLine = string.Format(
"exec --depsfile {0} --runtimeconfig {1} {2} _{3} {4}", // note the underscore prepended to the command name
EscapePath(depsFile),
EscapePath(runtimeConfig),
EscapePath(typeof(Program).GetTypeInfo().Assembly.Location),
commandName,
string.Join(" ", subProcessArguments.Select(x => EscapePath(x)))
);
return subProcessCommandLine;
}

private static string EscapePath(string path)
{
return path.Contains(' ')
Expand Down
Loading

0 comments on commit cf81985

Please sign in to comment.