diff --git a/.github/workflows/release-internal.yml b/.github/workflows/release-beta.yml similarity index 97% rename from .github/workflows/release-internal.yml rename to .github/workflows/release-beta.yml index 1231b9e6..9cbebb05 100644 --- a/.github/workflows/release-internal.yml +++ b/.github/workflows/release-beta.yml @@ -1,7 +1,9 @@ name: Publish beta NuGet package on: workflow_dispatch: - + push: + branches: + - vnext jobs: check: runs-on: ubuntu-latest diff --git a/.github/workflows/release-manual.yml b/.github/workflows/release-manual.yml new file mode 100644 index 00000000..0eeca64b --- /dev/null +++ b/.github/workflows/release-manual.yml @@ -0,0 +1,28 @@ +name: Publish custom NuGet package version +on: + workflow_dispatch: + inputs: + package_version: + description: 'NuGet package version (e.g. 6.0.0-beta.1041)' + required: true + +jobs: + pre-release: + runs-on: ubuntu-latest + name: Publish NuGet packages + environment: AsyncAPI + strategy: + matrix: + package-name: [ "LEGO.AsyncAPI", "LEGO.AsyncAPI.Readers", "LEGO.AsyncAPI.Bindings" ] + steps: + - name: Checkout repository + uses: actions/checkout@v1 + + - name: Setup .NET Core @ Latest + uses: actions/setup-dotnet@v1 + + - name: Build ${{ matrix.package-name }} project and pack NuGet package + run: dotnet pack src/${{ matrix.package-name }}/${{ matrix.package-name }}.csproj -c Release -o out-${{ matrix.package-name }} -p:PackageVersion=${{ github.event.inputs.package_version }} + + - name: Push generated package to NuGet + run: dotnet nuget push out-${{ matrix.package-name }}/*.nupkg -s https://api.nuget.org/v3/index.json --skip-duplicate -n --api-key ${{secrets.NUGET}} diff --git a/CODEOWNERS b/CODEOWNERS index f1759cb1..2e87be63 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1 @@ -* @VisualBean +* @VisualBean @UlrikSandberg diff --git a/src/LEGO.AsyncAPI/LEGO.AsyncAPI.csproj b/src/LEGO.AsyncAPI/LEGO.AsyncAPI.csproj index 99e69016..a321a003 100644 --- a/src/LEGO.AsyncAPI/LEGO.AsyncAPI.csproj +++ b/src/LEGO.AsyncAPI/LEGO.AsyncAPI.csproj @@ -19,7 +19,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + <_Parameter1>$(MSBuildProjectName).Tests diff --git a/src/LEGO.AsyncAPI/Models/AsyncApiDocument.cs b/src/LEGO.AsyncAPI/Models/AsyncApiDocument.cs index 5be55202..b6488883 100644 --- a/src/LEGO.AsyncAPI/Models/AsyncApiDocument.cs +++ b/src/LEGO.AsyncAPI/Models/AsyncApiDocument.cs @@ -6,8 +6,8 @@ namespace LEGO.AsyncAPI.Models using System.Collections.Generic; using LEGO.AsyncAPI.Exceptions; using LEGO.AsyncAPI.Models.Interfaces; - using LEGO.AsyncAPI.Writers; using LEGO.AsyncAPI.Services; + using LEGO.AsyncAPI.Writers; /// /// This is the root document object for the API specification. It combines resource listing and API declaration together into one document. @@ -46,7 +46,7 @@ public class AsyncApiDocument : IAsyncApiExtensible, IAsyncApiSerializable /// /// REQUIRED. The available channels and messages for the API. /// - public IDictionary Channels { get; set; } = new Dictionary(); + public IDictionary Channels { get; set; } /// /// an element to hold various schemas for the specification. diff --git a/src/LEGO.AsyncAPI/Validation/Rules/AsyncApiDocumentRules.cs b/src/LEGO.AsyncAPI/Validation/Rules/AsyncApiDocumentRules.cs index 27076369..264c1611 100644 --- a/src/LEGO.AsyncAPI/Validation/Rules/AsyncApiDocumentRules.cs +++ b/src/LEGO.AsyncAPI/Validation/Rules/AsyncApiDocumentRules.cs @@ -30,7 +30,7 @@ public static class AsyncApiDocumentRules context.Exit(); context.Enter("channels"); - if (document.Channels == null || !document.Channels.Keys.Any()) + if (document.Channels == null) { context.CreateError( nameof(DocumentRequiredFields), diff --git a/src/LEGO.AsyncAPI/Writers/AsyncApiWriterExtensions.cs b/src/LEGO.AsyncAPI/Writers/AsyncApiWriterExtensions.cs index 67c4737a..25777d51 100644 --- a/src/LEGO.AsyncAPI/Writers/AsyncApiWriterExtensions.cs +++ b/src/LEGO.AsyncAPI/Writers/AsyncApiWriterExtensions.cs @@ -285,10 +285,7 @@ public static void WriteRequiredMap( Action action) where T : IAsyncApiElement { - if (elements != null && elements.Any()) - { - writer.WriteMapInternal(name, elements, action); - } + writer.WriteMapInternal(name, elements, action); } /// diff --git a/test/LEGO.AsyncAPI.Tests/AsyncApiDocumentBuilder.cs b/test/LEGO.AsyncAPI.Tests/AsyncApiDocumentBuilder.cs index 3f2ee429..886fb7bf 100644 --- a/test/LEGO.AsyncAPI.Tests/AsyncApiDocumentBuilder.cs +++ b/test/LEGO.AsyncAPI.Tests/AsyncApiDocumentBuilder.cs @@ -2,9 +2,10 @@ namespace LEGO.AsyncAPI.Tests { + using System; + using System.Collections.Generic; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Models.Interfaces; - using System; internal class AsyncApiDocumentBuilder { @@ -42,6 +43,10 @@ public AsyncApiDocumentBuilder WithDefaultContentType(string contentType = "appl public AsyncApiDocumentBuilder WithChannel(string key, AsyncApiChannel channel) { + if (this.document.Channels == null) + { + this.document.Channels = new Dictionary(); + } this.document.Channels.Add(key, channel); return this; } diff --git a/test/LEGO.AsyncAPI.Tests/AsyncApiDocumentV2Tests.cs b/test/LEGO.AsyncAPI.Tests/AsyncApiDocumentV2Tests.cs index 63e818b4..13ae85e5 100644 --- a/test/LEGO.AsyncAPI.Tests/AsyncApiDocumentV2Tests.cs +++ b/test/LEGO.AsyncAPI.Tests/AsyncApiDocumentV2Tests.cs @@ -1202,6 +1202,10 @@ public void Serialize_WithBindingReferences_SerializesDeserializes() }, }, }; + if (doc.Channels == null) + { + doc.Channels = new Dictionary(); + } doc.Channels.Add( "testChannel", new AsyncApiChannel @@ -1260,6 +1264,10 @@ public void Serializev2_WithBindings_Serializes() Protocol = "pulsar+ssl", Url = "example.com", }); + if (doc.Channels == null) + { + doc.Channels = new Dictionary(); + } doc.Channels.Add( "testChannel", new AsyncApiChannel @@ -1325,5 +1333,36 @@ public void Serializev2_WithBindings_Serializes() Assert.AreEqual("this mah binding", httpBinding.Headers.Description); } + + + + [Test] + public void SerializeV2_EmptyChannelObject_DeserializeAndSerializePreserveChannelObject() + { + // Arrange + var spec = """ + asyncapi: 2.6.0 + info: + title: Spec with missing channel info + description: test description + servers: + production: + url: example.com + protocol: pulsar+ssl + description: test description + channels: { } + """; + + var settings = new AsyncApiReaderSettings(); + var reader = new AsyncApiStringReader(settings); + + // Act + var deserialized = reader.Read(spec, out var diagnostic); + var actual = deserialized.Serialize(AsyncApiVersion.AsyncApi2_0, AsyncApiFormat.Yaml); + + // Assert + actual.Should() + .BePlatformAgnosticEquivalentTo(spec); + } } } \ No newline at end of file