diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index b7759e1ee..2199e091d 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -212,4 +212,4 @@ jobs: dotnet fantomless --recurse . git diff --exit-code - name: Check style of our F#, C#, TypeScript, YML and XAML code - run: sudo dotnet fsi scripts/styleChecker.fsx + run: sudo dotnet fsi scripts/styleCheck.fsx diff --git a/scripts/eofConvention.fsx b/scripts/eofConvention.fsx index 32bfb983f..81935e96b 100644 --- a/scripts/eofConvention.fsx +++ b/scripts/eofConvention.fsx @@ -3,6 +3,8 @@ open System.IO open System +#r "nuget: Fsdk, Version=0.6.0--date20230214-0422.git-1ea6f62" +#load "../src/FileConventions/Config.fs" #load "../src/FileConventions/Helpers.fs" #load "../src/FileConventions/Library.fs" diff --git a/scripts/inconsistentVersionsInFSharpScripts.fsx b/scripts/inconsistentVersionsInFSharpScripts.fsx index e73479968..464da9ea4 100644 --- a/scripts/inconsistentVersionsInFSharpScripts.fsx +++ b/scripts/inconsistentVersionsInFSharpScripts.fsx @@ -3,8 +3,10 @@ open System.IO open System.Linq -#load "../src/FileConventions/Library.fs" +#r "nuget: Fsdk, Version=0.6.0--date20230214-0422.git-1ea6f62" +#load "../src/FileConventions/Config.fs" #load "../src/FileConventions/Helpers.fs" +#load "../src/FileConventions/Library.fs" let rootDir = Path.Combine(__SOURCE_DIRECTORY__, "..") |> DirectoryInfo let currentDir = Directory.GetCurrentDirectory() |> DirectoryInfo diff --git a/scripts/inconsistentVersionsInGitHubCI.fsx b/scripts/inconsistentVersionsInGitHubCI.fsx index 80bd9a1c5..6113482e8 100644 --- a/scripts/inconsistentVersionsInGitHubCI.fsx +++ b/scripts/inconsistentVersionsInGitHubCI.fsx @@ -2,8 +2,10 @@ open System.IO -#load "../src/FileConventions/Library.fs" +#r "nuget: Fsdk, Version=0.6.0--date20230214-0422.git-1ea6f62" +#load "../src/FileConventions/Config.fs" #load "../src/FileConventions/Helpers.fs" +#load "../src/FileConventions/Library.fs" let rootDir = Path.Combine(__SOURCE_DIRECTORY__, "..") |> DirectoryInfo diff --git a/scripts/mixedLineEndings.fsx b/scripts/mixedLineEndings.fsx index 7b404c98d..e04182958 100644 --- a/scripts/mixedLineEndings.fsx +++ b/scripts/mixedLineEndings.fsx @@ -3,8 +3,10 @@ open System open System.IO -#load "../src/FileConventions/Library.fs" +#r "nuget: Fsdk, Version=0.6.0--date20230214-0422.git-1ea6f62" +#load "../src/FileConventions/Config.fs" #load "../src/FileConventions/Helpers.fs" +#load "../src/FileConventions/Library.fs" let rootDir = Path.Combine(__SOURCE_DIRECTORY__, "..") |> DirectoryInfo diff --git a/scripts/nonVerboseFlagsInGitHubCIAndScripts.fsx b/scripts/nonVerboseFlagsInGitHubCIAndScripts.fsx index 6ffb88019..ed5c092bf 100644 --- a/scripts/nonVerboseFlagsInGitHubCIAndScripts.fsx +++ b/scripts/nonVerboseFlagsInGitHubCIAndScripts.fsx @@ -3,8 +3,10 @@ open System open System.IO -#load "../src/FileConventions/Library.fs" +#r "nuget: Fsdk, Version=0.6.0--date20230214-0422.git-1ea6f62" +#load "../src/FileConventions/Config.fs" #load "../src/FileConventions/Helpers.fs" +#load "../src/FileConventions/Library.fs" let rootDir = Path.Combine(__SOURCE_DIRECTORY__, "..") |> DirectoryInfo diff --git a/scripts/shebangConvention.fsx b/scripts/shebangConvention.fsx index 89e1f0fb5..e4adb3c3d 100644 --- a/scripts/shebangConvention.fsx +++ b/scripts/shebangConvention.fsx @@ -3,8 +3,10 @@ open System open System.IO -#load "../src/FileConventions/Library.fs" +#r "nuget: Fsdk, Version=0.6.0--date20230214-0422.git-1ea6f62" +#load "../src/FileConventions/Config.fs" #load "../src/FileConventions/Helpers.fs" +#load "../src/FileConventions/Library.fs" let rootDir = Path.Combine(__SOURCE_DIRECTORY__, "..") |> DirectoryInfo diff --git a/scripts/styleApply.fsx b/scripts/styleApply.fsx new file mode 100644 index 000000000..881e41814 --- /dev/null +++ b/scripts/styleApply.fsx @@ -0,0 +1,18 @@ +#!/usr/bin/env -S dotnet fsi + +#r "nuget: Fsdk, Version=0.6.0--date20230214-0422.git-1ea6f62" +#load "../src/FileConventions/Config.fs" +#load "../src/FileConventions/Helpers.fs" +#load "../src/FileConventions/Library.fs" + +open System.IO + +open FileConventions + +let rootDir = Path.Combine(__SOURCE_DIRECTORY__, "..") |> DirectoryInfo + +StyleFSharpFiles rootDir +StyleTypeScriptFiles() +StyleYmlFiles() +StyleCSharpFiles rootDir +StyleXamlFiles() diff --git a/scripts/styleCheck.fsx b/scripts/styleCheck.fsx new file mode 100644 index 000000000..e3f87c3c3 --- /dev/null +++ b/scripts/styleCheck.fsx @@ -0,0 +1,192 @@ +#!/usr/bin/env -S dotnet fsi + +#r "nuget: Fsdk, Version=0.6.0--date20230214-0422.git-1ea6f62" +#load "../src/FileConventions/Config.fs" +#load "../src/FileConventions/Helpers.fs" +#load "../src/FileConventions/Library.fs" + +open System +open System.IO + +open Fsdk +open Fsdk.Process + +open Helpers +open FileConventions + +let ContainsFiles (rootDir: DirectoryInfo) (searchPattern: string) = + Helpers.GetFiles rootDir searchPattern |> Seq.length > 0 + +let GitDiff() : ProcessResult = + + // Since we changed file modes in the prettier step we need the following command to + // make git ignore mode changes in files and doesn't include them in the git diff command. + Process + .Execute( + { + Command = "git" + Arguments = "config core.fileMode false" + }, + Echo.Off + ) + .UnwrapDefault() + |> ignore + + let processResult = + Process.Execute( + { + Command = "git" + Arguments = "diff --exit-code" + }, + Echo.Off + ) + + processResult + +let GitRestore() = + Process + .Execute( + { + Command = "git" + Arguments = "restore ." + }, + Echo.Off + ) + .UnwrapDefault() + |> ignore + +let CheckStyleOfFSharpFiles(rootDir: DirectoryInfo) : bool = + let suggestion = + Some "Please style your F# code using: `dotnet fantomless --recurse .`" + + GitRestore() + + let success = + if ContainsFiles rootDir "*.fs" || ContainsFiles rootDir ".fsx" then + StyleFSharpFiles rootDir + let processResult = GitDiff() + UnwrapProcessResult suggestion true processResult |> ignore + IsProcessSuccessful processResult + + else + true + + success + +let CheckStyleOfTypeScriptFiles(rootDir: DirectoryInfo) : bool = + let pattern = + $".{Path.DirectorySeparatorChar}**{Path.DirectorySeparatorChar}*.ts" + + let suggestion = + Some + $"Please style your TypeScript code using: `npx prettier --quote-props=consistent --write {pattern}`" + + GitRestore() + + let success = + if ContainsFiles rootDir "*.ts" then + StyleTypeScriptFiles() + let processResult = GitDiff() + UnwrapProcessResult suggestion true processResult |> ignore + IsProcessSuccessful processResult + + else + true + + success + +let CheckStyleOfYmlFiles(rootDir: DirectoryInfo) : bool = + let pattern = + $".{Path.DirectorySeparatorChar}**{Path.DirectorySeparatorChar}*.yml" + + let suggestion = + Some + $"Please style your YML code using: `npx prettier --quote-props=consistent --write {pattern}`" + + GitRestore() + + let success = + if ContainsFiles rootDir "*.yml" then + StyleYmlFiles() + let processResult = GitDiff() + UnwrapProcessResult suggestion true processResult |> ignore + IsProcessSuccessful processResult + else + true + + success + +let CheckStyleOfCSharpFiles(rootDir: DirectoryInfo) : bool = + let suggestion = + Some + "Please style your C# code using: `dotnet format whitespace . --folder" + + GitRestore() + + let success = + if ContainsFiles rootDir "*.cs" then + StyleCSharpFiles rootDir + let processResult = GitDiff() + UnwrapProcessResult suggestion true processResult |> ignore + IsProcessSuccessful processResult + else + true + + success + +let CheckStyleOfXamlFiles(rootDir: DirectoryInfo) : bool = + let prettierPath = + Path.Combine( + Directory.GetCurrentDirectory(), + "node_modules", + ".bin", + "prettier" + ) + + let pattern = $"**{Path.DirectorySeparatorChar}*.xaml" + + let suggestion = + "Please style your XAML code using:" + + Environment.NewLine + + $"`{prettierPath} --xml-whitespace-sensitivity ignore --tab-width 4 --prose-wrap preserve --write {pattern}`" + |> Some + + GitRestore() + + let success = + if ContainsFiles rootDir "*.xaml" then + StyleXamlFiles() + let processResult = GitDiff() + UnwrapProcessResult suggestion true processResult |> ignore + IsProcessSuccessful processResult + else + true + + success + +let rootDir = Path.Combine(__SOURCE_DIRECTORY__, "..") |> DirectoryInfo + +// We need this step so we can change the files using `npx prettier --write` in the prettier calls. +// Otherwise we get permission denied error in the CI. +Process + .Execute( + { + Command = "chmod" + Arguments = "777 --recursive ." + }, + Echo.Off + ) + .UnwrapDefault() +|> ignore + +let processSuccessStates = + [| + CheckStyleOfFSharpFiles rootDir + CheckStyleOfCSharpFiles rootDir + CheckStyleOfTypeScriptFiles rootDir + CheckStyleOfYmlFiles rootDir + CheckStyleOfXamlFiles rootDir + |] + +if processSuccessStates |> Seq.contains false then + Environment.Exit 1 diff --git a/scripts/styleChecker.fsx b/scripts/styleChecker.fsx deleted file mode 100644 index fd9d0c8b1..000000000 --- a/scripts/styleChecker.fsx +++ /dev/null @@ -1,438 +0,0 @@ -#!/usr/bin/env -S dotnet fsi - -#r "nuget: Fsdk, Version=0.6.0--date20230214-0422.git-1ea6f62" -#load "../src/FileConventions/Helpers.fs" - -open System -open System.IO - -open Fsdk -open Fsdk.Process - -open Helpers - -let fantomlessToolVersion = "4.7.997-prerelease" -let prettierVersion = "2.8.3" -let pluginXmlVersion = "v2.2.0" - -let InstallFantomlessTool(version: string) = - let isFantomlessInstalled = - let installedPackages: string = - Process - .Execute( - { - Command = "dotnet" - Arguments = "tool list" - }, - Echo.Off - ) - .UnwrapDefault() - - installedPackages.Split Environment.NewLine - |> Seq.map(fun line -> - line.Contains "fantomless-tool" - && line.Contains fantomlessToolVersion - ) - |> Seq.contains true - - if not(isFantomlessInstalled) then - Process - .Execute( - { - Command = "dotnet" - Arguments = "new tool-manifest --force" - }, - Echo.Off - ) - .UnwrapDefault() - |> ignore - - Process - .Execute( - { - Command = "dotnet" - Arguments = - $"tool install fantomless-tool --version {version}" - }, - Echo.Off - ) - .UnwrapDefault() - |> ignore - - Process - .Execute( - { - Command = "dotnet" - Arguments = "tool restore" - }, - Echo.Off - ) - .UnwrapDefault() - |> ignore - -let UnwrapProcessResult - (maybeSuggestion: Option) - (ignoreErrorExitCode: bool) - (processResult: ProcessResult) - : string = - let errMsg = - sprintf - "Error when running '%s %s'" - processResult.Details.Command - processResult.Details.Args - - match processResult.Result with - | Success output -> - Console.WriteLine output - output - | Error(_, output) -> - if processResult.Details.Echo = Echo.Off then - output.PrintToConsole() - Console.WriteLine() - Console.Out.Flush() - - let fullErrMsg = - match maybeSuggestion with - | Some suggestion -> errMsg + Environment.NewLine + suggestion - | None -> errMsg - - Console.Error.WriteLine fullErrMsg - - if ignoreErrorExitCode then - fullErrMsg - else - raise <| ProcessFailed errMsg - - | WarningsOrAmbiguous output -> - if processResult.Details.Echo = Echo.Off then - output.PrintToConsole() - Console.WriteLine() - Console.Out.Flush() - - let fullErrMsg = sprintf "%s (with warnings?)" errMsg - Console.Error.WriteLine fullErrMsg - fullErrMsg - -let IsProcessSuccessful(processResult: ProcessResult) : bool = - match processResult.Result with - | Success output -> true - | _ -> false - -let InstallPrettier(version: string) = - let isPrettierInstalled = - Process.Execute( - { - Command = "npm" - Arguments = $"list prettier@{version}" - }, - Echo.All - ) - |> IsProcessSuccessful - - if not(isPrettierInstalled) then - Process.Execute( - { - Command = "npm" - Arguments = $"install prettier@{version}" - }, - Echo.Off - ) - |> UnwrapProcessResult None false - |> ignore - -let StyleFSharpFiles(rootDir: DirectoryInfo) = - InstallFantomlessTool fantomlessToolVersion - - Process - .Execute( - { - Command = "dotnet" - Arguments = $"fantomless --recurse {rootDir.FullName}" - }, - Echo.Off - ) - .UnwrapDefault() - |> ignore - -let StyleCSharpFiles(rootDir: DirectoryInfo) = - Process - .Execute( - { - Command = "dotnet" - Arguments = $"format whitespace {rootDir.FullName} --folder" - }, - Echo.Off - ) - .UnwrapDefault() - |> ignore - -let InstallPrettierPluginXml(version: string) = - let isPrettierPluginXmlInstalled = - Process.Execute( - { - Command = "npm" - Arguments = $"list @prettier/plugin-xml@{version}" - }, - Echo.Off - ) - |> IsProcessSuccessful - - if not(isPrettierPluginXmlInstalled) then - Process - .Execute( - { - Command = "npm" - Arguments = $"install @prettier/plugin-xml@{version}" - }, - Echo.Off - ) - .UnwrapDefault() - |> ignore - -let StyleXamlFiles() = - InstallPrettier prettierVersion - InstallPrettierPluginXml pluginXmlVersion - - Process - .Execute( - { - Command = "npm" - Arguments = - $"install --save-dev prettier@{prettierVersion} @prettier/plugin-xml@{pluginXmlVersion}" - }, - Echo.Off - ) - .UnwrapDefault() - |> ignore - - let pattern = $"**{Path.DirectorySeparatorChar}*.xaml" - - Process - .Execute( - { - Command = - Path.Combine( - Directory.GetCurrentDirectory(), - "node_modules", - ".bin", - "prettier" - ) - - Arguments = - $"--xml-whitespace-sensitivity ignore --tab-width 4 --prose-wrap preserve --write {pattern}" - }, - Echo.Off - ) - .UnwrapDefault() - |> ignore - -let RunPrettier(arguments: string) = - - // We need this step so we can change the files using `npx prettier --write` in the next step. - // Otherwise we get permission denied error in the CI. - Process - .Execute( - { - Command = "chmod" - Arguments = "777 --recursive ." - }, - Echo.Off - ) - .UnwrapDefault() - |> ignore - - Process.Execute( - { - Command = "npx" - Arguments = $"prettier {arguments}" - }, - Echo.Off - ) - |> UnwrapProcessResult None false - |> ignore - - - // Since after installing commitlint dependencies package.json file changes, we need to - // run the following command to ignore package.json file - Process - .Execute( - { - Command = "git" - Arguments = "restore package.json" - }, - Echo.Off - ) - .UnwrapDefault() - |> ignore - -let StyleTypeScriptFiles() = - let pattern = - $"{Directory.GetCurrentDirectory()}{Path.DirectorySeparatorChar}**{Path.DirectorySeparatorChar}*.ts" - - RunPrettier $"--quote-props=consistent --write {pattern}" - -let StyleYmlFiles() = - let pattern = - $"{Directory.GetCurrentDirectory()}{Path.DirectorySeparatorChar}**{Path.DirectorySeparatorChar}*.yml" - - RunPrettier $"--quote-props=consistent --write {pattern}" - -let ContainsFiles (rootDir: DirectoryInfo) (searchPattern: string) = - Helpers.GetFiles rootDir searchPattern |> Seq.length > 0 - -let GitDiff() : ProcessResult = - - // Since we changed file modes in the prettier step we need the following command to - // make git ignore mode changes in files and doesn't include them in the git diff command. - Process - .Execute( - { - Command = "git" - Arguments = "config core.fileMode false" - }, - Echo.Off - ) - .UnwrapDefault() - |> ignore - - let processResult = - Process.Execute( - { - Command = "git" - Arguments = "diff --exit-code" - }, - Echo.Off - ) - - processResult - -let GitRestore() = - Process - .Execute( - { - Command = "git" - Arguments = "restore ." - }, - Echo.Off - ) - .UnwrapDefault() - |> ignore - -let CheckStyleOfFSharpFiles(rootDir: DirectoryInfo) : bool = - let suggestion = - Some "Please style your F# code using: `dotnet fantomless --recurse .`" - - GitRestore() - - let success = - if ContainsFiles rootDir "*.fs" || ContainsFiles rootDir ".fsx" then - StyleFSharpFiles rootDir - let processResult = GitDiff() - UnwrapProcessResult suggestion true processResult |> ignore - IsProcessSuccessful processResult - - else - true - - success - -let CheckStyleOfTypeScriptFiles(rootDir: DirectoryInfo) : bool = - let pattern = - $".{Path.DirectorySeparatorChar}**{Path.DirectorySeparatorChar}*.ts" - - let suggestion = - Some - $"Please style your TypeScript code using: `npx prettier --quote-props=consistent --write {pattern}`" - - GitRestore() - - let success = - if ContainsFiles rootDir "*.ts" then - InstallPrettier prettierVersion - StyleTypeScriptFiles() - let processResult = GitDiff() - UnwrapProcessResult suggestion true processResult |> ignore - IsProcessSuccessful processResult - - else - true - - success - -let CheckStyleOfYmlFiles(rootDir: DirectoryInfo) : bool = - let pattern = - $".{Path.DirectorySeparatorChar}**{Path.DirectorySeparatorChar}*.yml" - - let suggestion = - Some - $"Please style your YML code using: `npx prettier --quote-props=consistent --write {pattern}`" - - GitRestore() - - let success = - if ContainsFiles rootDir "*.yml" then - InstallPrettier prettierVersion - StyleYmlFiles() - let processResult = GitDiff() - UnwrapProcessResult suggestion true processResult |> ignore - IsProcessSuccessful processResult - else - true - - success - -let CheckStyleOfCSharpFiles(rootDir: DirectoryInfo) : bool = - let suggestion = - Some - "Please style your C# code using: `dotnet format whitespace . --folder" - - GitRestore() - - let success = - if ContainsFiles rootDir "*.cs" then - StyleCSharpFiles rootDir - let processResult = GitDiff() - UnwrapProcessResult suggestion true processResult |> ignore - IsProcessSuccessful processResult - else - true - - success - -let CheckStyleOfXamlFiles(rootDir: DirectoryInfo) : bool = - let prettierPath = Path.Combine(".", "node_modules", ".bin", "prettier") - - let pattern = $"**{Path.DirectorySeparatorChar}*.xaml" - - let suggestion = - "Please style your XAML code using:" - + Environment.NewLine - + $"`{prettierPath} --xml-whitespace-sensitivity ignore --tab-width 4 --prose-wrap preserve --write {pattern}`" - |> Some - - GitRestore() - - let success = - if ContainsFiles rootDir "*.xaml" then - StyleXamlFiles() - let processResult = GitDiff() - UnwrapProcessResult suggestion true processResult |> ignore - IsProcessSuccessful processResult - else - true - - success - -let rootDir = Path.Combine(__SOURCE_DIRECTORY__, "..") |> DirectoryInfo - -let processSuccessStates = - [| - CheckStyleOfFSharpFiles rootDir - CheckStyleOfCSharpFiles rootDir - CheckStyleOfTypeScriptFiles rootDir - CheckStyleOfYmlFiles rootDir - CheckStyleOfXamlFiles rootDir - |] - -if processSuccessStates |> Seq.contains false then - Environment.Exit 1 diff --git a/scripts/unpinnedDotnetPackageVersions.fsx b/scripts/unpinnedDotnetPackageVersions.fsx index f40429602..9fb0a1fa4 100644 --- a/scripts/unpinnedDotnetPackageVersions.fsx +++ b/scripts/unpinnedDotnetPackageVersions.fsx @@ -3,8 +3,10 @@ open System open System.IO -#load "../src/FileConventions/Library.fs" +#r "nuget: Fsdk, Version=0.6.0--date20230214-0422.git-1ea6f62" +#load "../src/FileConventions/Config.fs" #load "../src/FileConventions/Helpers.fs" +#load "../src/FileConventions/Library.fs" let rootDir = Path.Combine(__SOURCE_DIRECTORY__, "..") |> DirectoryInfo diff --git a/scripts/unpinnedDotnetToolInstallVersions.fsx b/scripts/unpinnedDotnetToolInstallVersions.fsx index 0d99b0f4d..ca311b9c2 100644 --- a/scripts/unpinnedDotnetToolInstallVersions.fsx +++ b/scripts/unpinnedDotnetToolInstallVersions.fsx @@ -3,8 +3,10 @@ open System open System.IO -#load "../src/FileConventions/Library.fs" +#r "nuget: Fsdk, Version=0.6.0--date20230214-0422.git-1ea6f62" +#load "../src/FileConventions/Config.fs" #load "../src/FileConventions/Helpers.fs" +#load "../src/FileConventions/Library.fs" let rootDir = Path.Combine(__SOURCE_DIRECTORY__, "..") |> DirectoryInfo diff --git a/scripts/unpinnedGitHubActionsImageVersions.fsx b/scripts/unpinnedGitHubActionsImageVersions.fsx index 451bdeb62..ee58fddd9 100644 --- a/scripts/unpinnedGitHubActionsImageVersions.fsx +++ b/scripts/unpinnedGitHubActionsImageVersions.fsx @@ -3,8 +3,10 @@ open System open System.IO -#load "../src/FileConventions/Library.fs" +#r "nuget: Fsdk, Version=0.6.0--date20230214-0422.git-1ea6f62" +#load "../src/FileConventions/Config.fs" #load "../src/FileConventions/Helpers.fs" +#load "../src/FileConventions/Library.fs" let rootDir = Path.Combine(__SOURCE_DIRECTORY__, "..") |> DirectoryInfo diff --git a/scripts/unpinnedNugetPackageReferenceVersions.fsx b/scripts/unpinnedNugetPackageReferenceVersions.fsx index 15aa408eb..0b18e9eb3 100644 --- a/scripts/unpinnedNugetPackageReferenceVersions.fsx +++ b/scripts/unpinnedNugetPackageReferenceVersions.fsx @@ -3,8 +3,10 @@ open System open System.IO -#load "../src/FileConventions/Library.fs" +#r "nuget: Fsdk, Version=0.6.0--date20230214-0422.git-1ea6f62" +#load "../src/FileConventions/Config.fs" #load "../src/FileConventions/Helpers.fs" +#load "../src/FileConventions/Library.fs" let rootDir = Path.Combine(__SOURCE_DIRECTORY__, "..") |> DirectoryInfo diff --git a/scripts/wrapLatestCommitMsg.fsx b/scripts/wrapLatestCommitMsg.fsx index bf38c0d64..f4ddaacee 100644 --- a/scripts/wrapLatestCommitMsg.fsx +++ b/scripts/wrapLatestCommitMsg.fsx @@ -4,6 +4,8 @@ open System.IO open System open System.Text.RegularExpressions +#load "../src/FileConventions/Config.fs" +#load "../src/FileConventions/Helpers.fs" #load "../src/FileConventions/Library.fs" #r "nuget: Fsdk, Version=0.6.0--date20230214-0422.git-1ea6f62" diff --git a/src/FileConventions/Config.fs b/src/FileConventions/Config.fs new file mode 100644 index 000000000..58f739e52 --- /dev/null +++ b/src/FileConventions/Config.fs @@ -0,0 +1,5 @@ +module Config + +let FantomlessToolVersion = "4.7.997-prerelease" +let PrettierVersion = "2.8.3" +let PluginXmlVersion = "v2.2.0" diff --git a/src/FileConventions/FileConventions.fsproj b/src/FileConventions/FileConventions.fsproj index 02d61ddad..9f2c8478b 100644 --- a/src/FileConventions/FileConventions.fsproj +++ b/src/FileConventions/FileConventions.fsproj @@ -6,8 +6,13 @@ - + + + + + + diff --git a/src/FileConventions/Helpers.fs b/src/FileConventions/Helpers.fs index b46cbdddf..63b7a5f7a 100644 --- a/src/FileConventions/Helpers.fs +++ b/src/FileConventions/Helpers.fs @@ -4,6 +4,9 @@ open System open System.IO open System.Linq +open Fsdk +open Fsdk.Process + let NotInDir (dirName: string) (fileInfo: FileInfo) = not( fileInfo.FullName.Contains @@ -59,3 +62,176 @@ let AssertNoInvalidFiles (invalidFiles: seq) (message: string) = |> String.concat Environment.NewLine) failwith message + +let InstallFantomlessTool(version: string) = + let isFantomlessInstalled = + let installedPackages: string = + Process + .Execute( + { + Command = "dotnet" + Arguments = "tool list" + }, + Echo.Off + ) + .UnwrapDefault() + + installedPackages.Split Environment.NewLine + |> Seq.map(fun line -> + line.Contains "fantomless-tool" && line.Contains version + ) + |> Seq.contains true + + if not(isFantomlessInstalled) then + Process + .Execute( + { + Command = "dotnet" + Arguments = "new tool-manifest --force" + }, + Echo.Off + ) + .UnwrapDefault() + |> ignore + + Process + .Execute( + { + Command = "dotnet" + Arguments = + $"tool install fantomless-tool --version {version}" + }, + Echo.Off + ) + .UnwrapDefault() + |> ignore + + Process + .Execute( + { + Command = "dotnet" + Arguments = "tool restore" + }, + Echo.Off + ) + .UnwrapDefault() + |> ignore + +let UnwrapProcessResult + (maybeSuggestion: Option) + (ignoreErrorExitCode: bool) + (processResult: ProcessResult) + : string = + let errMsg = + sprintf + "Error when running '%s %s'" + processResult.Details.Command + processResult.Details.Args + + match processResult.Result with + | Success output -> + Console.WriteLine output + output + | Error(_, output) -> + if processResult.Details.Echo = Echo.Off then + output.PrintToConsole() + Console.WriteLine() + Console.Out.Flush() + + let fullErrMsg = + match maybeSuggestion with + | Some suggestion -> errMsg + Environment.NewLine + suggestion + | None -> errMsg + + Console.Error.WriteLine fullErrMsg + + if ignoreErrorExitCode then + fullErrMsg + else + raise <| ProcessFailed errMsg + + | WarningsOrAmbiguous output -> + if processResult.Details.Echo = Echo.Off then + output.PrintToConsole() + Console.WriteLine() + Console.Out.Flush() + + let fullErrMsg = sprintf "%s (with warnings?)" errMsg + Console.Error.WriteLine fullErrMsg + fullErrMsg + +let IsProcessSuccessful(processResult: ProcessResult) : bool = + match processResult.Result with + | Success _ -> true + | _ -> false + +let InstallPrettier(version: string) = + let isPrettierInstalled = + Process.Execute( + { + Command = "npm" + Arguments = $"list prettier@{version}" + }, + Echo.All + ) + |> IsProcessSuccessful + + if not(isPrettierInstalled) then + Process.Execute( + { + Command = "npm" + Arguments = $"install prettier@{version}" + }, + Echo.Off + ) + |> UnwrapProcessResult None false + |> ignore + +let InstallPrettierPluginXml(version: string) = + let isPrettierPluginXmlInstalled = + Process.Execute( + { + Command = "npm" + Arguments = $"list @prettier/plugin-xml@{version}" + }, + Echo.Off + ) + |> IsProcessSuccessful + + if not(isPrettierPluginXmlInstalled) then + Process + .Execute( + { + Command = "npm" + Arguments = $"install @prettier/plugin-xml@{version}" + }, + Echo.Off + ) + .UnwrapDefault() + |> ignore + +let RunPrettier(arguments: string) = + + Process.Execute( + { + Command = "npx" + Arguments = $"prettier {arguments}" + }, + Echo.Off + ) + |> UnwrapProcessResult None false + |> ignore + + + // Since after installing commitlint dependencies package.json file changes, we need to + // run the following command to ignore package.json file + Process + .Execute( + { + Command = "git" + Arguments = "restore package.json" + }, + Echo.Off + ) + .UnwrapDefault() + |> ignore diff --git a/src/FileConventions/Library.fs b/src/FileConventions/Library.fs index c5d36f8b1..b08486d61 100644 --- a/src/FileConventions/Library.fs +++ b/src/FileConventions/Library.fs @@ -5,6 +5,12 @@ open System.IO open System.Linq open System.Text.RegularExpressions +open Fsdk +open Fsdk.Process + +open Helpers +open Config + let HasCorrectShebang(fileInfo: FileInfo) = let fileText = File.ReadLines fileInfo.FullName @@ -378,3 +384,83 @@ let NonVerboseFlags(fileInfo: FileInfo) = |> Seq.length numInvalidFlags > 0 + + +let StyleFSharpFiles(rootDir: DirectoryInfo) = + InstallFantomlessTool FantomlessToolVersion + + Process + .Execute( + { + Command = "dotnet" + Arguments = $"fantomless --recurse {rootDir.FullName}" + }, + Echo.Off + ) + .UnwrapDefault() + |> ignore + +let StyleCSharpFiles(rootDir: DirectoryInfo) = + Process + .Execute( + { + Command = "dotnet" + Arguments = $"format whitespace {rootDir.FullName} --folder" + }, + Echo.Off + ) + .UnwrapDefault() + |> ignore + +let StyleXamlFiles() = + InstallPrettier PrettierVersion + InstallPrettierPluginXml PluginXmlVersion + + Process + .Execute( + { + Command = "npm" + Arguments = + $"install --save-dev prettier@{PrettierVersion} @prettier/plugin-xml@{PluginXmlVersion}" + }, + Echo.Off + ) + .UnwrapDefault() + |> ignore + + let pattern = $"**{Path.DirectorySeparatorChar}*.xaml" + + Process + .Execute( + { + Command = + Path.Combine( + Directory.GetCurrentDirectory(), + "node_modules", + ".bin", + "prettier" + ) + + Arguments = + $"--xml-whitespace-sensitivity ignore --tab-width 4 --prose-wrap preserve --write {pattern}" + }, + Echo.Off + ) + .UnwrapDefault() + |> ignore + +let StyleTypeScriptFiles() = + InstallPrettier PrettierVersion + + let pattern = + $".{Path.DirectorySeparatorChar}**{Path.DirectorySeparatorChar}*.ts" + + RunPrettier $"--quote-props=consistent --write {pattern}" + +let StyleYmlFiles() = + InstallPrettier PrettierVersion + + let pattern = + $".{Path.DirectorySeparatorChar}**{Path.DirectorySeparatorChar}*.yml" + + RunPrettier $"--quote-props=consistent --write {pattern}"