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