moving from "min_noctalia" to "plugin_api"
This commit is contained in:
@@ -25,7 +25,8 @@
|
||||
- [ ] Tested on Hyprland
|
||||
- [ ] Tested on Sway
|
||||
- [ ] 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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"])
|
||||
+ "]",
|
||||
|
||||
@@ -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 "<author>/<plugin>", 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):
|
||||
|
||||
Reference in New Issue
Block a user