Compare commits

...

37 commits

Author SHA1 Message Date
8c6be4c30d
Merge branch 'main' into updatechecker 2024-01-13 14:13:22 +00:00
9a7b627854
fix(updatechecker): trying to figure out why I'm getting an error 2024-01-08 06:06:30 +00:00
50180c6301
fix(updatechecker): fixed error in the fetch_gitea_thumbnail method 2024-01-07 19:51:18 +00:00
88ee068cbd
fix(updatechecker): final pylint fixes (for now) 2024-01-07 19:29:01 +00:00
45fcc00cdb
fix(updatechecker): more pylint fixes 2024-01-07 19:27:19 +00:00
bc57fb8eca
fix(updatechecker): pylint fixes 2024-01-07 19:20:21 +00:00
77a4001fed
misc(docs): changed colors 2024-01-07 19:11:40 +00:00
c179dd0649
feat(docs): read through mkdocs material documentation and enabled a whole bunch of qol features 2024-01-07 18:52:25 +00:00
174775daad
fix(docs): fixed incorrect installation directions 2024-01-07 14:32:26 +00:00
19972fda33 Merge branch 'main' into updatechecker 2024-01-07 14:26:52 +00:00
a477c8482b
misc(workflow): some random changes 2024-01-07 14:23:36 +00:00
1ab812bf35
Merge branch 'main' into updatechecker 2024-01-07 14:15:26 +00:00
ee22541b99
misc(workflow): changed workflow name to Actions 2024-01-07 14:15:01 +00:00
e837fb1293
feat(workflow): seperated workflow into two seperate jobs 2024-01-07 14:11:59 +00:00
8664c883a5
fix(updatechecker): use discord.ext tasks 2024-01-07 14:01:27 +00:00
0695dc061e
misc(updatechecker): moved parsed_url 2024-01-07 13:59:20 +00:00
be687a58fa
misc(updatechecker): docstring change 2024-01-07 13:48:35 +00:00
3bf508859b
fix(updatechecker): hopefully fixed detecting rss changes 2024-01-07 13:47:45 +00:00
130fc6028a
feat(updatechecker): added support for thumbnails in gitea/forgejo 2024-01-07 13:41:53 +00:00
b4647a3c6b
feat(updatechecker): added gitea/forgejo support 2024-01-07 13:30:02 +00:00
c2b2dcb8a0
fix(docs): fixed env variable name 2024-01-07 13:14:36 +00:00
f3022a980e
fix(docs): fixed images breaking on branch docs 2024-01-07 13:13:16 +00:00
5a01a3b4b9
Merge branch 'main' into updatechecker 2024-01-07 13:05:18 +00:00
602f999285 Merge branch 'main' into updatechecker 2024-01-07 12:50:10 +00:00
4b44db2c9d Merge branch 'main' into updatechecker 2024-01-07 12:41:33 +00:00
eaabd4cd04 Merge branch 'main' into updatechecker 2024-01-07 12:38:35 +00:00
50410d3c08 Merge branch 'main' into updatechecker 2024-01-07 12:25:02 +00:00
84532af05e Merge branch 'main' into updatechecker 2024-01-07 12:22:20 +00:00
960c97ba44 Merge branch 'main' into updatechecker 2024-01-07 12:18:43 +00:00
9d445690db Merge branch 'main' into updatechecker 2024-01-07 02:47:04 +00:00
c9916f7ea7 Merge branch 'main' into updatechecker 2024-01-07 02:38:30 +00:00
21cbe8008e
Merge branch 'main' into updatechecker 2024-01-07 02:27:35 +00:00
3fb695b2e5
Merge branch 'main' into updatechecker 2024-01-07 02:15:10 +00:00
ac0c775740 Merge branch 'main' into updatechecker 2024-01-06 19:31:15 +00:00
7513258cf5
feat(updatechecker): added the cog 2024-01-06 18:54:31 +00:00
b9ef96665e
feat(docs): added documentation for the updatechecker cog 2024-01-06 18:49:19 +00:00
e49be8bda8 Merge branch 'main' into updatechecker 2024-01-06 18:37:16 +00:00
8 changed files with 571 additions and 6 deletions

View file

@ -0,0 +1,5 @@
{% extends "base.html" %}
{% block announce %}
Put an announcement here.
{% endblock %}

22
.docs/updatechecker.md Normal file
View file

