From c6db61e5b05ec638abd8a1ffb47e25146658be11 Mon Sep 17 00:00:00 2001 From: per1234 Date: Thu, 3 Dec 2020 12:51:24 -0800 Subject: [PATCH 01/10] Add dedicated test data for library without examples Previously, tests that needed a library without examples used a library that just happened to not have examples for test data. Using test data specifically intended to provide the necessary conditions will result in less fragile tests. --- check/checkfunctions/library_test.go | 4 ++-- .../testdata/libraries/NoExamples/library.properties | 9 +++++++++ .../testdata/libraries/NoExamples/src/NoExamples.h | 0 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 check/checkfunctions/testdata/libraries/NoExamples/library.properties create mode 100644 check/checkfunctions/testdata/libraries/NoExamples/src/NoExamples.h diff --git a/check/checkfunctions/library_test.go b/check/checkfunctions/library_test.go index 09936413..faaf227c 100644 --- a/check/checkfunctions/library_test.go +++ b/check/checkfunctions/library_test.go @@ -346,7 +346,7 @@ func TestMisspelledExamplesFolderName(t *testing.T) { testTables := []libraryCheckFunctionTestTable{ {"Correctly spelled", "ExamplesFolder", checkresult.Pass, ""}, {"Misspelled", "MisspelledExamplesFolder", checkresult.Fail, ""}, - {"No examples folder", "Recursive", checkresult.Pass, ""}, + {"No examples folder", "NoExamples", checkresult.Pass, ""}, } checkLibraryCheckFunction(MisspelledExamplesFolderName, testTables, t) @@ -356,7 +356,7 @@ func TestIncorrectExamplesFolderNameCase(t *testing.T) { testTables := []libraryCheckFunctionTestTable{ {"Correct case", "ExamplesFolder", checkresult.Pass, ""}, {"Incorrect case", "IncorrectExamplesFolderCase", checkresult.Fail, ""}, - {"No examples folder", "Recursive", checkresult.Pass, ""}, + {"No examples folder", "NoExamples", checkresult.Pass, ""}, } checkLibraryCheckFunction(IncorrectExamplesFolderNameCase, testTables, t) diff --git a/check/checkfunctions/testdata/libraries/NoExamples/library.properties b/check/checkfunctions/testdata/libraries/NoExamples/library.properties new file mode 100644 index 00000000..8b1ff0d7 --- /dev/null +++ b/check/checkfunctions/testdata/libraries/NoExamples/library.properties @@ -0,0 +1,9 @@ +name=NoExamples +version=1.0.0 +author=Cristian Maglie , Pippo Pluto +maintainer=Cristian Maglie +sentence=A library that makes coding a web server a breeze. +paragraph=Supports HTTP1.1 and you can do GET and POST. +category=Communication +url=http://example.com/ +architectures=avr diff --git a/check/checkfunctions/testdata/libraries/NoExamples/src/NoExamples.h b/check/checkfunctions/testdata/libraries/NoExamples/src/NoExamples.h new file mode 100644 index 00000000..e69de29b From 2118c62eddaa8b72376d5f107567595418d3410b Mon Sep 17 00:00:00 2001 From: per1234 Date: Thu, 3 Dec 2020 12:54:40 -0800 Subject: [PATCH 02/10] Add check for missing library examples --- .../checkconfigurations.go | 15 +++++++++++++ check/checkfunctions/library.go | 22 +++++++++++++++++++ check/checkfunctions/library_test.go | 10 +++++++++ .../ExampleFolder/example/Example/Example.ino | 2 ++ .../ExampleFolder/library.properties | 9 ++++++++ .../ExampleFolder/src/ExampleFolder.h | 0 6 files changed, 58 insertions(+) create mode 100644 check/checkfunctions/testdata/libraries/ExampleFolder/example/Example/Example.ino create mode 100644 check/checkfunctions/testdata/libraries/ExampleFolder/library.properties create mode 100644 check/checkfunctions/testdata/libraries/ExampleFolder/src/ExampleFolder.h diff --git a/check/checkconfigurations/checkconfigurations.go b/check/checkconfigurations/checkconfigurations.go index 06d5ad89..5f4aac44 100644 --- a/check/checkconfigurations/checkconfigurations.go +++ b/check/checkconfigurations/checkconfigurations.go @@ -1016,6 +1016,21 @@ var configurations = []Type{ ErrorModes: []checkmode.Type{checkmode.Default}, CheckFunction: checkfunctions.IncorrectLibrarySrcFolderNameCase, }, + { + ProjectType: projecttype.Library, + Category: "structure", + Subcategory: "", + ID: "", + Brief: "no examples", + Description: "", + MessageTemplate: "No example sketches found. Please provide examples. See: https://arduino.github.io/arduino-cli/latest/library-specification/#library-examples", + DisableModes: nil, + EnableModes: []checkmode.Type{checkmode.Default}, + InfoModes: nil, + WarningModes: []checkmode.Type{checkmode.Default}, + ErrorModes: nil, + CheckFunction: checkfunctions.MissingExamples, + }, { ProjectType: projecttype.Library, Category: "structure", diff --git a/check/checkfunctions/library.go b/check/checkfunctions/library.go index 3fece099..f53b61ea 100644 --- a/check/checkfunctions/library.go +++ b/check/checkfunctions/library.go @@ -1084,6 +1084,28 @@ func IncorrectLibrarySrcFolderNameCase() (result checkresult.Type, output string return checkresult.Pass, "" } +// MissingExamples checks whether the library is missing examples. +func MissingExamples() (result checkresult.Type, output string) { + for _, examplesFolderName := range library.ExamplesFolderSupportedNames() { + examplesPath := checkdata.ProjectPath().Join(examplesFolderName) + exists, err := examplesPath.IsDirCheck() + if err != nil { + panic(err) + } + if exists { + directoryListing, _ := examplesPath.ReadDirRecursive() + directoryListing.FilterDirs() + for _, potentialExamplePath := range directoryListing { + if sketch.ContainsMainSketchFile(potentialExamplePath) { + return checkresult.Pass, "" + } + } + } + } + + return checkresult.Fail, "" +} + // MisspelledExamplesFolderName checks for incorrectly spelled `examples` folder name. func MisspelledExamplesFolderName() (result checkresult.Type, output string) { directoryListing, err := checkdata.ProjectPath().ReadDir() diff --git a/check/checkfunctions/library_test.go b/check/checkfunctions/library_test.go index faaf227c..9dcea4ab 100644 --- a/check/checkfunctions/library_test.go +++ b/check/checkfunctions/library_test.go @@ -342,6 +342,16 @@ func TestIncorrectLibrarySrcFolderNameCase(t *testing.T) { checkLibraryCheckFunction(IncorrectLibrarySrcFolderNameCase, testTables, t) } +func TestMissingExamples(t *testing.T) { + testTables := []libraryCheckFunctionTestTable{ + {"Has examples", "ExamplesFolder", checkresult.Pass, ""}, + {`Has examples (in "example" folder)`, "ExampleFolder", checkresult.Pass, ""}, + {"No examples", "NoExamples", checkresult.Fail, ""}, + } + + checkLibraryCheckFunction(MissingExamples, testTables, t) +} + func TestMisspelledExamplesFolderName(t *testing.T) { testTables := []libraryCheckFunctionTestTable{ {"Correctly spelled", "ExamplesFolder", checkresult.Pass, ""}, diff --git a/check/checkfunctions/testdata/libraries/ExampleFolder/example/Example/Example.ino b/check/checkfunctions/testdata/libraries/ExampleFolder/example/Example/Example.ino new file mode 100644 index 00000000..660bdbcc --- /dev/null +++ b/check/checkfunctions/testdata/libraries/ExampleFolder/example/Example/Example.ino @@ -0,0 +1,2 @@ +void setup() {} +void loop() {} diff --git a/check/checkfunctions/testdata/libraries/ExampleFolder/library.properties b/check/checkfunctions/testdata/libraries/ExampleFolder/library.properties new file mode 100644 index 00000000..da141157 --- /dev/null +++ b/check/checkfunctions/testdata/libraries/ExampleFolder/library.properties @@ -0,0 +1,9 @@ +name=ExampleFolder +version=1.0.0 +author=Cristian Maglie , Pippo Pluto +maintainer=Cristian Maglie +sentence=A library that makes coding a web server a breeze. +paragraph=Supports HTTP1.1 and you can do GET and POST. +category=Communication +url=http://example.com/ +architectures=avr diff --git a/check/checkfunctions/testdata/libraries/ExampleFolder/src/ExampleFolder.h b/check/checkfunctions/testdata/libraries/ExampleFolder/src/ExampleFolder.h new file mode 100644 index 00000000..e69de29b From dd2966ddb8a0462b913eaffc61244f4a63b928ab Mon Sep 17 00:00:00 2001 From: per1234 Date: Thu, 3 Dec 2020 19:18:58 -0800 Subject: [PATCH 03/10] Add checks for missing license file If a file with one of the names supported by the licensee gem is in the root of the repository containing the text of a standard license, GitHub recognizes the license type and enables some nice integrations. So having such a file is best practices. These checks are only for the presence of the file, rather than their contents. --- .../checkconfigurations.go | 45 +++++++++++++++++++ check/checkfunctions/checkfunctions.go | 32 ++++++++++--- check/checkfunctions/checkfunctions_test.go | 11 +++++ .../subfolder/LICENSE | 0 .../testdata/general/license-file/LICENSE | 0 .../testdata/general/no-license-file/.gitkeep | 0 6 files changed, 82 insertions(+), 6 deletions(-) create mode 100644 check/checkfunctions/testdata/general/license-file-in-subfolder/subfolder/LICENSE create mode 100644 check/checkfunctions/testdata/general/license-file/LICENSE create mode 100644 check/checkfunctions/testdata/general/no-license-file/.gitkeep diff --git a/check/checkconfigurations/checkconfigurations.go b/check/checkconfigurations/checkconfigurations.go index 5f4aac44..159dd983 100644 --- a/check/checkconfigurations/checkconfigurations.go +++ b/check/checkconfigurations/checkconfigurations.go @@ -971,6 +971,21 @@ var configurations = []Type{ ErrorModes: []checkmode.Type{checkmode.Strict}, CheckFunction: checkfunctions.MissingReadme, }, + { + ProjectType: projecttype.Library, + Category: "structure", + Subcategory: "", + ID: "", + Brief: "no license file", + Description: "", + MessageTemplate: "No license file found. See: https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository#detecting-a-license", + DisableModes: nil, + EnableModes: []checkmode.Type{checkmode.Default}, + InfoModes: nil, + WarningModes: []checkmode.Type{checkmode.Default}, + ErrorModes: []checkmode.Type{checkmode.Strict}, + CheckFunction: checkfunctions.MissingLicenseFile, + }, { ProjectType: projecttype.Sketch, Category: "structure", @@ -1166,6 +1181,21 @@ var configurations = []Type{ ErrorModes: []checkmode.Type{checkmode.Strict}, CheckFunction: checkfunctions.MissingReadme, }, + { + ProjectType: projecttype.Sketch, + Category: "structure", + Subcategory: "", + ID: "", + Brief: "no license file", + Description: "", + MessageTemplate: "No license file found. See: https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository#detecting-a-license", + DisableModes: nil, + EnableModes: []checkmode.Type{checkmode.Default}, + InfoModes: nil, + WarningModes: []checkmode.Type{checkmode.Default}, + ErrorModes: []checkmode.Type{checkmode.Strict}, + CheckFunction: checkfunctions.MissingLicenseFile, + }, { ProjectType: projecttype.Platform, Category: "configuration files", @@ -1196,6 +1226,21 @@ var configurations = []Type{ ErrorModes: []checkmode.Type{checkmode.Default}, CheckFunction: checkfunctions.BoardsTxtFormat, }, + { + ProjectType: projecttype.Platform, + Category: "structure", + Subcategory: "", + ID: "", + Brief: "no license file", + Description: "", + MessageTemplate: "No license file found. See: https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository#detecting-a-license", + DisableModes: nil, + EnableModes: []checkmode.Type{checkmode.Default}, + InfoModes: nil, + WarningModes: []checkmode.Type{checkmode.Default}, + ErrorModes: []checkmode.Type{checkmode.Strict}, + CheckFunction: checkfunctions.MissingLicenseFile, + }, { ProjectType: projecttype.PackageIndex, Category: "data", diff --git a/check/checkfunctions/checkfunctions.go b/check/checkfunctions/checkfunctions.go index 33764079..018006df 100644 --- a/check/checkfunctions/checkfunctions.go +++ b/check/checkfunctions/checkfunctions.go @@ -77,17 +77,37 @@ func MissingReadme() (result checkresult.Type, output string) { readmeRegexp := regexp.MustCompile(`(?i)^readme\.(markdown)|(mdown)|(mkdn)|(md)|(textile)|(rdoc)|(org)|(creole)|(mediawiki)|(wiki)|(rst)|(asciidoc)|(adoc)|(asc)|(pod)|(txt)$`) // https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/about-readmes#about-readmes - if pathContainsReadme(checkdata.ProjectPath(), readmeRegexp) || - (checkdata.ProjectPath().Join("docs").Exist() && pathContainsReadme(checkdata.ProjectPath().Join("docs"), readmeRegexp)) || - (checkdata.ProjectPath().Join(".github").Exist() && pathContainsReadme(checkdata.ProjectPath().Join(".github"), readmeRegexp)) { + if pathContainsRegexpMatch(checkdata.ProjectPath(), readmeRegexp) || + (checkdata.ProjectPath().Join("docs").Exist() && pathContainsRegexpMatch(checkdata.ProjectPath().Join("docs"), readmeRegexp)) || + (checkdata.ProjectPath().Join(".github").Exist() && pathContainsRegexpMatch(checkdata.ProjectPath().Join(".github"), readmeRegexp)) { return checkresult.Pass, "" } return checkresult.Fail, "" } -// pathContainsReadme checks if the provided path contains a readme file recognized by GitHub. -func pathContainsReadme(path *paths.Path, readmeRegexp *regexp.Regexp) bool { +// MissingLicenseFile checks if the project has a license file that will be recognized by GitHub. +func MissingLicenseFile() (result checkresult.Type, output string) { + if checkdata.ProjectType() != checkdata.SuperProjectType() { + return checkresult.NotRun, "License file not required for subprojects" + } + + // https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository#detecting-a-license + // https://github.com/licensee/licensee/blob/master/docs/what-we-look-at.md#detecting-the-license-file + // Should be `(?i)^(((un)?licen[sc]e)|(copy(ing|right))|(ofl)|(patents))(\.(?!spdx|header|gemspec).+)?$` but regexp package doesn't support negative lookahead, so only using "preferred extensions". + // github.com/dlclark/regexp2 does support negative lookahead, but I'd prefer to stick with the standard package. + licenseRegexp := regexp.MustCompile(`(?i)^(((un)?licen[sc]e)|(copy(ing|right))|(ofl)|(patents))(\.((md)|(markdown)|(txt)|(html)))?$`) + + // License file must be in root of repo + if pathContainsRegexpMatch(checkdata.ProjectPath(), licenseRegexp) { + return checkresult.Pass, "" + } + + return checkresult.Fail, "" +} + +// pathContainsRegexpMatch checks if the provided path contains a file name matching the given regular expression. +func pathContainsRegexpMatch(path *paths.Path, pathRegexp *regexp.Regexp) bool { listing, err := path.ReadDir() if err != nil { panic(err) @@ -95,7 +115,7 @@ func pathContainsReadme(path *paths.Path, readmeRegexp *regexp.Regexp) bool { listing.FilterOutDirs() for _, file := range listing { - if readmeRegexp.MatchString(file.Base()) { + if pathRegexp.MatchString(file.Base()) { return true } } diff --git a/check/checkfunctions/checkfunctions_test.go b/check/checkfunctions/checkfunctions_test.go index 2c2501c1..70f422fd 100644 --- a/check/checkfunctions/checkfunctions_test.go +++ b/check/checkfunctions/checkfunctions_test.go @@ -71,3 +71,14 @@ func TestMissingReadme(t *testing.T) { checkCheckFunction(MissingReadme, testTables, t) } + +func TestMissingLicenseFile(t *testing.T) { + testTables := []checkFunctionTestTable{ + {"Subproject", "no-license-file", projecttype.Sketch, projecttype.Library, checkresult.NotRun, ""}, + {"Has license", "license-file", projecttype.Sketch, projecttype.Sketch, checkresult.Pass, ""}, + {"Has license in subfolder", "license-file-in-subfolder", projecttype.Sketch, projecttype.Sketch, checkresult.Fail, ""}, + {"No license", "no-license-file", projecttype.Sketch, projecttype.Sketch, checkresult.Fail, ""}, + } + + checkCheckFunction(MissingLicenseFile, testTables, t) +} diff --git a/check/checkfunctions/testdata/general/license-file-in-subfolder/subfolder/LICENSE b/check/checkfunctions/testdata/general/license-file-in-subfolder/subfolder/LICENSE new file mode 100644 index 00000000..e69de29b diff --git a/check/checkfunctions/testdata/general/license-file/LICENSE b/check/checkfunctions/testdata/general/license-file/LICENSE new file mode 100644 index 00000000..e69de29b diff --git a/check/checkfunctions/testdata/general/no-license-file/.gitkeep b/check/checkfunctions/testdata/general/no-license-file/.gitkeep new file mode 100644 index 00000000..e69de29b From b81f90ca5e46cc1c782b3d48869929989a39cb23 Mon Sep 17 00:00:00 2001 From: per1234 Date: Thu, 3 Dec 2020 19:46:21 -0800 Subject: [PATCH 04/10] Add check for missing readme in platforms --- check/checkconfigurations/checkconfigurations.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/check/checkconfigurations/checkconfigurations.go b/check/checkconfigurations/checkconfigurations.go index 159dd983..f32eb424 100644 --- a/check/checkconfigurations/checkconfigurations.go +++ b/check/checkconfigurations/checkconfigurations.go @@ -1226,6 +1226,21 @@ var configurations = []Type{ ErrorModes: []checkmode.Type{checkmode.Default}, CheckFunction: checkfunctions.BoardsTxtFormat, }, + { + ProjectType: projecttype.Platform, + Category: "structure", + Subcategory: "", + ID: "", + Brief: "no readme", + Description: "", + MessageTemplate: "No readme found. Please document your library. See: https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/about-readmes", + DisableModes: nil, + EnableModes: []checkmode.Type{checkmode.Default}, + InfoModes: nil, + WarningModes: []checkmode.Type{checkmode.Default}, + ErrorModes: []checkmode.Type{checkmode.Strict}, + CheckFunction: checkfunctions.MissingReadme, + }, { ProjectType: projecttype.Platform, Category: "structure", From 48a30d5a0549be38ce9583c0903720a326d81d0d Mon Sep 17 00:00:00 2001 From: per1234 Date: Thu, 3 Dec 2020 21:53:04 -0800 Subject: [PATCH 05/10] Add checks for incorrect Arduino.h filename case in #include directives --- .../checkconfigurations.go | 45 +++++++++++++++++++ check/checkfunctions/checkfunctions.go | 32 +++++++++++++ check/checkfunctions/checkfunctions_test.go | 10 +++++ .../testdata/general/Arduino.h/foo.h | 1 + .../testdata/general/arduino.h-angle/foo.h | 1 + .../testdata/general/arduino.h-quote/foo.h | 1 + 6 files changed, 90 insertions(+) create mode 100644 check/checkfunctions/testdata/general/Arduino.h/foo.h create mode 100644 check/checkfunctions/testdata/general/arduino.h-angle/foo.h create mode 100644 check/checkfunctions/testdata/general/arduino.h-quote/foo.h diff --git a/check/checkconfigurations/checkconfigurations.go b/check/checkconfigurations/checkconfigurations.go index f32eb424..8d29ed6b 100644 --- a/check/checkconfigurations/checkconfigurations.go +++ b/check/checkconfigurations/checkconfigurations.go @@ -1121,6 +1121,21 @@ var configurations = []Type{ ErrorModes: []checkmode.Type{checkmode.Default}, CheckFunction: checkfunctions.RecursiveLibraryWithUtilityFolder, }, + { + ProjectType: projecttype.Library, + Category: "code", + Subcategory: "", + ID: "", + Brief: "incorrect Arduino.h case", + Description: "This causes compilation failure on filename case-sensitive OS (e.g., Linux).", + MessageTemplate: "Incorrect of Arduino.h filename case detected in #include directive: {{.}}", + DisableModes: nil, + EnableModes: []checkmode.Type{checkmode.Default}, + InfoModes: nil, + WarningModes: []checkmode.Type{checkmode.Default}, + ErrorModes: []checkmode.Type{checkmode.Strict}, + CheckFunction: checkfunctions.IncorrectArduinoDotHFileNameCase, + }, { ProjectType: projecttype.Sketch, Category: "structure", @@ -1196,6 +1211,21 @@ var configurations = []Type{ ErrorModes: []checkmode.Type{checkmode.Strict}, CheckFunction: checkfunctions.MissingLicenseFile, }, + { + ProjectType: projecttype.Sketch, + Category: "code", + Subcategory: "", + ID: "", + Brief: "incorrect Arduino.h case", + Description: "This causes compilation failure on filename case-sensitive OS (e.g., Linux).", + MessageTemplate: "Incorrect of Arduino.h filename case detected in #include directive: {{.}}", + DisableModes: nil, + EnableModes: []checkmode.Type{checkmode.Default}, + InfoModes: nil, + WarningModes: []checkmode.Type{checkmode.Default}, + ErrorModes: []checkmode.Type{checkmode.Strict}, + CheckFunction: checkfunctions.IncorrectArduinoDotHFileNameCase, + }, { ProjectType: projecttype.Platform, Category: "configuration files", @@ -1256,6 +1286,21 @@ var configurations = []Type{ ErrorModes: []checkmode.Type{checkmode.Strict}, CheckFunction: checkfunctions.MissingLicenseFile, }, + { + ProjectType: projecttype.Platform, + Category: "code", + Subcategory: "", + ID: "", + Brief: "incorrect Arduino.h case", + Description: "This causes compilation failure on filename case-sensitive OS (e.g., Linux).", + MessageTemplate: "Incorrect of Arduino.h filename case detected in #include directive: {{.}}", + DisableModes: nil, + EnableModes: []checkmode.Type{checkmode.Default}, + InfoModes: nil, + WarningModes: []checkmode.Type{checkmode.Default}, + ErrorModes: []checkmode.Type{checkmode.Strict}, + CheckFunction: checkfunctions.IncorrectArduinoDotHFileNameCase, + }, { ProjectType: projecttype.PackageIndex, Category: "data", diff --git a/check/checkfunctions/checkfunctions.go b/check/checkfunctions/checkfunctions.go index 018006df..ef64a7fb 100644 --- a/check/checkfunctions/checkfunctions.go +++ b/check/checkfunctions/checkfunctions.go @@ -18,11 +18,13 @@ package checkfunctions import ( "encoding/json" + "fmt" "regexp" "strings" "github.com/arduino/arduino-check/check/checkdata" "github.com/arduino/arduino-check/check/checkresult" + "github.com/arduino/arduino-check/project/sketch" "github.com/arduino/go-paths-helper" ) @@ -106,6 +108,36 @@ func MissingLicenseFile() (result checkresult.Type, output string) { return checkresult.Fail, "" } +// IncorrectArduinoDotHFileNameCase checks for incorrect file name case of Arduino.h in #include directives. +func IncorrectArduinoDotHFileNameCase() (result checkresult.Type, output string) { + incorrectCaseRegexp := regexp.MustCompile(`^\s*#\s*include\s*["<](a((?i)rduino)|(ARDUINO))\.[hH][">]`) + + directoryListing, err := checkdata.ProjectPath().ReadDirRecursive() + if err != nil { + panic(err) + } + directoryListing.FilterOutDirs() + + for _, file := range directoryListing { + if !sketch.HasSupportedExtension(file) { // Won't catch all possible files, but good enough. + continue + } + + lines, err := file.ReadFileAsLines() + if err != nil { + panic(err) + } + + for lineNumber, line := range lines { + if incorrectCaseRegexp.MatchString(line) { + return checkresult.Fail, fmt.Sprintf("%s:%v: %s", file, lineNumber+1, line) + } + } + } + + return checkresult.Pass, "" +} + // pathContainsRegexpMatch checks if the provided path contains a file name matching the given regular expression. func pathContainsRegexpMatch(path *paths.Path, pathRegexp *regexp.Regexp) bool { listing, err := path.ReadDir() diff --git a/check/checkfunctions/checkfunctions_test.go b/check/checkfunctions/checkfunctions_test.go index 70f422fd..c85adb84 100644 --- a/check/checkfunctions/checkfunctions_test.go +++ b/check/checkfunctions/checkfunctions_test.go @@ -82,3 +82,13 @@ func TestMissingLicenseFile(t *testing.T) { checkCheckFunction(MissingLicenseFile, testTables, t) } + +func TestIncorrectArduinoDotHFileNameCase(t *testing.T) { + testTables := []checkFunctionTestTable{ + {"Incorrect, angle brackets", "arduino.h-angle", projecttype.Sketch, projecttype.Sketch, checkresult.Fail, ""}, + {"Incorrect, quotes", "arduino.h-quote", projecttype.Sketch, projecttype.Sketch, checkresult.Fail, ""}, + {"Correct case", "Arduino.h", projecttype.Sketch, projecttype.Sketch, checkresult.Pass, ""}, + } + + checkCheckFunction(IncorrectArduinoDotHFileNameCase, testTables, t) +} diff --git a/check/checkfunctions/testdata/general/Arduino.h/foo.h b/check/checkfunctions/testdata/general/Arduino.h/foo.h new file mode 100644 index 00000000..dca27d86 --- /dev/null +++ b/check/checkfunctions/testdata/general/Arduino.h/foo.h @@ -0,0 +1 @@ +#include diff --git a/check/checkfunctions/testdata/general/arduino.h-angle/foo.h b/check/checkfunctions/testdata/general/arduino.h-angle/foo.h new file mode 100644 index 00000000..7e5c3d89 --- /dev/null +++ b/check/checkfunctions/testdata/general/arduino.h-angle/foo.h @@ -0,0 +1 @@ +#include diff --git a/check/checkfunctions/testdata/general/arduino.h-quote/foo.h b/check/checkfunctions/testdata/general/arduino.h-quote/foo.h new file mode 100644 index 00000000..bd1a57e6 --- /dev/null +++ b/check/checkfunctions/testdata/general/arduino.h-quote/foo.h @@ -0,0 +1 @@ +#include "arduino.h" From a18fef1199b9df9069a5459d0f8a7f6d397fc38e Mon Sep 17 00:00:00 2001 From: per1234 Date: Fri, 4 Dec 2020 06:46:48 -0800 Subject: [PATCH 06/10] Add functions to provide check data for sketches --- check/checkdata/checkdata.go | 1 + check/checkdata/sketch.go | 60 +++++++++++++++++++ project/sketch/sketch.go | 24 ++++++++ project/sketch/sketch_test.go | 5 ++ .../HasMetadataFile/HasMetadataFile.ino | 2 + .../testdata/HasMetadataFile/sketch.json | 0 .../NoMetadataFile/NoMetadataFile.ino | 2 + 7 files changed, 94 insertions(+) create mode 100644 check/checkdata/sketch.go create mode 100644 project/sketch/testdata/HasMetadataFile/HasMetadataFile.ino create mode 100644 project/sketch/testdata/HasMetadataFile/sketch.json create mode 100644 project/sketch/testdata/NoMetadataFile/NoMetadataFile.ino diff --git a/check/checkdata/checkdata.go b/check/checkdata/checkdata.go index 4626aaa2..0b101ed4 100644 --- a/check/checkdata/checkdata.go +++ b/check/checkdata/checkdata.go @@ -33,6 +33,7 @@ func Initialize(project project.Type, schemasPath *paths.Path) { projectPath = project.Path switch project.ProjectType { case projecttype.Sketch: + InitializeForSketch(project) case projecttype.Library: InitializeForLibrary(project, schemasPath) case projecttype.Platform: diff --git a/check/checkdata/sketch.go b/check/checkdata/sketch.go new file mode 100644 index 00000000..4013b571 --- /dev/null +++ b/check/checkdata/sketch.go @@ -0,0 +1,60 @@ +// This file is part of arduino-check. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-check. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package checkdata + +import ( + "github.com/arduino/arduino-check/project" + "github.com/arduino/arduino-cli/arduino/sketches" +) + +// InitializeForSketch gathers the check data for the specified sketch project. +func InitializeForSketch(project project.Type) { + loadedSketch, sketchLoadError = sketches.NewSketchFromPath(ProjectPath()) + + metadataSketchObject := &sketches.Sketch{ + Name: ProjectPath().Base(), + FullPath: ProjectPath(), + } + metadataLoadError = metadataSketchObject.ImportMetadata() +} + +var sketchLoadError error + +// SketchLoadError returns the error output from Arduino CLI loading the sketch. +func SketchLoadError() error { + return sketchLoadError +} + +var loadedSketch *sketches.Sketch + +// Sketch returns the sketch object generated by Arduino CLI. +func Sketch() *sketches.Sketch { + return loadedSketch +} + +var metadataLoadError error + +// MetadataLoadError returns the error produced during load of the sketch metadata. +func MetadataLoadError() error { + return metadataLoadError +} + +var metadataSketchObject *sketches.Sketch + +// Metadata returns the metadata object produced by Arduino CLI. +func Metadata() *sketches.Metadata { + return metadataSketchObject.Metadata +} diff --git a/project/sketch/sketch.go b/project/sketch/sketch.go index cb0390d0..19695b84 100644 --- a/project/sketch/sketch.go +++ b/project/sketch/sketch.go @@ -62,3 +62,27 @@ func HasSupportedExtension(filePath *paths.Path) bool { _, hasAdditionalFileValidExtensions := globals.AdditionalFileValidExtensions[filePath.Ext()] return hasAdditionalFileValidExtensions || HasMainFileValidExtension(filePath) } + +var empty struct{} + +// See: https://arduino.github.io/arduino-cli/latest/sketch-specification/#metadata +var metadataFilenames = map[string]struct{}{ + "sketch.json": empty, +} + +// MetadataPath returns the path of the sketch's metadata file. +func MetadataPath(sketchPath *paths.Path) *paths.Path { + for metadataFileName := range metadataFilenames { + metadataPath := sketchPath.Join(metadataFileName) + exist, err := metadataPath.ExistCheck() + if err != nil { + panic(err) + } + + if exist { + return metadataPath + } + } + + return nil +} diff --git a/project/sketch/sketch_test.go b/project/sketch/sketch_test.go index aa8750c5..5fedc56e 100644 --- a/project/sketch/sketch_test.go +++ b/project/sketch/sketch_test.go @@ -45,3 +45,8 @@ func TestHasSupportedExtension(t *testing.T) { assert.True(t, HasSupportedExtension(paths.New("/foo/bar.h"))) assert.False(t, HasSupportedExtension(paths.New("/foo/bar.baz"))) } + +func TestMetadataPath(t *testing.T) { + assert.True(t, MetadataPath(testDataPath.Join("HasMetadataFile")).EquivalentTo(testDataPath.Join("HasMetadataFile", "sketch.json"))) + assert.Nil(t, MetadataPath(testDataPath.Join("NoMetadataFile"))) +} diff --git a/project/sketch/testdata/HasMetadataFile/HasMetadataFile.ino b/project/sketch/testdata/HasMetadataFile/HasMetadataFile.ino new file mode 100644 index 00000000..660bdbcc --- /dev/null +++ b/project/sketch/testdata/HasMetadataFile/HasMetadataFile.ino @@ -0,0 +1,2 @@ +void setup() {} +void loop() {} diff --git a/project/sketch/testdata/HasMetadataFile/sketch.json b/project/sketch/testdata/HasMetadataFile/sketch.json new file mode 100644 index 00000000..e69de29b diff --git a/project/sketch/testdata/NoMetadataFile/NoMetadataFile.ino b/project/sketch/testdata/NoMetadataFile/NoMetadataFile.ino new file mode 100644 index 00000000..660bdbcc --- /dev/null +++ b/project/sketch/testdata/NoMetadataFile/NoMetadataFile.ino @@ -0,0 +1,2 @@ +void setup() {} +void loop() {} From 351c5543fea056e5ab9e45fdee54b232991eee93 Mon Sep 17 00:00:00 2001 From: per1234 Date: Fri, 4 Dec 2020 06:48:09 -0800 Subject: [PATCH 07/10] Add check for sketch.json invalid JSON document --- .prettierignore | 1 + check/checkconfigurations/checkconfigurations.go | 15 +++++++++++++++ check/checkfunctions/sketch.go | 14 ++++++++++++++ check/checkfunctions/sketch_test.go | 10 ++++++++++ .../InvalidJSONMetadataFile.ino | 2 ++ .../sketches/InvalidJSONMetadataFile/sketch.json | 7 +++++++ .../sketches/NoMetadataFile/NoMetadataFile.ino | 2 ++ .../ValidMetadataFile/ValidMetadataFile.ino | 2 ++ .../sketches/ValidMetadataFile/sketch.json | 6 ++++++ 9 files changed, 59 insertions(+) create mode 100644 check/checkfunctions/testdata/sketches/InvalidJSONMetadataFile/InvalidJSONMetadataFile.ino create mode 100644 check/checkfunctions/testdata/sketches/InvalidJSONMetadataFile/sketch.json create mode 100644 check/checkfunctions/testdata/sketches/NoMetadataFile/NoMetadataFile.ino create mode 100644 check/checkfunctions/testdata/sketches/ValidMetadataFile/ValidMetadataFile.ino create mode 100644 check/checkfunctions/testdata/sketches/ValidMetadataFile/sketch.json diff --git a/.prettierignore b/.prettierignore index 2a89a4cb..b2616922 100644 --- a/.prettierignore +++ b/.prettierignore @@ -8,3 +8,4 @@ /check/checkdata/schema/testdata/invalid-schema.json /check/checkdata/testdata/packageindexes/invalid-JSON/package_foo_index.json /check/checkfunctions/testdata/packageindexes/invalid-JSON/package_foo_index.json +/check/checkfunctions/testdata/sketches/InvalidJSONMetadataFile/sketch.json diff --git a/check/checkconfigurations/checkconfigurations.go b/check/checkconfigurations/checkconfigurations.go index 8d29ed6b..e2d831e3 100644 --- a/check/checkconfigurations/checkconfigurations.go +++ b/check/checkconfigurations/checkconfigurations.go @@ -1211,6 +1211,21 @@ var configurations = []Type{ ErrorModes: []checkmode.Type{checkmode.Strict}, CheckFunction: checkfunctions.MissingLicenseFile, }, + { + ProjectType: projecttype.Sketch, + Category: "metadata", + Subcategory: "sketch.json", + ID: "", + Brief: "invalid sketch.json JSON format", + Description: "", + MessageTemplate: "sketch.json is not a valid JSON document. See: https://arduino.github.io/arduino-cli/latest/sketch-specification/#metadata", + DisableModes: nil, + EnableModes: []checkmode.Type{checkmode.Default}, + InfoModes: nil, + WarningModes: []checkmode.Type{checkmode.Permissive}, + ErrorModes: []checkmode.Type{checkmode.Default}, + CheckFunction: checkfunctions.SketchDotJSONJSONFormat, + }, { ProjectType: projecttype.Sketch, Category: "code", diff --git a/check/checkfunctions/sketch.go b/check/checkfunctions/sketch.go index f3b931b9..1e039a94 100644 --- a/check/checkfunctions/sketch.go +++ b/check/checkfunctions/sketch.go @@ -100,3 +100,17 @@ func PdeSketchExtension() (result checkresult.Type, output string) { return checkresult.Pass, "" } + +// SketchDotJSONJSONFormat checks whether the sketch.json metadata file is a valid JSON document. +func SketchDotJSONJSONFormat() (result checkresult.Type, output string) { + metadataPath := sketch.MetadataPath(checkdata.ProjectPath()) + if metadataPath == nil { + return checkresult.NotRun, "No metadata file" + } + + if isValidJSON(metadataPath) { + return checkresult.Pass, "" + } + + return checkresult.Fail, "" +} diff --git a/check/checkfunctions/sketch_test.go b/check/checkfunctions/sketch_test.go index 4ad9a025..518a9c36 100644 --- a/check/checkfunctions/sketch_test.go +++ b/check/checkfunctions/sketch_test.go @@ -95,3 +95,13 @@ func TestPdeSketchExtension(t *testing.T) { checkSketchCheckFunction(PdeSketchExtension, testTables, t) } + +func TestSketchDotJSONJSONFormat(t *testing.T) { + testTables := []sketchCheckFunctionTestTable{ + {"No metadata file", "NoMetadataFile", checkresult.NotRun, ""}, + {"Valid", "ValidMetadataFile", checkresult.Pass, ""}, + {"Invalid", "InvalidJSONMetadataFile", checkresult.Fail, ""}, + } + + checkSketchCheckFunction(SketchDotJSONJSONFormat, testTables, t) +} diff --git a/check/checkfunctions/testdata/sketches/InvalidJSONMetadataFile/InvalidJSONMetadataFile.ino b/check/checkfunctions/testdata/sketches/InvalidJSONMetadataFile/InvalidJSONMetadataFile.ino new file mode 100644 index 00000000..660bdbcc --- /dev/null +++ b/check/checkfunctions/testdata/sketches/InvalidJSONMetadataFile/InvalidJSONMetadataFile.ino @@ -0,0 +1,2 @@ +void setup() {} +void loop() {} diff --git a/check/checkfunctions/testdata/sketches/InvalidJSONMetadataFile/sketch.json b/check/checkfunctions/testdata/sketches/InvalidJSONMetadataFile/sketch.json new file mode 100644 index 00000000..07c0d397 --- /dev/null +++ b/check/checkfunctions/testdata/sketches/InvalidJSONMetadataFile/sketch.json @@ -0,0 +1,7 @@ +[ + { + "foo": "bar" + }, + { + "baz": "bat" + } diff --git a/check/checkfunctions/testdata/sketches/NoMetadataFile/NoMetadataFile.ino b/check/checkfunctions/testdata/sketches/NoMetadataFile/NoMetadataFile.ino new file mode 100644 index 00000000..660bdbcc --- /dev/null +++ b/check/checkfunctions/testdata/sketches/NoMetadataFile/NoMetadataFile.ino @@ -0,0 +1,2 @@ +void setup() {} +void loop() {} diff --git a/check/checkfunctions/testdata/sketches/ValidMetadataFile/ValidMetadataFile.ino b/check/checkfunctions/testdata/sketches/ValidMetadataFile/ValidMetadataFile.ino new file mode 100644 index 00000000..660bdbcc --- /dev/null +++ b/check/checkfunctions/testdata/sketches/ValidMetadataFile/ValidMetadataFile.ino @@ -0,0 +1,2 @@ +void setup() {} +void loop() {} diff --git a/check/checkfunctions/testdata/sketches/ValidMetadataFile/sketch.json b/check/checkfunctions/testdata/sketches/ValidMetadataFile/sketch.json new file mode 100644 index 00000000..3a994a0a --- /dev/null +++ b/check/checkfunctions/testdata/sketches/ValidMetadataFile/sketch.json @@ -0,0 +1,6 @@ +{ + "cpu": { + "fqbn": "arduino:avr:uno", + "port": "" + } +} From 6ce9b3b0e96bc8cb3fa55dfa31e4ab289e4c5186 Mon Sep 17 00:00:00 2001 From: per1234 Date: Fri, 4 Dec 2020 06:48:46 -0800 Subject: [PATCH 08/10] Add check for sketch.json invalid data format This checks whether sketch.json is compliant with the expected data format. --- check/checkconfigurations/checkconfigurations.go | 15 +++++++++++++++ check/checkfunctions/sketch.go | 14 ++++++++++++++ check/checkfunctions/sketch_test.go | 11 +++++++++++ .../InvalidDataMetadataFile.ino | 2 ++ .../sketches/InvalidDataMetadataFile/sketch.json | 8 ++++++++ 5 files changed, 50 insertions(+) create mode 100644 check/checkfunctions/testdata/sketches/InvalidDataMetadataFile/InvalidDataMetadataFile.ino create mode 100644 check/checkfunctions/testdata/sketches/InvalidDataMetadataFile/sketch.json diff --git a/check/checkconfigurations/checkconfigurations.go b/check/checkconfigurations/checkconfigurations.go index e2d831e3..78d1d203 100644 --- a/check/checkconfigurations/checkconfigurations.go +++ b/check/checkconfigurations/checkconfigurations.go @@ -1226,6 +1226,21 @@ var configurations = []Type{ ErrorModes: []checkmode.Type{checkmode.Default}, CheckFunction: checkfunctions.SketchDotJSONJSONFormat, }, + { + ProjectType: projecttype.Sketch, + Category: "metadata", + Subcategory: "sketch.json", + ID: "", + Brief: "invalid sketch.json data format", + Description: "", + MessageTemplate: "sketch.json has an invalid data format: {{.}}. See: https://arduino.github.io/arduino-cli/latest/sketch-specification/#metadata", + DisableModes: nil, + EnableModes: []checkmode.Type{checkmode.Default}, + InfoModes: nil, + WarningModes: []checkmode.Type{checkmode.Permissive}, + ErrorModes: []checkmode.Type{checkmode.Default}, + CheckFunction: checkfunctions.SketchDotJSONFormat, + }, { ProjectType: projecttype.Sketch, Category: "code", diff --git a/check/checkfunctions/sketch.go b/check/checkfunctions/sketch.go index 1e039a94..93819720 100644 --- a/check/checkfunctions/sketch.go +++ b/check/checkfunctions/sketch.go @@ -114,3 +114,17 @@ func SketchDotJSONJSONFormat() (result checkresult.Type, output string) { return checkresult.Fail, "" } + +// SketchDotJSONFormat checks whether the sketch.json metadata file has the required data format. +func SketchDotJSONFormat() (result checkresult.Type, output string) { + metadataPath := sketch.MetadataPath(checkdata.ProjectPath()) + if metadataPath == nil { + return checkresult.NotRun, "No metadata file" + } + + if checkdata.MetadataLoadError() == nil { + return checkresult.Pass, "" + } + + return checkresult.Fail, checkdata.MetadataLoadError().Error() +} diff --git a/check/checkfunctions/sketch_test.go b/check/checkfunctions/sketch_test.go index 518a9c36..56d3b54d 100644 --- a/check/checkfunctions/sketch_test.go +++ b/check/checkfunctions/sketch_test.go @@ -105,3 +105,14 @@ func TestSketchDotJSONJSONFormat(t *testing.T) { checkSketchCheckFunction(SketchDotJSONJSONFormat, testTables, t) } + +func TestSketchDotJSONFormat(t *testing.T) { + testTables := []sketchCheckFunctionTestTable{ + {"No metadata file", "NoMetadataFile", checkresult.NotRun, ""}, + {"Valid", "ValidMetadataFile", checkresult.Pass, ""}, + {"Invalid JSON", "InvalidJSONMetadataFile", checkresult.Fail, ""}, + {"Invalid data", "InvalidDataMetadataFile", checkresult.Fail, ""}, + } + + checkSketchCheckFunction(SketchDotJSONFormat, testTables, t) +} diff --git a/check/checkfunctions/testdata/sketches/InvalidDataMetadataFile/InvalidDataMetadataFile.ino b/check/checkfunctions/testdata/sketches/InvalidDataMetadataFile/InvalidDataMetadataFile.ino new file mode 100644 index 00000000..660bdbcc --- /dev/null +++ b/check/checkfunctions/testdata/sketches/InvalidDataMetadataFile/InvalidDataMetadataFile.ino @@ -0,0 +1,2 @@ +void setup() {} +void loop() {} diff --git a/check/checkfunctions/testdata/sketches/InvalidDataMetadataFile/sketch.json b/check/checkfunctions/testdata/sketches/InvalidDataMetadataFile/sketch.json new file mode 100644 index 00000000..8966cd56 --- /dev/null +++ b/check/checkfunctions/testdata/sketches/InvalidDataMetadataFile/sketch.json @@ -0,0 +1,8 @@ +[ + { + "foo": "bar" + }, + { + "baz": "bat" + } +] From 5a56b424f9148ab21baa7074c3a98f7d7a83836b Mon Sep 17 00:00:00 2001 From: per1234 Date: Fri, 4 Dec 2020 07:20:19 -0800 Subject: [PATCH 09/10] Add check for sketch name mismatch --- .../checkconfigurations/checkconfigurations.go | 15 +++++++++++++++ check/checkfunctions/sketch.go | 18 ++++++++++++++++++ check/checkfunctions/sketch_test.go | 9 +++++++++ .../sketches/NameMismatch/Mismatch.ino | 2 ++ 4 files changed, 44 insertions(+) create mode 100644 check/checkfunctions/testdata/sketches/NameMismatch/Mismatch.ino diff --git a/check/checkconfigurations/checkconfigurations.go b/check/checkconfigurations/checkconfigurations.go index 78d1d203..b2383d58 100644 --- a/check/checkconfigurations/checkconfigurations.go +++ b/check/checkconfigurations/checkconfigurations.go @@ -1241,6 +1241,21 @@ var configurations = []Type{ ErrorModes: []checkmode.Type{checkmode.Default}, CheckFunction: checkfunctions.SketchDotJSONFormat, }, + { + ProjectType: projecttype.Sketch, + Category: "structure", + Subcategory: "", + ID: "", + Brief: "name mismatch", + Description: "", + MessageTemplate: "Sketch file/folder name mismatch. The primary sketch file name must match the folder: {{.}}. See: https://arduino.github.io/arduino-cli/latest/sketch-specification/#primary-sketch-file", + DisableModes: nil, + EnableModes: []checkmode.Type{checkmode.Default}, + InfoModes: nil, + WarningModes: []checkmode.Type{checkmode.Permissive}, + ErrorModes: []checkmode.Type{checkmode.Default}, + CheckFunction: checkfunctions.SketchNameMismatch, + }, { ProjectType: projecttype.Sketch, Category: "code", diff --git a/check/checkfunctions/sketch.go b/check/checkfunctions/sketch.go index 93819720..7ba5a571 100644 --- a/check/checkfunctions/sketch.go +++ b/check/checkfunctions/sketch.go @@ -23,6 +23,7 @@ import ( "github.com/arduino/arduino-check/check/checkdata" "github.com/arduino/arduino-check/check/checkresult" "github.com/arduino/arduino-check/project/sketch" + "github.com/arduino/arduino-cli/arduino/globals" ) // IncorrectSketchSrcFolderNameCase checks for incorrect case of src subfolder name in recursive format libraries. @@ -128,3 +129,20 @@ func SketchDotJSONFormat() (result checkresult.Type, output string) { return checkresult.Fail, checkdata.MetadataLoadError().Error() } + +// SketchNameMismatch checks for mismatch between sketch folder name and primary file name. +func SketchNameMismatch() (result checkresult.Type, output string) { + for extension := range globals.MainFileValidExtensions { + validPrimarySketchFilePath := checkdata.ProjectPath().Join(checkdata.ProjectPath().Base() + extension) + exist, err := validPrimarySketchFilePath.ExistCheck() + if err != nil { + panic(err) + } + + if exist { + return checkresult.Pass, "" + } + } + + return checkresult.Fail, checkdata.ProjectPath().Base() + ".ino" +} diff --git a/check/checkfunctions/sketch_test.go b/check/checkfunctions/sketch_test.go index 56d3b54d..dc96dca3 100644 --- a/check/checkfunctions/sketch_test.go +++ b/check/checkfunctions/sketch_test.go @@ -116,3 +116,12 @@ func TestSketchDotJSONFormat(t *testing.T) { checkSketchCheckFunction(SketchDotJSONFormat, testTables, t) } + +func TestSketchNameMismatch(t *testing.T) { + testTables := []sketchCheckFunctionTestTable{ + {"Valid", "Valid", checkresult.Pass, ""}, + {"Mismatch", "NameMismatch", checkresult.Fail, ""}, + } + + checkSketchCheckFunction(SketchNameMismatch, testTables, t) +} diff --git a/check/checkfunctions/testdata/sketches/NameMismatch/Mismatch.ino b/check/checkfunctions/testdata/sketches/NameMismatch/Mismatch.ino new file mode 100644 index 00000000..660bdbcc --- /dev/null +++ b/check/checkfunctions/testdata/sketches/NameMismatch/Mismatch.ino @@ -0,0 +1,2 @@ +void setup() {} +void loop() {} From 0ebcb787db416611982a5316c5fe21d38cc9e6f9 Mon Sep 17 00:00:00 2001 From: per1234 Date: Sun, 6 Dec 2020 06:53:48 -0800 Subject: [PATCH 10/10] Add check for forgotten library.properties version bump --- .../checkconfigurations.go | 15 +++ check/checkfunctions/library.go | 98 ++++++++++++++++ check/checkfunctions/library_test.go | 107 ++++++++++++++++++ .../libraries/Version1.0.0/library.properties | 9 ++ .../libraries/Version1.0.0/src/Version1.0.0.h | 0 .../VersionFormatInvalid/library.properties | 9 ++ .../src/VersionFormatInvalid.h | 0 go.mod | 2 + go.sum | 19 ++++ 9 files changed, 259 insertions(+) create mode 100644 check/checkfunctions/testdata/libraries/Version1.0.0/library.properties create mode 100644 check/checkfunctions/testdata/libraries/Version1.0.0/src/Version1.0.0.h create mode 100644 check/checkfunctions/testdata/libraries/VersionFormatInvalid/library.properties create mode 100644 check/checkfunctions/testdata/libraries/VersionFormatInvalid/src/VersionFormatInvalid.h diff --git a/check/checkconfigurations/checkconfigurations.go b/check/checkconfigurations/checkconfigurations.go index b2383d58..f4c9ccff 100644 --- a/check/checkconfigurations/checkconfigurations.go +++ b/check/checkconfigurations/checkconfigurations.go @@ -371,6 +371,21 @@ var configurations = []Type{ ErrorModes: []checkmode.Type{checkmode.Strict}, CheckFunction: checkfunctions.LibraryPropertiesVersionFieldNonSemver, }, + { + ProjectType: projecttype.Library, + Category: "library.properties", + Subcategory: "version field", + ID: "", + Brief: "tag mismatch", + Description: "The Library Manager indexer will reject any tag that has a library.properties version equal to a previous tag in the index.", + MessageTemplate: "The latest Git tag appears to be greater than the library.properties version value: {{.}}. You must update the version value before making the tag.", + DisableModes: []checkmode.Type{checkmode.Default}, + EnableModes: []checkmode.Type{checkmode.LibraryManagerIndexed}, + InfoModes: nil, + WarningModes: []checkmode.Type{checkmode.Default}, + ErrorModes: []checkmode.Type{checkmode.Strict}, + CheckFunction: checkfunctions.LibraryPropertiesVersionFieldBehindTag, + }, { ProjectType: projecttype.Library, Category: "library.properties", diff --git a/check/checkfunctions/library.go b/check/checkfunctions/library.go index f53b61ea..3941eedc 100644 --- a/check/checkfunctions/library.go +++ b/check/checkfunctions/library.go @@ -18,6 +18,7 @@ package checkfunctions // The check functions for libraries. import ( + "fmt" "net/http" "os" "path/filepath" @@ -33,7 +34,11 @@ import ( "github.com/arduino/arduino-cli/arduino/libraries" "github.com/arduino/arduino-cli/arduino/utils" "github.com/arduino/go-properties-orderedmap" + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/object" "github.com/sirupsen/logrus" + semver "go.bug.st/relaxed-semver" ) // LibraryPropertiesFormat checks for invalid library.properties format. @@ -381,6 +386,99 @@ func LibraryPropertiesVersionFieldNonSemver() (result checkresult.Type, output s return checkresult.Pass, "" } +// LibraryPropertiesVersionFieldBehindTag checks whether a release tag was made without first bumping the library.properties version value. +func LibraryPropertiesVersionFieldBehindTag() (result checkresult.Type, output string) { + if checkdata.ProjectType() != checkdata.SuperProjectType() { + return checkresult.NotRun, "Not relevant for subprojects" + } + + if checkdata.LibraryPropertiesLoadError() != nil { + return checkresult.NotRun, "Couldn't load library.properties" + } + + versionString, ok := checkdata.LibraryProperties().GetOk("version") + if !ok { + return checkresult.NotRun, "Field not present" + } + + version, err := semver.Parse(versionString) + if err != nil { + return checkresult.NotRun, "Can't parse version value" + } + logrus.Tracef("version value: %s", version) + + repository, err := git.PlainOpen(checkdata.ProjectPath().String()) + if err != nil { + return checkresult.NotRun, "Project path is not a repository" + } + + headRef, err := repository.Head() + if err != nil { + panic(err) + } + + headCommit, err := repository.CommitObject(headRef.Hash()) + if err != nil { + panic(err) + } + + commits := object.NewCommitIterCTime(headCommit, nil, nil) // Get iterator for the head commit and all its parents in chronological commit time order. + + tagRefs, err := repository.Tags() // Get an iterator of the refs of the repository's tags. These are not in a useful order, so it's necessary to cross-reference them against the commits, which are. + + for { // Iterate over all commits in reverse chronological order. + commit, err := commits.Next() + if err != nil { + // Reached end of commits. + break + } + + for { // Iterate over all tag refs. + tagRef, err := tagRefs.Next() + if err != nil { + // Reached end of tags + break + } + + // Annotated tags have their own hash, different from the commit hash, so they must be resolved before comparing with the commit. + resolvedTagRef, err := repository.ResolveRevision(plumbing.Revision(tagRef.Hash().String())) + if err != nil { + panic(err) + } + + if commit.Hash == *resolvedTagRef { + logrus.Tracef("Found tag: %s", tagRef.Name()) + + tagName := strings.TrimPrefix(tagRef.Name().String(), "refs/tags/") + tagName = strings.TrimPrefix(tagName, "v") // It's common practice to prefix release tag names with "v". + tagVersion, err := semver.Parse(tagName) + if err != nil { + // The normalized tag name is not a recognizable "relaxed semver" version. + logrus.Tracef("Can't parse tag name.") + break // Disregard unparsable tags. + } + logrus.Tracef("Tag version: %s", tagVersion) + + if tagVersion.GreaterThan(version) { + logrus.Tracef("Tag is greater.") + + if strings.Contains(tagVersion.String(), "-") { + // The lack of version bump may have been intentional. + logrus.Tracef("Tag is pre-release.") + break + } + + return checkresult.Fail, fmt.Sprintf("%s vs %s", tagName, versionString) + } + + return checkresult.Pass, "" // Tag is less than or equal to version field value, all is well. + } + } + } + + return checkresult.Pass, "" // No problems were found. +} + // LibraryPropertiesAuthorFieldMissing checks for missing library.properties "author" field. func LibraryPropertiesAuthorFieldMissing() (result checkresult.Type, output string) { if checkdata.LibraryPropertiesLoadError() != nil { diff --git a/check/checkfunctions/library_test.go b/check/checkfunctions/library_test.go index 9dcea4ab..50cefd51 100644 --- a/check/checkfunctions/library_test.go +++ b/check/checkfunctions/library_test.go @@ -19,12 +19,15 @@ import ( "os" "regexp" "testing" + "time" "github.com/arduino/arduino-check/check/checkdata" "github.com/arduino/arduino-check/check/checkresult" "github.com/arduino/arduino-check/project" "github.com/arduino/arduino-check/project/projecttype" "github.com/arduino/go-paths-helper" + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing/object" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -152,6 +155,110 @@ func TestLibraryPropertiesNameFieldHeaderMismatch(t *testing.T) { checkLibraryCheckFunction(LibraryPropertiesNameFieldHeaderMismatch, testTables, t) } +func TestLibraryPropertiesVersionFieldBehindTag(t *testing.T) { + // Set up the test repository folders. + TagPrereleaseGreaterPath := librariesTestDataPath.Join("TagPrereleaseGreater") + require.Nil(t, librariesTestDataPath.Join("Recursive").CopyDirTo(TagPrereleaseGreaterPath)) + defer TagPrereleaseGreaterPath.RemoveAll() + + TagGreaterPath := librariesTestDataPath.Join("TagGreater") + require.Nil(t, librariesTestDataPath.Join("Recursive").CopyDirTo(TagGreaterPath)) + defer TagGreaterPath.RemoveAll() + + LightweightTagGreaterPath := librariesTestDataPath.Join("LightweightTagGreater") + require.Nil(t, librariesTestDataPath.Join("Recursive").CopyDirTo(LightweightTagGreaterPath)) + defer LightweightTagGreaterPath.RemoveAll() + + TagMatchPath := librariesTestDataPath.Join("TagMatch") + require.Nil(t, librariesTestDataPath.Join("Recursive").CopyDirTo(TagMatchPath)) + defer TagMatchPath.RemoveAll() + + LightweightTagMatchPath := librariesTestDataPath.Join("LightweightTagMatch") + require.Nil(t, librariesTestDataPath.Join("Recursive").CopyDirTo(LightweightTagMatchPath)) + defer LightweightTagMatchPath.RemoveAll() + + TagMatchWithPrefixPath := librariesTestDataPath.Join("TagMatchWithPrefix") + require.Nil(t, librariesTestDataPath.Join("Recursive").CopyDirTo(TagMatchWithPrefixPath)) + defer TagMatchWithPrefixPath.RemoveAll() + + TagLessThanPath := librariesTestDataPath.Join("TagLessThan") + require.Nil(t, librariesTestDataPath.Join("Recursive").CopyDirTo(TagLessThanPath)) + defer TagLessThanPath.RemoveAll() + + TagNotVersionPath := librariesTestDataPath.Join("TagNotVersion") + require.Nil(t, librariesTestDataPath.Join("Recursive").CopyDirTo(TagNotVersionPath)) + defer TagNotVersionPath.RemoveAll() + + NoTagsPath := librariesTestDataPath.Join("NoTags") + require.Nil(t, librariesTestDataPath.Join("Recursive").CopyDirTo(NoTagsPath)) + defer NoTagsPath.RemoveAll() + + // Test repositories are generated on the fly. + gitInitAndTag := func(t *testing.T, repositoryPath *paths.Path, tagName string, annotated bool) string { + repository, err := git.PlainInit(repositoryPath.String(), false) + require.Nil(t, err) + worktree, err := repository.Worktree() + require.Nil(t, err) + _, err = worktree.Add(".") + require.Nil(t, err) + + signature := &object.Signature{ + Name: "Jane Developer", + Email: "janedeveloper@example.com", + When: time.Now(), + } + + _, err = worktree.Commit( + "Test commit message", + &git.CommitOptions{ + Author: signature, + }, + ) + require.Nil(t, err) + + headRef, err := repository.Head() + require.Nil(t, err) + + if tagName != "" { + // Annotated and lightweight tags are significantly different, so it's important to ensure the check code works correctly with both. + if annotated { + _, err = repository.CreateTag( + tagName, + headRef.Hash(), + &git.CreateTagOptions{ + Tagger: signature, + Message: tagName, + }, + ) + } else { + _, err = repository.CreateTag(tagName, headRef.Hash(), nil) + } + require.Nil(t, err) + } + + return repositoryPath.Base() + } + + testTables := []libraryCheckFunctionTestTable{ + // TODO: Test NotRun if subproject + {"Unable to load", "InvalidLibraryProperties", checkresult.NotRun, ""}, + {"Legacy", "Legacy", checkresult.NotRun, ""}, + {"Unparsable version", "VersionFormatInvalid", checkresult.NotRun, ""}, + {"Not repo", "Recursive", checkresult.NotRun, ""}, + {"Tag name not a version", gitInitAndTag(t, TagNotVersionPath, "foo", true), checkresult.Pass, ""}, + {"Match w/ tag prefix", gitInitAndTag(t, TagMatchWithPrefixPath, "1.0.0", true), checkresult.Pass, ""}, + {"Pre-release tag greater", gitInitAndTag(t, TagPrereleaseGreaterPath, "1.0.1-rc1", true), checkresult.Pass, ""}, + {"Tag greater", gitInitAndTag(t, TagGreaterPath, "1.0.1", true), checkresult.Fail, ""}, + {"Lightweight tag greater", gitInitAndTag(t, LightweightTagGreaterPath, "1.0.1", false), checkresult.Fail, ""}, + {"Tag matches", gitInitAndTag(t, TagMatchPath, "1.0.0", true), checkresult.Pass, ""}, + {"Lightweight tag matches", gitInitAndTag(t, LightweightTagMatchPath, "1.0.0", false), checkresult.Pass, ""}, + {"Tag less than version", gitInitAndTag(t, TagLessThanPath, "0.1.0", true), checkresult.Pass, ""}, + {"No tags", gitInitAndTag(t, NoTagsPath, "", true), checkresult.Pass, ""}, + } + + checkLibraryCheckFunction(LibraryPropertiesVersionFieldBehindTag, testTables, t) +} + func TestLibraryPropertiesSentenceFieldSpellCheck(t *testing.T) { testTables := []libraryCheckFunctionTestTable{ {"Unable to load", "InvalidLibraryProperties", checkresult.NotRun, ""}, diff --git a/check/checkfunctions/testdata/libraries/Version1.0.0/library.properties b/check/checkfunctions/testdata/libraries/Version1.0.0/library.properties new file mode 100644 index 00000000..b6f1766a --- /dev/null +++ b/check/checkfunctions/testdata/libraries/Version1.0.0/library.properties @@ -0,0 +1,9 @@ +name=Version1.0.0 +version=1.0.0 +author=Cristian Maglie , Pippo Pluto +maintainer=Cristian Maglie +sentence=A library that makes coding a web server a breeze. +paragraph=Supports HTTP1.1 and you can do GET and POST. +category=Communication +url=http://example.com/ +architectures=avr diff --git a/check/checkfunctions/testdata/libraries/Version1.0.0/src/Version1.0.0.h b/check/checkfunctions/testdata/libraries/Version1.0.0/src/Version1.0.0.h new file mode 100644 index 00000000..e69de29b diff --git a/check/checkfunctions/testdata/libraries/VersionFormatInvalid/library.properties b/check/checkfunctions/testdata/libraries/VersionFormatInvalid/library.properties new file mode 100644 index 00000000..b2fecbf6 --- /dev/null +++ b/check/checkfunctions/testdata/libraries/VersionFormatInvalid/library.properties @@ -0,0 +1,9 @@ +name=VersionFormatInvalid +version=foo +author=Cristian Maglie , Pippo Pluto +maintainer=Cristian Maglie +sentence=A library that makes coding a web server a breeze. +paragraph=Supports HTTP1.1 and you can do GET and POST. +category=Communication +url=http://example.com/ +architectures=avr diff --git a/check/checkfunctions/testdata/libraries/VersionFormatInvalid/src/VersionFormatInvalid.h b/check/checkfunctions/testdata/libraries/VersionFormatInvalid/src/VersionFormatInvalid.h new file mode 100644 index 00000000..e69de29b diff --git a/go.mod b/go.mod index 57e7d49f..03596073 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/arduino/go-paths-helper v1.3.2 github.com/arduino/go-properties-orderedmap v1.4.0 github.com/client9/misspell v0.3.4 + github.com/go-git/go-git/v5 v5.2.0 github.com/ory/jsonschema/v3 v3.0.1 github.com/sirupsen/logrus v1.6.0 github.com/spf13/cobra v1.0.1-0.20200710201246-675ae5f5a98c @@ -14,4 +15,5 @@ require ( github.com/stretchr/testify v1.6.1 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 github.com/xeipuuv/gojsonschema v1.2.0 + go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18 ) diff --git a/go.sum b/go.sum index ce7dbbcf..df851873 100644 --- a/go.sum +++ b/go.sum @@ -20,9 +20,11 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/arduino/arduino-cli v0.0.0-20201124150942-8d026eddbfb4 h1:JwDx5LSWigpw6GZK+1iYSrkh3PDsAeZZ0fDWaUehKD8= github.com/arduino/arduino-cli v0.0.0-20201124150942-8d026eddbfb4/go.mod h1:PpHwX4OKp/PFumezvkSRixh5N9uLiCASm3gqK/Da5is= @@ -40,6 +42,7 @@ github.com/arduino/go-timeutils v0.0.0-20171220113728-d1dd9e313b1b/go.mod h1:uwG github.com/arduino/go-win32-utils v0.0.0-20180330194947-ed041402e83b h1:3PjgYG5gVPA7cipp7vIR2lF96KkEJIFBJ+ANnuv6J20= github.com/arduino/go-win32-utils v0.0.0-20180330194947-ed041402e83b/go.mod h1:iIPnclBMYm1g32Q5kXoqng4jLhMStReIP7ZxaoUC2y8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.23.19/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -110,12 +113,22 @@ github.com/fluxio/iohelpers v0.0.0-20160419043813-3a4dd67a94d2 h1:C6sOwknxwWfLBE github.com/fluxio/iohelpers v0.0.0-20160419043813-3a4dd67a94d2/go.mod h1:c7sGIpDbBo0JZZ1tKyC1p5smWf8QcUjK4bFtZjHAecg= github.com/fluxio/multierror v0.0.0-20160419044231-9c68d39025e5 h1:R8jFW6G/bjoXjWPFrEfw9G5YQDlYhwV4AC+Eonu6wmk= github.com/fluxio/multierror v0.0.0-20160419044231-9c68d39025e5/go.mod h1:BEUDl7FG1cc76sM0J0x8dqr6RhiL4uqvk6oFkwuNyuM= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM= +github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M= +github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= +github.com/go-git/go-git/v5 v5.2.0 h1:YPBLG/3UK1we1ohRkncLjaXWLW+HKp5QNM/jTli2JgI= +github.com/go-git/go-git/v5 v5.2.0/go.mod h1:kh02eMX+wdqqxgNMEyq8YgwlIOsDOa9homkUq1PoTMs= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -355,6 +368,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= +github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imjasonmiller/godice v0.1.2 h1:T1/sW/HoDzFeuwzOOuQjmeMELz9CzZ53I2CnD+08zD4= github.com/imjasonmiller/godice v0.1.2/go.mod h1:8cTkdnVI+NglU2d6sv+ilYcNaJ5VSTBwvMbFULJd/QQ= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= @@ -685,6 +700,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 h1:DOmugCavvUtnUD114C1Wh+UgTgQZ4pMLzXxi1pSt+/Y= golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -727,6 +743,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -773,6 +790,7 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200121082415-34d275377bf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLNP8UFfcKjblhVCWftOM= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -884,6 +902,7 @@ gopkg.in/square/go-jose.v2 v2.1.9/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76 gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= +gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg= gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=