Skip to main content

JPD Field Validation

Overview​

The sync tool automatically validates that all required JPD custom fields exist and have the correct types before starting the sync process. This prevents sync failures and provides clear, actionable error messages when fields are missing or misconfigured.

Features​

✅ Pre-Sync Validation - Validates fields before any sync operations
✅ Type Checking - Ensures fields have the expected data types
✅ Required vs Optional - Distinguishes between required and optional fields
✅ Helpful Error Reports - Provides clear instructions on how to fix issues
✅ Automatic Detection - Extracts project key from JQL automatically

Configuration​

Defining Fields​

Add a fields section to your config file:

fields:
# Example: Required numeric field
- id: "customfield_10001"
name: "Impact Score"
type: "number"
required: true
description: "RICE Impact score (0-10)"

# Example: Optional text field
- id: "customfield_10002"
name: "Notes"
type: "text"
required: false
description: "Additional notes"

# Example: Multi-select field
- id: "customfield_10003"
name: "Product Themes"
type: "multiselect"
required: true
description: "Strategic product themes"

Field Properties​

PropertyTypeRequiredDescription
idstring✅JPD custom field ID (e.g., customfield_14377)
namestring✅Human-readable field name
typeFieldType✅Expected field type (see below)
requiredboolean✅Whether field is required for sync
descriptionstring❌Brief description (for documentation)
searcherKeystring❌Jira searcher key (for future API creation)

Supported Field Types​

TypeDescriptionJPD Examples
stringSingle-line textShort text fields
textMulti-line textLong descriptions
numberNumeric valuesRICE scores, estimates
selectSingle-select dropdownPriority, Status
multiselectMulti-select dropdownThemes, Tags
userUser pickerAssignee, Reporter
dateDate pickerDue date
datetimeDate-time pickerTimestamps
urlURL fieldLinks, references
arrayArray/listGeneric arrays

How It Works​

1. Automatic Project Detection​

The validator extracts the project key from your JQL:

sync:
jql: "project = YOUR_PROJECT" # Automatically detects "YOUR_PROJECT"

Or from environment variable:

JPD_PROJECT_KEY=YOUR_PROJECT

2. Sample Issue Validation​

The validator fetches one issue from the project and checks all configured fields:

  • ✅ Field exists
  • ✅ Field has correct type
  • ✅ Required fields are not null

3. Type Compatibility​

The validator understands JPD's field structures:

// Single-select field
{ value: "High Priority" } → type: "select"

// Multi-select field
[{ value: "Theme A" }, { value: "Theme B" }] → type: "multiselect"

// Number field
42 → type: "number"

Validation Results​

Success ✅​

[INFO] Validating 9 JPD custom fields...
[INFO] ✅ All 8 required fields validated successfully
[WARN] Optional field "Notes" (customfield_14388) is null.
[INFO] Syncing JPD -> GitHub

Failure ❌​

╔══════════════════════════════════════════════════════════════╗
║ ║
║ ❌ JPD FIELD VALIDATION FAILED ❌ ║
║ ║
╚══════════════════════════════════════════════════════════════╝

🚫 ERRORS:
─────────────────────────────────────────────────────────────

❌ Impact Score (customfield_10001)
Required field "Impact Score" (customfield_10001) not found in JPD project.

💡 How to fix:
1. Go to JPD Project Settings
2. Create custom field: "Impact Score"
3. Type: number
4. Add to project screens

─────────────────────────────────────────────────────────────
Sync cannot continue until all required fields are available.
─────────────────────────────────────────────────────────────

Discovering Field IDs​

To find JPD custom field IDs, use the JPD API or debug logging:

# Enable debug mode
DEBUG=1 pnpm run dev -- --dry-run

Look for output like:

[DEBUG] Processing PROJ-1. Available fields: customfield_12345, customfield_67890, ...

Or use curl:

curl -u "your-email:your-api-token" \
"https://your-instance.atlassian.net/rest/api/3/issue/PROJ-1" \
| jq '.fields | keys'

Best Practices​

1. Start with Required Fields Only​

fields:
# Only validate fields you actually use in mappings
- id: "customfield_14377"
name: "Theme"
type: "multiselect"
required: true

2. Mark Optional Fields Appropriately​

fields:
# Optional fields won't fail sync if null
- id: "customfield_14388"
name: "Notes"
type: "text"
required: false # ← Won't block sync if empty

3. Validate Before Production​

# Test validation without making changes
pnpm run dev -- --dry-run

4. Document Your Fields​

fields:
- id: "customfield_14376"
name: "Impact"
type: "number"
required: true
description: "RICE Impact score - How many people affected?"

Disabling Validation​

If you don't want field validation, simply omit the fields section:

sync:
direction: bidirectional
jql: "project = MTT"

mappings:
- jpd: "fields.summary"
github: "title"

# No fields section = no validation

Troubleshooting​

"No issues found in project"​

Cause: Project is empty or JQL is incorrect
Fix: Create at least one issue in the project

"Field has type 'null' but expected 'text'"​

Cause: Field exists but is empty on the sample issue
Fix: Either:

  • Populate the field on at least one issue
  • Mark the field as required: false

"Could not determine project key"​

Cause: JQL doesn't include project = X clause
Fix: Add project key to JQL or set JPD_PROJECT_KEY env var

Future Enhancements​

🚧 Automatic Field Creation (requires admin permissions)
🚧 Field Value Validation (ranges, patterns, etc.)
🚧 Custom Validation Rules (via functions)
🚧 Bulk Field Discovery (scan all issues)

Example: Complete Config​

sync:
direction: bidirectional
jql: "project = MTT"

mappings:
- jpd: "fields.summary"
github: "title"

- jpd: "fields.customfield_14377[0].value"
github: "labels"
template: "{{fields.customfield_14377[0].value | slugify}}"

fields:
# Core RICE fields
- id: "customfield_14377"
name: "Theme"
type: "multiselect"
required: true
description: "Product theme"

- id: "customfield_14376"
name: "Impact"
type: "number"
required: true
description: "RICE Impact (0-10)"

- id: "customfield_14379"
name: "Reach"
type: "number"
required: true
description: "RICE Reach (users/quarter)"

- id: "customfield_14388"
name: "Notes"
type: "text"
required: false
description: "Optional notes"

See Also​