Skip to content

Commit

Permalink
feat(version): add new version print flags to display the last releas…
Browse files Browse the repository at this point in the history
…ed version and tag
  • Loading branch information
cfxegbert committed Mar 12, 2024
1 parent c82bd67 commit a41e6d9
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 5 deletions.
27 changes: 27 additions & 0 deletions docs/commands.rst
Original file line number Diff line number Diff line change
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``).

.. _cmd-version-option-force-level:

``--major/--minor/--patch``
Expand Down
54 changes: 49 additions & 5 deletions semantic_release/cli/commands/version.py
Original file line number Diff line number Diff line change
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)
@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
Original file line number Diff line number Diff line change
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 == ""
assert "No release tags found." in caplog.text

0 comments on commit a41e6d9

Please sign in to comment.