Skip to content
Snippets Groups Projects
lint.sh 4.02 KiB
Newer Older
  • Learn to ignore specific revisions
  • #
    # Runs linting scripts over the local Synapse checkout
    # black - opinionated code formatter
    
    # ruff - lints and finds mistakes
    
    usage() {
      echo
      echo "Usage: $0 [-h] [-d] [paths...]"
      echo
      echo "-d"
      echo "  Lint files that have changed since the last git commit."
      echo
      echo "  If paths are provided and this option is set, both provided paths and those"
      echo "  that have changed since the last commit will be linted."
      echo
      echo "  If no paths are provided and this option is not set, all files will be linted."
      echo
      echo "  Note that paths with a file extension that is not '.py' will be excluded."
      echo "-h"
      echo "  Display this help text."
    }
    
    USING_DIFF=0
    files=()
    
    while getopts ":dh" opt; do
      case $opt in
        d)
          USING_DIFF=1
          ;;
        h)
          usage
          exit
          ;;
        \?)
          echo "ERROR: Invalid option: -$OPTARG" >&2
          usage
          exit
          ;;
      esac
    done
    
    # Strip any options from the command line arguments now that
    # we've finished processing them
    shift "$((OPTIND-1))"
    
    if [ $USING_DIFF -eq 1 ]; then
      # Check both staged and non-staged changes
      for path in $(git diff HEAD --name-only); do
        filename=$(basename "$path")
        file_extension="${filename##*.}"
    
        # If an extension is present, and it's something other than 'py',
        # then ignore this file
        if [[ -n ${file_extension+x} && $file_extension != "py" ]]; then
          continue
        fi
    
        # Append this path to our list of files to lint
        files+=("$path")
      done
    fi
    
    # Append any remaining arguments as files to lint
    files+=("$@")
    
    if [[ $USING_DIFF -eq 1 ]]; then
      # If we were asked to lint changed files, and no paths were found as a result...
      if [ ${#files[@]} -eq 0 ]; then
        # Then print and exit
        echo "No files found to lint."
        exit 0
      fi
    
      # If we were not asked to lint changed files, and no paths were found as a result,
      # then lint everything!
      if [[ -z ${files+x} ]]; then
    
          # CI runs each linter on the entire checkout, e.g. `black .`. So don't
          # rely on this list to *find* lint targets if that misses a file; instead;
          # use it to exclude files from linters when this can't be done by config.
          #
          # To check which files the linters examine, use:
          #     black --verbose . 2>&1 | \grep -v ignored
          #     isort --show-files .
          #     flake8 --verbose .  # This isn't a great option
          #     mypy has explicit config in mypy.ini; there is also mypy --verbose
          files=(
              "synapse" "docker" "tests"
              "scripts-dev"
    
              "contrib" "synmark" "stubs" ".ci"
    
    echo "Linting these paths: ${files[*]}"
    echo
    
    # Print out the commands being run
    set -x
    
    
    # Ensure the sort order of imports.
    
    
    # Ensure Python code conforms to an opinionated style.
    
    
    # Ensure the sample configuration file conforms to style checks.
    
    ./scripts-dev/config-lint.sh
    
    
    # Catch any common programming mistakes in Python code.
    
    # --quiet suppresses the update check.
    ruff --quiet "${files[@]}"
    
    
    # Catch any common programming mistakes in Rust code.
    #
    # --bins, --examples, --lib, --tests combined explicitly disable checking
    # the benchmarks, which can fail due to `#![feature]` macros not being
    # allowed on the stable rust toolchain (rustc error E0554).
    #
    # --allow-staged and --allow-dirty suppress clippy raising errors
    # for uncommitted files. Only needed when using --fix.
    #
    # -D warnings disables the "warnings" lint.
    #
    # Using --fix has a tendency to cause subsequent runs of clippy to recompile
    # rust code, which can slow down this script. Thus we run clippy without --fix
    # first which is quick, and then re-run it with --fix if an error was found.
    if ! cargo-clippy --bins --examples --lib --tests -- -D warnings > /dev/null 2>&1; then
      cargo-clippy \
        --bins --examples --lib --tests --allow-staged --allow-dirty --fix -- -D warnings
    fi
    
    # Ensure the formatting of Rust code.
    cargo-fmt
    
    # Ensure all Pydantic models use strict types.
    
    ./scripts-dev/check_pydantic_models.py lint
    
    
    # Ensure type hints are correct.