Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(version): Add new version print flags to display the last released version and tag. #852

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 27 additions & 0 deletions docs/commands.rst
Expand Up @@ -144,6 +144,33 @@ command line options::
semantic-release version --patch --print
semantic-release version --prerelease --print

.. _cmd-version-option-print-tag:

``--print-tag``
***************

Same as the :ref:`cmd-version-option-print` flag but prints the complete tag
name (ex. ``v1.0.0`` or ``py-v1.0.0``) instead of the raw version number
(``1.0.0``).

.. _cmd-version-option-print-last-released:

``--print-last-released``
*************************

Print the last released version based on the Git tags. This flag is useful if you just
want to see the released version without determining what the next version will be.
Note if the version can not be found nothing will be printed.

.. _cmd-version-option-print-last-released-tag:

``--print-last-released-tag``
***************

Same as the :ref:`cmd-version-option-print-last-released` flag but prints the
complete tag name (ex. ``v1.0.0`` or ``py-v1.0.0``) instead of the raw version
number (``1.0.0``).

cfxegbert marked this conversation as resolved.
Show resolved Hide resolved
.. _cmd-version-option-force-level:

``--major/--minor/--patch``
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Expand Up @@ -23,6 +23,7 @@ readme = "README.rst"
authors = [{ name = "Rolf Erik Lekang", email = "me@rolflekang.com" }]
dependencies = [
"click>=8,<9",
"click-option-group~=0.5",
"gitpython>=3.0.8,<4",
"requests>=2.25,<3",
"jinja2>=3.1.2,<4",
Expand Down
54 changes: 49 additions & 5 deletions semantic_release/cli/commands/version.py
Expand Up @@ -9,6 +9,7 @@

import click
import shellingham # type: ignore[import]
from click_option_group import MutuallyExclusiveOptionGroup, optgroup
from git.exc import GitCommandError

from semantic_release.changelog import ReleaseHistory, environment, recursive_render
Expand All @@ -26,8 +27,9 @@

log = logging.getLogger(__name__)

if TYPE_CHECKING:
if TYPE_CHECKING: # pragma: no cover
from git import Repo
from git.refs.tag import Tag

from semantic_release.cli.config import RuntimeContext
from semantic_release.version import VersionTranslator
Expand All @@ -48,6 +50,13 @@ def is_forced_prerelease(
return force_prerelease or ((force_level is None) and prerelease)


def last_released(
repo: Repo, translator: VersionTranslator
) -> tuple[Tag, Version] | None:
ts_and_vs = tags_and_versions(repo.tags, translator)
return ts_and_vs[0] if ts_and_vs else None


def version_from_forced_level(
repo: Repo, level_bump: LevelBump, translator: VersionTranslator
) -> Version:
Expand Down Expand Up @@ -111,9 +120,26 @@ def shell(cmd: str, *, check: bool = True) -> subprocess.CompletedProcess:
"help_option_names": ["-h", "--help"],
},
)
@click.option(
@optgroup.group("Print flags", cls=MutuallyExclusiveOptionGroup)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very neat!

@optgroup.option(
"--print", "print_only", is_flag=True, help="Print the next version and exit"
)
@optgroup.option(
"--print-tag",
"print_only_tag",
is_flag=True,
help="Print the next version tag and exit",
)
@optgroup.option(
"--print-last-released",
is_flag=True,
help="Print the last released version and exit",
)
@optgroup.option(
"--print-last-released-tag",
is_flag=True,
help="Print the last released version tag and exit",
)
@click.option(
"--prerelease",
"force_prerelease",
Expand Down Expand Up @@ -191,6 +217,9 @@ def shell(cmd: str, *, check: bool = True) -> subprocess.CompletedProcess:
def version( # noqa: C901
ctx: click.Context,
print_only: bool = False,
print_only_tag: bool = False,
print_last_released: bool = False,
print_last_released_tag: bool = False,
force_prerelease: bool = False,
prerelease_token: str | None = None,
force_level: str | None = None,
Expand Down Expand Up @@ -219,8 +248,20 @@ def version( # noqa: C901
"""
runtime: RuntimeContext = ctx.obj
repo = runtime.repo
parser = runtime.commit_parser
translator = runtime.version_translator

# We can short circuit updating the release if we are only printing the last released version
if print_last_released or print_last_released_tag:
if last_release := last_released(repo, translator):
if print_last_released:
click.echo(last_release[1])
if print_last_released_tag:
click.echo(last_release[0])
else:
log.warning("No release tags found.")
ctx.exit(0)

parser = runtime.commit_parser
prerelease = is_forced_prerelease(
force_prerelease=force_prerelease,
force_level=force_level,
Expand Down Expand Up @@ -301,7 +342,10 @@ def version( # noqa: C901
ctx.call_on_close(gha_output.write_if_possible)

# Print the new version so that command-line output capture will work
click.echo(str(new_version))
if print_only_tag:
click.echo(translator.str_to_tag(str(new_version)))
else:
click.echo(str(new_version))

# If the new version has already been released, we fail and abort if strict;
# otherwise we exit with 0.
Expand All @@ -318,7 +362,7 @@ def version( # noqa: C901
)
ctx.exit(0)

if print_only:
if print_only or print_only_tag:
ctx.exit(0)

rprint(f"[bold green]The next version is: [white]{new_version!s}[/white]! :rocket:")
Expand Down
33 changes: 33 additions & 0 deletions tests/command_line/test_version.py
Expand Up @@ -743,3 +743,36 @@ def test_version_only_update_files_no_git_actions(
assert len(removed) == 1
assert re.match('__version__ = ".*"', removed[0])
assert added == [f'__version__ = "{expected_new_version}"\n']


def test_version_print_last_released_prints_version(
repo_with_single_branch_tag_commits: Repo, cli_runner: CliRunner
):
result = cli_runner.invoke(main, [version.name, "--print-last-released"])
assert result.exit_code == 0
assert result.stdout == "0.1.1\n"


def test_version_print_last_released_prints_released_if_commits(
repo_with_single_branch_tag_commits: Repo,
example_project_dir: ExProjectDir,
cli_runner: CliRunner,
):
new_file = example_project_dir / "temp.txt"
new_file.write_text("test --print-last-released")

repo_with_single_branch_tag_commits.git.add(str(new_file.resolve()))
repo_with_single_branch_tag_commits.git.commit(m="fix: temp new file")

result = cli_runner.invoke(main, [version.name, "--print-last-released"])
assert result.exit_code == 0
assert result.stdout == "0.1.1\n"


def test_version_print_last_released_prints_nothing_if_no_tags(
caplog, repo_with_no_tags_angular_commits: Repo, cli_runner: CliRunner
):
result = cli_runner.invoke(main, [version.name, "--print-last-released"])
assert result.exit_code == 0
assert result.stdout == ""
relekang marked this conversation as resolved.
Show resolved Hide resolved
assert "No release tags found." in caplog.text