From 4f3bb221953b6cecab2bf61cf5c9c55738980b3c Mon Sep 17 00:00:00 2001 From: realmarv Date: Tue, 23 May 2023 15:00:39 +0330 Subject: [PATCH 01/10] FileConventions.Test: add test Add test for DetectUnpinnedDotnetToolInstallVersions function. --- ...CIWithoutUnpinnedDotnetToolInstallVersion.yml | 16 ++++++++++++++++ src/FileConventions.Test/FileConventions.Test.fs | 15 +++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 src/FileConventions.Test/DummyFiles/DummyCIWithoutUnpinnedDotnetToolInstallVersion.yml diff --git a/src/FileConventions.Test/DummyFiles/DummyCIWithoutUnpinnedDotnetToolInstallVersion.yml b/src/FileConventions.Test/DummyFiles/DummyCIWithoutUnpinnedDotnetToolInstallVersion.yml new file mode 100644 index 000000000..10084073b --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyCIWithoutUnpinnedDotnetToolInstallVersion.yml @@ -0,0 +1,16 @@ +name: CI + +on: [push, pull_request] + +jobs: + build: + name: Build + runs-on: ubuntu-22.04 + container: + image: "ubuntu:22.04" + steps: + - name: Install fantomless-tool + run: | + dotnet tool install fantomless-tool --version 4.8.999 + - name: Print "Hello World!" + run: echo "Hello World" diff --git a/src/FileConventions.Test/FileConventions.Test.fs b/src/FileConventions.Test/FileConventions.Test.fs index 81d82bc68..1082950d0 100644 --- a/src/FileConventions.Test/FileConventions.Test.fs +++ b/src/FileConventions.Test/FileConventions.Test.fs @@ -140,6 +140,21 @@ let DetectUnpinnedDotnetToolInstallVersions1() = Is.EqualTo true ) +[] +let DetectUnpinnedDotnetToolInstallVersions2() = + let fileInfo = + (FileInfo( + Path.Combine( + dummyFilesDirectory.FullName, + "DummyCIWithoutUnpinnedDotnetToolInstallVersion.yml" + ) + )) + + Assert.That( + DetectUnpinnedDotnetToolInstallVersions fileInfo, + Is.EqualTo false + ) + [] let DetectAsteriskInPackageReferenceItems1() = From 0a1178a96f59eee44beda49b6e260ef0bb234a27 Mon Sep 17 00:00:00 2001 From: realmarv Date: Tue, 23 May 2023 15:03:57 +0330 Subject: [PATCH 02/10] FileConventions: remove extra parentheses --- src/FileConventions/Library.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FileConventions/Library.fs b/src/FileConventions/Library.fs index e471f54cd..38613bb83 100644 --- a/src/FileConventions/Library.fs +++ b/src/FileConventions/Library.fs @@ -73,7 +73,7 @@ let DetectUnpinnedVersionsInGitHubCI(fileInfo: FileInfo) = latestTagInRunsOnRegex.IsMatch fileText let DetectUnpinnedDotnetToolInstallVersions(fileInfo: FileInfo) = - assert (fileInfo.FullName.EndsWith(".yml")) + assert fileInfo.FullName.EndsWith ".yml" let fileLines = File.ReadLines fileInfo.FullName @@ -84,7 +84,7 @@ let DetectUnpinnedDotnetToolInstallVersions(fileInfo: FileInfo) = fileLines |> Seq.filter dotnetToolInstallRegex.IsMatch |> Seq.filter(fun line -> - not(line.Contains("--version")) && not(line.Contains("-v")) + not(line.Contains "--version") && not(line.Contains "-v") ) |> (fun unpinnedVersions -> Seq.length unpinnedVersions > 0) From 134e1a107875de757b7c715407173ab684aafd7b Mon Sep 17 00:00:00 2001 From: realmarv Date: Thu, 6 Jul 2023 12:39:50 +0330 Subject: [PATCH 03/10] FileConventions.Test: add failing test Add failing test for detecting unpinned version in npm package installations. --- ...mmyCIWithUnpinnedNpmPackageInstallVersion.yml | 11 +++++++++++ src/FileConventions.Test/FileConventions.Test.fs | 16 ++++++++++++++++ src/FileConventions/Library.fs | 4 ++++ 3 files changed, 31 insertions(+) create mode 100644 src/FileConventions.Test/DummyFiles/DummyCIWithUnpinnedNpmPackageInstallVersion.yml diff --git a/src/FileConventions.Test/DummyFiles/DummyCIWithUnpinnedNpmPackageInstallVersion.yml b/src/FileConventions.Test/DummyFiles/DummyCIWithUnpinnedNpmPackageInstallVersion.yml new file mode 100644 index 000000000..4f0e52c33 --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyCIWithUnpinnedNpmPackageInstallVersion.yml @@ -0,0 +1,11 @@ +name: CI + +on: [push, pull_request] + +jobs: + file-conventions: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install prettier without specifying its version + run: npm install prettier diff --git a/src/FileConventions.Test/FileConventions.Test.fs b/src/FileConventions.Test/FileConventions.Test.fs index 1082950d0..7e19e19cb 100644 --- a/src/FileConventions.Test/FileConventions.Test.fs +++ b/src/FileConventions.Test/FileConventions.Test.fs @@ -156,6 +156,22 @@ let DetectUnpinnedDotnetToolInstallVersions2() = ) +[] +let DetectUnpinnedNpmPackageInstallVersions1() = + let fileInfo = + (FileInfo( + Path.Combine( + dummyFilesDirectory.FullName, + "DummyCIWithUnpinnedNpmPackageInstallVersion.yml" + ) + )) + + Assert.That( + DetectUnpinnedNpmPackageInstallVersions fileInfo, + Is.EqualTo true + ) + + [] let DetectAsteriskInPackageReferenceItems1() = let fileInfo = diff --git a/src/FileConventions/Library.fs b/src/FileConventions/Library.fs index 38613bb83..6910b4e93 100644 --- a/src/FileConventions/Library.fs +++ b/src/FileConventions/Library.fs @@ -90,6 +90,10 @@ let DetectUnpinnedDotnetToolInstallVersions(fileInfo: FileInfo) = unpinnedDotnetToolInstallVersions +let DetectUnpinnedNpmPackageInstallVersions(fileInfo: FileInfo) = + printfn "File Path: %s" fileInfo.FullName + false + let DetectAsteriskInPackageReferenceItems(fileInfo: FileInfo) = assert (fileInfo.FullName.EndsWith "proj") From 27de48e7f458e0650548a9483cb935b033f5bbb6 Mon Sep 17 00:00:00 2001 From: realmarv Date: Thu, 6 Jul 2023 12:56:59 +0330 Subject: [PATCH 04/10] FileConventions: implement the function Implement DetectUnpinnedNpmPackageInstallVersions function. --- src/FileConventions/Library.fs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/FileConventions/Library.fs b/src/FileConventions/Library.fs index 6910b4e93..f13d1d049 100644 --- a/src/FileConventions/Library.fs +++ b/src/FileConventions/Library.fs @@ -91,8 +91,20 @@ let DetectUnpinnedDotnetToolInstallVersions(fileInfo: FileInfo) = unpinnedDotnetToolInstallVersions let DetectUnpinnedNpmPackageInstallVersions(fileInfo: FileInfo) = - printfn "File Path: %s" fileInfo.FullName - false + assert fileInfo.FullName.EndsWith ".yml" + + let fileLines = File.ReadLines fileInfo.FullName + + let npmPackageInstallRegex = + Regex("npm\\s+install\\s+", RegexOptions.Compiled) + + let unpinnedNpmPackageInstallVersions = + fileLines + |> Seq.filter(fun line -> npmPackageInstallRegex.IsMatch line) + |> Seq.filter(fun line -> not(line.Contains "@")) + |> (fun unpinnedVersions -> Seq.length unpinnedVersions > 0) + + unpinnedNpmPackageInstallVersions let DetectAsteriskInPackageReferenceItems(fileInfo: FileInfo) = assert (fileInfo.FullName.EndsWith "proj") From 16e3502abe59a6924f86f338d71dcb6d086de86c Mon Sep 17 00:00:00 2001 From: realmarv Date: Thu, 6 Jul 2023 14:14:06 +0330 Subject: [PATCH 05/10] FileConventions.Test: add test Add another test for DetectUnpinnedNpmPackageInstallVersions. --- ...CIWithoutUnpinnedNpmPackageInstallVersion.yml | 11 +++++++++++ src/FileConventions.Test/FileConventions.Test.fs | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/FileConventions.Test/DummyFiles/DummyCIWithoutUnpinnedNpmPackageInstallVersion.yml diff --git a/src/FileConventions.Test/DummyFiles/DummyCIWithoutUnpinnedNpmPackageInstallVersion.yml b/src/FileConventions.Test/DummyFiles/DummyCIWithoutUnpinnedNpmPackageInstallVersion.yml new file mode 100644 index 000000000..080f74605 --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyCIWithoutUnpinnedNpmPackageInstallVersion.yml @@ -0,0 +1,11 @@ +name: CI + +on: [push, pull_request] + +jobs: + file-conventions: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install prettier with specifying its version + run: npm install prettier@2.8.3 diff --git a/src/FileConventions.Test/FileConventions.Test.fs b/src/FileConventions.Test/FileConventions.Test.fs index 7e19e19cb..0319edbca 100644 --- a/src/FileConventions.Test/FileConventions.Test.fs +++ b/src/FileConventions.Test/FileConventions.Test.fs @@ -172,6 +172,22 @@ let DetectUnpinnedNpmPackageInstallVersions1() = ) +[] +let DetectUnpinnedNpmPackageInstallVersions2() = + let fileInfo = + (FileInfo( + Path.Combine( + dummyFilesDirectory.FullName, + "DummyCIWithoutUnpinnedNpmPackageInstallVersion.yml" + ) + )) + + Assert.That( + DetectUnpinnedNpmPackageInstallVersions fileInfo, + Is.EqualTo false + ) + + [] let DetectAsteriskInPackageReferenceItems1() = let fileInfo = From 4823d7d8edb8987af58b5d403e96823611d4db8c Mon Sep 17 00:00:00 2001 From: realmarv Date: Thu, 6 Jul 2023 14:20:56 +0330 Subject: [PATCH 06/10] scripts/unpinnedNpmPackageInstallVersions.fsx: add Add unpinnedNpmPackageInstallVersions.fsx script and specify package versions in npm install commands in GitHubCI. --- .github/workflows/CI.yml | 6 +++-- scripts/unpinnedNpmPackageInstallVersions.fsx | 23 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100755 scripts/unpinnedNpmPackageInstallVersions.fsx diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 5c23e7db2..1c830059f 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -90,7 +90,7 @@ jobs: npm --version - name: Install yarn run: | - npm install --verbose --global yarn + npm install --verbose --global yarn@1.22.19 yarn add --dev typescript - name: Install commitlint dependencies run: | @@ -121,7 +121,7 @@ jobs: sudo apt install --yes --no-install-recommends npm curl - name: Install yarn run: | - npm install --verbose --global yarn + npm install --verbose --global yarn@1.22.19 yarn add --dev typescript ts-node - name: Install commitlint dependencies run: | @@ -210,6 +210,8 @@ jobs: run: dotnet fsi scripts/unpinnedNugetPackageReferenceVersionsInFSharpScripts.fsx - name: Check there are no unpinned versions in `dotnet tool install` commands run: dotnet fsi scripts/unpinnedDotnetToolInstallVersions.fsx + - name: Check there are no unpinned versions in `npm install` commands + run: dotnet fsi scripts/unpinnedNpmPackageInstallVersions.fsx - name: Check commits 1 by 1 if: github.event_name == 'pull_request' run: dotnet fsi scripts/checkCommits1by1.fsx diff --git a/scripts/unpinnedNpmPackageInstallVersions.fsx b/scripts/unpinnedNpmPackageInstallVersions.fsx new file mode 100755 index 000000000..c93620cce --- /dev/null +++ b/scripts/unpinnedNpmPackageInstallVersions.fsx @@ -0,0 +1,23 @@ +#!/usr/bin/env -S dotnet fsi + +open System +open System.IO + +#r "nuget: Mono.Unix, Version=7.1.0-final.1.21458.1" +#r "nuget: YamlDotNet, Version=16.1.3" + +#load "../src/FileConventions/Library.fs" +#load "../src/FileConventions/Helpers.fs" + +let rootDir = Path.Combine(__SOURCE_DIRECTORY__, "..") |> DirectoryInfo + +let invalidFiles = + Helpers.GetInvalidFiles + rootDir + "*.yml" + FileConventions.DetectUnpinnedNpmPackageInstallVersions + +let message = + "Please define the package version number in the `npm install` commands." + +Helpers.AssertNoInvalidFiles invalidFiles message From 6e03e117a543cf3dff7756d3f83d4e1c18408c91 Mon Sep 17 00:00:00 2001 From: realmarv Date: Thu, 6 Jul 2023 14:29:20 +0330 Subject: [PATCH 07/10] FileConventions.Test: add failing test Add failing test for DetectUnpinnedNpmPackageInstallVersions function. --- ...IWithUnpinnedNpmPackageInstallVersion1.yml} | 0 ...CIWithUnpinnedNpmPackageInstallVersion2.yml | 11 +++++++++++ .../FileConventions.Test.fs | 18 +++++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) rename src/FileConventions.Test/DummyFiles/{DummyCIWithUnpinnedNpmPackageInstallVersion.yml => DummyCIWithUnpinnedNpmPackageInstallVersion1.yml} (100%) create mode 100644 src/FileConventions.Test/DummyFiles/DummyCIWithUnpinnedNpmPackageInstallVersion2.yml diff --git a/src/FileConventions.Test/DummyFiles/DummyCIWithUnpinnedNpmPackageInstallVersion.yml b/src/FileConventions.Test/DummyFiles/DummyCIWithUnpinnedNpmPackageInstallVersion1.yml similarity index 100% rename from src/FileConventions.Test/DummyFiles/DummyCIWithUnpinnedNpmPackageInstallVersion.yml rename to src/FileConventions.Test/DummyFiles/DummyCIWithUnpinnedNpmPackageInstallVersion1.yml diff --git a/src/FileConventions.Test/DummyFiles/DummyCIWithUnpinnedNpmPackageInstallVersion2.yml b/src/FileConventions.Test/DummyFiles/DummyCIWithUnpinnedNpmPackageInstallVersion2.yml new file mode 100644 index 000000000..a05bab538 --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyCIWithUnpinnedNpmPackageInstallVersion2.yml @@ -0,0 +1,11 @@ +name: CI + +on: [push, pull_request] + +jobs: + file-conventions: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install an npm package without specifying its version + run: sudo npm install --save-dev @prettier/plugin-xml diff --git a/src/FileConventions.Test/FileConventions.Test.fs b/src/FileConventions.Test/FileConventions.Test.fs index 0319edbca..e912e6050 100644 --- a/src/FileConventions.Test/FileConventions.Test.fs +++ b/src/FileConventions.Test/FileConventions.Test.fs @@ -162,7 +162,7 @@ let DetectUnpinnedNpmPackageInstallVersions1() = (FileInfo( Path.Combine( dummyFilesDirectory.FullName, - "DummyCIWithUnpinnedNpmPackageInstallVersion.yml" + "DummyCIWithUnpinnedNpmPackageInstallVersion1.yml" ) )) @@ -188,6 +188,22 @@ let DetectUnpinnedNpmPackageInstallVersions2() = ) +[] +let DetectUnpinnedNpmPackageInstallVersions3() = + let fileInfo = + (FileInfo( + Path.Combine( + dummyFilesDirectory.FullName, + "DummyCIWithUnpinnedNpmPackageInstallVersion2.yml" + ) + )) + + Assert.That( + DetectUnpinnedNpmPackageInstallVersions fileInfo, + Is.EqualTo true + ) + + [] let DetectAsteriskInPackageReferenceItems1() = let fileInfo = From 42380be0e444f77644d8035028fa4f97443ea213 Mon Sep 17 00:00:00 2001 From: realmarv Date: Thu, 6 Jul 2023 14:37:49 +0330 Subject: [PATCH 08/10] FileConventions: fix the function Fix DetectUnpinnedNpmPackageInstallVersions function. --- src/FileConventions/Library.fs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/FileConventions/Library.fs b/src/FileConventions/Library.fs index f13d1d049..b99df9cfb 100644 --- a/src/FileConventions/Library.fs +++ b/src/FileConventions/Library.fs @@ -98,10 +98,15 @@ let DetectUnpinnedNpmPackageInstallVersions(fileInfo: FileInfo) = let npmPackageInstallRegex = Regex("npm\\s+install\\s+", RegexOptions.Compiled) + let npmPackageVersionRegex = + Regex("@((\\d+\\.\\d+\\.\\d+)|(\\$[A-Z_]+))", RegexOptions.Compiled) + let unpinnedNpmPackageInstallVersions = fileLines - |> Seq.filter(fun line -> npmPackageInstallRegex.IsMatch line) - |> Seq.filter(fun line -> not(line.Contains "@")) + |> Seq.filter(fun line -> + npmPackageInstallRegex.IsMatch line + && npmPackageVersionRegex.IsMatch line |> not + ) |> (fun unpinnedVersions -> Seq.length unpinnedVersions > 0) unpinnedNpmPackageInstallVersions From 714e0cd8eea755621151f77c5150a2d9617aa5f4 Mon Sep 17 00:00:00 2001 From: realmarv Date: Thu, 6 Jul 2023 15:03:04 +0330 Subject: [PATCH 09/10] FileConventions: add another failing test Add failing test for DetectUnpinnedNpmPackageInstallVersions function. --- ...myCIWithUnpinnedNpmPackageInstallVersion3.yml | 11 +++++++++++ src/FileConventions.Test/FileConventions.Test.fs | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/FileConventions.Test/DummyFiles/DummyCIWithUnpinnedNpmPackageInstallVersion3.yml diff --git a/src/FileConventions.Test/DummyFiles/DummyCIWithUnpinnedNpmPackageInstallVersion3.yml b/src/FileConventions.Test/DummyFiles/DummyCIWithUnpinnedNpmPackageInstallVersion3.yml new file mode 100644 index 000000000..87ed0e981 --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyCIWithUnpinnedNpmPackageInstallVersion3.yml @@ -0,0 +1,11 @@ +name: CI + +on: [push, pull_request] + +jobs: + file-conventions: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install two npm packages, one with version and the other one without version + run: sudo npm install --save-dev @prettier/plugin-xml prettier@2.4.0 diff --git a/src/FileConventions.Test/FileConventions.Test.fs b/src/FileConventions.Test/FileConventions.Test.fs index e912e6050..736d41807 100644 --- a/src/FileConventions.Test/FileConventions.Test.fs +++ b/src/FileConventions.Test/FileConventions.Test.fs @@ -204,6 +204,22 @@ let DetectUnpinnedNpmPackageInstallVersions3() = ) +[] +let DetectUnpinnedNpmPackageInstallVersions4() = + let fileInfo = + (FileInfo( + Path.Combine( + dummyFilesDirectory.FullName, + "DummyCIWithUnpinnedNpmPackageInstallVersion3.yml" + ) + )) + + Assert.That( + DetectUnpinnedNpmPackageInstallVersions fileInfo, + Is.EqualTo true + ) + + [] let DetectAsteriskInPackageReferenceItems1() = let fileInfo = From d51a9035d270d569b317d79ad95bf6df55720ed6 Mon Sep 17 00:00:00 2001 From: realmarv Date: Thu, 6 Jul 2023 16:13:43 +0330 Subject: [PATCH 10/10] FileConventions: fix the function Fix DetectUnpinnedNpmPackageInstallVersions function. --- src/FileConventions/Library.fs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/FileConventions/Library.fs b/src/FileConventions/Library.fs index b99df9cfb..a8ff42703 100644 --- a/src/FileConventions/Library.fs +++ b/src/FileConventions/Library.fs @@ -103,9 +103,22 @@ let DetectUnpinnedNpmPackageInstallVersions(fileInfo: FileInfo) = let unpinnedNpmPackageInstallVersions = fileLines + |> Seq.filter(fun line -> npmPackageInstallRegex.IsMatch line) |> Seq.filter(fun line -> - npmPackageInstallRegex.IsMatch line - && npmPackageVersionRegex.IsMatch line |> not + let npmPackagesRegex = + Regex("(?<=npm install ).*$", RegexOptions.Compiled) + + let npmInstallPackages = npmPackagesRegex.Match line + + let numNpmInstallPackages = + npmInstallPackages.Value.Split(" ") + |> Seq.filter(fun word -> word.Trim().StartsWith("-") |> not) + |> Seq.length + + let numNpmInstallVersions = + npmPackageVersionRegex.Matches line |> Seq.length + + numNpmInstallPackages = numNpmInstallVersions |> not ) |> (fun unpinnedVersions -> Seq.length unpinnedVersions > 0)