-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Support multiple linting rules #9859
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
base: upgrade-linting-tool
Are you sure you want to change the base?
Support multiple linting rules #9859
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## upgrade-linting-tool #9859 +/- ##
=======================================================
Coverage ? 93.33%
=======================================================
Files ? 209
Lines ? 16807
Branches ? 0
=======================================================
Hits ? 15687
Misses ? 1120
Partials ? 0 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Just a note, the pagination linting rule should actually be based around the |
| choice = input(prompt).lower().strip() | ||
| if choice in ["y", "n", "u", "s"]: | ||
| choice = ( | ||
| input("\nApply this fix? [y]es, [n]o, [u]pdate all, [s]ave and exit, [q]uit: ") |
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.
For accessibility, we should make the letter to select separate from the word that describes. A screen reader would not be able to read this well. How about:
| input("\nApply this fix? [y]es, [n]o, [u]pdate all, [s]ave and exit, [q]uit: ") | |
| input("\nApply this fix? [y] yes, [n] no, [u] update all, [s] save and exit, [q] quit: ") |
kdaily
left a 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.
Thanks, nice work so far! Mostly a few basic comments and suggestions.
I think the biggest feedback is the main() method is quite long and a bit hard to follow. I would recommend breaking it out into a few helpers to clarify the branching behavior a bit better.
| def description(self) -> str: | ||
| return ( | ||
| "AWS CLI v2 uses pagination by default for commands that return large result sets. " | ||
| "Add --no-cli-paginate to disable pagination and match v1 behavior." |
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.
Users can also disable pagination via env variable or config file option, which they may be already doing. Would that make detection a false positive?. If so, how do we account for that?
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.
Good question. Since this is a static linter, we cannot resolve the user's config profile values, and if that behavior is desired, we can point users to use the --v2-debug runtime migration tool instead, which has that functionality. Being static, we should be processing these scripts independent of the environment: the only input is a script, and the only output is a script (possibly with a detections summary).
I generally agree that would be a false positive case. As a workaround, if a user knows they configured pagination to disable the pager, then they can reject the auto-fix in interactive mode by entering "n" when the fix is suggested. In any case, even if the auto-fix is made, the command-line option overrides the configuration in precedence order, and the behavior would not change (pager gets disabled anyways). So, the worst case scenario is that the flag is added even when it's unnecessary, however, it being unnecessary does not cause breakage.
| # Group findings by rule | ||
| findings_by_rule: Dict[str, List[LintFinding]] = {} | ||
| for finding, rule in findings_with_rules: | ||
| if rule.name not in findings_by_rule: |
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.
nit: could use collections.defaultdict to reduce checking here, not a strong preference.
| ast = parse(linter.apply_fixes(ast, accepted_findings)) | ||
| return ast, len(accepted_findings) > 0, last_choice | ||
| elif last_choice == "q": | ||
| print("Quit without saving.") |
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.
nit:
| print("Quit without saving.") | |
| print("Quitting without saving.") |
| findings = interactive_mode(findings, script_content) | ||
| if not findings: | ||
| # Do an initial parse-and-lint with all the rules simultaneously to compute the total | ||
| # number of findings for displaying progress in interactive mode. |
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.
What's the value of displaying progress here? It seems a bit unnecessary to completely run through the entire set of possible changes only to do it again without just saving the diffs of what would have been changed and then accepting/denying them in the later loop. That would increase complexity of the solution, and may not matter for performance (scripts might not be that big).
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 would also be fine with a summary at the end that said how many changes could have been applied and how many were.
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.
Good point, I was second-guessing this myself. I figured users may want to know how many findings are left especially if the script is large. However, that may not be super valuable, can always add it back if users request it.
Will remove this in next revision.
| any_changes = False | ||
| finding_offset = 0 | ||
|
|
||
| # Calculate total findings for display |
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.
See comment above, but this should probably go above the comment "# Process one rule at a time" for clarity of where the logic starts.
| output_path = Path(args.output) if args.output else script_path | ||
| output_path.write_text(fixed_content) | ||
| output_path.write_text(current_script) | ||
| print(f"Fixed script written to: {output_path}") |
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.
nit:
| print(f"Fixed script written to: {output_path}") | |
| print(f"Modified script written to: {output_path}") |
Description of changes:
'refreshed'. We avoid this problem by linting the script one-rule-at-a-time.
Base64BinaryFormatRuleso that it does not requirefile://prefix in an argument value to trigger a detection. It now flags all AWS CLI commands.PaginationRulethat flags all AWS CLI commands, and adds--no-cli-paginateas a fix.ScriptLinterclass with utility functions. Updated their interface to let callers pass in their own AST.PaginationRule.Description of tests:
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.