diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index dc1a6f3f..300ef954 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -13,7 +13,7 @@ jobs: - name: Install required dependencies run: | apt update - apt install -y sudo + apt install --yes sudo sudo apt install --yes --no-install-recommends git # workaround for https://github.com/actions/runner/issues/2033 - name: ownership workaround @@ -186,12 +186,14 @@ jobs: run: dotnet fsi scripts/inconsistentVersionsInGitHubCI.fsx - name: Check there are no inconsistent versions in nuget package references of F# scripts run: dotnet fsi scripts/inconsistentVersionsInFSharpScripts.fsx + - name: Check there are no non-verbose flags in scripts and CI YML files + run: dotnet fsi scripts/nonVerboseFlagsInGitHubCIAndScripts.fsx - name: Install prettier run: npm install prettier@2.8.3 - name: Change file permissions # 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. - run: sudo chmod 777 -R . + run: sudo chmod 777 --recursive . - name: Run "prettier" to check the style of our TypeScript and YML code run: | sudo npx prettier --quote-props=consistent --write './**/*.ts' diff --git a/ReadMe.md b/ReadMe.md index a9f1621b..709e597f 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -10,6 +10,7 @@ This is a repository that contains several useful things that other `nblockchain * [EOF without EOL detection](scripts/eofConvention.fsx). * [Mixed line-endings detection](scripts/mixedLineEndings.fsx). * [Auto-wrap the latest commit message](scripts/wrapLatestCommitMsg.fsx). + * [Detect non-verbose flags (e.g. `dotnet build -c Debug` instead of `dotnet build --configuration Debug`) being used in scripts or YML CI files (there are exceptions, e.g. `env -S`)](scripts/nonVerboseFlagsInGitHubCIAndScripts.fsx). * Use of unpinned versions: * [Use of `-latest` suffix in `runs-on:` GitHubCI tags](scripts/unpinnedGitHubActionsImageVersions.fsx). * [Use of asterisk (*) in `PackageReference` items of .NET projects](scripts/unpinnedDotnetPackageVersions.fsx). @@ -25,4 +26,3 @@ More things to come: - Detect .fsx files without +x attrib. - Detect old versions of FSharpLint and fantomas/fantomless being used. - Detect old versions of .editorconfig or Directory.Build.props being used. -- Detect non-verbose flags (e.g. `dotnet build -c Debug` instead of `dotnet build --configuration Debug`) being used in scripts or YML CI files (there are exceptions, e.g. `env -S`). diff --git a/scripts/nonVerboseFlagsInGitHubCIAndScripts.fsx b/scripts/nonVerboseFlagsInGitHubCIAndScripts.fsx new file mode 100644 index 00000000..6ffb8801 --- /dev/null +++ b/scripts/nonVerboseFlagsInGitHubCIAndScripts.fsx @@ -0,0 +1,31 @@ +#!/usr/bin/env -S dotnet fsi + +open System +open System.IO + +#load "../src/FileConventions/Library.fs" +#load "../src/FileConventions/Helpers.fs" + +let rootDir = Path.Combine(__SOURCE_DIRECTORY__, "..") |> DirectoryInfo + +let validExtensions = + seq { + ".yml" + ".fsx" + ".fs" + ".sh" + } + +let invalidFiles = + validExtensions + |> Seq.map(fun ext -> + Helpers.GetInvalidFiles + rootDir + ("*" + ext) + FileConventions.NonVerboseFlags + ) + |> Seq.concat + +let message = "Please don't use non-verbose flags in the following files:" + +Helpers.AssertNoInvalidFiles invalidFiles message diff --git a/src/FileConventions.Test/DummyFiles/DummyCIWithAcceptedNonVerboseFlag1.yml b/src/FileConventions.Test/DummyFiles/DummyCIWithAcceptedNonVerboseFlag1.yml new file mode 100644 index 00000000..38ca7e8e --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyCIWithAcceptedNonVerboseFlag1.yml @@ -0,0 +1,11 @@ +name: CI + +on: [push, pull_request] + +jobs: + file-conventions: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Print "Hello World!" + run: env -S "echo Hello World!" diff --git a/src/FileConventions.Test/DummyFiles/DummyCIWithAcceptedNonVerboseFlag2.yml b/src/FileConventions.Test/DummyFiles/DummyCIWithAcceptedNonVerboseFlag2.yml new file mode 100644 index 00000000..1a722cfa --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyCIWithAcceptedNonVerboseFlag2.yml @@ -0,0 +1,11 @@ +name: CI + +on: [push, pull_request] + +jobs: + file-conventions: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: unzip a file + run: unzip -n path-to-file.zip diff --git a/src/FileConventions.Test/DummyFiles/DummyCIWithNonVerboseFlag.yml b/src/FileConventions.Test/DummyFiles/DummyCIWithNonVerboseFlag.yml new file mode 100644 index 00000000..d06a1c9b --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyCIWithNonVerboseFlag.yml @@ -0,0 +1,11 @@ +name: CI + +on: [push, pull_request] + +jobs: + file-conventions: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Print apt version + run: apt -v diff --git a/src/FileConventions.Test/DummyFiles/DummyCIWithoutNonVerboseFlags.yml b/src/FileConventions.Test/DummyFiles/DummyCIWithoutNonVerboseFlags.yml new file mode 100644 index 00000000..d8efcfc1 --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyCIWithoutNonVerboseFlags.yml @@ -0,0 +1,11 @@ +name: CI + +on: [push, pull_request] + +jobs: + file-conventions: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Print apt version + run: apt --version diff --git a/src/FileConventions.Test/DummyFiles/DummyScriptWithNonVerboseFlag.fsx b/src/FileConventions.Test/DummyFiles/DummyScriptWithNonVerboseFlag.fsx new file mode 100644 index 00000000..097eeaaa --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyScriptWithNonVerboseFlag.fsx @@ -0,0 +1,17 @@ +#!/usr/bin/env -S dotnet fsi + +#r "nuget: Fsdk, Version=0.6.0--date20230214-0422.git-1ea6f62" + +open Fsdk +open Fsdk.Process + +let gitRemote = + { + Command = "git" + Arguments = "remote -v" + } + +let gitRemoteOutput = + Process + .Execute(gitRemote, Echo.All) + .UnwrapDefault() diff --git a/src/FileConventions.Test/DummyFiles/DummyScriptWithoutNonVerboseFlag.fsx b/src/FileConventions.Test/DummyFiles/DummyScriptWithoutNonVerboseFlag.fsx new file mode 100644 index 00000000..6b13300e --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyScriptWithoutNonVerboseFlag.fsx @@ -0,0 +1,17 @@ +#!/usr/bin/env -S dotnet fsi + +#r "nuget: Fsdk, Version=0.6.0--date20230214-0422.git-1ea6f62" + +open Fsdk +open Fsdk.Process + +let gitRemote = + { + Command = "git" + Arguments = "remote --version" + } + +let gitRemoteOutput = + Process + .Execute(gitRemote, Echo.All) + .UnwrapDefault() diff --git a/src/FileConventions.Test/FileConventions.Test.fs b/src/FileConventions.Test/FileConventions.Test.fs index 5e756b3a..15ba902e 100644 --- a/src/FileConventions.Test/FileConventions.Test.fs +++ b/src/FileConventions.Test/FileConventions.Test.fs @@ -547,3 +547,81 @@ let DetectInconsistentVersionsInFSharpScripts2() = (Some(Seq.singleton "DummyScripts")), Is.EqualTo false ) + + +[] +let NonVerboseFlagsInGitHubCI1() = + let fileInfo = + (FileInfo( + Path.Combine( + dummyFilesDirectory.FullName, + "DummyCIWithNonVerboseFlag.yml" + ) + )) + + Assert.That(NonVerboseFlags fileInfo, Is.EqualTo true) + + +[] +let NonVerboseFlagsInGitHubCI2() = + let fileInfo = + (FileInfo( + Path.Combine( + dummyFilesDirectory.FullName, + "DummyCIWithoutNonVerboseFlags.yml" + ) + )) + + Assert.That(NonVerboseFlags fileInfo, Is.EqualTo false) + + +[] +let NonVerboseFlagsInGitHubCI3() = + let fileInfo = + (FileInfo( + Path.Combine( + dummyFilesDirectory.FullName, + "DummyCIWithAcceptedNonVerboseFlag1.yml" + ) + )) + + Assert.That(NonVerboseFlags fileInfo, Is.EqualTo false) + + +[] +let NonVerboseFlagsInGitHubCI4() = + let fileInfo = + (FileInfo( + Path.Combine( + dummyFilesDirectory.FullName, + "DummyScriptWithNonVerboseFlag.fsx" + ) + )) + + Assert.That(NonVerboseFlags fileInfo, Is.EqualTo true) + + +[] +let NonVerboseFlagsInGitHubCI5() = + let fileInfo = + (FileInfo( + Path.Combine( + dummyFilesDirectory.FullName, + "DummyScriptWithoutNonVerboseFlag.fsx" + ) + )) + + Assert.That(NonVerboseFlags fileInfo, Is.EqualTo false) + + +[] +let NonVerboseFlagsInGitHubCI6() = + let fileInfo = + (FileInfo( + Path.Combine( + dummyFilesDirectory.FullName, + "DummyCIWithAcceptedNonVerboseFlag2.yml" + ) + )) + + Assert.That(NonVerboseFlags fileInfo, Is.EqualTo false) diff --git a/src/FileConventions/Library.fs b/src/FileConventions/Library.fs index 9fc1f1e9..c5d36f8b 100644 --- a/src/FileConventions/Library.fs +++ b/src/FileConventions/Library.fs @@ -329,3 +329,52 @@ let DetectInconsistentVersionsInFSharpScripts false else DetectInconsistentVersionsInNugetRefsInFSharpScripts fsxFiles + +let allowedNonVerboseFlags = + seq { + "unzip" + + // even if env in linux has --split-string=foo as equivalent to env -S, it + // doesn't seem to be present in macOS' env man page and doesn't work either + "env -S" + } + +let NonVerboseFlags(fileInfo: FileInfo) = + let validExtensions = + seq { + ".yml" + ".fsx" + ".fs" + ".sh" + } + + let isFileExtentionValid = + validExtensions + |> Seq.map(fun ext -> fileInfo.FullName.EndsWith ext) + |> Seq.contains true + + if not isFileExtentionValid then + let sep = "," + + failwith + $"NonVerboseFlags function only supports {String.concat sep validExtensions} files." + + let fileLines = File.ReadLines fileInfo.FullName + + let nonVerboseFlagsRegex = Regex("\\s-[a-zA-Z]\\b", RegexOptions.Compiled) + + let numInvalidFlags = + fileLines + |> Seq.filter(fun line -> + let nonVerboseFlag = nonVerboseFlagsRegex.IsMatch line + + let allowedNonVerboseFlag = + allowedNonVerboseFlags + |> Seq.map(fun allowedFlag -> line.Contains allowedFlag) + |> Seq.contains true + + nonVerboseFlag && not allowedNonVerboseFlag + ) + |> Seq.length + + numInvalidFlags > 0