visualboyadvance-m/cmake/MakeReleaseCommitAndTag.cmake

257 lines
7.1 KiB
CMake

# Set TAG_RELEASE to ON/TRUE/1 to increment minor, or to new version, or to
# UNDO to undo release.
# Increment version.
# Update CHANGELOG.md with git log.
# Make release commit.
# Tag release commit.
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/.git")
message(FATAL_ERROR "releases can only be done from a git clone")
endif()
find_package(Git)
if(NOT GIT_FOUND)
message(FATAL_ERROR "git is required to make a release")
endif()
find_program(GPG_EXECUTABLE gpg)
if(NOT GPG_EXECUTABLE)
message(FATAL_ERROR "gpg must be installed and set up with your key to make a release")
endif()
# From: https://gist.github.com/alorence/59d18896aaad5188b7b4.
macro(CURRENT_DATE RESULT)
if(CMAKE_HOST_SYSTEM MATCHES Windows OR ((NOT DEFINED CMAKE_HOST_SYSTEM) AND WIN32))
execute_process(COMMAND "cmd" " /C date /T" OUTPUT_VARIABLE ${RESULT})
string(REGEX REPLACE ".*(..)/(..)/(....).*" "\\3-\\1-\\2" ${RESULT} ${${RESULT}})
else()
execute_process(COMMAND "date" "+%Y-%m-%d" OUTPUT_VARIABLE ${RESULT})
endif()
endmacro()
function(make_release_commit_and_tag)
# First make sure we are on master.
execute_process(
COMMAND ${GIT_EXECUTABLE} rev-parse --short --abbrev-ref=strict HEAD
OUTPUT_VARIABLE git_branch
OUTPUT_STRIP_TRAILING_WHITESPACE
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
if(NOT git_branch STREQUAL master)
message(FATAL_ERROR "you must be on the git master branch to release")
endif()
execute_process(
COMMAND ${GIT_EXECUTABLE} status --porcelain=2
OUTPUT_VARIABLE git_status
OUTPUT_STRIP_TRAILING_WHITESPACE
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
string(LENGTH "${git_status}" git_status_length)
if(NOT git_status_length EQUAL 0)
message(FATAL_ERROR "working tree must be clean to do a release")
endif()
execute_process(
COMMAND ${GIT_EXECUTABLE} tag --sort=-v:refname
OUTPUT_VARIABLE git_tags
OUTPUT_STRIP_TRAILING_WHITESPACE
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
string(REGEX REPLACE ";" "\\\\;" git_tags_lines "${git_tags}")
string(REGEX REPLACE "\r?\n" ";" git_tags_lines "${git_tags_lines}")
foreach(line ${git_tags_lines})
if(line MATCHES "^v[0-9]")
set(git_last_tag ${line})
break()
endif()
endforeach()
if(NOT DEFINED git_last_tag)
message(FATAL_ERROR "cannot find last release tag")
endif()
execute_process(
COMMAND ${GIT_EXECUTABLE} log ${git_last_tag}.. "--pretty=format:* %h - %s [%aL]"
OUTPUT_VARIABLE release_log
OUTPUT_STRIP_TRAILING_WHITESPACE
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
# Calculate new release version, unless it was passed in.
if(TAG_RELEASE STREQUAL UNDO)
execute_process(
COMMAND ${GIT_EXECUTABLE} tag -d ${git_last_tag}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
execute_process(
COMMAND ${GIT_EXECUTABLE} reset HEAD~1
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
execute_process(
COMMAND ${GIT_EXECUTABLE} checkout HEAD CHANGELOG.md
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
message(FATAL_ERROR [=[
**** RELEASE COMMIT AND TAG HAVE BEEN REMOVED ****"
The git and working tree state have been restored to their state before the
TAG_RELEASE operation.
Ignore the following cmake error.
]=])
elseif(NOT (TAG_RELEASE STREQUAL TRUE OR TAG_RELEASE STREQUAL ON OR TAG_RELEASE STREQUAL 1))
set(new_tag ${TAG_RELEASE})
else()
string(REGEX MATCH "\\.[0-9]+$" last_tag_minor_part ${git_last_tag})
string(REGEX REPLACE "\\.[0-9]+$" "" last_tag_minor_stripped ${git_last_tag})
string(SUBSTRING ${last_tag_minor_part} 1 -1 last_tag_minor)
math(EXPR last_minor_incremented "${last_tag_minor} + 1")
string(CONCAT new_tag ${last_tag_minor_stripped} . ${last_minor_incremented})
endif()
# Make sure tag begins with "v".
if(NOT new_tag MATCHES "^v")
set(new_tag "v${new_tag}")
endif()
# But remove the "v" for the version string.
string(REGEX REPLACE "^v" "" new_version ${new_tag})
current_date(current_date)
# Rewrite CHANGELOG.md
# First make a copy for backing out.
configure_file(
${CMAKE_SOURCE_DIR}/CHANGELOG.md
${CMAKE_BINARY_DIR}/CHANGELOG.md.orig
COPYONLY
)
# Now read it and add the new release.
include(FileIterator)
fi_open_file(${CMAKE_SOURCE_DIR}/CHANGELOG.md)
set(work_file ${CMAKE_BINARY_DIR}/CHANGELOG.md.work)
file(REMOVE ${work_file})
set(last_release_found FALSE)
while(NOT fi_done)
fi_get_next_line()
if(NOT last_release_found AND fi_line MATCHES "^## \\[[0-9]")
set(last_release_found TRUE)
set(tag_line "## [${new_version}] - ${current_date}")
string(LENGTH "${tag_line}" tag_line_length)
unset(tag_line_under_bar)
foreach(i RANGE 1 ${tag_line_length})
set(tag_line_under_bar "=${tag_line_under_bar}")
endforeach()
file(APPEND ${work_file} ${tag_line} "\n")
file(APPEND ${work_file} ${tag_line_under_bar} "\n")
file(APPEND ${work_file} "${release_log}" "\n")
file(APPEND ${work_file} "\n")
endif()
file(APPEND ${work_file} "${fi_line}" "\n")
endwhile()
# Convert to UNIX line endings on Windows, just copy the file otherwise.
if(CMAKE_HOST_SYSTEM MATCHES Windows OR ((NOT DEFINED CMAKE_HOST_SYSTEM) AND WIN32))
execute_process(
COMMAND powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command [=[
$text = [IO.File]::ReadAllText("CHANGELOG.md.work") -replace "`r`n", "`n"
[IO.File]::WriteAllText("CHANGELOG.md", $text)
]=]
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
else()
configure_file(
${CMAKE_BINARY_DIR}/CHANGELOG.md.work
${CMAKE_BINARY_DIR}/CHANGELOG.md
COPYONLY
)
endif()
# Copy the new file and add it to the commit.
configure_file(
${CMAKE_BINARY_DIR}/CHANGELOG.md
${CMAKE_SOURCE_DIR}/CHANGELOG.md
COPYONLY
)
execute_process(
COMMAND ${GIT_EXECUTABLE} add CHANGELOG.md
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
# Make the release commit.
execute_process(
COMMAND ${GIT_EXECUTABLE} commit -m "release ${new_tag}" --signoff -S
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
# Make release tag.
execute_process(
COMMAND ${GIT_EXECUTABLE} tag -s -m${new_tag} ${new_tag}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
message(FATAL_ERROR [=[
Release commit and tag generated.
**** IF YOU ARE SURE YOU WANT TO RELEASE ****
Run the following commands to push the release commit and tag:
git push
git push --tags
**** TO UNDO THE RELEASE ****
To rollback these changes, run this command:
cmake .. -DTAG_RELEASE=UNDO
Ignore the "configuration incomplete" message following, this mode does not
build anything.
]=])
endfunction()
make_release_commit_and_tag()