Skip to content

Commit 262379f

Browse files
authored
Merge branch 'plugin_api_v2' into plugin_api_v2
2 parents d1e85bd + 1fe3373 commit 262379f

File tree

75 files changed

+3500
-2655
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+3500
-2655
lines changed

.github/workflows/links.yml

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,33 @@ name: Check Links
22

33
on:
44
workflow_dispatch:
5-
push:
6-
paths:
7-
- 'plugins.json'
85
pull_request:
96
paths:
10-
- 'plugins.json'
7+
- plugins/**
118
schedule:
12-
- cron: "0 */12 * * *"
9+
- cron: "0 1 * * *"
1310

1411
jobs:
1512
linkChecker:
1613
runs-on: ubuntu-latest
1714
steps:
1815
- uses: actions/checkout@v4
1916

17+
- name: Create plugins.json For All Plugins
18+
if: ${{ github.event_name == 'schedule' }}
19+
run: |
20+
python ./ci/src/merge-manifest.py
21+
22+
- name: Create plugins.json For New Plugins Only
23+
if: ${{ github.event_name == 'pull_request' }}
24+
run: |
25+
python ./ci/src/merge-manifest.py new-only
26+
2027
- name: Link Checker
2128
id: lychee
22-
uses: lycheeverse/lychee-action@v1.8.0
29+
uses: lycheeverse/lychee-action@v2
2330
with:
2431
args: --verbose --no-progress plugins.json
2532
fail: true
26-
env:
27-
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
33+
failIfEmpty: false
34+
token: ${{ secrets.LINKCHECKER }}

.github/workflows/python-passed.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,12 @@ jobs:
1919
uses: actions/setup-python@v5
2020
with:
2121
python-version: 3.x
22+
- name: Install dependencies
23+
run: |
24+
python -m pip install --upgrade pip
25+
pip install -r ./ci/envs/requirements-update-tested.txt
2226
- name: Run script
23-
run: python ./ci/src/update-tested.py
27+
run: python ./ci/src/update-tested.py ${{ secrets.DISCORD_WEBHOOK }}
2428
- name: Update plugin manifest
2529
if: success()
2630
uses: stefanzweifel/git-auto-commit-action@v4

.github/workflows/test-python.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747
uses: actions/setup-python@v5
4848
with:
4949
python-version: ${{ github.event.inputs.pyversion }}
50-
- uses: actions/cache@v2
50+
- uses: actions/cache@v4
5151
if: startsWith(runner.os, 'Windows')
5252
with:
5353
path: ~\AppData\Local\pip\Cache
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
aiohttp
2+
tqdm

ci/src/_utils.py

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
# -*-coding: utf-8 -*-
22
import json
3+
import os
4+
import re
35
from pathlib import Path
46
from typing import Dict, List, TypeVar
5-
import re
6-
import os
7+
8+
# If adding a third-party library here, check CI workflows Python files
9+
# that are dependant on this and require pip install.
710

811
# path
912
utils_path = Path(__file__).resolve()
@@ -17,7 +20,18 @@
1720
# constants
1821
id_name = "ID"
1922
language_name = "Language"
20-
language_list = ("csharp", "executable", "fsharp", "python", "javascript", "typescript", "python_v2", "executable_v2", "javascript_v2", "typescript_v2")
23+
language_list = (
24+
"csharp",
25+
"executable",
26+
"fsharp",
27+
"python",
28+
"javascript",
29+
"typescript",
30+
"python_v2",
31+
"executable_v2",
32+
"javascript_v2",
33+
"typescript_v2",
34+
)
2135
etag = "ETag"
2236
version = "Version"
2337
url_sourcecode = "UrlSourceCode"
@@ -30,6 +44,7 @@
3044
github_url = "https://github.com"
3145
release_date = "LatestReleaseDate"
3246
date_added = "DateAdded"
47+
website = "Website"
3348

