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

Improve output of V2 fmt and lint goals #9710

Merged
merged 4 commits into from
May 7, 2020

Conversation

Eric-Arellano
Copy link
Contributor

@Eric-Arellano Eric-Arellano commented May 6, 2020

Problem

It's confusing which linters and formatters have run. For example, docformatter will simply put the file name with no context when there is a lint failure, like this:

$ ./v2 lint src/python::

src/python/pants/util/strutil.py

Goals of the design:

  1. Disambiguate which linters were run.
  2. Preserve the original output.
  3. Be minimally intrusive to the user.

Result

fmt example

lint example

We always write to stderr for consistency and to follow the Unix philosophy. Because the output mangles multiple tools into one stream, the output cannot be safely piped to other tools. (Instead, we should add support for writing tool output to specific files, like we allow with Pytest.)

[ci skip-rust-tests]
[ci skip-jvm-tests]

[ci skip-rust-tests]
[ci skip-jvm-tests]
@benjyw
Copy link
Contributor

benjyw commented May 6, 2020

I think we might want to route tool stdout to our stderr, so that everything, including our headings, go there. It's probably wrong for linters to write to stdout anyway.

Could be convinced either way though.

@asherf
Copy link
Member

asherf commented May 6, 2020

I think we might want to route tool stdout to our stderr, so that everything, including our headings, go there. It's probably wrong for linters to write to stdout anyway.

Could be convinced either way though.

I think most linter can write results to some output file...
I was think of adding that capability to pants and integrating with the linter tools that support that features.
I know Jenkins can read those linter files. not sure about other CI systems.
https://plugins.jenkins.io/violations/

@cosmicexplorer
Copy link
Contributor

cosmicexplorer commented May 6, 2020

Goals of the design:

Yes to all of these! I think these are very thoughtful.

I think we might want to route tool stdout to our stderr, so that everything, including our headings, go there. It's probably wrong for linters to write to stdout anyway.

+1. If a linter writes to stdout I'm thinking it should be something structured like json. If it's all text, I think stderr makes perfect sense. Several ways to do this:

  1. redirect the linter's stdout to stderr with a shell command ([WIP] Integrate bash scripts into v2 @rules easily #9101 would at least make this more hygienic so we're not passing in a single flat string to execute the shell).
  2. redirect the linter's stdout to stderr by executing the linter with the right arguments (the right arguments may not exist for some linter tools).
  3. don't interleave stdout and stderr, and just cat them together at the end, in pants python rules (if the linter writes messages to both stdout and stderr, the messages wouldn't be correlated, so the output could be hard to read).
  4. add a kwarg to Process to interleave stdout/stderr (the rust stdlib subprocess library has a flag for this, and i like this approach the most).

EDIT: I really like @asherf's note above. While the right arguments to make a linter interleave output might not exist, an output file feels much more likely to be a command-line option (and we do always have the option of #9101 if we need to do one-off redirections). I like the idea of using an output file because it seems like something that'd be more reliably available as a CLI arg, but I also like the idea of (4) above, which wouldn't require modifying any command lines.

# Delete this line to force CI to run Clippy and the Rust tests.
[ci skip-rust-tests]
# Delete this line to force CI to run the JVM tests.
[ci skip-jvm-tests]
@Eric-Arellano
Copy link
Contributor Author

Okay, talked to John, and decided per your suggestions + his to always write to stderr.

John pointed out this would better follow the Unix philosophy - users cannot pipe the output to other programs because it will be mangled with the output of other linters, so it belongs in stderr.

He coined the "emoji rule": "emoji == bs for humans == stderr" 😂

@cosmicexplorer
Copy link
Contributor

He coined the "emoji rule": "emoji == bs for humans == stderr" 😂

I love this!!!

# Delete this line to force CI to run Clippy and the Rust tests.
[ci skip-rust-tests]
# Delete this line to force CI to run the JVM tests.
[ci skip-jvm-tests]
Copy link
Member

@stuhood stuhood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

As discussed offline, I feel pretty strongly that similar to with test we need to move to a place where we can render actionable (ie, failing or warning) output immediately while other things are still being computed (ie, show you the results of one linter or one-linter-for-one-target while others are still running). I believe that that means that this will need to change further: but this definitely clarifies things in the meantime, so we can cross that bridge soon.

if result.stdout:
console.print_stdout(result.stdout)
console.print_stderr(result.stdout)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving forward (and if we think that it generalizes) we should consider whether we want to indent tool outputs by a small amount (ie, nowhere near the unbounded indentation of v1). So I think we'd have exactly two levels of indentation: the workunit containers would be un-indented, and tool outputs would be indented.

@Eric-Arellano
Copy link
Contributor Author

I feel pretty strongly that similar to with test we need to move to a place where we can render actionable (ie, failing or warning) output immediately

Agreed. I also strongly agree with that. I think we will end up using very similar wording to this PR, just we'll render it right away, rather than at the end.

@Eric-Arellano Eric-Arellano merged commit be07ae7 into pantsbuild:master May 7, 2020
@Eric-Arellano Eric-Arellano deleted the lint-output branch May 7, 2020 20:39
Eric-Arellano added a commit that referenced this pull request May 7, 2020
Changes:
* Don't log with `test --debug`.
* Stop explicitly separating `stdout` and `stderr` into distinct sections for the same result.
* Use `✓` and `𐄂` when outputting the test's output.
* Only render the summary if > 1 target.
* Don't output "Tests failed". The summary, return code, and individual results already express this.
* Always write to stderr. See #9710 (comment) for a justification.


![success](https://user-images.githubusercontent.com/14852634/81332659-448f8680-9058-11ea-9184-0bc729da8f19.png)

![failure](https://user-images.githubusercontent.com/14852634/81332671-48bba400-9058-11ea-9ee5-f0ccf544697e.png)

Once we have streaming workunits, we will replace the log statements with immediately writing the results to the console.

[ci skip-jvm-tests]
Eric-Arellano added a commit that referenced this pull request Jan 29, 2022
…k`, and `test` (#14303)

Before:

```
❯ ./pants --black-skip fmt src/python/pants/util/strutil.py
07:22:21.51 [INFO] Completed: Format with Autoflake - autoflake made no changes.
07:22:22.52 [INFO] Completed: Format with docformatter - Docformatter made no changes.
07:22:22.54 [INFO] Completed: Format with isort - isort made no changes.

- Black skipped.
✓ Docformatter made no changes.
✓ autoflake made no changes.
✓ isort made no changes.
```


After:

```
❯ ./pants --black-skip fmt src/python/pants/util/strutil.py                                           
07:22:01.24 [INFO] Completed: Format with Autoflake - autoflake made no changes.
07:22:01.41 [INFO] Completed: Format with docformatter - Docformatter made no changes.
07:22:01.70 [INFO] Completed: Format with isort - isort made no changes.

✓ Docformatter made no changes.
✓ autoflake made no changes.
✓ isort made no changes.
```

As we've added more tools, rendering skipping is somewhat noisy. 

More importantly, it causes a problem when tools want to disable themselves via some complex logic that requires the Rules API. For example, with Go, we don't know if a `go_package` has tests in it or not until compiling the code and running our analyzer: 

https://github.com/pantsbuild/pants/blob/0488605f54ef3602797d68a5c4797dea9d706b14/src/python/pants/backend/go/goals/test.py#L192-L193

With the upcoming `regex-lint` (formerly `validate`), we want to only enable the linter if `[regex-lint].config` is set up: #14102. 

In both these cases, it is annoying & noisy to render the skipped tools in the summary. I wasn't anticipating these use cases when designing this summary in 2020: #9710.

We will still log that the tool is skipped at `-ldebug`, which helps if users are confused why something isn't showing up.

[ci skip-rust]
[ci skip-build-wheels]
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

Successfully merging this pull request may close these issues.

5 participants