-
Notifications
You must be signed in to change notification settings - Fork 0
Upgrade Sonarcloud Functionality #114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7748976
251d325
6b9460a
30b3257
521f3d5
a48ca1b
56672ba
562de0f
453b583
b5ad810
319f92b
f228b50
7c95253
f21ea9c
455832f
9164f7e
039d8fa
09cd3a3
24bf5da
b4c3eec
3df95d0
bd65687
0256b61
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -70,22 +70,32 @@ function(swift_list_targets out_var) | |
set(all_targets) | ||
|
||
foreach(target IN LISTS x_all_targets) | ||
get_target_property(type ${target} TYPE) | ||
if(x_TYPES) | ||
get_target_property(type ${target} TYPE) | ||
if(NOT ${type} IN_LIST x_TYPES) | ||
continue() | ||
endif() | ||
endif() | ||
|
||
if(x_SWIFT_TYPES) | ||
get_target_property(type ${target} SWIFT_TYPE) | ||
if(NOT ${type} IN_LIST x_SWIFT_TYPES) | ||
if (type STREQUAL "INTERFACE_LIBRARY") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. previously if the target was an interface library (ex |
||
get_target_property(swift_type ${target} INTERFACE_SWIFT_TYPE) | ||
else() | ||
get_target_property(swift_type ${target} SWIFT_TYPE) | ||
endif() | ||
|
||
if(NOT ${swift_type} IN_LIST x_SWIFT_TYPES) | ||
continue() | ||
endif() | ||
endif() | ||
|
||
if(x_ONLY_THIS_REPO) | ||
get_target_property(target_dir ${target} SOURCE_DIR) | ||
if (type STREQUAL "INTERFACE_LIBRARY") | ||
get_target_property(target_dir ${target} INTERFACE_SOURCE_DIR) | ||
else() | ||
get_target_property(target_dir ${target} SOURCE_DIR) | ||
endif() | ||
|
||
# This replacement makes sure that we only filter out third_party subdirectories which actually exist in the root project source dir - ie, a git repo cloned in to a path | ||
# which just so happens to contain third_party should not break this function | ||
string(REPLACE ${CMAKE_SOURCE_DIR} "" target_dir ${target_dir}) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
# | ||
# Copyright (C) 2022 Swift Navigation Inc. | ||
# Contact: Swift Navigation <[email protected]> | ||
# | ||
# This source is subject to the license found in the file 'LICENSE' which must | ||
# be distributed together with this source. All other rights reserved. | ||
# | ||
# THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, | ||
# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED | ||
# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. | ||
# | ||
|
||
# | ||
# OVERVIEW | ||
# ======== | ||
# | ||
# Offers a way to generate the necessary Sonarcloud project file from the | ||
# information available via cmake build system. User can call on | ||
# "generate_sonarcloud_project_properties" to produce this project file which | ||
# outlines to Sonarcloud what files/directories are deemed source files and | ||
# which files are test files. | ||
# | ||
# This module will work in conjunction with "TestTargets" and "SwiftTargets", | ||
# and "ListTargets" to identify all Swift production source/test code through. | ||
# This means that only targets created via "swift_add_*" functions that are | ||
# categorized as "production" code will be included in the analysis. No other | ||
# none C/C++ source code will be included in the Sonarcloud project properties | ||
# file (at the moment). | ||
# | ||
# USAGE | ||
# ===== | ||
# | ||
# To generate the Sonarcloud project file, simply call the following method at | ||
# the end of your projects CMakeLists.txt file: | ||
# | ||
# generate_sonarcloud_project_properties(${CMAKE_BINARY_DIR}/sonar-project.properties) | ||
# | ||
# This will generate a sonar project file in your root build directory (please | ||
# don't ever write this to your source directory). Prior to uploading the | ||
# results to Sonarcloud, you will need to manually transform all absolute path | ||
# references to relative paths. This manual step can be done easily with the | ||
# following Linux command: | ||
# | ||
# sed -i -E "s|^(\s+)(${PWD}/)|\1|g" 'sonar-project.properties' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know this is a one liner but I think it would be good to make it available as a bash script, and have pipelines use the bash script to fix up the paths rather than writing this snippet directly into pipeline scripts. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
# | ||
# The reason why this extra step is required and was not taken care by cmake, | ||
# is because targets have generator expressions to them which can only be | ||
# evaluated at the end of the configuration stage. At that point there is no | ||
# find/replace functionality. | ||
# | ||
|
||
include(ListTargets) | ||
|
||
set(_sonarcloud_newline "\\\n ") | ||
|
||
function(_transform_sonarcloud_source_files output_variable target) | ||
# | ||
# Based off of https://cmake.org/cmake/help/latest/prop_tgt/SOURCES.html we | ||
# need to correctly interpret the SOURCES properties to be able to transform | ||
# them into what sonarcloud project properties is comfortable with (ie. | ||
# relative path from project source directory). | ||
# | ||
get_target_property(target_binary_dir ${target} BUILD_DIR) | ||
get_target_property(target_source_dir ${target} SOURCE_DIR) | ||
|
||
unset(source_files) | ||
foreach (source_file IN LISTS ARGN) | ||
get_source_file_property(is_build_generated_file ${target_binary_dir}/${source_file} GENERATED) | ||
|
||
if(IS_ABSOLUTE ${source_file}) | ||
list(APPEND source_files ${source_file}) | ||
continue() | ||
endif() | ||
|
||
if (is_build_generated_file) | ||
list(APPEND source_files ${target_binary_dir}/${source_file}) | ||
continue() | ||
endif() | ||
|
||
if (EXISTS ${target_source_dir}/${source_file}) | ||
list(APPEND source_files ${target_source_dir}/${source_file}) | ||
continue() | ||
endif() | ||
|
||
if (source_file MATCHES "^\\$<.+>$") | ||
list(APPEND source_files "$<$<BOOL:${source_file}>:$<JOIN:${source_file},$<COMMA>${_sonarcloud_newline}>>") | ||
continue() | ||
endif() | ||
|
||
message(WARNING "Sonarcloud is missing source file \"${source_file}\" for target ${target}") | ||
endforeach() | ||
|
||
set(${output_variable} ${source_files} PARENT_SCOPE) | ||
endfunction() | ||
|
||
function(_transform_sonarcloud_include_directories output_variable target) | ||
unset(include_directories) | ||
|
||
foreach (include_directory IN LISTS ARGN) | ||
if(IS_ABSOLUTE ${include_directory}) | ||
list(APPEND include_directories ${include_directory}) | ||
continue() | ||
endif() | ||
|
||
if (include_directory MATCHES "^\\$<INSTALL_INTERFACE:.+>$") | ||
# ignoring installation interfaces | ||
continue() | ||
endif() | ||
|
||
if (include_directory MATCHES "^\\$<.+>$") | ||
list(APPEND include_directories "$<$<BOOL:${include_directory}>:$<JOIN:${include_directory},$<COMMA>${_sonarcloud_newline}>>") | ||
continue() | ||
endif() | ||
|
||
message(WARNING "Sonarcloud is missing include directory \"${include_directory}\" for target ${target}") | ||
endforeach() | ||
|
||
set(${output_variable} ${include_directories} PARENT_SCOPE) | ||
endfunction() | ||
|
||
function(_extract_sonarcloud_project_files output_project_source_files output_project_include_directories) | ||
unset(project_source_files) | ||
unset(project_include_directories) | ||
|
||
foreach (target IN LISTS ARGN) | ||
get_target_property(target_type ${target} TYPE) | ||
|
||
unset(target_source_files) | ||
unset(target_include_directories) | ||
|
||
if (NOT target_type STREQUAL "INTERFACE_LIBRARY") | ||
get_target_property(target_source_files ${target} SOURCES) | ||
if (target_source_files) | ||
_transform_sonarcloud_source_files(target_source_files ${target} ${target_source_files}) | ||
else() | ||
unset(target_source_files) | ||
endif() | ||
|
||
get_target_property(target_include_directories ${target} INCLUDE_DIRECTORIES) | ||
if (target_include_directories) | ||
_transform_sonarcloud_include_directories(target_include_directories ${target} ${target_include_directories}) | ||
else() | ||
unset(target_include_directories) | ||
endif() | ||
endif() | ||
|
||
get_target_property(target_interface_include_directories ${target} INTERFACE_INCLUDE_DIRECTORIES) | ||
if (target_interface_include_directories) | ||
_transform_sonarcloud_include_directories(target_interface_include_directories ${target} ${target_interface_include_directories}) | ||
else() | ||
unset(target_interface_include_directories) | ||
endif() | ||
|
||
list(APPEND project_source_files ${target_source_files}) | ||
list(APPEND project_include_directories ${target_include_directories}) | ||
list(APPEND project_include_directories ${target_interface_include_directories}) | ||
endforeach() | ||
|
||
if (project_source_files) | ||
list(SORT project_source_files) | ||
list(REMOVE_DUPLICATES project_source_files) | ||
endif() | ||
|
||
if (project_include_directories) | ||
list(SORT project_include_directories) | ||
list(REMOVE_DUPLICATES project_include_directories) | ||
endif() | ||
|
||
set(${output_project_source_files} ${project_source_files} PARENT_SCOPE) | ||
set(${output_project_include_directories} ${project_include_directories} PARENT_SCOPE) | ||
endfunction() | ||
|
||
function(generate_sonarcloud_project_properties sonarcloud_project_properties_path) | ||
if (NOT IS_ABSOLUTE ${sonarcloud_project_properties_path}) | ||
message(FATAL_ERROR "Function \"generate_sonarcloud_project_properties\"" | ||
"only accepts absolute paths to avoid ambiguity") | ||
endif() | ||
|
||
if (NOT ${PROJECT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) | ||
return() | ||
endif() | ||
|
||
swift_list_targets(source_targets | ||
ONLY_THIS_REPO | ||
SWIFT_TYPES | ||
executable | ||
library | ||
) | ||
|
||
swift_list_targets(test_targets | ||
ONLY_THIS_REPO | ||
SWIFT_TYPES | ||
test | ||
test_library | ||
) | ||
|
||
_extract_sonarcloud_project_files(source_source_files source_include_directories ${source_targets}) | ||
_extract_sonarcloud_project_files(test_source_files test_include_directories ${test_targets}) | ||
|
||
set(sonarcloud_project_properties_content "sonar.sourceEncoding=UTF-8\n") | ||
|
||
set(source_files ${source_source_files} ${source_include_directories}) | ||
list(JOIN source_files ",${_sonarcloud_newline}" sonar_sources) | ||
string(APPEND sonarcloud_project_properties_content "sonar.inclusions=${_sonarcloud_newline}${sonar_sources}\n") | ||
|
||
set(test_files ${test_source_files}) | ||
list(JOIN test_files ",${_sonarcloud_newline}" sonar_tests) | ||
string(APPEND sonarcloud_project_properties_content "sonar.tests.inclusions=${_sonarcloud_newline}${sonar_tests}\n") | ||
|
||
file(GENERATE | ||
OUTPUT "${sonarcloud_project_properties_path}" | ||
CONTENT "${sonarcloud_project_properties_content}" | ||
) | ||
|
||
endfunction() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -115,6 +115,9 @@ | |
# C_EXTENSIONS_ON: C extensions are disabled by default, adding this keyword | ||
# enables C extensions. | ||
# | ||
# SKIP_COMPILE_OPTIONS: will forgo invoking the swift_set_compile_options on | ||
# the target. | ||
# | ||
# SINGLE VALUE KEYWORDS | ||
# | ||
# C_STANDARD: allow uses to override the default C standard used in a target, | ||
|
@@ -156,6 +159,31 @@ define_property(TARGET | |
BRIEF_DOCS "Swift target type" | ||
FULL_DOCS "For use by other modules in this repository which need to know the classification of target. One of executable, library, tool, tool_library, test, test_library") | ||
|
||
define_property(TARGET | ||
PROPERTY INTERFACE_SWIFT_TYPE | ||
BRIEF_DOCS "Swift target type" | ||
FULL_DOCS "Identical use as SWIFT_TYPE except that this applies to ALL target types, including INTERFACE") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
define_property(TARGET | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm currently not using this property at the moment. I originally implemented (accidentally) an alternative solution to |
||
PROPERTY SWIFT_PROJECT | ||
BRIEF_DOCS "Swift project name" | ||
FULL_DOCS "For use by other modules in this repository which need to know the project which this target belongs to") | ||
|
||
define_property(TARGET | ||
PROPERTY INTERFACE_SWIFT_PROJECT | ||
BRIEF_DOCS "Swift project name" | ||
FULL_DOCS "Identical use as SWIFT_PROJECT except that this applies to ALL target types, including INTERFACE") | ||
|
||
define_property(TARGET | ||
PROPERTY SWIFT_TEST_TYPE | ||
BRIEF_DOCS "Swift test type" | ||
FULL_DOCS "When target's SWIFT_PROJECT property is \"test\", this option, if set, will identify what type of test it is. Currently support \"unit\" or \"integration\"") | ||
|
||
define_property(TARGET | ||
PROPERTY INTERFACE_SOURCE_DIR | ||
BRIEF_DOCS "Target's source directory" | ||
FULL_DOCS "Identical use as SOURCE_DIR except that this applies to ALL target types, including INTERFACE") | ||
|
||
macro(swift_collate_arguments prefix name) | ||
set(exclusion_list ${ARGN}) | ||
set(${name}_args "") | ||
|
@@ -182,7 +210,7 @@ macro(swift_collate_arguments prefix name) | |
endmacro() | ||
|
||
function(swift_add_target target type) | ||
set(this_option INTERFACE OBJECT STATIC SHARED MODULE) | ||
set(this_option INTERFACE OBJECT STATIC SHARED MODULE SKIP_COMPILE_OPTIONS) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This flag here is introduced to allow Orion + friends to use this function. To allow us to slowly transition all their code to use these |
||
set(this_single "") | ||
set(this_multi SOURCES) | ||
|
||
|
@@ -288,11 +316,38 @@ function(swift_add_target target type) | |
message(FATAL_ERROR "Unknown Swift target type ${type}") | ||
endif() | ||
|
||
# | ||
# This edge case is needed for cmake version < 3.19.0 where INTERFACE | ||
# classes cannot contain any property other than those prefixed with | ||
# "INTERFACE_". | ||
# | ||
# see: https://stackoverflow.com/questions/68502038/custom-properties-for-interface-libraries | ||
# | ||
# Until we migrate the cmake scripts to require 3.19.0, we should use the | ||
# "INTERFACE_*" properties. If you want to go the extra mile, make sure to | ||
# check both `INTERFACE_` and non `INTERFACE_` properties, later on we can | ||
# delete the `INTERFACE_` once this illogical constraint is removed. | ||
# | ||
set_target_properties(${target} | ||
PROPERTIES | ||
INTERFACE_SWIFT_PROJECT ${PROJECT_NAME} | ||
INTERFACE_SWIFT_TYPE ${type} | ||
INTERFACE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} | ||
) | ||
|
||
if (NOT x_INTERFACE) | ||
set_target_properties(${target} PROPERTIES SWIFT_TYPE ${type}) | ||
swift_set_compile_options(${target} ${compile_options_args} EXTRA_FLAGS ${extra_flags}) | ||
set_target_properties(${target} | ||
PROPERTIES | ||
SWIFT_PROJECT ${PROJECT_NAME} | ||
SWIFT_TYPE ${type} | ||
) | ||
|
||
swift_set_language_standards(${target} ${language_standards_args}) | ||
target_code_coverage(${target} NO_RUN) | ||
|
||
if (NOT x_SKIP_COMPILE_OPTIONS) | ||
swift_set_compile_options(${target} ${compile_options_args} EXTRA_FLAGS ${extra_flags}) | ||
endif() | ||
endif() | ||
endfunction() | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is some cmake linting which is failing due to
SwiftTarget .cmake
having too many if statements in the function.