Skip to content

Commit e48c2be

Browse files
authored
Merge pull request #92 from arduino/per1234/add-checks
Add checks
2 parents f22ed88 + 0ebcb78 commit e48c2be

File tree

40 files changed

+762
-8
lines changed

40 files changed

+762
-8
lines changed

Diff for: .prettierignore

+1
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
/check/checkdata/schema/testdata/invalid-schema.json
99
/check/checkdata/testdata/packageindexes/invalid-JSON/package_foo_index.json
1010
/check/checkfunctions/testdata/packageindexes/invalid-JSON/package_foo_index.json
11+
/check/checkfunctions/testdata/sketches/InvalidJSONMetadataFile/sketch.json

Diff for: check/checkconfigurations/checkconfigurations.go

+180
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,21 @@ var configurations = []Type{
371371
ErrorModes: []checkmode.Type{checkmode.Strict},
372372
CheckFunction: checkfunctions.LibraryPropertiesVersionFieldNonSemver,
373373
},
374+
{
375+
ProjectType: projecttype.Library,
376+
Category: "library.properties",
377+
Subcategory: "version field",
378+
ID: "",
379+
Brief: "tag mismatch",
380+
Description: "The Library Manager indexer will reject any tag that has a library.properties version equal to a previous tag in the index.",
381+
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.",
382+
DisableModes: []checkmode.Type{checkmode.Default},
383+
EnableModes: []checkmode.Type{checkmode.LibraryManagerIndexed},
384+
InfoModes: nil,
385+
WarningModes: []checkmode.Type{checkmode.Default},
386+
ErrorModes: []checkmode.Type{checkmode.Strict},
387+
CheckFunction: checkfunctions.LibraryPropertiesVersionFieldBehindTag,
388+
},
374389
{
375390
ProjectType: projecttype.Library,
376391
Category: "library.properties",
@@ -971,6 +986,21 @@ var configurations = []Type{
971986
ErrorModes: []checkmode.Type{checkmode.Strict},
972987
CheckFunction: checkfunctions.MissingReadme,
973988
},
989+
{
990+
ProjectType: projecttype.Library,
991+
Category: "structure",
992+
Subcategory: "",
993+
ID: "",
994+
Brief: "no license file",
995+
Description: "",
996+
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",
997+
DisableModes: nil,
998+
EnableModes: []checkmode.Type{checkmode.Default},
999+
InfoModes: nil,
1000+
WarningModes: []checkmode.Type{checkmode.Default},
1001+
ErrorModes: []checkmode.Type{checkmode.Strict},
1002+
CheckFunction: checkfunctions.MissingLicenseFile,
1003+
},
9741004
{
9751005
ProjectType: projecttype.Sketch,
9761006
Category: "structure",
@@ -1016,6 +1046,21 @@ var configurations = []Type{
10161046
ErrorModes: []checkmode.Type{checkmode.Default},
10171047
CheckFunction: checkfunctions.IncorrectLibrarySrcFolderNameCase,
10181048
},
1049+
{
1050+
ProjectType: projecttype.Library,
1051+
Category: "structure",
1052+
Subcategory: "",
1053+
ID: "",
1054+
Brief: "no examples",
1055+
Description: "",
1056+
MessageTemplate: "No example sketches found. Please provide examples. See: https://arduino.github.io/arduino-cli/latest/library-specification/#library-examples",
1057+
DisableModes: nil,
1058+
EnableModes: []checkmode.Type{checkmode.Default},
1059+
InfoModes: nil,
1060+
WarningModes: []checkmode.Type{checkmode.Default},
1061+
ErrorModes: nil,
1062+
CheckFunction: checkfunctions.MissingExamples,
1063+
},
10191064
{
10201065
ProjectType: projecttype.Library,
10211066
Category: "structure",
@@ -1091,6 +1136,21 @@ var configurations = []Type{
10911136
ErrorModes: []checkmode.Type{checkmode.Default},
10921137
CheckFunction: checkfunctions.RecursiveLibraryWithUtilityFolder,
10931138
},
1139+
{
1140+
ProjectType: projecttype.Library,
1141+
Category: "code",
1142+
Subcategory: "",
1143+
ID: "",
1144+
Brief: "incorrect Arduino.h case",
1145+
Description: "This causes compilation failure on filename case-sensitive OS (e.g., Linux).",
1146+
MessageTemplate: "Incorrect of Arduino.h filename case detected in #include directive: {{.}}",
1147+
DisableModes: nil,
1148+
EnableModes: []checkmode.Type{checkmode.Default},
1149+
InfoModes: nil,
1150+
WarningModes: []checkmode.Type{checkmode.Default},
1151+
ErrorModes: []checkmode.Type{checkmode.Strict},
1152+
CheckFunction: checkfunctions.IncorrectArduinoDotHFileNameCase,
1153+
},
10941154
{
10951155
ProjectType: projecttype.Sketch,
10961156
Category: "structure",
@@ -1151,6 +1211,81 @@ var configurations = []Type{
11511211
ErrorModes: []checkmode.Type{checkmode.Strict},
11521212
CheckFunction: checkfunctions.MissingReadme,
11531213
},
1214+
{
1215+
ProjectType: projecttype.Sketch,
1216+
Category: "structure",
1217+
Subcategory: "",
1218+
ID: "",
1219+
Brief: "no license file",
1220+
Description: "",
1221+
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",
1222+
DisableModes: nil,
1223+
EnableModes: []checkmode.Type{checkmode.Default},
1224+
InfoModes: nil,
1225+
WarningModes: []checkmode.Type{checkmode.Default},
1226+
ErrorModes: []checkmode.Type{checkmode.Strict},
1227+
CheckFunction: checkfunctions.MissingLicenseFile,
1228+
},
1229+
{
1230+
ProjectType: projecttype.Sketch,
1231+
Category: "metadata",
1232+
Subcategory: "sketch.json",
1233+
ID: "",
1234+
Brief: "invalid sketch.json JSON format",
1235+
Description: "",
1236+
MessageTemplate: "sketch.json is not a valid JSON document. See: https://arduino.github.io/arduino-cli/latest/sketch-specification/#metadata",
1237+
DisableModes: nil,
1238+
EnableModes: []checkmode.Type{checkmode.Default},
1239+
InfoModes: nil,
1240+
WarningModes: []checkmode.Type{checkmode.Permissive},
1241+
ErrorModes: []checkmode.Type{checkmode.Default},
1242+
CheckFunction: checkfunctions.SketchDotJSONJSONFormat,
1243+
},
1244+
{
1245+
ProjectType: projecttype.Sketch,
1246+
Category: "metadata",
1247+
Subcategory: "sketch.json",
1248+
ID: "",
1249+
Brief: "invalid sketch.json data format",
1250+
Description: "",
1251+
MessageTemplate: "sketch.json has an invalid data format: {{.}}. See: https://arduino.github.io/arduino-cli/latest/sketch-specification/#metadata",
1252+
DisableModes: nil,
1253+
EnableModes: []checkmode.Type{checkmode.Default},
1254+
InfoModes: nil,
1255+
WarningModes: []checkmode.Type{checkmode.Permissive},
1256+
ErrorModes: []checkmode.Type{checkmode.Default},
1257+
CheckFunction: checkfunctions.SketchDotJSONFormat,
1258+
},
1259+
{
1260+
ProjectType: projecttype.Sketch,
1261+
Category: "structure",
1262+
Subcategory: "",
1263+
ID: "",
1264+
Brief: "name mismatch",
1265+
Description: "",
1266+
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",
1267+
DisableModes: nil,
1268+
EnableModes: []checkmode.Type{checkmode.Default},
1269+
InfoModes: nil,
1270+
WarningModes: []checkmode.Type{checkmode.Permissive},
1271+
ErrorModes: []checkmode.Type{checkmode.Default},
1272+
CheckFunction: checkfunctions.SketchNameMismatch,
1273+
},
1274+
{
1275+
ProjectType: projecttype.Sketch,
1276+
Category: "code",
1277+
Subcategory: "",
1278+
ID: "",
1279+
Brief: "incorrect Arduino.h case",
1280+
Description: "This causes compilation failure on filename case-sensitive OS (e.g., Linux).",
1281+
MessageTemplate: "Incorrect of Arduino.h filename case detected in #include directive: {{.}}",
1282+
DisableModes: nil,
1283+
EnableModes: []checkmode.Type{checkmode.Default},
1284+
InfoModes: nil,
1285+
WarningModes: []checkmode.Type{checkmode.Default},
1286+
ErrorModes: []checkmode.Type{checkmode.Strict},
1287+
CheckFunction: checkfunctions.IncorrectArduinoDotHFileNameCase,
1288+
},
11541289
{
11551290
ProjectType: projecttype.Platform,
11561291
Category: "configuration files",
@@ -1181,6 +1316,51 @@ var configurations = []Type{
11811316
ErrorModes: []checkmode.Type{checkmode.Default},
11821317
CheckFunction: checkfunctions.BoardsTxtFormat,
11831318
},
1319+
{
1320+
ProjectType: projecttype.Platform,
1321+
Category: "structure",
1322+
Subcategory: "",
1323+
ID: "",
1324+
Brief: "no readme",
1325+
Description: "",
1326+
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",
1327+
DisableModes: nil,
1328+
EnableModes: []checkmode.Type{checkmode.Default},
1329+
InfoModes: nil,
1330+
WarningModes: []checkmode.Type{checkmode.Default},
1331+
ErrorModes: []checkmode.Type{checkmode.Strict},
1332+
CheckFunction: checkfunctions.MissingReadme,
1333+
},
1334+
{
1335+
ProjectType: projecttype.Platform,
1336+
Category: "structure",
1337+
Subcategory: "",
1338+
ID: "",
1339+
Brief: "no license file",
1340+
Description: "",
1341+
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",
1342+
DisableModes: nil,
1343+
EnableModes: []checkmode.Type{checkmode.Default},
1344+
InfoModes: nil,
1345+
WarningModes: []checkmode.Type{checkmode.Default},
1346+
ErrorModes: []checkmode.Type{checkmode.Strict},
1347+
CheckFunction: checkfunctions.MissingLicenseFile,
1348+
},
1349+
{
1350+
ProjectType: projecttype.Platform,
1351+
Category: "code",
1352+
Subcategory: "",
1353+
ID: "",
1354+
Brief: "incorrect Arduino.h case",
1355+
Description: "This causes compilation failure on filename case-sensitive OS (e.g., Linux).",
1356+
MessageTemplate: "Incorrect of Arduino.h filename case detected in #include directive: {{.}}",
1357+
DisableModes: nil,
1358+
EnableModes: []checkmode.Type{checkmode.Default},
1359+
InfoModes: nil,
1360+
WarningModes: []checkmode.Type{checkmode.Default},
1361+
ErrorModes: []checkmode.Type{checkmode.Strict},
1362+
CheckFunction: checkfunctions.IncorrectArduinoDotHFileNameCase,
1363+
},
11841364
{
11851365
ProjectType: projecttype.PackageIndex,
11861366
Category: "data",

Diff for: check/checkdata/checkdata.go

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func Initialize(project project.Type, schemasPath *paths.Path) {
3333
projectPath = project.Path
3434
switch project.ProjectType {
3535
case projecttype.Sketch:
36+
InitializeForSketch(project)
3637
case projecttype.Library:
3738
InitializeForLibrary(project, schemasPath)
3839
case projecttype.Platform:

Diff for: check/checkdata/sketch.go

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// This file is part of arduino-check.
2+
//
3+
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-check.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package checkdata
17+
18+
import (
19+
"github.com/arduino/arduino-check/project"
20+
"github.com/arduino/arduino-cli/arduino/sketches"
21+
)
22+
23+
// InitializeForSketch gathers the check data for the specified sketch project.
24+
func InitializeForSketch(project project.Type) {
25+
loadedSketch, sketchLoadError = sketches.NewSketchFromPath(ProjectPath())
26+
27+
metadataSketchObject := &sketches.Sketch{
28+
Name: ProjectPath().Base(),
29+
FullPath: ProjectPath(),
30+
}
31+
metadataLoadError = metadataSketchObject.ImportMetadata()
32+
}
33+
34+
var sketchLoadError error
35+
36+
// SketchLoadError returns the error output from Arduino CLI loading the sketch.
37+
func SketchLoadError() error {
38+
return sketchLoadError
39+
}
40+
41+
var loadedSketch *sketches.Sketch
42+
43+
// Sketch returns the sketch object generated by Arduino CLI.
44+
func Sketch() *sketches.Sketch {
45+
return loadedSketch
46+
}
47+
48+
var metadataLoadError error
49+
50+
// MetadataLoadError returns the error produced during load of the sketch metadata.
51+
func MetadataLoadError() error {
52+
return metadataLoadError
53+
}
54+
55+
var metadataSketchObject *sketches.Sketch
56+
57+
// Metadata returns the metadata object produced by Arduino CLI.
58+
func Metadata() *sketches.Metadata {
59+
return metadataSketchObject.Metadata
60+
}

Diff for: check/checkfunctions/checkfunctions.go

+58-6
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ package checkfunctions
1818

1919
import (
2020
"encoding/json"
21+
"fmt"
2122
"regexp"
2223
"strings"
2324

2425
"github.com/arduino/arduino-check/check/checkdata"
2526
"github.com/arduino/arduino-check/check/checkresult"
27+
"github.com/arduino/arduino-check/project/sketch"
2628
"github.com/arduino/go-paths-helper"
2729
)
2830

@@ -77,25 +79,75 @@ func MissingReadme() (result checkresult.Type, output string) {
7779
readmeRegexp := regexp.MustCompile(`(?i)^readme\.(markdown)|(mdown)|(mkdn)|(md)|(textile)|(rdoc)|(org)|(creole)|(mediawiki)|(wiki)|(rst)|(asciidoc)|(adoc)|(asc)|(pod)|(txt)$`)
7880

7981
// https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/about-readmes#about-readmes
80-
if pathContainsReadme(checkdata.ProjectPath(), readmeRegexp) ||
81-
(checkdata.ProjectPath().Join("docs").Exist() && pathContainsReadme(checkdata.ProjectPath().Join("docs"), readmeRegexp)) ||
82-
(checkdata.ProjectPath().Join(".github").Exist() && pathContainsReadme(checkdata.ProjectPath().Join(".github"), readmeRegexp)) {
82+
if pathContainsRegexpMatch(checkdata.ProjectPath(), readmeRegexp) ||
83+
(checkdata.ProjectPath().Join("docs").Exist() && pathContainsRegexpMatch(checkdata.ProjectPath().Join("docs"), readmeRegexp)) ||
84+
(checkdata.ProjectPath().Join(".github").Exist() && pathContainsRegexpMatch(checkdata.ProjectPath().Join(".github"), readmeRegexp)) {
8385
return checkresult.Pass, ""
8486
}
8587

8688
return checkresult.Fail, ""
8789
}
8890

89-
// pathContainsReadme checks if the provided path contains a readme file recognized by GitHub.
90-
func pathContainsReadme(path *paths.Path, readmeRegexp *regexp.Regexp) bool {
91+
// MissingLicenseFile checks if the project has a license file that will be recognized by GitHub.
92+
func MissingLicenseFile() (result checkresult.Type, output string) {
93+
if checkdata.ProjectType() != checkdata.SuperProjectType() {
94+
return checkresult.NotRun, "License file not required for subprojects"
95+
}
96+
97+
// https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository#detecting-a-license
98+
// https://github.com/licensee/licensee/blob/master/docs/what-we-look-at.md#detecting-the-license-file
99+
// 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".
100+
// github.com/dlclark/regexp2 does support negative lookahead, but I'd prefer to stick with the standard package.
101+
licenseRegexp := regexp.MustCompile(`(?i)^(((un)?licen[sc]e)|(copy(ing|right))|(ofl)|(patents))(\.((md)|(markdown)|(txt)|(html)))?$`)
102+
103+
// License file must be in root of repo
104+
if pathContainsRegexpMatch(checkdata.ProjectPath(), licenseRegexp) {
105+
return checkresult.Pass, ""
106+
}
107+
108+
return checkresult.Fail, ""
109+
}
110+
111+
// IncorrectArduinoDotHFileNameCase checks for incorrect file name case of Arduino.h in #include directives.
112+
func IncorrectArduinoDotHFileNameCase() (result checkresult.Type, output string) {
113+
incorrectCaseRegexp := regexp.MustCompile(`^\s*#\s*include\s*["<](a((?i)rduino)|(ARDUINO))\.[hH][">]`)
114+
115+
directoryListing, err := checkdata.ProjectPath().ReadDirRecursive()
116+
if err != nil {
117+
panic(err)
118+
}
119+
directoryListing.FilterOutDirs()
120+
121+
for _, file := range directoryListing {
122+
if !sketch.HasSupportedExtension(file) { // Won't catch all possible files, but good enough.
123+
continue
124+
}
125+
126+
lines, err := file.ReadFileAsLines()
127+
if err != nil {
128+
panic(err)
129+
}
130+
131+
for lineNumber, line := range lines {
132+
if incorrectCaseRegexp.MatchString(line) {
133+
return checkresult.Fail, fmt.Sprintf("%s:%v: %s", file, lineNumber+1, line)
134+
}
135+
}
136+
}
137+
138+
return checkresult.Pass, ""
139+
}
140+
141+
// pathContainsRegexpMatch checks if the provided path contains a file name matching the given regular expression.
142+
func pathContainsRegexpMatch(path *paths.Path, pathRegexp *regexp.Regexp) bool {
91143
listing, err := path.ReadDir()
92144
if err != nil {
93145
panic(err)
94146
}
95147
listing.FilterOutDirs()
96148

97149
for _, file := range listing {
98-
if readmeRegexp.MatchString(file.Base()) {
150+
if pathRegexp.MatchString(file.Base()) {
99151
return true
100152
}
101153
}

0 commit comments

Comments
 (0)