Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d0f5416624 |
@@ -1,25 +0,0 @@
|
||||
name: Verify Manager release install
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
verify-manager-install:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out release tag
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "22"
|
||||
- name: Clone and validate the declared public repository
|
||||
run: python tools/verify_manager_install.py --source .
|
||||
+8
-3
@@ -2,11 +2,16 @@
|
||||
|
||||
All notable changes to this project are documented here.
|
||||
|
||||
## 1.0.3 - 2026-08-26
|
||||
|
||||
- Route Registry publication through the Manager installation gate and keep
|
||||
the API key out of process arguments and environment variables.
|
||||
|
||||
## 1.0.2 - 2026-08-26
|
||||
|
||||
- Add a credential-free ComfyUI Manager clone gate and tag-triggered workflow
|
||||
so Registry releases fail when their declared public repository is missing,
|
||||
inaccessible, stale, or inconsistent with the release commit and version.
|
||||
- Add a credential-free ComfyUI Manager clone gate so Registry releases fail
|
||||
when their declared public repository is missing, inaccessible, stale, or
|
||||
inconsistent with the release commit and version.
|
||||
|
||||
## 1.0.1 - 2026-08-26
|
||||
|
||||
|
||||
@@ -57,8 +57,19 @@ python3 tools/verify_manager_install.py --source .
|
||||
The gate reads the public repository from `pyproject.toml`, disables ambient
|
||||
Git credentials, performs Manager's recursive clone into a clean
|
||||
`custom_nodes` directory, verifies the release commit and version tag, and
|
||||
compiles every shipped Python and JavaScript source from the clone. The Gitea
|
||||
tag workflow runs the same command before a release is considered installable.
|
||||
compiles every shipped Python and JavaScript source from the clone.
|
||||
|
||||
Registry publishing is supported only through the gated release command:
|
||||
|
||||
```bash
|
||||
python3 -m tools.publish_registry_release \
|
||||
--changelog "Describe this release"
|
||||
```
|
||||
|
||||
It runs the Manager installation gate and Registry validation before invoking
|
||||
publication. The API key is read interactively and sent to `comfy` over
|
||||
standard input; it is never placed in process arguments or environment
|
||||
variables. Direct `comfy node publish` calls bypass the required release gate.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
+4
-1
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "etk-ltxv-timeline-editor"
|
||||
version = "1.0.2"
|
||||
version = "1.0.3"
|
||||
description = "A visual timeline editor for LTXV image guides, prompts, strengths, and frame positions in ComfyUI."
|
||||
license = { file = "LICENSE" }
|
||||
requires-python = ">=3.10"
|
||||
@@ -20,3 +20,6 @@ Documentation = "https://git.hoppingmadgames.com/hmg-comfy/ComfyUI_ETK_LTXV_Time
|
||||
PublisherId = "hmg"
|
||||
DisplayName = "ETK LTXV Timeline Image Editor"
|
||||
requires-comfyui = ">=0.33.0"
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"tools/__init__.py" = ["N999"]
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from tools import publish_registry_release
|
||||
|
||||
|
||||
def test_publish_stops_before_registry_when_manager_gate_fails(monkeypatch, tmp_path):
|
||||
calls = []
|
||||
|
||||
def fail_gate(source):
|
||||
raise RuntimeError("public clone failed")
|
||||
|
||||
monkeypatch.setattr(publish_registry_release, "verify_manager_install", fail_gate)
|
||||
monkeypatch.setattr(
|
||||
publish_registry_release.subprocess,
|
||||
"run",
|
||||
lambda *args, **kwargs: calls.append((args, kwargs)),
|
||||
)
|
||||
|
||||
with pytest.raises(RuntimeError, match="public clone failed"):
|
||||
publish_registry_release.publish_release(
|
||||
tmp_path,
|
||||
comfy="comfy",
|
||||
token="private-token",
|
||||
changelog="release",
|
||||
)
|
||||
assert calls == []
|
||||
|
||||
|
||||
def test_publish_keeps_token_out_of_arguments_and_environment(monkeypatch, tmp_path):
|
||||
calls = []
|
||||
monkeypatch.setattr(
|
||||
publish_registry_release,
|
||||
"verify_manager_install",
|
||||
lambda source: ("1.0.3", "https://example.test/owner/repo", "abc123"),
|
||||
)
|
||||
|
||||
def record_run(command, **kwargs):
|
||||
calls.append((command, kwargs))
|
||||
|
||||
monkeypatch.setattr(publish_registry_release.subprocess, "run", record_run)
|
||||
publish_registry_release.publish_release(
|
||||
Path(tmp_path),
|
||||
comfy="comfy",
|
||||
token="private-token",
|
||||
changelog="release notes",
|
||||
)
|
||||
|
||||
assert [command for command, _ in calls] == [
|
||||
["comfy", "node", "validate"],
|
||||
["comfy", "node", "publish"],
|
||||
]
|
||||
publish_kwargs = calls[1][1]
|
||||
assert publish_kwargs["input"] == "private-token\n"
|
||||
assert "private-token" not in repr(calls[1][0])
|
||||
assert "private-token" not in repr(publish_kwargs["env"])
|
||||
assert publish_kwargs["env"]["COMFY_NODE_CHANGELOG"] == "release notes"
|
||||
@@ -0,0 +1 @@
|
||||
"""Release tooling for the standalone timeline node pack."""
|
||||
Executable
+68
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Publish only after the public Manager installation path is verified."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import getpass
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from tools.verify_manager_install import verify_manager_install
|
||||
|
||||
|
||||
def publish_release(
|
||||
source: Path,
|
||||
*,
|
||||
comfy: str,
|
||||
token: str,
|
||||
changelog: str,
|
||||
) -> None:
|
||||
verify_manager_install(source)
|
||||
subprocess.run([comfy, "node", "validate"], cwd=source, check=True)
|
||||
env = dict(os.environ)
|
||||
env["COMFY_NODE_CHANGELOG"] = changelog
|
||||
subprocess.run(
|
||||
[comfy, "node", "publish"],
|
||||
cwd=source,
|
||||
env=env,
|
||||
input=f"{token}\n",
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--source",
|
||||
type=Path,
|
||||
default=Path(__file__).resolve().parents[1],
|
||||
help="tagged release repository",
|
||||
)
|
||||
parser.add_argument("--changelog", required=True)
|
||||
parser.add_argument("--comfy", default=shutil.which("comfy") or "comfy")
|
||||
args = parser.parse_args()
|
||||
token = getpass.getpass("Comfy Registry API key: ").strip()
|
||||
if not token:
|
||||
print("REGISTRY RELEASE FAILED: API key is empty", file=sys.stderr)
|
||||
return 1
|
||||
try:
|
||||
publish_release(
|
||||
args.source.resolve(),
|
||||
comfy=args.comfy,
|
||||
token=token,
|
||||
changelog=args.changelog,
|
||||
)
|
||||
except (OSError, subprocess.CalledProcessError, RuntimeError) as exc:
|
||||
print(f"REGISTRY RELEASE FAILED: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
print("REGISTRY RELEASE PASSED THE MANAGER INSTALL GATE AND WAS UPLOADED")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user