mirror of
https://github.com/pytorch/pytorch.git
synced 2025-10-20 21:14:14 +08:00
Local lint fixes - missing steps, pin to bash (#56752)
Summary: Fixes #56738 * `setup_lint` now installs mypy / shellcheck * the shell used to execute commands is pinned to `bash` (on Ubuntu the default is `dash`, which was causing the false positives in #56738) * the emoji check marks don't always work, so use more basic ones instead * adds `Run autogen` step for mypy (for the `lint` step only since it's pretty slow) ](https://our.intern.facebook.com/intern/diff/27972006/) Pull Request resolved: https://github.com/pytorch/pytorch/pull/56752 Pulled By: driazati Reviewed By: samestep Differential Revision: D27972006 fbshipit-source-id: 624e6c1af2d4f7c8623f420516744922b6b829a5
This commit is contained in:
committed by
Facebook GitHub Bot
parent
6de1d9b2d0
commit
0424f6af93
15
.github/workflows/lint.yml
vendored
15
.github/workflows/lint.yml
vendored
@ -38,8 +38,11 @@ jobs:
|
|||||||
pip install ruamel.yaml==0.17.4
|
pip install ruamel.yaml==0.17.4
|
||||||
.github/scripts/lint_native_functions.py
|
.github/scripts/lint_native_functions.py
|
||||||
- name: Extract scripts from GitHub Actions workflows
|
- name: Extract scripts from GitHub Actions workflows
|
||||||
run: tools/extract_scripts.py --out=.extracted_scripts
|
run: |
|
||||||
- name: ShellCheck
|
# For local lints, remove the .extracted_scripts folder if it was already there
|
||||||
|
rm -rf .extracted_scripts
|
||||||
|
tools/extract_scripts.py --out=.extracted_scripts
|
||||||
|
- name: Install ShellCheck
|
||||||
# https://github.com/koalaman/shellcheck/tree/v0.7.2#installing-a-pre-compiled-binary
|
# https://github.com/koalaman/shellcheck/tree/v0.7.2#installing-a-pre-compiled-binary
|
||||||
run: |
|
run: |
|
||||||
set -x
|
set -x
|
||||||
@ -48,6 +51,8 @@ jobs:
|
|||||||
sudo cp "shellcheck-${scversion}/shellcheck" /usr/bin/
|
sudo cp "shellcheck-${scversion}/shellcheck" /usr/bin/
|
||||||
rm -r "shellcheck-${scversion}"
|
rm -r "shellcheck-${scversion}"
|
||||||
shellcheck --version
|
shellcheck --version
|
||||||
|
- name: Run ShellCheck
|
||||||
|
run: |
|
||||||
tools/run_shellcheck.sh .jenkins/pytorch .extracted_scripts
|
tools/run_shellcheck.sh .jenkins/pytorch .extracted_scripts
|
||||||
- name: Ensure correct trailing newlines
|
- name: Ensure correct trailing newlines
|
||||||
run: |
|
run: |
|
||||||
@ -204,8 +209,10 @@ jobs:
|
|||||||
path: flake8-output/
|
path: flake8-output/
|
||||||
- name: Fail if there were any warnings
|
- name: Fail if there were any warnings
|
||||||
run: |
|
run: |
|
||||||
cat flake8-output.txt
|
set -eux
|
||||||
[ ! -s flake8-output.txt ]
|
# Re-output flake8 status so GitHub logs show it on the step that actually failed
|
||||||
|
cat "${GITHUB_WORKSPACE}"/flake8-output.txt
|
||||||
|
[ ! -s "${GITHUB_WORKSPACE}"/flake8-output.txt ]
|
||||||
|
|
||||||
clang-tidy:
|
clang-tidy:
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
|
30
Makefile
30
Makefile
@ -33,13 +33,25 @@ generate-gha-workflows:
|
|||||||
|
|
||||||
setup_lint:
|
setup_lint:
|
||||||
python tools/actions_local_runner.py --file .github/workflows/lint.yml \
|
python tools/actions_local_runner.py --file .github/workflows/lint.yml \
|
||||||
--job 'flake8-py3' --step 'Install dependencies'
|
--job 'flake8-py3' --step 'Install dependencies' --no-quiet
|
||||||
python tools/actions_local_runner.py --file .github/workflows/lint.yml \
|
python tools/actions_local_runner.py --file .github/workflows/lint.yml \
|
||||||
--job 'cmakelint' --step 'Install dependencies'
|
--job 'cmakelint' --step 'Install dependencies' --no-quiet
|
||||||
|
python tools/actions_local_runner.py --file .github/workflows/lint.yml \
|
||||||
|
--job 'mypy' --step 'Install dependencies' --no-quiet
|
||||||
|
|
||||||
|
# TODO: This is broken on MacOS (it downloads a Linux binary)
|
||||||
|
python tools/actions_local_runner.py --file .github/workflows/lint.yml \
|
||||||
|
--job 'quick-checks' --step 'Install ShellCheck' --no-quiet
|
||||||
pip install jinja2
|
pip install jinja2
|
||||||
|
|
||||||
quick_checks:
|
quick_checks:
|
||||||
# TODO: This is broken when 'git config submodule.recurse' is 'true'
|
@python tools/actions_local_runner.py \
|
||||||
|
--file .github/workflows/lint.yml \
|
||||||
|
--job 'quick-checks' \
|
||||||
|
--step 'Extract scripts from GitHub Actions workflows'
|
||||||
|
|
||||||
|
# TODO: This is broken when 'git config submodule.recurse' is 'true' since the
|
||||||
|
# lints will descend into third_party submodules
|
||||||
@python tools/actions_local_runner.py \
|
@python tools/actions_local_runner.py \
|
||||||
--file .github/workflows/lint.yml \
|
--file .github/workflows/lint.yml \
|
||||||
--job 'quick-checks' \
|
--job 'quick-checks' \
|
||||||
@ -50,6 +62,7 @@ quick_checks:
|
|||||||
--step 'Ensure no unqualified noqa' \
|
--step 'Ensure no unqualified noqa' \
|
||||||
--step 'Ensure no unqualified type ignore' \
|
--step 'Ensure no unqualified type ignore' \
|
||||||
--step 'Ensure no direct cub include' \
|
--step 'Ensure no direct cub include' \
|
||||||
|
--step 'Run ShellCheck' \
|
||||||
--step 'Ensure correct trailing newlines'
|
--step 'Ensure correct trailing newlines'
|
||||||
|
|
||||||
flake8:
|
flake8:
|
||||||
@ -59,8 +72,19 @@ flake8:
|
|||||||
$(CHANGED_ONLY) \
|
$(CHANGED_ONLY) \
|
||||||
--job 'flake8-py3' \
|
--job 'flake8-py3' \
|
||||||
--step 'Run flake8'
|
--step 'Run flake8'
|
||||||
|
@python tools/actions_local_runner.py \
|
||||||
|
--file .github/workflows/lint.yml \
|
||||||
|
--file-filter '.py' \
|
||||||
|
$(CHANGED_ONLY) \
|
||||||
|
--job 'flake8-py3' \
|
||||||
|
--step 'Fail if there were any warnings'
|
||||||
|
|
||||||
mypy:
|
mypy:
|
||||||
|
@if [ -z "$(CHANGED_ONLY)" ]; then \
|
||||||
|
python tools/actions_local_runner.py --file .github/workflows/lint.yml --job 'mypy' --step 'Run autogen'; \
|
||||||
|
else \
|
||||||
|
echo "mypy: Skipping typestub generation"; \
|
||||||
|
fi
|
||||||
@python tools/actions_local_runner.py \
|
@python tools/actions_local_runner.py \
|
||||||
--file .github/workflows/lint.yml \
|
--file .github/workflows/lint.yml \
|
||||||
--file-filter '.py' \
|
--file-filter '.py' \
|
||||||
|
@ -6,6 +6,8 @@ import os
|
|||||||
import argparse
|
import argparse
|
||||||
import yaml
|
import yaml
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import shutil
|
||||||
|
import re
|
||||||
from typing import List, Dict, Any, Optional
|
from typing import List, Dict, Any, Optional
|
||||||
|
|
||||||
|
|
||||||
@ -68,7 +70,7 @@ def find_changed_files() -> List[str]:
|
|||||||
return [x.strip() for x in all_files if x.strip() != ""]
|
return [x.strip() for x in all_files if x.strip() != ""]
|
||||||
|
|
||||||
|
|
||||||
async def run_step(step: Dict[str, Any], job_name: str, files: Optional[List[str]]) -> bool:
|
async def run_step(step: Dict[str, Any], job_name: str, files: Optional[List[str]], quiet: bool) -> bool:
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env["GITHUB_WORKSPACE"] = "/tmp"
|
env["GITHUB_WORKSPACE"] = "/tmp"
|
||||||
if files is None:
|
if files is None:
|
||||||
@ -77,17 +79,19 @@ async def run_step(step: Dict[str, Any], job_name: str, files: Optional[List[str
|
|||||||
env["LOCAL_FILES"] = " ".join(files)
|
env["LOCAL_FILES"] = " ".join(files)
|
||||||
script = step["run"]
|
script = step["run"]
|
||||||
|
|
||||||
PASS = "\U00002705"
|
PASS = color(col.GREEN, '\N{check mark}')
|
||||||
FAIL = "\U0000274C"
|
FAIL = color(col.RED, 'x')
|
||||||
# We don't need to print the commands for local running
|
|
||||||
# TODO: Either lint that GHA scripts only use 'set -eux' or make this more
|
if quiet:
|
||||||
# resilient
|
# TODO: Either lint that GHA scripts only use 'set -eux' or make this more
|
||||||
script = script.replace("set -eux", "set -eu")
|
# resilient
|
||||||
|
script = script.replace("set -eux", "set -eu")
|
||||||
|
script = re.sub(r"^time ", "", script, flags=re.MULTILINE)
|
||||||
name = f'{job_name}: {step["name"]}'
|
name = f'{job_name}: {step["name"]}'
|
||||||
|
|
||||||
def header(passed: bool) -> None:
|
def header(passed: bool) -> None:
|
||||||
icon = PASS if passed else FAIL
|
icon = PASS if passed else FAIL
|
||||||
cprint(col.BLUE, f"{icon} {name}")
|
print(f"{icon} {color(col.BLUE, name)}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
proc = await asyncio.create_subprocess_shell(
|
proc = await asyncio.create_subprocess_shell(
|
||||||
@ -97,6 +101,7 @@ async def run_step(step: Dict[str, Any], job_name: str, files: Optional[List[str
|
|||||||
env=env,
|
env=env,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
|
executable=shutil.which("bash"),
|
||||||
)
|
)
|
||||||
|
|
||||||
stdout_bytes, stderr_bytes = await proc.communicate()
|
stdout_bytes, stderr_bytes = await proc.communicate()
|
||||||
@ -118,8 +123,8 @@ async def run_step(step: Dict[str, Any], job_name: str, files: Optional[List[str
|
|||||||
return proc.returncode == 0
|
return proc.returncode == 0
|
||||||
|
|
||||||
|
|
||||||
async def run_steps(steps: List[Dict[str, Any]], job_name: str, files: Optional[List[str]]) -> None:
|
async def run_steps(steps: List[Dict[str, Any]], job_name: str, files: Optional[List[str]], quiet: bool) -> None:
|
||||||
coros = [run_step(step, job_name, files) for step in steps]
|
coros = [run_step(step, job_name, files, quiet) for step in steps]
|
||||||
await asyncio.gather(*coros)
|
await asyncio.gather(*coros)
|
||||||
|
|
||||||
|
|
||||||
@ -158,6 +163,7 @@ def main() -> None:
|
|||||||
parser.add_argument("--file-filter", help="only pass through files with this extension", default='')
|
parser.add_argument("--file-filter", help="only pass through files with this extension", default='')
|
||||||
parser.add_argument("--changed-only", help="only run on changed files", action='store_true', default=False)
|
parser.add_argument("--changed-only", help="only run on changed files", action='store_true', default=False)
|
||||||
parser.add_argument("--job", help="job name", required=True)
|
parser.add_argument("--job", help="job name", required=True)
|
||||||
|
parser.add_argument("--no-quiet", help="output commands", action='store_true', default=False)
|
||||||
parser.add_argument("--step", action="append", help="steps to run (in order)")
|
parser.add_argument("--step", action="append", help="steps to run (in order)")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--all-steps-after", help="include every step after this one (non inclusive)"
|
"--all-steps-after", help="include every step after this one (non inclusive)"
|
||||||
@ -165,6 +171,7 @@ def main() -> None:
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
relevant_files = None
|
relevant_files = None
|
||||||
|
quiet = not args.no_quiet
|
||||||
|
|
||||||
if args.changed_only:
|
if args.changed_only:
|
||||||
changed_files: Optional[List[str]] = None
|
changed_files: Optional[List[str]] = None
|
||||||
@ -206,7 +213,8 @@ def main() -> None:
|
|||||||
relevant_steps = grab_all_steps_after(args.all_steps_after, job)
|
relevant_steps = grab_all_steps_after(args.all_steps_after, job)
|
||||||
|
|
||||||
if sys.version_info > (3, 7):
|
if sys.version_info > (3, 7):
|
||||||
asyncio.run(run_steps(relevant_steps, args.job, relevant_files))
|
loop = asyncio.get_event_loop()
|
||||||
|
loop.run_until_complete(run_steps(relevant_steps, args.job, relevant_files, quiet))
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Only Python >3.7 is supported")
|
raise RuntimeError("Only Python >3.7 is supported")
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user