moving from "min_noctalia" to "plugin_api"
This commit is contained in:
@@ -25,7 +25,8 @@
|
|||||||
- [ ] Tested on Hyprland
|
- [ ] Tested on Hyprland
|
||||||
- [ ] Tested on Sway
|
- [ ] Tested on Sway
|
||||||
- [ ] Tested on another compositor:
|
- [ ] Tested on another compositor:
|
||||||
- **Noctalia version tested against:** <!-- must be >= min_noctalia in plugin.toml -->
|
- **Noctalia version tested against:**
|
||||||
|
- **Plugin API level:** <!-- must match plugin_api in plugin.toml -->
|
||||||
|
|
||||||
## Screenshots / Videos
|
## Screenshots / Videos
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@
|
|||||||
[README template](https://github.com/noctalia-dev/community-plugins/blob/main/README_TEMPLATE.md), documents
|
[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.
|
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).
|
- [ ] 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
|
- [ ] 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).
|
understand that language well enough to review and maintain it (no unreviewed machine/LLM translations).
|
||||||
- [ ] I did not edit `catalog.toml`; CI generates it.
|
- [ ] I did not edit `catalog.toml`; CI generates it.
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
ROOT_DIR = Path(__file__).resolve().parents[2]
|
ROOT_DIR = Path(__file__).resolve().parents[2]
|
||||||
CATALOG_PATH = ROOT_DIR / "catalog.toml"
|
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_STRING_FIELDS = ("license", "icon", "description")
|
||||||
OPTIONAL_BOOL_FIELDS = ("deprecated",)
|
OPTIONAL_BOOL_FIELDS = ("deprecated",)
|
||||||
|
|
||||||
@@ -24,6 +24,12 @@ def load_plugin_manifest(path: Path) -> dict:
|
|||||||
missing_fields = ", ".join(missing)
|
missing_fields = ", ".join(missing)
|
||||||
raise ValueError(f"{path.relative_to(ROOT_DIR)} is missing: {missing_fields}")
|
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(
|
if not isinstance(manifest["tags"], list) or not all(
|
||||||
isinstance(tag, str) for tag in manifest["tags"]
|
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.append(f"deprecated = {toml_bool(plugin['deprecated'])}")
|
||||||
lines.extend(
|
lines.extend(
|
||||||
[
|
[
|
||||||
f"min_noctalia = {toml_string(plugin['min_noctalia'])}",
|
f"plugin_api = {plugin['plugin_api']}",
|
||||||
"tags = ["
|
"tags = ["
|
||||||
+ ", ".join(toml_string(tag) for tag in plugin["tags"])
|
+ ", ".join(toml_string(tag) for tag in plugin["tags"])
|
||||||
+ "]",
|
+ "]",
|
||||||
|
|||||||
@@ -85,7 +85,6 @@ ROOT_STRING_FIELDS = (
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"version",
|
"version",
|
||||||
"min_noctalia",
|
|
||||||
"author",
|
"author",
|
||||||
"license",
|
"license",
|
||||||
"icon",
|
"icon",
|
||||||
@@ -112,6 +111,7 @@ PANEL_POSITIONS = {
|
|||||||
ROOT_FIELDS = set(ROOT_STRING_FIELDS) | set(ROOT_ARRAY_FIELDS) | set(ENTRY_TYPES) | {
|
ROOT_FIELDS = set(ROOT_STRING_FIELDS) | set(ROOT_ARRAY_FIELDS) | set(ENTRY_TYPES) | {
|
||||||
"setting",
|
"setting",
|
||||||
"deprecated",
|
"deprecated",
|
||||||
|
"plugin_api",
|
||||||
}
|
}
|
||||||
BASE_ENTRY_FIELDS = {"id", "entry"}
|
BASE_ENTRY_FIELDS = {"id", "entry"}
|
||||||
ENTRY_FIELDS = {
|
ENTRY_FIELDS = {
|
||||||
@@ -521,6 +521,12 @@ class Validator:
|
|||||||
if "deprecated" in manifest and not isinstance(manifest["deprecated"], bool):
|
if "deprecated" in manifest and not isinstance(manifest["deprecated"], bool):
|
||||||
self.add_error(manifest_path, "root field 'deprecated' must be a 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 "<author>/<plugin>", and the part after the "/" is the directory
|
# A plugin id is "<author>/<plugin>", and the part after the "/" is the directory
|
||||||
# it lives in - so a folder name is taken once for the whole repo.
|
# it lives in - so a folder name is taken once for the whole repo.
|
||||||
folder = manifest_path.parent.name
|
folder = manifest_path.parent.name
|
||||||
@@ -539,10 +545,9 @@ class Validator:
|
|||||||
if folder in RESERVED_NAMES:
|
if folder in RESERVED_NAMES:
|
||||||
self.add_error(manifest_path, f"'{folder}' is a reserved name and cannot be a plugin directory")
|
self.add_error(manifest_path, f"'{folder}' is a reserved name and cannot be a plugin directory")
|
||||||
|
|
||||||
for field in ("version", "min_noctalia"):
|
version = manifest.get("version")
|
||||||
value = manifest.get(field)
|
if is_non_empty_string(version) and not SEMVER_RE.fullmatch(version):
|
||||||
if is_non_empty_string(value) and not SEMVER_RE.fullmatch(value):
|
self.add_error(manifest_path, "root field 'version' must use MAJOR.MINOR.PATCH")
|
||||||
self.add_error(manifest_path, f"root field '{field}' must use MAJOR.MINOR.PATCH")
|
|
||||||
|
|
||||||
def validate_entry_path(self, manifest_path: Path, context: str, plugin_dir: Path, value: Any) -> None:
|
def validate_entry_path(self, manifest_path: Path, context: str, plugin_dir: Path, value: Any) -> None:
|
||||||
if not is_non_empty_string(value):
|
if not is_non_empty_string(value):
|
||||||
|
|||||||
@@ -147,8 +147,8 @@ Open a PR against `main`. CI validates your manifest, entry scripts, required fi
|
|||||||
- **One plugin per PR.**
|
- **One plugin per PR.**
|
||||||
- The directory name matches the part of `id` after the `/` in `plugin.toml` **exactly**.
|
- 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.
|
- `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
|
- `plugin_api` is the oldest Noctalia plugin API level the plugin requires. Use the current documented level for a new
|
||||||
needs an upgrade instead of getting a broken install.
|
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.
|
- `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
|
- `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.
|
your plugin directory. There is no repo-wide license covering contributed plugins.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ name = "Color Picker"
|
|||||||
description = "Pick a color from your screen with hyprpicker."
|
description = "Pick a color from your screen with hyprpicker."
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
min_noctalia = "5.0.0"
|
plugin_api = 3
|
||||||
icon = "palette"
|
icon = "palette"
|
||||||
dependencies = ["hyprpicker"]
|
dependencies = ["hyprpicker"]
|
||||||
tags = ["theming", "utility", "bar", "panel"]
|
tags = ["theming", "utility", "bar", "panel"]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
id = "nzlov/daily-wallpaper"
|
id = "nzlov/daily-wallpaper"
|
||||||
name = "Daily Wallpaper"
|
name = "Daily Wallpaper"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
min_noctalia = "5.0.0"
|
plugin_api = 3
|
||||||
author = "nzlov"
|
author = "nzlov"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
dependencies = []
|
dependencies = []
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
id = "lux/ideapad-conservation-mode"
|
id = "lux/ideapad-conservation-mode"
|
||||||
name = "IdeaPad Conservation Mode"
|
name = "IdeaPad Conservation Mode"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
min_noctalia = "5.0.0"
|
plugin_api = 3
|
||||||
author = "lux"
|
author = "lux"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
tags = ["hardware", "shortcut", "system"]
|
tags = ["hardware", "shortcut", "system"]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
id = "nikolaj-zwergius/iio_lock"
|
id = "nikolaj-zwergius/iio_lock"
|
||||||
name = "iio-lock"
|
name = "iio-lock"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
min_noctalia = "5.0.0"
|
plugin_api = 3
|
||||||
author = "nikolaj-zwergius"
|
author = "nikolaj-zwergius"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
dependencies = ["pgrep","pkill","iio-hyprland","iio-sway","hyprctl","swaymsg"]
|
dependencies = ["pgrep","pkill","iio-hyprland","iio-sway","hyprctl","swaymsg"]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
id = "gambled23/mangowm-keymode"
|
id = "gambled23/mangowm-keymode"
|
||||||
name = "Mangowm Keymode"
|
name = "Mangowm Keymode"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
min_noctalia = "5.0.0"
|
plugin_api = 3
|
||||||
author = "gambled23"
|
author = "gambled23"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
dependencies = ["mmsg"]
|
dependencies = ["mmsg"]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
id = "8bury/mini-docker"
|
id = "8bury/mini-docker"
|
||||||
name = "Mini Docker"
|
name = "Mini Docker"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
min_noctalia = "5.0.0"
|
plugin_api = 3
|
||||||
author = "8bury"
|
author = "8bury"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
icon = "brand-docker"
|
icon = "brand-docker"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
id = "avivbintangaringga/nix-monitor"
|
id = "avivbintangaringga/nix-monitor"
|
||||||
name = "Nix Monitor"
|
name = "Nix Monitor"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
min_noctalia = "5.0.0"
|
plugin_api = 3
|
||||||
icon = "package"
|
icon = "package"
|
||||||
author = "avivbintangaringga"
|
author = "avivbintangaringga"
|
||||||
description = "Nixpkgs update monitor"
|
description = "Nixpkgs update monitor"
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
id = "rxtsel/portctl"
|
id = "rxtsel/portctl"
|
||||||
name = "Portctl"
|
name = "Portctl"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
min_noctalia = "5.0.0"
|
plugin_api = 3
|
||||||
author = "Cristhian Melo"
|
author = "Cristhian Melo"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
icon = "plug"
|
icon = "plug"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
id = "radimous/prismlauncher-instances"
|
id = "radimous/prismlauncher-instances"
|
||||||
name = "PrismLauncher Instances"
|
name = "PrismLauncher Instances"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
min_noctalia = "5.0.0"
|
plugin_api = 3
|
||||||
author = "radimous"
|
author = "radimous"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
dependencies = ["prismlauncher"]
|
dependencies = ["prismlauncher"]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
id = "lucasoe/proton-pass"
|
id = "lucasoe/proton-pass"
|
||||||
name = "Proton Pass"
|
name = "Proton Pass"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
min_noctalia = "5.0.0"
|
plugin_api = 3
|
||||||
author = "LucasOe"
|
author = "LucasOe"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
icon = "lock"
|
icon = "lock"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
id = "whyoolw/sharednd"
|
id = "whyoolw/sharednd"
|
||||||
name = "ShareDND"
|
name = "ShareDND"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
min_noctalia = "5.0.0"
|
plugin_api = 3
|
||||||
author = "whyoolw"
|
author = "whyoolw"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
dependencies = ["niri"]
|
dependencies = ["niri"]
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ id = "joshuaslate/shelly"
|
|||||||
name = "Shelly"
|
name = "Shelly"
|
||||||
icon = "package"
|
icon = "package"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
min_noctalia = "5.0.0"
|
plugin_api = 3
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
author = "joshuaslate"
|
author = "joshuaslate"
|
||||||
dependencies = ["shelly"]
|
dependencies = ["shelly"]
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@
|
|||||||
id = "nightwatch75/todo"
|
id = "nightwatch75/todo"
|
||||||
name = "To Do"
|
name = "To Do"
|
||||||
version = "0.0.7"
|
version = "0.0.7"
|
||||||
min_noctalia = "5.0.0"
|
plugin_api = 3
|
||||||
author = "nightwatch75"
|
author = "nightwatch75"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
dependencies = []
|
dependencies = []
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
id = "thatonecalculator/um5606_fan_state"
|
id = "thatonecalculator/um5606_fan_state"
|
||||||
name = "ASUS UM5606 Fan State"
|
name = "ASUS UM5606 Fan State"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
min_noctalia = "5.0.0"
|
plugin_api = 3
|
||||||
author = "ThatOneCalculator"
|
author = "ThatOneCalculator"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
tags = ["hardware"]
|
tags = ["hardware"]
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
id = "neuro/upbeat"
|
id = "neuro/upbeat"
|
||||||
name = "Upbeat"
|
name = "Upbeat"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
min_noctalia = "5.0.0"
|
plugin_api = 3
|
||||||
author = "neuro"
|
author = "neuro"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
dependencies = []
|
dependencies = []
|
||||||
|
|||||||
Reference in New Issue
Block a user