From e0b342138575cd682ffabdc6807dcec465732f9c Mon Sep 17 00:00:00 2001 From: jaimergp Date: Fri, 22 Mar 2024 10:50:04 +0100 Subject: [PATCH 1/4] adjust linter output formatting for friendlier markdown rendering --- conda_smithy/cli.py | 6 +++- conda_smithy/lint_recipe.py | 55 +++++++++++++++++++++++++++++-------- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/conda_smithy/cli.py b/conda_smithy/cli.py index 72fe1a641..2b3e076d9 100644 --- a/conda_smithy/cli.py +++ b/conda_smithy/cli.py @@ -599,9 +599,13 @@ def _call(self, args, temporary_directory): class RecipeLint(Subcommand): subcommand = "recipe-lint" + aliases = ["lint"] def __init__(self, parser): - super(RecipeLint, self).__init__(parser, "Lint a single conda recipe.") + super(RecipeLint, self).__init__( + parser, + "Lint a single conda recipe and its configuration.", + ) scp = self.subcommand_parser scp.add_argument("--conda-forge", action="store_true") scp.add_argument("recipe_directory", default=[os.getcwd()], nargs="*") diff --git a/conda_smithy/lint_recipe.py b/conda_smithy/lint_recipe.py index 6f91bd346..36a16603d 100644 --- a/conda_smithy/lint_recipe.py +++ b/conda_smithy/lint_recipe.py @@ -6,15 +6,18 @@ import copy import fnmatch -from glob import glob import io import itertools +import json import os import re import requests import shutil import subprocess import sys +from glob import glob +from inspect import cleandoc +from textwrap import indent import github @@ -1065,6 +1068,22 @@ def jinja_lines(lines): yield line, i +def _format_validation_msg(error: "jsonschema.ValidationError"): + return cleandoc( + f""" + In conda-forge.yml: `{error.json_path} = {error.instance}`. +{indent(error.message, " " * 12 + "> ")} +
+ Schema + + ```json +{indent(json.dumps(error.schema, indent=2), " " * 12)} + ``` + +
+ """ + ) + def main(recipe_dir, conda_forge=False, return_hints=False): recipe_dir = os.path.abspath(recipe_dir) recipe_meta = os.path.join(recipe_dir, "meta.yaml") @@ -1080,19 +1099,31 @@ def main(recipe_dir, conda_forge=False, return_hints=False): recipe_dir=recipe_dir ) - validation_errors = [str(err) for err in validation_errors] - validation_errors = [ - ( - err.split("\n")[0] - if err.startswith("Additional properties are not allowed") - else err - ) - for err in validation_errors - ] - results.extend(validation_errors) - hints.extend([str(lint) for lint in validation_hints]) + results.extend([_format_validation_msg(err) for err in validation_errors]) + hints.extend([_format_validation_msg(hint) for hint in validation_hints]) if return_hints: return results, hints else: return results + + +if __name__ == "__main__": + # This block is supposed to help debug how the rendered version + # of the linter bot would look like in Github. Taken from + # https://github.com/conda-forge/conda-forge-webservices/blob/747f75659/conda_forge_webservices/linting.py#L138C1-L146C72 + rel_path = sys.argv[1] + lints, hints = main(rel_path, False, True) + messages = [] + if lints: + print(lints, file=sys.stderr) + all_pass = False + messages.append("\nFor **{}**:\n\n{}".format( + rel_path, + '\n'.join('* {}'.format(lint) for lint in lints))) + if hints: + messages.append("\nFor **{}**:\n\n{}".format( + rel_path, + '\n'.join('* {}'.format(hint) for hint in hints))) + + print(*messages, sep="\n") From 4ac334dc77b5449df83555ae09e41dea88266d01 Mon Sep 17 00:00:00 2001 From: jaimergp Date: Fri, 22 Mar 2024 11:11:05 +0100 Subject: [PATCH 2/4] link key to help page --- conda_smithy/lint_recipe.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/conda_smithy/lint_recipe.py b/conda_smithy/lint_recipe.py index 36a16603d..3d7f1c496 100644 --- a/conda_smithy/lint_recipe.py +++ b/conda_smithy/lint_recipe.py @@ -1069,15 +1069,22 @@ def jinja_lines(lines): def _format_validation_msg(error: "jsonschema.ValidationError"): + if error.schema: + descriptionless_schema = {k:v for (k, v) in error.schema.items() if k != "description"} + else: + descriptionless_schema = {} + # We can get the help url from the first level on the JSON path ($.top_level_key.2nd_level_key) + top_level_key = error.json_path.split(".")[1].split("[")[0].replace("_", "-") + help_url = f"https://conda-forge.org/docs/maintainer/conda_forge_yml/#{top_level_key}" return cleandoc( f""" - In conda-forge.yml: `{error.json_path} = {error.instance}`. + In conda-forge.yml: [`{error.json_path}`]({help_url}) `=` `{error.instance}`. {indent(error.message, " " * 12 + "> ")}
Schema ```json -{indent(json.dumps(error.schema, indent=2), " " * 12)} +{indent(json.dumps(descriptionless_schema, indent=2), " " * 12)} ```
@@ -1116,7 +1123,6 @@ def main(recipe_dir, conda_forge=False, return_hints=False): lints, hints = main(rel_path, False, True) messages = [] if lints: - print(lints, file=sys.stderr) all_pass = False messages.append("\nFor **{}**:\n\n{}".format( rel_path, From bba465dadbdedc930fe6c68284d16eedc2247d24 Mon Sep 17 00:00:00 2001 From: jaimergp Date: Fri, 22 Mar 2024 11:16:57 +0100 Subject: [PATCH 3/4] add news --- news/1886-prettier-lints.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/1886-prettier-lints.rst diff --git a/news/1886-prettier-lints.rst b/news/1886-prettier-lints.rst new file mode 100644 index 000000000..03f2cd332 --- /dev/null +++ b/news/1886-prettier-lints.rst @@ -0,0 +1,23 @@ +**Added:** + +* + +**Changed:** + +* Adjust how the linter processes ``conda-forge.yml`` validation issues for prettier Markdown rendering. (#1860 via #1886) + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From b137ebeaf06fad9d6ea0f951eee5d0a46d74b84b Mon Sep 17 00:00:00 2001 From: jaimergp Date: Fri, 22 Mar 2024 11:17:29 +0100 Subject: [PATCH 4/4] pre-commit --- conda_smithy/lint_recipe.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/conda_smithy/lint_recipe.py b/conda_smithy/lint_recipe.py index 3d7f1c496..45802be07 100644 --- a/conda_smithy/lint_recipe.py +++ b/conda_smithy/lint_recipe.py @@ -1070,11 +1070,15 @@ def jinja_lines(lines): def _format_validation_msg(error: "jsonschema.ValidationError"): if error.schema: - descriptionless_schema = {k:v for (k, v) in error.schema.items() if k != "description"} + descriptionless_schema = { + k: v for (k, v) in error.schema.items() if k != "description" + } else: descriptionless_schema = {} # We can get the help url from the first level on the JSON path ($.top_level_key.2nd_level_key) - top_level_key = error.json_path.split(".")[1].split("[")[0].replace("_", "-") + top_level_key = ( + error.json_path.split(".")[1].split("[")[0].replace("_", "-") + ) help_url = f"https://conda-forge.org/docs/maintainer/conda_forge_yml/#{top_level_key}" return cleandoc( f""" @@ -1091,6 +1095,7 @@ def _format_validation_msg(error: "jsonschema.ValidationError"): """ ) + def main(recipe_dir, conda_forge=False, return_hints=False): recipe_dir = os.path.abspath(recipe_dir) recipe_meta = os.path.join(recipe_dir, "meta.yaml") @@ -1124,12 +1129,16 @@ def main(recipe_dir, conda_forge=False, return_hints=False): messages = [] if lints: all_pass = False - messages.append("\nFor **{}**:\n\n{}".format( - rel_path, - '\n'.join('* {}'.format(lint) for lint in lints))) + messages.append( + "\nFor **{}**:\n\n{}".format( + rel_path, "\n".join("* {}".format(lint) for lint in lints) + ) + ) if hints: - messages.append("\nFor **{}**:\n\n{}".format( - rel_path, - '\n'.join('* {}'.format(hint) for hint in hints))) + messages.append( + "\nFor **{}**:\n\n{}".format( + rel_path, "\n".join("* {}".format(hint) for hint in hints) + ) + ) print(*messages, sep="\n")