| #!/bin/bash |
| # Copyright 2025 Google LLC |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| # Script to run gofmt, golint, and gazelle before committing. |
| # To install, use the following command: |
| # ./scripts/install_precommit.sh |
| |
| set -e |
| |
| SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}") |
| source "${SCRIPT_DIR}/infra/common.sh" || exit $? |
| source "${SCRIPT_DIR}/license_exemptions.sh" || exit $? |
| |
| cd "$(get_workspace_root)" |
| |
| # License header check. |
| echo "Checking for license headers..." |
| MISSING_LICENSE_HEADER_FILES=() |
| DUPLICATE_COPYRIGHT_FILES=() |
| MISSING_BLANK_LINE_FILES=() |
| for file in $(git ls-files); do |
| if [ ! -f "$file" ]; then |
| continue |
| fi |
| if ! requires_license_header "$file"; then |
| continue |
| fi |
| |
| HEADER=$(head -n 15 "$file") |
| # Check 1 & 2: Header content |
| if ! echo "$HEADER" | grep -q "Licensed under the Apache License, Version 2.0" || ! echo "$HEADER" | grep -q "Copyright.*Google LLC"; then |
| MISSING_LICENSE_HEADER_FILES+=("$file") |
| continue # Next file |
| fi |
| |
| # Check 3: Duplicate copyright |
| if [ $(grep -c -E "^(#|//)\s*Copyright" "$file") -gt 1 ]; then |
| DUPLICATE_COPYRIGHT_FILES+=("$file") |
| continue # Next file |
| fi |
| |
| # Check 4: Blank line after header |
| end_line_num=$(grep -n -E "(#|//) limitations under the License." "$file" | head -n 1 | cut -d: -f1) |
| if [ -n "$end_line_num" ]; then |
| line_num_after=$((end_line_num + 1)) |
| # Check if we are not at the end of the file |
| if [ "$line_num_after" -le $(wc -l < "$file") ]; then |
| line_after=$(sed -n "${line_num_after}p" "$file") |
| # Check if the line contains any non-whitespace characters |
| if [[ "$line_after" =~ [^[:space:]] ]]; then |
| MISSING_BLANK_LINE_FILES+=("$file") |
| continue # Next file |
| fi |
| fi |
| fi |
| done |
| |
| FAILING_FILES=() |
| if [ ${#MISSING_LICENSE_HEADER_FILES[@]} -ne 0 ]; then |
| echo -e "\033[0;31mError: License header or copyright notice is missing or incorrect in the following files:\033[0m" |
| for file in "${MISSING_LICENSE_HEADER_FILES[@]}"; do |
| echo " $file" |
| FAILING_FILES+=("$file") |
| done |
| fi |
| if [ ${#DUPLICATE_COPYRIGHT_FILES[@]} -ne 0 ]; then |
| echo -e "\033[0;31mError: Duplicate copyright notice in the following files:\033[0m" |
| for file in "${DUPLICATE_COPYRIGHT_FILES[@]}"; do |
| echo " $file" |
| FAILING_FILES+=("$file") |
| done |
| fi |
| if [ ${#MISSING_BLANK_LINE_FILES[@]} -ne 0 ]; then |
| echo -e "\033[0;31mError: Missing blank line after license header in the following files:\033[0m" |
| for file in "${MISSING_BLANK_LINE_FILES[@]}"; do |
| echo " $file" |
| FAILING_FILES+=("$file") |
| done |
| fi |
| |
| if [ ${#FAILING_FILES[@]} -ne 0 ]; then |
| echo -e "\033[0;33mTo fix these issues, run the following script, which will prompt to apply the necessary changes:\033[0m" |
| echo " ${SCRIPT_DIR}/fix_license_headers.sh ${FAILING_FILES[*]}" |
| exit 1 |
| fi |
| |
| echo "License header check passed." |
| |
| STAGED_GO_FILES=$(git diff --cached --name-only --diff-filter=d | grep ".go$" || true) |
| |
| # Ensures that non-interactive shell sessions can run Go tools |
| if command -v go &>/dev/null; then |
| export PATH="$PATH:$(go env GOPATH)/bin" |
| fi |
| |
| # Use downloaded version of bazel. |
| ./scripts/infra/bootstrap_prebuilts.sh |
| |
| # Run go mod tidy |
| run_go_mod_tidy |
| |
| GAZELLEPASS=true |
| echo Running Gazelle... |
| if ! run_bazel_tool //:gazelle; then |
| GAZELLEPASS=false |
| fi |
| |
| LINTPASS=true |
| echo Running gofmt... |
| run_bazel_tool @io_bazel_rules_go//go -- fmt ./... |
| |
| PASS=true |
| if ! $LINTPASS; then |
| printf "\033[0;30m\033[41mThere are lint errors. Please fix!\033[0m\n" |
| PASS=false |
| fi |
| |
| if ! $GAZELLEPASS; then |
| printf "\033[0;30m\033[41mbazel run //:gazelle failed. Please fix the errors and try again.\033[0m\n" |
| PASS=false |
| fi |
| |
| SKIP_DIFF_CHECK=false |
| for arg in "$@"; do |
| if [[ "$arg" == "--skip-diff-check" ]]; then |
| SKIP_DIFF_CHECK=true |
| break |
| fi |
| done |
| |
| if [ "$SKIP_DIFF_CHECK" = false ]; then |
| if ! git diff --exit-code &> /dev/null; then |
| printf "\033[0;30m\033[41mPrecommit made changes to source. Please check the changes and re-stage files.\033[0m\n" |
| echo "To bypass this git-diff check, pass --skip-diff-check to this script." |
| PASS=false |
| fi |
| fi |
| |
| if ! $PASS; then |
| printf "\033[0;30m\033[41mCOMMIT FAILED\033[0m\n" |
| exit 1 |
| else |
| printf "\033[0;30m\033[42mCOMMIT SUCCEEDED\033[0m\n" |
| fi |