@@ -171,3 +171,72 @@ def test_prod_versions_excluded(self, mock_config_with_matrix_dev_image):
171171 versions_in_output = {e ["version" ] for e in data }
172172 assert prod_ver1 .name not in versions_in_output
173173 assert prod_ver2 .name not in versions_in_output
174+
175+
176+ @pytest .fixture
177+ def mock_config_with_two_channel_dev_image ():
178+ """Patch BakeryConfig to return one non-matrix image carrying both a
179+ daily and a preview dev version (the workbench/session-init shape)."""
180+ daily = _make_version ("2026.99.0+237" , is_dev = True , channel = ReleaseChannelEnum .DAILY )
181+ preview = _make_version ("2026.99.0+240" , is_dev = True , channel = ReleaseChannelEnum .PREVIEW )
182+ img = MagicMock ()
183+ img .name = "workbench"
184+ img .matrix = None
185+ img .versions = [daily , preview ]
186+
187+ with patch ("posit_bakery.cli.ci.BakeryConfig" ) as mock :
188+ instance = MagicMock ()
189+ instance .model .images = [img ]
190+ mock .from_context .return_value = instance
191+ yield mock , daily , preview
192+
193+
194+ class TestCiMatrixDevSpecChannelFilter :
195+ """A --dev-spec carrying a channel filters the matrix to that channel even
196+ when --dev-channel is omitted. The shared workflow folds the channel into
197+ the dev-spec and drops --dev-channel, so the matrix must honor it."""
198+
199+ def test_filters_to_dev_spec_channel (self , mock_config_with_two_channel_dev_image ):
200+ _ , daily , preview = mock_config_with_two_channel_dev_image
201+ result = runner .invoke (
202+ app ,
203+ [
204+ "ci" ,
205+ "matrix" ,
206+ "--context" ,
207+ BASIC_CONTEXT ,
208+ "--dev-versions" ,
209+ "only" ,
210+ "--dev-spec" ,
211+ '{"version": "2026.99.0+240", "channel": "preview"}' ,
212+ ],
213+ catch_exceptions = False ,
214+ )
215+ assert result .exit_code == 0 , result .output
216+ data = json .loads (result .stdout .strip ())
217+ versions = {e ["version" ] for e in data }
218+ assert preview .name in versions
219+ assert daily .name not in versions
220+
221+ def test_branch_only_dev_spec_does_not_filter (self , mock_config_with_two_channel_dev_image ):
222+ """A branch-only dev-spec carries no channel, so all channels stay in the matrix."""
223+ _ , daily , preview = mock_config_with_two_channel_dev_image
224+ result = runner .invoke (
225+ app ,
226+ [
227+ "ci" ,
228+ "matrix" ,
229+ "--context" ,
230+ BASIC_CONTEXT ,
231+ "--dev-versions" ,
232+ "only" ,
233+ "--dev-spec" ,
234+ '{"release_branch": "2026.06"}' ,
235+ ],
236+ catch_exceptions = False ,
237+ )
238+ assert result .exit_code == 0 , result .output
239+ data = json .loads (result .stdout .strip ())
240+ versions = {e ["version" ] for e in data }
241+ assert preview .name in versions
242+ assert daily .name in versions
0 commit comments