@ -0,0 +1,22 @@
# UpdateChecker
/// admonition | This project is not ready for production use
type: danger
The UpdateChecker cog is currently in an unfinished state, until it is completed please use [NeuroAssassin's UpdateChecker cog](https://github.com/NeuroAssassin/Toxic-Cogs) instead.
///
UpdateChecker will tell when there is an update available for a repository you have added for your bot, and, depending on settings, will auto update or will just notify you.
This is a fork of [NeuroAssassin's UpdateChecker cog](https://github.com/NeuroAssassin/Toxic-Cogs).
Additional features include support for Gitea/Forgejo RSS feeds, instead of just GitHub. (1)
{ .annotate }
1. ⚠️ Not yet implemented.
## Installation
```bash
[p]repo add seacogs-updatechecker https://coastalcommits.com/SeaswimmerTheFsh/SeaCogs updatechecker
[p]cog install seacogs-updatechecker updatechecker
[p]cog load updatechecker
```

View file

@ -1,8 +1,8 @@
site_name: SeaCogs Documentation site_name: SeaCogs Documentation
site_url: https://seacogs.coastalcommits.com site_url: !ENV [SITE_URL, 'https://seacogs.coastalcommits.com']
repo_name: CoastalCommits repo_name: CoastalCommits
repo_url: https://coastalcommits.com/SeaswimmerTheFsh/SeaCogs repo_url: https://coastalcommits.com/SeaswimmerTheFsh/SeaCogs
edit_uri: src/branch/main/.docs edit_uri: !ENV [EDIT_URI, 'src/branch/main/.docs']
copyright: Copyright © 2024, SeaswimmerTheFsh copyright: Copyright © 2024, SeaswimmerTheFsh
docs_dir: .docs docs_dir: .docs
@ -12,11 +12,12 @@ site_description: Documentation for my Red-DiscordBot Cogs.
nav: nav:
- Home: index.md - Home: index.md
- Aurora: - Aurora:
- Home: aurora/index.md - aurora/index.md
- Moderation Commands: aurora/moderation-commands.md - Moderation Commands: aurora/moderation-commands.md
- Case Commands: aurora/case-commands.md - Case Commands: aurora/case-commands.md
- Configuration: aurora/configuration.md - Configuration: aurora/configuration.md
- Nerdify: nerdify.md - Nerdify: nerdify.md
- UpdateChecker: updatechecker.md
plugins: plugins:
- git-authors - git-authors
@ -62,19 +63,44 @@ markdown_extensions:
theme: theme:
name: material name: material
custom_dir: ./.docs/.overrides
palette: palette:
- media: '(prefers-color-scheme: light)'
scheme: default
primary: cyan
accent: light blue
toggle:
icon: material/toggle-switch
name: Switch to dark mode
- media: '(prefers-color-scheme: dark)'
scheme: slate scheme: slate
primary: cyan
accent: light blue
toggle:
icon: material/toggle-switch-off-outline
name: Switch to light mode
features: features:
- announce.dismiss
- content.code.annotate - content.code.annotate
- content.code.copy - content.code.copy
- navigation.instant - navigation.instant
- navigation.instant.progress
- navigation.tabs - navigation.tabs
- navigation.tracking
- navigation.top
- navigation.sections
- navigation.indexes
- search.suggest - search.suggest
- search.highlight - search.highlight
- search.share - search.share
- toc.follow
logo: img/logo.png logo: img/logo.png
favicon: img/logo.png favicon: img/logo.png
icon:
repo: simple/forgejo
watch: watch:
- ./aurora - ./aurora
- ./nerdify - ./nerdify
- ./updatechecker

28
poetry.lock generated
View file

@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. # This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
[[package]] [[package]]
name = "aiodns" name = "aiodns"
@ -685,6 +685,20 @@ files = [
{file = "distro-1.8.0.tar.gz", hash = "sha256:02e111d1dc6a50abb8eed6bf31c3e48ed8b0830d1ea2a1b78c61765c2513fdd8"}, {file = "distro-1.8.0.tar.gz", hash = "sha256:02e111d1dc6a50abb8eed6bf31c3e48ed8b0830d1ea2a1b78c61765c2513fdd8"},
] ]
[[package]]
name = "feedparser"
version = "6.0.11"
description = "Universal feed parser, handles RSS 0.9x, RSS 1.0, RSS 2.0, CDF, Atom 0.3, and Atom 1.0 feeds"
optional = false
python-versions = ">=3.6"
files = [
{file = "feedparser-6.0.11-py3-none-any.whl", hash = "sha256:0be7ee7b395572b19ebeb1d6aafb0028dee11169f1c934e0ed67d54992f4ad45"},
{file = "feedparser-6.0.11.tar.gz", hash = "sha256:c9d0407b64c6f2a065d0ebb292c2b35c01050cc0dc33757461aaabdc4c4184d5"},
]
[package.dependencies]
sgmllib3k = "*"
[[package]] [[package]]
name = "frozenlist" name = "frozenlist"
version = "1.4.0" version = "1.4.0"
@ -2191,6 +2205,16 @@ files = [
[package.dependencies] [package.dependencies]
contextlib2 = ">=0.5.5" contextlib2 = ">=0.5.5"
[[package]]
name = "sgmllib3k"
version = "1.0.0"
description = "Py3k port of sgmllib."
optional = false
python-versions = "*"
files = [
{file = "sgmllib3k-1.0.0.tar.gz", hash = "sha256:7868fb1c8bfa764c1ac563d3cf369c381d1325d36124933a726f29fcdaa812e9"},
]
[[package]] [[package]]
name = "six" name = "six"
version = "1.16.0" version = "1.16.0"
@ -2558,4 +2582,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = ">=3.9,<3.12" python-versions = ">=3.9,<3.12"
content-hash = "b3a94060974d7ece0d58a3625794c721dd84d34c8215296deeb352b0eb49e29b" content-hash = "6f70528246aa941fb37cc239583217faa49660ccaa6196fe13eb39a9c3605735"

View file

@ -11,6 +11,7 @@ python = ">=3.9,<3.12"
Red-DiscordBot = "^3.5.5" Red-DiscordBot = "^3.5.5"
pytimeparse2 = "^1.7.1" pytimeparse2 = "^1.7.1"
humanize = "^4.8.0" humanize = "^4.8.0"
feedparser = "^6.0.11"
[tool.poetry.group.dev] [tool.poetry.group.dev]
optional = true optional = true

10
updatechecker/__init__.py Normal file
View file

@ -0,0 +1,10 @@
from .updatechecker import UpdateChecker
__red_end_user_data_statement__ = (
"This cog does not persistently store data or metadata about users."
)
async def setup(bot):
cog = UpdateChecker(bot)
await bot.add_cog(cog)

17
updatechecker/info.json Normal file
View file

@ -0,0 +1,17 @@
{
"author": [
"SeaswimmerTheFsh", "Neuro Assassin"
],
"install_msg": "Thank you for downloading this cog.",
"name": "updatechecker",
"short": "Notifies you when an update for a repo is available.",
"description": "This cog will tell when there is an update available for a repository you have added for your bot, and, depending on settings, will auto update or will just notify you.",
"tags": [
"tools"
],
"requirements": [
"feedparser"
],
"hidden": false,
"disabled": false
}

View file

@ -0,0 +1,460 @@
"""
MIT License
Copyright (c) 2018-Present NeuroAssassin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
# Huge thanks to Sinbad for allowing me to copy parts of his RSS cog
# (https://github.com/mikeshardmind/SinbadCogs/tree/v3/rss), which I
# used to grab the latest commits from repositories.
# Also, the code I use for updating repos I took directly from Red,
# and just took out the message interactions
import asyncio
import traceback
from datetime import datetime
from urllib.parse import urlparse
import aiohttp
import discord
from discord.ext import tasks
from redbot.cogs.downloader.repo_manager import Repo
from redbot.core import Config, commands
from redbot.core.utils.chat_formatting import box, humanize_list, inline
import feedparser
class UpdateChecker(commands.Cog):
"""Get notices or auto-update cogs when an update is available for its repo"""
def __init__(self, bot):
self.bot = bot
self.session = aiohttp.ClientSession()
self.conf = Config.get_conf(self, identifier=473541068378341376)
default_global = {
"repos": {},
"auto": False,
"gochannel": 0,
"embed": True,
"whitelist": [],
"blacklist": [],
}
self.conf.register_global(**default_global)
self.task = self.bot.loop.create_task(self.bg_task())
async def cog_unload(self):
self.__unload()
def __unload(self):
self.task.cancel()
self.session.detach()
async def red_delete_data_for_user(self, **kwargs): # pylint: disable=unused-argument
"""This cog does not store user data"""
return
@tasks.loop(minutes=1)
async def bg_task(self):
cog = self.bot.get_cog("Downloader")
if cog is not None:
data = await self.conf.all()
repos = data["repos"]
channel = data["gochannel"]
auto = data["auto"]
use_embed = data["embed"]
whitelist = data["whitelist"]
blacklist = data["blacklist"]
if channel:
channel = self.bot.get_channel(channel)
if channel is None:
await self.bot.send_to_owners(
"[Update Checker] It appears that I am no longer allowed to send messages to the designated update channel. "
"From now on, it will DM you."
)
await self.conf.gochannel.set(0)
send = self.bot.send_to_owners
else:
use_embed = (
use_embed and channel.permissions_for(channel.guild.me).embed_links
)
send = channel.send
else:
send = self.bot.send_to_owners
all_repos = cog._repo_manager.get_all_repo_names() # pylint: disable=protected-access
for repo in all_repos:
if not (repo in list(repos.keys())):
repos[repo] = "--default--"
await self.conf.repos.set(repos)
saving_dict = {k: v for k, v in repos.items() if k in all_repos}
for repo_name, commit_saved in saving_dict.items():
repo = cog._repo_manager.get_repo(repo_name) # pylint: disable=protected-access
if not repo:
continue
parsed_url = urlparse(repo.url)
if parsed_url.netloc == "github.com":
url = repo.url + r"/commits/" + repo.branch + ".atom"
response = await self.fetch_feed(url)
try:
commit = response.entries[0]["id"][33:]
chash = "[" + commit + "](" + response.entries[0]["link"] + ")"
cn = response.entries[0]["title"] + " - " + response.entries[0]["author"]
image = response.entries[0]["media_thumbnail"][0]["url"].split("?")[0]
except AttributeError:
continue
else:
url = repo.url + r"/rss/branch/" + repo.branch
response = await self.fetch_feed(url)
try:
commit = response.entries[0]["id"][33:]
chash = "[" + commit + "](" + response.entries[0]["link"] + ")"
cn = response.entries[0]["title"] + " - " + response.entries[0]["author"]
image = await self.fetch_gitea_thumbnail(parsed_url.scheme + "://" + parsed_url.netloc + "/api/v1/repos" + parsed_url.path)
except AttributeError:
continue
saving_dict[repo_name] = commit
if whitelist:
if repo_name not in whitelist:
continue
if repo_name in blacklist:
continue
# CN is used here for backwards compatability, don't want people to get an
# update for each and every one of their cogs when updating this cog
if commit_saved not in (commit, cn, '--default--'):
if use_embed:
e = discord.Embed(
title="Update Checker",
description=f"Update available for repo: {repo.name}",
timestamp=datetime.utcnow(),
color=0x00FF00,
)
e.add_field(name="URL", value=repo.url)
e.add_field(name="Branch", value=repo.branch)
e.add_field(name="Commit", value=cn)
e.add_field(name="Hash", value=chash)
if image is not None:
e.set_thumbnail(url=image)
else:
e = box(
"[Update Checker]"
f" Repo: {repo.name}\n"
f" URL: {repo.url}\n"
f" Commit: {cn}\n"
f" Hash: {commit}\n"
f" Time: {datetime.utcnow()}",
'css'
)
try:
if use_embed:
await send(embed=e)
else:
await send(e)
except discord.Forbidden:
# send_to_owners suppresses Forbidden, logging it to console.
# As a result, this will only happen if a channel was set.
await self.bot.send_to_owners(
"[Update Checker] It appears that I am no longer allowed to send messages to the designated update channel. "
"From now on, it will DM you."
)
if use_embed:
await self.bot.send_to_owners(embed=e)
else:
await self.bot.send_to_owners(e)
await self.conf.gochannel.set(0)
# Was already inaccessible before I got here, so I'm just gonna leave it and look at it later -- Sea
# try:
# await channel.send(
# f"[Update Checker] Update found for repo: {repo.name}. Updating repos..."
# )
# except AttributeError:
# owner = (await self.bot.application_info()).owner
# await owner.send(
# "[Update Checker] It appears that the channel for this cog has been deleted. From now on, it will DM you."
# )
# channel = owner
# await self.conf.gochannel.set(0)
# except discord.errors.Forbidden:
# owner = (await self.bot.application_info()).owner
# await owner.send(
# "[Update Checker] It appears that I am no longer allowed to send messages to the designated update channel. From now on, it will DM you."
# )
# channel = owner
# await self.conf.gochannel.set(0)
# # Just a copy of `[p]cog update`, but without using ctx things
# try:
# installed_cogs = set(await cog.installed_cogs())
# updated = await cog._repo_manager.update_all_repos()
# updated_cogs = set(
# cog for repo in updated for cog in repo.available_cogs
# )
# installed_and_updated = updated_cogs & installed_cogs
# if installed_and_updated:
# await cog._reinstall_requirements(installed_and_updated)
# await cog._reinstall_cogs(installed_and_updated)
# await cog._reinstall_libraries(installed_and_updated)
# cognames = {c.name for c in installed_and_updated}
# message = humanize_list(tuple(map(inline, cognames)))
# except Exception as error:
# exception_log = (
# "Exception while updating repos in Update Checker \n"
# )
# exception_log += "".join(
# traceback.format_exception(
# type(error), error, error.__traceback__
# )
# )
# try:
# await channel.send(
# f"[Update Checker]: Error while updating repos.\n\n{exception_log}"
# )
# except discord.errors.Forbidden:
# pass
# else:
# try:
# await channel.send(
# f"[Update Checker]: Ran cog update. Updated cogs: {message}"
# )
# except discord.errors.Forbidden:
# pass
await asyncio.sleep(1)
await self.conf.repos.set(saving_dict)
async def fetch_feed(self, url: str):
# Thank's to Sinbad's rss cog after which I copied this
timeout = aiohttp.client.ClientTimeout(total=15)
try:
async with self.session.get(url, timeout=timeout) as response:
data = await response.read()
except (aiohttp.ClientError, asyncio.TimeoutError):
return None
ret = feedparser.parse(data)
if ret.bozo:
return None
return ret
async def fetch_gitea_thumbnail(self, url: str) -> str:
timeout = aiohttp.client.ClientTimeout(total=15)
try:
async with self.session.get(url, timeout=timeout) as response:
data = await response.json()
except (aiohttp.ClientError, asyncio.TimeoutError):
return None
return data['avatar_url']
@commands.is_owner()
@commands.group(name="cogupdater", aliases=["cu"])
async def update(self, ctx: commands.Context):
"""Group command for controlling the update checker cog."""
@commands.is_owner()
@update.command()
async def auto(self, ctx: commands.Context):
"""Changes automatic cog updates to the opposite setting."""
# Was already inaccessible before I got here, so I'm just gonna leave it and look at it later -- Sea
# auto = await self.conf.auto()
# await self.conf.auto.set(not auto)
# status = "disabled" if auto else "enabled"
# await ctx.send(f"Auto cog updates are now {status}")
await ctx.send(
"This command is disabled for the time being. Cog updates will not run automatically, however notifications will still send."
)
@commands.is_owner()
@update.command()
async def channel(self, ctx: commands.Context, channel: discord.TextChannel = None):
"""
Sets a channel for update messages to go to.
If argument is not supplied, it will be sent to the default notifications channel(s) specified in `[p]set ownernotifications`.
By default, this goes to owner DMs.
"""
if channel:
await self.conf.gochannel.set(channel.id)
await ctx.send(f"Update messages will now be sent to {channel.mention}")
else:
await self.conf.gochannel.set(0)
await ctx.send("Update messages will now be DMed to you.")
@commands.is_owner()
@update.command()
async def settings(self, ctx: commands.Context):
"""See settings for the Update Checker cog.
Right now, this shows whether the bot updates cogs automatically and what channel logs are sent to.
"""
auto = await self.conf.auto()
channel = await self.conf.gochannel()
embed = await self.conf.embed()
if embed:
e = discord.Embed(title="Update Checker Settings", color=0x00FF00)
e.add_field(name="Automatic Cog Updates", value=str(auto))
if channel == 0:
channel = "Direct Messages"
else:
channel = self.bot.get_channel(channel).name
if channel is None:
channel = "Unknown"
e.add_field(name="Update Channel", value=channel)
await ctx.send(embed=e)
else:
if channel == 0:
channel = "Direct Messages"
else:
channel = self.bot.get_channel(channel).name
if channel is None:
channel = "Unknown"
message = (
"```css\n"
"[Update Checker settings]"
"``````css\n"
f"[Automatic Cog Updates]: {str(auto)}\n"
f" [Update Channel]: {channel}"
"```"
)
await ctx.send(message)
@commands.is_owner()
@update.command()
async def embed(self, ctx: commands.Context):
"""Toggles whether to use embeds or colorful codeblock messages when sending an update."""
c = await self.conf.embed()
await self.conf.embed.set(not c)
word = "disabled" if c else "enabled"
await ctx.send(f"Embeds are now {word}")
@commands.is_owner()
@update.group(name="list")
async def whiteblacklist(self, ctx: commands.Context):
"""Whitelist/blacklist certain repositories from which to receive updates."""
if ctx.invoked_subcommand is None:
data = await self.conf.all()
whitelist = data["whitelist"]
blacklist = data["blacklist"]
await ctx.send(
f"Whitelisted: {humanize_list(tuple(map(inline, whitelist or ['None'])))}\nBlacklisted: {humanize_list(tuple(map(inline, blacklist or ['None'])))}"
)
@whiteblacklist.group()
async def whitelist(self, ctx: commands.Context):
"""Whitelist certain repos from which to receive updates."""
@whitelist.command(name="add")
async def whitelistadd(self, ctx: commands.Context, *repos: Repo):
"""Add repos to the whitelist"""
data = await self.conf.whitelist()
ds = set(data)
ns = {r.name for r in repos}
ss = ds | ns
await self.conf.whitelist.set(list(ss))
await ctx.send(f"Whitelist update successful: {humanize_list(tuple(map(inline, ss)))}")
@whitelist.command(name="remove")
async def whitelistremove(self, ctx: commands.Context, *repos: Repo):
"""Remove repos from the whitelist"""
data = await self.conf.whitelist()
ds = set(data)
ns = {r.name for r in repos}
ss = ds - ns
await self.conf.whitelist.set(list(ss))
await ctx.send(
f"Whitelist update successful: {humanize_list(tuple(map(inline, ss or ['None'])))}"
)
@whitelist.command(name="clear")
async def whitelistclear(self, ctx: commands.Context):
"""Removes all repos from the whitelist"""
await self.conf.whitelist.set([])
await ctx.send("Whitelist update successful")
@whiteblacklist.group()
async def blacklist(self, ctx: commands.Context):
"""Blacklist certain repos from which to receive updates."""
@blacklist.command(name="add")
async def blacklistadd(self, ctx: commands.Context, *repos: Repo):
"""Add repos to the blacklist"""
data = await self.conf.blacklist()
ds = set(data)
ns = {r.name for r in repos}
ss = ds | ns
await self.conf.blacklist.set(list(ss))
await ctx.send(f"Backlist update successful: {humanize_list(tuple(map(inline, ss)))}")
@blacklist.command(name="remove")
async def blacklistremove(self, ctx: commands.Context, *repos: Repo):
"""Remove repos from the blacklist"""
data = await self.conf.blacklist()
ds = set(data)
ns = {r.name for r in repos}
ss = ds - ns
await self.conf.blacklist.set(list(ss))
await ctx.send(
f"Blacklist update successful: {humanize_list(tuple(map(inline, ss or ['None'])))}"
)
@blacklist.command(name="clear")
async def blacklistclear(self, ctx: commands.Context):
"""Removes all repos from the blacklist"""
await self.conf.blacklist.set([])
await ctx.send("Blacklist update successful")
@commands.is_owner()
@update.group(name="task")
async def _group_update_task(self, ctx: commands.Context):
"""View the status of the task (the one checking for updates)."""
@_group_update_task.command()
async def status(self, ctx: commands.Context):
"""Get the current status of the update task."""
message = "Task is currently "
cancelled = self.task.cancelled()
if cancelled:
message += "canceled."
else:
done = self.task.done()
if done:
message += "done."
else:
message += "running."
try:
self.task.exception()
except asyncio.exceptions.InvalidStateError:
message += " No error has been encountered."
else:
message += f" An error has been encountered. Please run `{ctx.prefix}cogupdater task error` and report it to SeaswimmerTheFsh (seasw.) on the help server."
await ctx.send(message)
@_group_update_task.command()
async def error(self, ctx: commands.Context):
"""Gets the latest error of the update task."""
try:
e = self.task.exception()
except asyncio.exceptions.InvalidStateError:
message = "No error has been encountered."
else:
ex = traceback.format_exception(type(e), e, e.__traceback__)
message = "An error has been encountered:" + box("".join(ex), "py")
await ctx.send(message)