diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f3f4e15..19215cc 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -25,7 +25,8 @@ - [ ] Tested on Hyprland - [ ] Tested on Sway - [ ] Tested on another compositor: -- **Noctalia version tested against:** +- **Noctalia version tested against:** +- **Plugin API level:** ## Screenshots / Videos @@ -39,7 +40,7 @@ [README template](https://github.com/noctalia-dev/community-plugins/blob/main/README_TEMPLATE.md), documents every entry id and dependency, and includes exact panel IPC commands and launcher prefixes where applicable. - [ ] I created `thumbnail.webp` with the [thumbnail generator](https://assets.noctalia.dev/plugins/thumbnail-generator.html). -- [ ] `version` follows semver and is bumped in this PR; `min_noctalia` is the version I tested against. +- [ ] `version` follows semver and is bumped in this PR; `plugin_api` is the oldest API level this plugin requires. - [ ] Every non-English translation in this PR uses a locale supported by Noctalia core, and I can read, write, and understand that language well enough to review and maintain it (no unreviewed machine/LLM translations). - [ ] I did not edit `catalog.toml`; CI generates it. diff --git a/.github/workflows/update-catalog.py b/.github/workflows/update-catalog.py index a7e5640..f81be4e 100644 --- a/.github/workflows/update-catalog.py +++ b/.github/workflows/update-catalog.py @@ -10,7 +10,7 @@ from pathlib import Path ROOT_DIR = Path(__file__).resolve().parents[2] CATALOG_PATH = ROOT_DIR / "catalog.toml" -REQUIRED_FIELDS = ("id", "name", "version", "author", "min_noctalia", "tags") +REQUIRED_FIELDS = ("id", "name", "version", "author", "plugin_api", "tags") OPTIONAL_STRING_FIELDS = ("license", "icon", "description") OPTIONAL_BOOL_FIELDS = ("deprecated",) @@ -24,6 +24,12 @@ def load_plugin_manifest(path: Path) -> dict: missing_fields = ", ".join(missing) raise ValueError(f"{path.relative_to(ROOT_DIR)} is missing: {missing_fields}") + plugin_api = manifest["plugin_api"] + if not isinstance(plugin_api, int) or isinstance(plugin_api, bool) or plugin_api <= 0: + raise ValueError( + f"{path.relative_to(ROOT_DIR)} has invalid plugin_api; expected a positive integer" + ) + if not isinstance(manifest["tags"], list) or not all( isinstance(tag, str) for tag in manifest["tags"] ): @@ -109,7 +115,7 @@ def render_catalog(plugins: list[dict]) -> str: lines.append(f"deprecated = {toml_bool(plugin['deprecated'])}") lines.extend( [ - f"min_noctalia = {toml_string(plugin['min_noctalia'])}", + f"plugin_api = {plugin['plugin_api']}", "tags = [" + ", ".join(toml_string(tag) for tag in plugin["tags"]) + "]", diff --git a/.github/workflows/validate-plugins.py b/.github/workflows/validate-plugins.py index c1cf05c..15b86b3 100644 --- a/.github/workflows/validate-plugins.py +++ b/.github/workflows/validate-plugins.py @@ -85,7 +85,6 @@ ROOT_STRING_FIELDS = ( "id", "name", "version", - "min_noctalia", "author", "license", "icon", @@ -112,6 +111,7 @@ PANEL_POSITIONS = { ROOT_FIELDS = set(ROOT_STRING_FIELDS) | set(ROOT_ARRAY_FIELDS) | set(ENTRY_TYPES) | { "setting", "deprecated", + "plugin_api", } BASE_ENTRY_FIELDS = {"id", "entry"} ENTRY_FIELDS = { @@ -521,6 +521,12 @@ class Validator: if "deprecated" in manifest and not isinstance(manifest["deprecated"], bool): self.add_error(manifest_path, "root field 'deprecated' must be a bool") + plugin_api = manifest.get("plugin_api") + if "plugin_api" not in manifest: + self.add_error(manifest_path, "missing required root field 'plugin_api'") + elif not is_int(plugin_api) or plugin_api <= 0: + self.add_error(manifest_path, "root field 'plugin_api' must be a positive integer") + # A plugin id is "/", and the part after the "/" is the directory # it lives in - so a folder name is taken once for the whole repo. folder = manifest_path.parent.name @@ -539,10 +545,9 @@ class Validator: if folder in RESERVED_NAMES: self.add_error(manifest_path, f"'{folder}' is a reserved name and cannot be a plugin directory") - for field in ("version", "min_noctalia"): - value = manifest.get(field) - if is_non_empty_string(value) and not SEMVER_RE.fullmatch(value): - self.add_error(manifest_path, f"root field '{field}' must use MAJOR.MINOR.PATCH") + version = manifest.get("version") + if is_non_empty_string(version) and not SEMVER_RE.fullmatch(version): + self.add_error(manifest_path, "root field 'version' must use MAJOR.MINOR.PATCH") def validate_entry_path(self, manifest_path: Path, context: str, plugin_dir: Path, value: Any) -> None: if not is_non_empty_string(value): diff --git a/README.md b/README.md index 28dd7ff..3080c21 100644 --- a/README.md +++ b/README.md @@ -147,8 +147,8 @@ Open a PR against `main`. CI validates your manifest, entry scripts, required fi - **One plugin per PR.** - The directory name matches the part of `id` after the `/` in `plugin.toml` **exactly**. - `version` is semver and gets bumped on every change to the plugin. -- `min_noctalia` is the Noctalia version you actually tested against. Users on older builds are then told the plugin - needs an upgrade instead of getting a broken install. +- `plugin_api` is the oldest Noctalia plugin API level the plugin requires. Use the current documented level for a new + plugin, and increase it only when the plugin adopts a capability from a newer API level. - `description` is concise catalog copy, limited to 120 characters. Put feature details in the plugin's README. - `license` is set in `plugin.toml`. You keep the copyright on your plugin; if it is not MIT, put a `LICENSE` file in your plugin directory. There is no repo-wide license covering contributed plugins. diff --git a/color_picker/plugin.toml b/color_picker/plugin.toml index bb95c00..713b2bc 100644 --- a/color_picker/plugin.toml +++ b/color_picker/plugin.toml @@ -4,7 +4,7 @@ name = "Color Picker" description = "Pick a color from your screen with hyprpicker." license = "MIT" version = "1.0.2" -min_noctalia = "5.0.0" +plugin_api = 3 icon = "palette" dependencies = ["hyprpicker"] tags = ["theming", "utility", "bar", "panel"] diff --git a/daily-wallpaper/plugin.toml b/daily-wallpaper/plugin.toml index 1373016..56ddde8 100644 --- a/daily-wallpaper/plugin.toml +++ b/daily-wallpaper/plugin.toml @@ -1,7 +1,7 @@ id = "nzlov/daily-wallpaper" name = "Daily Wallpaper" version = "1.0.0" -min_noctalia = "5.0.0" +plugin_api = 3 author = "nzlov" license = "MIT" dependencies = [] diff --git a/ideapad-conservation-mode/plugin.toml b/ideapad-conservation-mode/plugin.toml index e6c5505..cd99432 100644 --- a/ideapad-conservation-mode/plugin.toml +++ b/ideapad-conservation-mode/plugin.toml @@ -1,7 +1,7 @@ id = "lux/ideapad-conservation-mode" name = "IdeaPad Conservation Mode" version = "0.3.0" -min_noctalia = "5.0.0" +plugin_api = 3 author = "lux" license = "MIT" tags = ["hardware", "shortcut", "system"] diff --git a/iio_lock/plugin.toml b/iio_lock/plugin.toml index 7a15c5c..cc0cba7 100644 --- a/iio_lock/plugin.toml +++ b/iio_lock/plugin.toml @@ -1,7 +1,7 @@ id = "nikolaj-zwergius/iio_lock" name = "iio-lock" version = "1.0.0" -min_noctalia = "5.0.0" +plugin_api = 3 author = "nikolaj-zwergius" license = "MIT" dependencies = ["pgrep","pkill","iio-hyprland","iio-sway","hyprctl","swaymsg"] diff --git a/mangowm-keymode/plugin.toml b/mangowm-keymode/plugin.toml index 8b27d6d..499db6e 100644 --- a/mangowm-keymode/plugin.toml +++ b/mangowm-keymode/plugin.toml @@ -1,7 +1,7 @@ id = "gambled23/mangowm-keymode" name = "Mangowm Keymode" version = "1.0.1" -min_noctalia = "5.0.0" +plugin_api = 3 author = "gambled23" license = "MIT" dependencies = ["mmsg"] diff --git a/mini-docker/plugin.toml b/mini-docker/plugin.toml index 7655741..dfe9b5f 100644 --- a/mini-docker/plugin.toml +++ b/mini-docker/plugin.toml @@ -1,7 +1,7 @@ id = "8bury/mini-docker" name = "Mini Docker" version = "1.0.3" -min_noctalia = "5.0.0" +plugin_api = 3 author = "8bury" license = "MIT" icon = "brand-docker" diff --git a/nix-monitor/plugin.toml b/nix-monitor/plugin.toml index c4e840b..01b885b 100644 --- a/nix-monitor/plugin.toml +++ b/nix-monitor/plugin.toml @@ -1,7 +1,7 @@ id = "avivbintangaringga/nix-monitor" name = "Nix Monitor" version = "1.1.1" -min_noctalia = "5.0.0" +plugin_api = 3 icon = "package" author = "avivbintangaringga" description = "Nixpkgs update monitor" diff --git a/portctl/plugin.toml b/portctl/plugin.toml index 2bb517a..abaa635 100644 --- a/portctl/plugin.toml +++ b/portctl/plugin.toml @@ -3,7 +3,7 @@ id = "rxtsel/portctl" name = "Portctl" version = "0.2.0" -min_noctalia = "5.0.0" +plugin_api = 3 author = "Cristhian Melo" license = "MIT" icon = "plug" diff --git a/prismlauncher-instances/plugin.toml b/prismlauncher-instances/plugin.toml index 0395d42..75fa0b8 100644 --- a/prismlauncher-instances/plugin.toml +++ b/prismlauncher-instances/plugin.toml @@ -1,7 +1,7 @@ id = "radimous/prismlauncher-instances" name = "PrismLauncher Instances" version = "1.0.0" -min_noctalia = "5.0.0" +plugin_api = 3 author = "radimous" license = "MIT" dependencies = ["prismlauncher"] diff --git a/proton-pass/plugin.toml b/proton-pass/plugin.toml index 5449e96..bee1bf9 100644 --- a/proton-pass/plugin.toml +++ b/proton-pass/plugin.toml @@ -1,7 +1,7 @@ id = "lucasoe/proton-pass" name = "Proton Pass" version = "0.1.0" -min_noctalia = "5.0.0" +plugin_api = 3 author = "LucasOe" license = "MIT" icon = "lock" diff --git a/sharednd/plugin.toml b/sharednd/plugin.toml index 9d8f09d..02ff9e4 100644 --- a/sharednd/plugin.toml +++ b/sharednd/plugin.toml @@ -14,7 +14,7 @@ id = "whyoolw/sharednd" name = "ShareDND" version = "1.1.1" -min_noctalia = "5.0.0" +plugin_api = 3 author = "whyoolw" license = "MIT" dependencies = ["niri"] diff --git a/shelly/plugin.toml b/shelly/plugin.toml index c1b1aa6..f0cf9e8 100644 --- a/shelly/plugin.toml +++ b/shelly/plugin.toml @@ -2,7 +2,7 @@ id = "joshuaslate/shelly" name = "Shelly" icon = "package" version = "1.0.1" -min_noctalia = "5.0.0" +plugin_api = 3 license = "MIT" author = "joshuaslate" dependencies = ["shelly"] diff --git a/todo/plugin.toml b/todo/plugin.toml index cdff51f..f7b72b8 100644 --- a/todo/plugin.toml +++ b/todo/plugin.toml @@ -9,7 +9,7 @@ id = "nightwatch75/todo" name = "To Do" version = "0.0.7" -min_noctalia = "5.0.0" +plugin_api = 3 author = "nightwatch75" license = "MIT" dependencies = [] diff --git a/um5606_fan_state/plugin.toml b/um5606_fan_state/plugin.toml index 46ec27d..25e4fa6 100644 --- a/um5606_fan_state/plugin.toml +++ b/um5606_fan_state/plugin.toml @@ -1,7 +1,7 @@ id = "thatonecalculator/um5606_fan_state" name = "ASUS UM5606 Fan State" version = "1.0.6" -min_noctalia = "5.0.0" +plugin_api = 3 author = "ThatOneCalculator" license = "MIT" tags = ["hardware"] diff --git a/upbeat/plugin.toml b/upbeat/plugin.toml index 23c9c16..e487dcb 100644 --- a/upbeat/plugin.toml +++ b/upbeat/plugin.toml @@ -1,7 +1,7 @@ id = "neuro/upbeat" name = "Upbeat" version = "1.0.1" -min_noctalia = "5.0.0" +plugin_api = 3 author = "neuro" license = "MIT" dependencies = []