Warning, /frameworks/extra-cmake-modules/kde-modules/KDEGitCommitHooks.cmake is written in an unsupported language. File is not indexed.

0001 # SPDX-FileCopyrightText: 2020-2023 Alexander Lohnau <alexander.lohnau@gmx.de>
0002 # SPDX-FileCopyrightText: 2022 Ahmad Samir <a.samirh78@gmail.com>
0003 # SPDX-FileCopyrightText: 2023 Johannes Zarl-Zierl <johannes@zarl-zierl.at>
0004 #
0005 # SPDX-License-Identifier: BSD-3-Clause
0006 
0007 #[=======================================================================[.rst:
0008 KDEGitCommitHooks
0009 --------------------
0010 
0011 This module provides a functionality to enforce formatting
0012 or in the future other QS checks.
0013 
0014 This module provides the following function:
0015 
0016 ::
0017 
0018   kde_configure_git_pre_commit_hook(
0019      CHECKS <check1> [<check2> [...]
0020      [CUSTOM_SCRIPTS [<script paths> [<script paths> ...]]] # since 5.109
0021   )
0022 
0023 This function will create a pre-commit hook which contains all the given checks.
0024 In addition to that, you can pass in paths to custom scripts that will be run as the pre-commit hook.
0025 If a custom hooks directory is set via ``core.hooksPath``, a warning is issued.
0026 
0027 Checks:
0028 
0029 - ``CLANG_FORMAT`` With this check enabled the ``git clang-format`` tool will be used to make sure that
0030   the changed parts are properly formatted. In case the changes are not properly formatted an error
0031   message with the command to preview the formatting changes and to format the files in place
0032   will be displayed. This tool will reuse the exsting ``.clang-format`` file, in case you
0033   want to use the one provided by ECM you can include ``include(KDEClangFormat)`` which will copy
0034   the file to the source dir. It is also recommended to reformat the entire project before enforcing
0035   the formatting using this commit hook.
0036   - ``JSON_SCHEMA`` Since 5.110, uses the check-jsonschema CLI tool to ensure that all files are valid JSON and
0037   match the KPluginMetaData spec. This only applied if the JSON file has a "KPlugin" object in its root.
0038   To ignore invalid files, for example for testing error handling, given files can be exlcuded in the .kde-ci.yml file
0039   Define Options.json-validate-ignore with an array of the files you want to ignore
0040 
0041 Example usage:
0042 
0043 .. code-block:: cmake
0044 
0045   include(KDEGitCommitHooks)
0046   kde_configure_git_pre_commit_hook(CHECKS JSON_SCHEMA CLANG_FORMAT)
0047 
0048 Since 5.79
0049 #]=======================================================================]
0050 
0051 # try to find clang-format in path
0052 find_program(KDE_CLANG_FORMAT_EXECUTABLE clang-format)
0053 find_program(KDE_CHECK_JSONSCHEMA_EXECUTABLE check-jsonschema)
0054 set(PRE_COMMIT_HOOK_UNIX "${CMAKE_CURRENT_LIST_DIR}/kde-git-commit-hooks/pre-commit.in")
0055 set(CLANG_FORMAT_UNIX "${CMAKE_CURRENT_LIST_DIR}/kde-git-commit-hooks/clang-format.sh")
0056 set(JSON_SCHEMA_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/kde-git-commit-hooks/json-schema.py")
0057 set(JSON_SCHEMA_IN "${CMAKE_CURRENT_LIST_DIR}/kde-git-commit-hooks/combined.schema.json.in")
0058 set(GIT_DIR "${CMAKE_SOURCE_DIR}/.git")
0059 set(GIT_HOOKS_DIR "${GIT_DIR}/hooks")
0060 set(JSON_SCHEMA_OUT "${GIT_HOOKS_DIR}/scripts/combined.schema.json")
0061 
0062 function(KDE_CONFIGURE_GIT_PRE_COMMIT_HOOK)
0063     set(_oneValueArgs "")
0064     set(_multiValueArgs CHECKS CUSTOM_SCRIPTS)
0065     cmake_parse_arguments(ARG "" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
0066 
0067     if(NOT CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
0068         message(STATUS "Project is not top level project - pre-commit hook not installed")
0069         return()
0070     endif()
0071 
0072     if(NOT ARG_CHECKS)
0073         message(FATAL_ERROR "No checks were specified")
0074     endif()
0075 
0076     find_package(Git QUIET)
0077 
0078     if (NOT IS_DIRECTORY ${GIT_DIR} # In case of tarballs there is no .git directory
0079         OR NOT (UNIX OR WIN32)
0080         OR NOT GIT_FOUND
0081         )
0082         return()
0083     endif()
0084 
0085     execute_process(COMMAND "${GIT_EXECUTABLE}" config --get core.hooksPath
0086         WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
0087         RESULT_VARIABLE _gitresult
0088         OUTPUT_VARIABLE _gitoutput
0089         ERROR_QUIET
0090         OUTPUT_STRIP_TRAILING_WHITESPACE)
0091 
0092     if(_gitresult EQUAL 0 AND NOT ${GIT_HOOKS_DIR} EQUAL "${_gitoutput}")
0093         message(WARNING "Git is configured to use '${_gitoutput}' for hooks. The generated commit hooks will likely not be executed.")
0094     endif()
0095 
0096     string(REPLACE ";" "\n" PRE_COMMIT_SCRIPTS "${ARG_CUSTOM_SCRIPTS}")
0097     set(_write_hook FALSE)
0098     if(KDE_CLANG_FORMAT_EXECUTABLE)
0099         list(FIND ARG_CHECKS "CLANG_FORMAT" _index)
0100         # Used to configure clang-format.sh script
0101         if (COMMAND KDE_CLANG_FORMAT)
0102             set(HAS_CLANG_FORMAT_COMMAND_INCLUDED TRUE)
0103         else()
0104             set(HAS_CLANG_FORMAT_COMMAND_INCLUDED FALSE)
0105         endif()
0106         if (${_index} GREATER -1)
0107             # get version of clang-format
0108             execute_process(
0109                 COMMAND "${KDE_CLANG_FORMAT_EXECUTABLE}" --version
0110                 OUTPUT_VARIABLE _clang_format_version_raw
0111                 ERROR_VARIABLE _clang_format_version_raw
0112             )
0113             if (_clang_format_version_raw MATCHES "clang-format version ([0-9]+)(\\.[0-9]+)*")
0114                 set(KDE_CLANG_FORMAT_MAJOR_VERSION "${CMAKE_MATCH_1}")
0115             endif()
0116             unset(_clang_format_version_raw)
0117             message(STATUS "Found clang-format version ${KDE_CLANG_FORMAT_MAJOR_VERSION}")
0118 
0119             set(CLANG_FORMAT_SCRIPT "\"$(git rev-parse --git-common-dir)\"/hooks/scripts/clang-format.sh")
0120             configure_file(${CLANG_FORMAT_UNIX} "${GIT_HOOKS_DIR}/scripts/clang-format.sh" @ONLY)
0121             set(PRE_COMMIT_SCRIPTS "\"$(git rev-parse --git-common-dir)\"/hooks/scripts/clang-format.sh\n${PRE_COMMIT_SCRIPTS}")
0122             set(_write_hook TRUE)
0123         endif()
0124     endif()
0125 
0126     list(FIND ARG_CHECKS "JSON_SCHEMA" _index)
0127     if (${_index} GREATER -1)
0128       set(_write_hook TRUE)
0129       foreach(path ${CMAKE_PREFIX_PATH};${CMAKE_INCLUDE_PATH})
0130           file(GLOB files "${path}/${KDE_INSTALL_DATADIR}/kf6/jsonschema/*.json") 
0131           set(SCHEMA_FILES ${SCHEMA_FILES};${files})
0132       endforeach()
0133         foreach (SCHEMA ${SCHEMA_FILES})
0134             if (SCHEMA_INCLUDES)
0135                 set(SCHEMA_INCLUDES "${SCHEMA_INCLUDES},")
0136             endif()
0137             set(SCHEMA_INCLUDES "${SCHEMA_INCLUDES}{\"$ref\": \"${SCHEMA}\"}")
0138         endforeach()
0139         configure_file(${JSON_SCHEMA_IN} ${JSON_SCHEMA_OUT} @ONLY)
0140         if (KDE_CHECK_JSONSCHEMA_EXECUTABLE)
0141             set(PRE_COMMIT_SCRIPTS "set -e\npython3 ${JSON_SCHEMA_SCRIPT} \"${JSON_SCHEMA_OUT}\"\n${PRE_COMMIT_SCRIPTS}")
0142         else()
0143             message(WARNING "check-jsonschema executable not found. Please install it using pip or using your package manager")
0144         endif()
0145     endif()
0146 
0147 
0148     set(_hook_file "${GIT_HOOKS_DIR}/pre-commit")
0149     # Appending to the file is quite ugly and causes edge cases. With the CUSTOM_SCRIPTS arg, this should not be needed though
0150     if (ECM_GLOBAL_FIND_VERSION VERSION_GREATER_EQUAL 5.109.0)
0151         set(PRE_COMMIT_SCRIPTS "# This file is autogenerated by kde_configure_git_pre_commit_hook, any changes will be lost! \n${PRE_COMMIT_SCRIPTS}")
0152         configure_file(${PRE_COMMIT_HOOK_UNIX} "${_hook_file}")
0153     else()
0154         if(NOT _write_hook)
0155             message(WARNING "No clang-format executable was found, skipping the formatting pre-commit hook")
0156             return()
0157         endif()
0158         # Doesn't exist? write away
0159         if(NOT EXISTS ${_hook_file})
0160             configure_file(${PRE_COMMIT_HOOK_UNIX} "${_hook_file}")
0161             return()
0162         endif()
0163 
0164         file(READ ${_hook_file} _contents)
0165 
0166         # For when CLANG_FORMAT_SCRIPT didn't have the 'git rev-parse --git-common-dir' part
0167         set(_old_cmd "./.git/hooks/scripts/clang-format.sh")
0168         string(FIND "${_contents}" "${_old_cmd}" _idx)
0169         if (${_idx} GREATER -1)
0170             string(REPLACE "${_old_cmd}" "${CLANG_FORMAT_SCRIPT}" _contents "${_contents}")
0171             file(WRITE ${_hook_file} "${_contents}")
0172             return()
0173         endif()
0174 
0175         string(FIND "${_contents}" "${CLANG_FORMAT_SCRIPT}" _idx)
0176         # File exists and doesn't have the clang-format.sh line, append it
0177         # so as to not overwrite users' customisations
0178         if (_idx EQUAL -1)
0179             file(APPEND ${_hook_file} "${CLANG_FORMAT_SCRIPT}")
0180         endif()
0181     endif()
0182 endfunction()