From 0bcbc4593bf8c1d53d1ffe5b33d00af1dfad6000 Mon Sep 17 00:00:00 2001
From: Thomas Boby
Date: Thu, 24 Oct 2024 08:42:01 +0100
Subject: [PATCH 1/7] Add pipeline auto-formatter and config changes from #24
---
.editorconfig | 20 ++++++--------------
.gitattributes | 7 +++++++
.github/workflows/buildAndTest.yml | 4 ++++
3 files changed, 17 insertions(+), 14 deletions(-)
create mode 100644 .gitattributes
diff --git a/.editorconfig b/.editorconfig
index eab37e5..2fbe3eb 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,23 +1,15 @@
root = true
-[*]
+[*.{fs,fsi,fsx}]
end_of_line = lf
-insert_final_newline = true
-indent_style = space
-indent_size = 4
-trim_trailing_whitespace = true
-
-[*.{fs,fsx,fsi}]
-max_line_length = 100
fsharp_alternative_long_member_definitions = true
fsharp_multi_line_lambda_closing_newline = true
fsharp_multiline_bracket_style = aligned
fsharp_keep_max_number_of_blank_lines = 1
fsharp_align_function_signature_to_indentation = true
-fsharp_max_if_then_else_short_width = 0
+fsharp_experimental_keep_indent_in_branch = true
+fsharp_bar_before_discriminated_union_declaration = true
-fsharp_experimental_elmish = true
-fsharp_record_multiline_formatter = number_of_items
-fsharp_array_or_list_multiline_formatter = number_of_items
-fsharp_max_record_number_of_items = 0
-fsharp_max_array_or_list_number_of_items = 0
+# Expecto looks a bit nicer with stroustrup
+[tests/**/*.fs]
+fsharp_multiline_bracket_style = stroustrup
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..e3ca87a
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,7 @@
+# Automatically normalize line endings
+* text=auto
+
+# Always use lf for F# files
+*.fs text eol=lf
+*.fsx text eol=lf
+*.fsi text eol=lf
\ No newline at end of file
diff --git a/.github/workflows/buildAndTest.yml b/.github/workflows/buildAndTest.yml
index 08dfdd1..3a9c110 100644
--- a/.github/workflows/buildAndTest.yml
+++ b/.github/workflows/buildAndTest.yml
@@ -12,6 +12,10 @@ jobs:
- uses: actions/checkout@v2
- name: Setup .NET Core
uses: actions/setup-dotnet@v4
+ - name: Tool restore
+ run: dotnet tool restore
+ - name: Format Check
+ run: dotnet fantomas . --check || echo "The code was not formatted, run `dotnet fantomas .` to format all code."
- name: Restore
run: dotnet restore
- name: Run Build
From 81c70d57c21e173f2203e48e02daba4a43df467b Mon Sep 17 00:00:00 2001
From: Thomas Boby
Date: Thu, 24 Oct 2024 08:43:54 +0100
Subject: [PATCH 2/7] Add stricter warnings/errors
---
Directory.Build.props | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/Directory.Build.props b/Directory.Build.props
index 6d0ad57..d35d286 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -9,6 +9,13 @@
true
true
+
+ true
+ $(NoWarn);3186,0042
+ $(NoWarn);NU1902
+ $(WarnOn);1182
+ $(WarnOn);3390
+
From 708cedf35d5814d8efb06343a5d803af62afe850 Mon Sep 17 00:00:00 2001
From: Thomas Boby
Date: Thu, 24 Oct 2024 08:49:56 +0100
Subject: [PATCH 3/7] Fail pipeline on formatting fail
---
.github/workflows/buildAndTest.yml | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/buildAndTest.yml b/.github/workflows/buildAndTest.yml
index 3a9c110..8f9d0db 100644
--- a/.github/workflows/buildAndTest.yml
+++ b/.github/workflows/buildAndTest.yml
@@ -15,7 +15,10 @@ jobs:
- name: Tool restore
run: dotnet tool restore
- name: Format Check
- run: dotnet fantomas . --check || echo "The code was not formatted, run `dotnet fantomas .` to format all code."
+ run: dotnet fantomas . --check
+ - name: log format failure
+ if: failure()
+ run: echo "The code was not formatted, run `dotnet fantomas .` to format all code."
- name: Restore
run: dotnet restore
- name: Run Build
From dc95c133fc795da8e03ceb9e5d80af9d76aed1da Mon Sep 17 00:00:00 2001
From: Thomas Boby
Date: Thu, 24 Oct 2024 08:49:56 +0100
Subject: [PATCH 4/7] Fail pipeline on formatting fail
---
.github/workflows/buildAndTest.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/buildAndTest.yml b/.github/workflows/buildAndTest.yml
index 8f9d0db..680f2bd 100644
--- a/.github/workflows/buildAndTest.yml
+++ b/.github/workflows/buildAndTest.yml
@@ -18,7 +18,7 @@ jobs:
run: dotnet fantomas . --check
- name: log format failure
if: failure()
- run: echo "The code was not formatted, run `dotnet fantomas .` to format all code."
+ run: echo "The code was not formatted, run 'dotnet fantomas .' to format all code."
- name: Restore
run: dotnet restore
- name: Run Build
From 635df0503f2f9c16e1d102d2ba320dd0b9fc10c2 Mon Sep 17 00:00:00 2001
From: Thomas Boby
Date: Thu, 24 Oct 2024 08:53:39 +0100
Subject: [PATCH 5/7] Single step CICD
---
.github/workflows/buildAndTest.yml | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/.github/workflows/buildAndTest.yml b/.github/workflows/buildAndTest.yml
index 680f2bd..870df03 100644
--- a/.github/workflows/buildAndTest.yml
+++ b/.github/workflows/buildAndTest.yml
@@ -15,10 +15,7 @@ jobs:
- name: Tool restore
run: dotnet tool restore
- name: Format Check
- run: dotnet fantomas . --check
- - name: log format failure
- if: failure()
- run: echo "The code was not formatted, run 'dotnet fantomas .' to format all code."
+ run: dotnet fantomas . --check || { if [ $? -eq 99 ]; then echo "The code was not formatted, run 'dotnet fantomas .' to format all code."; exit 1; fi; }
- name: Restore
run: dotnet restore
- name: Run Build
From 0d6c9ff65b1ace0dc95d25380d1ceba40239b93e Mon Sep 17 00:00:00 2001
From: Thomas Boby
Date: Thu, 24 Oct 2024 08:55:41 +0100
Subject: [PATCH 6/7] Apply formatting
---
src/Library.fs | 22 ++++++++-----
src/Log.fs | 11 ++-----
tests/IntegrationTests.fs | 11 ++++---
tests/UnitTests.fs | 67 ++++++++++++++++++++++++---------------
4 files changed, 63 insertions(+), 48 deletions(-)
diff --git a/src/Library.fs b/src/Library.fs
index 07c36a7..a48d7c6 100644
--- a/src/Library.fs
+++ b/src/Library.fs
@@ -32,7 +32,8 @@ type ChangelogExtensions =
(string section.Type,
section.ItemCollection
|> Seq.map _.MarkdownText
- |> String.concat Environment.NewLine))
+ |> String.concat Environment.NewLine)
+ )
[]
static member ToTaskItem(unreleased: ChangelogSectionUnreleased) =
@@ -51,9 +52,12 @@ type ChangelogExtensions =
| false, _ -> None
| true, version ->
Some
- {| version = version
- date = section.ToDateTime()
- collection = section.SubSectionCollection |})
+ {|
+ version = version
+ date = section.ToDateTime()
+ collection = section.SubSectionCollection
+ |}
+ )
[]
static member ToMarkdown(subsections: ChangelogSubSectionCollection) =
@@ -62,12 +66,13 @@ type ChangelogExtensions =
subsections
|> Seq.fold
(fun (builder: StringBuilder) subsection ->
- let state = builder.AppendLine $"### {subsection.Type}"
- |> (fun x -> x.AppendLine "")
+ let state =
+ builder.AppendLine $"### {subsection.Type}" |> (fun x -> x.AppendLine "")
subsection.ItemCollection
|> Seq.fold (fun (builder: StringBuilder) line -> builder.AppendLine $"- {line.MarkdownText}") state
- |> (fun x -> x.AppendLine ""))
+ |> (fun x -> x.AppendLine "")
+ )
builder
|> _.ToString()
|> _.Trim()
@@ -146,7 +151,8 @@ type ParseChangeLogs() =
for (key, value) in x.collection.ToTaskItemMetadata() do
taskItem.SetMetadata(key, value)
- taskItem :> ITaskItem)
+ taskItem :> ITaskItem
+ )
this.CurrentReleaseChangelog <- mapped[0]
this.AllReleasedChangelogs <- mapped
diff --git a/src/Log.fs b/src/Log.fs
index 0a12007..042d64f 100644
--- a/src/Log.fs
+++ b/src/Log.fs
@@ -19,10 +19,7 @@ let changelogFileNotFound (filePath: string) =
ErrorCode = "IKC0001"
HelpKeyword = "Missing Changelog file"
Message = "The Changelog file {0} was not found."
- MessageArgs =
- [|
- box filePath
- |]
+ MessageArgs = [| box filePath |]
}
let invalidChangelog (filePath: string) (error: string) =
@@ -30,9 +27,5 @@ let invalidChangelog (filePath: string) (error: string) =
ErrorCode = "IKC0002"
HelpKeyword = "Invalid Changelog file"
Message = "The Changelog file {0} is invalid. The error was: {1}"
- MessageArgs =
- [|
- box filePath
- box error
- |]
+ MessageArgs = [| box filePath; box error |]
}
diff --git a/tests/IntegrationTests.fs b/tests/IntegrationTests.fs
index f4fbdcf..a1184db 100644
--- a/tests/IntegrationTests.fs
+++ b/tests/IntegrationTests.fs
@@ -9,13 +9,15 @@ open Faqt
open SimpleExec
open Workspace
-
module Utils =
let packAndGetPackageProperties projectName =
let packageCache = VirtualWorkspace.``test-package-cache``.``.``
+
if Directory.Exists packageCache then
Directory.Delete(packageCache, true)
+
Directory.CreateDirectory packageCache |> ignore
+
Command.Run(
"dotnet",
CmdLine.empty
@@ -24,6 +26,7 @@ module Utils =
|> CmdLine.toString,
workingDirectory = Workspace.fixtures.``.``
)
+
Command.ReadAsync(
"dotnet",
CmdLine.empty
@@ -39,8 +42,8 @@ module Utils =
type StringHelper =
[]
- static member ReplaceEscapedNewLines (s: string) =
- s.ReplaceLineEndings().Replace("\\r\\n","\\n")
+ static member ReplaceEscapedNewLines(s: string) =
+ s.ReplaceLineEndings().Replace("\\r\\n", "\\n")
[]
type IntegrationTests() =
@@ -52,7 +55,6 @@ type IntegrationTests() =
this.testPackageVersion <- $"0.0.1-test-{suffix}"
-
// Create a package to be used in the tests
// I didn't find a way to test the MSBuild tasks execution using MSBuild only
// So each fsproj, will use a package reference to the package created here
@@ -78,7 +80,6 @@ type IntegrationTests() =
workingDirectory = Workspace.fixtures.``.``
)
-
[]
member this.``works for absolute path with keep a changelog``() : Task =
task {
diff --git a/tests/UnitTests.fs b/tests/UnitTests.fs
index 32b328f..b66825b 100644
--- a/tests/UnitTests.fs
+++ b/tests/UnitTests.fs
@@ -8,25 +8,25 @@ open Faqt.Operators
open Microsoft.VisualStudio.TestTools.UnitTesting
open Workspace
-type TestContext =
- {
- BuildEngine: Mock
- Errors: ResizeArray
- }
+type TestContext = {
+ BuildEngine: Mock
+ Errors: ResizeArray
+} with
member this.PrintErrors() =
this.Errors |> Seq.iter (fun error -> printfn "Error: %s" error.Message)
+
[]
type UnitTests() =
member val context = Unchecked.defaultof with get, set
+
[]
member this.Initialize() =
- this.context <-
- {
- BuildEngine = Mock()
- Errors = ResizeArray()
- }
+ this.context <- {
+ BuildEngine = Mock()
+ Errors = ResizeArray()
+ }
this.context.BuildEngine
.Setup(fun engine -> engine.LogErrorEvent(It.IsAny()))
@@ -34,7 +34,7 @@ type UnitTests() =
|> ignore
[]
- member this.``task fails when changelog file does not exist`` () =
+ member this.``task fails when changelog file does not exist``() =
let myTask = ParseChangeLogs(ChangelogFile = "ThisFileDoesNotExist.md")
myTask.BuildEngine <- this.context.BuildEngine.Object
@@ -46,7 +46,7 @@ type UnitTests() =
%this.context.Errors.[0].Code.Should().Be("IKC0001")
[]
- member this.``task succeeds when changelog file exists (relative path)`` () =
+ member this.``task succeeds when changelog file exists (relative path)``() =
// When running tests, the working directory is where the dll is located
let myTask = ParseChangeLogs(ChangelogFile = "../../../changelogs/CHANGELOG.md")
@@ -60,7 +60,7 @@ type UnitTests() =
%this.context.Errors.Count.Should().Be(0)
[]
- member this.``task succeeds when changelog file exists (absolute path)`` () =
+ member this.``task succeeds when changelog file exists (absolute path)``() =
let myTask = ParseChangeLogs(ChangelogFile = Workspace.changelogs.``CHANGELOG.md``)
myTask.BuildEngine <- this.context.BuildEngine.Object
@@ -70,7 +70,7 @@ type UnitTests() =
%this.context.Errors.Count.Should().Be(0)
[]
- member this.``task fails when changelog file is invalid`` () =
+ member this.``task fails when changelog file is invalid``() =
let myTask =
ParseChangeLogs(ChangelogFile = Workspace.changelogs.``CHANGELOG_invalid.md``)
@@ -82,9 +82,8 @@ type UnitTests() =
%this.context.Errors.Count.Should().Be(1)
%this.context.Errors.[0].Code.Should().Be("IKC0002")
-
[]
- member this.``task correctly parses details from changelog file`` () =
+ member this.``task correctly parses details from changelog file``() =
let myTask =
ParseChangeLogs(ChangelogFile = Workspace.changelogs.``CHANGELOG_detailed.md``)
@@ -93,26 +92,42 @@ type UnitTests() =
let success = myTask.Execute()
%success.Should().BeTrue "Should have successfully parsed the changelog data"
%myTask.AllReleasedChangelogs.Length.Should().Be(9, "Should have 9 versions")
- %myTask.CurrentReleaseChangelog.ItemSpec.Should().Be("0.1.8", "Should have the most recent version")
- %myTask.CurrentReleaseChangelog.GetMetadata("Date").Should().Be("2022-03-31", "Should have the most recent version's date")
- %(myTask.CurrentReleaseChangelog.MetadataNames |> Seq.cast |> _.Should().Contain("Changed", "Should have changed metadata"))
- %(myTask.CurrentReleaseChangelog.MetadataNames |> Seq.cast |> _.Should().Contain("Date", "Should have date metadata"))
+
+ %myTask.CurrentReleaseChangelog.ItemSpec
+ .Should()
+ .Be("0.1.8", "Should have the most recent version")
+
+ %myTask.CurrentReleaseChangelog
+ .GetMetadata("Date")
+ .Should()
+ .Be("2022-03-31", "Should have the most recent version's date")
+
+ %(myTask.CurrentReleaseChangelog.MetadataNames
+ |> Seq.cast
+ |> _.Should().Contain("Changed", "Should have changed metadata"))
+
+ %(myTask.CurrentReleaseChangelog.MetadataNames
+ |> Seq.cast
+ |> _.Should().Contain("Date", "Should have date metadata"))
[]
- member this.``task produces expected markdown`` () =
- let myTask =
- ParseChangeLogs(ChangelogFile = Workspace.changelogs.``CHANGELOG.md``)
+ member this.``task produces expected markdown``() =
+ let myTask = ParseChangeLogs(ChangelogFile = Workspace.changelogs.``CHANGELOG.md``)
myTask.BuildEngine <- this.context.BuildEngine.Object
let success = myTask.Execute()
%success.Should().BeTrue "Should have successfully parsed the changelog data"
- %myTask.LatestReleaseNotes.Should().Be("""### Added
+
+ %myTask.LatestReleaseNotes
+ .Should()
+ .Be(
+ """### Added
- Created the package
### Changed
- Changed something in the package
-- Updated the target framework""")
-
+- Updated the target framework"""
+ )
From 2a952a0ab2488b4851af2d990f02e82ef52224d3 Mon Sep 17 00:00:00 2001
From: Thomas Boby
Date: Fri, 25 Oct 2024 08:42:15 +0100
Subject: [PATCH 7/7] Create line ending assertion helper for tests
---
tests/Helpers.fs | 32 +++++++++++++++++++
tests/IntegrationTests.fs | 20 ++++--------
tests/Ionide.KeepAChangelog.Tasks.Test.fsproj | 1 +
tests/UnitTests.fs | 4 ++-
4 files changed, 42 insertions(+), 15 deletions(-)
create mode 100644 tests/Helpers.fs
diff --git a/tests/Helpers.fs b/tests/Helpers.fs
new file mode 100644
index 0000000..33e5fa6
--- /dev/null
+++ b/tests/Helpers.fs
@@ -0,0 +1,32 @@
+module Ionide.KeepAChangelog.Tasks.Test.Helpers
+
+open System.Runtime.CompilerServices
+open Faqt
+open Faqt.AssertionHelpers
+
+[]
+type Assertions =
+
+ /// Asserts that the subject is equal to the specified string when CLRF is replaced with LF in both raw and
+ /// escaped forms.
+ []
+ static member BeLineEndingEquivalent(t: Testable, expected: string, ?because) : And =
+ use _ = t.Assert()
+
+ if isNull expected then
+ nullArg (nameof expected)
+
+ if isNull t.Subject then
+ t.With("Expected", expected).With("But was", t.Subject).Fail(because)
+
+ let expectedNormalised = expected.Replace("\r\n", "\n").Replace("\\r\\n", "\\n")
+
+ let subjectNormalised = t.Subject.Replace("\r\n", "\n").Replace("\\r\\n", "\\n")
+
+ if subjectNormalised <> expectedNormalised then
+ t
+ .With("Expected", expectedNormalised)
+ .With("But was", subjectNormalised)
+ .Fail(because)
+
+ And(t)
diff --git a/tests/IntegrationTests.fs b/tests/IntegrationTests.fs
index a1184db..19ab843 100644
--- a/tests/IntegrationTests.fs
+++ b/tests/IntegrationTests.fs
@@ -1,13 +1,14 @@
module Tests.IntegrationTests
open System.IO
-open System.Runtime.CompilerServices
open System.Threading.Tasks
+open Ionide.KeepAChangelog.Tasks.Test
open Microsoft.VisualStudio.TestTools.UnitTesting
open BlackFox.CommandLine
open Faqt
open SimpleExec
open Workspace
+open Helpers
module Utils =
let packAndGetPackageProperties projectName =
@@ -40,11 +41,6 @@ module Utils =
workingDirectory = Workspace.fixtures.``.``
)
-type StringHelper =
- []
- static member ReplaceEscapedNewLines(s: string) =
- s.ReplaceLineEndings().Replace("\\r\\n", "\\n")
-
[]
type IntegrationTests() =
@@ -90,9 +86,8 @@ type IntegrationTests() =
let! struct (stdout, _) = Utils.packAndGetPackageProperties projectName
stdout
- .ReplaceEscapedNewLines()
.Should()
- .Be(
+ .BeLineEndingEquivalent(
"""{
"Properties": {
"Version": "0.1.0",
@@ -115,9 +110,8 @@ type IntegrationTests() =
let! struct (stdout, _) = Utils.packAndGetPackageProperties projectName
stdout
- .ReplaceEscapedNewLines()
.Should()
- .Be(
+ .BeLineEndingEquivalent(
"""{
"Properties": {
"Version": "0.1.0",
@@ -140,9 +134,8 @@ type IntegrationTests() =
let! struct (stdout, _) = Utils.packAndGetPackageProperties projectName
stdout
- .ReplaceEscapedNewLines()
.Should()
- .Be(
+ .BeLineEndingEquivalent(
"""{
"Properties": {
"Version": "1.0.0",
@@ -165,9 +158,8 @@ type IntegrationTests() =
let! struct (stdout, _) = Utils.packAndGetPackageProperties projectName
stdout
- .ReplaceEscapedNewLines()
.Should()
- .Be(
+ .BeLineEndingEquivalent(
"""{
"Properties": {
"Version": "1.0.0",
diff --git a/tests/Ionide.KeepAChangelog.Tasks.Test.fsproj b/tests/Ionide.KeepAChangelog.Tasks.Test.fsproj
index 311c781..bc17ce0 100644
--- a/tests/Ionide.KeepAChangelog.Tasks.Test.fsproj
+++ b/tests/Ionide.KeepAChangelog.Tasks.Test.fsproj
@@ -7,6 +7,7 @@
+
diff --git a/tests/UnitTests.fs b/tests/UnitTests.fs
index b66825b..43a096e 100644
--- a/tests/UnitTests.fs
+++ b/tests/UnitTests.fs
@@ -1,5 +1,6 @@
module Tests.UnitTests
+open Ionide.KeepAChangelog.Tasks.Test
open Moq
open Microsoft.Build.Framework
open Ionide.KeepAChangelog.Tasks
@@ -7,6 +8,7 @@ open Faqt
open Faqt.Operators
open Microsoft.VisualStudio.TestTools.UnitTesting
open Workspace
+open Helpers
type TestContext = {
BuildEngine: Mock
@@ -121,7 +123,7 @@ type UnitTests() =
%myTask.LatestReleaseNotes
.Should()
- .Be(
+ .BeLineEndingEquivalent(
"""### Added
- Created the package