3449
# typing
3550
PluginType = Dict[str, str]
@@ -51,12 +66,20 @@ def plugin_reader() -> P:
5166

5267
return manifests
5368

69+
70+
def save_plugins_json_file(content: list[dict[str]]) -> None:
71+
with open("plugins.json", "w", encoding="utf-8") as f:
72+
json.dump(content, f, indent=4, ensure_ascii=False)
73+
74+
5475
def get_plugin_file_paths() -> list[str]:
5576
return [os.path.join(plugin_dir, filename) for filename in get_plugin_filenames()]
5677

78+
5779
def get_plugin_filenames() -> list[str]:
5880
return os.listdir(plugin_dir)
5981

82+
6083
def etag_reader() -> ETagsType:
6184
with open(etag_file, "r", encoding="utf-8") as f:
6285
return json.load(f)
@@ -66,7 +89,8 @@ def plugin_writer(content: P):
6689
for plugin in content:
6790
with open(plugin_dir / f"{plugin[plugin_name]}-{plugin[id_name]}.json", "w", encoding="utf-8") as f:
6891
json.dump(plugin, f, indent=4)
69-
92+
93+
7094
def etags_writer(content: ETagsType):
7195
with open(etag_file, "w", encoding="utf-8") as f:
7296
json.dump(content, f, indent=4)
@@ -75,10 +99,12 @@ def etags_writer(content: ETagsType):
7599
def clean(string: str, flag="-") -> str:
76100
return string.lower().replace(flag, "").strip()
77101

102+
78103
def version_tuple(version: str) -> tuple:
79104
version = clean(version, "v")
80105
return tuple(version.split("."))
81106

