Skip to content

Commit

Permalink
Initial conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
coordt committed Apr 8, 2023
1 parent d7dec79 commit f5d1cab
Show file tree
Hide file tree
Showing 49 changed files with 3,707 additions and 116 deletions.
6 changes: 3 additions & 3 deletions .composition.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ context:
packaging_tool: pip/setuptools
project_name: bump-my-version
project_short_description: Version bump your Python project
project_slug: bump_version
project_slug: bumpversion
version: 0.1.0
directory: cookiecutter-boilerplate
merge_strategies:
Expand All @@ -50,7 +50,7 @@ context:
friendly_name: Bump My Version
project_name: bump-my-version
project_short_description: Version bump your Python project
project_slug: bump_version
project_slug: bumpversion
version: 0.1.0
directory: cookiecutter-cli
merge_strategies:
Expand Down Expand Up @@ -86,7 +86,7 @@ context:
friendly_name: Bump My Version
github_user: callowayproject
project_name: bump-my-version
project_slug: bump_version
project_slug: bumpversion
directory: cookiecutter-docs
merge_strategies:
'*.json': comprehensive
Expand Down
54 changes: 0 additions & 54 deletions bump_version/cli.py

This file was deleted.

1 change: 0 additions & 1 deletion bump_version/commands/__init__.py

This file was deleted.

7 changes: 0 additions & 7 deletions bump_version/commands/say_hello.py

This file was deleted.

File renamed without changes.
4 changes: 4 additions & 0 deletions bumpversion/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"""Main entrypoint for module."""
from bumpversion.cli import cli

