@@ -226,8 +226,9 @@ class Jira {
226
226
* Search for issues with a specific status and update them
227
227
* @param {string } currentStatus - Current status to search for
228
228
* @param {string } newStatus - New status to transition to
229
+ * @param {Object } fields - Additional fields to set during transition
229
230
*/
230
- async updateByStatus ( currentStatus , newStatus ) {
231
+ async updateByStatus ( currentStatus , newStatus , fields = { } ) {
231
232
try {
232
233
let jql = `status = "${ currentStatus } "`
233
234
const response = await this . request ( '/search' , {
@@ -244,7 +245,7 @@ class Jira {
244
245
console . log ( `Found ${ issues . length } issues in "${ currentStatus } " status` )
245
246
246
247
for ( const issue of issues ) {
247
- await this . transitionIssue ( issue . key , newStatus )
248
+ await this . transitionIssue ( issue . key , newStatus , [ 'Blocked' , 'Rejected' ] , fields )
248
249
}
249
250
250
251
return issues . length
@@ -258,8 +259,9 @@ class Jira {
258
259
* Find issues that mention a PR URL and update their status
259
260
* @param {string } prUrl - PR URL to search for (e.g., "myrepo/pull/123")
260
261
* @param {string } newStatus - New status to transition to
262
+ * @param {Object } fields - Additional fields to set during transition
261
263
*/
262
- async updateByPR ( prUrl , newStatus ) {
264
+ async updateByPR ( prUrl , newStatus , fields = { } ) {
263
265
try {
264
266
let jql = `text ~ "${ prUrl } "`
265
267
const response = await this . request ( '/search' , {
@@ -276,7 +278,7 @@ class Jira {
276
278
console . log ( `Found ${ issues . length } issues mentioning PR ${ prUrl } ` )
277
279
278
280
for ( const issue of issues ) {
279
- await this . transitionIssue ( issue . key , newStatus )
281
+ await this . transitionIssue ( issue . key , newStatus , [ 'Blocked' , 'Rejected' ] , fields )
280
282
}
281
283
282
284
return issues . length
@@ -321,6 +323,54 @@ class Jira {
321
323
}
322
324
}
323
325
326
+ /**
327
+ * Generic method to get field values by type
328
+ * @param {string } fieldName - Field name (resolution, priority, etc)
329
+ * @returns {Promise<Array> } Available options for the field
330
+ */
331
+ async getFieldOptions ( fieldName ) {
332
+ try {
333
+ const fieldMappings = {
334
+ 'resolution' : '/resolution' ,
335
+ 'priority' : '/priority' ,
336
+ 'issuetype' : '/issuetype' ,
337
+ 'component' : '/component' ,
338
+ 'version' : '/version'
339
+ }
340
+
341
+ const endpoint = fieldMappings [ fieldName ]
342
+ if ( ! endpoint ) {
343
+ console . log ( `No endpoint mapping for field: ${ fieldName } ` )
344
+ return [ ]
345
+ }
346
+
347
+ const response = await this . request ( endpoint )
348
+ const options = await response . json ( )
349
+ return options
350
+ } catch ( error ) {
351
+ console . error ( `Error getting ${ fieldName } options:` , error . message )
352
+ return [ ]
353
+ }
354
+ }
355
+
356
+ /**
357
+ * Get transition details including required fields
358
+ * @param {string } issueKey - Jira issue key
359
+ * @param {string } transitionId - Transition ID
360
+ * @returns {Promise<Object> } Transition details
361
+ */
362
+ async getTransitionDetails ( issueKey , transitionId ) {
363
+ try {
364
+ const response = await this . request ( `/issue/${ issueKey } /transitions?transitionId=${ transitionId } &expand=transitions.fields` )
365
+ const data = await response . json ( )
366
+ const transition = data . transitions . find ( t => t . id === transitionId )
367
+ return transition || { }
368
+ } catch ( error ) {
369
+ console . error ( `Error getting transition details:` , error . message )
370
+ throw error
371
+ }
372
+ }
373
+
324
374
/**
325
375
* Find the shortest path between two statuses using BFS, excluding paths through certain states
326
376
* @param {Object } stateMachine - The workflow state machine
@@ -407,8 +457,9 @@ class Jira {
407
457
* @param {string } issueKey - Jira issue key
408
458
* @param {string } targetStatus - Target status name
409
459
* @param {Array<string> } excludeStates - Array of state names to exclude from paths (optional)
460
+ * @param {Object } fields - Additional fields to set during the final transition
410
461
*/
411
- async transitionIssue ( issueKey , targetStatusName , excludeStates = [ 'Blocked' , 'Rejected' ] ) {
462
+ async transitionIssue ( issueKey , targetStatusName , excludeStates = [ 'Blocked' , 'Rejected' ] , fields = { } ) {
412
463
try {
413
464
const issueResponse = await this . request ( `/issue/${ issueKey } ?fields=status` )
414
465
const issueData = await issueResponse . json ( )
@@ -439,7 +490,9 @@ class Jira {
439
490
console . log ( `Found shortest transition path with ${ shortestPath . length } steps:` )
440
491
shortestPath . forEach ( t => console . log ( ` ${ t . fromName } → ${ t . toName } (${ t . name } )` ) )
441
492
442
- for ( const transition of shortestPath ) {
493
+ for ( let i = 0 ; i < shortestPath . length ; i ++ ) {
494
+ const transition = shortestPath [ i ]
495
+ const isLastTransition = i === shortestPath . length - 1
443
496
const availableTransitions = await this . getTransitions ( issueKey )
444
497
445
498
const actualTransition = availableTransitions . find ( t =>
@@ -453,13 +506,28 @@ class Jira {
453
506
return false
454
507
}
455
508
509
+ const transitionPayload = {
510
+ transition : {
511
+ id : actualTransition . id
512
+ }
513
+ }
514
+
515
+ if ( isLastTransition && Object . keys ( fields ) . length > 0 ) {
516
+ transitionPayload . fields = fields
517
+ }
518
+
519
+ const transitionDetails = await this . getTransitionDetails ( issueKey , actualTransition . id )
520
+ if ( transitionDetails . fields ) {
521
+ for ( const [ fieldId , fieldInfo ] of Object . entries ( transitionDetails . fields ) ) {
522
+ if ( fieldInfo . required && ! transitionPayload . fields ?. [ fieldId ] ) {
523
+ console . warn ( `Required field ${ fieldId } (${ fieldInfo . name } ) not provided for transition to ${ transition . toName } ` )
524
+ }
525
+ }
526
+ }
527
+
456
528
await this . request ( `/issue/${ issueKey } /transitions` , {
457
529
method : 'POST' ,
458
- body : JSON . stringify ( {
459
- transition : {
460
- id : actualTransition . id
461
- }
462
- } )
530
+ body : JSON . stringify ( transitionPayload )
463
531
} )
464
532
465
533
console . log ( `✓ Transitioned ${ issueKey } : ${ transition . fromName } → ${ transition . toName } ` )
0 commit comments