From 5e2cfc3aa8be265fa32072fa38038d0099cc8893 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 8 Dec 2025 20:08:16 +0530 Subject: [PATCH] One clean commit after all the testing --- .github/workflows/ci.yml | 108 +++++++++++++---------- .github/workflows/release.yml | 6 +- README.md | 90 ++++++-------------- test/auto_apply_plugin_metadata.py | 132 +++++++++++++++++++++++++++++ test/get_latest.py | 20 ++++- test/test_checks.py | 3 +- 6 files changed, 242 insertions(+), 117 deletions(-) create mode 100644 test/auto_apply_plugin_metadata.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de36220..7fc19ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,15 @@ name: CI +# WORD OF CAUTION: +# TO anyone modifying this +# Things will break if you modify this +# without understanding how it works + +# A simple flow of this file: +# Apply AutoPEP8 → Apply Plugin Metadata → CRITICAL COMMIT (format + plugin meta) +# ← ← ← ← ← ↵ +# ↪ Apply Version Metadata → Commit (version meta) → Tests + on: push: branches: @@ -9,48 +19,58 @@ on: jobs: build: runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.12"] steps: - - uses: actions/checkout@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - repository: ${{ github.event.pull_request.head.repo.full_name }} - ref: ${{ github.head_ref }} - fetch-depth: 0 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - - name: Install Dependencies - run: | - python -m pip install -U pip - python -m pip install -U pycodestyle==2.12.1 autopep8 - python -m pip install -U -r test/pip_reqs.txt - - - name: Apply AutoPEP8 - run: | - autopep8 --in-place --recursive --max-line-length=100 . - - - name: Commit AutoPEP8 - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: "[ci] auto-format" - branch: ${{ github.head_ref }} - - - name: Apply Version Metadata - run: | - python test/auto_apply_version_metadata.py $(git log --pretty=format:'%h' -n 1) - - - name: Commit Version Metadata - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: "[ci] apply-version-metadata" - branch: ${{ github.head_ref }} - - - name: Execute Tests - run: | - python -m unittest discover -v + - uses: actions/checkout@v6 + with: + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.12" + + - name: Install Dependencies + run: | + python -m pip install -U pip + python -m pip install -U pycodestyle==2.12.1 autopep8 + python -m pip install -U -r test/pip_reqs.txt + + - name: Apply AutoPEP8 + run: | + autopep8 --in-place --recursive --max-line-length=100 . + + - name: Apply Plugin Metadata + if: github.event_name == 'pull_request_target' + # should this only be run on pull_request_target and not pushes?? + run: | + LAST_COMMIT_HASH=$(git log --pretty=format:'%H' -n 1) + CHANGED_FILES=$(git diff-tree --no-commit-id --name-only -r "$LAST_COMMIT_HASH") + python test/auto_apply_plugin_metadata.py "$CHANGED_FILES" + + # This is a CRITICAL COMMIT for the next step + # which bases this as the commit to get the sha to store in index.json or plugin.json + - name: Commit Plugin Metadata and AutoPEP8 + uses: stefanzweifel/git-auto-commit-action@v7 + with: + commit_message: "[ci] apply-plugin-metadata-and-formatting" + branch: ${{ github.head_ref }} + + - name: Apply Version Metadata + run: | + python test/auto_apply_version_metadata.py $(git log --pretty=format:'%h' -n 1) + + - name: Commit Version Metadata + uses: stefanzweifel/git-auto-commit-action@v7 + with: + commit_message: "[ci] apply-version-metadata" + branch: ${{ github.head_ref }} + + - name: Refresh Repository + run: | + git fetch origin + git reset --hard HEAD + + - name: Execute Tests + run: | + python -m unittest discover -v diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9cfbbd7..59d8dd8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,9 +12,9 @@ jobs: name: Create Release runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: '3.12' @@ -27,7 +27,7 @@ jobs: - name: set_variables run: | - output1=$(python3 test/get_latest.py get_latest_version) + output1=$(python3 test/get_latest.py get_latest_plugman_version) { echo "changelog< plugman_version: + with open("index.json", "r+") as file: + data = json.load(file) + data[current_version] = None + data["versions"] = dict(sorted(data["versions"].items(), reverse=True)) + + +def update_plugin_json(plugin_info, category): + name = plugin_info["plugin_name"] + + with open(f"plugins/{category}.json", "r+") as file: + data = json.load(file) + try: + # Check if plugin is already in the json + plugin = data["plugins"][name] + plugman_version = int(get_latest_version(name, category).replace(".", "")) + current_version = int(plugin_info["version"].replace(".", "")) + # Ensure the version is always greater from the already released version + if current_version > plugman_version: + plugin["versions"][plugin_info["version"]] = None + # Ensure latest version appears first + plugin["versions"] = dict(sorted(plugin["versions"].items(), reverse=True)) + plugin["description"] = plugin_info["description"] + plugin["external_url"] = plugin_info["external_url"] + plugin["authors"] = plugin_info["authors"] + elif current_version <= plugman_version: + raise Exception("Version cant be lower or equal than the previous version.") + except KeyError: + data["plugins"][name] = { + "description": plugin_info["description"], + "external_url": plugin_info["external_url"], + "authors": plugin_info["authors"], + "versions": {plugin_info["version"]: None}, + } + + file.seek(0) + json.dump(data, file, indent=2, ensure_ascii=False) + # Ensure old content is removed + file.truncate() + + +def extract_plugman(plugins): + for plugin in plugins: + if "plugins/" in plugin: + + debug_print(plugin) + try: + # Split the path and get the part after 'plugins/' + parts = plugin.split("plugins/")[1].split("/") + file_name_no_extension = plugin.split("/")[-1].replace(".py", "") + category = parts[0] # First part after plugins/ + except ValueError: + if "plugin_manager" in plugin: + continue + with open(plugin, "r") as f: + tree = ast.parse(f.read()) + + for node in ast.walk(tree): + if isinstance(node, ast.Assign) and len(node.targets) == 1: + target = node.targets[0] + if isinstance(target, ast.Name) and target.id == "plugman": + if isinstance(node.value, ast.Dict): + # i dont want to support multiple formats for now + # because its harder to parse and maintain + # ill leave this here for now, though not supported + # Standard dictionary format {key: value} + return ast.literal_eval(node.value) + elif ( + isinstance(node.value, ast.Call) + and isinstance(node.value.func, ast.Name) + and node.value.func.id == "dict" + ): + # dict() constructor format + result = {} + for kw in node.value.keywords: + if kw.arg == "plugin_name": + plugin_name = ast.literal_eval(kw.value) + # some basic validation specific to plugin manager + if (plugin_name != plugin_name.lower()): + raise ValueError( + "Plugin name in plugman must be in snakecase.") + if (plugin_name != file_name_no_extension): + raise ValueError( + "Plugin name in plugman does not match the file name.") + result[kw.arg] = ast.literal_eval(kw.value) + if category: + update_plugin_json(result, category=category) + else: + update_plugman_json(result) + # raise ValueError("Variable plugman not found in the file or has unsupported format.") + + +if __name__ == "__main__": + plugins = sys.argv[1].split('\n') + debug_print(plugins) + extract_plugman(plugins) diff --git a/test/get_latest.py b/test/get_latest.py index 3dde5db..275cbbf 100644 --- a/test/get_latest.py +++ b/test/get_latest.py @@ -2,7 +2,7 @@ import json import sys -def get_latest_version(): +def get_latest_plugman_version() -> str: """Get latest version entry from index.json""" with open('index.json', 'r') as file: content = json.loads(file.read()) @@ -10,16 +10,28 @@ def get_latest_version(): return latest_version +def get_latest_plugin_version(plugin_name, json_path) -> str: + """Get latest version entry from json file for a specific plugin""" + with open(json_path, 'r') as file: + content = json.loads(file.read()) + latest_version = list(content["plugins"][plugin_name]["versions"].keys())[0] + return latest_version + + def get_latest_api(): """Get latest api entry from index.json""" with open('index.json', 'r') as file: content = json.loads(file.read()) - latest_api = content["versions"][get_latest_version()]["api_version"] + latest_api = content["versions"][get_latest_plugman_version()]["api_version"] return latest_api if __name__ == "__main__": if len(sys.argv) < 2: - print(f"Usage: python3 {__file__.split('/')[-1]} function") + print(f"Usage: python3 {__file__.split('/')[-1]} function [args...]") sys.exit(1) - print(globals()[sys.argv[1]]()) # used to call the fucntion passed as cli parameter + function_name = sys.argv[1] + function_args = sys.argv[2:] + print( + globals()[function_name](*function_args) + ) # used to call the function passed as cli parameter with additional arguments diff --git a/test/test_checks.py b/test/test_checks.py index 69a6a4e..c5bc6df 100644 --- a/test/test_checks.py +++ b/test/test_checks.py @@ -157,7 +157,7 @@ class BaseCategoryMetadataTestCases: if md5sum != version_metadata["md5sum"]: self.fail( - f"{plugin} checksum changed;\n" + f"{plugin} checksum changed for version {version_name};\n" f"{version_metadata['md5sum']} (mentioned in {self.category_metadata_file}) ->\n" f"{md5sum} (actual)" ) @@ -177,6 +177,7 @@ class BaseCategoryMetadataTestCases: if md5sum != latest_version_metadata["md5sum"]: self.fail( + f"Latest version {latest_version_name} of " f"{plugin} checksum changed;\n" f"{latest_version_metadata['md5sum']} (mentioned in {self.category_metadata_file}) ->\n" f"{md5sum} (actual)"