create-issue.handler.ts•5.91 kB
/**
 * Create Issue Handler
 *
 * MCP tool handler for creating new JIRA issues with comprehensive validation
 * Refactored to use the use-case pattern for better separation of concerns
 */
import { BaseToolHandler } from "@core/tools/tool-handler.class";
import { formatZodError } from "@core/utils/validation";
import {
  JiraApiError,
  JiraNotFoundError,
  JiraPermissionError,
} from "@features/jira/client/errors";
import { IssueCreationFormatter } from "@features/jira/issues/formatters/issue-creation.formatter";
import {
  type CreateIssueParams,
  createIssueParamsSchema,
} from "@features/jira/issues/use-cases";
import type {
  CreateIssueUseCase,
  CreateIssueUseCaseRequest,
} from "@features/jira/issues/use-cases";
import { IssueCreateParamsValidationError } from "@features/jira/issues/validators/errors";
/**
 * Handler for creating new JIRA issues
 * Provides comprehensive issue creation with validation and rich responses
 * Uses the use-case pattern for separation of concerns
 */
export class CreateIssueHandler extends BaseToolHandler<
  CreateIssueParams,
  string
> {
  private readonly formatter: IssueCreationFormatter;
  /**
   * Create a new CreateIssueHandler with necessary dependencies
   *
   * @param createIssueUseCase - Use case for creating issues with validation
   * @param projectValidator - Validator for project-related validation
   * @param permissionChecker - Checker for permission-related validation
   */
  constructor(private readonly createIssueUseCase: CreateIssueUseCase) {
    super("JIRA", "Create Issue");
    this.formatter = new IssueCreationFormatter();
  }
  /**
   * Execute the handler logic
   * Creates a new JIRA issue with comprehensive validation and formatting
   * Delegates business logic to the use case
   *
   * @param params - Parameters for issue creation
   */
  protected async execute(params: CreateIssueParams): Promise<string> {
    try {
      // Step 1: Validate parameters
      const validatedParams = this.validateParameters(params);
      this.logger.info(
        `Creating JIRA issue in project: ${validatedParams.projectKey}`,
      );
      // Step 2: Map parameters to use case request
      const useCaseRequest: CreateIssueUseCaseRequest = {
        projectKey: validatedParams.projectKey,
        summary: validatedParams.summary,
        issueType: validatedParams.issueType,
        description: validatedParams.description,
        customFields: validatedParams.customFields,
      };
      // Step 3: Execute the use case
      this.logger.debug("Delegating to CreateIssueUseCase", {
        projectKey: validatedParams.projectKey,
        issueType: validatedParams.issueType,
        summary: validatedParams.summary,
      });
      const createdIssue =
        await this.createIssueUseCase.execute(useCaseRequest);
      // Step 4: Format and return success response
      this.logger.info(`Successfully created issue: ${createdIssue.key}`);
      return this.formatter.format(createdIssue);
    } catch (error) {
      this.logger.error(`Failed to create JIRA issue: ${error}`);
      throw this.enhanceError(error, params.projectKey, params.issueType);
    }
  }
  /**
   * Validate parameters using Zod schema
   */
  private validateParameters(params: CreateIssueParams): CreateIssueParams {
    const result = createIssueParamsSchema.safeParse(params);
    if (!result.success) {
      const errorMessage = `Invalid issue creation parameters: ${formatZodError(
        result.error,
      )}`;
      throw new IssueCreateParamsValidationError(errorMessage);
    }
    return result.data;
  }
  /**
   * Enhance error messages for better user guidance
   */
  private enhanceError(
    error: unknown,
    projectKey?: string,
    issueType?: string,
  ): Error {
    if (error instanceof JiraNotFoundError) {
      return new Error(
        `❌ **Project Not Found**\n\nProject '${projectKey}' not found or you don't have permission to create issues.\n\n**Solutions:**\n- Verify the project key is correct\n- Check your JIRA permissions\n- Use \`jira_get_projects\` to see available projects\n\n**Example:** \`jira_create_issue projectKey=MYPROJ summary="Fix bug" issueType=Bug\``,
      );
    }
    if (error instanceof JiraPermissionError) {
      return new Error(
        `❌ **Permission Denied**\n\nYou don't have permission to create issues in project '${projectKey}'.\n\n**Solutions:**\n- Check your JIRA permissions for this project\n- Contact your JIRA administrator\n- Verify you have CREATE_ISSUES permission\n\n**Required Permissions:** Create Issues`,
      );
    }
    if (error instanceof IssueCreateParamsValidationError) {
      return new Error(
        `❌ **Validation Error**\n\n${error.message}\n\n**Solutions:**\n- Check the format of all parameters\n- Ensure required fields are provided\n- Verify field values match expected formats\n\n**Example:** \`jira_create_issue projectKey=PROJ summary="My issue" issueType=Task\``,
      );
    }
    if (error instanceof JiraApiError) {
      return new Error(
        `❌ **JIRA API Error**\n\n${error.message}\n\n**Solutions:**\n- Check all required fields are provided\n- Verify field values match JIRA requirements\n- Ensure issue type '${issueType}' exists in project '${projectKey}'\n\n**Example:** \`jira_create_issue projectKey=PROJ summary="My issue" issueType=Task\``,
      );
    }
    if (error instanceof Error) {
      return new Error(
        `❌ **Creation Failed**\n\n${error.message}\n\n**Solutions:**\n- Check your parameters are valid\n- Verify the project and issue type exist\n- Try with minimal required fields first\n\n**Example:** \`jira_create_issue projectKey=PROJ summary="Test issue" issueType=Task\``,
      );
    }
    return new Error(
      "❌ **Unknown Error**\n\nAn unknown error occurred during issue creation.\n\nPlease check your parameters and try again.",
    );
  }
}