chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
import typing as t
|
||||
from enum import Enum
|
||||
from itertools import chain
|
||||
from pathlib import Path
|
||||
|
||||
import click
|
||||
import tomli
|
||||
from semver import VersionInfo
|
||||
|
||||
CWD = Path.cwd()
|
||||
SKIPDIR = (".venv", "venv", ".nox", ".tox", "temp", "node_modules", "site-packages")
|
||||
PYPROJECT = "pyproject.toml"
|
||||
SETUP = "setup.py"
|
||||
|
||||
BumpTypes = {
|
||||
"M": "major",
|
||||
"m": "minor",
|
||||
"p": "patch",
|
||||
"b": "post",
|
||||
"c": "pre",
|
||||
"s": "skip",
|
||||
}
|
||||
BumpTypesPrompt = " | ".join([f"{k}-{v.title()}" for k, v in BumpTypes.items()])
|
||||
|
||||
|
||||
class BumpType(Enum):
|
||||
MAJOR = "major"
|
||||
MINOR = "minor"
|
||||
PATCH = "patch"
|
||||
PRE = "pre"
|
||||
POST = "post"
|
||||
|
||||
|
||||
def _get_bumped_version(current: VersionInfo, bump_type: BumpType) -> VersionInfo:
|
||||
if bump_type == BumpType.MAJOR:
|
||||
return current.next_version("major")
|
||||
|
||||
if bump_type == BumpType.MINOR:
|
||||
return current.next_version("minor")
|
||||
|
||||
if bump_type == BumpType.PATCH:
|
||||
return current.next_version("patch")
|
||||
|
||||
if bump_type == BumpType.PRE:
|
||||
return current.next_version("prerelease")
|
||||
|
||||
return current.bump_build(token="post")
|
||||
|
||||
|
||||
def _skip(file: Path) -> bool:
|
||||
return any(skipdir in file.parts for skipdir in SKIPDIR)
|
||||
|
||||
|
||||
def _find_packages():
|
||||
files = []
|
||||
for file in chain(CWD.glob(f"**/{PYPROJECT}"), CWD.glob(f"**/{SETUP}")):
|
||||
if _skip(file=file):
|
||||
continue
|
||||
files.append(file)
|
||||
return files
|
||||
|
||||
|
||||
def _get_version_update(
|
||||
package: str,
|
||||
version: str,
|
||||
bump_type_selector: t.Optional[str] = None,
|
||||
) -> t.Optional[str]:
|
||||
pre = None
|
||||
if "-" in version:
|
||||
version, pre = version.split("-", maxsplit=1)
|
||||
|
||||
if "rc" in version:
|
||||
version, marker, number = version.partition("rc")
|
||||
pre = f"{marker}{number}"
|
||||
|
||||
# TODO: Add support for post builds
|
||||
current_version = VersionInfo.parse(version=version)
|
||||
current_version._prerelease = pre
|
||||
bump_type_selector = t.cast(
|
||||
str,
|
||||
bump_type_selector
|
||||
or click.prompt(f"* Bump {package}@{version} -> {BumpTypesPrompt}"),
|
||||
)
|
||||
if bump_type_selector == "s":
|
||||
return None
|
||||
|
||||
try:
|
||||
_bump_type = BumpType(BumpTypes[bump_type_selector])
|
||||
except (ValueError, KeyError) as e:
|
||||
raise click.ClickException(f"Invalid bump type: {e}")
|
||||
|
||||
return str(_get_bumped_version(current=current_version, bump_type=_bump_type))
|
||||
|
||||
|
||||
def _bump_setup_py(file: Path, bump_type: t.Optional[str] = None):
|
||||
# Load config
|
||||
content = file.read_text(encoding="utf-8")
|
||||
_, _, arguments = content.partition("setup(")
|
||||
|
||||
package, version = None, None
|
||||
for line in arguments.split("\n"):
|
||||
if "=" not in line:
|
||||
continue
|
||||
|
||||
arg, val = line.strip().split("=", maxsplit=1)
|
||||
val = val.replace('"', "").replace(",", "").strip()
|
||||
if arg == "name":
|
||||
package = val
|
||||
|
||||
if arg == "version":
|
||||
version = val
|
||||
|
||||
# Skip the main setup.py
|
||||
if package == "composio":
|
||||
return
|
||||
|
||||
if package is None or version is None:
|
||||
raise ValueError(f"Package or version not found in {file}")
|
||||
|
||||
# Bump version
|
||||
next_version = _get_version_update(
|
||||
package=package,
|
||||
version=version,
|
||||
bump_type_selector=bump_type,
|
||||
)
|
||||
if next_version is None:
|
||||
click.echo(f"* Skipping {package}")
|
||||
return
|
||||
|
||||
click.echo(f"* Bumping {package} {version} -> {next_version}")
|
||||
content = content.replace(f'version="{version}"', f'version="{next_version}"')
|
||||
file.write_text(content, encoding="utf-8")
|
||||
|
||||
|
||||
def _bump_pyproject_toml(file: Path, bump_type: t.Optional[str] = None):
|
||||
# Load config
|
||||
content = file.read_text(encoding="utf-8")
|
||||
config = tomli.loads(content)
|
||||
project = t.cast(dict, config["project"])
|
||||
|
||||
# Extract meta
|
||||
package = project["name"]
|
||||
version = project["version"]
|
||||
|
||||
# Bump version
|
||||
next_version = _get_version_update(
|
||||
package=package,
|
||||
version=version,
|
||||
bump_type_selector=bump_type,
|
||||
)
|
||||
if next_version is None:
|
||||
click.echo(f"* Skipping {package}")
|
||||
return
|
||||
|
||||
click.echo(f"* Bumping {package} {version} -> {next_version}")
|
||||
content = content.replace(f'version = "{version}"', f'version = "{next_version}"')
|
||||
file.write_text(content, encoding="utf-8")
|
||||
|
||||
|
||||
def _bump_package(file: Path, bump_type: t.Optional[str] = None):
|
||||
if file.name == PYPROJECT:
|
||||
return _bump_pyproject_toml(file=file, bump_type=bump_type)
|
||||
return _bump_setup_py(file=file, bump_type=bump_type)
|
||||
|
||||
|
||||
@click.command("bump")
|
||||
@click.option("--pre", "bump_type", flag_value="c")
|
||||
@click.option("--post", "bump_type", flag_value="b")
|
||||
@click.option("--patch", "bump_type", flag_value="p")
|
||||
@click.option("--minor", "bump_type", flag_value="m")
|
||||
@click.option("--major", "bump_type", flag_value="M")
|
||||
def bump(bump_type: t.Optional[str]):
|
||||
packages = _find_packages()
|
||||
for package in packages:
|
||||
try:
|
||||
_bump_package(file=package, bump_type=bump_type)
|
||||
except Exception as e:
|
||||
raise e.__class__(f"Error bumping {package}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
bump()
|
||||
Reference in New Issue
Block a user