Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible to surface the reason/comment for rule suppression? #216

Open
blakeNaccarato opened this issue May 4, 2024 · 6 comments
Open

Comments

@blakeNaccarato
Copy link

The hosted version of repo-review is really cool!

Idea

I don't know whether this feature request is most appropriate for repo-review core or just the web plug-in itself, but I thought it would be nice to render rules that have been suppressed/skipped with a reason/message given by the maintainers.

For instance, if I use pyright for type-checking and Renovate for dependency management, I might suppress the mypy and Dependabot rules. But maybe I provide a reason for it in the tool config, and that gets rendered in the hosted web app checklist as a grayed out checkbox, like..

➖ (suppressed) mypy This package uses pyright for type-checking instead

Rationale

I imagine it would be difficult to add checks for every conceivable combination of tools and best practices, so an "escape-hatch" that allows for self-documenting config about why certain rules are suppressed could be a nice middle-ground.

Caveats

But I also understand how that complicates the configuration story, from a simple list of suppressed strings to some messy combination of strings and string-string (rule-rationale) mappings. And the alternative of picking up reasons by parsing the TOML in a comments-aware way is probably not fun, either.

Breaking changes

It would be possible to implement this without breaking existing configs, but would make configs more complex and maintaining two ways of specifying rules could get ugly.

Alternative/workaround

I haven't tried this, but presumably a repo config suppressing certain rules simply won't render those rules in the web hosted report, which could make a repo look all green just by only selecting the set of passing checks. But instead of individual rationale, a single config item like message could give maintainers a place to detail their specific repo health decisions that would render at the top of repo-review reports, including in the hosted version.


Thanks for this! It's great that you not only signal potential repo issues, but also document the way to solve them. Infrastructure is such a big part of friction in projects, and also the hardest to justify spending time on, so having concise guidance is helpful.

@henryiii
Copy link
Collaborator

henryiii commented May 5, 2024

The hosted version of repo-review is really cool!

The CLI version isn't? 😛

Config

The config for this should be pretty simple, I think: you could take the current syntax:

[tool.repo-review]
ignore = ["PC110"]

and use this instead:

[tool.repo-review.ignore]
PC110 = ""

Due to the way dict iteration works in Python, this is backward compatible with the current versions of repo-review. Empty strings would be un-annotated, which is the old behavior.

PS: We need to remove this ignore from this repo. The check works now. :)

One worry here is how to mark each check. I would expect that this:

[tool.repo-review.ignore]
MY = "This package uses pyright for type-checking instead"

maybe should produce one line about MyPy checks being ignored, but it matches multiple checks, each with their own URLs, etc. Also if several ignores match, I guess we should just clearly document the behavior, like last one matches (or first, etc).

API

We can make arbitrary changes to the API if we need to, we use ~= in the WebApp. It's close to not needing an change, since this doesn't require computing the checks, but it does require computing the fixtures, and the current API does everything in one function (process). We could add an extra output to the named tuple return; it's slightly breaking (if you unpack the named tuple). We could instead have a keyword argument that adds ignored checks to the resulting list (those would be sorted already, too, as a bonus). That might be the best way.

We could just read and output the ignore lines without matching them up to checks, say at the top or the bottom. That would be the easiest, as it would not require any API changes (in fact, you could get it entirely from the pyproject.toml in the WebApp without any repo-review helpers, though we should add those if we go that way).

Web version

The example provided here is exactly what sp-repo-review uses, so this is the right place to update it. We'll just copy it over after a release.

CLI version

I think we could add this to the output just like the web version. Some care might be needed to make sure the JSON output isn't a breaking change.


Would the "simple" way work? Here's AstroPy's current config:

[tool.repo-review]
ignore = [
    "MY",    # ignore MyPy setting checks
    "PC111", # ignore using `blacken-docs` in pre-commit
    "PC140", # ignore using `mypy` in pre-commit
    "PC180", # ignore using `prettier` in pre-commit
    "PC901", # ignore using custom update message (we have many of the default ones in our history already)
    "PP308", # ignore requiring `-ra` flag for pytest, astropy's test suite is too large for this to be useful
]

Imagining something like this:

[tool.repo-review.ignore]
MY = "ignore MyPy setting checks"
PC111 = "ignore using `blacken-docs` in pre-commit"
PC140 = "ignore using `mypy` in pre-commit"
PC180 = "ignore using `prettier` in pre-commit"
PC901 = "ignore using custom update message (we have many of the default ones in our history already)"
PP308 = "ignore requiring `-ra` flag for pytest, astropy's test suite is too large for this to be useful"

The "simple" version would just put something like this on the beginning or end:

Ignored checks:

MY: ignore MyPy setting checks
PC111: ignore using blacken-docs in pre-commit
PC140: ignore using mypy in pre-commit
PC180: ignore using prettier in pre-commit
PC901: ignore using custom update message (we have many of the default ones in our history already)
PP308: ignore requiring -ra flag for pytest, astropy's test suite is too large for this to be useful