cli()
32 changes: 32 additions & 0 deletions bumpversion/aliases.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Utilities for handling command aliases."""
from typing import List

import rich_click as click
from click import Context
from rich_click.rich_group import RichGroup


class AliasedGroup(RichGroup):
"""
This following example implements a subclass of Group that accepts a prefix for a command.
If there were a command called ``push``, it would accept ``pus`` as an alias (so long as it was unique)
"""

def get_command(self, ctx: Context, cmd_name: str) -> None:
"""Given a context and a command name, this returns a Command object if it exists or returns None."""
rv = click.Group.get_command(self, ctx, cmd_name)
if rv is not None:
return rv
matches = [x for x in self.list_commands(ctx) if x.startswith(cmd_name)]
if not matches:
return None
elif len(matches) == 1:
return click.Group.get_command(self, ctx, matches[0])
ctx.fail(f"Too many matches: {', '.join(sorted(matches))}")

def resolve_command(self, ctx: Context, args: List[str]) -> tuple:
"""Find the command and make sure the full command name is returned."""
# always return the full command name
_, cmd, args = super().resolve_command(ctx, args)
return cmd.name, cmd, args
80 changes: 80 additions & 0 deletions bumpversion/autocast.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
"""
Automatically detect the true Python type of a string and cast it to the correct type.
Based on https://github.com/cgreer/cgAutoCast/blob/master/cgAutoCast.py
"""

import contextlib
from typing import Any


def boolify(s: str) -> bool:
"""Convert a string to a boolean."""
if s in {"True", "true"}:
return True
if s in {"False", "false"}:
return False
raise ValueError("Not Boolean Value!")


def noneify(s: str) -> None:
"""Convert a string to None."""
if s == "None":
return None
raise ValueError("Not None Value!")


def listify(s: str) -> list:
"""
Convert a string representation of a list into list of homogenous basic types.
Type of elements in list is determined via first element. Successive elements are
cast to that type.
Args:
s: String representation of a list.
Raises:
ValueError: If string does not represent a list.
TypeError: If string does not represent a list of homogenous basic types.
Returns:
List of homogenous basic types.
"""
if "," not in s and "\n" not in s:
raise ValueError("Not a List")

# derive the type of the variable
str_list = s.strip().split(",") if "," in s else s.strip().split("\n")
element_caster = str
for caster in (boolify, int, float, noneify, element_caster):
with contextlib.suppress(ValueError):
caster(str_list[0]) # type: ignore[operator]
element_caster = caster # type: ignore[assignment]
break
# cast all elements
try:
return [element_caster(x) for x in str_list]
except ValueError as e:
raise TypeError("Autocasted list must be all same type") from e


def autocast_value(var: Any) -> Any:
"""
Guess the string representation of the variable's type.
Args:
var: Value to autocast.
Returns:
The autocasted value.
"""
if not isinstance(var, str): # don't need to guess non-string types
return var

# guess string representation of var
for caster in (boolify, int, float, noneify, listify):
with contextlib.suppress(ValueError):
return caster(var) # type: ignore[operator]

return var
111 changes: 111 additions & 0 deletions bumpversion/bump.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
"""Version changing methods."""
import logging
import shlex
from pathlib import Path
from typing import TYPE_CHECKING, ChainMap, List, Optional

if TYPE_CHECKING: # pragma: no-coverage
from bumpversion.files import ConfiguredFile
from bumpversion.version_part import Version

from bumpversion.config import Config, update_config_file
from bumpversion.exceptions import ConfigurationError
from bumpversion.utils import get_context, key_val_string

logger = logging.getLogger("bumpversion")


def get_next_version(
current_version: "Version", config: Config, version_part: Optional[str], new_version: Optional[str]
) -> "Version":
"""
Bump the version_part to the next value.
Args:
current_version: The current version
config: The current configuration
version_part: Optional part of the version to bump
new_version: Optional specific version to bump to
Returns:
The new version
Raises:
ConfigurationError: If it can't generate the next version.
"""
if new_version:
next_version = config.version_config.parse(new_version)
elif version_part:
logger.info("Attempting to increment part '%s'", version_part)
next_version = current_version.bump(version_part, config.version_config.order)
else:
raise ConfigurationError("Unable to get the next version.")

logger.info("Values are now: %s", key_val_string(next_version.values))
return next_version


def do_bump(
version_part: Optional[str],
new_version: Optional[str],
config: Config,
config_file: Optional[Path] = None,
dry_run: bool = False,
) -> None:
"""
Bump the version_part to the next value or set the version to new_version.
Args:
version_part: The version part to bump
new_version: The explicit version to set
config: The configuration to use
config_file: The configuration file to update
dry_run: True if the operation should be a dry run
"""
from bumpversion.files import modify_files, resolve_file_config

ctx = get_context(config)
version = config.version_config.parse(config.current_version)
next_version = get_next_version(version, config, version_part, new_version)
next_version_str = config.version_config.serialize(next_version, ctx)
logger.info("New version will be '%s'", next_version_str)

ctx = get_context(config, version, next_version)

configured_files = resolve_file_config(config.files, config.version_config)

modify_files(configured_files, version, next_version, ctx, dry_run)

update_config_file(config_file, config.current_version, next_version_str, dry_run)

commit_and_tag(config, config_file, configured_files, ctx, dry_run)


def commit_and_tag(
config: Config,
config_file: Optional[Path],
configured_files: List["ConfiguredFile"],
ctx: ChainMap,
dry_run: bool = False,
) -> None:
"""
Commit and tag the changes, if a tool is configured.
Args:
config: The configuration
config_file: The configuration file to include in the commit, if it exists
configured_files: A list of files to commit
ctx: The context used to render the tag and tag message
dry_run: True if the operation should be a dry run
"""
if not config.scm_info.tool:
return

extra_args = shlex.split(config.commit_args) if config.commit_args else []

commit_files = {f.path for f in configured_files}
if config_file:
commit_files |= {str(config_file)}

config.scm_info.tool.commit_to_scm(list(commit_files), config, ctx, extra_args, dry_run)
config.scm_info.tool.tag_in_scm(config, ctx, dry_run)
Loading

0 comments on commit f5d1cab

Please sign in to comment.