Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion odev/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@
# or merged change.
# ------------------------------------------------------------------------------

__version__ = "4.30.1"
__version__ = "4.30.2"
7 changes: 6 additions & 1 deletion odev/commands/git/fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,15 @@ def run(self):
for worktree in sorted_worktree:
self.run_hook(worktree, changes_by_worktree[worktree])

# Drop the blank line trailing the output of the last worktree.
self.console.clear_line()

def run_hook(self, worktree: str, changes: list[tuple[str, int, int]]):
"""Print a summary of the pending changes for a worktree."""
"""Print a summary of the pending changes for a worktree.

Overrides must terminate their output with a blank line, separating consecutive worktrees and letting
:meth:`run` clear the last one.
"""
self.table(
[
TableHeader("Repository", min_width=max(len(repository.name) for repository in self.repositories)),
Expand Down
17 changes: 8 additions & 9 deletions odev/commands/git/pull.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ class PullCommand(FetchCommand):
_help = "Pull changes in local worktrees managed by odev."

def run_hook(self, name: str, changes: list[tuple[str, int, int]]):
"""Print a summary of the pending changes for a worktree."""
"""Pull the pending changes for a worktree and print a summary of the operation."""
self.console.title_rule(name)

for change in changes:
repository, behind, _ = change
worktree = next(
Expand All @@ -33,19 +35,16 @@ def run_hook(self, name: str, changes: list[tuple[str, int, int]]):
raise self.error(f"Worktree {name!r} does not exist")

if worktree.detached:
logger.info(f"Worktree {name!r} is detached")
logger.info(f"Detached worktree in {repository!r}")
continue

if not behind:
logger.info(
f"No pending changes for worktree {name!r} in {repository!r} for version {worktree.branch!r}"
)
logger.info(f"No pending changes in {repository!r} for version {worktree.branch!r}")
continue

with progress.spinner(
f"Pulling {behind} commits in {worktree.connector.name!r} for version {worktree.branch!r}"
):
with progress.spinner(f"Pulling {behind} commits in {repository!r} for version {worktree.branch!r}"):
worktree.connector.pull_worktrees([worktree], force=True)
logger.info(f"Pulled {behind} commits in {worktree.connector.name!r} for version {worktree.branch!r}")
logger.info(f"Pulled {behind} commits in {repository!r} for version {worktree.branch!r}")

self.print()
self.odev.config.repositories.set_date(name, datetime.today())
22 changes: 15 additions & 7 deletions odev/common/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,20 @@ def print(
else:
super().print(renderable, *args, **kwargs)

def title_rule(self, title: str) -> None:
"""Print a left-aligned rule introducing a section of output.

:param title: Text to display inside the rule.
"""
rule_char: str = "─"

self.rule(
f"{rule_char} {string.stylize(title, 'bold color.cyan')}",
align="left",
style="",
characters=rule_char,
)

def table(
self,
headers: Sequence[TableHeader],
Expand All @@ -408,13 +422,7 @@ def table(
:param kwargs: Additional keyword arguments to pass to the Rich Table.
"""
if title is not None:
rule_char: str = "─"
self.rule(
f"{rule_char} {string.stylize(title, 'bold color.cyan')}",
align="left",
style="",
characters=rule_char,
)
self.title_rule(title)
return self.table(headers, rows, totals, show_header=any(header.title for header in headers), box=None)

kwargs.setdefault("show_header", True)
Expand Down
23 changes: 23 additions & 0 deletions tests/tests/commands/test_git_and_scripts.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from argparse import Namespace
from unittest.mock import MagicMock

from odev.commands.git.pull import PullCommand
from odev.commands.scripts.assets import PathfinderCommand as AssetsCommand
from odev.commands.scripts.pathfinder import PathfinderCommand
from odev.common.connectors.git import GitConnector
Expand Down Expand Up @@ -33,6 +34,28 @@ def test_04_worktree_name_required_for_create(self):
_, stderr = self.dispatch_command("worktree", "--create")
self.assertIn("provide a name for the worktree", stderr)

def test_05_pull_output_ends_with_blank_line(self):
"""`FetchCommand.run` clears the line trailing the last worktree, so `run_hook` must end on a blank one."""
worktree = MagicMock(name="17.0", detached=False, branch="17.0")
worktree.name = "17.0"
worktree.connector.name = "odoo/odoo"

command = PullCommand.__new__(PullCommand)
printed: list[str] = []
titled: list[str] = []

with (
self.patch_property(PullCommand, "worktrees", [worktree]),
self.patch(
self.odev.console, "print", side_effect=lambda renderable="", *_, **__: printed.append(renderable)
),
self.patch(self.odev.console, "title_rule", side_effect=titled.append),
):
command.run_hook("17.0", [("odoo/odoo", 0, 0)])

self.assertEqual(titled, ["17.0"])
self.assertEqual(printed, [""])


class TestScriptCommands(OdevTestCase):
def test_01_assets_script_run_after(self):
Expand Down