Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -1360,8 +1360,21 @@ The option `--next-phase` allows the increment of prerelease phase versions.
| prerelease --next-phase | 1.0.3b0 | 1.0.3rc0 |
| prerelease --next-phase | 1.0.3rc0 | 1.0.3 |

The option `--dev` creates or bumps development release versions for bump rules.

| rule | before | after |
|--------------------------------|---------------|---------------|
| major --dev | 1.1.0 | 2.0.0.dev0 |
| major --dev | 2.0.0.dev0 | 2.0.0.dev1 |
| major | 2.0.0.dev1 | 2.0.0 |
| prerelease --dev | 1.1.0 | 1.1.1a0.dev0 |
| prerelease --dev | 1.1.1a0.dev0 | 1.1.1a0.dev1 |
| prerelease | 1.1.1a0.dev1 | 1.1.1a0 |
| prerelease --next-phase --dev | 1.1.0a2.dev1 | 1.1.0b0.dev0 |

#### Options

* `--dev`: Create or bump a development release for a bump rule.
* `--next-phase`: Increment the phase of the current version.
* `--short (-s)`: Output the version number only.
* `--dry-run`: Do not update pyproject.toml file.
35 changes: 32 additions & 3 deletions src/poetry/console/commands/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ class VersionCommand(Command):
"Shows the version of the project or bumps it when a valid "
"bump rule is provided."
)
BUMP_RULES: ClassVar[frozenset[str]] = frozenset(
{
"major",
"minor",
"patch",
"premajor",
"preminor",
"prepatch",
"prerelease",
}
)

arguments: ClassVar[list[Argument]] = [
argument(
Expand All @@ -38,6 +49,7 @@ class VersionCommand(Command):
"Do not update pyproject.toml file",
),
option("next-phase", None, "Increment the phase of the current version"),
option("dev", None, "Create or bump a development release for a bump rule"),
]

help = """\
Expand All @@ -54,7 +66,10 @@ def handle(self) -> int:

if version:
version = self.increment_version(
self.poetry.package.pretty_version, version, self.option("next-phase")
self.poetry.package.pretty_version,
version,
self.option("next-phase"),
self.option("dev"),
)

if self.option("short"):
Expand Down Expand Up @@ -87,7 +102,7 @@ def handle(self) -> int:
return 0

def increment_version(
self, version: str, rule: str, next_phase: bool = False
self, version: str, rule: str, next_phase: bool = False, dev: bool = False
) -> Version:
from poetry.core.constraints.version import Version

Expand All @@ -96,6 +111,12 @@ def increment_version(
except InvalidVersionError:
raise ValueError("The project's version doesn't seem to follow semver")

if dev and rule not in self.BUMP_RULES:
raise ValueError(
"The --dev option can only be used with a bump rule, "
"not an explicit version."
)

if rule in {"major", "premajor"}:
new = parsed.next_major()
if rule == "premajor":
Expand All @@ -109,7 +130,9 @@ def increment_version(
if rule == "prepatch":
new = new.first_prerelease()
elif rule == "prerelease":
if parsed.is_unstable():
if parsed.dev is not None and (not next_phase or parsed.pre is None):
new = parsed.without_devrelease()
elif parsed.is_unstable():
pre = parsed.pre
assert pre is not None
pre = pre.next_phase() if next_phase else pre.next()
Expand All @@ -119,4 +142,10 @@ def increment_version(
else:
new = Version.parse(rule)

if dev:
if parsed.dev is not None and new == parsed.without_devrelease():
new = parsed.next_devrelease()
else:
new = new.first_devrelease()

return new
81 changes: 81 additions & 0 deletions tests/console/commands/test_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,80 @@ def test_next_phase_version(
assert command.increment_version(version, rule, True).text == expected


@pytest.mark.parametrize(
"version, rule, next_phase, expected",
[
("1.1.0", "major", False, "2.0.0.dev0"),
("1.1.0", "minor", False, "1.2.0.dev0"),
("1.1.0", "patch", False, "1.1.1.dev0"),
("1.1.0", "premajor", False, "2.0.0a0.dev0"),
("1.1.0", "preminor", False, "1.2.0a0.dev0"),
("1.1.0", "prepatch", False, "1.1.1a0.dev0"),
("1.1.0", "prerelease", False, "1.1.1a0.dev0"),
("2.0.0.dev0", "major", False, "2.0.0.dev1"),
("1.1.0.dev0", "minor", False, "1.1.0.dev1"),
("1.1.1a0.dev0", "prerelease", False, "1.1.1a0.dev1"),
],
)
def test_dev_version_creates_or_increments_dev_release(
version: str,
rule: str,
next_phase: bool,
expected: str,
command: VersionCommand,
) -> None:
assert (
command.increment_version(version, rule, next_phase, dev=True).text == expected
)


@pytest.mark.parametrize(
"version, rule, next_phase, expected",
[
("1.1.1.dev0", "minor", False, "1.2.0.dev0"),
("1.1.0a2.dev1", "prerelease", True, "1.1.0b0.dev0"),
],
)
def test_dev_version_resets_dev_release_when_base_changes(
version: str,
rule: str,
next_phase: bool,
expected: str,
command: VersionCommand,
) -> None:
assert (
command.increment_version(version, rule, next_phase, dev=True).text == expected
)


@pytest.mark.parametrize(
"version, rule, next_phase, expected",
[
("2.0.0.dev1", "major", False, "2.0.0"),
("1.1.1a0.dev1", "prerelease", False, "1.1.1a0"),
("1.1.0a2.dev1", "prerelease", True, "1.1.0b0"),
],
)
def test_version_without_dev_flag_removes_dev_release(
version: str,
rule: str,
next_phase: bool,
expected: str,
command: VersionCommand,
) -> None:
assert command.increment_version(version, rule, next_phase).text == expected


def test_dev_option_requires_bump_rule(command: VersionCommand) -> None:
with pytest.raises(ValueError) as e:
command.increment_version("1.0.0", "2.0.0", dev=True)

assert (
str(e.value) == "The --dev option can only be used with a bump rule, "
"not an explicit version."
)


def test_version_show(tester: CommandTester) -> None:
tester.execute()
assert tester.io.fetch_output() == "simple-project 1.2.3\n"
Expand Down Expand Up @@ -124,6 +198,13 @@ def test_phase_version_update(tester: CommandTester) -> None:
assert tester.io.fetch_output() == "Bumping version from 1.2.4a0 to 1.2.4b0\n"


def test_dev_version_update(tester: CommandTester) -> None:
assert isinstance(tester.command, VersionCommand)
tester.command.poetry.package._set_version("1.1.0")
tester.execute("major --dev")
assert tester.io.fetch_output() == "Bumping version from 1.1.0 to 2.0.0.dev0\n"


def test_dry_run(tester: CommandTester) -> None:
assert isinstance(tester.command, VersionCommand)
old_pyproject = tester.command.poetry.file.path.read_text(encoding="utf-8")
Expand Down
Loading