| #!/usr/bin/env bash |
| |
| # |
| # Licensed to the Apache Software Foundation (ASF) under one or more |
| # contributor license agreements. See the NOTICE file distributed with |
| # this work for additional information regarding copyright ownership. |
| # The ASF licenses this file to You 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. |
| # |
| |
| SPARK_PROFILES=${1:-"-Pkubernetes -Pyarn -Pspark-ganglia-lgpl -Pkinesis-asl -Phive-thriftserver -Phive -Pvolcano -Pjvm-profiler -Phadoop-cloud -Pdocker-integration-tests -Pkubernetes-integration-tests"} |
| |
| # NOTE: echo "q" is needed because SBT prompts the user for input on encountering a build file |
| # with failure (either resolution or compilation); the "q" makes SBT quit. |
| ERRORS=$(echo -e "q\n" \ |
| | build/sbt \ |
| ${SPARK_PROFILES} \ |
| scalastyle test:scalastyle \ |
| | awk '{if($1~/error/)print}' \ |
| ) |
| |
| if test ! -z "$ERRORS"; then |
| echo -e "Scalastyle checks failed at following occurrences:\n$ERRORS" |
| # When running under GitHub Actions, also emit each scalastyle violation as |
| # a workflow `::error` annotation so it appears inline on the PR's "Files |
| # changed" tab. Without this, a violation cascades into ~7 red CI checks |
| # (Linters, Java 17/25 Maven build, Documentation generation, sparkr, |
| # Docker integration, TPC-DS) -- all needing catalyst to compile -- and |
| # each only surfaces a generic "exit code 1" with no file/line, forcing |
| # the user to download a full job log to find the actual violation. |
| if [[ "${GITHUB_ACTIONS:-}" == "true" ]]; then |
| # Strip ANSI color codes from the captured output before regex |
| # matching. Today sbt under awk's pipe is not a TTY and skips color, |
| # so the input is already plain. But if sbt color is ever forced |
| # (`-Dsbt.color=always`, custom CI shell), `\e[31m` would silently |
| # break every regex below. Cheap to harden. |
| ERRORS_PLAIN=$(printf '%s' "$ERRORS" | sed -E $'s/\x1b\\[[0-9;]*[A-Za-z]//g') |
| # Helper: emit one `::error` annotation. Centralised so the two regex |
| # branches below stay short. |
| emit_annotation() { |
| local file="$1" lineno="$2" msg="$3" |
| # Strip the GitHub Actions workspace prefix so the annotation |
| # references the path as it appears in the repo. |
| local file_rel="${file#${GITHUB_WORKSPACE:-}/}" |
| # Escape the few characters GitHub reserves in annotation values: |
| # %, \r, \n. (`,` and `:` need not be escaped in the message body, |
| # only inside parameter values, which we don't use.) |
| local msg_escaped="${msg//%/%25}" |
| msg_escaped="${msg_escaped//$'\r'/%0D}" |
| msg_escaped="${msg_escaped//$'\n'/%0A}" |
| printf '::error file=%s,line=%s,title=Scalastyle::%s\n' \ |
| "$file_rel" "$lineno" "$msg_escaped" |
| } |
| printf '%s\n' "$ERRORS_PLAIN" | while IFS= read -r raw; do |
| # Two scalastyle output formats reach us: |
| # |
| # (a) scalastyle's native console writer (`Tasks.doScalastyle` when |
| # invoked by the explicit `scalastyle` / `test:scalastyle` |
| # tasks): |
| # error file=<path> message=<text> line=<n> [column=<n>] |
| # The path has no spaces, the message can; `column=<n>` is |
| # appended for checkers that report a column (e.g. |
| # `WhitespaceEndOfLineChecker`) and absent otherwise. |
| # |
| # (b) sbt's logger format, used when `Tasks.doScalastyle` writes |
| # through `streams.value.log.error(...)` -- which is what the |
| # explicit `scalastyle` / `test:scalastyle` tasks invoked by |
| # this script do, and so this is the format we see in CI: |
| # [error] <path>:<line>: <message> |
| # The leading `[error] ` plus a single `:<line>:` (with no |
| # `:<col>:` follow-up) is what tells it apart from a regular |
| # Scala compile error of shape `[error] <path>:<line>:<col>: <msg>`. |
| if [[ "$raw" =~ ^error[[:space:]]+file=([^[:space:]]+)[[:space:]]+message=(.*)[[:space:]]+line=([0-9]+)([[:space:]]+column=[0-9]+)?$ ]]; then |
| emit_annotation "${BASH_REMATCH[1]}" "${BASH_REMATCH[3]}" "${BASH_REMATCH[2]}" |
| elif [[ "$raw" =~ ^\[error\][[:space:]]+(/[^:[:space:]]+):([0-9]+):[[:space:]]+(.+)$ ]]; then |
| emit_annotation "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}" |
| fi |
| done |
| fi |
| exit 1 |
| else |
| echo -e "Scalastyle checks passed." |
| fi |
| |