Hello guys, I was able to get code coverage and sonar-scanner working with Xcode Cloud.
- First in, in post-clone script I install sonar-scanner tool like this
brew install sonar-scanner
- Then, in post-xcodebuild script, I do three things: (a) get current app version, (b)
get app version, (c) run xcodebuild again with forced code coverage reporting, (d) find coverage data and convert it to the format that Sonarqube understands, and finally (e) run sonar-scanner, which uploads results to Sonarqube dashboard.
cd $CI_WORKSPACE
# declare variables
SCHEME=[REMOVED]
PRODUCT_NAME=[REMOVED]
WORKSPACE_NAME=${PRODUCT_NAME}.xcworkspace
APP_VERSION=$(sed -n '/MARKETING_VERSION/{s/MARKETING_VERSION = //;s/;//;s/^[[:space:]]*//;p;q;}' ./${PRODUCT_NAME}.xcodeproj/project.pbxproj)
# clean, build and test project
xcodebuild \
-workspace ${WORKSPACE_NAME} \
-destination 'platform=iOS Simulator,name=iPad (10th generation),OS=latest' \
-scheme ${SCHEME} \
-derivedDataPath DerivedData/ \
-enableCodeCoverage YES \
-resultBundlePath DerivedData/Logs/Test/ResultBundle.xcresult \
clean build test
# find profdata and binary
PROFDATA=$(find . -name "Coverage.profdata")
BINARY=$(find . -path "*${PRODUCT_NAME}.app/${PRODUCT_NAME}")
# check if we have profdata file
if [[ -z $PROFDATA ]]; then
echo "ERROR: Unable to find Coverage.profdata. Be sure to execute tests before running this script."
exit 1
fi
# extract coverage data from project using xcode native tool
xcrun --run llvm-cov show -instr-profile=${PROFDATA} ${BINARY} > sonarqube-coverage.report
# run sonar scanner and upload coverage data with the current app version
sonar-scanner \
-Dsonar.projectVersion=${APP_VERSION}
It all works fine but my team and I think that this is a workaround that shouldn't work like this, because technically xcodebuild command is executed two times, first by Xcode Cloud, then by my script, which takes a lot of time and feels hacky.
Ideally, Xcode Cloud's Build and Test actions should generate code coverage (the option is already enabled in our project) and give us access to profile data in DerivedData folder which I can access with environment variable CI_DERIVED_DATA_PATH. However, there is none.
My question is, do I do everything correctly? Is there a way to improve this flow? Do I miss on how to correctly get code coverage data from Xcode Cloud?