Skip to content

feat: Jira custom field importer CLI tool#11

Merged
shannonwho merged 11 commits intomainfrom
feature/jira-custom-field-importer
May 4, 2026
Merged

feat: Jira custom field importer CLI tool#11
shannonwho merged 11 commits intomainfrom
feature/jira-custom-field-importer

Conversation

@shannonwho
Copy link
Copy Markdown
Collaborator

@shannonwho shannonwho commented May 4, 2026

Closes https://linear.app/linear/issue/SOL-337/precisely-jira-required-custom-field-import-after-sync

Summary

  • Adds a new standalone CLI tool scripts/jira-custom-field-importer that reads specified Jira custom fields and appends their values into matching Linear issue descriptions as labeled markdown sections (e.g. Acceptance Criteria)
  • Supports field lookup by Jira field key (customfield_10316) or display name
  • Posts an activity comment on each updated Linear issue linking back to the source Jira ticket
  • Upserts on re-runs: updates the section in-place if the Jira value has changed, skips if unchanged
  • Recovers missed comments from previous runs without duplicating them

How it works

  1. Fetches all Linear issues for a configured team
  2. Matches each Linear issue to its Jira counterpart via attachment URL (Linear's native Jira sync stores the Jira URL on the issue) or by identifier
  3. Reads the configured custom fields from Jira (supports ADF and plain text values, resolves field display names to keys automatically)
  4. Upserts each field as a **Label**\nvalue section in the Linear description
  5. Posts a comment in the Linear activity feed: 🤖 Jira Custom Field Importer synced Acceptance Criteria from ST-12

Test plan

  • npm install completes with 0 vulnerabilities
  • npm run build compiles with no TypeScript errors
  • npm run dev -- validate confirms API connections to both Linear and Jira
  • npm run dev -- sync --dry-run --verbose logs expected matches and field values without writing anything
  • npm run dev -- sync updates Linear descriptions and posts activity comments
  • Re-running sync with unchanged Jira data skips all issues (no duplicate sections or comments)
  • Updating a Jira custom field value and re-running sync replaces the old value in the Linear description and posts a new comment

🤖 Generated with Claude Code

Shannon Hu and others added 9 commits April 15, 2026 14:32
…el permissions

Introduces a hierarchical allowlist model with field-level permission grants.

- AllowlistGroup / AllowlistLeaf types with unlimited nesting depth
- linearTeamId: all members of a Linear team auto-match the group; membership
  fetched at startup via getTeamMembers and refreshed every 4 hours
- Four permissions: labels, sla, priority, slaBaseline (clock anchor — most restricted)
- Union resolution: user matching multiple entries receives the most permissive union
- Partial authorization: only unauthorized fields are reverted per webhook event
- Backward compatible: flat leaf entries with no permissions default to all four
- 36-case authorization test suite covering inheritance, union, partial auth, and
  linearTeamId resolution

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
getTeamMembers now detects whether the configured value is a UUID or a
short team key (e.g. "ADM", "ENG"). Keys use the teams(filter:{key:{eq:}})
query; UUIDs use the existing team(id:) query.

Previously, passing a team key to team(id:) caused "Entity not found" errors
at startup, leaving the team member cache empty and blocking all team-based
authorization until the next restart.

Docs updated in README and IMPLEMENTATION_GUIDE to recommend the team key
format and explain where to find it in the Linear UI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rations API

- Fetch SLA rules from Linear's slaConfigurations API at startup instead of
  reading them from the slaRules array in config.json; refresh every 4 hours
  alongside the team member cache
- Build a team ancestor map at startup (getAllTeams + parent chain walk) so
  child-team issues (BAC, MOB) automatically match parent-team SLA rules (ENG)
  without hardcoding team IDs in slaTeamIds
- Fix createdAt: null breaking SLA correction — pass createdAt in every
  updateCache call; fall back to liveIssue.createdAt in the setTimeout path
  for issues not seeded at startup
- Optimize priority-change SLA correction: when a rule match is computable
  from webhook data alone, skip the live issue fetch and reduce the wait from
  2500ms to 1000ms (fast path); keep 2000ms + live fetch for the no-rule fallback
- Allow empty protectedLabels — protection scope can now be driven entirely
  by slaConfigRules without requiring a label-based trigger
- Add explore-sla-config.ts script for ad-hoc testing of the slaConfigurations API

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All conflicts resolved by keeping feature branch — our version is the
superset of main's squashed PR #6 (hierarchical auth + slaRules) plus
the new slaConfigurations API work. No functionality changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New standalone tool that reads specified Jira custom fields and appends
their values to matching Linear issue descriptions as labeled sections
(e.g. "Acceptance Criteria"). Supports field resolution by key or display
name, idempotent re-runs, dry-run mode, and all three matching strategies.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Posts a comment on each updated Linear issue linking back to the source
Jira ticket, so the import is visible in the issue activity feed.
Adds a README covering setup, config reference, matching strategies,
usage, env vars, and troubleshooting.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the idempotency check with a proper upsert: if a section
heading already exists in the Linear description but the Jira value
has changed, the section is updated in-place rather than skipped.
Also fixes comment posting to check success flag and recover missed
comments from previous runs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@linear-code
Copy link
Copy Markdown

linear-code Bot commented May 4, 2026

Shannon Hu and others added 2 commits May 4, 2026 14:47
Critical optimizations for large workspaces (30k+ issues):

- Stream Linear issues one page at a time instead of loading all into
  memory — keeps RAM flat regardless of workspace size
- Batch Jira lookups: one JQL IN() call per 100 issues instead of one
  API call per issue (100x fewer Jira API calls)
- Checkpoint/resume: progress saved to sync-checkpoint.json after each
  page; re-running after a crash/interruption resumes from where it
  stopped rather than starting over

Estimated runtime for 30k issues: ~20-30 min vs ~3 hours previously.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@shannonwho shannonwho merged commit d97ba0c into main May 4, 2026
shannonwho added a commit that referenced this pull request May 5, 2026
… fix (#13)

On top of the initial tool (merged via #11), this adds:

- Streaming pagination and batch JQL lookups (~100x fewer Jira API calls)
- Checkpoint/resume for large workspaces (saves progress after every page)
- Upsert behavior: updates description section if Jira value changed
- Activity comment on each updated Linear issue linking back to Jira
- Linear-side scope filters: states, labels, projectName
- Jira-side scope filter: filterJql ANDed into every batch query
- Fix: switch batch search to POST /rest/api/3/search/jql (old endpoint returns 410)
- Fix: add 410 to non-retryable status codes
- Docs: README with performance table, checkpoint/resume, and scope filter examples

Co-authored-by: Shannon Hu <shannon@macbook-pro.lan>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
shannonwho added a commit that referenced this pull request May 6, 2026
* feat(jira-importer): scope filters, batch optimizations, and Jira API fix

On top of the initial tool (merged via #11), this adds:

- Streaming pagination and batch JQL lookups (~100x fewer Jira API calls)
- Checkpoint/resume for large workspaces (saves progress after every page)
- Upsert behavior: updates description section if Jira value changed
- Activity comment on each updated Linear issue linking back to Jira
- Linear-side scope filters: states, labels, projectName
- Jira-side scope filter: filterJql ANDed into every batch query
- Fix: switch batch search to POST /rest/api/3/search/jql (old endpoint returns 410)
- Fix: add 410 to non-retryable status codes
- Docs: README with performance table, checkpoint/resume, and scope filter examples

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs(jira-importer): add OAuth background agent guidance to README

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Shannon Hu <shannon@macbook-pro.lan>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

1 participant