Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package
python-comfyui-workflow-templates-core for openSUSE:Factory checked in at
2026-10-15 12:25:38
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-comfyui-workflow-templates-core
(Old)
and
/work/SRC/openSUSE:Factory/.python-comfyui-workflow-templates-core.new.3698736
(New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-comfyui-workflow-templates-core"
Thu Oct 15 12:25:38 2026 rev:18 rq:1384887 version:0.3.373
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-comfyui-workflow-templates-core/python-comfyui-workflow-templates-core.changes
2026-10-08 13:28:27.417476628 +0200
+++
/work/SRC/openSUSE:Factory/.python-comfyui-workflow-templates-core.new.3698736/python-comfyui-workflow-templates-core.changes
2026-10-15 12:25:45.597177493 +0200
@@ -1,0 +2,19 @@
+Thu Oct 15 04:52:59 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Update to version 0.3.373: the manifest now lists 618
+ templates (was 614)
+ * New, all owned by the media-assets-02 bundle: FishAudio Drama
+ 3 dialogue and directed, Higgsfield motion transfer, and Qwen
+ Image 2.1 Turbo image edit plus text to image
+ * Drop the retired Luma Ray 2 image-to-video and text-to-video
+ entries from the media-api bundle
+ * The bump crosses 0.3.372, which added the six entries and
+ dropped the Luma pair; 0.3.373 only fixes the Qwen multiangle
+ entry id. Described together here as only 0.3.373 is submitted
+- No code or dependency change: loader.py is byte-identical,
+ the sdist still declares no runtime requirements, and the
+ json >= 0.1.102 and media-assets-02 >= 0.1.9 Requires floors
+ are still satisfied (the six new entries previews need
+ media-assets-02 0.1.14, not packaged yet)
+
+-------------------------------------------------------------------
Old:
----
comfyui_workflow_templates_core-0.3.369.tar.gz
New:
----
comfyui_workflow_templates_core-0.3.373.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-comfyui-workflow-templates-core.spec ++++++
--- /var/tmp/diff_new_pack.oNxmaT/_old 2026-10-15 12:25:46.375210049 +0200
+++ /var/tmp/diff_new_pack.oNxmaT/_new 2026-10-15 12:25:46.377210133 +0200
@@ -16,7 +16,7 @@
#
Name: python-comfyui-workflow-templates-core
-Version: 0.3.369
+Version: 0.3.373
Release: 0
Summary: Core helpers for ComfyUI workflow templates
# Legal-Review-Notice: sdist ships no LICENSE file; upstream
++++++ comfyui_workflow_templates_core-0.3.369.tar.gz ->
comfyui_workflow_templates_core-0.3.373.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/comfyui_workflow_templates_core-0.3.369/PKG-INFO
new/comfyui_workflow_templates_core-0.3.373/PKG-INFO
--- old/comfyui_workflow_templates_core-0.3.369/PKG-INFO 2026-10-07
18:01:12.141493300 +0200
+++ new/comfyui_workflow_templates_core-0.3.373/PKG-INFO 2026-10-13
19:13:47.441332800 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: comfyui-workflow-templates-core
-Version: 0.3.369
+Version: 0.3.373
Summary: Core helpers for ComfyUI workflow templates
License-Expression: MIT
Requires-Python: >=3.9
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/comfyui_workflow_templates_core-0.3.369/pyproject.toml
new/comfyui_workflow_templates_core-0.3.373/pyproject.toml
--- old/comfyui_workflow_templates_core-0.3.369/pyproject.toml 2026-10-07
18:00:41.900971000 +0200
+++ new/comfyui_workflow_templates_core-0.3.373/pyproject.toml 2026-10-13
19:13:18.663047800 +0200
@@ -4,7 +4,7 @@
[project]
name = "comfyui-workflow-templates-core"
-version = "0.3.369"
+version = "0.3.373"
description = "Core helpers for ComfyUI workflow templates"
readme = {text = "Core helpers for ComfyUI workflow templates.", content-type
= "text/plain"}
requires-python = ">=3.9"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/comfyui_workflow_templates_core-0.3.369/src/comfyui_workflow_templates_core/manifest.json
new/comfyui_workflow_templates_core-0.3.373/src/comfyui_workflow_templates_core/manifest.json
---
old/comfyui_workflow_templates_core-0.3.369/src/comfyui_workflow_templates_core/manifest.json
2026-10-07 18:01:09.568760000 +0200
+++
new/comfyui_workflow_templates_core-0.3.373/src/comfyui_workflow_templates_core/manifest.json
2026-10-13 19:13:44.954892400 +0200
@@ -598,24 +598,6 @@
}
},
{
- "id": "api_luma_i2v",
- "bundle": "media-api",
- "version": "0.0.0",
- "assets": [
- {
- "filename": "api_luma_i2v.json",
- "sha256":
"0c660c05d325a7fb6fbefcc106ceedac79ac59796c26949ae174c331290be8dd"
- },
- {
- "filename": "api_luma_i2v-1.webp",
- "sha256":
"e4d981fa4e3f5359375de871b60d1e81fa46e51531add655b66ef4b8f84503fa"
- }
- ],
- "cdn": {
- "path": "media-api/api_luma_i2v/"
- }
- },
- {
"id": "api_luma_photon_i2i",
"bundle": "media-api",
"version": "0.0.0",
@@ -660,24 +642,6 @@
}
},
{
- "id": "api_luma_t2v",
- "bundle": "media-api",
- "version": "0.0.0",
- "assets": [
- {
- "filename": "api_luma_t2v.json",
- "sha256":
"681de365515c93102b6abced05e86de093193162e2a83a3bdde327cbe78e8808"
- },
- {
- "filename": "api_luma_t2v-1.webp",
- "sha256":
"b7a70af0a918c1f3ea9fb4c8216363fa2bf0f91b66509f2e2d27dbfb53f2ddbd"
- }
- ],
- "cdn": {
- "path": "media-api/api_luma_t2v/"
- }
- },
- {
"id": "api_meshy_image_to_model",
"bundle": "media-api",
"version": "0.0.0",
@@ -2476,7 +2440,7 @@
"assets": [
{
"filename": "api_quiver_image_to_svg.json",
- "sha256":
"516d6219b353f82071832c5963e218c886119ee1bc624f16784944b1e56909fc"
+ "sha256":
"d02146d03cbddb471bf4cfb37291e327a49363ab3d25e130e7172dae44aa516e"
},
{
"filename": "api_quiver_image_to_svg-1.webp",
@@ -2494,7 +2458,7 @@
"assets": [
{
"filename": "api_quiver_text_to_svg.json",
- "sha256":
"3e02c8c2c3f1436a396f1acdd069b5efd834e283618bd7eb3a7ce041ec75d2cc"
+ "sha256":
"4c2bd3bee35502fb35d93053993867038e4c2495200f3dfe82ab67712223e595"
},
{
"filename": "api_quiver_text_to_svg-1.webp",
@@ -5924,7 +5888,7 @@
"assets": [
{
"filename": "api_tripo3_1_multiview_to_model.json",
- "sha256":
"057605bd9ae9a91f768f93319df5d3f636c341b3517067714f3e61a02737824a"
+ "sha256":
"95ed72c82cb3c5be64e751c3debacbf350f856cdbde250520f7af6110508e25c"
},
{
"filename": "api_tripo3_1_multiview_to_model-1.webp",
@@ -5942,7 +5906,7 @@
"assets": [
{
"filename": "api_tripo3_1_text_to_model.json",
- "sha256":
"bd71b7e1e28e42ca0c88f3493d30fc5d9b1171aa3e99ee070696d34336d7ebc0"
+ "sha256":
"72428f7c10598ef89db328c77a74f8b7a8c65c845e3ca797d508418089291e5c"
},
{
"filename": "api_tripo3_1_text_to_model-1.webp",
@@ -6190,7 +6154,7 @@
"assets": [
{
"filename": "index.json",
- "sha256":
"34211034f887adffb17ffdbcd31ec0aab854ed8b01bcaf75634a09421a437e1e"
+ "sha256":
"8b584653f46e5c6efff6ef6728397c0a978a1db6176f0bd9cc03838847f87d78"
}
],
"cdn": {
@@ -6204,7 +6168,7 @@
"assets": [
{
"filename": "index.ar.json",
- "sha256":
"ab610746cb6c73c8e79a81c4b07873901fd062639be9265f4f6433e65ee1f038"
+ "sha256":
"619e811e1b5aff02af63a0452a3779baa9f94740708229150efa53c92cea413b"
}
],
"cdn": {
@@ -6218,7 +6182,7 @@
"assets": [
{
"filename": "index.es.json",
- "sha256":
"e186fad112ebb1a886bec7e6e8ca6af3f4aee9c73d9f04834e131dd8f3869ccf"
+ "sha256":
"da76405afbe29176dbad44c06be27f330b0ba416c77f5b2f3598c07d6114ee89"
}
],
"cdn": {
@@ -6232,7 +6196,7 @@
"assets": [
{
"filename": "index.fa.json",
- "sha256":
"f4c33d0f2e4979329a009678fbc2b81c89dec63a56cbfc009a012428e4bdd03d"
+ "sha256":
"29ff743109de0ac6df9e431ad05e7364f376d746a288a7a8406ae65b99c03529"
}
],
"cdn": {
@@ -6246,7 +6210,7 @@
"assets": [
{
"filename": "index.fr.json",
- "sha256":
"4d556d971e8915b80ad5112af0f0ca5ca53860a2f7f25fdd726e0c9517ec7b9e"
+ "sha256":
"8335e39b4f2c98e6f9c83e385d4eedd09d8225ae772063387efc37433402bf56"
}
],
"cdn": {
@@ -6260,7 +6224,7 @@
"assets": [
{
"filename": "index.ja.json",
- "sha256":
"47f5b26870c7d1f3df91b28ab5493806084f309a4b358f5ed8ab8eaaba7b3a00"
+ "sha256":
"148acd41b740fa08f1c6cc8eaaf911d1ddebb489864d8c84df5fe7ffe9fa0c6e"
}
],
"cdn": {
@@ -6274,7 +6238,7 @@
"assets": [
{
"filename": "index.ko.json",
- "sha256":
"a35d8c9297a04ed843c7ca8ddc4723791b4b2a5b4cbc9e821bdfac915f7d2ea8"
+ "sha256":
"43e7dce67e5a03fc8a66ec1f20f2769bd2a15f8616f7df0caf76558ed6b04a0a"
}
],
"cdn": {
@@ -6288,7 +6252,7 @@
"assets": [
{
"filename": "index.mcp.json",
- "sha256":
"32dde137d4f291eda117549d8a799b451c3781d34beb8f592b01a81c969a8e36"
+ "sha256":
"069abf7ee27c418d66eb47f9dc25b0a3d6a81648512e6d1517b0f1eb84fcbe0e"
}
],
"cdn": {
@@ -6302,7 +6266,7 @@
"assets": [
{
"filename": "index.pt-BR.json",
- "sha256":
"b778efb324be90015174d2fdcdc7bedc1ab944e95e94537686974923a1534e05"
+ "sha256":
"4fedf5149ed32c4a2729e820ea3220f352632a815f5d956865c245b872f041d1"
}
],
"cdn": {
@@ -6316,7 +6280,7 @@
"assets": [
{
"filename": "index.ru.json",
- "sha256":
"cc129b169fd1ea25dbe7819aaf0a083476508b7dbac7175567247a81580d4525"
+ "sha256":
"e3be40b1113057bc3e9ef9d64aac2182893b23d3af0097204c8132b832a3b48b"
}
],
"cdn": {
@@ -6344,7 +6308,7 @@
"assets": [
{
"filename": "index.tr.json",
- "sha256":
"069b04940eaa7b6e4f96ed10fe320af2aa48e86460398d8b10867c872c7957cc"
+ "sha256":
"67e44cc6e1208a2faf323a4d57f1ff0ca75fd1799c8c9507d8827c0affa2de61"
}
],
"cdn": {
@@ -6358,7 +6322,7 @@
"assets": [
{
"filename": "index.zh.json",
- "sha256":
"c0d66f68a3a66c8432cb8ff584773507eca351a1e858051b585613d521294e3a"
+ "sha256":
"aef34bb284de6753627d5fbae77ecd26f530f10a949180a3378b1675ae784d83"
}
],
"cdn": {
@@ -6372,7 +6336,7 @@
"assets": [
{
"filename": "index.zh-TW.json",
- "sha256":
"8693fe44f0055721c200b4782464050a2b452c32319d427dc2cf059b00c17b04"
+ "sha256":
"ccbdb3fdf1749bd9806d76cc888a8682f6949db46f90625867e4b7161790fac6"
}
],
"cdn": {
@@ -6386,7 +6350,7 @@
"assets": [
{
"filename": "index_logo.json",
- "sha256":
"071dc2dd15d1f0b29db655d679f6a1569c3e64ec564df15b24a8082f384815c6"
+ "sha256":
"50311fb442b664ef0a61f6b1a700bb8244c5aee79d9e2b0669ccf546fd859ef3"
},
{
"filename": "logo/anthropic.webp",
@@ -6435,6 +6399,11 @@
"bundle": "media-assets-02"
},
{
+ "filename": "logo/higgsfield.png",
+ "sha256":
"22e061f4c2779478b03e7526747b6591a2090c45f43bf4c4bf7da3acbfb64457",
+ "bundle": "media-assets-02"
+ },
+ {
"filename": "logo/hitpaw.png",
"sha256":
"b0f08587a2a7de1d1edb70e5aa07c621b93a9f4411702a84a0d47f144c468a3a"
},
@@ -10978,7 +10947,7 @@
"assets": [
{
"filename": "video_wan_animate2.json",
- "sha256":
"c7e67adc03ce0414c11554caf155aa81fb47bf29e8184135768419f91182c845"
+ "sha256":
"951fb2140c55ef8011a1ddc60639b0c76a5bd99a77212a7ef587af1b7df74652"
},
{
"filename": "video_wan_animate2-1.webp",
@@ -11192,6 +11161,42 @@
}
},
{
+ "id": "api_fishaudio_drama3_dialogue",
+ "bundle": "media-assets-02",
+ "version": "0.0.0",
+ "assets": [
+ {
+ "filename": "api_fishaudio_drama3_dialogue.json",
+ "sha256":
"04ada6ece59b0da654e76913c69e887708ac2fd7f992260f3823c4be29db656a"
+ },
+ {
+ "filename": "api_fishaudio_drama3_dialogue-1.webp",
+ "sha256":
"a1b6cc6cdfdb6cdfbe9ddd083f74924ff8b77bc31f5a0592b28fe095542f9b53"
+ }
+ ],
+ "cdn": {
+ "path": "media-assets-02/api_fishaudio_drama3_dialogue/"
+ }
+ },
+ {
+ "id": "api_fishaudio_drama3_directed",
+ "bundle": "media-assets-02",
+ "version": "0.0.0",
+ "assets": [
+ {
+ "filename": "api_fishaudio_drama3_directed.json",
+ "sha256":
"1c08755afe00350353d3db87c94e493126c3761bc7031f0ac4f3e5178befc190"
+ },
+ {
+ "filename": "api_fishaudio_drama3_directed-1.webp",
+ "sha256":
"cc57d7afd4f35ed101c7957b1b5a78fb604f10d17a3699785d956a29d6e69235"
+ }
+ ],
+ "cdn": {
+ "path": "media-assets-02/api_fishaudio_drama3_directed/"
+ }
+ },
+ {
"id": "api_grok_imagine_video_1_5_lite_i2v",
"bundle": "media-assets-02",
"version": "0.0.0",
@@ -11282,6 +11287,24 @@
}
},
{
+ "id": "api_higgsfield_genjutsu_motion_transfer",
+ "bundle": "media-assets-02",
+ "version": "0.0.0",
+ "assets": [
+ {
+ "filename": "api_higgsfield_genjutsu_motion_transfer.json",
+ "sha256":
"0e07dbc509eb7be12eabaf1104eb88721fec6dec9c489f01bb223d3ecd457690"
+ },
+ {
+ "filename": "api_higgsfield_genjutsu_motion_transfer-1.webp",
+ "sha256":
"fba1ea8748d98209e343b44b436776bbd0ca77ce7e086fdc11a1bd4fcfc111e3"
+ }
+ ],
+ "cdn": {
+ "path": "media-assets-02/api_higgsfield_genjutsu_motion_transfer/"
+ }
+ },
+ {
"id": "api_ideogram_v4_5_image_edit",
"bundle": "media-assets-02",
"version": "0.0.0",
@@ -11498,7 +11521,7 @@
"assets": [
{
"filename": "api_quiver_arrow2_image_to_svg.json",
- "sha256":
"a706b115c58167b63b5f658ad6079760d73dc5a4915aedc13316c80efeb78cb4"
+ "sha256":
"99bd727308518a48deb99745115157eca7edf717b39734230483d97be04142f0"
},
{
"filename": "api_quiver_arrow2_image_to_svg-1.webp",
@@ -11520,7 +11543,7 @@
"assets": [
{
"filename": "api_quiver_arrow2_text_to_svg.json",
- "sha256":
"f6b1a5aa4808f27129e90c32b15897d4389d7fbc1d796e0f3a4065725ac034d7"
+ "sha256":
"bbf10674003489b0696577fa31ad57434448bfe98369c072a780e83ae62f8ff1"
},
{
"filename": "api_quiver_arrow2_text_to_svg-1.webp",
@@ -11862,6 +11885,64 @@
}
},
{
+ "id": "image_qwen_image_2_1_turbo_image_edit",
+ "bundle": "media-assets-02",
+ "version": "0.0.0",
+ "assets": [
+ {
+ "filename": "image_qwen_image_2_1_turbo_image_edit.json",
+ "sha256":
"5a9622d550866800414afcb9c70523ec5c6965eb171476e401e243a7fe8d5a4e"
+ },
+ {
+ "filename": "image_qwen_image_2_1_turbo_image_edit-1.webp",
+ "sha256":
"93b2d2fc22eb91efd34e9d0c5e07505727629377c20852c15bd23de5e16ab0fc"
+ },
+ {
+ "filename": "image_qwen_image_2_1_turbo_image_edit-2.webp",
+ "sha256":
"289cc45cb3c7c315d7c0bf5d6b75de9d4b89dd77f54647908e030fc3f1226c82"
+ }
+ ],
+ "cdn": {
+ "path": "media-assets-02/image_qwen_image_2_1_turbo_image_edit/"
+ }
+ },
+ {
+ "id": "image_qwen_image_2_1_turbo_t2i",
+ "bundle": "media-assets-02",
+ "version": "0.0.0",
+ "assets": [
+ {
+ "filename": "image_qwen_image_2_1_turbo_t2i.json",
+ "sha256":
"3eb9cef2866c0186fbe30172701f112b35e574cf3c6575c6e4a6b5dd1e76a403"
+ },
+ {
+ "filename": "image_qwen_image_2_1_turbo_t2i-1.webp",
+ "sha256":
"d16ac0f6130e6a4d3ada442d02c3b81db678031cfcdfdd0ca608b86222947d08"
+ }
+ ],
+ "cdn": {
+ "path": "media-assets-02/image_qwen_image_2_1_turbo_t2i/"
+ }
+ },
+ {
+ "id": "template_qwen_multiangle.app",
+ "bundle": "media-assets-02",
+ "version": "0.0.0",
+ "assets": [
+ {
+ "filename": "template_qwen_multiangle.app.json",
+ "sha256":
"ee47cfe4a9a7885bd6a99bccb468a5e8b6595477e30a2849114d35657ecd5847"
+ },
+ {
+ "filename": "template_qwen_multiangle.app-1.webp",
+ "sha256":
"ee4db80e6f4682744b47e1b7f7d9fce7a6ac3270b94c68d5c25ab4d97a6de356"
+ }
+ ],
+ "cdn": {
+ "path": "media-assets-02/template_qwen_multiangle.app/"
+ }
+ },
+ {
"id": "utility_moge3_geometry_estimation",
"bundle": "media-assets-02",
"version": "0.0.0",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/comfyui_workflow_templates_core-0.3.369/src/comfyui_workflow_templates_core.egg-info/PKG-INFO
new/comfyui_workflow_templates_core-0.3.373/src/comfyui_workflow_templates_core.egg-info/PKG-INFO
---
old/comfyui_workflow_templates_core-0.3.369/src/comfyui_workflow_templates_core.egg-info/PKG-INFO
2026-10-07 18:01:12.127464300 +0200
+++
new/comfyui_workflow_templates_core-0.3.373/src/comfyui_workflow_templates_core.egg-info/PKG-INFO
2026-10-13 19:13:47.426462200 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: comfyui-workflow-templates-core
-Version: 0.3.369
+Version: 0.3.373
Summary: Core helpers for ComfyUI workflow templates
License-Expression: MIT
Requires-Python: >=3.9
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/comfyui_workflow_templates_core-0.3.369/tests/test_ci_version_manager.py
new/comfyui_workflow_templates_core-0.3.373/tests/test_ci_version_manager.py
---
old/comfyui_workflow_templates_core-0.3.369/tests/test_ci_version_manager.py
2026-10-07 18:00:41.903253600 +0200
+++
new/comfyui_workflow_templates_core-0.3.373/tests/test_ci_version_manager.py
2026-10-13 19:13:18.664749000 +0200
@@ -1,8 +1,11 @@
"""Regression tests for release-time package version detection."""
import importlib.util
+import json
+import os
import subprocess
import sys
+import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch
@@ -28,53 +31,204 @@
ci_version_manager._committed_files_cache.clear()
ci_version_manager._unstaged_files_cache = None
- def test_release_looks_before_pr_merge_base_for_package_version(self):
- """A version-only release PR must see unreleased changes already on
main."""
+ def test_release_uses_tag_and_bumps_core_json_once(self):
+ """The release snapshot includes changes already merged to main."""
calls = []
def fake_run_git(args):
calls.append(args)
- if args[0] == "log":
- return "version-intro\nolder-version"
- if args[:2] == ["show",
"version-intro:packages/core/pyproject.toml"]:
- return '[project]\nversion = "1.2.3"\n'
- if args[:2] == ["show",
"older-version:packages/core/pyproject.toml"]:
- return '[project]\nversion = "1.2.2"\n'
- raise AssertionError(f"Unexpected git invocation: {args}")
+ if args[0] == "tag":
+ return "v1.0.0"
+ if args[0] == "show":
+ return '{"templates": []}'
+ if args[0] == "diff":
+ return ""
+ raise AssertionError(args)
with (
patch.object(ci_version_manager, "run_git",
side_effect=fake_run_git),
- patch.object(ci_version_manager, "get_current_version",
return_value="1.2.3"),
+ patch.object(ci_version_manager, "get_merge_base",
return_value="merge-base"),
+ patch.object(ci_version_manager, "get_frozen_packages",
return_value=set()),
+ patch.object(ci_version_manager, "_blocked_frozen_media_updates",
return_value=set()),
+ patch.object(ci_version_manager, "get_current_version",
return_value="1.0.0"),
+ patch.object(ci_version_manager, "get_version_at_ref",
return_value="1.0.0"),
+ patch.object(Path, "read_text", return_value='{"templates": []}'),
):
- since = ci_version_manager.get_since_commit_for_package(
- "core", "pr-merge-base"
- )
+ result = ci_version_manager.get_changed_packages()
+
+ self.assertEqual(result, {"core", "json", "meta"})
+ self.assertFalse(any(args[0] == "log" for args in calls))
- self.assertEqual(since, "version-intro")
- log_call = calls[0]
- self.assertEqual(log_call[:2], ["log", "--format=%H"])
- self.assertNotIn("pr-merge-base..HEAD", log_call)
- self.assertEqual(log_call[-1], "packages/core/pyproject.toml")
+ def test_already_bumped_packages_are_not_bumped_again(self):
+ with (
+ patch.object(
+ ci_version_manager, "run_git", side_effect=["v1.0.0",
'{"templates": []}']
+ ),
+ patch.object(ci_version_manager, "get_merge_base",
return_value="merge-base"),
+ patch.object(ci_version_manager, "get_frozen_packages",
return_value=set()),
+ patch.object(ci_version_manager, "_blocked_frozen_media_updates",
return_value=set()),
+ patch.object(ci_version_manager, "get_current_version",
return_value="1.0.1"),
+ patch.object(ci_version_manager, "get_version_at_ref",
return_value="1.0.0"),
+ patch.object(Path, "read_text", return_value='{"templates": []}'),
+ ):
+ self.assertEqual(ci_version_manager.get_changed_packages(), set())
- def test_latest_auto_bump_commit_becomes_the_next_detection_boundary(self):
- """A rerun after CI commits a bump must not inspect changes before
that bump."""
+ def test_replacing_existing_media_asset_bumps_its_bundle(self):
+ """bundles.json need not change when an existing thumbnail is
replaced."""
+ before = (
+ '{"templates": [{"bundle": "media-assets-02", '
+ '"assets": [{"filename": "a.webp", "sha256": "old"}]}]}'
+ )
+ after = before.replace('"old"', '"new"')
def fake_run_git(args):
- if args[0] == "log":
- return "auto-bump-commit\nprevious-version"
- if args[:2] == ["show",
"auto-bump-commit:packages/json/pyproject.toml"]:
- return '[project]\nversion = "2.0.1"\n'
- raise AssertionError(f"Unexpected git invocation: {args}")
+ if args[0] == "tag":
+ return "v1.0.0"
+ if args[0] == "show":
+ return before
+ if args[0] == "diff":
+ return ""
+ raise AssertionError(args)
with (
patch.object(ci_version_manager, "run_git",
side_effect=fake_run_git),
- patch.object(ci_version_manager, "get_current_version",
return_value="2.0.1"),
+ patch.object(ci_version_manager, "get_merge_base",
return_value="merge-base"),
+ patch.object(
+ ci_version_manager, "get_frozen_packages",
+ return_value={
+ "media_api", "media_video", "media_image", "media_other",
"media_assets_01"
+ },
+ ),
+ patch.object(ci_version_manager, "_blocked_frozen_media_updates",
return_value=set()),
+ patch.object(ci_version_manager, "get_current_version",
return_value="1.0.0"),
+ patch.object(ci_version_manager, "get_version_at_ref",
return_value="1.0.0"),
+ patch.object(Path, "read_text", return_value=after),
):
- since = ci_version_manager.get_since_commit_for_package(
- "json", "pr-merge-base"
- )
+ result = ci_version_manager.get_changed_packages()
+
+ self.assertEqual(result, {"core", "json", "media_assets_02", "meta"})
+
+ def test_missing_release_tag_fails_without_bumping(self):
+ with (
+ patch.object(ci_version_manager, "run_git", return_value=""),
+ patch.object(ci_version_manager, "get_merge_base",
return_value="merge-base"),
+ patch.object(ci_version_manager, "get_frozen_packages",
return_value=set()),
+ patch.object(ci_version_manager, "_blocked_frozen_media_updates",
return_value=set()),
+ ):
+ with self.assertRaisesRegex(SystemExit, "No reachable release
tag"):
+ ci_version_manager.get_changed_packages()
+
+ def test_media_package_source_change_bumps_without_asset_changes(self):
+ def fake_run_git(args):
+ if args[0] == "tag":
+ return "v1.0.0"
+ if args[0] == "show":
+ return '{"templates": []}'
+ if args[0] == "diff":
+ if "packages/media_assets_02/" in args:
+ return "packages/media_assets_02/src/example/__init__.py"
+ return ""
+ raise AssertionError(args)
+
+ with (
+ patch.object(ci_version_manager, "run_git",
side_effect=fake_run_git),
+ patch.object(ci_version_manager, "get_merge_base",
return_value="merge-base"),
+ patch.object(ci_version_manager, "get_frozen_packages",
return_value=set()),
+ patch.object(ci_version_manager, "_blocked_frozen_media_updates",
return_value=set()),
+ patch.object(ci_version_manager, "get_current_version",
return_value="1.0.0"),
+ patch.object(ci_version_manager, "get_version_at_ref",
return_value="1.0.0"),
+ patch.object(Path, "read_text", return_value='{"templates": []}'),
+ ):
+ self.assertEqual(ci_version_manager.get_changed_packages(), {
+ "core", "json", "media_assets_02", "meta"
+ })
+
+ def test_prerelease_tag_is_not_used_as_release_baseline(self):
+ def fake_run_git(args):
+ if args[0] == "tag":
+ return "v1.1.0-rc.1\nv1.0.0"
+ if args[0] == "show":
+ self.assertTrue(args[1].startswith("v1.0.0:"))
+ return '{"templates": []}'
+ if args[0] == "diff":
+ return ""
+ raise AssertionError(args)
- self.assertEqual(since, "auto-bump-commit")
+ with (
+ patch.object(ci_version_manager, "run_git",
side_effect=fake_run_git),
+ patch.object(ci_version_manager, "get_merge_base",
return_value="merge-base"),
+ patch.object(ci_version_manager, "get_frozen_packages",
return_value=set()),
+ patch.object(ci_version_manager, "_blocked_frozen_media_updates",
return_value=set()),
+ patch.object(ci_version_manager, "get_current_version",
return_value="1.0.0"),
+ patch.object(ci_version_manager, "get_version_at_ref",
return_value="1.0.0"),
+ patch.object(Path, "read_text", return_value='{"templates": []}'),
+ ):
+ self.assertEqual(ci_version_manager.get_changed_packages(),
{"core", "json", "meta"})
+
+ def test_only_prerelease_tags_fail_without_bumping(self):
+ with (
+ patch.object(ci_version_manager, "run_git",
return_value="v1.0.0-rc.1"),
+ patch.object(ci_version_manager, "get_merge_base",
return_value="merge-base"),
+ patch.object(ci_version_manager, "get_frozen_packages",
return_value=set()),
+ patch.object(ci_version_manager, "_blocked_frozen_media_updates",
return_value=set()),
+ ):
+ with self.assertRaisesRegex(SystemExit, "No reachable release
tag"):
+ ci_version_manager.get_changed_packages()
+
+ def test_required_baseline_version_read_failure_is_not_zero(self):
+ with patch.object(
+ ci_version_manager, "run_git",
+ side_effect=subprocess.CalledProcessError(128, ["git", "show"]),
+ ):
+ with self.assertRaisesRegex(RuntimeError, "Cannot read package
version for core"):
+ ci_version_manager.get_version_at_ref("core", "v1.0.0",
required=True)
+
+ def test_required_baseline_version_must_have_project_version(self):
+ with patch.object(ci_version_manager, "run_git",
return_value="[project]\n"):
+ with self.assertRaisesRegex(RuntimeError, "Cannot read package
version for core"):
+ ci_version_manager.get_version_at_ref("core", "v1.0.0",
required=True)
+
+ def test_missing_package_at_valid_ref_is_distinct_from_git_failure(self):
+ with patch.object(ci_version_manager, "run_git", return_value="") as
run_git:
+ self.assertEqual(ci_version_manager.get_version_at_ref(
+ "core", "base", required=True, allow_missing=True
+ ), "0.0.0")
+ run_git.assert_called_once_with(["ls-tree", "base", "--",
"packages/core/pyproject.toml"])
+ with patch.object(ci_version_manager, "run_git",
side_effect=subprocess.CalledProcessError(
+ 128, ["git", "ls-tree"], stderr=b"fatal: invalid object name"
+ )):
+ with self.assertRaisesRegex(RuntimeError, "invalid object name"):
+ ci_version_manager.get_version_at_ref(
+ "core", "base", required=True, allow_missing=True
+ )
+
+ def test_frozen_updates_stop_detection_before_tag_queries(self):
+ with (
+ patch.object(ci_version_manager, "get_merge_base",
return_value="base"),
+ patch.object(ci_version_manager, "get_frozen_packages",
return_value={"media_api"}),
+ patch.object(
+ ci_version_manager, "_blocked_frozen_media_updates",
return_value={"media_api"}
+ ),
+ patch.object(ci_version_manager, "run_git") as run_git,
+ ):
+ with self.assertRaisesRegex(SystemExit, "Frozen media packages
need an update"):
+ ci_version_manager.get_changed_packages()
+ run_git.assert_not_called()
+
+ def test_detection_git_error_is_reported_without_a_traceback(self):
+ with (
+ patch.object(ci_version_manager, "_parse_args", return_value=type(
+ "Args", (), {"list_publish_packages": False}
+ )()),
+ patch.object(ci_version_manager, "root_version_changed",
return_value=True),
+ patch.object(ci_version_manager, "get_changed_packages",
side_effect=(
+ subprocess.CalledProcessError(128, ["git", "tag"],
stderr=b"fatal: bad ref")
+ )),
+ ):
+ with self.assertRaisesRegex(
+ SystemExit, "Release change detection failed: fatal: bad ref"
+ ):
+ ci_version_manager.main()
def test_update_dependencies_uses_provided_package_set(self):
"""Pin updates must not re-run the full change scan."""
@@ -94,32 +248,6 @@
get_changed.assert_not_called()
self.assertTrue(write_text.called)
- def test_frozen_packages_skip_version_intro_scan(self):
- """Frozen packages must not trigger months-long history walks."""
- with (
- patch.object(ci_version_manager, "get_merge_base",
return_value="merge-base"),
- patch.object(
- ci_version_manager,
- "get_frozen_packages",
- return_value={"media_api", "media_assets_01"},
- ),
- patch.object(
- ci_version_manager, "get_since_commit_for_package"
- ) as get_since,
- patch.object(
- ci_version_manager, "get_files_affecting_package",
return_value=[]
- ),
- patch.object(
- ci_version_manager, "_blocked_frozen_media_updates",
return_value=set()
- ),
- patch.object(ci_version_manager, "get_current_version",
return_value="0.0.1"),
- ):
- result = ci_version_manager.get_changed_packages()
-
- self.assertEqual(result, set())
- analyzed = {call.args[0] for call in get_since.call_args_list}
- self.assertNotIn("media_api", analyzed)
- self.assertNotIn("media_assets_01", analyzed)
def test_blocked_frozen_media_uses_merge_base_not_version_intro(self):
calls = []
@@ -200,5 +328,127 @@
self.assertEqual(len(calls), 2)
+class ReleaseIntegrationTests(unittest.TestCase):
+ def test_release_includes_main_changes_and_rerun_does_not_bump_again(self):
+ self._exercise_release()
+
+ def test_stale_tag_does_not_skip_versions_already_advanced_on_main(self):
+ self._exercise_release(stale_tag=True)
+
+ def test_package_added_on_main_after_tag_can_be_released(self):
+ self._exercise_release(new_package=True)
+
+ def
test_package_added_on_pr_keeps_initial_version_and_is_publishable(self):
+ self._exercise_release(new_on_pr=True)
+
+ def test_blueprint_core_manifest_change_is_detected(self):
+ self._exercise_release(manifest_only=True)
+
+ def _exercise_release(
+ self, *, stale_tag=False, new_package=False, new_on_pr=False,
manifest_only=False
+ ):
+ """Exercise real tags, package versions and content across a release
PR."""
+ with tempfile.TemporaryDirectory() as directory:
+ root = Path(directory)
+
+ def git(*args):
+ return subprocess.check_output(
+ ["git", *args], cwd=root, stderr=subprocess.PIPE
+ ).decode().strip()
+
+ def write(path, content):
+ target = root / path
+ target.parent.mkdir(parents=True, exist_ok=True)
+ target.write_text(content)
+
+ def commit(message):
+ git("add", ".")
+ git("commit", "-m", message)
+
+ git("init", "-b", "main")
+ git("config", "user.name", "Release test")
+ git("config", "user.email", "[email protected]")
+ for pkg in ("core", "json", "media_assets_02", "blueprints"):
+ if (new_package or new_on_pr) and pkg == "media_assets_02":
+ continue
+ write(f"packages/{pkg}/pyproject.toml", '[project]\nversion =
"1.0.0"\n')
+ write("pyproject.toml", '[project]\nversion = "1.0.0"\n')
+ manifest_path =
"packages/core/src/comfyui_workflow_templates_core/manifest.json"
+ manifest = {"templates": [{"bundle": "media-assets-02", "assets": [
+ {"filename": "a.webp", "sha256": "old"}
+ ]}]}
+ write(manifest_path, json.dumps(manifest))
+ write("blueprints/example.json", "{}")
+ blueprint_manifest = (
+
"packages/core/src/comfyui_workflow_templates_core/blueprints_manifest.json"
+ )
+ write(blueprint_manifest, '{"blueprints": []}')
+ commit("Published release")
+ git("tag", "v1.0.0")
+
+ if stale_tag:
+ for pkg in ("core", "json", "media_assets_02", "blueprints"):
+ write(f"packages/{pkg}/pyproject.toml",
'[project]\nversion = "1.0.1"\n')
+ write("pyproject.toml", '[project]\nversion = "1.0.1"\n')
+ commit("Previous release succeeded but its tag was not
created")
+ if new_package:
+ write("packages/media_assets_02/pyproject.toml",
'[project]\nversion = "1.0.1"\n')
+ if manifest_only:
+ write(blueprint_manifest, '{"blueprints": [{"id":
"example"}]}')
+ else:
+ manifest["templates"][0]["assets"][0]["sha256"] = "new"
+ write(manifest_path, json.dumps(manifest))
+ write("blueprints/example.json", '{"changed": true}')
+ commit("Merge template and blueprint changes into main")
+ git("update-ref", "refs/remotes/origin/main", "HEAD")
+ git("checkout", "-b", "release")
+ if new_on_pr:
+ write("packages/media_assets_02/pyproject.toml",
'[project]\nversion = "1.0.1"\n')
+ # A reachable prerelease tag must not become the published
baseline.
+ git("tag", "v1.1.0-rc.1")
+ release_version = "1.0.2" if stale_tag else "1.0.1"
+ write("pyproject.toml", f'[project]\nversion =
"{release_version}"\n')
+ commit("Start next release")
+
+ previous_cwd = Path.cwd()
+ try:
+ os.chdir(root)
+ with (
+ patch.object(ci_version_manager, "ROOT", root),
+ patch.object(ci_version_manager, "get_frozen_packages",
return_value=set()),
+ patch.object(
+ ci_version_manager, "_blocked_frozen_media_updates",
return_value=set()
+ ),
+ patch.object(ci_version_manager, "ALL_PACKAGE_IDS", (
+ "core", "json", "media_assets_02", "blueprints", "meta"
+ )),
+ ):
+ self.assertTrue(ci_version_manager.root_version_changed())
+ changed = ci_version_manager.get_changed_packages()
+ expected = {"core", "json", "blueprints", "meta"}
+ if not manifest_only and not new_on_pr:
+ expected.add("media_assets_02")
+ self.assertEqual(changed, expected)
+ ci_version_manager.bump_versions(changed)
+ if "media_assets_02" in expected:
+ expected_version = "1.0.2" if stale_tag or new_package
else "1.0.1"
+ self.assertEqual(
+
ci_version_manager.get_current_version("media_assets_02"),
+ expected_version,
+ )
+ if new_on_pr:
+ self.assertEqual(
+
ci_version_manager.get_current_version("media_assets_02"), "1.0.1"
+ )
+ self.assertIn("media_assets_02",
ci_version_manager.get_publish_package_ids(
+ "origin/main"
+ ))
+ commit("Auto-bump package versions")
+ self.assertTrue(ci_version_manager.root_version_changed())
+
self.assertEqual(ci_version_manager.get_changed_packages(), set())
+ finally:
+ os.chdir(previous_cwd)
+
+
if __name__ == "__main__":
unittest.main()