kNCurses/cmake/version.cmake

78 lines
3.4 KiB
CMake

##
# @brief a ${SEMANTIC_VERSION} based on Git tags (or a `VERSION` file) à la
# `v<major>.<minor>.<patch>` is provided
#
# Versions have the format "v<major>.<minor>.<patch>" in accordance with
# Semantic Versioning. If a version is provided by a file named `VERSION`, the
# full version must be given. If a version is provided by Git tags, only part of
# the version must be given, the format is then: "v<major>.<minor>". The <patch>
# version is automatically deduced from the distance in commits to the latest
# Git tag. The version set in the file overrides the tags in the Git repository.
#
# based upon Semantic Versioning: https://semver.org/
#
# @attention The <patch> version-part is a bit flaky; it gives the distance in
# commits to the <major>.<minor> version. Due to the non-linear
# nature of the commit history (because of branches), it is ambigous
# (i. e. multiple commits can be found at the same distance). On top
# of that, it is your job to make sure, that patches only fix bugs
# and do not change the API (no new functionalty; or old removed).
#
# One option to address both issues is: Stay in one branch for
# releases — for example named 'release' — and cherry-pick new
# versions into the branch (alphas, betas, candidates and releases).
# Optional: squash cherry-picked commits, so that the <patch> part of
# the version is only incremented by one.
# @warning To update the version you have to run CMake again.
#
# @todo escape/quote paths
# @todo test cases for CMake file components?
# @todo make variables local (see: unset()) and put them in a "namespace"
# @author Christian Burger <christian@krikkel.de>
find_package(Git)
function(get_semantic_version)
if(EXISTS "${CMAKE_SOURCE_DIR}/VERSION")
message(STATUS "using file `VERSION` to determine version")
file(READ "VERSION" REPOSITORY_VERSION)
elseif(GIT_FOUND)
message(STATUS "using Git to determine project version")
execute_process(COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_SOURCE_DIR} describe --always --match v[0-9]*.[0-9]*
OUTPUT_VARIABLE REPOSITORY_VERSION)
else()
message(WARNING "We need Git or a file \"VERSION\" to determine a version (e. g. \"v1.0\").")
endif()
# test cases
#set(REPOSITORY_VERSION "v0.1") # = 0.1.0
#set(REPOSITORY_VERSION "v0.1-1-g12345678") # = 0.1.1
#set(REPOSITORY_VERSION "v0.1") # = 0.0.0
#set(REPOSITORY_VERSION "1234abcd") # = 0.0.0
#set(REPOSITORY_VERSION "") # = 0.1.0
string(REGEX MATCH "^v([0-9]+)\.([0-9]+)([-\\.]([0-9]+))?" SEMANTIC_VERSION_PREPROCESSED "${REPOSITORY_VERSION}")
if("${SEMANTIC_VERSION_PREPROCESSED}" STREQUAL "")
message(STATUS "Found no version tag (e. g. \"v1.0\").")
endif()
set(SEMANTIC_VERSION_MAJOR ${CMAKE_MATCH_1})
set(SEMANTIC_VERSION_MINOR ${CMAKE_MATCH_2})
set(SEMANTIC_VERSION_PATCH ${CMAKE_MATCH_4})
if("${SEMANTIC_VERSION_MAJOR}" STREQUAL "")
set(SEMANTIC_VERSION "0.0.0")
else()
if("${SEMANTIC_VERSION_PATCH}" STREQUAL "")
set(SEMANTIC_VERSION_PATCH "0")
endif()
set(SEMANTIC_VERSION "${SEMANTIC_VERSION_MAJOR}.${SEMANTIC_VERSION_MINOR}.${SEMANTIC_VERSION_PATCH}")
endif()
message(STATUS "Project version is: ${SEMANTIC_VERSION}")
set(SEMANTIC_VERSION "${SEMANTIC_VERSION}" PARENT_SCOPE)
endfunction()
get_semantic_version()