[ci] use lintrunner in CI

This changes our lint workflows to use lintrunner for the linters that
are currently supported

+ some random fixes to make things lint clean on master
+ changes to Makefile to use lintrunner

Pull Request resolved: https://github.com/pytorch/pytorch/pull/68460

Approved by: https://github.com/t10-13rocket, https://github.com/seemethere, https://github.com/janeyx99
This commit is contained in:
Michael Suo
2022-04-14 16:58:06 -07:00
committed by PyTorch MergeBot
parent 54bd9e0402
commit 1c60b9aaa5
6 changed files with 142 additions and 463 deletions

View File

@ -0,0 +1,63 @@
import json
import subprocess
import sys
from enum import Enum
from pathlib import Path
from typing import NamedTuple, Optional
# From: https://docs.github.com/en/rest/reference/checks
class GitHubAnnotationLevel(str, Enum):
NOTICE = "notice"
WARNING = "warning"
FAILURE = "failure"
class GitHubAnnotation(NamedTuple):
path: str
start_line: int
end_line: int
start_column: Optional[int]
end_column: Optional[int]
annotation_level: GitHubAnnotationLevel
message: str
title: Optional[str]
raw_details: Optional[str]
PYTORCH_ROOT = Path(subprocess.check_output(['git', 'rev-parse', '--show-toplevel']).decode('ascii').strip())
annotations = []
for line in sys.stdin:
lint_message = json.loads(line)
path = lint_message.get("path")
line = lint_message.get("line")
code = lint_message["code"]
severity = lint_message["severity"]
name = lint_message["name"]
description = lint_message.get("description")
# These fields are required by the GitHub API, but optional in lintrunner.
# If they don't exist, just skip.
if path is None or line is None:
print(f"No path/line for lint: ({code}) {name}", file=sys.stderr)
continue
# normalize path relative to git root
path = Path(path).relative_to(PYTORCH_ROOT)
annotations.append(GitHubAnnotation(
path=str(path),
start_line=int(line),
end_line=int(line),
start_column=None,
end_column=None,
annotation_level=GitHubAnnotationLevel.FAILURE,
message=description,
title=f"({code}) {name}",
raw_details=None,
)._asdict())
print(json.dumps(annotations), flush=True)

View File

@ -7,6 +7,72 @@ on:
pull_request: pull_request:
jobs: jobs:
lintrunner:
runs-on: ubuntu-18.04
steps:
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.8
architecture: x64
- name: Checkout PyTorch
uses: pytorch/pytorch/.github/actions/checkout-pytorch@master
with:
submodules: false
- name: Install lintrunner
run: pip install lintrunner==0.5.*
- name: Initialize lint dependencies
run: lintrunner init
- name: Do build steps necessary for linters
run: |
python3 -m tools.linter.clang_tidy.generate_build_files
python3 -m tools.generate_torch_version --is_debug=false
python3 -m tools.pyi.gen_pyi \
--native-functions-path aten/src/ATen/native/native_functions.yaml \
--deprecated-functions-path "tools/autograd/deprecated.yaml"
- name: Run lintrunner on all files
if: github.event_name == 'push'
run: lintrunner -vv --paths-cmd='git grep -Il .' --force-color
- name: Run lintrunner on PR files
if: github.event_name == 'pull_request'
env:
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
MERGE_BASE=$(git merge-base "$PR_BASE_SHA" "$PR_HEAD_SHA")
lintrunner -vv --force-color --revision "${MERGE_BASE}"
echo ""
echo -e "\e[1m\e[36mYou can reproduce these results locally by using \`lintrunner\`.\e[0m"
echo -e "\e[1m\e[36mSee https://github.com/pytorch/pytorch/wiki/lintrunner for setup instructions.\e[0m"
- name: Store annotations
# Don't run on forked pull requests
if: failure() && github.event.pull_request.head.repo.full_name == github.repository
run: |
lintrunner --json \
| python .github/scripts/convert_lintrunner_annotations_to_github.py \
> annotations.json
cat annotations.json
- name: Add annotations
# Don't run on forked pull requests
if: failure() && github.event.pull_request.head.repo.full_name == github.repository
uses: pytorch/add-annotations-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
check_name: 'lintrunner'
linter_output_path: annotations.json
commit_sha: ${{ github.event.pull_request.head.sha }}
mode: json
quick-checks: quick-checks:
name: quick-checks name: quick-checks
runs-on: ubuntu-18.04 runs-on: ubuntu-18.04
@ -28,70 +94,16 @@ jobs:
- name: Install requirements - name: Install requirements
id: requirements id: requirements
run: pip3 install -r requirements.txt --user run: pip3 install -r requirements.txt --user
- name: Ensure consistent CircleCI YAML config
if: ${{ always() && steps.requirements.outcome == 'success' }}
run: cd .circleci && ./ensure-consistency.py
- name: Lint native_functions.yaml
if: ${{ always() && steps.requirements.outcome == 'success' }}
run: |
pip3 install ruamel.yaml==0.17.4 --user
.github/scripts/lint_native_functions.py
- name: Ensure correct trailing newlines
if: ${{ always() && steps.requirements.outcome == 'success' }}
run: |
(! git --no-pager grep -Il '' -- . ':(exclude)**/contrib/**' ':(exclude)third_party' ':(exclude)**.expect' ':(exclude)**.ipynb' ':(exclude)tools/clang_format_hash' | tools/linter/trailing_newlines.py || (echo "The above files do not have correct trailing newlines; please normalize them"; false))
- name: Ensure no trailing spaces
if: always()
run: |
(! git --no-pager grep -In '[[:blank:]]$' -- . ':(exclude)**/contrib/**' ':(exclude)**.diff' ':(exclude)third_party' || (echo "The above lines have trailing spaces; please remove them"; false))
- name: Ensure no tabs
if: always()
run: |
(! git --no-pager grep -In $'\t' -- . ':(exclude)*.svg' ':(exclude)**Makefile' ':(exclude)**/contrib/**' ':(exclude)third_party' ':(exclude).gitattributes' ':(exclude).gitmodules' || (echo "The above lines have tabs; please convert them to spaces"; false))
- name: Ensure no non-breaking spaces - name: Ensure no non-breaking spaces
if: always() if: always()
run: | run: |
# NB: We use 'printf' below rather than '\u000a' since bash pre-4.2 # NB: We use 'printf' below rather than '\u000a' since bash pre-4.2
# does not support the '\u000a' syntax (which is relevant for local linters) # does not support the '\u000a' syntax (which is relevant for local linters)
(! git --no-pager grep -In "$(printf '\xC2\xA0')" -- . || (echo "The above lines have non-breaking spaces (U+00A0); please convert them to spaces (U+0020)"; false)) (! git --no-pager grep -In "$(printf '\xC2\xA0')" -- . || (echo "The above lines have non-breaking spaces (U+00A0); please convert them to spaces (U+0020)"; false))
- name: Ensure canonical include
if: always()
run: |
(! git --no-pager grep -In $'#include "' -- ./c10 ./aten ./torch/csrc ':(exclude)aten/src/ATen/native/quantized/cpu/qnnpack/**' ':(exclude)torch/csrc/jit/serialization/mobile_bytecode_generated.h'|| (echo "The above lines have include with quotes; please convert them to #include <xxxx>"; false))
- name: Ensure no versionless Python shebangs - name: Ensure no versionless Python shebangs
if: always() if: always()
run: | run: |
(! git --no-pager grep -In '#!.*python$' -- . || (echo "The above lines have versionless Python shebangs; please specify either python2 or python3"; false)) (! git --no-pager grep -In '#!.*python$' -- . || (echo "The above lines have versionless Python shebangs; please specify either python2 or python3"; false))
- name: Ensure no unqualified noqa
if: always()
run: |
# shellcheck disable=SC2016
(! git --no-pager grep -InP '# noqa(?!: [A-Z]+\d{3})' -- '**.py' '**.pyi' ':(exclude)caffe2' || (echo 'The above lines have unqualified `noqa`; please convert them to `noqa: XXXX`'; false))
- name: Ensure no unqualified type ignore
if: always()
run: |
# shellcheck disable=SC2016
(! git --no-pager grep -InP '# type:\s*ignore(?!\[)' -- '**.py' '**.pyi' ':(exclude)test/test_jit.py' || (echo 'The above lines have unqualified `type: ignore`; please convert them to `type: ignore[xxxx]`'; false))
- name: Ensure GitHub PyPi dependencies are pinned
if: always()
run: |
(! git --no-pager grep --color=always -InP \
'(pip|pip3|python -m pip|python3 -m pip|python3 -mpip|python -mpip) install ([a-z][\.a-z-0-9]*+(?!(=|.*\.whl))([[:blank:]]|))+' \
-- .github \
':(exclude)**.rst' \
':(exclude)**.py' \
':(exclude)**.md' \
':(exclude)**.diff' \
':(exclude)third_party' ||
(echo "The above lines have unpinned PyPi installs; please pin them to a specific version: e.g. 'thepackage==1.2'"; false))
# note that this next step depends on a clean checkout;
# if you run it locally then it will likely to complain
# about all the generated files in torch/test
- name: Ensure C++ source files are not executable
if: always()
run: |
# shellcheck disable=SC2016
(! find . \( -path ./third_party -o -path ./.git -o -path ./torch/bin -o -path ./build \) -prune -o -type f -executable -regextype posix-egrep -not -regex '.+(\.(bash|sh|py|so)|git-pre-commit|git-clang-format|gradlew)$' -print | grep . || (echo 'The above files have executable permission; please remove their executable permission by using `chmod -x`'; false))
- name: C++ docs check - name: C++ docs check
if: ${{ always() && steps.requirements.outcome == 'success' }} if: ${{ always() && steps.requirements.outcome == 'success' }}
run: | run: |
@ -102,86 +114,12 @@ jobs:
run: | run: |
set -eux set -eux
python torch/testing/_check_kernel_launches.py |& tee "${GITHUB_WORKSPACE}"/cuda_kernel_launch_checks.txt python torch/testing/_check_kernel_launches.py |& tee "${GITHUB_WORKSPACE}"/cuda_kernel_launch_checks.txt
- name: Ensure no direct cub include
if: always()
run: |
(! git --no-pager grep -I -no $'#include <cub/' -- ./aten ':(exclude)aten/src/ATen/cuda/cub*.cuh' || (echo "The above files have direct cub include; please include ATen/cuda/cub.cuh instead and wrap your cub calls in at::native namespace if necessary"; false))
- name: Ensure no raw cuda api calls
if: always()
run: |
(! git --no-pager grep -I -no $'cudaStreamSynchronize' -- ./aten ./c10 ':(exclude)aten/src/ATen/test' ':(exclude)c10/cuda/CUDAFunctions.h' || (echo "The above files call raw cuda APIs directly; please use at::cuda wrappers instead"; false))
- name: Ensure all test files have header containing ownership information - name: Ensure all test files have header containing ownership information
if: always() if: always()
run: | run: |
python3 -m pip install boto3==1.19.12 python3 -m pip install boto3==1.19.12
.github/scripts/lint_test_ownership.py .github/scripts/lint_test_ownership.py
clang-format:
name: clang-format
runs-on: ubuntu-18.04
if: ${{ github.event_name == 'pull_request' }}
steps:
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.x
architecture: x64
# [see note: pytorch repo ref]
# deep clone (fetch-depth 0 required to use git merge-base)
- name: Checkout PyTorch
uses: pytorch/pytorch/.github/actions/checkout-pytorch@master
with:
submodules: false
- name: Run clang-format
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: |
set -eu
# This is necessary to get the same results regardless of whether the
# PR was opened directly or from a forked repo. See: `9f890a92` for more info.
git remote add upstream https://github.com/pytorch/pytorch
git fetch upstream "$GITHUB_BASE_REF"
# only run clang-format on allowlisted files
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo "| clang-format failures found! Run: "
echo "| tools/linter/clang_format_ci.sh ${BASE_SHA} "
echo "| to fix this error. "
echo "| For more info, see: https://github.com/pytorch/pytorch/wiki/clang-format "
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
tools/linter/clang_format_ci.sh "${BASE_SHA}"
GIT_DIFF=$(git diff)
if [[ -z $GIT_DIFF ]]; then
exit 0
fi
echo "$GIT_DIFF"
exit 1
py2-setup-validate-errormsg:
name: py2-setup-validate-errormsg
runs-on: ubuntu-18.04
steps:
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 2.x
architecture: x64
# [see note: pytorch repo ref]
- name: Checkout PyTorch
uses: pytorch/pytorch/.github/actions/checkout-pytorch@master
with:
submodules: false
- name: Attempt to run setup.py
run: |
if ! python2 setup.py | grep -q "Python 2 has reached end-of-life and is no longer supported by PyTorch."; then
echo 'Running setup.py with Python 2 did not give the expected error message.'
false
fi
- name: Keep torch.utils.collect_env python2 compliant
run: python2 -m py_compile torch/utils/collect_env.py
shellcheck: shellcheck:
name: shellcheck name: shellcheck
runs-on: ubuntu-18.04 runs-on: ubuntu-18.04
@ -266,7 +204,6 @@ jobs:
./actionlint --color ./actionlint --color
rm actionlint rm actionlint
toc: toc:
name: toc name: toc
runs-on: ubuntu-18.04 runs-on: ubuntu-18.04
@ -307,239 +244,6 @@ jobs:
false false
fi fi
flake8-py3:
name: flake8-py3
runs-on: ubuntu-18.04
steps:
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.x
architecture: x64
# [see note: pytorch repo ref]
# fetch-depth 2 required to allow us to use github.event.pull_request.head.sha
- name: Checkout PyTorch
uses: pytorch/pytorch/.github/actions/checkout-pytorch@master
with:
submodules: false
- name: Prepare output dir with HEAD commit SHA
env:
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
mkdir flake8-output
cd flake8-output
echo "$HEAD_SHA" > commit-sha.txt
- name: Install dependencies
run: |
set -eux
pip3 install typing-extensions==3.10 --user # for tools/linter/translate_annotations.py
pip3 install -r requirements-flake8.txt --user
flake8 --version
- name: Run flake8
run: |
set -eux
flake8 | tee "${GITHUB_WORKSPACE}"/flake8-output.txt
- name: Translate annotations
if: ${{ github.event_name == 'pull_request' }}
env:
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
tools/linter/translate_annotations.py \
--file="${GITHUB_WORKSPACE}"/flake8-output.txt \
--regex='^(?P<filename>.*?):(?P<lineNumber>\d+):(?P<columnNumber>\d+): (?P<errorCode>\w+\d+) (?P<errorDesc>.*)' \
--commit="$HEAD_SHA" \
> flake8-output/annotations.json
- name: Fail if there were any warnings
run: |
set -eu
# Re-output flake8 status so GitHub logs show it on the step that actually failed
cat "${GITHUB_WORKSPACE}"/flake8-output.txt
if [ -s "${GITHUB_WORKSPACE}"/flake8-output.txt ]; then
echo 'Please fix the above Flake8 warnings.'
false
fi
- name: Add annotations
# Don't run on forked pull requests
if: ${{ failure() && github.event.pull_request.head.repo.full_name == github.repository }}
uses: pytorch/add-annotations-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
check_name: 'flake8-py3'
linter_output_path: flake8-output/annotations.json
commit_sha: ${{ github.event.pull_request.head.sha }}
mode: json
clang-tidy:
name: clang-tidy
runs-on: [self-hosted, linux.2xlarge]
container:
# ubuntu20.04-cuda11.2-py3.8-tidy11
image: ghcr.io/pytorch/cilint-clang-tidy:d8f0c777964d0dd8a147360de80aed1a13eb613a
steps:
- name: Clean workspace
run: |
rm -rf "${GITHUB_WORKSPACE}"
mkdir "${GITHUB_WORKSPACE}"
# [see note: pytorch repo ref]
# deep clone (fetch-depth 0) to allow tools/linter/clang_tidy.py to do its thing
- name: Checkout PyTorch
uses: pytorch/pytorch/.github/actions/checkout-pytorch@master
with:
no-sudo: true
submodules: false
- name: Prepare output dir with HEAD commit SHA
env:
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
cd "${GITHUB_WORKSPACE}"
mkdir clang-tidy-output
cd clang-tidy-output
echo "$HEAD_SHA" > commit-sha.txt
- name: Fetch PR diff
if: ${{ github.event_name == 'pull_request' }}
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
cd "${GITHUB_WORKSPACE}"
wget -O pr.diff "https://patch-diff.githubusercontent.com/raw/pytorch/pytorch/pull/$PR_NUMBER.diff"
- name: Generate build files
run: |
cd "${GITHUB_WORKSPACE}"
python3 -m tools.linter.clang_tidy.generate_build_files
- name: Run PR clang-tidy
if: ${{ github.event_name == 'pull_request' }}
run: |
cd "${GITHUB_WORKSPACE}"
# The Docker image has our custom build, so we don't need to install it
python3 -m tools.linter.clang_tidy \
--clang-tidy-exe "$(which clang-tidy)" \
--diff-file pr.diff \
--disable-progress-bar 2>&1 | tee "${GITHUB_WORKSPACE}"/clang-tidy-output.txt
# Run clang-tidy on a smaller subset of the codebase on master until we
# make the repository clang-tidy clean
- name: Run master clang-tidy
run: |
cd "${GITHUB_WORKSPACE}"
python3 -m tools.linter.clang_tidy \
--paths \
torch/csrc/cuda \
torch/csrc/fx \
torch/csrc/utils \
torch/csrc/generic \
torch/csrc/deploy \
torch/csrc/onnx \
torch/csrc/tensor \
--clang-tidy-exe "$(which clang-tidy)" \
--disable-progress-bar 2>&1 | tee -a "${GITHUB_WORKSPACE}"/clang-tidy-output.txt
- name: Annotate output
if: ${{ github.event_name == 'pull_request' }}
env:
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
cd "${GITHUB_WORKSPACE}"
sed --in-place 's/^\.\.\///g' clang-tidy-output.txt
tools/linter/translate_annotations.py \
--file=clang-tidy-output.txt \
--regex='^(?P<filename>.*?):(?P<lineNumber>\d+):(?P<columnNumber>\d+): (?P<errorDesc>.*?) \[(?P<errorCode>.*)\]' \
--commit="$HEAD_SHA" \
> clang-tidy-output/annotations.json
- name: Check for warnings
run: |
cd "${GITHUB_WORKSPACE}"
set -eu
cat "${GITHUB_WORKSPACE}"/clang-tidy-output.txt
if grep -Fq "Warnings detected!" "${GITHUB_WORKSPACE}"/clang-tidy-output.txt; then
echo 'Please fix the above clang-tidy warnings.'
false
fi
- name: Add annotations
# Don't run on forked pull requests
if: ${{ failure() && github.event.pull_request.head.repo.full_name == github.repository }}
uses: pytorch/add-annotations-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
check_name: 'clang-tidy'
linter_output_path: clang-tidy/annotations.json
commit_sha: ${{ github.event.pull_request.head.sha }}
mode: json
cmakelint:
name: cmakelint
runs-on: ubuntu-18.04
steps:
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.x
architecture: x64
# [see note: pytorch repo ref]
- name: Checkout PyTorch
uses: pytorch/pytorch/.github/actions/checkout-pytorch@master
with:
submodules: false
- name: Install dependencies
run: |
set -eux
pip3 install cmakelint==1.4.1 --user
cmakelint --version
- name: Run cmakelint
run: |
set -eux
git ls-files -z -- bootstrap '*.cmake' '*.cmake.in' '*CMakeLists.txt' | \
grep -E -z -v '^(cmake/Modules/|cmake/Modules_CUDA_fix/|cmake/Caffe2Config.cmake.in|aten/src/ATen/ATenConfig.cmake.in|cmake/Caffe2ConfigVersion.cmake.in|cmake/TorchConfig.cmake.in|cmake/TorchConfigVersion.cmake.in|cmake/cmake_uninstall.cmake.in)' | \
xargs -0 cmakelint --config=.cmakelintrc --spaces=2 --quiet
mypy:
name: mypy
runs-on: ubuntu-18.04
steps:
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.8
architecture: x64
# [see note: pytorch repo ref]
- name: Checkout PyTorch
uses: pytorch/pytorch/.github/actions/checkout-pytorch@master
with:
submodules: false
- name: Install dependencies
run: |
set -eux
python3 -mpip install -r requirements.txt --user
python3 -mpip install numpy==1.20 --user # https://github.com/pytorch/pytorch/pull/60472
python3 -mpip install expecttest==0.1.3 mypy==0.812 --user
# Needed to check tools/render_junit.py
python3 -mpip install junitparser==2.1.1 rich==10.9.0 --user
- name: Run autogen
run: |
set -eux
time python3 -mtools.generate_torch_version --is_debug=false
time python3 -mtools.codegen.gen -s aten/src/ATen -d build/aten/src/ATen
time python3 -mtools.pyi.gen_pyi --native-functions-path aten/src/ATen/native/native_functions.yaml --deprecated-functions-path "tools/autograd/deprecated.yaml"
- name: Run mypy
env:
MYPY_FORCE_COLOR: 1
TERM: xterm-color
run: |
set -eux
STATUS=
for CONFIG in mypy*.ini; do
if ! python3 -mmypy --config="$CONFIG"; then
STATUS=fail
fi
done
if [ -n "$STATUS" ]; then
echo 'Please fix the above mypy warnings.'
false
fi
test-tools: test-tools:
name: Test tools name: Test tools
if: ${{ github.repository == 'pytorch/pytorch' }} if: ${{ github.repository == 'pytorch/pytorch' }}
@ -563,6 +267,10 @@ jobs:
set -eux set -eux
python3 -mpip install -r requirements.txt python3 -mpip install -r requirements.txt
python3 -mpip install boto3==1.16.34 python3 -mpip install boto3==1.16.34
pip3 install typing-extensions==3.10 --user
pip3 install -r requirements-flake8.txt --user
python3 -mpip install -r requirements.txt --user
python3 -mpip install mypy==0.812 --user
make setup_lint make setup_lint
- name: Test tools - name: Test tools
run: | run: |

View File

@ -1,5 +1,6 @@
# This makefile does nothing but delegating the actual building to cmake. # This makefile does nothing but delegating the actual building to cmake.
PYTHON = python3 PYTHON = python3
PIP = pip3
all: all:
@mkdir -p build && cd build && cmake .. $(shell $(PYTHON) ./scripts/get_python_cmake_flags.py) && $(MAKE) @mkdir -p build && cd build && cmake .. $(shell $(PYTHON) ./scripts/get_python_cmake_flags.py) && $(MAKE)
@ -51,12 +52,7 @@ shellcheck:
--job 'shellcheck' --job 'shellcheck'
setup_lint: setup_lint:
$(PYTHON) tools/actions_local_runner.py --file .github/workflows/lint.yml \ $(PIP) install lintrunner
--job 'flake8-py3' --step 'Install dependencies' --no-quiet
$(PYTHON) tools/actions_local_runner.py --file .github/workflows/lint.yml \
--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
$(PYTHON) tools/actions_local_runner.py --file .github/workflows/lint.yml \ $(PYTHON) tools/actions_local_runner.py --file .github/workflows/lint.yml \
--job 'shellcheck' --step 'Install Jinja2' --no-quiet --job 'shellcheck' --step 'Install Jinja2' --no-quiet
@ -71,8 +67,6 @@ setup_lint:
--job 'shellcheck' --step 'Install ShellCheck' --no-quiet; \ --job 'shellcheck' --step 'Install ShellCheck' --no-quiet; \
fi fi
$(PYTHON) -mpip install jinja2 --user $(PYTHON) -mpip install jinja2 --user
$(PYTHON) -mpip install -r tools/linter/clang_tidy/requirements.txt --user
$(PYTHON) -m tools.linter.install.clang_tidy
quick_checks: quick_checks:
# TODO: This is broken when 'git config submodule.recurse' is 'true' since the # TODO: This is broken when 'git config submodule.recurse' is 'true' since the
@ -80,41 +74,7 @@ quick_checks:
@$(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' \
--step 'Ensure no trailing spaces' \ --step 'Ensure no versionless Python shebangs'
--step 'Ensure no tabs' \
--step 'Ensure no non-breaking spaces' \
--step 'Ensure canonical include' \
--step 'Ensure no versionless Python shebangs' \
--step 'Ensure no unqualified noqa' \
--step 'Ensure GitHub PyPi dependencies are pinned' \
--step 'Ensure no unqualified type ignore' \
--step 'Ensure no direct cub include' \
--step 'Ensure correct trailing newlines' \
--step 'Ensure no raw cuda api calls'
flake8:
@$(PYTHON) tools/actions_local_runner.py \
$(CHANGED_ONLY) \
$(REF_BRANCH) \
--job 'flake8-py3'
mypy:
@$(PYTHON) tools/actions_local_runner.py \
$(CHANGED_ONLY) \
$(REF_BRANCH) \
--job 'mypy'
cmakelint:
@$(PYTHON) tools/actions_local_runner.py \
--file .github/workflows/lint.yml \
--job 'cmakelint' \
--step 'Run cmakelint'
clang-tidy:
@$(PYTHON) tools/actions_local_runner.py \
$(CHANGED_ONLY) \
$(REF_BRANCH) \
--job 'clang-tidy'
toc: toc:
@$(PYTHON) tools/actions_local_runner.py \ @$(PYTHON) tools/actions_local_runner.py \
@ -122,7 +82,9 @@ toc:
--job 'toc' \ --job 'toc' \
--step "Regenerate ToCs and check that they didn't change" --step "Regenerate ToCs and check that they didn't change"
lint: flake8 mypy quick_checks cmakelint shellcheck lint: quick_checks shellcheck
lintrunner
quicklint: CHANGED_ONLY=--changed-only quicklint: CHANGED_ONLY=--changed-only
quicklint: mypy flake8 quick_checks cmakelint shellcheck clang-tidy quicklint: quick_checks shellcheck
lintrunner

View File

@ -58,7 +58,7 @@ def main() -> None:
gha_expressions_found = False gha_expressions_found = False
for p in Path('.github/workflows').iterdir(): for p in Path('.github/workflows').iterdir():
with open(p) as f: with open(p, "rb") as f:
workflow = yaml.safe_load(f) workflow = yaml.safe_load(f)
for job_name, job in workflow['jobs'].items(): for job_name, job in workflow['jobs'].items():

View File

@ -45,7 +45,7 @@ if __name__ == "__main__":
"Package {package_name} did not have a version specified. " "Package {package_name} did not have a version specified. "
"Please specify a version to product a consistent linting experience." "Please specify a version to product a consistent linting experience."
) )
pip_args = ["pip3", "install", "--user"] pip_args = ["pip3", "install"]
pip_args.extend(args.packages) pip_args.extend(args.packages)
dry_run = args.dry_run == "1" dry_run = args.dry_run == "1"

