From d06d36bef4e7cac5fa578bb6e62be2d055041cd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Bertrand?= Date: Fri, 6 Mar 2015 06:36:11 +0100 Subject: [PATCH] Fix #11 and fix #16 --- .../SemanticReleaseNotesFormatterTest.cs | 80 ++++++++++++++----- .../SemanticReleaseNotesParserTest.cs | 23 +++++- SemanticReleaseNotesParser.Core/Metadata.cs | 20 +++++ .../Parser/MetadataDefinition.cs | 14 ++++ .../SemanticReleaseNotesParser.cs | 29 +++++++ .../ReleaseNotes.cs | 8 +- .../Resources/GroupByCategories.liquid | 8 +- .../Resources/GroupBySections.liquid | 8 +- .../SemanticReleaseNotesParser.Core.csproj | 4 +- 9 files changed, 167 insertions(+), 27 deletions(-) create mode 100644 SemanticReleaseNotesParser.Core/Metadata.cs create mode 100644 SemanticReleaseNotesParser.Core/Parser/MetadataDefinition.cs rename SemanticReleaseNotesParser.Core/{ => Parser}/SemanticReleaseNotesParser.cs (84%) diff --git a/SemanticReleaseNotesParser.Core.Tests/SemanticReleaseNotesFormatterTest.cs b/SemanticReleaseNotesParser.Core.Tests/SemanticReleaseNotesFormatterTest.cs index 25413c5..45fcc6d 100644 --- a/SemanticReleaseNotesParser.Core.Tests/SemanticReleaseNotesFormatterTest.cs +++ b/SemanticReleaseNotesParser.Core.Tests/SemanticReleaseNotesFormatterTest.cs @@ -61,23 +61,23 @@ public void Format_ExampleA_Output_Html() public void Format_ExampleA_Output_Markdown() { // act - var resultHtml = SemanticReleaseNotesFormatter.Format(GetExempleAReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown }); + var resultMarkdown = SemanticReleaseNotesFormatter.Format(GetExempleAReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown }); // assert - Assert.Equal(ExampleAMarkdown, resultHtml.Trim()); + Assert.Equal(ExampleAMarkdown, resultMarkdown.Trim()); } [Fact] public void Format_ExampleA_Output_Markdown_TextWriter() { // arrange - var resultHtml = new StringBuilder(); + var resultMarkdown = new StringBuilder(); // act - SemanticReleaseNotesFormatter.Format(new StringWriter(resultHtml), GetExempleAReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown }); + SemanticReleaseNotesFormatter.Format(new StringWriter(resultMarkdown), GetExempleAReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown }); // assert - Assert.Equal(ExampleAMarkdown, resultHtml.ToString().Trim()); + Assert.Equal(ExampleAMarkdown, resultMarkdown.ToString().Trim()); } [Fact] @@ -94,10 +94,10 @@ public void Format_ExampleA_Output_Html_GroupBy_Categories() public void Format_ExampleA_Output_Markdown_GroupBy_Categories() { // act - var resultHtml = SemanticReleaseNotesFormatter.Format(GetExempleAReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown, GroupBy = GroupBy.Categories }); + var resultMarkdown = SemanticReleaseNotesFormatter.Format(GetExempleAReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown, GroupBy = GroupBy.Categories }); // assert - Assert.Equal(ExampleAMarkdownCategories, resultHtml.Trim()); + Assert.Equal(ExampleAMarkdownCategories, resultMarkdown.Trim()); } [Fact] @@ -114,10 +114,10 @@ public void Format_ExampleB_Output_Html() public void Format_ExampleB_Output_Markdown() { // act - var resultHtml = SemanticReleaseNotesFormatter.Format(GetExempleBReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown }); + var resultMarkdown = SemanticReleaseNotesFormatter.Format(GetExempleBReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown }); // assert - Assert.Equal(ExampleBMarkdown, resultHtml.Trim()); + Assert.Equal(ExampleBMarkdown, resultMarkdown.Trim()); } [Fact] @@ -134,10 +134,10 @@ public void Format_ExampleA_Output_Html_Custom_LiquidTemplate() public void Format_ExampleA_Output_Markdown_Custom_LiquidTemplate() { // act - var resultHtml = SemanticReleaseNotesFormatter.Format(GetExempleAReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown, LiquidTemplate = CustomLiquidTemplate }); + var resultMarkdown = SemanticReleaseNotesFormatter.Format(GetExempleAReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown, LiquidTemplate = CustomLiquidTemplate }); // assert - Assert.Equal(CustomLiquidTemplateMarkdown, resultHtml.Trim()); + Assert.Equal(CustomLiquidTemplateMarkdown, resultMarkdown.Trim()); } [Fact] @@ -154,10 +154,10 @@ public void Format_ExampleC_Output_Html() public void Format_ExampleC_Output_Markdown() { // act - var resultHtml = SemanticReleaseNotesFormatter.Format(GetExempleCReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown }); + var resultMarkdown = SemanticReleaseNotesFormatter.Format(GetExempleCReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown }); // assert - Assert.Equal(ExampleCMarkdown, resultHtml.Trim()); + Assert.Equal(ExampleCMarkdown, resultMarkdown.Trim()); } [Fact] @@ -174,10 +174,10 @@ public void Format_ExampleC_Output_Html_GroupBy_Categories() public void Format_ExampleC_Output_Markdown_GroupBy_Categories() { // act - var resultHtml = SemanticReleaseNotesFormatter.Format(GetExempleCReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown, GroupBy = GroupBy.Categories }); + var resultMarkdown = SemanticReleaseNotesFormatter.Format(GetExempleCReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown, GroupBy = GroupBy.Categories }); // assert - Assert.Equal(ExampleCMarkdownCategories, resultHtml.Trim()); + Assert.Equal(ExampleCMarkdownCategories, resultMarkdown.Trim()); } [Fact] @@ -195,10 +195,10 @@ public void Format_ExampleD_Output_Html() public void Format_ExampleD_Output_Markdown() { // act - var resultHtml = SemanticReleaseNotesFormatter.Format(GetExempleDReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown }); + var resultMarkdown = SemanticReleaseNotesFormatter.Format(GetExempleDReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown }); // assert - Assert.Equal(ExampleDMarkdown, resultHtml.Trim()); + Assert.Equal(ExampleDMarkdown, resultMarkdown.Trim()); } [Fact] @@ -215,10 +215,30 @@ public void Format_ExampleA_Output_Html_PluralizeCategoriesTitle() public void Format_ExampleA_Output_Markdown_PluralizeCategoriesTitle() { // act - var resultHtml = SemanticReleaseNotesFormatter.Format(GetExempleABisReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown, GroupBy = GroupBy.Categories, PluralizeCategoriesTitle = true }); + var resultMarkdown = SemanticReleaseNotesFormatter.Format(GetExempleABisReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown, GroupBy = GroupBy.Categories, PluralizeCategoriesTitle = true }); + + // assert + Assert.Equal(ExampleABisMarkdownCategories, resultMarkdown.Trim()); + } + + [Fact] + public void Format_SyntaxMetadataCommits_Output_Html() + { + // act + var resultHtml = SemanticReleaseNotesFormatter.Format(GetSyntaxMetadataCommitsReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Html, GroupBy = GroupBy.Categories, PluralizeCategoriesTitle = true }); + + // assert + Assert.Equal(SyntaxMetadataCommitsHtml, resultHtml.Trim()); + } + + [Fact] + public void Format_SyntaxMetadataCommits_Output_Markdown() + { + // act + var resultMarkdown = SemanticReleaseNotesFormatter.Format(GetSyntaxMetadataCommitsReleaseNotes(), new SemanticReleaseNotesConverterSettings { OutputFormat = OutputFormat.Markdown, GroupBy = GroupBy.Categories, PluralizeCategoriesTitle = true }); // assert - Assert.Equal(ExampleABisMarkdownCategories, resultHtml.Trim()); + Assert.Equal(SyntaxMetadataCommitsMarkdown, resultMarkdown.Trim()); } private ReleaseNotes GetExempleAReleaseNotes() @@ -316,6 +336,18 @@ private ReleaseNotes GetExempleABisReleaseNotes() }; } + private ReleaseNotes GetSyntaxMetadataCommitsReleaseNotes() + { + return new ReleaseNotes + { + Metadata = new List + { + new Metadata { Name = "Commits", Value = "56af25a...d3fead4" }, + new Metadata { Name = "Commits", Value = "[56af25a...d3fead4](https://github.com/Glimpse/Semantic-Release-Notes/compare/56af25a...d3fead4)" } + } + }; + } + private const string ExampleAHtml = @"