Is that enough? Or would having the URLs, expanded checks (with repeated reasons), original reasons, etc. be useful?

@blakeNaccarato
Copy link
Author

blakeNaccarato commented May 7, 2024

The CLI version isn't? 😛

Haha, well I guess it speaks to the coolness of the hosted version. All from my phone and thus not having used the CLI yet, over the course of an hour I went from zero knowledge, to discovery via your Mastodon post, to running it against my copier-python template, to reading some of your config docs, and finally raising this discussion. That tight loop from discovery, to usage, to having an opinion (lol) is pretty cool!

Your description sounds about right, thanks for the detailed consideration! I like the non-breaking way of allowing a TOML table in place of an array due to the way that Python iterates mappings and sequences. One thing to consider is that allowing TOML tables would make it easier to accidentally give checks empty TOML tables like so:

Warning

[tool.repo-review.ignore.PC110]
[tool.repo-review.ignore]
PC110 = {}

Maybe you already handle these invalid configs in your parsing. If not, you'll want to either disallow that or silently handle it (or handle and warn) and consider it equivalent to an empty string. And yeah, representing check values in the resulting report may be non-trivial. The "simple" version you mention is totally reasonable. However, maybe it gets unwieldy for lots of ignores. Below the "details" fold I have rendered an example report for astropy (with GH21 also ignored as an illustrative example) of the "fully integrated" version, with the following rules:

  • Ignored checks without a reason (empty string) don't appear in the report
  • Fully-qualified ignored checks with non-empty strings in the pyproject.toml, like PC901, ARE printed in the report, but with a symbol (different from the "skipped" info status, e.g. a "➖", and a reason printed on that line
  • Partially-qualified ignored checks visually grouped with the "Reason" rendering just above them, like the GH21 group. Not strictly necessary, could just repeat the reason for each check to avoid computing a complex document tree
  • Suppressed categories like MY have an ignore reason given inside the category

But if any of these rules require significant refactor, it's totally fine to have either the "simple" version, or one with "reasons" repeated on each rule they apply to, for instance, rather than the more structured report shown below.

In any case, thanks for taking the time to write up your conception of it, and for detailing some of the internals involved!


[tool.repo-review.ignore]
GH21 = "some good reason for ignoring all the GH210s rules"
MY = "ignore MyPy setting checks"
PC111 = "ignore using `blacken-docs` in pre-commit"
PC140 = "ignore using `mypy` in pre-commit"
PC180 = "ignore using `prettier` in pre-commit"
PC901 = "ignore using custom update message (we have many of the default ones in our history already)"
PP308 = "ignore requiring `-ra` flag for pytest, astropy's test suite is too large for this to be useful"
Details

General

  • Detected build backend: setuptools.build_meta
  • Detected license(s): BSD License
  • PY001: Has a pyproject.toml
  • PY002: Has a README.(md|rst) file
  • PY003: Has a LICENSE* file
  • PY004: Has docs folder
  • PY005: Has tests folder
  • PY006: Has pre-commit config
  • PY007: Supports an easy task runner (nox or tox)

PyProject

  • PP002: Has a proper build-system table
  • PP003: Does not list wheel as a build-dep
  • PP301: Has pytest in pyproject
  • PP302: Sets a minimum pytest to at least 6
  • PP303: Sets the test paths
  • PP304: Sets the log level in pytest
  • PP305: Specifies xfail_strict
  • PP306: Specifies strict config
  • PP307: Specifies strict markers
  • [-] PP308: Specifies useful pytest summary. [ignored] Reason: ignore requiring -ra flag for pytest, astropy's test suite is too large for this to be useful
  • PP309: Filter warnings specified

GitHub Actions

  • GH100: Has GitHub Actions config
  • GH101: Has nice names
  • GH102: Auto-cancel on repeated PRs
  • GH103: At least one workflow with manual dispatch trigger
  • GH104: Use unique names for upload-artifact
  • GH200: Maintained by Dependabot

GH21* [ignored]: some good reason for ignoring all the GH210s rules

  • [-] GH210 [ignored]: Maintains the GitHub action versions with Dependabot
  • [-] GH211 [ignored]: Do not pin core actions as major versions
  • [-] GH212 [ignored]: Require GHA update grouping
  • GH220: Not a real rule, but you'd see it here if it was.

Pre-commit

  • PC100: Has pre-commit-hooks
  • PC110: Uses black or ruff-format
  • [-] PC111: Uses blacken-docs [ignored] Reason: ignore using blacken-docs in pre-commit
  • [-] PC140: Uses mypy [ignored] Reason: ignore using mypy in pre-commit
  • PC160: Uses codespell
  • PC170: Uses PyGrep hooks (only needed if RST present)
  • [-] PC180: Uses prettier [ignored] Reason: ignore using prettier in pre-commit
  • PC190: Uses Ruff
  • PC191: Ruff show fixes if fixes enabled
  • [-] PC901: Custom pre-commit CI message [ignored] Reason: Ignore using custom update message (we have many of the default ones in our history already)

MyPy [ignored]

  • Reason: ignore MyPy setting checks

Ruff

  • RF001: Has Ruff config
  • RF002: Target version must be set
  • [i] RF003: src directory specified if used [skipped]
  • RF101: Bugbear must be selected
  • RF102: isort must be selected
  • RF103: pyupgrade must be selected
  • RF201: Avoid using deprecated config settings
  • RF202: Use (new) lint config section

...

@henryiii
Copy link
Collaborator

henryiii commented May 7, 2024

Aside,

pipx run sp-repo-review[cli,validate-pyproject] --format html gh:astropy/astropy@main

produces output you can paste into GitHub:

Details:

General

  • Detected build backend: setuptools.build_meta
  • Detected license(s): BSD License
?NameDescription
PY001 Has a pyproject.toml
PY002 Has a README.(md|rst) file
PY003 Has a LICENSE* file
PY004 Has docs folder
PY005 Has tests folder
PY006 Has pre-commit config
PY007 Supports an easy task runner (nox or tox)

PyProject

?NameDescription
PP002 Has a proper build-system table
PP003 Does not list wheel as a build-dep
PP301 Has pytest in pyproject
PP302 Sets a minimum pytest to at least 6
PP303 Sets the test paths
PP304 Sets the log level in pytest
PP305 Specifies xfail_strict
PP306 Specifies strict config
PP307 Specifies strict markers
PP309 Filter warnings specified

GitHub Actions

?NameDescription
GH100 Has GitHub Actions config
GH101 Has nice names
GH102 Auto-cancel on repeated PRs
GH103 At least one workflow with manual dispatch trigger
GH104 Use unique names for upload-artifact
GH200 Maintained by Dependabot
GH210 Maintains the GitHub action versions with Dependabot
GH211 Do not pin core actions as major versions
GH212 Require GHA update grouping

Pre-commit

?NameDescription
PC100 Has pre-commit-hooks
PC110 Uses black or ruff-format
PC160 Uses codespell
PC170 Uses PyGrep hooks (only needed if RST present)
PC190 Uses Ruff
PC191 Ruff show fixes if fixes enabled

Ruff

?NameDescription
RF001 Has Ruff config
RF002 Target version must be set
⚠️ RF003 src directory specified if used
RF101 Bugbear must be selected
RF102 isort must be selected
RF103 pyupgrade must be selected
RF201 Avoid using deprecated config settings
RF202 Use (new) lint config section

Documentation

?NameDescription
RTD100 Uses ReadTheDocs (pyproject config)
RTD101 You have to set the RTD version number to 2
RTD102 You have to set the RTD build image
RTD103 You have to set the RTD python version

@henryiii
Copy link
Collaborator

henryiii commented May 7, 2024

Ignored checks without a reason (empty string) don't appear in the report

Easy, that's what we already do.

Fully-qualified ignored checks with non-empty strings in the pyproject.toml, like PC901, ARE printed in the report, but with a symbol (different from the "skipped" info status, e.g. a "➖", and a reason printed on that line

Pretty easy, it does require a change to the api, though the simplest way would probably to have a new keyword argument to process that includes the ignored checks, with reasons. Passing the argument means you know how to process the output.

Partially-qualified ignored checks visually grouped with the "Reason" rendering just above them, like the GH21 group. Not strictly necessary, could just repeat the reason for each check to avoid computing a complex document tree

This is hard, as this would affect the ordering, wouldn't be clear if multiple ignores matched a check, etc. Probably not impossible.

Suppressed categories like MY have an ignore reason given inside the category

Also hard, as "family" and check name are not actually linked. You could have several codes inside one family, or even split codes across different families.

A first version could do the "simple" thing, with a more advanced version as a followup eventually.

One thing to consider is that allowing TOML tables would make it easier to accidentally give checks empty TOML tables

That's supported now, any iterable can be used. validate-pyproject can be used to validate the config, and we'd update our schema to allow either a list or strings or a table of strings, currently it's a list of strings.

@blakeNaccarato
Copy link
Author

Yeah, even the "simple" approach will be nice, scarequotes around it because even with the clear path to it I'm sure it'll take a bit of time.

If you already had a zillion rules and complex include/exclude machinery in place to specify arbitrarily complex intersections, the more involved solution would probably be a closer hill. But the tight integration between rules and your documentation is pretty cool, it seems very docs-first in a good way.

Anyways this is a quality-of-life request, and it's cool the idea is hammered out, but of course there's no pressure to prioritize this. It certainly seems a reasonably good first issue for someone to pick up.

I'd offer to work it into a PR but somehow I've managed to fall behind on a couple past-due "PR promises", so I don't want to overcommit and then never get around to it 😅

Thanks for helping me work out the idea, it could be a good first issue if you get any takers, otherwise I'll check back in next month and see if it's still unworked!

@henryiii
Copy link
Collaborator

henryiii commented May 8, 2024

I've added this issue to the summit planning doc, maybe someone can work on it there. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants