-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
Replace Paver quality and js_test commands #35159
base: master
Are you sure you want to change the base?
Conversation
This comment was marked as outdated.
This comment was marked as outdated.
@feanil @kdmccormick |
@salman2013 as you remove Paver commands, please remove the tests that correspond to those commands. |
Thanks for the PR @salman2013, but this only goes part of the way. The goal of #35159 is not only to get rid of the Keep in mind that there are several things that pavelib code did that are now completely unnecessary, for example:
I recommend starting with one simple check, such as |
@kdmccormick Could you please look into my comment #34845 (comment) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just "Requesting Changes" so this doesn't show up in my queue. The direction is looking great-- just re-request my review whenever you're ready Salman.
@kdmccormick This PR is ready for another pass. Please take a look thanks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fantastic work so far. Really happy to see these running without Paver.
@kdmccormick I believe this PR is ready for another pass. Please take a look thanks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of this feedback is straightforward, except the very last item regarding subprocess.run
. I'm happy to go over that in our sync tomorrow morning if my comment isn't clear.
@kdmccormick Thanks for reviewing the PR, I have fixed all your comments, and the PR is ready for another pass. |
Taking another look... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's a partial review-- I'll have some more comments tomorrow, and I still need to run each check locally. But generally this is looking good and it's exciting to see how much you were able to delete.
I've created a series of PRs based on this branch to make sure that each check fails when a violation is added:
|
@salman2013 I'm currently validating each individual check with this spreadsheet: https://docs.google.com/spreadsheets/d/1KHl4bD9z1OodgLsJLUkobL8R0itMikEOSbHmkIFsMok/edit?gid=0#gid=0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- pycodestyle and test-js are failing correctly 😄 Good job on those ✔️
- pii_check has problems on this PR, but it also has problems on master-- see my comment below.
- xsslint on this PR is failing to catch violations, although it works on master.
- check_keywords on this PR is properly finding violations, but it does not print the message to CI output.
- I'm still trying out coverage-js, eslint, stylelint-- I'll let you know how testing those goes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I've highlighted, existing issues with Paver have made it so that these checks are not working on master or your branch, so please just remove them entirely:
- coverage-js 🪓
- stylelint 🪓
Furthermore, the following checks do not rely on any complicated output parsing, so instead of being part of a Python script, please pull the underlying shell commands directly into their respective Makefile target:
- check_keywords
- pii_check
and, for the same reason, pull this into its own npm run
command in package.json:
- test-js
which will allow you to delete scripts/js_test.py.
That leaves just two commands in scripts/quality_test.py...
- run_xsslint: This is a python function that uses a shell command to call a python script. That's bonkers (not your fault, it was that way before). The implementation in your PR, though, currently silently passes when there are xsslint violations. Instead of fixing it, let's simplify further. Please delete this function. Move the logic which compares violations against xsslint_thresholds.json logic into scripts/xsslint/xsslint/main.py. Finally, create a Makefile target which invokes scripts/xsslint/xss_linter.py directly.
- run_eslint: This command currently works, both in the Paver implementation, and in your implementation. However, it is still more complicated than it needs to be. Please pull it into a new Python script called
scripts/eslint.py
. Keep it as simple as possible. Minimal variables, minimal functions, no constants. Do not generate any report files; just capture the output directly and parse the last line. Please also be sure toprint()
both the shell command and the command's output so that developers can understand the check when they look at the build log.
scripts/js_test.py
Outdated
# ("compare-branch=", "b", "Branch to compare against, defaults to origin/master"), | ||
# ], share_with=['coverage']) | ||
|
||
def diff_coverage(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, I have found that the JS coverage check does not actually validate anything, both on master and on this branch.
Here is a PR that removes a significant number of JS tests. You would expect that this would cause JS coverage to fail. However, both with the Paver checks and with your new Paver-free checks, it seems that coverage check is not actually doing anything. The operative log lines seems to be:
-------------
Diff Coverage
Diff: origin/master..HEAD, staged and unstaged changes
-------------
No lines with coverage information in this diff.
-------------
In my opinion, it is not worthwhile trying to turn JS coverage check back on. All the JS in edx-platform is legacy code. It is either deprecated or soon-to-be-deprecated. Please just remove all the JS coverage checks from this PR.
scripts/quality_test.py
Outdated
command = [ | ||
'node', 'node_modules/stylelint', | ||
'*scss_files', | ||
'--custom-formatter', 'stylelint-formatter-pretty/index.js' | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This command was silently passing because:
node_modules/stylelint
is a directory, not a binary. The binary is atnode_modules/.bin/stylelint
. Runningnode
on a directory does nothing.*scss_files
matches nothing. The correct pattern is**/*.scss
Regardless, though, the Paver version of this command doesn't work on master either. It has been silently failing with /bin/sh: 1: stylelint: not found
for potentially several years now. There are now 24k+ sass style violations on master. Fixing all those violations would not be a good use of our time, especially since we intend to delete all the Sass code in edx-platform.
So, you can just remove all the stylelint
checks.
scripts/quality_test.py
Outdated
), | ||
ignore_error=True | ||
) | ||
violations_limit = 4950 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This threshold is way too high! I know it comes from the master branch. I don't know why it was set so high in the first place.
There are only 1213 eslint violations on master currently. Can you lower the threshold down to that?
scripts/eslint.py
Outdated
num_violations = int(re.search(regex, last_line).group(0)) if last_line else 0 | ||
# An AttributeError will occur if the regex finds no matches. | ||
except (AttributeError, ValueError): | ||
print(f"FAILURE: Number of eslint violations could not be found in '{last_line}'") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If num_violations
cannot be parsed, then that should cause the quality to check to immediately fail with this error message.
Otherwise, we would fail with a a NameError
on line 53, which would be confusing to developers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@salman2013 , simply printing an error message is this case is not sufficient. We need to be sure that the process fails (exits non-zero status code) so that the PR check fails. You can do so by adding raise
to this block.
While testing this PR, I found an existing logging issue with our JS CI, and I made a fix that is ready for review: #35954 Once that merges, could you rebase on top of it (or merge it in) so that we have better JS test logging to work with? |
@kdmccormick I have rebased this branch with #35954 |
@kdmccormick I have fixed the comments. Could you take another look thanks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
scripts/eslint.py
Outdated
def fail_quality(name, message): | ||
""" | ||
Fail the specified quality check. | ||
""" | ||
print(name) | ||
print(message) | ||
sys.exit() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As written, this displays the word "FAILURE" but it not actually cause the quality check to fail. That is problem... you can check the CI logs on this PR, and see how we are violating the threshold but still getting a green build:
(separate comment: looks like the violations limit needs to be 1303 rather than 1213)
Are you familiar with the idea of exit codes? It is a universal convention where each process in a system returns an integer upon completion. Zero indicates success, nonzero indicates failure. That is how GitHub Actions and many other systems determine whether a process succeeded or not. When you raise a Python exception, that automatically causes the process to return a nonzero exit code.
Here, sys.exit()
returns exit code 0, indicating success. Obviously, that is not what we want :) You want to raise exit code 1, indicating "general error" to the surrounding process, which will cause the PR check to fail as desired.
scripts/eslint.py
Outdated
"--ext", ".js", | ||
"--ext", ".jsx", | ||
"--format=compact", | ||
"." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"." | |
"lms", | |
"cms", | |
"common", | |
"openedx", | |
"xmodule", |
I haven't tested it yet, but perhaps specifying each root path would lower the violation count. Specifying "."
(current directory) might be including node_modules accidentally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kdmccormick I believe your thoughts are right, making these changes the error count reduced to 1285 from 1303.
result = subprocess.run( | ||
command, | ||
text=True, | ||
check=False, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check=False, | |
check=True, |
Using check=True ensures that the script will fail if subprocess.run
fails. Using check=False hides the errors-- in other words, check=False means "fail silently".
Failing silently is usually bad. In CI scripting, failing silently is very bad, because it means that PRs can pass tests even when they shouldn't.
@salman2013 , every time you call subprocess.run
, including here, please please use check=True unless you are actively handling the error case yourself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kdmccormick
You are right, actually, i intentionally used check=False
, Reason is that check-True
command is failing with status code 1. I tried to figure out the reason, there could be the following three possibility
- Command Syntax
- Eslint Configuration issue
- Files path issue
The above three issues were not the reasons i investigated. The result.stderr
is showing nothing but the result.stdout
is printing almost 1285 errors from different files. Which i figured out the command is sending status code 1 as a lot of errors in different files.
As we raise exceptions in case of violation count comparison, I thought it safe to use check=False.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh I see @salman2013 . You are right, it makes sense to check=False
here. Just please then inspect the actual integer value of the exit code. According to the eslint docs, exit code 1 indicates that linting happened successfully but there were violations, whereas exit code 2 indicates that an unexpected error occurred (in which case we'd want to fail CI).
a61d9a7
to
ca2712a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used these PRs to confirm that each kind of build failure is caught by the check as we'd expect. Great work!
Just one comment about raising the pii_check threshold, and there is my comment from earlier about xsslint exit codes 1 vs 2. With those comments resolved, feel free to merge 🚀
Nitpick: Can you label this commit as build:
rather than chore:
? "chore" is meant to indicate minor, repetitive tasks like routine requirement upgrades. This PR is an overhaul of the quality and JS build suite, much more ambitious than a chore 😄
@@ -1,7 +1,7 @@ | |||
source_path: ./ | |||
report_path: pii_report | |||
safelist_path: .annotation_safe_list.yml | |||
coverage_target: 94.5 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PII annotation coverage has improved even further since my last review! Can you bump this up to 85.3?
scripts/eslint.py
Outdated
@@ -0,0 +1,73 @@ | |||
""" # pylint: disable=django-not-configured | |||
Check code quality using pycodestyle, pylint, and diff_quality. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please update this comment before merging.
4788953
to
f85d452
Compare
Paver is deprecated, and we aim to fully remove it soon. You can find more details here:
Paver deprecation issue
Paver removal PR
A few Paver commands remain in the edx-platform, and to proceed with its removal, we've replaced the following Paver commands with equivalent Make commands:
How to Test This PR:
In the edx-platform directory, you can use the following terminal commands to check for linting issues in Python and JavaScript files. Make sure your virtual environment is activated before running these commands.
make pycodestyle
make eslint
make stylelint
make xsslint
make pi_check
make check_keyword
make test-js
make test-coverage
make quality-test
For more details, please refer to the ticket: Replace paver quality and js_test commands