From 1454230a27d6ae60c05d1795d14bd34011283018 Mon Sep 17 00:00:00 2001 From: Marcos Rivereto Date: Tue, 17 Dec 2024 14:08:32 -0300 Subject: [PATCH] Create script to create coverage report --- .gitignore | 7 + Dockerfile | 2 + Example/TrustlySDK/ViewController.swift | 31 +- .../TrustlySDK/Session/SessionManager.swift | 2 + run-sonar-swift.sh | 528 ++++++++++++++++++ ...ect.properties => sonar-project.properties | 18 +- xccov-to-sonarqube-generic.sh | 45 ++ 7 files changed, 611 insertions(+), 22 deletions(-) create mode 100644 Dockerfile create mode 100755 run-sonar-swift.sh rename Example/sonar-project.properties => sonar-project.properties (89%) create mode 100644 xccov-to-sonarqube-generic.sh diff --git a/.gitignore b/.gitignore index 9399111..ad3e642 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,10 @@ Carthage/Build # */Podfile.lock */Pods/ + +# Sonar +sonar-reports/* +.scannerwork +compile_commands.json +Coverage.xml +*.log diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ea67406 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,2 @@ +FROM sonarqube:community +COPY sonar-custom-plugin-*.jar /opt/sonarqube/extensions/ \ No newline at end of file diff --git a/Example/TrustlySDK/ViewController.swift b/Example/TrustlySDK/ViewController.swift index 8f1decd..5d6fe37 100644 --- a/Example/TrustlySDK/ViewController.swift +++ b/Example/TrustlySDK/ViewController.swift @@ -19,21 +19,22 @@ class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - self.establishData = ["accessId": "", - "merchantId" : "", - "currency" : "USD", - "amount" : "1.00", - "merchantReference" : "", - "paymentType" : "Retrieval", - "returnUrl": "/returnUrl", - "cancelUrl": "/cancelUrl", - "requestSignature": "", - "customer.name": "John", - "customer.address.country": "US", - "metadata.urlScheme": "demoapp://", - "description": "First Data Mobile Test", - "env": "<[int, sandbox, local]>", - "localUrl": ""] + self.establishData = [ + "accessId": "A48B73F694C4C8EE6306", + "merchantId" : "110005514", + "currency" : "USD", + "amount" : "1.00", + "merchantReference" : "cac73df7-52b4-47d7-89d3-9628d2cfb65e", + "paymentType" : "Retrieval", + "returnUrl": "/returnUrl", + "cancelUrl": "/cancelUrl", + "requestSignature": "HT5mVOqBXa8ZlvgX2USmPeLns5o=", + "customer.name": "John", + "customer.address.country": "US", + "metadata.urlScheme": "demoapp://", + "description": "First Data Mobile Test", + "env": "int", + "localUrl": "192.168.0.13"] self.trustlyView.onChangeListener { (eventName, attributes) in diff --git a/Sources/TrustlySDK/Session/SessionManager.swift b/Sources/TrustlySDK/Session/SessionManager.swift index 4b3c3ff..a22af2f 100644 --- a/Sources/TrustlySDK/Session/SessionManager.swift +++ b/Sources/TrustlySDK/Session/SessionManager.swift @@ -16,8 +16,10 @@ struct SessionCid: Codable { func isValid(expirationTimeLimit: Int) -> Bool { let dateNow = Date() + let diffs = Calendar.current.dateComponents([.hour], from: expirationTime, to: dateNow) + if let hours = diffs.hour { return hours < expirationTimeLimit } diff --git a/run-sonar-swift.sh b/run-sonar-swift.sh new file mode 100755 index 0000000..89e1c5d --- /dev/null +++ b/run-sonar-swift.sh @@ -0,0 +1,528 @@ +#!/bin/bash +# +# backelite-sonar-swift-plugin - Enables analysis of Swift and Objective-C projects into SonarQube. +# Copyright © 2015 Backelite (${email}) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +# + +## INSTALLATION: Copy this script somewhere in your PATH +## USAGE: ./run-sonar-swift.sh +## DEBUG: ./run-sonar-swift.sh -v +## WARNING: edit your project parameters in sonar-project.properties rather than modifying this script +# + +# Global parameters +SLATHER_CMD=slather +SWIFTLINT_CMD=swiftlint +TAILOR_CMD=tailor +XCPRETTY_CMD=xcpretty +LIZARD_CMD=lizard +XCODEBUILD_CMD=xcodebuild + + +trap "echo 'Script interrupted by Ctrl+C'; stopProgress; exit 1" SIGHUP SIGINT SIGTERM + +function startProgress() { + while true + do + echo -n "." + sleep 5 + done +} + +function stopProgress() { + if [ "$vflag" = "" -a "$nflag" = "" ]; then + kill $PROGRESS_PID &>/dev/null + fi +} + +function testIsInstalled() { + + hash $1 2>/dev/null + if [ $? -eq 1 ]; then + echo >&2 "ERROR - $1 is not installed or not in your PATH"; exit 1; + fi +} + +function readParameter() { + + variable=$1 + shift + parameter=$1 + shift + + eval $variable="\"$(sed '/^\#/d' sonar-project.properties | grep $parameter | tail -n 1 | cut -d '=' -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')\"" +} + +# Run a set of commands with logging and error handling +function runCommand() { + + # 1st arg: redirect stdout + # 2nd arg: command to run + # 3rd..nth arg: args + redirect=$1 + shift + + command=$1 + shift + + if [ "$nflag" = "on" ]; then + # don't execute command, just echo it + echo + if [ "$redirect" = "/dev/stdout" ]; then + if [ "$vflag" = "on" ]; then + echo "+" $command "$@" + else + echo "+" $command "$@" "> /dev/null" + fi + elif [ "$redirect" != "no" ]; then + echo "+" $command "$@" "> $redirect" + else + echo "+" $command "$@" + fi + + elif [ "$vflag" = "on" ]; then + echo + + if [ "$redirect" = "/dev/stdout" ]; then + set -x #echo on + $command "$@" + returnValue=$? + set +x #echo off + elif [ "$redirect" != "no" ]; then + set -x #echo on + $command "$@" > $redirect + returnValue=$? + set +x #echo off + else + set -x #echo on + $command "$@" + returnValue=$? + set +x #echo off + fi + + if [[ $returnValue != 0 && $returnValue != 5 ]] ; then + stopProgress + echo "ERROR - Command '$command $@' failed with error code: $returnValue" + exit $returnValue + fi + else + + if [ "$redirect" = "/dev/stdout" ]; then + $command "$@" > /dev/null + elif [ "$redirect" != "no" ]; then + $command "$@" > $redirect + else + $command "$@" + fi + + returnValue=$? + if [[ $returnValue != 0 && $returnValue != 5 ]] ; then + stopProgress + echo "ERROR - Command '$command $@' failed with error code: $returnValue" + exit $returnValue + fi + + + echo + fi +} + +## COMMAND LINE OPTIONS +vflag="" +nflag="" +unittests="on" +swiftlint="off" +tailor="off" +lizard="off" +oclint="off" +fauxpas="off" +sonarscanner="" + +while [ $# -gt 0 ] +do + case "$1" in + -v) vflag=on;; + -n) nflag=on;; + -nounittests) unittests="";; + -noswiftlint) swiftlint="";; + -notailor) tailor="";; + -usesonarscanner) sonarscanner="on";; + --) shift; break;; + -*) + echo >&2 "Usage: $0 [-v]" + exit 1;; + *) break;; # terminate while loop + esac + shift +done + +# Usage OK +echo "Running run-sonar-swift.sh..." + +## CHECK PREREQUISITES + +# sonar-project.properties in current directory +if [ ! -f sonar-project.properties ]; then + echo >&2 "ERROR - No sonar-project.properties in current directory"; exit 1; +fi + +## READ PARAMETERS from sonar-project.properties + +#.xcodeproj filename +projectFile=''; readParameter projectFile 'sonar.swift.project' +workspaceFile=''; readParameter workspaceFile 'sonar.swift.workspace' + +# Count projects +if [[ ! -z "$projectFile" ]]; then + projectCount=$(echo $projectFile | sed -n 1'p' | tr ',' '\n' | wc -l | tr -d '[[:space:]]') + if [ "$vflag" = "on" ]; then + echo "Project count is [$projectCount]" + fi +fi + +# Source directories for .swift files +srcDirs=''; readParameter srcDirs 'sonar.sources' +# The name of your application scheme in Xcode +appScheme=''; readParameter appScheme 'sonar.swift.appScheme' +# The app configuration to use for the build +appConfiguration=''; readParameter appConfiguration 'sonar.swift.appConfiguration' +# The name of your test scheme in Xcode +testScheme=''; readParameter testScheme 'sonar.swift.testScheme' +# The name of your binary file (application) +binaryName=''; readParameter binaryName 'sonar.swift.appName' +# Get the path of plist file +plistFile=`xcodebuild -showBuildSettings -project "${projectFile}" | grep -i 'PRODUCT_SETTINGS_PATH' -m 1 | sed 's/[ ]*PRODUCT_SETTINGS_PATH = //'` +# Number version from plist if no sonar.projectVersion +numVerionFromPlist=`defaults read ${plistFile} CFBundleShortVersionString` + +# Read destination simulator +destinationSimulator=''; readParameter destinationSimulator 'sonar.swift.simulator' + +# Read tailor configuration +tailorConfiguration=''; readParameter tailorConfiguration 'sonar.swift.tailor.config' + +# The file patterns to exclude from coverage report +excludedPathsFromCoverage=''; readParameter excludedPathsFromCoverage 'sonar.swift.excludedPathsFromCoverage' + +# Check for mandatory parameters +if [ -z "$projectFile" -o "$projectFile" = " " ] && [ -z "$workspaceFile" -o "$workspaceFile" = " " ]; then + echo >&2 "ERROR - sonar.swift.project or/and sonar.swift.workspace parameter is missing in sonar-project.properties. You must specify which projects (comma-separated list) are application code or which workspace and project to use." + exit 1 +elif [ ! -z "$workspaceFile" ] && [ -z "$projectFile" ]; then + echo >&2 "ERROR - sonar.swift.workspace parameter is present in sonar-project.properties but sonar.swift.project and is not. You must specify which projects (comma-separated list) are application code or which workspace and project to use." + exit 1 +fi +if [ -z "$srcDirs" -o "$srcDirs" = " " ]; then + echo >&2 "ERROR - sonar.sources parameter is missing in sonar-project.properties. You must specify which directories contain your .swift source files (comma-separated list)." + exit 1 +fi +if [ -z "$appScheme" -o "$appScheme" = " " ]; then + echo >&2 "ERROR - sonar.swift.appScheme parameter is missing in sonar-project.properties. You must specify which scheme is used to build your application." + exit 1 +fi +if [ "$unittests" = "on" ]; then + if [ -z "$destinationSimulator" -o "$destinationSimulator" = " " ]; then + echo >&2 "ERROR - sonar.swift.simulator parameter is missing in sonar-project.properties. You must specify which simulator to use." + exit 1 + fi +fi + +# if the appConfiguration is not specified then set to Debug +if [ -z "$appConfiguration" -o "$appConfiguration" = " " ]; then + appConfiguration="Debug" +fi + + + +if [ "$vflag" = "on" ]; then + echo "Xcode project file is: $projectFile" + echo "Xcode workspace file is: $workspaceFile" + echo "Xcode application scheme is: $appScheme" + echo "Number version from plist is: $numVerionFromPlist" + if [ -n "$unittests" ]; then + echo "Destination simulator is: $destinationSimulator" + echo "Excluded paths from coverage are: $excludedPathsFromCoverage" + else + echo "Unit surefire are disabled" + fi +fi + +## SCRIPT + +# Start progress indicator in the background +if [ "$vflag" = "" -a "$nflag" = "" ]; then + startProgress & + # Save PID + PROGRESS_PID=$! +fi + +# Create sonar-reports/ for reports output +if [ "$vflag" = "on" ]; then + echo 'Creating directory sonar-reports/' +fi +rm -rf sonar-reports +mkdir sonar-reports + +# Extracting project information needed later +echo -n 'Extracting Xcode project information' +if [[ "$workspaceFile" != "" ]] ; then + buildCmdPrefix="-workspace $workspaceFile" +else + buildCmdPrefix="-project $projectFile" +fi +buildCmd=($XCODEBUILD_CMD clean build $buildCmdPrefix -scheme $appScheme) +if [[ ! -z "$destinationSimulator" ]]; then + buildCmd+=(-destination "$destinationSimulator" -destination-timeout 360 COMPILER_INDEX_STORE_ENABLE=NO) +fi +runCommand xcodebuild.log "${buildCmd[@]}" +#oclint-xcodebuild # Transform the xcodebuild.log file into a compile_command.json file +cat xcodebuild.log | $XCPRETTY_CMD -r json-compilation-database -o compile_commands.json + +# Objective-C code detection +hasObjC="no" +compileCmdFile=compile_commands.json +minimumSize=3 +actualSize=$(stat -f%z "$compileCmdFile") +echo "actual = $actualSize, min = $minimumSize" +if [ $actualSize -ge $minimumSize ]; then + hasObjC="yes" +fi + +# Unit surefire and coverage +if [ "$unittests" = "on" ]; then + + # Put default xml files with no surefire and no coverage... + echo "" > sonar-reports/TEST-report.xml + + echo -n 'Running surefire' + buildCmd=($XCODEBUILD_CMD clean build test) + if [[ ! -z "$workspaceFile" ]]; then + buildCmd+=(-workspace "$workspaceFile") + elif [[ ! -z "$projectFile" ]]; then + buildCmd+=(-project "$projectFile") + fi + buildCmd+=( -scheme "$appScheme" -configuration "$appConfiguration" -enableCodeCoverage YES -derivedDataPath sonar-reports/) + if [[ ! -z "$destinationSimulator" ]]; then + buildCmd+=(-destination "$destinationSimulator" -destination-timeout 60) + fi + + runCommand sonar-reports/xcodebuild.log "${buildCmd[@]}" + cat sonar-reports/xcodebuild.log | $XCPRETTY_CMD -t --report junit + mv build/reports/junit.xml sonar-reports/TEST-report.xml + + + echo '\nComputing coverage report\n' + + # Build the --exclude flags + excludedCommandLineFlags="" + if [ ! -z "$excludedPathsFromCoverage" -a "$excludedPathsFromCoverage" != " " ]; then + echo $excludedPathsFromCoverage | sed -n 1'p' | tr ',' '\n' > tmpFileRunSonarSh2 + while read word; do + excludedCommandLineFlags+=" -i $word" + done < tmpFileRunSonarSh2 + rm -rf tmpFileRunSonarSh2 + fi + if [ "$vflag" = "on" ]; then + echo "Command line exclusion flags for slather is:$excludedCommandLineFlags" + fi + + firstProject=$(echo $projectFile | sed -n 1'p' | tr ',' '\n' | head -n 1) + + bash xccov-to-sonarqube-generic.sh sonar-reports/Logs/Test/Run-TrustlySDK-Example-*.xcresult/ > sonar-reports/generic-coverage.xml + # slatherCmd=($SLATHER_CMD coverage) + # if [[ ! -z "$binaryName" ]]; then + # slatherCmd+=( --binary-basename "$binaryName") + # fi + + # slatherCmd+=( --input-format profdata $excludedCommandLineFlags --cobertura-xml --output-directory sonar-reports) + + # if [[ ! -z "$workspaceFile" ]]; then + # slatherCmd+=( --workspace "$workspaceFile") + # fi + # slatherCmd+=( --scheme "$appScheme" "$firstProject") + + # echo "${slatherCmd[@]}" + + # runCommand /dev/stdout "${slatherCmd[@]}" + # mv sonar-reports/cobertura.xml sonar-reports/coverage-swift.xml +fi + +# SwiftLint +if [ "$swiftlint" = "on" ]; then + if hash $SWIFTLINT_CMD 2>/dev/null; then + echo -n 'Running SwiftLint...' + + # Build the --include flags + currentDirectory=${PWD##*/} + echo "$srcDirs" | sed -n 1'p' | tr ',' '\n' > tmpFileRunSonarSh + while read word; do + + # Run SwiftLint command + $SWIFTLINT_CMD lint --path "$word" > sonar-reports/"$appScheme"-swiftlint.txt + + done < tmpFileRunSonarSh + rm -rf tmpFileRunSonarSh + else + echo "Skipping SwiftLint (not installed!)" + fi + +else + echo 'Skipping SwiftLint (test purposes only!)' +fi + +# Tailor +if [ "$tailor" = "on" ]; then + if hash $TAILOR_CMD 2>/dev/null; then + echo -n 'Running Tailor...' + + # Build the --include flags + currentDirectory=${PWD##*/} + echo "$srcDirs" | sed -n 1'p' | tr ',' '\n' > tmpFileRunSonarSh + while read word; do + + # Run tailor command + $TAILOR_CMD $tailorConfiguration "$word" > sonar-reports/"$appScheme"-tailor.txt + + done < tmpFileRunSonarSh + rm -rf tmpFileRunSonarSh + else + echo "Skipping Tailor (not installed!)" + fi + +else + echo 'Skipping Tailor!' +fi + +if [ "$oclint" = "on" ] && [ "$hasObjC" = "yes" ]; then + + echo -n 'Running OCLint...' + + # Options + maxPriority=10000 + longLineThreshold=250 + + # Build the --include flags + currentDirectory=${PWD##*/} + echo "$srcDirs" | sed -n 1'p' | tr ',' '\n' > tmpFileRunSonarSh + while read word; do + + includedCommandLineFlags=" --include .*/${currentDirectory}/${word}/*" + if [ "$vflag" = "on" ]; then + echo + echo -n "Path included in oclint analysis is:$includedCommandLineFlags" + fi + # Run OCLint with the right set of compiler options + runCommand no oclint-json-compilation-database -v $includedCommandLineFlags -- -rc LONG_LINE=$longLineThreshold -max-priority-1 $maxPriority -max-priority-2 $maxPriority -max-priority-3 $maxPriority -report-type pmd -o sonar-reports/$appScheme-oclint.xml + + done < tmpFileRunSonarSh + rm -rf tmpFileRunSonarSh + + +else + echo 'Skipping OCLint (test purposes only!)' +fi + +#FauxPas +if [ "$fauxpas" = "on" ] && [ "$hasObjC" = "yes" ]; then + hash fauxpas 2>/dev/null + if [ $? -eq 0 ]; then + + echo -n 'Running FauxPas...' + + if [ "$projectCount" = "1" ] + then + + fauxpas -o json check $projectFile --workspace $workspaceFile --scheme $appScheme > sonar-reports/fauxpas.json + + + else + + echo $projectFile | sed -n 1'p' | tr ',' '\n' > tmpFileRunSonarSh + while read projectName; do + + $XCODEBUILD_CMD -list -project $projectName | sed -n '/Schemes/,$p' | while read scheme + do + + if [ "$scheme" = "" ] + then + exit + fi + + if [ "$scheme" == "${scheme/Schemes/}" ] + then + if [ "$scheme" != "$testScheme" ] + then + projectBaseDir=$(dirname $projectName) + workspaceRelativePath=$(python -c "import os.path; print os.path.relpath('$workspaceFile', '$projectBaseDir')") + fauxpas -o json check $projectName --workspace $workspaceRelativePath --scheme $scheme > sonar-reports/$(basename $projectName .xcodeproj)-$scheme-fauxpas.json + fi + fi + + done + + done < tmpFileRunSonarSh + rm -rf tmpFileRunSonarSh + + fi + + else + echo 'Skipping FauxPas (not installed)' + fi +else + echo 'Skipping FauxPas' +fi + +# Lizard Complexity +if [ "$lizard" = "on" ]; then + if hash $LIZARD_CMD 2>/dev/null; then + echo -n 'Running Lizard...' + $LIZARD_CMD --xml "$srcDirs" > sonar-reports/lizard-report.xml + else + echo 'Skipping Lizard (not installed!)' + fi +else + echo 'Skipping Lizard (test purposes only!)' +fi + +# The project version from properties file +numVersionSonarRunner=''; readParameter numVersionSonarRunner 'sonar.projectVersion' +if [ -z "$numVersionSonarRunner" -o "$numVersionSonarRunner" = " " ]; then + numVersionSonarRunner=" --define sonar.projectVersion=$numVerionFromPlist" +else + #if we have version number in properties file, we don't overide numVersion for sonar-runner/sonar-scanner command + numVersionSonarRunner=''; +fi +# SonarQube +if [ "$sonarscanner" = "on" ]; then + echo -n 'Running SonarQube using SonarQube Scanner' + if hash /dev/stdout sonar-scanner 2>/dev/null; then + runCommand /dev/stdout sonar-scanner $numVersionSonarRunner + else + echo 'Skipping sonar-scanner (not installed!)' + fi +else + echo -n 'Running SonarQube using SonarQube Runner' + if hash /dev/stdout sonar-runner 2>/dev/null; then + runCommand /dev/stdout sonar-runner $numVersionSonarRunner + else + runCommand /dev/stdout sonar-scanner $numVersionSonarRunner + fi +fi + +# Kill progress indicator +stopProgress + +exit 0 \ No newline at end of file diff --git a/Example/sonar-project.properties b/sonar-project.properties similarity index 89% rename from Example/sonar-project.properties rename to sonar-project.properties index 7cfcf60..bdf402d 100644 --- a/Example/sonar-project.properties +++ b/sonar-project.properties @@ -19,7 +19,8 @@ # Sonar Server details sonar.host.url=http://localhost:9000 sonar.login=admin -sonar.password=Trustly$Sonar2024 +sonar.password=Sonarqube$24 +# sonar.token=sqp_8cba87ecfe9b5459a833660cabcdc5e8a138deb8 # Project Details sonar.projectKey=org.cocoapods.TrustlySDK-Example @@ -40,7 +41,7 @@ sonar.exclusions=**/*.xml,Pods/**/*,Reports/**/* # sonar.inclusions=*.swift # Path to test directories (comment if no test) -sonar.tests=Tests +sonar.tests=Example/Tests # Destination Simulator to run surefire # As string expected in destination argument of xcodebuild command @@ -51,8 +52,8 @@ sonar.swift.simulator=platform=iOS Simulator,name=iPhone 16 Pro Max,OS=18.0 # Xcode project configuration (.xcodeproj) # and use the later to specify which project(s) to include in the analysis (comma separated list) # Specify either xcodeproj or xcodeproj + xcworkspace -sonar.swift.project=TrustlySDK.xcodeproj -sonar.swift.workspace=TrustlySDK.xcworkspace +sonar.swift.project=Example/TrustlySDK.xcodeproj +sonar.swift.workspace=Example/TrustlySDK.xcworkspace # Specify your appname. # This will be something like "myApp" @@ -84,8 +85,11 @@ sonar.junit.reportsPath=sonar-reports/TEST-report.xml # Cobertura report generated by run-sonar.sh is stored in sonar-reports/coverage-swift.xml # Change it only if you generate the file on your own -sonar.swift.coverage.reportPattern=sonar-reports/coverage-swift*.xml -#sonar.swift.coverage.reportPattern=sonar-reports/cobertura.xml +# sonar.swift.coverage.reportPattern=sonar-reports/coverage-swift*.xml +# sonar.swift.coverage.reportPaths=sonar-reports/coverage-swift.xml +sonar.coverageReportPaths=sonar-reports/generic-coverage.xml +# sonar.cobertura.reportPath=sonar-reports/coverage-swift.xml +# sonar.swift.coverage.reportPattern=sonar-reports/cobertura.xml # OCLint report generated by run-sonar.sh is stored in sonar-reports/oclint.xml # Change it only if you generate the file on your own @@ -112,5 +116,5 @@ sonar.swift.tailor.report=sonar-reports/*tailor.txt # --max-severity= maximum severity # --max-struct-length=<0-999> maximum Struct length (in lines) # --min-name-length=<1-999> minimum Identifier name length (in characters) - +sonar.verbose=true sonar.swift.tailor.config=--no-color --max-line-length=100 --max-file-length=500 --max-name-length=40 --max-name-length=40 --min-name-length=4 diff --git a/xccov-to-sonarqube-generic.sh b/xccov-to-sonarqube-generic.sh new file mode 100644 index 0000000..d069e04 --- /dev/null +++ b/xccov-to-sonarqube-generic.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +function convert_xccov_to_xml { + sed -n \ + -e '/:$/s/&/\&/g;s/^\(.*\):$/ /p' \ + -e 's/^ *\([0-9][0-9]*\): 0.*$/ /p' \ + -e 's/^ *\([0-9][0-9]*\): [1-9].*$/ /p' \ + -e 's/^$/ <\/file>/p' +} + +function xccov_to_generic { + local xcresult="$1" + + echo '' + xcrun xccov view --archive "$xcresult" | convert_xccov_to_xml + echo '' +} + +function check_xcode_version() { + local major=${1:-0} minor=${2:-0} + return $(( (major >= 14) || (major == 13 && minor >= 3) )) +} + +if ! xcode_version="$(xcodebuild -version | sed -n '1s/^Xcode \([0-9.]*\)$/\1/p')"; then + echo 'Failed to get Xcode version' 1>&2 + exit 1 +elif check_xcode_version ${xcode_version//./ }; then + echo "Xcode version '$xcode_version' not supported, version 13.3 or above is required" 1>&2; + exit 1 +fi + +xcresult="$1" +if [[ $# -ne 1 ]]; then + echo "Invalid number of arguments. Expecting 1 path matching '*.xcresult'" + exit 1 +elif [[ ! -d $xcresult ]]; then + echo "Path not found: $xcresult" 1>&2; + exit 1 +elif [[ $xcresult != *".xcresult"* ]]; then + echo "Expecting input to match '*.xcresult', got: $xcresult" 1>&2; + exit 1 +fi + +xccov_to_generic "$xcresult" \ No newline at end of file