Skip to content

Commit

Permalink
chore: Add package version update action (#78)
Browse files Browse the repository at this point in the history
  • Loading branch information
akotyla authored Oct 23, 2024
1 parent 17f9ac2 commit 2d92dae
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 12 deletions.
4 changes: 4 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
### Checklist

- [ ] I have updated the documentation accordingly.
- [ ] I have updated the CHANGELOG.md file accordingly.
67 changes: 67 additions & 0 deletions .github/workflows/semantic_release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Semantic Release

on:
workflow_dispatch:
inputs:
updateType:
description: "version update type"
required: true
type: choice
default: "patch"
options:
- "major"
- "minor"
- "patch"
packageName:
description: "name of the package to update"
required: true
type: choice
options:
- "ragbits"
- "ragbits-cli"
- "ragbits-core"
- "ragbits-document-search"

jobs:
release:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write
steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v2
with:
version: "0.4.10"

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"

- name: Create release branch
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git checkout -b release/${{ github.event.inputs.packageName }}-$(date +%Y-%m-%d)
- name: Update packages
id: packages_update
run: |
echo old_version=`grep version packages/${{ github.event.inputs.packageName }}/pyproject.toml | cut -d \" -f2` >> $GITHUB_OUTPUT
uv run scripts/update_ragbits_package.py ${{ github.event.inputs.packageName }} ${{ github.event.inputs.updateType }}
echo new_version=`grep version packages/${{ github.event.inputs.packageName }}/pyproject.toml | cut -d \" -f2` >> $GITHUB_OUTPUT
uv sync
- name: Create PR with updated packages
run: |
COMMIT_MESSAGE="release(${{ github.event.inputs.packageName }}): update to v${{ steps.packages_update.outputs.new_version }}"
git add .
git commit -m "$COMMIT_MESSAGE"
git push -u origin HEAD
gh pr create -B main --title "$COMMIT_MESSAGE" \
--body 'Update ${{ github.event.inputs.packageName }} version from ${{ steps.packages_update.outputs.old_version }} to ${{ steps.packages_update.outputs.new_version }}'
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
12 changes: 12 additions & 0 deletions packages/ragbits-cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# CHANGELOG

## Unreleased

## 0.1.0 (2024-10-08)

### Added

- Initial release of the package.
- Add prompts lab command.
- Add prompts generate-promptfoo-configs command.

17 changes: 17 additions & 0 deletions packages/ragbits-core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# CHANGELOG

## Unreleased

## 0.1.0 (2024-10-08)

### Added


- Initial release of the package.
- Introduce core components: Prompts, LLMs, Embeddings and VectorStores.
- `Prompt` class integration with promptfoo.
- LiteLLM integration.
- ChromaDB integration.
- Prompts lab.
- Prompts autodiscovery.

12 changes: 12 additions & 0 deletions packages/ragbits-document-search/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# CHANGELOG

## Unreleased


## 0.1.0 (2024-10-08)

### Added

- Initial release of the package.
- Introduce core modules: documents, ingestion and retrival.
- Unstructured integration.
26 changes: 26 additions & 0 deletions packages/ragbits/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# CHANGELOG

## Unreleased

## 0.1.0 (2024-10-08)

### Added

- ragbits-core v0.1.0:
- Initial release of the package.
- Introduce core components: Prompts, LLMs, Embeddings and VectorStores.
- `Prompt` class integration with promptfoo.
- LiteLLM integration.
- ChromaDB integration.
- Prompts lab.
- Prompts autodiscovery.

- ragbits-cli v0.1.0:
- Initial release of the package.
- Add prompts lab command.
- Add prompts generate-promptfoo-configs command.

- ragbits-document-search v0.1.0:
- Initial release of the package.
- Introduce core modules: documents, ingestion and retrival.
- Unstructured integration.
107 changes: 95 additions & 12 deletions scripts/update_ragbits_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
#
# uv run scripts/update_ragbits_package.py
#

import re
from copy import deepcopy
from datetime import datetime
from enum import Enum
from pathlib import Path
from typing import Optional
Expand Down Expand Up @@ -46,17 +47,15 @@ def _version_to_list(version_string):
return [int(part) for part in version_string.split(".")]


def _check_update_type(version: str, new_version: str) -> Optional[UpdateType]:
def _check_update_type(version: str, new_version: str) -> UpdateType:
version_list = _version_to_list(version)
new_version_list = _version_to_list(new_version)

if version_list[0] != new_version_list[0]:
return UpdateType.MAJOR
if version_list[1] != new_version_list[1]:
return UpdateType.MINOR
if version_list[2] != new_version_list[2]:
return UpdateType.PATCH
return None
return UpdateType.PATCH


def _get_updated_version(version: str, update_type: UpdateType) -> str:
Expand All @@ -78,6 +77,7 @@ def _update_pkg_version(
pkg_pyproject: Optional[tomlkit.TOMLDocument] = None,
new_version: Optional[str] = None,
update_type: Optional[UpdateType] = None,
sync_ragbits_version: bool = False,
) -> tuple[str, str]:
if not pkg_pyproject:
pkg_pyproject = tomlkit.parse((PACKAGES_DIR / pkg_name / "pyproject.toml").read_text())
Expand All @@ -97,9 +97,87 @@ def _update_pkg_version(
assert isinstance(new_version, str)
pprint(f"[green]The {pkg_name} package was successfully updated from {version} to {new_version}.[/green]")

if pkg_name != "ragbits":
_sync_ragbits_deps(pkg_name, version, new_version, sync_ragbits_version)

_create_changelog_release(pkg_name=pkg_name, new_version=new_version)

return version, new_version


def _sync_ragbits_deps(pkg_name: str, pkg_version: str, pkg_new_version: str, update_version: bool = True):
ragbits_pkg_project = tomlkit.parse((PACKAGES_DIR / "ragbits" / "pyproject.toml").read_text())
ragbits_deps: list[str] = [dep.split("==")[0] for dep in ragbits_pkg_project["project"]["dependencies"]]

update_type = _check_update_type(pkg_version, pkg_new_version)

if pkg_name in ragbits_deps:
idx = ragbits_pkg_project["project"]["dependencies"].index(f"{pkg_name}=={pkg_version}")
del ragbits_pkg_project["project"]["dependencies"][idx]
ragbits_pkg_project["project"]["dependencies"].insert(idx, f"{pkg_name}=={pkg_new_version}")
_add_updated_dependency_to_changelog("ragbits", pkg_name, pkg_new_version)

if update_version:
ragbits_old_version = ragbits_pkg_project["project"]["version"]
ragbits_new_version = _get_updated_version(ragbits_old_version, update_type=update_type)
ragbits_pkg_project["project"]["version"] = ragbits_new_version

pprint(
"[green]The ragbits package was successfully updated "
f"from {ragbits_old_version} to {ragbits_new_version}.[/green]"
)
_create_changelog_release(pkg_name="ragbits", new_version=ragbits_new_version)

(PACKAGES_DIR / "ragbits" / "pyproject.toml").write_text(tomlkit.dumps(ragbits_pkg_project))


def _add_updated_dependency_to_changelog(pkg_name: str, dependency_name: str, new_dependency_version: str) -> None:
changelog_path = PACKAGES_DIR / pkg_name / "CHANGELOG.md"
changelog_content = changelog_path.read_text()

# Find the "## Unreleased" section
unreleased_match = re.search(r"^## Unreleased\s*$", changelog_content, re.MULTILINE)
if unreleased_match:
unreleased_index = unreleased_match.end()

# Find the next section after "## Unreleased"
next_section_match = re.search(r"^##\s", changelog_content[unreleased_index:], re.MULTILINE)
next_section_index = (
unreleased_index + next_section_match.start() if next_section_match else len(changelog_content)
)

# Check if "### Changed" exists in the "## Unreleased" section
changed_match = re.search(
r"^### Changed\s*$", changelog_content[unreleased_index:next_section_index], re.MULTILINE
)
if not changed_match:
# If "### Changed" does not exist, create it above any existing sections
changelog_content = (
changelog_content[:unreleased_index]
+ f"\n### Changed\n\n- {dependency_name} updated to version v{new_dependency_version}\n"
+ changelog_content[unreleased_index:]
)
else:
# If "### Changed" exists, append the new entry
changed_index = unreleased_index + changed_match.end()
changelog_content = (
changelog_content[:changed_index]
+ f"\n- {dependency_name} updated to version v{new_dependency_version}"
+ changelog_content[changed_index:]
)

changelog_path.write_text(changelog_content)


def _create_changelog_release(pkg_name: str, new_version: str) -> None:
changelog_path = PACKAGES_DIR / pkg_name / "CHANGELOG.md"
changelog_content = changelog_path.read_text()
changelog_content = changelog_content.replace(
"## Unreleased", f"## Unreleased\n\n## {new_version} ({datetime.today().strftime('%Y-%m-%d')})"
)
changelog_path.write_text(changelog_content)


def run(pkg_name: Optional[str] = typer.Argument(None), update_type: Optional[str] = typer.Argument(None)) -> None:
"""
Main entry point for the package version updater. Updates package versions based on user input.
Expand Down Expand Up @@ -130,32 +208,37 @@ def run(pkg_name: Optional[str] = typer.Argument(None), update_type: Optional[st
pkg_name = list_input("Enter the package name", choices=packages)

casted_update_type = _update_type_to_enum(update_type)

user_prompt_required = pkg_name is None or casted_update_type is None

if pkg_name == "ragbits-core":
if pkg_name == "ragbits":
_update_pkg_version(pkg_name, update_type=casted_update_type)

elif pkg_name == "ragbits-core":
if user_prompt_required:
print("When upgrading the ragbits-core package it is also necessary to upgrade the other packages.")
is_continue = confirm(message="Do you want to continue?")
else:
is_continue = True

if is_continue:
ragbits_version, new_ragbits_version = _update_pkg_version(pkg_name, update_type=casted_update_type)
casted_update_type = _check_update_type(ragbits_version, new_ragbits_version)
version, new_version = _update_pkg_version(pkg_name, update_type=casted_update_type)
casted_update_type = _check_update_type(version, new_version)

for pkg in [pkg for pkg in packages if pkg != "ragbits-core"]:
for pkg in sorted([pkg for pkg in packages if pkg != "ragbits-core"], reverse=True):
pkg_pyproject = tomlkit.parse((PACKAGES_DIR / pkg / "pyproject.toml").read_text())
pkg_pyproject["project"]["dependencies"] = [
dep for dep in pkg_pyproject["project"]["dependencies"] if "ragbits-core" not in dep
]
pkg_pyproject["project"]["dependencies"].append(f"ragbits-core=={new_ragbits_version}")
pkg_pyproject["project"]["dependencies"].append(f"ragbits-core=={new_version}")
if pkg != "ragbits":
_add_updated_dependency_to_changelog(pkg, pkg_name, new_version)
_update_pkg_version(pkg, pkg_pyproject, update_type=casted_update_type)

else:
pprint("[red]The ragbits-core package was not successfully updated.[/red]")

else:
_update_pkg_version(pkg_name, update_type=casted_update_type)
_update_pkg_version(pkg_name, update_type=casted_update_type, sync_ragbits_version=True)


if __name__ == "__main__":
Expand Down

0 comments on commit 2d92dae

Please sign in to comment.