@@ -158,6 +158,54 @@ def test_default_matrix_tag_patterns_includes_strip_patch_under_latest_patch_fil
158158 )
159159
160160
161+ def test_default_matrix_tag_patterns_includes_channel_patterns ():
162+ """Matrix tag patterns include floating {{ Channel }} patterns gated by CHANNEL_LATEST.
163+
164+ These give matrix dev images channel-head tags (e.g. "daily", "daily-min") that the
165+ CHANNEL_LATEST filter suppresses for builds targeting an older-than-head version.
166+ """
167+ patterns = default_matrix_tag_patterns ()
168+ channel_patterns = [p for p in patterns if any ("{{ Channel }}" in pat for pat in p .patterns )]
169+
170+ # The composite "{{ Version }}" axis is dropped for channel tags, so only the primary-reduced
171+ # variants are emitted to avoid collisions across matrix combinations.
172+ expected = {
173+ (("{{ Channel }}-{{ Variant }}" ,), (TagPatternFilter .CHANNEL_LATEST , TagPatternFilter .PRIMARY_OS )),
174+ (("{{ Channel }}-{{ OS }}" ,), (TagPatternFilter .CHANNEL_LATEST , TagPatternFilter .PRIMARY_VARIANT )),
175+ (
176+ ("{{ Channel }}" ,),
177+ (TagPatternFilter .CHANNEL_LATEST , TagPatternFilter .PRIMARY_OS , TagPatternFilter .PRIMARY_VARIANT ),
178+ ),
179+ }
180+ assert {(tuple (p .patterns ), tuple (p .only )) for p in channel_patterns } == expected
181+
182+ # Every channel pattern must be gated by CHANNEL_LATEST so older-than-head builds suppress them.
183+ for pattern in channel_patterns :
184+ assert TagPatternFilter .CHANNEL_LATEST in pattern .only , (
185+ f"Channel pattern must be gated by CHANNEL_LATEST: { pattern .patterns } only={ pattern .only } "
186+ )
187+
188+
189+ def test_default_matrix_channel_patterns_render_with_channel ():
190+ """Channel patterns render floating channel tags when a Channel value is supplied."""
191+ patterns = [p for p in default_matrix_tag_patterns () if any ("{{ Channel }}" in pat for pat in p .patterns )]
192+ rendered = []
193+ for pattern in patterns :
194+ rendered .extend (pattern .render (Channel = "daily" , OS = "ubuntu2404" , Variant = "min" ))
195+
196+ assert set (rendered ) == {"daily-min" , "daily-ubuntu2404" , "daily" }
197+
198+
199+ def test_default_matrix_channel_patterns_render_nothing_without_channel ():
200+ """Channel patterns produce no tags when no Channel value is supplied (non-channel images)."""
201+ patterns = [p for p in default_matrix_tag_patterns () if any ("{{ Channel }}" in pat for pat in p .patterns )]
202+ rendered = []
203+ for pattern in patterns :
204+ rendered .extend (pattern .render (Version = "R4.3.3-python3.11.15" , OS = "ubuntu2404" , Variant = "min" ))
205+
206+ assert rendered == []
207+
208+
161209def test_default_matrix_tag_patterns_strip_patch_renders_minor_tags ():
162210 """stripPatch-filtered tag patterns produce minor-only tags from composite matrix versions."""
163211 patterns = [p for p in default_matrix_tag_patterns () if TagPatternFilter .LATEST_PATCH in p .only ]
0 commit comments