Incremental release designed to provide an update to some of the core plugins.

@@ -559,5 +591,15 @@ private ReleaseNotes GetExempleABisReleaseNotes() # Plugin 1. {Changed} *Timeline*: Comes with an additional grid view to show the same data. 1. {Fix} *Ajax*: Fix that crashed poll in Chrome and IE due to log/trace statement. [i1234](http://getglimpse.com)"; + + private const string SyntaxMetadataCommitsMarkdown = @"Commits: 56af25a...d3fead4 +Commits: [56af25a...d3fead4](https://github.com/Glimpse/Semantic-Release-Notes/compare/56af25a...d3fead4)"; + + private const string SyntaxMetadataCommitsHtml = @" + +

Commits: 56af25a...d3fead4

+

Commits: 56af25a...d3fead4

+ +"; } } \ No newline at end of file diff --git a/SemanticReleaseNotesParser.Core.Tests/SemanticReleaseNotesParserTest.cs b/SemanticReleaseNotesParser.Core.Tests/SemanticReleaseNotesParserTest.cs index 555da00..d0289cc 100644 --- a/SemanticReleaseNotesParser.Core.Tests/SemanticReleaseNotesParserTest.cs +++ b/SemanticReleaseNotesParser.Core.Tests/SemanticReleaseNotesParserTest.cs @@ -290,9 +290,10 @@ public void Parse_Real_NVika() var releaseNote = SemanticReleaseNotesParser.Parse(NVikaReleaseNotes); // assert - Assert.Equal(@" + Assert.Equal(1, releaseNote.Metadata.Count); + Assert.Equal("Commits", releaseNote.Metadata[0].Name); + Assert.Equal("[19556f025b...0203ea9a43](https://github.com/laedit/vika/compare/19556f025b...0203ea9a43)", releaseNote.Metadata[0].Value); -Commits: [19556f025b...0203ea9a43](https://github.com/laedit/vika/compare/19556f025b...0203ea9a43)", releaseNote.Summary); Assert.Equal(3, releaseNote.Items.Count); Assert.Equal("Enhancement", releaseNote.Items[0].Categories[0]); @@ -327,6 +328,21 @@ public void Parse_Example_A_WithOnlyLF() Assert.Equal("Fix", releaseNote.Items[3].Categories[0]); } + [Fact] + public void Parse_Syntax_Metadata_Commits() + { + // act + var releaseNote = SemanticReleaseNotesParser.Parse(Syntax_Metadata_Commits); + + // assert + Assert.Equal(2, releaseNote.Metadata.Count); + + Assert.Equal("Commits", releaseNote.Metadata[0].Name); + Assert.Equal("56af25a...d3fead4", releaseNote.Metadata[0].Value); + Assert.Equal("Commits", releaseNote.Metadata[1].Name); + Assert.Equal("[56af25a...d3fead4](https://github.com/Glimpse/Semantic-Release-Notes/compare/56af25a...d3fead4)", releaseNote.Metadata[1].Value); + } + private TextReader GetTextReader(string input) { return new StringReader(input); @@ -426,5 +442,8 @@ This description is specific to plugin section. Commits: [19556f025b...0203ea9a43](https://github.com/laedit/vika/compare/19556f025b...0203ea9a43) "; + + private const string Syntax_Metadata_Commits = @"56af25a...d3fead4 +Commits: [56af25a...d3fead4](https://github.com/Glimpse/Semantic-Release-Notes/compare/56af25a...d3fead4)"; } } \ No newline at end of file diff --git a/SemanticReleaseNotesParser.Core/Metadata.cs b/SemanticReleaseNotesParser.Core/Metadata.cs new file mode 100644 index 0000000..925da67 --- /dev/null +++ b/SemanticReleaseNotesParser.Core/Metadata.cs @@ -0,0 +1,20 @@ +using DotLiquid; + +namespace SemanticReleaseNotesParser.Core +{ + /// + /// Metadata of a release note + /// + public sealed class Metadata : Drop + { + /// + /// Name of the metadata + /// + public string Name { get; set; } + + /// + /// Value of the metadata + /// + public string Value { get; set; } + } +} \ No newline at end of file diff --git a/SemanticReleaseNotesParser.Core/Parser/MetadataDefinition.cs b/SemanticReleaseNotesParser.Core/Parser/MetadataDefinition.cs new file mode 100644 index 0000000..7c153bc --- /dev/null +++ b/SemanticReleaseNotesParser.Core/Parser/MetadataDefinition.cs @@ -0,0 +1,14 @@ +using System; +using System.Text.RegularExpressions; + +namespace SemanticReleaseNotesParser.Core +{ + internal sealed class MetadataDefinition + { + public string Name { get; set; } + + public Regex Regex { get; set; } + + public Func GetValue { get; set; } + } +} \ No newline at end of file diff --git a/SemanticReleaseNotesParser.Core/SemanticReleaseNotesParser.cs b/SemanticReleaseNotesParser.Core/Parser/SemanticReleaseNotesParser.cs similarity index 84% rename from SemanticReleaseNotesParser.Core/SemanticReleaseNotesParser.cs rename to SemanticReleaseNotesParser.Core/Parser/SemanticReleaseNotesParser.cs index 7825d30..1e5d9ab 100644 --- a/SemanticReleaseNotesParser.Core/SemanticReleaseNotesParser.cs +++ b/SemanticReleaseNotesParser.Core/Parser/SemanticReleaseNotesParser.cs @@ -1,5 +1,6 @@ using Humanizer; using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; @@ -17,6 +18,15 @@ internal static class SemanticReleaseNotesParser private static readonly Regex CategoryRegex = new Regex(@"\+([\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex SummaryRegex = new Regex(@"^[a-zA-Z0-9]", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly List MetadataDefinitions = new List + { + { new MetadataDefinition { + Name = "Commits", + Regex = new Regex(@"^(?:commits:)?[ ]*(?:([0-9a-f]{5,40}\.{3}[0-9a-f]{5,40})|(\[[0-9a-f]{5,40}\.{3}[0-9a-f]{5,40}\]\(https?:\/\/\S+\)))$", RegexOptions.Compiled | RegexOptions.IgnoreCase), + GetValue = match => match.Groups[1].Success ? match.Groups[1].Value : match.Groups[2].Value + } } + }; + /// /// Parse a release notes from a stream /// @@ -63,6 +73,11 @@ public static ReleaseNotes Parse(string rawReleaseNotes, SemanticReleaseNotesCon matched = ProcessItem(rawLine, releaseNotes); } + if (!matched) + { + matched = ProcessMetadata(rawLine, releaseNotes); + } + if (!matched) { string nextInput = string.Empty; @@ -77,6 +92,20 @@ public static ReleaseNotes Parse(string rawReleaseNotes, SemanticReleaseNotesCon return releaseNotes; } + private static bool ProcessMetadata(string input, ReleaseNotes releaseNotes) + { + foreach (var metadataDefinition in MetadataDefinitions) + { + var match = metadataDefinition.Regex.Match(input); + if (match.Success) + { + releaseNotes.Metadata.Add(new Metadata { Name = metadataDefinition.Name, Value = metadataDefinition.GetValue(match) }); + return true; + } + } + return false; + } + private static void ProcessPrimary(string input, ReleaseNotes releaseNotes, string nextInput) { input = input.Trim(); diff --git a/SemanticReleaseNotesParser.Core/ReleaseNotes.cs b/SemanticReleaseNotesParser.Core/ReleaseNotes.cs index 0acf181..1b50a2a 100644 --- a/SemanticReleaseNotesParser.Core/ReleaseNotes.cs +++ b/SemanticReleaseNotesParser.Core/ReleaseNotes.cs @@ -23,6 +23,11 @@ public sealed class ReleaseNotes : Drop /// public List Items { get; set; } + /// + /// Metadata of the release notes + /// + public List Metadata { get; set; } + /// /// Instantiates a new ReleaseNotes /// @@ -30,6 +35,7 @@ public ReleaseNotes() { Sections = new List
(); Items = new List(); + Metadata = new List(); } } -} +} \ No newline at end of file diff --git a/SemanticReleaseNotesParser.Core/Resources/GroupByCategories.liquid b/SemanticReleaseNotesParser.Core/Resources/GroupByCategories.liquid index f3f1185..9afeb28 100644 --- a/SemanticReleaseNotesParser.Core/Resources/GroupByCategories.liquid +++ b/SemanticReleaseNotesParser.Core/Resources/GroupByCategories.liquid @@ -1,12 +1,12 @@ {{ release_notes.summary }} -{%- if items_without_categories.size > 0 -%} +{%- if items_without_categories != empty -%} {%- endif -%} {%- for item in items_without_categories -%} {% if item.priority > 0 -%} {{ item.priority }}. {%- else -%} - {%- endif %} {{ item.summary }} {%- if item.task_id %} [{{ item.task_id }}]({{ item.task_link }}) {%- endif -%} {%- endfor -%} -{%- if categories.size > 0 -%} +{%- if categories != empty -%} {%- endif -%} {%- for category in categories -%} @@ -16,4 +16,8 @@ {%- endfor -%} +{%- endfor -%} +{%- for metadata in release_notes.metadata -%} +{{ metadata.name }}: {{ metadata.value }} + {%- endfor -%} \ No newline at end of file diff --git a/SemanticReleaseNotesParser.Core/Resources/GroupBySections.liquid b/SemanticReleaseNotesParser.Core/Resources/GroupBySections.liquid index f95bb39..570a622 100644 --- a/SemanticReleaseNotesParser.Core/Resources/GroupBySections.liquid +++ b/SemanticReleaseNotesParser.Core/Resources/GroupBySections.liquid @@ -1,12 +1,12 @@ {{ release_notes.summary }} -{%- if release_notes.items.size > 0 -%} +{%- if release_notes.items != empty -%} {%- endif -%} {%- for item in release_notes.items -%} {% if item.priority > 0 -%} {{ item.priority }}. {%- else -%} - {%- endif %} {% if item.categories != empty -%}{{ lcb }}{%- for category in item.categories -%}{%- if forloop.first == false -%}, {% endif -%}{{ category }}{%- endfor -%}{{ rcb }} {% endif %}{{ item.summary }} {%- if item.task_id %} [{{ item.task_id }}]({{ item.task_link }}) {%- endif -%} {%- endfor -%} -{%- if release_notes.sections.size > 0 -%} +{%- if release_notes.sections != empty -%} {%- endif -%} {%- for section in release_notes.sections -%} @@ -16,4 +16,8 @@ {%- endfor -%} +{%- endfor -%} +{%- for metadata in release_notes.metadata -%} +{{ metadata.name }}: {{ metadata.value }} + {%- endfor -%} \ No newline at end of file diff --git a/SemanticReleaseNotesParser.Core/SemanticReleaseNotesParser.Core.csproj b/SemanticReleaseNotesParser.Core/SemanticReleaseNotesParser.Core.csproj index 207304d..1f4ed44 100644 --- a/SemanticReleaseNotesParser.Core/SemanticReleaseNotesParser.Core.csproj +++ b/SemanticReleaseNotesParser.Core/SemanticReleaseNotesParser.Core.csproj @@ -58,13 +58,15 @@ + + - +