From 615e45f8730b7a718e763fa20d2874151409e521 Mon Sep 17 00:00:00 2001 From: Anton Chernov Date: Wed, 2 Sep 2026 02:32:19 +0300 Subject: [PATCH] Fixed version-bump-on-development.yml; Updated make_release.py --- .../workflows/version-bump-on-development.yml | 18 ++-- README.md | 12 ++- make_release.py | 82 ++++++++++++------- 3 files changed, 70 insertions(+), 42 deletions(-) diff --git a/.github/workflows/version-bump-on-development.yml b/.github/workflows/version-bump-on-development.yml index 92a47ee..f3fb88b 100644 --- a/.github/workflows/version-bump-on-development.yml +++ b/.github/workflows/version-bump-on-development.yml @@ -50,18 +50,18 @@ jobs: import re from pathlib import Path - version_file = Path('app/main.cpp') + version_file = Path('app/main.cpp') text = version_file.read_text(encoding='utf-8') - major = re.search(r'^#define\s+VERSION_MAJOR\s+(\d+)', text, re.M) - minor = re.search(r'^#define\s+VERSION_MINOR\s+(\d+)', text, re.M) - patch = re.search(r'^#define\s+VERSION_PATCH\s+(\d+)', text, re.M) + major = re.search(r'^#define\s+VERSION_MAJOR\s+(\d+)', text, re.M) + minor = re.search(r'^#define\s+VERSION_MINOR\s+(\d+)', text, re.M) + patch = re.search(r'^#define\s+VERSION_PATCH\s+(\d+)', text, re.M) - if not (major and minor and patch): - raise SystemExit('Unable to determine version from app/main.cpp') - next_version = f"{major.group(1)}.{minor.group(1)}.{int(patch.group(1)) + 1}" + if not (major and minor and patch): + raise SystemExit('Unable to determine version from app/main.cpp') + next_version = f"{major.group(1)}.{minor.group(1)}.{int(patch.group(1)) + 1}" with open(os.environ['GITHUB_OUTPUT'], 'a', encoding='utf-8') as out: - out.write(f'version={next_version}\n') + out.write(f'version={next_version}\n') print(f'Computed next version: {next_version}') @@ -82,7 +82,7 @@ jobs: git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add CMakeLists.txt app/main.cpp + git add -u if git diff --cached --quiet; then echo "No version changes detected. Nothing to commit." exit 0 diff --git a/README.md b/README.md index b81715f..dc985a3 100644 --- a/README.md +++ b/README.md @@ -140,7 +140,7 @@ By default, `linux_build.sh` uses the `Output` directory. Its executable is: Versions use the `MAJOR.MINOR.PATCH` format and are updated with: ```bash -python3 make_release.py 0.1.1 --skip-build +python3 make_release.py 0.1.1 ``` The script synchronizes: @@ -148,10 +148,14 @@ The script synchronizes: - the CMake project version in `CMakeLists.txt`; - the `@version` field in `app/main.cpp`; - the `VERSION_MAJOR`, `VERSION_MINOR`, and `VERSION_PATCH` macros; -- the embedded `FileVersion` and `ProductVersion` strings. +- the embedded `FileVersion` and `ProductVersion` strings; +- the version shown in `README.md`, `docs/mainpage.md`, and `docs/Doxyfile`. + +Without `--skip-build`, the script builds the project after updating metadata +and restores the previous files if the build fails. + +CI can update only the version metadata by passing `--skip-build`. -Without `--skip-build`, the script builds the project after updating the -metadata and restores the previous files if the build fails. ## Next Steps diff --git a/make_release.py b/make_release.py index 8de86dd..dd187ea 100755 --- a/make_release.py +++ b/make_release.py @@ -94,30 +94,52 @@ def validate(self) -> bool: print("{} is not available".format(self.CMAKE_FILE)) return False - required_files = ( - self.MAIN_CPP_FILE, - self.MAINPAGE_FILE, - self.DOXYFILE, - ) + required_files = (self.MAINPAGE_FILE, self.DOXYFILE) for file in required_files: if not isfile(file): print("{} is not available".format(file)) return False + if not self.findSourceFiles(): + print("No project source files were found in {}".format(self.CMAKE_FILE)) + return False + self.check_passed = True return True def isValid(self) -> bool: return self.check_passed + # Read project source paths from the CMake source and header lists. + def findSourceFiles(self) -> tuple: + with File(self.CMAKE_FILE, "r") as opened_file: + cmake_content = opened_file.read() + + source_files = [] + for list_name in ("SOURCES_LIST", "HEADERS_LIST"): + match = re.search( + r"set\s*\(\s*{}\s*(.*?)\)".format(list_name), + cmake_content, + re.DOTALL, + ) + if match is None: + continue + + for line in match.group(1).splitlines(): + path = line.split("#", 1)[0].strip() + if path and "${" not in path and isfile(path): + source_files.append(path) + + return tuple(source_files) + # Step 2: collect the files that need version metadata updates. def findLibFiles(self) -> tuple: flist = [ self.CMAKE_FILE, - self.MAIN_CPP_FILE, self.MAINPAGE_FILE, self.DOXYFILE, ] + flist.extend(self.findSourceFiles()) if not self.skip_readme and isfile(self.README_FILE): flist.append(self.README_FILE) return tuple(flist) @@ -184,6 +206,7 @@ def updateFiles(self, ftuple: tuple = ()) -> None: ) MAINPAGE_VER = r"(\*\*Version:\*\*\s+)\d+\.\d+\.\d+" DOXYFILE_VER = r"(?m)^(PROJECT_NUMBER\s+=\s+)\d+\.\d+\.\d+" + source_files = self.findSourceFiles() VER = self.lib_ver.split('.') for file in ftuple: @@ -201,35 +224,36 @@ def updateFiles(self, ftuple: tuple = ()) -> None: content, count=1, ) - elif file == self.MAIN_CPP_FILE: + elif file in source_files: content = re.sub( HEADER, rf"\g<1>{self.lib_ver}", content, count=1, ) - major, minor, patch = VER - content = re.sub(MAJOR_VER, rf"\g<1>{major}", content, count=1) - content = re.sub(MINOR_VER, rf"\g<1>{minor}", content, count=1) - content = re.sub(PATCH_VER, rf"\g<1>{patch}", content, count=1) - content = re.sub( - FILE_VER, - rf"\g<1>{major}.{minor}.{patch}.0\g<2>", - content, - count=1, - ) - content = re.sub( - PROD_VER, - rf"\g<1>{major}.{minor}.{patch}.0\g<2>", - content, - count=1, - ) - content = re.sub( - COPYRIGHT, - rf"\g<1>Anton Chernov, {YEAR}\g<2>", - content, - count=1, - ) + if file == self.MAIN_CPP_FILE: + major, minor, patch = VER + content = re.sub(MAJOR_VER, rf"\g<1>{major}", content, count=1) + content = re.sub(MINOR_VER, rf"\g<1>{minor}", content, count=1) + content = re.sub(PATCH_VER, rf"\g<1>{patch}", content, count=1) + content = re.sub( + FILE_VER, + rf"\g<1>{major}.{minor}.{patch}.0\g<2>", + content, + count=1, + ) + content = re.sub( + PROD_VER, + rf"\g<1>{major}.{minor}.{patch}.0\g<2>", + content, + count=1, + ) + content = re.sub( + COPYRIGHT, + rf"\g<1>Anton Chernov, {YEAR}\g<2>", + content, + count=1, + ) elif file == self.README_FILE: if self.skip_readme: continue