formatting.sh 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. #!/usr/bin/env bash
  2. # YAPF formatter, adapted from ray and skypilot.
  3. #
  4. # Usage:
  5. # # Do work and commit your work.
  6. # # Format files that differ from origin/main.
  7. # bash formatting.sh
  8. # # Commit changed files with message 'Run yapf and ruff'
  9. #
  10. #
  11. # YAPF + Clang formatter (if installed). This script formats all changed files from the last mergebase.
  12. # You are encouraged to run this locally before pushing changes for review.
  13. # Cause the script to exit if a single command fails
  14. set -eo pipefail
  15. # this stops git rev-parse from failing if we run this from the .git directory
  16. builtin cd "$(dirname "${BASH_SOURCE:-$0}")"
  17. ROOT="$(git rev-parse --show-toplevel)"
  18. builtin cd "$ROOT" || exit 1
  19. YAPF_VERSION=$(yapf --version | awk '{print $2}')
  20. RUFF_VERSION=$(ruff --version | awk '{print $2}')
  21. MYPY_VERSION=$(mypy --version | awk '{print $2}')
  22. CODESPELL_VERSION=$(codespell --version)
  23. # # params: tool name, tool version, required version
  24. tool_version_check() {
  25. if [[ $2 != $3 ]]; then
  26. echo "Wrong $1 version installed: $3 is required, not $2."
  27. exit 1
  28. fi
  29. }
  30. tool_version_check "yapf" $YAPF_VERSION "$(grep yapf requirements-dev.txt | cut -d'=' -f3)"
  31. tool_version_check "ruff" $RUFF_VERSION "$(grep "ruff==" requirements-dev.txt | cut -d'=' -f3)"
  32. tool_version_check "mypy" "$MYPY_VERSION" "$(grep mypy requirements-dev.txt | cut -d'=' -f3)"
  33. tool_version_check "codespell" "$CODESPELL_VERSION" "$(grep codespell requirements-dev.txt | cut -d'=' -f3)"
  34. YAPF_FLAGS=(
  35. '--recursive'
  36. '--parallel'
  37. )
  38. YAPF_EXCLUDES=(
  39. '--exclude' 'build/**'
  40. )
  41. # Format specified files
  42. format() {
  43. yapf --in-place "${YAPF_FLAGS[@]}" "$@"
  44. }
  45. # Format files that differ from main branch. Ignores dirs that are not slated
  46. # for autoformat yet.
  47. format_changed() {
  48. # The `if` guard ensures that the list of filenames is not empty, which
  49. # could cause yapf to receive 0 positional arguments, making it hang
  50. # waiting for STDIN.
  51. #
  52. # `diff-filter=ACM` and $MERGEBASE is to ensure we only format files that
  53. # exist on both branches.
  54. MERGEBASE="$(git merge-base origin/main HEAD)"
  55. if ! git diff --diff-filter=ACM --quiet --exit-code "$MERGEBASE" -- '*.py' '*.pyi' &>/dev/null; then
  56. git diff --name-only --diff-filter=ACM "$MERGEBASE" -- '*.py' '*.pyi' | xargs -P 5 \
  57. yapf --in-place "${YAPF_EXCLUDES[@]}" "${YAPF_FLAGS[@]}"
  58. fi
  59. }
  60. # Format all files
  61. format_all() {
  62. yapf --in-place "${YAPF_FLAGS[@]}" "${YAPF_EXCLUDES[@]}" .
  63. }
  64. ## This flag formats individual files. --files *must* be the first command line
  65. ## arg to use this option.
  66. if [[ "$1" == '--files' ]]; then
  67. format "${@:2}"
  68. # If `--all` is passed, then any further arguments are ignored and the
  69. # entire python directory is formatted.
  70. elif [[ "$1" == '--all' ]]; then
  71. format_all
  72. else
  73. # Format only the files that changed in last commit.
  74. format_changed
  75. fi
  76. echo 'Aphrodite yapf: Done'
  77. CODESPELL_EXCLUDES=(
  78. '--skip' '*docs/source/_build/**'
  79. )
  80. # check spelling of specified files
  81. spell_check() {
  82. codespell "$@"
  83. }
  84. spell_check_all(){
  85. codespell --toml pyproject.toml "${CODESPELL_EXCLUDES[@]}"
  86. }
  87. # Spelling check of files that differ from main branch.
  88. spell_check_changed() {
  89. # The `if` guard ensures that the list of filenames is not empty, which
  90. # could cause ruff to receive 0 positional arguments, making it hang
  91. # waiting for STDIN.
  92. #
  93. # `diff-filter=ACM` and $MERGEBASE is to ensure we only lint files that
  94. # exist on both branches.
  95. MERGEBASE="$(git merge-base origin/main HEAD)"
  96. if ! git diff --diff-filter=ACM --quiet --exit-code "$MERGEBASE" -- '*.py' '*.pyi' &>/dev/null; then
  97. git diff --name-only --diff-filter=ACM "$MERGEBASE" -- '*.py' '*.pyi' | xargs \
  98. codespell "${CODESPELL_EXCLUDES[@]}"
  99. fi
  100. }
  101. # Run Codespell
  102. ## This flag runs spell check of individual files. --files *must* be the first command line
  103. ## arg to use this option.
  104. if [[ "$1" == '--files' ]]; then
  105. spell_check "${@:2}"
  106. # If `--all` is passed, then any further arguments are ignored and the
  107. # entire python directory is linted.
  108. elif [[ "$1" == '--all' ]]; then
  109. spell_check_all
  110. else
  111. # Check spelling only of the files that changed in last commit.
  112. spell_check_changed
  113. fi
  114. echo 'Aphrodite codespell: Done'
  115. # Lint specified files
  116. lint() {
  117. ruff "$@"
  118. }
  119. # Lint files that differ from main branch. Ignores dirs that are not slated
  120. # for autolint yet.
  121. lint_changed() {
  122. # The `if` guard ensures that the list of filenames is not empty, which
  123. # could cause ruff to receive 0 positional arguments, making it hang
  124. # waiting for STDIN.
  125. #
  126. # `diff-filter=ACM` and $MERGEBASE is to ensure we only lint files that
  127. # exist on both branches.
  128. MERGEBASE="$(git merge-base origin/main HEAD)"
  129. if ! git diff --diff-filter=ACM --quiet --exit-code "$MERGEBASE" -- '*.py' '*.pyi' &>/dev/null; then
  130. git diff --name-only --diff-filter=ACM "$MERGEBASE" -- '*.py' '*.pyi' | xargs \
  131. ruff
  132. fi
  133. }
  134. # Run Ruff
  135. echo 'Aphrodite ruff:'
  136. ### This flag lints individual files. --files *must* be the first command line
  137. ### arg to use this option.
  138. if [[ "$1" == '--files' ]]; then
  139. lint "${@:2}"
  140. # If `--all` is passed, then any further arguments are ignored and the
  141. # entire python directory is linted.
  142. elif [[ "$1" == '--all' ]]; then
  143. lint aphrodite tests
  144. else
  145. # Format only the files that changed in last commit.
  146. lint_changed
  147. fi
  148. if ! git diff --quiet &>/dev/null; then
  149. echo 'Reformatted files. Please review and stage the changes.'
  150. echo 'Changes not staged for commit:'
  151. echo
  152. git --no-pager diff --name-only
  153. exit 1
  154. fi