feat: Jira custom field importer CLI tool#11
Merged
shannonwho merged 11 commits intomainfrom May 4, 2026
Merged
Conversation
…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>
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>
5 tasks
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes https://linear.app/linear/issue/SOL-337/precisely-jira-required-custom-field-import-after-sync
Summary
scripts/jira-custom-field-importerthat reads specified Jira custom fields and appends their values into matching Linear issue descriptions as labeled markdown sections (e.g. Acceptance Criteria)customfield_10316) or display nameHow it works
**Label**\nvaluesection in the Linear descriptionTest plan
npm installcompletes with 0 vulnerabilitiesnpm run buildcompiles with no TypeScript errorsnpm run dev -- validateconfirms API connections to both Linear and Jiranpm run dev -- sync --dry-run --verboselogs expected matches and field values without writing anythingnpm run dev -- syncupdates Linear descriptions and posts activity comments🤖 Generated with Claude Code