lint.sh 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #!/usr/bin/env bash
  2. #
  3. # Runs linting scripts over the local Synapse checkout
  4. # black - opinionated code formatter
  5. # ruff - lints and finds mistakes
  6. set -e
  7. usage() {
  8. echo
  9. echo "Usage: $0 [-h] [-d] [paths...]"
  10. echo
  11. echo "-d"
  12. echo " Lint files that have changed since the last git commit."
  13. echo
  14. echo " If paths are provided and this option is set, both provided paths and those"
  15. echo " that have changed since the last commit will be linted."
  16. echo
  17. echo " If no paths are provided and this option is not set, all files will be linted."
  18. echo
  19. echo " Note that paths with a file extension that is not '.py' will be excluded."
  20. echo "-h"
  21. echo " Display this help text."
  22. }
  23. USING_DIFF=0
  24. files=()
  25. while getopts ":dh" opt; do
  26. case $opt in
  27. d)
  28. USING_DIFF=1
  29. ;;
  30. h)
  31. usage
  32. exit
  33. ;;
  34. \?)
  35. echo "ERROR: Invalid option: -$OPTARG" >&2
  36. usage
  37. exit
  38. ;;
  39. esac
  40. done
  41. # Strip any options from the command line arguments now that
  42. # we've finished processing them
  43. shift "$((OPTIND-1))"
  44. if [ $USING_DIFF -eq 1 ]; then
  45. # Check both staged and non-staged changes
  46. for path in $(git diff HEAD --name-only); do
  47. filename=$(basename "$path")
  48. file_extension="${filename##*.}"
  49. # If an extension is present, and it's something other than 'py',
  50. # then ignore this file
  51. if [[ -n ${file_extension+x} && $file_extension != "py" ]]; then
  52. continue
  53. fi
  54. # Append this path to our list of files to lint
  55. files+=("$path")
  56. done
  57. fi
  58. # Append any remaining arguments as files to lint
  59. files+=("$@")
  60. if [[ $USING_DIFF -eq 1 ]]; then
  61. # If we were asked to lint changed files, and no paths were found as a result...
  62. if [ ${#files[@]} -eq 0 ]; then
  63. # Then print and exit
  64. echo "No files found to lint."
  65. exit 0
  66. fi
  67. else
  68. # If we were not asked to lint changed files, and no paths were found as a result,
  69. # then lint everything!
  70. if [[ -z ${files+x} ]]; then
  71. # CI runs each linter on the entire checkout, e.g. `black .`. So don't
  72. # rely on this list to *find* lint targets if that misses a file; instead;
  73. # use it to exclude files from linters when this can't be done by config.
  74. #
  75. # To check which files the linters examine, use:
  76. # black --verbose . 2>&1 | \grep -v ignored
  77. # isort --show-files .
  78. # flake8 --verbose . # This isn't a great option
  79. # mypy has explicit config in mypy.ini; there is also mypy --verbose
  80. files=(
  81. "synapse" "docker" "tests"
  82. "scripts-dev"
  83. "contrib" "synmark" "stubs" ".ci"
  84. "dev-docs"
  85. )
  86. fi
  87. fi
  88. echo "Linting these paths: ${files[*]}"
  89. echo
  90. # Print out the commands being run
  91. set -x
  92. # Ensure the sort order of imports.
  93. isort "${files[@]}"
  94. # Ensure Python code conforms to an opinionated style.
  95. python3 -m black "${files[@]}"
  96. # Ensure the sample configuration file conforms to style checks.
  97. ./scripts-dev/config-lint.sh
  98. # Catch any common programming mistakes in Python code.
  99. # --quiet suppresses the update check.
  100. ruff --quiet --fix "${files[@]}"
  101. # Catch any common programming mistakes in Rust code.
  102. #
  103. # --bins, --examples, --lib, --tests combined explicitly disable checking
  104. # the benchmarks, which can fail due to `#![feature]` macros not being
  105. # allowed on the stable rust toolchain (rustc error E0554).
  106. #
  107. # --allow-staged and --allow-dirty suppress clippy raising errors
  108. # for uncommitted files. Only needed when using --fix.
  109. #
  110. # -D warnings disables the "warnings" lint.
  111. #
  112. # Using --fix has a tendency to cause subsequent runs of clippy to recompile
  113. # rust code, which can slow down this script. Thus we run clippy without --fix
  114. # first which is quick, and then re-run it with --fix if an error was found.
  115. if ! cargo-clippy --bins --examples --lib --tests -- -D warnings > /dev/null 2>&1; then
  116. cargo-clippy \
  117. --bins --examples --lib --tests --allow-staged --allow-dirty --fix -- -D warnings
  118. fi
  119. # Ensure the formatting of Rust code.
  120. cargo-fmt
  121. # Ensure all Pydantic models use strict types.
  122. ./scripts-dev/check_pydantic_models.py lint
  123. # Ensure type hints are correct.
  124. mypy