Skip to content

Commit

Permalink
Merge pull request #143 from PetRich-MSFT/GenerateDocs
Browse files Browse the repository at this point in the history
Initial support for generating Markdown documentation from EDMX files
  • Loading branch information
rgregg authored Jul 17, 2017
2 parents fc88865 + 40b7a3b commit 1a99665
Show file tree
Hide file tree
Showing 43 changed files with 1,900 additions and 47 deletions.
4 changes: 4 additions & 0 deletions ApiDocs.Console/ApiDocs.ConsoleApp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ApiDocs.DocumentationGeneration\ApiDocs.DocumentationGeneration.csproj">
<Project>{cd27998c-4021-4299-970b-91be877fd01b}</Project>
<Name>ApiDocs.DocumentationGeneration</Name>
</ProjectReference>
<ProjectReference Include="..\ApiDocs.Publishing\ApiDocs.Publishing.csproj">
<Project>{B675CF73-AA42-4A54-B5E7-FF5F155DA4A7}</Project>
<Name>ApiDocs.Publishing</Name>
Expand Down
11 changes: 11 additions & 0 deletions ApiDocs.Console/CommandLineOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ class CommandLineOptions
public const string VerbAbout = "about";
public const string VerbCheckAll = "check-all";
public const string VerbPublishMetadata = "publish-edmx";

public const string VerbGenerateDocs = "generate-docs";

[VerbOption(VerbPrint, HelpText="Print files, resources, and methods discovered in the documentation.")]
public PrintOptions PrintVerbOptions { get; set; }
Expand All @@ -72,6 +74,9 @@ class CommandLineOptions
[VerbOption(VerbMetadata, HelpText="Check service CSDL metadata against documentation.")]
public CheckMetadataOptions CheckMetadataVerb { get; set; }

[VerbOption(VerbGenerateDocs, HelpText="Generate documentation from an CSDL model")]
public GenerateDocsOptions GenerateDocsVerb { get; set; }

[VerbOption(VerbAbout, HelpText="Print about information for this application.")]
public BaseOptions AboutVerb { get; set; }

Expand Down Expand Up @@ -541,4 +546,10 @@ public enum PublishFormat
JsonToc
}
}

class GenerateDocsOptions : CheckMetadataOptions
{
[Option("resource-template", HelpText = "Specifies the path to a mustache template file to use for generating documentation for resources (complex and entity types)", Required = false)]
public string ResourceTemplateFile { get; set; }
}
}
29 changes: 27 additions & 2 deletions ApiDocs.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ namespace ApiDocs.ConsoleApp
using System.Linq;
using System.Threading.Tasks;
using AppVeyor;
using ApiDocs.DocumentationGeneration;
using Publishing.Html;
using Publishing.Swagger;
using Validation;
Expand Down Expand Up @@ -200,6 +201,9 @@ private static async Task RunInvokedMethodAsync(CommandLineOptions origCommandLi
case CommandLineOptions.VerbMetadata:
await CheckServiceMetadataAsync((CheckMetadataOptions)options);
break;
case CommandLineOptions.VerbGenerateDocs:
returnSuccess = await GenerateDocsAsync((GenerateDocsOptions)options);
break;
case CommandLineOptions.VerbAbout:
PrintAboutMessage();
Exit(failure: false);
Expand Down Expand Up @@ -1360,7 +1364,7 @@ static void publisher_NewMessage(object sender, ValidationMessageEventArgs e)
}


private static async Task<List<Schema>> TryGetMetadataSchemasAsync(CheckMetadataOptions options)
private static async Task<EntityFramework> TryGetMetadataEntityFrameworkAsync(CheckMetadataOptions options)
{
if (string.IsNullOrEmpty(options.ServiceMetadataLocation))
{
Expand All @@ -1374,7 +1378,7 @@ private static async Task<List<Schema>> TryGetMetadataSchemasAsync(CheckMetadata
try
{
Uri metadataUrl;
if (Uri.TryCreate(options.ServiceMetadataLocation, UriKind.Absolute, out metadataUrl))
if (Uri.IsWellFormedUriString(options.ServiceMetadataLocation, UriKind.Absolute) && Uri.TryCreate(options.ServiceMetadataLocation, UriKind.Absolute, out metadataUrl))
{
edmx = await ODataParser.ParseEntityFrameworkFromUrlAsync(metadataUrl);
}
Expand All @@ -1389,6 +1393,13 @@ private static async Task<List<Schema>> TryGetMetadataSchemasAsync(CheckMetadata
return null;
}

return edmx;
}

private static async Task<List<Schema>> TryGetMetadataSchemasAsync(CheckMetadataOptions options)
{
EntityFramework edmx = await TryGetMetadataEntityFrameworkAsync(options);

return edmx.DataServices.Schemas;
}

Expand Down Expand Up @@ -1481,6 +1492,20 @@ from r in docSet.Resources
results.PrintToConsole();
return !results.WereFailures;
}

private static async Task<bool> GenerateDocsAsync(GenerateDocsOptions options)
{
EntityFramework ef = await TryGetMetadataEntityFrameworkAsync(options);
if (null == ef)
return false;

FancyConsole.WriteLine(FancyConsole.ConsoleSuccessColor, " found {0} schema definitions: {1}", ef.DataServices.Schemas.Count, (from s in ef.DataServices.Schemas select s.Namespace).ComponentsJoinedByString(", "));

DocumentationGenerator docGenerator = new DocumentationGenerator(options.ResourceTemplateFile);
docGenerator.GenerateDocumentationFromEntityFrameworkAsync(ef, options.DocumentationSetPath);

return true;
}
}

class ConsoleAppLogger : ILogHelper
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{32323786-6B69-4A7A-A5DA-DBBBF1148387}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ApiDocs.DocumentationGeneration.UnitTests</RootNamespace>
<AssemblyName>ApiDocs.DocumentationGeneration.UnitTests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="nunit.framework, Version=3.6.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.6.1\lib\net45\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="DescriptionTests.cs" />
<Compile Include="DocumentationTestBase.cs" />
<Compile Include="NavigationPropertyTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PropertyTests.cs" />
<Compile Include="ResourceRoundTripTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ApiDocs.DocumentationGeneration\ApiDocs.DocumentationGeneration.csproj">
<Project>{CD27998C-4021-4299-970B-91BE877FD01B}</Project>
<Name>ApiDocs.DocumentationGeneration</Name>
</ProjectReference>
<ProjectReference Include="..\ApiDocs.Validation.UnitTests\ApiDocs.Validation.UnitTests.csproj">
<Project>{EE3453F1-FD69-406C-9BD7-0643D6E999F3}</Project>
<Name>ApiDocs.Validation.UnitTests</Name>
</ProjectReference>
<ProjectReference Include="..\ApiDocs.Validation\ApiDocs.Validation.csproj">
<Project>{33B10320-3802-49CF-8965-3510AE66D5EC}</Project>
<Name>ApiDocs.Validation</Name>
</ProjectReference>
<ProjectReference Include="..\OSS\markdowndeep\MarkdownDeep\MarkdownDeep.csproj">
<Project>{1569ed47-c7c9-4261-b6f4-7445bd0f2c95}</Project>
<Name>MarkdownDeep</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
76 changes: 76 additions & 0 deletions ApiDocs.DocumentationGeneration.UnitTests/DescriptionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Markdown Scanner
* Copyright (c) Microsoft Corporation
* All rights reserved.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the ""Software""), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

namespace ApiDocs.DocumentationGeneration.Tests
{
using ApiDocs.Validation.OData;

using NUnit.Framework;

[TestFixture]
public class DescriptionTests : DocumentationTestBase
{
[Test]
public void TestInlineComplexTypeDescription()
{
string inlineDescription = "Inline description";
ComplexType ct = this.GetComplexType(this.schema, "Test", inlineDescription: inlineDescription);
string markDown = this.documentationGenerator.GetMarkDownForType(this.entityFramework, ct);

Assert.IsTrue(markDown.Contains(inlineDescription), "Generated markdown should contain inline description annotation");
}

[Test]
public void TestInlinePropertyDescription()
{
string inlineDescription = "Inline property description";
ComplexType ct = this.GetComplexType(this.schema, "Test", inlineDescription: inlineDescription);
this.AddProperty(ct, "TestProperty", inlineDescription: inlineDescription);
string markDown = this.documentationGenerator.GetMarkDownForType(this.entityFramework, ct);

Assert.IsTrue(markDown.Contains(inlineDescription), "Generated markdown should contain inline description annotation");
}

[Test]
public void TestSchemaComplexTypeDescription()
{
string schemaDescription = "Schema description";
ComplexType ct = this.GetComplexType(this.schema, "Test", schemaDescription: schemaDescription);
string markDown = this.documentationGenerator.GetMarkDownForType(this.entityFramework, ct);

Assert.IsTrue(markDown.Contains(schemaDescription), "Generated markdown should contain schema description annotation");
}

[Test]
public void TestSchemaPropertyDescription()
{
string schemaDescription = "Schema description";
ComplexType ct = this.GetComplexType(this.schema, "Test", schemaDescription: schemaDescription);
string markDown = this.documentationGenerator.GetMarkDownForType(this.entityFramework, ct);

Assert.IsTrue(markDown.Contains(schemaDescription), "Generated markdown should contain schema description annotation");
}
}
}
Loading

0 comments on commit 1a99665

Please sign in to comment.