@@ -26,6 +26,8 @@ describe('devops promotion validate', () => {
2626 const validatePromotionStub = sinon . stub ( ) ;
2727 const resolveProjectIdFromWorkItemStub = sinon . stub ( ) ;
2828 const getPipelineIdForProjectStub = sinon . stub ( ) ;
29+ const fetchPipelineStagesStub = sinon . stub ( ) ;
30+ const computeFirstStageIdStub = sinon . stub ( ) ;
2931 const mockConnection = { getApiVersion : ( ) => '65.0' } ;
3032 const mockOrg = { id : '1' , getOrgId : ( ) => '1' , getConnection : ( ) => mockConnection } ;
3133
@@ -39,6 +41,8 @@ describe('devops promotion validate', () => {
3941 } ,
4042 '../../../../src/utils/pipelineUtils.js' : {
4143 getPipelineIdForProject : getPipelineIdForProjectStub ,
44+ fetchPipelineStages : fetchPipelineStagesStub ,
45+ computeFirstStageId : computeFirstStageIdStub ,
4246 } ,
4347 } ) ;
4448 ValidateCommand = mod . default ;
@@ -49,6 +53,11 @@ describe('devops promotion validate', () => {
4953 validatePromotionStub . reset ( ) ;
5054 resolveProjectIdFromWorkItemStub . reset ( ) ;
5155 getPipelineIdForProjectStub . reset ( ) ;
56+ fetchPipelineStagesStub . reset ( ) ;
57+ computeFirstStageIdStub . reset ( ) ;
58+ // Default: target stage is not the pipeline's first stage, so combine details are requested.
59+ fetchPipelineStagesStub . resolves ( [ ] ) ;
60+ computeFirstStageIdStub . returns ( undefined ) ;
5261 // eslint-disable-next-line @typescript-eslint/no-explicit-any
5362 sandbox . stub ( Org , 'create' as any ) . returns ( mockOrg ) ;
5463 } ) ;
@@ -85,17 +94,68 @@ describe('devops promotion validate', () => {
8594 test
8695 . stdout ( )
8796 . stderr ( )
88- . it ( 'requests combine details from the API' , async ( ) => {
97+ . it ( 'requests combine details from the API for multiple work items ' , async ( ) => {
8998 resolveProjectIdFromWorkItemStub . resolves ( { projectId : 'PROJ001' , pipelineStageId : '' } ) ;
9099 getPipelineIdForProjectStub . resolves ( 'PIPE001' ) ;
91100 validatePromotionStub . resolves ( { success : true , errorType : null , errorDetails : null , combineDetails : null } ) ;
92101
93- await ValidateCommand . run ( [ '-o' , 'testOrg' , '-i' , '1fkxx0000000001' , '-t' , '1QVxx0000000003' ] ) ;
102+ await ValidateCommand . run ( [
103+ '-o' ,
104+ 'testOrg' ,
105+ '-i' ,
106+ '1fkxx0000000001' ,
107+ '-i' ,
108+ '1fkxx0000000002' ,
109+ '-t' ,
110+ '1QVxx0000000003' ,
111+ ] ) ;
94112
95113 // checkCombineDetails (5th arg) must be true so the API returns shared-component info.
96114 expect ( validatePromotionStub . firstCall . args [ 4 ] ) . to . be . true ;
97115 } ) ;
98116
117+ test
118+ . stdout ( )
119+ . stderr ( )
120+ . it ( 'requests combine details for a single work item promoted to a non-first stage' , async ( ) => {
121+ resolveProjectIdFromWorkItemStub . resolves ( { projectId : 'PROJ001' , pipelineStageId : '' } ) ;
122+ getPipelineIdForProjectStub . resolves ( 'PIPE001' ) ;
123+ validatePromotionStub . resolves ( { success : true , errorType : null , errorDetails : null , combineDetails : null } ) ;
124+
125+ await ValidateCommand . run ( [ '-o' , 'testOrg' , '-i' , '1fkxx0000000001' , '-t' , '1QVxx0000000003' ] ) ;
126+
127+ // Combine details are requested regardless of work-item count, as long as the target is
128+ // not the pipeline's first stage.
129+ expect ( validatePromotionStub . firstCall . args [ 4 ] ) . to . be . true ;
130+ } ) ;
131+
132+ test
133+ . stdout ( )
134+ . stderr ( )
135+ . it ( 'does not request combine details when promoting to the first stage' , async ( ) => {
136+ resolveProjectIdFromWorkItemStub . resolves ( { projectId : 'PROJ001' , pipelineStageId : '' } ) ;
137+ getPipelineIdForProjectStub . resolves ( 'PIPE001' ) ;
138+ // The target stage is the pipeline's first stage, so work items have no source stage.
139+ fetchPipelineStagesStub . resolves ( [ { Id : '1QVxx0000000003' , Name : 'Integration' , NextStageId : null } ] ) ;
140+ computeFirstStageIdStub . returns ( '1QVxx0000000003' ) ;
141+ validatePromotionStub . resolves ( { success : true , errorType : null , errorDetails : null , combineDetails : null } ) ;
142+
143+ await ValidateCommand . run ( [
144+ '-o' ,
145+ 'testOrg' ,
146+ '-i' ,
147+ '1fkxx0000000001' ,
148+ '-i' ,
149+ '1fkxx0000000002' ,
150+ '-t' ,
151+ '1QVxx0000000003' ,
152+ ] ) ;
153+
154+ // Combine details for the first stage NPE server-side (null source stage), so skip them
155+ // regardless of work-item count.
156+ expect ( validatePromotionStub . firstCall . args [ 4 ] ) . to . be . false ;
157+ } ) ;
158+
99159 test
100160 . stdout ( )
101161 . stderr ( )
0 commit comments