[V3 Downloader] Allow to specify minimum and maximum bot version in info.json (#2605)

* feat(downloader): add `min_bot_version` and `max_bot_version`

Adds actually working way of specifying minimum and maximum bot version and removes not working
`bot_version`

BREAKING CHANGE: - removal of `bot_version` attribute in `Installable`

* test(downloader): `Installable` tests fix for new bot version attributes

* docs(changelog): added changelog entries for this PR
This commit is contained in:
jack1142 2019-04-29 18:33:49 +02:00 committed by Michael H
parent 07f127ffe4
commit 24ac111782
7 changed files with 70 additions and 10 deletions

View File

@ -60,6 +60,8 @@ Downloader
* Fixed bug, that caused Downloader to include submodules on cog list (`#2590`_) * Fixed bug, that caused Downloader to include submodules on cog list (`#2590`_)
* ``[p]cog uninstall`` allows to uninstall multiple cogs now (`#2592`_) * ``[p]cog uninstall`` allows to uninstall multiple cogs now (`#2592`_)
* ``[p]cog uninstall`` will now remove cog from installed cogs even if it can't find the cog in install path anymore (`#2595`_) * ``[p]cog uninstall`` will now remove cog from installed cogs even if it can't find the cog in install path anymore (`#2595`_)
* ``[p]cog install`` will not allow to install cogs which aren't suitable for installed version of Red anymore (`#2605`_)
* Cog Developers now have to use ``min_bot_version`` in form of version string instead of ``bot_version`` in info.json and they can also use ``max_bot_version`` to specify maximum version of Red, more in :doc:`framework_downloader`. (`#2605`_)
--- ---
Mod Mod
@ -141,5 +143,6 @@ Utility Functions
.. _#2600: https://github.com/Cog-Creators/Red-DiscordBot/pull/2600 .. _#2600: https://github.com/Cog-Creators/Red-DiscordBot/pull/2600
.. _#2602: https://github.com/Cog-Creators/Red-DiscordBot/pull/2602 .. _#2602: https://github.com/Cog-Creators/Red-DiscordBot/pull/2602
.. _#2604: https://github.com/Cog-Creators/Red-DiscordBot/pull/2604 .. _#2604: https://github.com/Cog-Creators/Red-DiscordBot/pull/2604
.. _#2605: https://github.com/Cog-Creators/Red-DiscordBot/pull/2605
.. _#2606: https://github.com/Cog-Creators/Red-DiscordBot/pull/2606 .. _#2606: https://github.com/Cog-Creators/Red-DiscordBot/pull/2606
.. _#2620: https://github.com/Cog-Creators/Red-DiscordBot/pull/2620 .. _#2620: https://github.com/Cog-Creators/Red-DiscordBot/pull/2620

View File

@ -30,7 +30,10 @@ Keys common to both repo and cog info.json (case sensitive)
Keys specific to the cog info.json (case sensitive) Keys specific to the cog info.json (case sensitive)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- ``bot_version`` (list of integer) - Min version number of Red in the format ``(MAJOR, MINOR, PATCH)`` - ``min_bot_version`` (string) - Min version number of Red in the format ``MAJOR.MINOR.MICRO``
- ``max_bot_version`` (string) - Max version number of Red in the format ``MAJOR.MINOR.MICRO``,
if ``min_bot_version`` is newer than ``max_bot_version``, ``max_bot_version`` will be ignored
- ``hidden`` (bool) - Determines if a cog is visible in the cog list for a repo. - ``hidden`` (bool) - Determines if a cog is visible in the cog list for a repo.

View File

@ -119,8 +119,14 @@ class VersionInfo:
"dev_release": self.dev_release, "dev_release": self.dev_release,
} }
def __lt__(self, other: "VersionInfo") -> bool: def _generate_comparison_tuples(
tups: _List[_Tuple[int, int, int, int, int, int, int]] = [] self, other: "VersionInfo"
) -> _List[
_Tuple[int, int, int, int, _Union[int, float], _Union[int, float], _Union[int, float]]
]:
tups: _List[
_Tuple[int, int, int, int, _Union[int, float], _Union[int, float], _Union[int, float]]
] = []
for obj in (self, other): for obj in (self, other):
tups.append( tups.append(
( (
@ -133,8 +139,20 @@ class VersionInfo:
obj.dev_release if obj.dev_release is not None else _inf, obj.dev_release if obj.dev_release is not None else _inf,
) )
) )
return tups
def __lt__(self, other: "VersionInfo") -> bool:
tups = self._generate_comparison_tuples(other)
return tups[0] < tups[1] return tups[0] < tups[1]
def __eq__(self, other: "VersionInfo") -> bool:
tups = self._generate_comparison_tuples(other)
return tups[0] == tups[1]
def __le__(self, other: "VersionInfo") -> bool:
tups = self._generate_comparison_tuples(other)
return tups[0] <= tups[1]
def __str__(self) -> str: def __str__(self) -> str:
ret = f"{self.major}.{self.minor}.{self.micro}" ret = f"{self.major}.{self.minor}.{self.micro}"
if self.releaselevel != self.FINAL: if self.releaselevel != self.FINAL:

View File

