Change ui messaging for the updater (#6437)

This commit is contained in:
Saugat Pachhai
2021-08-16 18:31:44 +03:00
committed by GitHub
parent 41bc81910f
commit 451bd3ebc8
3 changed files with 118 additions and 62 deletions
+2 -11
View File
@@ -10,21 +10,12 @@ logger = logging.getLogger(__name__)
class CmdVersion(CmdBaseNoRepo):
def run(self):
from dvc.info import get_dvc_info
from dvc.repo import NotDvcRepoError, Repo
from dvc.updater import notify_updates
dvc_info = get_dvc_info()
ui.write(dvc_info, force=True)
try:
with Repo() as repo:
from dvc.updater import Updater
hardlink_lock = repo.config["core"].get("hardlink_lock", False)
updater = Updater(repo.tmp_dir, hardlink_lock=hardlink_lock)
updater.check()
except NotDvcRepoError:
pass
notify_updates()
return 0
+58 -43
View File
@@ -2,17 +2,20 @@ import logging
import os
import sys
import time
from typing import TYPE_CHECKING, Optional
import colorama
from packaging import version
from dvc import __version__
from dvc.utils.pkg import PKG
if TYPE_CHECKING:
from rich.text import Text
logger = logging.getLogger(__name__)
class Updater: # pragma: no cover
class Updater:
URL = "https://updater.dvc.org"
UPDATER_FILE = "updater"
TIMEOUT = 24 * 60 * 60 # every day
@@ -105,57 +108,58 @@ class Updater: # pragma: no cover
with open(self.updater_file, "w+") as fobj:
json.dump(info, fobj)
def _notify(self, latest):
def _notify(self, latest: str, pkg: Optional[str] = PKG) -> None:
from dvc.ui import ui
if not sys.stdout.isatty():
return
message = (
"Update available {red}{current}{reset} -> {green}{latest}{reset}"
+ "\n"
+ self._get_update_instructions()
).format(
red=colorama.Fore.RED,
reset=colorama.Fore.RESET,
green=colorama.Fore.GREEN,
yellow=colorama.Fore.YELLOW,
blue=colorama.Fore.BLUE,
current=self.current,
latest=latest,
message = self._get_message(latest, pkg=pkg)
return ui.error_write(message, styled=True)
def _get_message(
self,
latest: str,
current: str = None,
color: str = "yellow",
pkg: Optional[str] = None,
) -> "Text":
from rich.text import Text
current = current or self.current
update_message = Text.from_markup(
f"You are using dvc version [bold]{current}[/]; "
f"however, version [bold]{latest}[/] is available."
)
instruction = Text.from_markup(self._get_update_instructions(pkg=pkg))
return Text.assemble(
"\n", update_message, "\n", instruction, style=color
)
from dvc.utils import boxify
def _get_update_instructions(self, pkg: Optional[str] = None) -> str:
if pkg in ("osxpkg", "exe", "binary"):
return (
"To upgrade, uninstall dvc and reinstall from "
"[blue]https://dvc.org[/]."
)
logger.info(boxify(message, border_color="yellow"))
def _get_update_instructions(self):
instructions = {
"pip": "Run `{yellow}pip{reset} install dvc "
"{blue}--upgrade{reset}`",
"rpm": "Run `{yellow}yum{reset} update dvc`",
"brew": "Run `{yellow}brew{reset} upgrade dvc`",
"deb": (
"Run `{yellow}apt-get{reset} install"
" {blue}--only-upgrade{reset} dvc`"
),
"binary": (
"To upgrade follow these steps:\n"
"1. Uninstall dvc binary\n"
"2. Go to {blue}https://dvc.org{reset}\n"
"3. Download and install new binary"
),
"conda": "Run `{yellow}conda{reset} update dvc`",
"choco": "Run `{yellow}choco{reset} upgrade dvc`",
None: (
"Find the latest release at\n"
"{blue}https://github.com/iterative/dvc/releases/latest{reset}"
),
"pip": "pip install --upgrade dvc",
"rpm": "yum update dvc",
"brew": "brew upgrade dvc",
"deb": "apt-get install --only-upgrade dvc",
"conda": "conda update dvc",
"choco": "choco upgrade dvc",
}
package_manager = PKG
if package_manager in ("osxpkg", "exe"):
package_manager = "binary"
if pkg not in instructions:
return (
"Find the latest release at "
"[blue]https://github.com/iterative/dvc/releases/latest[/]."
)
return instructions[package_manager]
instruction = instructions[pkg]
return f"To upgrade, run '{instruction}'."
def is_enabled(self):
from dvc.config import Config, to_bool
@@ -167,3 +171,14 @@ class Updater: # pragma: no cover
"Check for update is {}abled.".format("en" if enabled else "dis")
)
return enabled
def notify_updates():
from contextlib import suppress
from dvc.repo import NotDvcRepoError, Repo
with suppress(NotDvcRepoError), Repo() as repo:
hardlink_lock = repo.config["core"].get("hardlink_lock", False)
updater = Updater(repo.tmp_dir, hardlink_lock=hardlink_lock)
updater.check()
+58 -8
View File
@@ -8,6 +8,7 @@ import pytest
from dvc import __version__
from dvc.updater import Updater
from tests.func.parsing.test_errors import escape_ansi
@pytest.fixture
@@ -85,19 +86,26 @@ def test_check_update_respect_config(mock_check, result, updater, mocker):
],
ids=["uptodate", "behind", "ahead"],
)
def test_check_updates(mock_tty, updater, caplog, current, latest, notify):
def test_check_updates(mocker, capsys, updater, current, latest, notify):
mocker.patch("sys.stdout.isatty", return_value=True)
updater.current = current
with open(updater.updater_file, "w+") as f:
json.dump({"version": latest}, f)
caplog.clear()
with caplog.at_level(logging.INFO, logger="dvc.updater"):
updater.check()
updater.check()
out, err = capsys.readouterr()
expected_message = (
(
f"You are using dvc version {current}; "
f"however, version {latest} is available.\n"
)
if notify
else ""
)
if notify:
assert f"Update available {current} -> {latest}" in caplog.text
else:
assert not caplog.text
assert expected_message in escape_ansi(err)
assert not out
def test_check_refetches_each_day(mock_tty, updater, caplog, mocker):
@@ -138,3 +146,45 @@ def test_check(mock_check, updater):
updater.check()
assert mock_check.call_count == 3
@pytest.mark.parametrize(
"pkg, instruction",
[
("pip", "To upgrade, run 'pip install --upgrade dvc'."),
("rpm", "To upgrade, run 'yum update dvc'."),
("brew", "To upgrade, run 'brew upgrade dvc'."),
("deb", "To upgrade, run 'apt-get install --only-upgrade dvc'."),
("conda", "To upgrade, run 'conda update dvc'."),
("choco", "To upgrade, run 'choco upgrade dvc'."),
(
"osxpkg",
"To upgrade, uninstall dvc and reinstall from https://dvc.org.",
),
(
"exe",
"To upgrade, uninstall dvc and reinstall from https://dvc.org.",
),
(
"binary",
"To upgrade, uninstall dvc and reinstall from https://dvc.org.",
),
(
None,
"Find the latest release at "
"https://github.com/iterative/dvc/releases/latest.",
),
(
"unknown",
"Find the latest release at "
"https://github.com/iterative/dvc/releases/latest.",
),
],
)
def test_notify_message(updater, pkg, instruction):
update_message = (
"You are using dvc version 0.0.2; however, version 0.0.3 is available."
)
message = updater._get_message("0.0.3", current="0.0.2", pkg=pkg)
assert message.plain.splitlines() == ["", update_message, instruction]