diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 43881eb98b8aab6424bcec2d2fb27f5a5f1c16e9..9eb53ea82bae755ad23a03385aaf44e1a98ebf1e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,19 +1,33 @@ image: lycantropos/cmake +variables: + PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" + +# Global caching directive for pip +cache: + key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG" + paths: + - .cache/pip + stages: - build - test + - deploy before_script: + - apt-get update -qq && apt-get -qq -y install python3-pip && python3 -m pip install --upgrade pip + - python3 -V + - python3 -m pip --version - g++ --version - cat /etc/*-release + - python3 -m pip install gcovr build: stage: build variables: - GIT_SUBMODULE_STRATEGY: normal - GCC_COLORS: "error=31;1:warning=35;1:note=36;1:range1=32:range2=34:locus=39;1:quote=39;1:fixit-insert=32:fixit-delete=31:diff-filename=39;1:diff-hunk=32:diff-delete=31:diff-insert=32:type-diff=32;1" - CLICOLOR_FORCE: 1 # Necessary for cmake to output colours + GIT_SUBMODULE_STRATEGY: normal + GCC_COLORS: "error=31;1:warning=35;1:note=36;1:range1=32:range2=34:locus=39;1:quote=39;1:fixit-insert=32:fixit-delete=31:diff-filename=39;1:diff-hunk=32:diff-delete=31:diff-insert=32:type-diff=32;1" + CLICOLOR_FORCE: 1 # Necessary for cmake to output colours script: - cmake . -DCMAKE_CXX_FLAGS="-Werror -fdiagnostics-color=always" - make -j4 @@ -23,15 +37,17 @@ build: tests: stage: test + coverage: '/^TOTAL.*\s+(\d+\%)$/' variables: GIT_SUBMODULE_STRATEGY: normal script: - cmake . - make tests -j4 - - ./tests --use-colour yes + - ./tests --use-colour yes # Run the tests after_script: - ./tests -r junit -o junit.xml artifacts: + expire_in: 1 week reports: junit: junit.xml @@ -75,4 +91,24 @@ clang-tidy: - clang-tidy-7 --version script: # Running with `script` to give clang a tty so that it outputs colours - - script -ec "bash -x ci/clang-tidy.sh" + - script -c "bash -x ci/clang-tidy.sh" + +pages: + stage: deploy + when: always # Deploy always and on build or test failure, generate just the documentation + cache: + key: "$CI_JOB_NAME" + paths: + - public + variables: + GIT_SUBMODULE_STRATEGY: normal + script: + - apt-get install -qq -y doxygen graphviz lcov + after_script: + - ./ci/pages_deploy.sh + - echo -e "\e[1;36mPublic directory contents\e[0m" && ls -l public/coverage # Print directory contents for debugging + artifacts: + paths: + - public # Upload the resulting website + only: + - branches # Deploy on all branches diff --git a/.gitmodules b/.gitmodules index d2fb166c6a97657b49df5c5ade5002c3b97e1092..2fc4ae0960502c851fe5afb7c4ffb3290db9f120 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "lib/etl"] path = lib/etl url = https://github.com/ETLCPP/etl.git +[submodule "ci/page_style/doxygen_dark_theme"] + path = ci/page_style/doxygen_dark_theme + url = https://github.com/MaJerle/doxygen_dark_theme.git diff --git a/.idea/vcs.xml b/.idea/vcs.xml index fea94c457eb70a79c73b917a8993a9fd83f68f71..b361e80b9ac2795e185ae4f8a0ebeac8becdd851 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,6 +2,7 @@ <project version="4"> <component name="VcsDirectoryMappings"> <mapping directory="$PROJECT_DIR$" vcs="Git" /> + <mapping directory="$PROJECT_DIR$/ci/page_style/doxygen_dark_theme" vcs="Git" /> <mapping directory="$PROJECT_DIR$/lib/Catch2" vcs="Git" /> <mapping directory="$PROJECT_DIR$/lib/etl" vcs="Git" /> </component> diff --git a/ci/lcovrc b/ci/lcovrc new file mode 100644 index 0000000000000000000000000000000000000000..1f8f4e3909219a3c55d2dc20e9b48ebb70c15409 --- /dev/null +++ b/ci/lcovrc @@ -0,0 +1,96 @@ +# genhtml configuration + +# External style sheet file +#genhtml_css_file = gcov.css + +# Width of line coverage field in source code view +genhtml_line_field_width = 12 + +# Width of branch coverage field in source code view +genhtml_branch_field_width = 16 + +# Width of overview image +genhtml_overview_width = 80 + +# Resolution of overview navigation +genhtml_nav_resolution = 4 + +# Offset for source code navigation +genhtml_nav_offset = 10 + +# Do not remove unused test descriptions if non-zero +genhtml_keep_descriptions = 1 + +# Do not remove prefix from directory names if non-zero +genhtml_no_prefix = 0 + +# Specify size of tabs +# genhtml_num_spaces = 8 + +# Highlight lines with converted-only data if non-zero +genhtml_highlight = 1 + +# Include color legend in HTML output if non-zero +genhtml_legend = 1 + +# Compress all generated html files with gzip. +genhtml_html_gzip = 0 + +# Include sorted overview pages +genhtml_sort = 1 + +# Include function coverage data display +genhtml_function_coverage = 1 + +# Include branch coverage data display +genhtml_branch_coverage = 1 + +# Specify the character set of all generated HTML pages +genhtml_charset=UTF-8 + + + + + +# geninfo configuration + +# Calculate a checksum for each line if non-zero +geninfo_checksum = 0 + +# Enable libtool compatibility mode if non-zero +geninfo_compat_libtool = 0 + +# Specify whether to capture coverage data for external source +# files +geninfo_external = 0 + +# Use gcov's --all-blocks option if non-zero +geninfo_gcov_all_blocks = 1 + +# Specify if geninfo should try to automatically determine +# the base-directory when collecting coverage data. +geninfo_auto_base = 1 + + + + + +# lcov configuration + +# Show full paths during list operation if non-zero +lcov_list_full_path = 1 + +# Specify the maximum width for list output. This value is +# ignored when lcov_list_full_path is non-zero. +#lcov_list_width = 80 + +# Specify the maximum percentage of file names which may be +# truncated when choosing a directory prefix in list output. +# This value is ignored when lcov_list_full_path is non-zero. +#lcov_list_truncate_max = 20 + +# Specify if function coverage data should be collected and processed. +lcov_function_coverage = 1 + +# Specify if branch coverage data should be collected andprocessed. +lcov_branch_coverage = 1 diff --git a/ci/page_style/custom_format.css b/ci/page_style/custom_format.css new file mode 100644 index 0000000000000000000000000000000000000000..5f5d8bdb1de416ded936f8093047ba9cbf6cf04d --- /dev/null +++ b/ci/page_style/custom_format.css @@ -0,0 +1,15 @@ +.coverLegendCovLo, .coverLegendCovMed, .coverLegendCovHi { + border-radius: 15px; +} + +#td.headerCovTableEntry { + border-radius: 15px; +} + +.headerCovTableEntryLo, .headerCovTableEntryMed, .headerCovTableEntryHi { + border-radius: 15px; +} + +.headerCovTableEntry { + border-radius: 15px; +} diff --git a/ci/page_style/doxygen_dark_theme b/ci/page_style/doxygen_dark_theme new file mode 160000 index 0000000000000000000000000000000000000000..460dbe28dbe807ee1b2d03dc712fe637a1b1ab6b --- /dev/null +++ b/ci/page_style/doxygen_dark_theme @@ -0,0 +1 @@ +Subproject commit 460dbe28dbe807ee1b2d03dc712fe637a1b1ab6b diff --git a/ci/page_style/epilog.html b/ci/page_style/epilog.html new file mode 100644 index 0000000000000000000000000000000000000000..b139036d7a0608fd210344ce151f1a1ccac68444 --- /dev/null +++ b/ci/page_style/epilog.html @@ -0,0 +1,3 @@ + <button onclick="window.location.href = 'gcovr/gcovr.html';">Gcovr Reports</button> + <link rel="stylesheet" href="custom_format.css"> +</body> diff --git a/ci/pages_deploy.sh b/ci/pages_deploy.sh new file mode 100755 index 0000000000000000000000000000000000000000..e957963ae95db41be2cf641519eefae3b68a2e70 --- /dev/null +++ b/ci/pages_deploy.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash + +# Bash color ouput +# https://misc.flogisoft.com/bash/tip_colors_and_formatting + +# Variables used in gcovr +EXCLUDED_FILES="^.*(test|lib|main.cpp|CMakeFiles)" +HTML_TITLE="Code coverage ${CI_PROJECT_NAME}/${CI_COMMIT_REF_NAME}" + +# Variables to use with lcov +cp ci/lcovrc ~/.lcovrc # The coverage configuration file resides in ~/ as ~/.lcovrc +PAGE_TITLE="${CI_COMMIT_REF_NAME}" + +# Assign the correct folder names +if [[ ${CI_COMMIT_REF_NAME} == "master" ]]; +then + ROOT_PATH="" + COVERAGE_PATH="coverage/" + DOCUMENT_PATH="docs/" +else + ROOT_PATH="${CI_COMMIT_REF_NAME}" + COVERAGE_PATH="coverage/${CI_COMMIT_REF_NAME}" + DOCUMENT_PATH="docs/${CI_COMMIT_REF_NAME}" +fi + +# Empty the contents from the stored cache, if any +rm -rf public/${DOCUMENT_PATH}/* + +# Create the necessary directories +mkdir -p public/${DOCUMENT_PATH} + + +# Try to make and build the application +cmake . -DCMAKE_CXX_FLAGS="-g -O0 --coverage" && make all -j4 + +# If the command above returned something different than zero, generate only the docs +if [[ $? -ne 0 ]]; +then + echo -e "\e[1;5;91mProgram build failed, only the documentation will be generated.\e[0m" +else + # Coverage generation using lcov + # Generate coverage baseline + lcov -q --capture --initial --directory . -o coverage_base + ./tests --use-colour yes # Run the tests to generate coverage notes + + # In the event of test failure, generate only the documentation + if [[ $? -ne 0 ]]; + then + echo -e "\e[1;5;91mTests failed, only documentation will be generated.\e[0m" + else + # Empty the contents from the stored cache, if any, and create the necessary directories + rm -rf public/${COVERAGE_PATH}/* + mkdir -p public/${COVERAGE_PATH} "public/${COVERAGE_PATH}/gcovr" + + # Generate the tracefile for the coverage reports + lcov -q --capture --directory . -o coverage_tests + lcov -q -a coverage_base -a coverage_tests -o coverage_total_unfiltered + + # Remove any unwanted files from coverage report, like external libraries + lcov -q --remove coverage_total_unfiltered "${PWD}/lib/*" "${PWD}/CMakeFiles/*" "${PWD}/test/*" "${PWD}/src/main.cpp" -o coverage_total_filtered + + + # Coverage generation using gcovr. Also generates the html page with the results + # Output a summary (-s), sort by ascending percentage (-p), exclude files (-e) + gcovr -s -p -e "${EXCLUDED_FILES}" --html --html-details --html-title "${HTML_TITLE}" -o public/${COVERAGE_PATH}/gcovr/gcovr.html + gcovr -e "^.*(test|lib|main.cpp|CMakeFiles)" # Generate coverage report for the CI + + # Render the html page for the lcov results + genhtml --demangle-cpp -t "${PAGE_TITLE}" --html-epilog ci/page_style/epilog.html -o public/${COVERAGE_PATH} coverage_total_filtered + cp ci/page_style/custom_format.css ci/page_style/epilog.html public/${COVERAGE_PATH} + + echo \ + " + .title:after { + content: \" for the ${CI_COMMIT_REF_NAME} branch\"; + } + " >> public/${COVERAGE_PATH}/custom_format.css + fi # Test failure check +fi # Build failure check + + +# Documentation generation +doxygen doxygen.conf +mv docs/html/* public/${DOCUMENT_PATH} + +# Expired branch deletion +git branch -a | grep "remote" | xargs -n 1 -i sh -c "path=\"{}\"; basename \"\$path\"" > branches_list +ls -d public/coverage/*/ | xargs -n 1 -i sh -c "name=\"{}\"; basename \"\$name\"" > directory_list + +# Output for debugging purposes +echo -e "\e[1;36mBranch names list\e[0m" +cat branches_list + +echo -e "\n\e[1;36mPublic directory contents list\e[0m" +cat directory_list + + +# Remove any expired branch folders +while read directory; +do + if ! grep -q "^${directory}$" branches_list + then + echo -e "\e[1;33m${directory} will be removed from the pages.\e[0m" + rm -rf "public/${directory}" "public/coverage/${directory}" "public/docs/${directory}" + fi +done < directory_list + +echo -e "\e[1;92mDocumentation page for this branch:\e[0m \e[0;36m${CI_PAGES_URL}/${DOCUMENT_PATH}\e[0m" +echo -e "\e[1;92mCoverage Reports page for this branch:\e[0m \e[0;36m${CI_PAGES_URL}/${COVERAGE_PATH}\e[0m\n" diff --git a/doxygen.conf b/doxygen.conf index 4dc3effc360ce57b2ee5b120aa7a03c25188f54e..894adb9c7745763b5dd4233bfeb7c9ba51fc1377 100644 --- a/doxygen.conf +++ b/doxygen.conf @@ -441,19 +441,19 @@ EXTRACT_ALL = YES # be included in the documentation. # The default value is: NO. -EXTRACT_PRIVATE = NO +EXTRACT_PRIVATE = YES # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. -EXTRACT_PACKAGE = NO +EXTRACT_PACKAGE = YES # If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. -EXTRACT_STATIC = NO +EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, @@ -1157,7 +1157,7 @@ HTML_FILE_EXTENSION = .html # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_HEADER = +HTML_HEADER = "ci/page_style/doxygen_dark_theme/html_header.html" # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard @@ -1167,7 +1167,7 @@ HTML_HEADER = # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_FOOTER = +HTML_FOOTER = "ci/page_style/doxygen_dark_theme/html_footer.html" # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of @@ -1192,7 +1192,8 @@ HTML_STYLESHEET = # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = +HTML_EXTRA_STYLESHEET = "ci/page_style/doxygen_dark_theme/custom.css" \ + "ci/page_style/doxygen_dark_theme/custom_dark_theme.css" # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1249,7 +1250,7 @@ HTML_TIMESTAMP = NO # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_DYNAMIC_SECTIONS = NO +HTML_DYNAMIC_SECTIONS = YES # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand