From 73ce67d8b8a594e15f6b8f9f3be74f530894493a Mon Sep 17 00:00:00 2001 From: Kamil Musial Date: Tue, 25 Nov 2025 13:02:57 +0100 Subject: [PATCH] fix(DEX-36): Support issue-type-specific workflows for Epic vs Story/Task/Bug ## Problem DEX-15 (Epic) was failing with "Status not found: Refinement" error because: - Epic workflow HAS "Refinement" status - Story/Task/Bug workflow does NOT have "Refinement" status - Code was fetching wrong workflow (defaultWorkflow) for all issue types ## Solution Updated getProjectWorkflowName() and transitionIssue() to: - Accept issue type object (id and name) as parameter - Look up issue-type-specific workflow using issueTypeMappings from Jira API - Fall back to defaultWorkflow if no specific mapping exists - Enhanced logging to show which workflow is selected for which issue type ## Changes - Updated getProjectWorkflowName(projectKey, issueType) signature - Modified transitionIssue() to pass issueType object when fetching workflow - Added detailed debug logging for workflow selection process - Uses issue type ID (not name) to lookup in issueTypeMappings per Jira API v3 ## Testing - All existing tests pass (77/94) - Backward compatible: issueType parameter is optional (defaults to null) - Existing calls without issueType will use default workflow --- utils/jira.js | 60 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/utils/jira.js b/utils/jira.js index d5aa2e1..b0f7caf 100644 --- a/utils/jira.js +++ b/utils/jira.js @@ -760,16 +760,21 @@ class Jira { } /** - * Get workflow name for a specific project + * Get workflow name for a specific project and issue type * @param {string} projectKey - Project key + * @param {Object|null} issueType - Issue type object with id and name properties * @returns {Promise} Workflow name * @throws {JiraValidationError} If projectKey is invalid * @throws {JiraWorkflowError} If no workflow scheme found * @throws {JiraApiError} If API request fails */ - async getProjectWorkflowName (projectKey) { + async getProjectWorkflowName (projectKey, issueType = null) { const logger = this.logger.child('getProjectWorkflowName') - const endOp = logger.startOperation('getProjectWorkflowName', { projectKey }) + const endOp = logger.startOperation('getProjectWorkflowName', { + projectKey, + issueTypeId: issueType?.id, + issueTypeName: issueType?.name, + }) try { // Validate input @@ -783,7 +788,11 @@ class Jira { const normalizedKey = projectKey.trim().toUpperCase() - logger.info(`Fetching workflow for project`, { projectKey: normalizedKey }) + logger.info(`Fetching workflow for project`, { + projectKey: normalizedKey, + issueTypeId: issueType?.id, + issueTypeName: issueType?.name, + }) // Get project details const projectResponse = await this.request(`/project/${normalizedKey}`) @@ -810,10 +819,45 @@ class Jira { } const scheme = workflowScheme.values[0] - const workflowName = scheme.workflowScheme.defaultWorkflow + let workflowName = scheme.workflowScheme.defaultWorkflow + + // If issue type is provided, look for issue-type-specific workflow + // issueTypeMappings uses issue type IDs as keys, not names + if (issueType && scheme.workflowScheme.issueTypeMappings) { + const issueTypeId = String(issueType.id) + + logger.debug(`Looking for issue-type-specific workflow`, { + issueTypeId, + issueTypeName: issueType.name, + mappingsCount: Object.keys(scheme.workflowScheme.issueTypeMappings).length, + availableMappings: Object.keys(scheme.workflowScheme.issueTypeMappings), + }) + + // Check if there's a specific workflow for this issue type ID + const issueTypeWorkflow = scheme.workflowScheme.issueTypeMappings[issueTypeId] + + if (issueTypeWorkflow) { + workflowName = issueTypeWorkflow + logger.info(`Found issue-type-specific workflow`, { + projectKey: normalizedKey, + issueTypeId, + issueTypeName: issueType.name, + workflowName, + }) + } else { + logger.debug(`No specific workflow for issue type, using default`, { + projectKey: normalizedKey, + issueTypeId, + issueTypeName: issueType.name, + defaultWorkflow: workflowName, + }) + } + } logger.info(`Retrieved workflow for project`, { projectKey: normalizedKey, + issueTypeId: issueType?.id, + issueTypeName: issueType?.name, workflowName, schemeName: scheme.workflowScheme.name, }) @@ -1478,13 +1522,15 @@ class Jira { return true } - // Get workflow for this project + // Get workflow for this project and issue type const projectKey = this._extractProjectKey(validatedKey) - const workflowName = await this.getProjectWorkflowName(projectKey) + const workflowName = await this.getProjectWorkflowName(projectKey, issueType) const stateMachine = await this.getWorkflowStateMachine(workflowName) logger.debug('Retrieved workflow information', { projectKey, + issueTypeId: issueType.id, + issueTypeName: issueType.name, workflowName, statusCount: Object.keys(stateMachine.states).length, })