diff --git a/GitHubIssueFormsParser/src/GitHubIssuesParserCli/IssueFormBody/Parsing/IssueFormBodyParser.cs b/GitHubIssueFormsParser/src/GitHubIssuesParserCli/IssueFormBody/Parsing/IssueFormBodyParser.cs
index 43a6820..2ef7adf 100644
--- a/GitHubIssueFormsParser/src/GitHubIssuesParserCli/IssueFormBody/Parsing/IssueFormBodyParser.cs
+++ b/GitHubIssueFormsParser/src/GitHubIssuesParserCli/IssueFormBody/Parsing/IssueFormBodyParser.cs
@@ -13,7 +13,10 @@ public static IssueFormBody Parse(IssueFormBodyText issueFormBodyText, IssueForm
{
var currentTemplateItem = templateItems[i];
var nextTemplateItem = templateItems.GetNextTemplateElement(i);
- var (startIdx, valueLength) = GetLevel3HeaderValueIndexes(currentTemplateItem.Label, nextTemplateItem?.Label, issueFormBodyText);
+ var (startIdx, valueLength) = GetLevel3HeaderValueIndexes(
+ currentTemplateItem.Label,
+ nextTemplateItem?.Label,
+ issueFormBodyText);
var bodyAsString = (string)issueFormBodyText;
var value = bodyAsString.Substring(startIdx, valueLength);
var issueFormItem = IssueFormItemFactory.CreateFormItem(currentTemplateItem.Id, currentTemplateItem.Type, value);
@@ -50,9 +53,26 @@ private static (int startIdx, int valueLength) GetLevel3HeaderValueIndexes(
private static int GetStartIndex(this IssueFormBodyText issueFormBodyText, string h3HeaderValue)
{
var bodyAsString = (string)issueFormBodyText;
- var startIdx = bodyAsString.IndexOf(h3HeaderValue, StringComparison.Ordinal);
- return startIdx is -1
- ? throw IssueFormBodyParserException.H3HeaderNotFound(h3HeaderValue)
- : startIdx;
+ var h3HeaderValueWindowsLineEnding = h3HeaderValue + NewLines.CR + NewLines.LF;
+ var startIdx = bodyAsString.IndexOf(h3HeaderValueWindowsLineEnding, StringComparison.Ordinal);
+ if (startIdx is not -1)
+ {
+ return startIdx;
+ }
+
+ var h3HeaderValueUnixLineEnding = h3HeaderValue + NewLines.LF;
+ startIdx = bodyAsString.IndexOf(h3HeaderValueUnixLineEnding, StringComparison.Ordinal);
+ if (startIdx is not -1)
+ {
+ return startIdx;
+ }
+
+ throw IssueFormBodyParserException.H3HeaderNotFound(h3HeaderValue);
+ }
+
+ internal static class NewLines
+ {
+ public const string CR = "\r";
+ public const string LF = "\n";
}
}
diff --git a/GitHubIssueFormsParser/tests/GitHubIssuesParserCli.Tests/CliCommands/ParseIssueFormCommandTests.cs b/GitHubIssueFormsParser/tests/GitHubIssuesParserCli.Tests/CliCommands/ParseIssueFormCommandTests.cs
index b10cf39..5d310dd 100644
--- a/GitHubIssueFormsParser/tests/GitHubIssuesParserCli.Tests/CliCommands/ParseIssueFormCommandTests.cs
+++ b/GitHubIssueFormsParser/tests/GitHubIssuesParserCli.Tests/CliCommands/ParseIssueFormCommandTests.cs
@@ -44,7 +44,6 @@ public async Task ParseIssueFormCommandTest1()
/// regardless of the line endings on the issue form body.
///
[Theory]
- [InlineData(CR)]
[InlineData(LF)]
[InlineData(CR + LF)]
public async Task ParseIssueFormCommandTest2(string newLine)
@@ -76,4 +75,27 @@ public async Task ParseIssueFormCommandTest2(string newLine)
issueFormJson.OperatingSystems.Unknown.ShouldNotBeNull();
issueFormJson.OperatingSystems.Unknown.ShouldBe(false);
}
+
+ ///
+ /// Tests that the produces the expected JSON output.
+ /// This tests an edge case scenario for matching on the H3 header values. The matching is done
+ /// with an string.IndexOf method and if two H3 headers start with the same value then the matching
+ /// would always return the first occurence.
+ ///
+ /// This has been fixed by changing the matching so that it only matches if the H3 header value
+ /// matches for an entire line, not just the first string occurence.
+ ///
+ [Fact]
+ public async Task ParseIssueFormCommandTest3()
+ {
+ using var console = new FakeInMemoryConsole();
+ var command = new ParseIssueFormCommand
+ {
+ IssueFormBody = File.ReadAllText("./TestFiles/IssueBody2.md").NormalizeLineEndings(),
+ TemplateFilepath = "./TestFiles/Template2.yml",
+ };
+ await command.ExecuteAsync(console);
+ var output = console.ReadOutputString();
+ output.ShouldNotBeNull();
+ }
}
diff --git a/GitHubIssueFormsParser/tests/GitHubIssuesParserCli.Tests/GitHubIssuesParserCli.Tests.csproj b/GitHubIssueFormsParser/tests/GitHubIssuesParserCli.Tests/GitHubIssuesParserCli.Tests.csproj
index 3502b72..0b0c74e 100644
--- a/GitHubIssueFormsParser/tests/GitHubIssuesParserCli.Tests/GitHubIssuesParserCli.Tests.csproj
+++ b/GitHubIssueFormsParser/tests/GitHubIssuesParserCli.Tests/GitHubIssuesParserCli.Tests.csproj
@@ -48,6 +48,9 @@
PreserveNewest
+
+ PreserveNewest
+
PreserveNewest
@@ -60,6 +63,9 @@
PreserveNewest
+
+ PreserveNewest
+
PreserveNewest
diff --git a/GitHubIssueFormsParser/tests/GitHubIssuesParserCli.Tests/TestFiles/IssueBody2.md b/GitHubIssueFormsParser/tests/GitHubIssuesParserCli.Tests/TestFiles/IssueBody2.md
new file mode 100644
index 0000000..131d0b7
--- /dev/null
+++ b/GitHubIssueFormsParser/tests/GitHubIssuesParserCli.Tests/TestFiles/IssueBody2.md
@@ -0,0 +1,7 @@
+### What NuGet package do you want to release?
+
+dotnet-sdk-extensions
+
+### What
+
+dotnet-sdk-extensions-testing
diff --git a/GitHubIssueFormsParser/tests/GitHubIssuesParserCli.Tests/TestFiles/Template2.yml b/GitHubIssueFormsParser/tests/GitHubIssuesParserCli.Tests/TestFiles/Template2.yml
new file mode 100644
index 0000000..da0fb3c
--- /dev/null
+++ b/GitHubIssueFormsParser/tests/GitHubIssuesParserCli.Tests/TestFiles/Template2.yml
@@ -0,0 +1,22 @@
+name: Release NuGet package
+description: Release a NuGet package.
+title: Release NuGet package
+body:
+ - type: dropdown
+ id: nuget-id
+ attributes:
+ label: What NuGet package do you want to release?
+ options:
+ - dotnet-sdk-extensions
+ - dotnet-sdk-extensions-testing
+ validations:
+ required: true
+ - type: dropdown
+ id: nuget-id-2
+ attributes:
+ label: What
+ options:
+ - dotnet-sdk-extensions
+ - dotnet-sdk-extensions-testing
+ validations:
+ required: true