check.sh 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #!/bin/bash
  2. # Copyright 2019 Google
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. # Checks that the current state of the tree is sane and optionally auto-fixes
  16. # errors automatically. Meant for interactive use.
  17. function usage() {
  18. cat <<EOF
  19. USAGE: scripts/check.sh [--allow-dirty] [--commit] [<revision>]
  20. Runs auto-formatting scripts, source-tree checks, and linters on any files that
  21. have changed since master.
  22. By default, any changes are left as uncommited changes in the working tree. You
  23. can review them with git diff. Pass --commit to automatically commit any changes.
  24. Pass an alternate revision to use as the basis for checking changes.
  25. OPTIONS:
  26. --allow-dirty
  27. By default, check.sh requires a clean working tree to keep any generated
  28. changes separate from logical changes.
  29. --commit
  30. Commit any auto-generated changes with a message indicating which tool made
  31. the changes.
  32. --amend
  33. Commit any auto-generated changes by amending the HEAD commit.
  34. --fixup
  35. Commit any auto-generated changes with a fixup! message for the HEAD
  36. commit. The next rebase will squash these fixup commits.
  37. --test-only
  38. Run all checks without making any changes to local files.
  39. <revision>
  40. Specifies a starting revision other than the default of master.
  41. EXAMPLES:
  42. check.sh
  43. Runs automated checks and formatters on all changed files since master.
  44. Check for changes with git diff.
  45. check.sh --commit
  46. Runs automated checks and formatters on all changed files since master and
  47. commits the results.
  48. check.sh --amend HEAD
  49. Runs automated checks and formatters on all changed files since the last
  50. commit and amends the last commit with the difference.
  51. check.sh --allow-dirty HEAD
  52. Runs automated checks and formatters on all changed files since the last
  53. commit and intermingles the changes with any pending changes. Useful for
  54. interactive use from an editor.
  55. EOF
  56. }
  57. set -euo pipefail
  58. unset CDPATH
  59. # Change to the top-directory of the working tree
  60. top_dir=$(git rev-parse --show-toplevel)
  61. cd "${top_dir}"
  62. ALLOW_DIRTY=false
  63. COMMIT_METHOD="none"
  64. START_REVISION="master"
  65. TEST_ONLY=false
  66. while [[ $# -gt 0 ]]; do
  67. case "$1" in
  68. --)
  69. # Do nothing: explicitly allow this, but ignore it
  70. ;;
  71. -h | --help)
  72. usage
  73. exit 1
  74. ;;
  75. --allow-dirty)
  76. ALLOW_DIRTY=true
  77. ;;
  78. --amend)
  79. COMMIT_METHOD=amend
  80. ;;
  81. --fixup)
  82. COMMIT_METHOD=fixup
  83. ;;
  84. --commit)
  85. COMMIT_METHOD=message
  86. ;;
  87. --test-only)
  88. # In test-only mode, no changes are made, so there's no reason to
  89. # require a clean source tree.
  90. ALLOW_DIRTY=true
  91. TEST_ONLY=true
  92. ;;
  93. *)
  94. if git rev-parse "$1" >& /dev/null; then
  95. START_REVISION="$1"
  96. break
  97. fi
  98. ;;
  99. esac
  100. shift
  101. done
  102. if [[ "${TEST_ONLY}" == true && "${COMMIT_METHOD}" != "none" ]]; then
  103. echo "--test-only cannot be combined with --amend, --fixup, or --commit"
  104. exit 1
  105. fi
  106. if [[ "${ALLOW_DIRTY}" == true && "${COMMIT_METHOD}" == "message" ]]; then
  107. echo "--allow-dirty and --commit are mutually exclusive"
  108. exit 1
  109. fi
  110. if ! git diff-index --quiet HEAD --; then
  111. if [[ "${ALLOW_DIRTY}" != true ]]; then
  112. echo "You have local changes that could be overwritten by this script."
  113. echo "Please commit your changes first or pass --allow-dirty."
  114. exit 2
  115. fi
  116. fi
  117. # Record actual start, but only if the revision is specified as a single
  118. # commit. Ranges specified with .. or ... are left alone.
  119. if [[ "${START_REVISION}" == *..* ]]; then
  120. START_SHA="${START_REVISION}"
  121. else
  122. START_SHA=$(git rev-parse "${START_REVISION}")
  123. fi
  124. # If committing --fixup, avoid messages with fixup! fixup! that might come from
  125. # multiple fixup commits.
  126. HEAD_SHA=$(git rev-parse HEAD)
  127. function maybe_commit() {
  128. local message="$1"
  129. if [[ "${COMMIT_METHOD}" == "none" ]]; then
  130. return
  131. fi
  132. echo "${message}"
  133. case "${COMMIT_METHOD}" in
  134. amend)
  135. git commit -a --amend -C "${HEAD_SHA}"
  136. ;;
  137. fixup)
  138. git commit -a --fixup="${HEAD_SHA}"
  139. ;;
  140. message)
  141. git commit -a -m "${message}"
  142. ;;
  143. *)
  144. echo "Unknown commit method ${COMMIT_METHOD}" 1>&2
  145. exit 2
  146. ;;
  147. esac
  148. }
  149. style_cmd=("${top_dir}/scripts/style.sh")
  150. if [[ "${TEST_ONLY}" == true ]]; then
  151. style_cmd+=(test-only)
  152. fi
  153. style_cmd+=("${START_SHA}")
  154. # Restyle and commit any changes
  155. "${style_cmd[@]}"
  156. if ! git diff --quiet; then
  157. maybe_commit "style.sh generated changes"
  158. fi
  159. # If there are changes to the Firestore project, ensure they're ordered
  160. # correctly to minimize conflicts.
  161. if ! git diff --quiet "${START_SHA}" -- Firestore; then
  162. "${top_dir}/scripts/sync_project.rb"
  163. if ! git diff --quiet; then
  164. maybe_commit "sync_project.rb generated changes"
  165. fi
  166. fi
  167. # Check lint errors.
  168. "${top_dir}/scripts/check_whitespace.sh"
  169. "${top_dir}/scripts/check_copyright.sh"
  170. "${top_dir}/scripts/check_no_module_imports.sh"
  171. "${top_dir}/scripts/check_test_inclusion.py"
  172. # Google C++ style
  173. "${top_dir}/scripts/lint.sh" "${START_SHA}"