PHOENIX-6836: Enable code coverage reporting to SonarQube in Phoenix-Queryserver (#112)

Co-authored-by: Dora Horvath <dora.horvath@cloudera.com>
diff --git a/dev/code-coverage/README.md b/dev/code-coverage/README.md
new file mode 100644
index 0000000..7a3be4e
--- /dev/null
+++ b/dev/code-coverage/README.md
@@ -0,0 +1,48 @@
+<!--
+ 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.
+-->
+
+# Code analysis
+
+The `run-coverage.sh` script runs maven with the **codecoverage** profile
+which generates the test coverage data for the java classes.
+If the required parameters are given it also runs the sonar code analysis
+and uploads the results to the given SonarQube Server.
+
+## Running code analysis
+
+After running the script the reports generated by the JaCoCo code coverage
+library can be found in the modules under the `/target/site/jacoco/` folder.
+
+Here is how you can generate the code coverage report:
+
+```./dev/code-coverage/run-coverage.sh```
+
+## Publishing coverage results to SonarQube
+
+The required parameters for publishing the results to SonarQube are:
+
+- host URL,
+- login credentials,
+- project key
+
+The project name is an optional parameter.
+
+Here is an example command for running and publishing the coverage data:
+
+`./dev/code-coverage/run-coverage.sh -l ProjectCredentials
+-u https://exampleserver.com -k Project_Key -n Project_Name`
diff --git a/dev/code-coverage/run-coverage.sh b/dev/code-coverage/run-coverage.sh
new file mode 100755
index 0000000..7f603d9
--- /dev/null
+++ b/dev/code-coverage/run-coverage.sh
@@ -0,0 +1,70 @@
+#!/usr/bin/env bash
+#  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.
+
+usage() {
+  echo
+  echo "options:"
+  echo "  -h     Display help"
+  echo "  -u     SonarQube Host URL"
+  echo "  -l     SonarQube Login Credentials"
+  echo "  -k     SonarQube Project Key"
+  echo "  -n     SonarQube Project Name"
+  echo "  -t     Number of threads (example: 1 or 2C)."
+  echo
+  echo "Important:"
+  echo "  The required parameters for publishing the coverage results to SonarQube:"
+  echo "    - Host URL"
+  echo "    - Login Credentials"
+  echo "    - Project Key"
+  echo
+}
+
+execute() {
+  SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
+  MAIN_POM="${SCRIPT_DIR}/../../pom.xml"
+  # Check the syntax for the THREAD_COUNT variable
+  if [[ "$THREAD_COUNT" =~ ^[0-9]+([.][0-9]+)?$ ]] || [[ "$THREAD_COUNT" =~ ^[0-9]+([.][0-9]+)+[C]?$ ]]; then
+    THREADS="${THREAD_COUNT}"
+  else
+    THREADS=1
+  fi
+
+  mvn -B -e -f "$MAIN_POM" clean verify -Pcodecoverage -fn -Dmaven.javadoc.skip=true -DskipShade -T "$THREADS"
+
+  # If the required parameters are given, the code coverage results are uploaded to the SonarQube Server
+  if [ -n "$SONAR_LOGIN" ] && [ -n "$SONAR_PROJECT_KEY" ] && [ -n "$SONAR_URL" ]; then
+    mvn -B -e -Pcodecoverage -f "$MAIN_POM" sonar:sonar -Dsonar.projectName="$SONAR_PROJECT_NAME" \
+      -Dsonar.host.url="$SONAR_URL" -Dsonar.login="$SONAR_LOGIN" -Dsonar.projectKey="$SONAR_PROJECT_KEY" -T "$THREADS"
+  fi
+}
+
+while getopts ":u:l:k:n:t:h" option; do
+  case $option in
+  u) SONAR_URL=${OPTARG:-} ;;
+  l) SONAR_LOGIN=${OPTARG:-} ;;
+  k) SONAR_PROJECT_KEY=${OPTARG:-} ;;
+  n) SONAR_PROJECT_NAME=${OPTARG:-} ;;
+  t) THREAD_COUNT=${OPTARG:-} ;;
+  h) # Display usage
+    usage
+    exit
+    ;;
+  \?) # Invalid option
+    echo "Error: Invalid option"
+    exit
+    ;;
+  esac
+done
+
+# Start code analysis
+execute
diff --git a/pom.xml b/pom.xml
index 091511b..b2d5ce9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -101,7 +101,8 @@
         <spotbugs-maven-plugin.version>4.1.3</spotbugs-maven-plugin.version>
         <spotbugs.version>4.1.3</spotbugs.version>
         <maven-owasp-plugin.version>6.5.3</maven-owasp-plugin.version>
-        <jacoco-maven-plugin.version>0.8.5</jacoco-maven-plugin.version>
+        <jacoco-maven-plugin.version>0.8.8</jacoco-maven-plugin.version>
+        <maven-sonar-plugin.version>3.9.1.2184</maven-sonar-plugin.version>
 
         <!-- Plugin options -->
         <it.failIfNoSpecifiedTests>false</it.failIfNoSpecifiedTests>
@@ -701,6 +702,13 @@
             <name>!skip.code-coverage</name>
         </property>
       </activation>
+      <properties>
+          <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
+          <sonar.surefire.reportsPath>${project.build.directory}/surefire-reports</sonar.surefire.reportsPath>
+          <sonar.coverage.jacoco.xmlReportPaths>
+              ${project.build.directory}/site/jacoco/jacoco.xml
+          </sonar.coverage.jacoco.xmlReportPaths>
+      </properties>
       <build>
         <plugins>
           <plugin>
@@ -752,6 +760,11 @@
               </execution>
             </executions>
           </plugin>
+            <plugin>
+                <groupId>org.sonarsource.scanner.maven</groupId>
+                <artifactId>sonar-maven-plugin</artifactId>
+                <version>${maven-sonar-plugin.version}</version>
+            </plugin>
         </plugins>
       </build>
     </profile>