From 78eb4f6770497d5dcdd165c3b025cfc21f3a5cb8 Mon Sep 17 00:00:00 2001 From: Vito Sansevero Date: Sat, 7 Nov 2026 04:28:27 -0800 Subject: [PATCH] chore(release): 1.4.0 with a Registry package that has its nodes - Anchor every .comfyignore rule to the root, as in ComfyUI-PromptManager. The unanchored "tools/" also matched kikotools/tools/, so the Registry packages for 1.2.0 to 1.3.1 shipped without the tool modules - Leave docs/ and examples/ out of the package too; they are only read on GitHub (8.5 MB down to about 0.26 MB) - Add tests/unit/test_package_contents.py, which holds the rules to what ComfyUI needs at run time, checked with comfy-cli's own matcher as well - Ship the Local Image Loader folder output and the Model Downloader server-side tokens already on main - Bump pyproject.toml to 1.4.0 and date the changelog section --- .comfyignore | 58 ++++++++------- CHANGELOG.md | 12 ++- pyproject.toml | 2 +- tests/unit/test_package_contents.py | 110 ++++++++++++++++++++++++++++ 4 files changed, 155 insertions(+), 27 deletions(-) create mode 100644 tests/unit/test_package_contents.py diff --git a/.comfyignore b/.comfyignore index 5ed727d..ae2a55e 100644 --- a/.comfyignore +++ b/.comfyignore @@ -1,29 +1,37 @@ -# Files excluded from the Comfy Registry archive (gitignore syntax). -# Everything here is development-only; the published node needs -# __init__.py, kikotools/, web/, examples/, README, LICENSE, pyproject.toml. +# Left out of the Comfy Registry package (comfy node publish). Git clones still +# have everything. tests/unit/test_package_contents.py holds these rules to what +# ComfyUI needs at run time; keep each one anchored to the root with a leading /. +# An unanchored "tools/" also matched kikotools/tools/ and shipped 1.2.0 to 1.3.1 +# without their nodes. -# Test suite and tooling -tests/ -scripts/ -.github/ -Makefile -pytest.ini -mypy.ini -.flake8 -.pre-commit-config.yaml -.secrets.baseline -requirements-dev.txt +# Development folders +/tests/ +/scripts/ +/tools/ +/.github/ +/.ci-comfyui/ +/coverage/ -# Reference / scratch code not imported by the node -example.py +# Docs, screenshots and example workflows used only on GitHub. ComfyUI only reads +# example workflows from *.json directly inside examples/, and there are none. +/docs/ +/examples/ + +# Development files +/Makefile +/pytest.ini +/mypy.ini +/.flake8 +/.pre-commit-config.yaml +/.secrets.baseline +/requirements-dev.txt +/example.py +/TESTING.md +/.gitignore +/.gitattributes # Agent and contributor docs -CLAUDE.md -CONTRIBUTING.md -CODE_OF_CONDUCT.md - -tools/ -.ci-comfyui/ -coverage/ -TESTING.md -AGENTS.md +/CLAUDE.md +/AGENTS.md +/CONTRIBUTING.md +/CODE_OF_CONDUCT.md diff --git a/CHANGELOG.md b/CHANGELOG.md index ebc3a52..a3c9c7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,16 @@ # Changelog -## Unreleased +## 1.4.0 + +### Packaging + +- The Comfy Registry package has its nodes again. An unanchored `tools/` rule in + `.comfyignore` also matched `kikotools/tools/`, so the 1.2.0 to 1.3.1 packages + shipped without the tool modules; installs from git were not affected. Every + rule is now anchored to the root, and `tests/unit/test_package_contents.py` + holds them to what ComfyUI needs. +- `docs/` and `examples/` are left out of the package as well; they are only + read on GitHub. The download goes from about 8.5 MB to about 0.26 MB. ### Local Image Loader diff --git a/pyproject.toml b/pyproject.toml index 79f96c9..f758ff1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta" [project] name = "kikotools" description = "Simple tools for ComfyUI" -version = "1.3.1" +version = "1.4.0" license = {text = "MIT"} dependencies = [] diff --git a/tests/unit/test_package_contents.py b/tests/unit/test_package_contents.py new file mode 100644 index 0000000..aa404a5 --- /dev/null +++ b/tests/unit/test_package_contents.py @@ -0,0 +1,110 @@ +"""What the Registry package leaves out. + +``comfy node publish`` zips the tracked files minus ``.comfyignore``. These checks +hold the two ways that can go wrong: a development folder creeping back into the +download, or a rule that drops something ComfyUI needs at run time. An unanchored +``tools/`` rule did the second for 1.2.0 to 1.3.1: it also matched kikotools/tools/, +so those packages shipped without their nodes. +""" + +import ast +import fnmatch +from pathlib import Path + +import pytest + +ROOT = Path(__file__).resolve().parents[2] +RUNTIME_DIRS = ("kikotools", "web") +DEVELOPMENT = ( + "tests/unit/test_package_contents.py", + "scripts/run_mypy.sh", + "tools/testing/package.json", + "docs/ui-migration.md", + "examples/workflows/display_text_example.json", + ".github/workflows/publish.yml", + "Makefile", + "requirements-dev.txt", + "CLAUDE.md", + "AGENTS.md", +) +KEPT = ( + "__init__.py", + "pyproject.toml", + "requirements.txt", + "LICENSE", + "README.md", + "CHANGELOG.md", + "kikotools/tools/model_downloader/node.py", + "web/kiko_local_image_loader.js", +) + + +def patterns(): + lines = (ROOT / ".comfyignore").read_text(encoding="utf-8").splitlines() + return [line.strip() for line in lines if line.strip() and line[0] != "#"] + + +def ignored(path): + """The rules this file allows: ``/folder/`` or a root file, both from the root.""" + for pattern in patterns(): + if pattern.endswith("/"): + if path.startswith(pattern.lstrip("/")): + return True + elif fnmatch.fnmatchcase(path, pattern.lstrip("/")): + return True + return False + + +def test_every_rule_is_anchored_to_the_root(): + # Unanchored, "tools/" also drops kikotools/tools/ and "tests/" any nested tests/. + for pattern in patterns(): + assert pattern.startswith("/"), pattern + assert "!" not in pattern, pattern + + +@pytest.mark.parametrize("path", DEVELOPMENT) +def test_development_files_are_left_out(path): + assert ignored(path) + + +@pytest.mark.parametrize("path", KEPT) +def test_package_files_stay(path): + assert not ignored(path) + + +def test_runtime_folders_ship_whole(): + for folder in RUNTIME_DIRS: + for file in (ROOT / folder).rglob("*"): + if file.is_file() and "__pycache__" not in file.parts: + relative = file.relative_to(ROOT).as_posix() + assert not ignored(relative), relative + + +def test_registry_matcher_agrees(): + """comfy-cli matches with pathspec's gitwildmatch; check the rules with it too.""" + pathspec = pytest.importorskip("pathspec") + spec = pathspec.PathSpec.from_lines("gitwildmatch", patterns()) + for folder in RUNTIME_DIRS: + for file in (ROOT / folder).rglob("*.py"): + assert not spec.match_file(file.relative_to(ROOT).as_posix()), file + for path in DEVELOPMENT: + assert spec.match_file(path), path + + +def test_runtime_code_imports_nothing_left_out(): + sources = [ROOT / "__init__.py", *(ROOT / "kikotools").rglob("*.py")] + for source in sources: + tree = ast.parse(source.read_text(encoding="utf-8")) + for node in ast.walk(tree): + names = [] + if isinstance(node, ast.Import): + names = [alias.name for alias in node.names] + elif isinstance(node, ast.ImportFrom) and not node.level: + names = [node.module or ""] + for name in names: + assert name.split(".")[0] not in ( + "tests", + "scripts", + "tools", + "examples", + ), source