View File

@ -47,16 +47,6 @@ if sys.version_info >= (3, 8):
class TestEndToEnd(unittest.TestCase): class TestEndToEnd(unittest.TestCase):
expected = [ expected = [
"cmakelint: Run cmakelint",
"quick-checks: Ensure no direct cub include",
"quick-checks: Ensure no unqualified type ignore",
"quick-checks: Ensure no unqualified noqa",
"quick-checks: Ensure canonical include",
"quick-checks: Ensure no non-breaking spaces",
"quick-checks: Ensure no tabs",
"flake8",
"quick-checks: Ensure correct trailing newlines",
"quick-checks: Ensure no trailing spaces",
"shellcheck: Regenerate workflows", "shellcheck: Regenerate workflows",
"shellcheck: Assert that regenerating the workflows didn't change them", "shellcheck: Assert that regenerating the workflows didn't change them",
"shellcheck: Extract scripts from GitHub Actions workflows", "shellcheck: Extract scripts from GitHub Actions workflows",
@ -73,8 +63,6 @@ if sys.version_info >= (3, 8):
for line in self.expected: for line in self.expected:
self.assertIn(line, stdout) self.assertIn(line, stdout)
self.assertIn("mypy", stdout)
def test_quicklint(self): def test_quicklint(self):
cmd = ["make", "quicklint", "-j", str(multiprocessing.cpu_count())] cmd = ["make", "quicklint", "-j", str(multiprocessing.cpu_count())]
proc = subprocess.run( proc = subprocess.run(
@ -85,9 +73,6 @@ if sys.version_info >= (3, 8):
for line in self.expected: for line in self.expected:
self.assertIn(line, stdout) self.assertIn(line, stdout)
# TODO: See https://github.com/pytorch/pytorch/issues/57967
self.assertIn("mypy (skipped typestub generation)", stdout)
class TestQuicklint(unittest.IsolatedAsyncioTestCase): class TestQuicklint(unittest.IsolatedAsyncioTestCase):
test_files = [ test_files = [
os.path.join("caffe2", "some_cool_file.py"), os.path.join("caffe2", "some_cool_file.py"),
@ -147,45 +132,6 @@ if sys.version_info >= (3, 8):
self.assertIn("SC2148: Tips depend on target shell", f.getvalue()) self.assertIn("SC2148: Tips depend on target shell", f.getvalue())
self.assertIn("SC2283: Remove spaces around = to assign", f.getvalue()) self.assertIn("SC2283: Remove spaces around = to assign", f.getvalue())
async def test_mypy(self):
self.maxDiff = None
f = io.StringIO()
with contextlib.redirect_stdout(f):
# Quicklint assumes this has been run already and doesn't work
# without it
_, _, _ = await actions_local_runner.shell_cmd(
[
f"{sys.executable}",
"tools/actions_local_runner.py",
"--job",
"mypy",
"--file",
".github/workflows/lint.yml",
"--step",
"Run autogen",
],
redirect=True,
)
await actions_local_runner.Mypy(self.test_py_files, True).run()
# Should exclude the aten/ file; also, apparently mypy
# typechecks files in reverse order
expected = textwrap.dedent(
"""
x mypy (skipped typestub generation)
torch/some_stubs.pyi:3:17: error: Incompatible types in assignment (expression has type "None", variable has type "str") [assignment]
torch/some_stubs.pyi:4:17: error: Incompatible types in assignment (expression has type "float", variable has type "str") [assignment]
torch/some_cool_file.py:3:17: error: Incompatible types in assignment (expression has type "None", variable has type "str") [assignment]
torch/some_cool_file.py:4:17: error: Incompatible types in assignment (expression has type "float", variable has type "str") [assignment]
caffe2/some_cool_file.py:3:17: error: Incompatible types in assignment (expression has type "None", variable has type "str") [assignment]
caffe2/some_cool_file.py:4:17: error: Incompatible types in assignment (expression has type "float", variable has type "str") [assignment]
""" # noqa: B950
).lstrip(
"\n"
)
self.assertEqual(expected, f.getvalue())
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()