107+
82108
def check_url(url: str) -> bool:
83109
regex = re.compile(
84110
r"^(?:http|ftp)s?://" # http:// or https://
@@ -100,3 +126,19 @@ def get_file_plugins_json_info(required_key: str = "") -> list[dict[str, str]]:
100126
return data
101127

102128
return [{required_key: plugin[required_key]} for plugin in data]
129+
130+
131+
def get_new_plugin_submission_ids() -> list[str]:
132+
plugins_json_ids = [item["ID"] for item in get_file_plugins_json_info("ID")]
133+
existing_plugin_file_ids = [info["ID"] for info in plugin_reader()]
134+
135+
new_ids = []
136+
137+
for id in existing_plugin_file_ids:
138+
# plugins.json would not contain new submission's ID.
139+
if id in plugins_json_ids:
140+
continue
141+
142+
new_ids.append(id)
143+
144+
return new_ids

ci/src/discord.py

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import aiohttp
2-
2+
from tqdm.asyncio import tqdm
33
from _utils import *
44

55
MAX_BODY_LEN = 1024
66

77

8-
async def update_hook(webhook_url: str, info: dict, latest_ver: str, release: dict) -> None:
8+
async def update_hook(webhook_url: str, info: PluginType, latest_ver: str, release: dict) -> None:
99
embed = {
1010
"content": None,
1111
"embeds": [
@@ -43,6 +43,43 @@ async def update_hook(webhook_url: str, info: dict, latest_ver: str, release: di
4343
embed['embeds'][0]['fields'].append({"name": "Release Notes", "value": truncate_release_notes(release['html_url'], release.get('body', ""))})
4444
async with aiohttp.ClientSession() as session:
4545
await session.post(webhook_url, json=embed)
46+
47+
async def release_hook(webhook_url: str, info: PluginType) -> None:
48+
embed = {
49+
"content": None,
50+
"embeds": [
51+
{
52+
"title": info[plugin_name],
53+
"description": f"New Plugin!\nReleased at v{info[version]}.",
54+
"url": info[website],
55+
"color": 5763719, # green
56+
"fields": [
57+
{
58+
"name": "Plugin Description",
59+
"value": info[description]
60+
},
61+
{
62+
"name": "Plugin Language",
63+
"value": info[language_name]
64+
}
65+
],
66+
"author": {
67+
"name": info[author]
68+
},
69+
"thumbnail": {
70+
"url": info[icon_path]
71+
}
72+
}
73+
]
74+
}
75+
if 'github.com' in info[url_sourcecode].lower():
76+
github_username = info[url_sourcecode].split('/')[3]
77+
embed['embeds'][0]['author']['name'] = github_username
78+
embed['embeds'][0]['author']['url'] = f"{github_url}/{github_username}"
79+
embed['embeds'][0]["author"]["icon_url"] = f"{github_url}/{github_username}.png?size=40"
80+
81+
async with aiohttp.ClientSession() as session:
82+
await session.post(webhook_url, json=embed)
4683

4784
def truncate_release_notes(url: str, release_notes: str, length: int = MAX_BODY_LEN) -> str:
4885
if len(release_notes) <= length:

ci/src/merge-manifest.py

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,30 @@
1-
import glob
2-
import json
1+
import sys
32

4-
if __name__ == "__main__":
5-
plugins = sorted(glob.glob("plugins/*.json"))
3+
from _utils import get_new_plugin_submission_ids, plugin_reader, save_plugins_json_file
4+
5+
6+
def get_all_plugins() -> list[dict[str]]:
7+
return plugin_reader()
8+
9+
10+
def get_new_plugins() -> list[dict[str]]:
11+
ids = get_new_plugin_submission_ids()
12+
plugins_from_plugins_dir = plugin_reader()
613

7-
manifests = []
14+
new_plugins = []
815

9-
for plugin in plugins:
10-
with open(plugin, "r", encoding="utf-8") as f:
11-
manifest = json.load(f)
12-
manifests.append(manifest)
16+
for id in ids:
17+
for plugin in plugins_from_plugins_dir:
18+
if plugin["ID"] == id:
19+
new_plugins.append(plugin)
20+
break
21+
22+
return new_plugins
23+
24+
25+
if __name__ == "__main__":
1326

14-
with open("plugins.json", "w", encoding="utf-8") as f:
15-
json.dump(manifests, f, indent=4, ensure_ascii=False)
27+
if len(sys.argv) > 1 and str(sys.argv[1]) == "new-only":
28+
save_plugins_json_file(get_new_plugins())
29+
else:
30+
save_plugins_json_file(get_all_plugins())

ci/src/update-tested.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,32 @@
1-
import sys
2-
import json
3-
import os
4-
import zipfile
5-
import io
6-
from datetime import datetime
1+
import asyncio
2+
from datetime import datetime, UTC
3+
from sys import argv
4+
from _utils import plugin_reader, plugin_writer, date_added
5+
from discord import release_hook
76

8-
from _utils import clean, id_name, language_list, language_name, plugin_reader, plugin_writer, release_date, date_added
97

10-
if __name__ == "__main__":
8+
async def update_tested():
9+
webhook_url = None
10+
if len(argv) > 1:
11+
webhook_url = argv[1]
12+
1113
plugin_infos = plugin_reader()
1214

1315
for idx, plugin in enumerate(plugin_infos):
1416
if plugin["Language"] == "python" and "Tested" not in plugin.keys():
1517
plugin_infos[idx]["Tested"] = True
18+
1619
# Add date added if field is not present
1720
if plugin.get(date_added) is None:
18-
plugin_infos[idx][date_added] = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
19-
plugin_writer(plugin_infos)
20-
21-
22-
21+
plugin_infos[idx][date_added] = datetime.now(UTC).strftime(
22+
"%Y-%m-%dT%H:%M:%SZ"
23+
)
2324

25+
if webhook_url:
26+
await release_hook(webhook_url, plugin)
2427

28+
plugin_writer(plugin_infos)
2529

2630

31+
if __name__ == "__main__":
32+
asyncio.run(update_tested())

0 commit comments

Comments
 (0)