From 442f58d45001c0a123773c09c1104ebb96a3f801 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Mon, 15 Mar 2021 12:00:40 +0100 Subject: [PATCH 1/3] lint(practice_exercises): check required files exist Each practice exercise's directory should contain at least the following two files: - .docs/instructions.md - .meta/config.json --- src/lint/lint.nim | 12 +++++++----- src/lint/practice_exercises.nim | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 src/lint/practice_exercises.nim diff --git a/src/lint/lint.nim b/src/lint/lint.nim index 75f8bb95..b21565ba 100644 --- a/src/lint/lint.nim +++ b/src/lint/lint.nim @@ -1,5 +1,5 @@ import ".."/cli -import "."/[concept_exercises, concepts, track_config] +import "."/[concept_exercises, concepts, practice_exercises, track_config] proc lint*(conf: Conf) = echo "The lint command is under development.\n" & @@ -9,16 +9,18 @@ proc lint*(conf: Conf) = let trackDir = conf.trackDir let b1 = isTrackConfigValid(trackDir) let b2 = conceptExerciseFilesExist(trackDir) - let b3 = conceptFilesExist(trackDir) - let b4 = isEveryConceptExerciseConfigValid(trackDir) + let b3 = practiceExerciseFilesExist(trackDir) + let b4 = conceptFilesExist(trackDir) + let b5 = isEveryConceptExerciseConfigValid(trackDir) - if b1 and b2 and b3 and b4: + if b1 and b2 and b3 and b4 and b5: echo """ Basic linting finished successfully: - config.json exists and is valid JSON - config.json has these valid fields: language, slug, active, blurb, version, tags - Every concept has the required .md files and links.json file - Every concept exercise has the required .md files and a .meta/config.json file -- Every concept exercise .meta/config.json file is valid""" +- Every concept exercise .meta/config.json file is valid +- Every practice exercise has the required .md files and a .meta/config.json file""" else: quit(1) diff --git a/src/lint/practice_exercises.nim b/src/lint/practice_exercises.nim new file mode 100644 index 00000000..b91af24c --- /dev/null +++ b/src/lint/practice_exercises.nim @@ -0,0 +1,14 @@ +import std/os +import "."/validators + +proc practiceExerciseFilesExist*(trackDir: string): bool = + ## Returns true if every subdirectory in `trackDir/exercises/practice` has the + ## required files. + const + requiredPracticeExerciseFiles = [ + ".docs" / "instructions.md", + ".meta" / "config.json", + ] + + let practiceExercisesDir = trackDir / "exercises" / "practice" + result = subdirsContain(practiceExercisesDir, requiredPracticeExerciseFiles) From 94f8f0f7ad27a2e2946550fa2bf4048927397ee9 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Mon, 15 Mar 2021 12:08:38 +0100 Subject: [PATCH 2/3] lint(practice_exercises): check .meta/config.json files Co-authored-by: ee7 <45465154+ee7@users.noreply.github.com> --- src/lint/lint.nim | 6 ++-- src/lint/practice_exercises.nim | 54 ++++++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/lint/lint.nim b/src/lint/lint.nim index b21565ba..68166e7a 100644 --- a/src/lint/lint.nim +++ b/src/lint/lint.nim @@ -12,8 +12,9 @@ proc lint*(conf: Conf) = let b3 = practiceExerciseFilesExist(trackDir) let b4 = conceptFilesExist(trackDir) let b5 = isEveryConceptExerciseConfigValid(trackDir) + let b6 = isEveryPracticeExerciseConfigValid(trackDir) - if b1 and b2 and b3 and b4 and b5: + if b1 and b2 and b3 and b4 and b5 and b6: echo """ Basic linting finished successfully: - config.json exists and is valid JSON @@ -21,6 +22,7 @@ Basic linting finished successfully: - Every concept has the required .md files and links.json file - Every concept exercise has the required .md files and a .meta/config.json file - Every concept exercise .meta/config.json file is valid -- Every practice exercise has the required .md files and a .meta/config.json file""" +- Every practice exercise has the required .md files and a .meta/config.json file +- Every practice exercise .meta/config.json file is valid""" else: quit(1) diff --git a/src/lint/practice_exercises.nim b/src/lint/practice_exercises.nim index b91af24c..87ee5681 100644 --- a/src/lint/practice_exercises.nim +++ b/src/lint/practice_exercises.nim @@ -1,6 +1,58 @@ -import std/os +import std/[json, os] +import ".."/helpers import "."/validators +proc isValidAuthorOrContributor(data: JsonNode, context: string, path: string): bool = + if isObject(data, context, path): + result = true + if not checkString(data, "github_username", path): + result = false + if not checkString(data, "exercism_username", path, isRequired = false): + result = false + +proc checkFiles(data: JsonNode, context, path: string): bool = + result = true + if hasObject(data, context, path): + if not checkArrayOfStrings(data, context, "solution", path): + result = false + if not checkArrayOfStrings(data, context, "test", path): + result = false + if not checkArrayOfStrings(data, context, "example", path): + result = false + else: + result = false + +proc isValidPracticeExerciseConfig(data: JsonNode, path: string): bool = + if isObject(data, "root", path): + result = true + if not checkArrayOf(data, "authors", path, isValidAuthorOrContributor): + result = false + if not checkArrayOf(data, "contributors", path, isValidAuthorOrContributor, + isRequired = false): + result = false + if not checkFiles(data, "files", path): + result = false + if not checkString(data, "language_versions", path, isRequired = false): + result = false + +proc isEveryPracticeExerciseConfigValid*(trackDir: string): bool = + let practiceExercisesDir = trackDir / "exercises" / "practice" + result = true + # Return true even if the directory does not exist - this allows a future + # track to have concept exercises and no practice exercises. + if dirExists(practiceExercisesDir): + for exerciseDir in getSortedSubdirs(practiceExercisesDir): + let configPath = exerciseDir / ".meta" / "config.json" + if fileExists(configPath): + let j = + try: + parseFile(configPath) + except: + result.setFalseAndPrint("JSON parsing error", getCurrentExceptionMsg()) + continue + if not isValidPracticeExerciseConfig(j, configPath): + result = false + proc practiceExerciseFilesExist*(trackDir: string): bool = ## Returns true if every subdirectory in `trackDir/exercises/practice` has the ## required files. From 699710a9c6c3eb31800938ce33ff1f0ea3d70bc9 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 17 Mar 2021 12:53:30 +0100 Subject: [PATCH 3/3] lint(practice_exercises): disable authors and files checks To prevent `configlet lint` from producing a lot of output for nearly every track, we temporarily disable two checks. With this commit, `configlet lint` will not check: - The `files` property in the .meta/config.json file of each practice exercise. - The `authors` property in the .meta/config.json file of each practice exercise. --- src/lint/practice_exercises.nim | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/lint/practice_exercises.nim b/src/lint/practice_exercises.nim index 87ee5681..16a53e0c 100644 --- a/src/lint/practice_exercises.nim +++ b/src/lint/practice_exercises.nim @@ -25,13 +25,17 @@ proc checkFiles(data: JsonNode, context, path: string): bool = proc isValidPracticeExerciseConfig(data: JsonNode, path: string): bool = if isObject(data, "root", path): result = true - if not checkArrayOf(data, "authors", path, isValidAuthorOrContributor): - result = false + # Temporarily disable the checking of authors as we'll be doing bulk PRs + # to pre-populate this field for all tracks + # if not checkArrayOf(data, "authors", path, isValidAuthorOrContributor): + # result = false if not checkArrayOf(data, "contributors", path, isValidAuthorOrContributor, isRequired = false): result = false - if not checkFiles(data, "files", path): - result = false + # Temporarily disable the checking of the files to give tracks the chance + # to update this manually + # if not checkFiles(data, "files", path): + # result = false if not checkString(data, "language_versions", path, isRequired = false): result = false