@ -8,7 +8,7 @@ from sys import path as syspath
from typing import Tuple, Union, Iterable from typing import Tuple, Union, Iterable
import discord import discord
from redbot.core import checks, commands, Config from redbot.core import checks, commands, Config, version_info as red_version_info
from redbot.core.bot import Red from redbot.core.bot import Red
from redbot.core.data_manager import cog_data_path from redbot.core.data_manager import cog_data_path
from redbot.core.i18n import Translator, cog_i18n from redbot.core.i18n import Translator, cog_i18n
@ -303,6 +303,26 @@ class Downloader(commands.Cog):
) )
) )
return return
ignore_max = cog.min_bot_version > cog.max_bot_version
if (
cog.min_bot_version > red_version_info
or not ignore_max
and cog.max_bot_version < red_version_info
):
await ctx.send(
_("This cog requires at least Red version {min_version}").format(
min_version=cog.min_bot_version
)
+ (
""
if ignore_max
else _(" and at most {max_version}").format(max_version=cog.max_bot_version)
)
+ _(", but you have {current_version}, aborting install.").format(
current_version=red_version_info
)
)
return
if not await repo.install_requirements(cog, self.LIB_PATH): if not await repo.install_requirements(cog, self.LIB_PATH):
libraries = humanize_list(tuple(map(inline, cog.requirements))) libraries = humanize_list(tuple(map(inline, cog.requirements)))

View File

@ -8,6 +8,8 @@ from typing import MutableMapping, Any, TYPE_CHECKING
from .log import log from .log import log
from .json_mixins import RepoJSONMixin from .json_mixins import RepoJSONMixin
from redbot.core import __version__, version_info as red_version_info, VersionInfo
if TYPE_CHECKING: if TYPE_CHECKING:
from .repo_manager import RepoManager from .repo_manager import RepoManager
@ -72,7 +74,8 @@ class Installable(RepoJSONMixin):
self.repo_name = self._location.parent.stem self.repo_name = self._location.parent.stem
self.author = () self.author = ()
self.bot_version = (3, 0, 0) self.min_bot_version = red_version_info
self.max_bot_version = red_version_info
self.min_python_version = (3, 5, 1) self.min_python_version = (3, 5, 1)
self.hidden = False self.hidden = False
self.disabled = False self.disabled = False
@ -157,10 +160,16 @@ class Installable(RepoJSONMixin):
self.author = author self.author = author
try: try:
bot_version = tuple(info.get("bot_version", [3, 0, 0])) min_bot_version = VersionInfo.from_str(str(info.get("min_bot_version", __version__)))
except ValueError: except ValueError:
bot_version = self.bot_version min_bot_version = self.min_bot_version
self.bot_version = bot_version self.min_bot_version = min_bot_version
try:
max_bot_version = VersionInfo.from_str(str(info.get("max_bot_version", __version__)))
except ValueError:
max_bot_version = self.max_bot_version
self.max_bot_version = max_bot_version
try: try:
min_python_version = tuple(info.get("min_python_version", [3, 5, 1])) min_python_version = tuple(info.get("min_python_version", [3, 5, 1]))

View File

@ -83,7 +83,8 @@ def bot_repo(event_loop):
# Installable # Installable
INFO_JSON = { INFO_JSON = {
"author": ("tekulvw",), "author": ("tekulvw",),
"bot_version": (3, 0, 0), "min_bot_version": "3.0.0",
"max_bot_version": "3.0.2",
"description": "A long description", "description": "A long description",
"hidden": False, "hidden": False,
"install_msg": "A post-installation message", "install_msg": "A post-installation message",
@ -96,7 +97,8 @@ INFO_JSON = {
LIBRARY_INFO_JSON = { LIBRARY_INFO_JSON = {
"author": ("seputaes",), "author": ("seputaes",),
"bot_version": (3, 0, 0), "min_bot_version": "3.0.0",
"max_bot_version": "3.0.2",
"description": "A long library description", "description": "A long library description",
"hidden": False, # libraries are always hidden, this tests it will be flipped "hidden": False, # libraries are always hidden, this tests it will be flipped
"install_msg": "A library install message", "install_msg": "A library install message",

View File

@ -5,12 +5,15 @@ import pytest
from redbot.pytest.downloader import * from redbot.pytest.downloader import *
from redbot.cogs.downloader.installable import Installable, InstallableType from redbot.cogs.downloader.installable import Installable, InstallableType
from redbot.core import VersionInfo
def test_process_info_file(installable): def test_process_info_file(installable):
for k, v in INFO_JSON.items(): for k, v in INFO_JSON.items():
if k == "type": if k == "type":
assert installable.type == InstallableType.COG assert installable.type == InstallableType.COG
elif k in ("min_bot_version", "max_bot_version"):
assert getattr(installable, k) == VersionInfo.from_str(v)
else: else:
assert getattr(installable, k) == v assert getattr(installable, k) == v
@ -19,6 +22,8 @@ def test_process_lib_info_file(library_installable):
for k, v in LIBRARY_INFO_JSON.items(): for k, v in LIBRARY_INFO_JSON.items():
if k == "type": if k == "type":
assert library_installable.type == InstallableType.SHARED_LIBRARY assert library_installable.type == InstallableType.SHARED_LIBRARY
elif k in ("min_bot_version", "max_bot_version"):
assert getattr(library_installable, k) == VersionInfo.from_str(v)
elif k == "hidden": elif k == "hidden":
# libraries are always hidden, even if False # libraries are always hidden, even if False
assert library_installable.hidden is True assert library_installable.hidden is True