diff --git a/.github/scripts/compute_vmi_version.py b/.github/scripts/compute_vmi_version.py index 3a9e23b9c5..3d37f87217 100644 --- a/.github/scripts/compute_vmi_version.py +++ b/.github/scripts/compute_vmi_version.py @@ -15,12 +15,12 @@ def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser( - description="Compute the VMI release version from a version file." + description="Compute the VMI release version from the top-level CMakeLists.txt." ) parser.add_argument( - "--version-file", - default="docs/release/VMI_VERSION", - help="Path to the VMI version file.", + "--cmake-file", + default="CMakeLists.txt", + help="Path to the top-level CMakeLists.txt file.", ) parser.add_argument( "--check-tag", @@ -29,11 +29,17 @@ def parse_args() -> argparse.Namespace: return parser.parse_args() -def read_version(version_file: pathlib.Path) -> str: - version = version_file.read_text(encoding="utf-8").strip() - if not re.fullmatch(r"[0-9]+\.[0-9]+\.[0-9]+", version): - raise ValueError(f"invalid VMI version '{version}' in {version_file}") - return version +def read_version(cmake_file: pathlib.Path) -> str: + content = cmake_file.read_text(encoding="utf-8") + match = re.search( + r'set\s*\(\s*PTOAS_VMI_VERSION\s+"([0-9]+\.[0-9]+\.[0-9]+)"\s*\)', + content, + ) + if not match: + raise ValueError( + f'could not find \'set(PTOAS_VMI_VERSION "x.y.z")\' in {cmake_file}' + ) + return match.group(1) def normalize_tag(tag: str) -> str: @@ -47,8 +53,8 @@ def normalize_tag(tag: str) -> str: def main() -> int: args = parse_args() - version_file = pathlib.Path(args.version_file) - version = read_version(version_file) + cmake_file = pathlib.Path(args.cmake_file) + version = read_version(cmake_file) if args.check_tag is not None: normalized_tag = normalize_tag(args.check_tag) diff --git a/.github/scripts/update_vmi_version.py b/.github/scripts/update_vmi_version.py new file mode 100644 index 0000000000..8c029009d6 --- /dev/null +++ b/.github/scripts/update_vmi_version.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +# Copyright (c) 2026 Huawei Technologies Co., Ltd. +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of +# CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. + +import argparse +import pathlib +import re +import sys + + +VMI_VERSION_RE = re.compile( + r'(set\s*\(\s*PTOAS_VMI_VERSION\s+")([0-9]+\.[0-9]+\.[0-9]+)("\s*\))' +) +TAG_VERSION_RE = re.compile(r"^vmi-v([0-9]+)\.([0-9]+)\.([0-9]+)$") + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Update the VMI version in the top-level CMakeLists.txt." + ) + parser.add_argument( + "--cmake-file", + default="CMakeLists.txt", + help="Path to the top-level CMakeLists.txt file.", + ) + parser.add_argument( + "--version", + required=True, + help="Released VMI version, for example vmi-v0.1.3.", + ) + parser.add_argument( + "--next", + action="store_true", + help="Advance the resolved version by one patch step.", + ) + return parser.parse_args() + + +def normalize_version(version: str) -> str: + match = TAG_VERSION_RE.fullmatch(version.strip()) + if not match: + raise ValueError(f"invalid VMI release tag '{version}'") + return ".".join(match.groups()) + + +def bump_version(version: str) -> str: + major, minor, patch = (int(part) for part in version.split(".")) + return f"{major}.{minor}.{patch + 1}" + + +def update_version(cmake_file: pathlib.Path, version: str) -> bool: + content = cmake_file.read_text(encoding="utf-8") + updated, count = VMI_VERSION_RE.subn( + lambda match: f"{match.group(1)}{version}{match.group(3)}", + content, + count=1, + ) + if count != 1: + raise ValueError( + f'could not find \'set(PTOAS_VMI_VERSION "x.y.z")\' in {cmake_file}' + ) + if updated == content: + return False + cmake_file.write_text(updated, encoding="utf-8") + return True + + +def main() -> int: + args = parse_args() + version = normalize_version(args.version) + if args.next: + version = bump_version(version) + update_version(pathlib.Path(args.cmake_file), version) + print(version) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index e515dd7890..98a8ac0c9f 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -74,7 +74,6 @@ jobs: case "${GITHUB_REF_NAME}" in vmi-v*) EXPECTED_RELEASE_VERSION="$(${PY_PATH}/bin/python .github/scripts/compute_vmi_version.py \ - --version-file docs/release/VMI_VERSION \ --check-tag "${GITHUB_REF_NAME}")" PTOAS_VERSION="${GITHUB_REF_NAME#vmi-v}" PTOAS_CLI_VERSION="vmi ${PTOAS_VERSION}" @@ -403,3 +402,36 @@ jobs: git add CMakeLists.txt git commit -m "chore(release): bump base version to v${{ steps.bump.outputs.next_base_version }}" git push origin HEAD:${{ github.event.repository.default_branch }} + + bump_vmi_version: + name: Bump VMI version after release + if: github.event_name == 'release' && github.event.action == 'released' && startsWith(github.ref_name, 'vmi-v') + needs: upload_release_assets + runs-on: ubuntu-latest + + steps: + - name: Checkout default branch + uses: actions/checkout@v4 + with: + ref: ${{ github.event.repository.default_branch }} + + - name: Update VMI version + id: bump + run: | + next_vmi_version="$(python3 .github/scripts/update_vmi_version.py \ + --version "${GITHUB_REF_NAME}" \ + --next)" + echo "next_vmi_version=${next_vmi_version}" >> "$GITHUB_OUTPUT" + + - name: Commit version bump + run: | + if git diff --quiet -- CMakeLists.txt; then + echo "CMakeLists.txt already matches the next VMI version." + exit 0 + fi + + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add CMakeLists.txt + git commit -m "chore(release): bump VMI version to v${{ steps.bump.outputs.next_vmi_version }}" + git push origin HEAD:${{ github.event.repository.default_branch }} diff --git a/.github/workflows/build_wheel_mac.yml b/.github/workflows/build_wheel_mac.yml index a9d21b39a7..9948a32759 100644 --- a/.github/workflows/build_wheel_mac.yml +++ b/.github/workflows/build_wheel_mac.yml @@ -79,7 +79,6 @@ jobs: case "${GITHUB_REF_NAME}" in vmi-v*) EXPECTED_RELEASE_VERSION="$(python .github/scripts/compute_vmi_version.py \ - --version-file docs/release/VMI_VERSION \ --check-tag "${GITHUB_REF_NAME}")" PTOAS_VERSION="${GITHUB_REF_NAME#vmi-v}" PTOAS_CLI_VERSION="vmi ${PTOAS_VERSION}" diff --git a/CMakeLists.txt b/CMakeLists.txt index ecfe8d6018..e9f9fccbb3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,7 @@ endfunction() ptoas_preseed_compilers_from_llvm_cache() project(ptoas VERSION 0.52) +set(PTOAS_VMI_VERSION "0.1.4") option(PTOAS_VALIDATE_CMAKE4_FETCHCONTENT_COMPAT "Validate CMake 4 compatibility for legacy FetchContent users" OFF) diff --git a/docs/release/VMI_VERSION b/docs/release/VMI_VERSION deleted file mode 100644 index b1e80bb248..0000000000 --- a/docs/release/VMI_VERSION +++ /dev/null @@ -1 +0,0 @@ -0.1.3 diff --git a/test/python/test_release_version_scripts.py b/test/python/test_release_version_scripts.py index 4644e9cf04..235face241 100644 --- a/test/python/test_release_version_scripts.py +++ b/test/python/test_release_version_scripts.py @@ -61,14 +61,17 @@ def test_ptoas_version_script_accepts_ptoas_tag_prefix(self): def test_vmi_version_script_accepts_vmi_tag_prefix(self): with tempfile.TemporaryDirectory() as temp_dir: temp_root = Path(temp_dir) - version_file = temp_root / "VMI_VERSION" - version_file.write_text("0.1.0\n", encoding="utf-8") + cmake_file = temp_root / "CMakeLists.txt" + cmake_file.write_text( + 'project(ptoas VERSION 0.51)\nset(PTOAS_VMI_VERSION "0.1.0")\n', + encoding="utf-8", + ) result = subprocess.run( [ sys.executable, str(REPO_ROOT / ".github/scripts/compute_vmi_version.py"), - "--version-file", - str(version_file), + "--cmake-file", + str(cmake_file), "--check-tag", "vmi-v0.1.0", ], @@ -78,6 +81,57 @@ def test_vmi_version_script_accepts_vmi_tag_prefix(self): ) self.assertEqual(result.stdout.strip(), "0.1.0") + def test_vmi_version_bump_updates_only_vmi_version(self): + with tempfile.TemporaryDirectory() as temp_dir: + temp_root = Path(temp_dir) + cmake_file = temp_root / "CMakeLists.txt" + cmake_file.write_text( + 'project(ptoas VERSION 0.51)\nset(PTOAS_VMI_VERSION "0.1.9")\n', + encoding="utf-8", + ) + result = subprocess.run( + [ + sys.executable, + str(REPO_ROOT / ".github/scripts/update_vmi_version.py"), + "--cmake-file", + str(cmake_file), + "--version", + "vmi-v0.1.9", + "--next", + ], + check=True, + capture_output=True, + text=True, + ) + self.assertEqual(result.stdout.strip(), "0.1.10") + self.assertEqual( + cmake_file.read_text(encoding="utf-8"), + 'project(ptoas VERSION 0.51)\nset(PTOAS_VMI_VERSION "0.1.10")\n', + ) + + def test_vmi_version_bump_rejects_ptoas_tag(self): + with tempfile.TemporaryDirectory() as temp_dir: + temp_root = Path(temp_dir) + cmake_file = temp_root / "CMakeLists.txt" + cmake_file.write_text( + 'project(ptoas VERSION 0.51)\nset(PTOAS_VMI_VERSION "0.1.0")\n', + encoding="utf-8", + ) + result = subprocess.run( + [ + sys.executable, + str(REPO_ROOT / ".github/scripts/update_vmi_version.py"), + "--cmake-file", + str(cmake_file), + "--version", + "v0.51", + "--next", + ], + capture_output=True, + text=True, + ) + self.assertNotEqual(result.returncode, 0) + def test_ptoas_version_bump_rejects_vmi_tag(self): with tempfile.TemporaryDirectory() as temp_dir: temp_root = Path(temp_dir)