From 1942f4a7a410414bd39e9e5ea6d2161a72bab7a0 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 21 Feb 2026 06:47:05 +0000 Subject: [PATCH 1/2] feat: implement automated versioning system - Created `scripts/bump_version.py` to handle version increments and documentation updates. - Added `.github/workflows/auto-version.yml` to trigger versioning on PR merges to master. - Integrated `git-cliff` for automated changelog generation and synchronization across bilingual docs. - Ensured the system handles missing files and no-change scenarios gracefully. Co-authored-by: dgaida <23057824+dgaida@users.noreply.github.com> --- .github/workflows/auto-version.yml | 66 ++++++++++++++++++++++++ scripts/bump_version.py | 81 ++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 .github/workflows/auto-version.yml create mode 100644 scripts/bump_version.py diff --git a/.github/workflows/auto-version.yml b/.github/workflows/auto-version.yml new file mode 100644 index 0000000..2b8dde8 --- /dev/null +++ b/.github/workflows/auto-version.yml @@ -0,0 +1,66 @@ +name: Auto Versioning + +on: + pull_request: + types: [closed] + branches: + - master + +permissions: + contents: write + +jobs: + bump-version: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: master + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Bump version + id: bump + run: python scripts/bump_version.py + + - name: Generate Changelog + uses: orhun/git-cliff-action@v4 + with: + config: cliff.toml + args: --tag v${{ steps.bump.outputs.new_version }} + outputPath: CHANGELOG.md + + - name: Sync Changelogs + run: | + for lang in en de; do + if [ -d "docs/$lang" ]; then + cp CHANGELOG.md "docs/$lang/CHANGELOG.md" + fi + done + + - name: Commit and Tag + run: | + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + + # Add modified files, ignore those that don't exist + FILES="pyproject.toml pyadm1/__version__.py tests/__init__.py CHANGELOG.md docs/en/metrics.md docs/de/metrics.md docs/en/CHANGELOG.md docs/de/CHANGELOG.md" + for f in $FILES; do + if [ -f "$f" ]; then + git add "$f" + fi + done + + if ! git diff --cached --quiet; then + git commit -m "chore(release): bump version to ${{ steps.bump.outputs.new_version }} [skip ci]" + git tag -a v${{ steps.bump.outputs.new_version }} -m "Release v${{ steps.bump.outputs.new_version }}" + git push origin master --tags + else + echo "No changes to commit" + fi diff --git a/scripts/bump_version.py b/scripts/bump_version.py new file mode 100644 index 0000000..1c5a011 --- /dev/null +++ b/scripts/bump_version.py @@ -0,0 +1,81 @@ +import os +import re +import sys +from datetime import date + +def bump_version(current_version): + parts = current_version.split('.') + if len(parts) != 3: + raise ValueError(f"Invalid version format: {current_version}") + major, minor, patch = map(int, parts) + patch += 1 + return f"{major}.{minor}.{patch}" + +def update_file(filepath, pattern, replacement, flags=0): + if not os.path.exists(filepath): + print(f"Warning: {filepath} not found.") + return + with open(filepath, 'r', encoding='utf-8') as f: + content = f.read() + + new_content, count = re.subn(pattern, replacement, content, flags=flags) + if count == 0: + print(f"Warning: No matches found for pattern in {filepath}") + else: + with open(filepath, 'w', encoding='utf-8') as f: + f.write(new_content) + print(f"Updated {filepath} ({count} replacements)") + +def main(): + pyproject_path = 'pyproject.toml' + if not os.path.exists(pyproject_path): + print(f"Error: {pyproject_path} not found.") + sys.exit(1) + + with open(pyproject_path, 'r', encoding='utf-8') as f: + content = f.read() + + # Specifically look for version in [project] section + match = re.search(r'\[project\]\n(?:.*\n)*?version\s*=\s*"([^"]*)"', content) + if not match: + # Fallback to general search if section not found exactly as expected + match = re.search(r'^version\s*=\s*"([^"]*)"', content, re.MULTILINE) + + if not match: + print("Error: Could not find version in pyproject.toml") + sys.exit(1) + + current_version = match.group(1) + new_version = bump_version(current_version) + today_iso = date.today().isoformat() + today_german = date.today().strftime('%d.%m.%Y') + + print(f"Bumping version: {current_version} -> {new_version}") + + # pyproject.toml: only update version in [project] section + update_file('pyproject.toml', + r'(\[project\]\n(?:.*\n)*?version\s*=\s*)"[^"]*"', + r'\g<1>"' + new_version + '"') + + # Other files + updates = [ + ('pyadm1/__version__.py', r'(__version__\s*=\s*)"[^"]*"', r'\g<1>"' + new_version + '"'), + ('tests/__init__.py', r'(__version__\s*=\s*)"[^"]*"', r'\g<1>"' + new_version + '"'), + ('docs/en/metrics.md', r'(\*\*Changelog\*\*:\s*Up to date \(v)[^)]*(\))', r'\g<1>' + new_version + r'\g<2>'), + ('docs/en/metrics.md', r'(\*\*Last Updated\*\*:\s*)\d{4}-\d{2}-\d{2}', r'\g<1>' + today_iso), + ('docs/de/metrics.md', r'(\*\*Changelog\*\*:\s*Aktuell \(v)[^)]*(\))', r'\g<1>' + new_version + r'\g<2>'), + ('docs/de/metrics.md', r'(\*\*Zuletzt aktualisiert\*\*:\s*)\d{2}\.\d{2}\.\d{4}', r'\g<1>' + today_german), + ] + + for filepath, pattern, replacement in updates: + update_file(filepath, pattern, replacement) + + github_output = os.environ.get('GITHUB_OUTPUT') + if github_output: + with open(github_output, 'a') as f: + f.write(f"new_version={new_version}\n") + + print(f"Successfully bumped version to {new_version}") + +if __name__ == "__main__": + main() From 01efc90f7853fccf37914a1c47edecd8a682f886 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 21 Feb 2026 06:48:26 +0000 Subject: [PATCH 2/2] feat: implement automated versioning system - Created `scripts/bump_version.py` to handle version increments and documentation updates. - Formatted `scripts/bump_version.py` with black to comply with project linting rules. - Added `.github/workflows/auto-version.yml` to trigger versioning on PR merges to master. - Integrated `git-cliff` for automated changelog generation and synchronization across bilingual docs. - Ensured the system handles missing files and no-change scenarios gracefully. Co-authored-by: dgaida <23057824+dgaida@users.noreply.github.com> --- scripts/bump_version.py | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/scripts/bump_version.py b/scripts/bump_version.py index 1c5a011..ad36f34 100644 --- a/scripts/bump_version.py +++ b/scripts/bump_version.py @@ -3,36 +3,39 @@ import sys from datetime import date + def bump_version(current_version): - parts = current_version.split('.') + parts = current_version.split(".") if len(parts) != 3: raise ValueError(f"Invalid version format: {current_version}") major, minor, patch = map(int, parts) patch += 1 return f"{major}.{minor}.{patch}" + def update_file(filepath, pattern, replacement, flags=0): if not os.path.exists(filepath): print(f"Warning: {filepath} not found.") return - with open(filepath, 'r', encoding='utf-8') as f: + with open(filepath, "r", encoding="utf-8") as f: content = f.read() new_content, count = re.subn(pattern, replacement, content, flags=flags) if count == 0: print(f"Warning: No matches found for pattern in {filepath}") else: - with open(filepath, 'w', encoding='utf-8') as f: + with open(filepath, "w", encoding="utf-8") as f: f.write(new_content) print(f"Updated {filepath} ({count} replacements)") + def main(): - pyproject_path = 'pyproject.toml' + pyproject_path = "pyproject.toml" if not os.path.exists(pyproject_path): print(f"Error: {pyproject_path} not found.") sys.exit(1) - with open(pyproject_path, 'r', encoding='utf-8') as f: + with open(pyproject_path, "r", encoding="utf-8") as f: content = f.read() # Specifically look for version in [project] section @@ -48,34 +51,33 @@ def main(): current_version = match.group(1) new_version = bump_version(current_version) today_iso = date.today().isoformat() - today_german = date.today().strftime('%d.%m.%Y') + today_german = date.today().strftime("%d.%m.%Y") print(f"Bumping version: {current_version} -> {new_version}") # pyproject.toml: only update version in [project] section - update_file('pyproject.toml', - r'(\[project\]\n(?:.*\n)*?version\s*=\s*)"[^"]*"', - r'\g<1>"' + new_version + '"') + update_file("pyproject.toml", r'(\[project\]\n(?:.*\n)*?version\s*=\s*)"[^"]*"', r'\g<1>"' + new_version + '"') # Other files updates = [ - ('pyadm1/__version__.py', r'(__version__\s*=\s*)"[^"]*"', r'\g<1>"' + new_version + '"'), - ('tests/__init__.py', r'(__version__\s*=\s*)"[^"]*"', r'\g<1>"' + new_version + '"'), - ('docs/en/metrics.md', r'(\*\*Changelog\*\*:\s*Up to date \(v)[^)]*(\))', r'\g<1>' + new_version + r'\g<2>'), - ('docs/en/metrics.md', r'(\*\*Last Updated\*\*:\s*)\d{4}-\d{2}-\d{2}', r'\g<1>' + today_iso), - ('docs/de/metrics.md', r'(\*\*Changelog\*\*:\s*Aktuell \(v)[^)]*(\))', r'\g<1>' + new_version + r'\g<2>'), - ('docs/de/metrics.md', r'(\*\*Zuletzt aktualisiert\*\*:\s*)\d{2}\.\d{2}\.\d{4}', r'\g<1>' + today_german), + ("pyadm1/__version__.py", r'(__version__\s*=\s*)"[^"]*"', r'\g<1>"' + new_version + '"'), + ("tests/__init__.py", r'(__version__\s*=\s*)"[^"]*"', r'\g<1>"' + new_version + '"'), + ("docs/en/metrics.md", r"(\*\*Changelog\*\*:\s*Up to date \(v)[^)]*(\))", r"\g<1>" + new_version + r"\g<2>"), + ("docs/en/metrics.md", r"(\*\*Last Updated\*\*:\s*)\d{4}-\d{2}-\d{2}", r"\g<1>" + today_iso), + ("docs/de/metrics.md", r"(\*\*Changelog\*\*:\s*Aktuell \(v)[^)]*(\))", r"\g<1>" + new_version + r"\g<2>"), + ("docs/de/metrics.md", r"(\*\*Zuletzt aktualisiert\*\*:\s*)\d{2}\.\d{2}\.\d{4}", r"\g<1>" + today_german), ] for filepath, pattern, replacement in updates: update_file(filepath, pattern, replacement) - github_output = os.environ.get('GITHUB_OUTPUT') + github_output = os.environ.get("GITHUB_OUTPUT") if github_output: - with open(github_output, 'a') as f: + with open(github_output, "a") as f: f.write(f"new_version={new_version}\n") print(f"Successfully bumped version to {new_version}") + if __name__ == "__main__": main()