check.sh 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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. VERBOSE=false
  67. # Default to verbose operation if this isn't an interactive build.
  68. if [[ ! -t 1 ]]; then
  69. VERBOSE=true
  70. fi
  71. while [[ $# -gt 0 ]]; do
  72. case "$1" in
  73. --)
  74. # Do nothing: explicitly allow this, but ignore it
  75. ;;
  76. -h | --help)
  77. usage
  78. exit 1
  79. ;;
  80. --allow-dirty)
  81. ALLOW_DIRTY=true
  82. ;;
  83. --amend)
  84. COMMIT_METHOD=amend
  85. ;;
  86. --fixup)
  87. COMMIT_METHOD=fixup
  88. ;;
  89. --commit)
  90. COMMIT_METHOD=message
  91. ;;
  92. --verbose)
  93. VERBOSE=true
  94. ;;
  95. --test-only)
  96. # In test-only mode, no changes are made, so there's no reason to
  97. # require a clean source tree.
  98. ALLOW_DIRTY=true
  99. TEST_ONLY=true
  100. ;;
  101. *)
  102. START_REVISION="$1"
  103. shift
  104. break
  105. ;;
  106. esac
  107. shift
  108. done
  109. if [[ "${TEST_ONLY}" == true && "${COMMIT_METHOD}" != "none" ]]; then
  110. echo "--test-only cannot be combined with --amend, --fixup, or --commit"
  111. exit 1
  112. fi
  113. if [[ "${ALLOW_DIRTY}" == true && "${COMMIT_METHOD}" == "message" ]]; then
  114. echo "--allow-dirty and --commit are mutually exclusive"
  115. exit 1
  116. fi
  117. if ! git diff-index --quiet HEAD --; then
  118. if [[ "${ALLOW_DIRTY}" != true ]]; then
  119. echo "You have local changes that could be overwritten by this script."
  120. echo "Please commit your changes first or pass --allow-dirty."
  121. exit 2
  122. fi
  123. fi
  124. # Show Travis-related environment variables, to help with debuging failures.
  125. if [[ "${VERBOSE}" == true ]]; then
  126. env | egrep '^TRAVIS_(BRANCH|COMMIT|PULL)' | sort || true
  127. fi
  128. # When travis clones a repo for building, it uses a shallow clone. When
  129. # building a branch it can sometimes give a revision range that refers to
  130. # commits that don't exist in the shallow clone. This has been observed in a
  131. # branch build where the branch only has a single commit. The cause of this
  132. # behavior is unclear but as a workaround ...
  133. if [[ "${START_REVISION}" == *..* ]]; then
  134. RANGE_START="${START_REVISION/..*/}"
  135. RANGE_END="${START_REVISION/*../}"
  136. # Figure out if we have access to master. If not add it to the repo.
  137. if ! git rev-parse origin/master >& /dev/null; then
  138. git remote set-branches --add origin master
  139. git fetch origin
  140. fi
  141. NEW_RANGE_START=$(git merge-base origin/master "${RANGE_END}")
  142. START_REVISION="${START_REVISION/$RANGE_START/$NEW_RANGE_START}"
  143. START_SHA="${START_REVISION}"
  144. else
  145. START_SHA=$(git rev-parse "${START_REVISION}")
  146. fi
  147. if [[ "${VERBOSE}" == true ]]; then
  148. echo "START_REVISION=$START_REVISION"
  149. echo "START_SHA=$START_SHA"
  150. fi
  151. # If committing --fixup, avoid messages with fixup! fixup! that might come from
  152. # multiple fixup commits.
  153. HEAD_SHA=$(git rev-parse HEAD)
  154. function maybe_commit() {
  155. local message="$1"
  156. if [[ "${COMMIT_METHOD}" == "none" ]]; then
  157. return
  158. fi
  159. echo "${message}"
  160. case "${COMMIT_METHOD}" in
  161. amend)
  162. git commit -a --amend -C "${HEAD_SHA}"
  163. ;;
  164. fixup)
  165. git commit -a --fixup="${HEAD_SHA}"
  166. ;;
  167. message)
  168. git commit -a -m "${message}"
  169. ;;
  170. *)
  171. echo "Unknown commit method ${COMMIT_METHOD}" 1>&2
  172. exit 2
  173. ;;
  174. esac
  175. }
  176. style_cmd=("${top_dir}/scripts/style.sh")
  177. if [[ "${TEST_ONLY}" == true ]]; then
  178. style_cmd+=(test-only)
  179. fi
  180. style_cmd+=("${START_SHA}")
  181. # Restyle and commit any changes
  182. "${style_cmd[@]}"
  183. if ! git diff --quiet; then
  184. maybe_commit "style.sh generated changes"
  185. fi
  186. # If there are changes to the Firestore project, ensure they're ordered
  187. # correctly to minimize conflicts.
  188. if ! git diff --quiet "${START_SHA}" -- Firestore; then
  189. "${top_dir}/scripts/sync_project.rb"
  190. if ! git diff --quiet; then
  191. maybe_commit "sync_project.rb generated changes"
  192. fi
  193. fi
  194. # Check lint errors.
  195. "${top_dir}/scripts/check_whitespace.sh"
  196. "${top_dir}/scripts/check_filename_spaces.sh"
  197. "${top_dir}/scripts/check_copyright.sh"
  198. "${top_dir}/scripts/check_no_module_imports.sh"
  199. "${top_dir}/scripts/check_test_inclusion.py"
  200. # Google C++ style
  201. "${top_dir}/scripts/lint.sh" "${START_SHA}"