Skip to content

feat(jira): add createCustomField method to JIRA client and tRPC endpoint#782

Merged
aaight merged 3 commits intodevfrom
feature/jira-custom-fields
Mar 13, 2026
Merged

feat(jira): add createCustomField method to JIRA client and tRPC endpoint#782
aaight merged 3 commits intodevfrom
feature/jira-custom-fields

Conversation

@aaight
Copy link
Copy Markdown
Collaborator

@aaight aaight commented Mar 13, 2026

Summary

This PR adds support for creating custom fields in JIRA through the dashboard and CLI.

  • JIRA client method: Added createCustomField(name, type) to jiraClient using the jira.js SDK's issueFields.createCustomField() API
  • tRPC endpoint: Added createJiraCustomField mutation to the integrations discovery router
  • Error handling: Gracefully wraps errors with a descriptive message noting that JIRA admin permissions are required
  • Comprehensive tests: Added unit tests for both the client method and tRPC endpoint covering success paths, input validation, auth, and error scenarios

Implementation Details

JIRA Client Method (src/jira/client.ts)

  • Method signature: createCustomField(name: string, type: string): Promise<{ id: string; name: string }>
  • Uses getClient().issueFields.createCustomField() from jira.js SDK
  • Returns the created field's ID and name
  • Error handling includes:
    • Descriptive error message noting admin permissions requirement
    • Logs failed attempts with name, type, and response details
    • Preserves JIRA API response details for debugging

tRPC Endpoint (src/api/routers/integrationsDiscovery.ts)

  • Endpoint: createJiraCustomField
  • Input schema: Extends jiraCredsInput with name: z.string().min(1).max(100)
  • Type is hardcoded to 'com.atlassian.jira.plugin.system.customfieldtypes:float' for numeric cost fields
  • Uses withResolvedJiraCreds helper for credential resolution and error wrapping
  • Requires authentication (protected procedure)

Test Coverage

  • JIRA client tests (5 new tests):

    • Success case with response mapping
    • Handling missing response fields
    • Error with admin permission details
    • Error without response detail
    • Scope validation
  • tRPC endpoint tests (6 new tests):

    • Success case verifying client method is called correctly
    • Authentication validation
    • Credential resolution validation
    • Input validation (name length)
    • API error wrapping in BAD_REQUEST

Acceptance Criteria

  • ✅ createCustomField(name, type) method added to jiraClient using getClient().issueFields.createCustomField()
  • ✅ Method uses type 'com.atlassian.jira.plugin.system.customfieldtypes:float' and returns { id, name }
  • ✅ Method gracefully wraps errors with admin permissions message
  • ✅ createJiraCustomField tRPC mutation endpoint added with jiraCredsInput + name input
  • ✅ Unit tests for JIRA client method cover success, response mapping, and error handling
  • ✅ Unit tests for tRPC endpoint cover auth, success, validation, and error wrapping

Tests

All tests passing:

  • 51 JIRA client tests (including 5 new)
  • 42 integrations discovery tests (including 6 new)
  • Lint and type checks passing

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Clean, well-structured addition that follows existing codebase patterns closely. Two observations worth considering — neither blocking.

Code Issues

Should Fix

  • src/jira/client.ts:337 — The error message hardcodes "requires admin permissions" for all failure scenarios (network errors, duplicate field names, validation errors, etc.). Compare with the existing createIssue error handler (line 190) which uses a neutral "JIRA createIssue failed" prefix. This will mislead debugging when the root cause isn't permissions. Consider using a neutral prefix like "JIRA createCustomField failed" and mentioning admin permissions only in a hint, e.g., "JIRA createCustomField failed (admin permissions may be required)".

Nitpick

  • src/jira/client.ts:319-321 — The JIRA createCustomField API accepts an optional searcherKey parameter. For float type, valid searchers are exactnumber or numberrange. Without specifying one, the created custom field won't be searchable via JQL. If this field will be used for cost tracking/reporting, JQL searchability could be valuable. This could also be addressed later if not needed now.

Replace misleading "requires admin permissions" prefix with neutral
"failed (admin permissions may be required)" to avoid confusion when
the root cause is a network error, duplicate name, or validation issue.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Clean, well-structured PR that follows existing patterns exactly. One functional consideration worth discussing.

Should Consider

  • Missing searcherKey for the custom field: The createCustomField call only passes name and type to the JIRA API. Per the jira.js SDK and JIRA REST API docs, omitting searcherKey means the created float field won't be searchable via JQL. For a numeric cost field, passing a searcher like exactnumber or numberrange would make the field queryable (e.g., "Cost" > 100). If this is intentional, a code comment noting the trade-off would be helpful; if not, it's worth adding.

Everything else looks good:

  • Client method correctly follows the createIssue error-handling pattern (message extraction, response data enrichment, admin permissions hint)
  • tRPC endpoint follows the createTrelloCustomField pattern (extend creds input, withResolvedJiraCreds, protected procedure)
  • Type casts and ?? '' fallbacks are consistent with FieldDetails having optional fields
  • Tests are comprehensive: success, missing fields, error enrichment (with/without response data), scope validation, auth, credential resolution, and input validation
  • CI is fully green

Pass the exactnumber searcherKey when creating a float custom field so
the field is queryable via JQL (e.g. `"Cost" > 100`). The method
signature accepts an optional searcherKey param; the tRPC endpoint
always passes exactnumber for the hardcoded float type.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@aaight
Copy link
Copy Markdown
Collaborator Author

aaight commented Mar 13, 2026

Review Feedback Addressed

Changes Made

  • Added searcherKey to createCustomField: Updated src/jira/client.ts to accept an optional searcherKey parameter and pass it to the JIRA API call. Added inline comments explaining the trade-off (the searcherKey enables JQL queries like "Cost" > 100; omitting it creates a non-searchable field).
  • exactnumber searcher in tRPC endpoint: The createJiraCustomField endpoint in src/api/routers/integrationsDiscovery.ts now passes 'com.atlassian.jira.plugin.system.customfieldtypes:exactnumber' as the searcherKey, making the float field queryable via JQL.
  • Updated tests: Added a new test case 'passes searcherKey when provided, enabling JQL searchability' in tests/unit/jira/client.test.ts, and updated the tRPC endpoint test assertion to verify the searcherKey argument is forwarded correctly.

Verification

  • All 94 unit tests passing (52 JIRA client + 42 integrations discovery)
  • Lint and type checks passing

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — Clean addition that follows established patterns exactly.

The createCustomField client method mirrors the existing createIssue error handling pattern (enriched error with response detail, admin permissions hint). The tRPC endpoint follows the same withResolvedJiraCreds + withJiraCredentials composition as all other JIRA endpoints in this router. Good design choice keeping the client method general-purpose (type and searcherKey as parameters) while the endpoint hardcodes the specific float/exactnumber values for the cost field use case. Test coverage is thorough across both layers.

@aaight aaight merged commit 1675c2c into dev Mar 13, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants