Skip to content

feat: add import#4

Open
tbinna wants to merge 1 commit into
mainfrom
add-import
Open

feat: add import#4
tbinna wants to merge 1 commit into
mainfrom
add-import

Conversation

@tbinna

@tbinna tbinna commented Jun 17, 2026

Copy link
Copy Markdown
Member

Closes #3

Summary by CodeRabbit

  • New Features

    • Added import command to CLI for importing Jira data from artifacts with space selection and batching support.
    • Import configuration now supports environment variables and command-line flags for target site, credentials, artifact path, and space selection.
  • Documentation

    • Updated README with import command details, including behavior description, flags, environment variables, and configuration instructions.
  • Tests

    • Added comprehensive test coverage for import workflows and Jira operations.
  • Chores

    • Updated .gitignore to exclude export and cache files.

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@tbinna, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 10 minutes and 42 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 17f014af-be08-466e-a7c9-f73f9c0b539b

📥 Commits

Reviewing files that changed from the base of the PR and between 2f17e90 and 73c2471.

📒 Files selected for processing (26)
  • .gitignore
  • README.md
  • src/cli.test.ts
  • src/cli/cli.service.ts
  • src/errors.ts
  • src/export/export.service.test.ts
  • src/export/export.service.ts
  • src/export/jira.service.ts
  • src/import/import.formatter.ts
  • src/import/import.model.ts
  • src/import/import.plan.test.ts
  • src/import/import.plan.ts
  • src/import/import.service.test.ts
  • src/import/import.service.ts
  • src/import/index.ts
  • src/import/jira.service.test.ts
  • src/import/jira.service.ts
  • src/shared/app/app.model.ts
  • src/shared/artifact/artifact.model.ts
  • src/shared/artifact/artifact.reader.test.ts
  • src/shared/config/config.model.ts
  • src/shared/config/import.config.ts
  • src/shared/config/index.ts
  • src/shared/jira/jira.client.test.ts
  • src/shared/jira/jira.client.ts
  • src/shared/jira/jira.model.ts
📝 Walkthrough

Walkthrough

This PR implements the ifj import CLI subcommand for migrating Intercom-for-Jira data into a target Jira Cloud site. It adds ImportConfig, ImportService orchestration, ImportJiraService (with bulk task polling), assessImportPlan, formatImportSummary, new JiraClient operations, artifact model validation tightening, and shared property key constants, wired into the CLI and documented in README.

Changes

Import Command Feature

Layer / File(s) Summary
Shared schemas and property key constants
src/shared/app/app.model.ts, src/export/jira.service.ts, src/shared/jira/jira.model.ts, src/shared/artifact/artifact.model.ts, src/shared/config/config.model.ts, src/errors.ts, src/shared/artifact/artifact.reader.test.ts
Moves spaceConfigurationPropertyKey/conversationLinksPropertyKey to shared app model, renames JiraCredentials.sourcesiteUrl, adds ConversationId validation and workItemKey prefix check to WorkItemConversationLinksRecord, makes space list normalization uppercase-first, and adds "import.bulkTaskFailed" error code; artifact reader tests extended for new validations.
Jira model extensions and JiraClient new operations
src/shared/jira/jira.model.ts, src/shared/jira/jira.client.ts, src/shared/jira/jira.client.test.ts
Adds Jira property/task schemas (JiraJsonPropertyValue, JiraIssuePropertyUpdate, BulkFetchWorkItemsRequest/Response, BulkIssuePropertiesRequest, JiraTaskStatus/JiraTaskResponse); extends JiraClient with writeProjectProperty, bulkFetchWorkItems, submitIssuePropertyBulkTask, getTask; sets redirect: "manual" on fetch layer; derives API URLs from siteUrl. Tests cover new bulk task submission and task retrieval.
Export service compatibility updates
src/export/export.service.ts, src/export/export.service.test.ts
Updates ExportService.layer to pass siteUrl to JiraClient.layer; refactors test mocks to use a shared defaultJiraClient spread extended with the new interface methods.
Import config, data model, and formatter
src/shared/config/import.config.ts, src/shared/config/index.ts, src/import/import.model.ts, src/import/import.formatter.ts
Adds ImportConfig interface and effect Config schemas for all import env vars (IMPORT_TARGET, IMPORT_USER, IMPORT_API_TOKEN, IMPORT_ARTIFACT_PATH, IMPORT_SPACES); adds all import domain interfaces; adds formatImportSummary.
ImportJiraService implementation and tests
src/import/jira.service.ts, src/import/jira.service.test.ts
New ImportJiraService backed by JiraClient implementing admin verification, space existence (case-insensitive), configuration write, work-item resolution via chunked bulk fetch, and bulk task submission/polling with tagged-union result validation (Success/Failed/Unknown). Tests cover case-insensitive matching, key ordering, empty success results, failed-entity errors, and unrecognized payload errors.
Import plan assessment and tests
src/import/import.plan.ts, src/import/import.plan.test.ts
assessImportPlan validates manifest presence, derives available spaces from artifact records, selects/normalizes configured spaces (or defaults to all), builds per-space plans, emits SAME_SITE_IMPORT warnings, and surfaces absent selections as skippedSpaces. Two tests verify default and explicit selection behaviors.
ImportService orchestration and tests
src/import/import.service.ts, src/import/import.service.test.ts, src/import/index.ts
Full import orchestration: mutable state, per-space configuration write, work-item link batching (100 items), conversation ID deduplication, skip/failure tracking, importProgram top-level effect, layerNoDeps/layer constructors. Four integration tests cover operation ordering, deduplication, batching/skips, and error propagation.
CLI import subcommand wiring and tests
src/cli/cli.service.ts, src/cli.test.ts
Adds importCommand with full flag schema (artifact path, target, user, API token, spaces, --json); extends makeCommand/runProgram/CliService.layerNoDeps/CliService.layer for the import service; new CLI end-to-end test exercises the import command with env-variable artifact path fallback.
README documentation and .gitignore
README.md, .gitignore
Adds full "Import" section (auth, space selection, batching, flags, env vars), updates Getting Started examples with separate source/target tokens, adds INSPECT_ARTIFACT_PATH note; adds .pnpm-store to .gitignore.

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant CLI as CliService (import command)
  participant ImportService
  participant ImportJiraService
  participant JiraClient
  participant JiraAPI as Jira Cloud API

  User->>CLI: ifj import --target --user --api-token --space
  CLI->>ImportService: run
  ImportService->>JiraClient: verifyGlobalAdmin
  JiraClient->>JiraAPI: GET /mypermissions
  JiraAPI-->>JiraClient: permissions
  ImportService->>ImportService: assessImportPlan(records)
  loop for each planned space
    ImportService->>JiraClient: targetSpaceAvailable(spaceKey)
    JiraClient->>JiraAPI: GET /project
    JiraAPI-->>JiraClient: projects list
    ImportService->>JiraClient: writeProjectProperty(spaceKey, config)
    JiraClient->>JiraAPI: PUT /project/{key}/properties/{propKey}
    loop batches of 100 work-item link records
      ImportService->>JiraClient: bulkFetchWorkItems(keys)
      JiraClient->>JiraAPI: POST /issue/bulkfetch
      JiraAPI-->>JiraClient: issues[]
      ImportService->>JiraClient: submitIssuePropertyBulkTask(propKey, updates)
      JiraClient->>JiraAPI: POST /issue/properties/multi
      JiraAPI-->>JiraClient: 303 Location
      loop poll every 2s
        ImportService->>JiraClient: getTask(location)
        JiraClient->>JiraAPI: GET task URL
        JiraAPI-->>JiraClient: JiraTaskResponse
      end
    end
  end
  ImportService-->>CLI: ImportSummary
  CLI-->>User: formatted summary (human or JSON)
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related issues

  • #3 (Implement import command): This PR directly implements all objectives in issue #3 — the ifj import CLI subcommand, artifact validation, space selection/normalization, sequential space processing, bulk API batching, partial failure handling, Effect-TS architecture, and progress/summary output.

Possibly related PRs

  • toolsplus/intercom-for-jira-migration#2: This PR extends CliService, JiraClient, and AppErrorCode first established by PR #2 (the export command implementation), and adds ImportService alongside the existing ExportService in the same service layer pattern.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add import' directly describes the main change—adding the import feature/command—which aligns with the primary objective of this pull request.
Linked Issues check ✅ Passed All major coding requirements from issue #3 are implemented: import command with CLI integration, artifact validation, space selection via flags, sequential space/link processing, batch-based work-item resolution and link writing, graceful failure handling with detailed outcomes, environment variable support, Effect-TS architecture with modular services, formatted output (human/JSON), Jira bulk task polling, and post-import reconnection guidance.
Out of Scope Changes check ✅ Passed All changes are scoped to import feature implementation or necessary shared infrastructure refactoring. The refactored property key exports, JiraClient extensions, and artifact model enhancements directly support import requirements; .gitignore and README updates document the new feature.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (3)
src/import/import.plan.test.ts (1)

25-98: ⚡ Quick win

Add direct tests for manifest gating and same-site warning paths.

Current coverage is solid for space selection, but it misses the two critical planner branches: fatal artifact.manifestMissing and SAME_SITE_IMPORT warning emission.

Suggested additions
+  it.effect("fails when first record is not a manifest", () =>
+    Effect.gen(function* () {
+      const exit = yield* Effect.exit(
+        assessImportPlan(defaultConfig, [
+          {
+            type: "spaceConfiguration",
+            spaceKey: "ENG",
+            configuration: { enabled: true },
+          },
+        ]),
+      );
+      expect(exit._tag).toBe("Failure");
+    }),
+  );
+
+  it.effect("emits SAME_SITE_IMPORT warning for same source and target", () =>
+    Effect.gen(function* () {
+      const plan = yield* assessImportPlan(
+        { ...defaultConfig, target: "https://source.atlassian.net" },
+        artifact(),
+      );
+      expect(plan.warnings).toMatchObject([{ code: "SAME_SITE_IMPORT" }]);
+    }),
+  );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/import/import.plan.test.ts` around lines 25 - 98, The test suite for the
import assessment currently covers space selection scenarios but is missing
tests for two critical code paths: the artifact.manifestMissing fatal error case
and the SAME_SITE_IMPORT warning emission. Add two new it.effect test cases
within the describe block that test the assessImportPlan function behavior when
the artifact lacks a manifest (should result in a fatal error) and when a
same-site import scenario occurs (should emit a warning), ensuring these edge
cases are properly validated alongside the existing space selection tests.
src/import/jira.service.ts (1)

217-220: 💤 Low value

Unused spaceKey parameter in writeWorkItemConversationLinks.

The service interface declares spaceKey as a parameter (line 217-218), but the implementation ignores it (line 233 uses _spaceKey). If this parameter is intentionally reserved for future use (e.g., logging, metrics, or scoping), consider documenting that intent. Otherwise, remove it from the interface to avoid confusion.

Also applies to: 233-234

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/import/jira.service.ts` around lines 217 - 220, The
`writeWorkItemConversationLinks` method declares a `spaceKey` parameter that is
not actively used in the implementation (notice the underscore prefix convention
`_spaceKey` at line 233-234 indicates unused parameters). Either remove the
`spaceKey` parameter from both the interface declaration at lines 217-218 and
the implementation at lines 233-234, or if this parameter is reserved for future
use such as logging or metrics, add a clear documentation comment explaining its
intended purpose in the interface declaration.
src/shared/jira/jira.client.test.ts (1)

463-490: ⚡ Quick win

Add a negative regression test for cross-origin task locations.

This test block verifies only the happy path. Please add a case asserting getTask(...) fails with jira.malformed when the task URL origin differs (guarded at Line 381 in src/shared/jira/jira.client.ts), so SSRF protection can’t regress silently.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/shared/jira/jira.client.test.ts` around lines 463 - 490, Add a new
negative regression test case in the test file following the existing happy path
test that verifies the getTask method rejects cross-origin task locations. The
test should invoke getTask with a URL that has a different origin than the
configured Jira instance (e.g., a URL from a different domain) and assert that
it fails with a jira.malformed error, ensuring the SSRF protection guard at Line
381 in src/shared/jira/jira.client.ts cannot regress silently.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/import/import.plan.ts`:
- Around line 27-29: The sameSiteWarning function performs a raw string
comparison between source and target URLs without normalization, which allows
semantically identical URLs with minor differences (such as trailing slashes or
casing variations) to bypass the SAME_SITE_IMPORT warning. Normalize both the
source and target parameters before the comparison in the sameSiteWarning
function (for example, by converting to lowercase and removing trailing
slashes). Apply the same normalization logic to the other location mentioned at
line 84 to ensure consistent URL comparison behavior throughout the import plan
logic.

In `@src/import/import.service.ts`:
- Around line 64-83: The summaryFromState function applies detailLimit to the
warnings field by slicing it, but the skippedSpaces, failedSpaceConfigurations,
skippedWorkItemLinks, and failedWorkItemLinkBatches fields are included without
truncation. Apply the same slice(0, detailLimit) approach to each of these four
fields in the summaryFromState function to ensure they are consistently limited
and prevent the summary from exceeding the intended size constraints.

In `@src/import/jira.service.ts`:
- Around line 115-136: In the resolveWorkItems function, the byKey map is keyed
by the canonical item keys returned from Jira's API, but the lookup attempts to
match against the originally requested keys which may differ in casing.
Normalize both sides of the comparison by converting keys to uppercase: when
creating the byKey map, use item.key.toUpperCase() as the map key, and when
performing the lookup with byKey.get(requestedKey), pass
requestedKey.toUpperCase() instead to ensure case-insensitive matching works
correctly regardless of the case variant of the requested key.

In `@src/shared/jira/jira.client.ts`:
- Around line 337-343: The numeric conversion of propertyUpdate.issueId lacks
validation before calling Number(), which could result in NaN or precision loss
if the issueId is not a valid numeric string. Before mapping over
propertyUpdates and converting issueId with Number() in the
HttpClientRequest.schemaBodyJson call, add validation to ensure each issueId is
a safe integer. This can be done by checking that the issueId string can be
safely parsed as an integer using Number.isSafeInteger() after conversion, or by
validating the string format before conversion to prevent data corruption from
invalid issue targeting.

---

Nitpick comments:
In `@src/import/import.plan.test.ts`:
- Around line 25-98: The test suite for the import assessment currently covers
space selection scenarios but is missing tests for two critical code paths: the
artifact.manifestMissing fatal error case and the SAME_SITE_IMPORT warning
emission. Add two new it.effect test cases within the describe block that test
the assessImportPlan function behavior when the artifact lacks a manifest
(should result in a fatal error) and when a same-site import scenario occurs
(should emit a warning), ensuring these edge cases are properly validated
alongside the existing space selection tests.

In `@src/import/jira.service.ts`:
- Around line 217-220: The `writeWorkItemConversationLinks` method declares a
`spaceKey` parameter that is not actively used in the implementation (notice the
underscore prefix convention `_spaceKey` at line 233-234 indicates unused
parameters). Either remove the `spaceKey` parameter from both the interface
declaration at lines 217-218 and the implementation at lines 233-234, or if this
parameter is reserved for future use such as logging or metrics, add a clear
documentation comment explaining its intended purpose in the interface
declaration.

In `@src/shared/jira/jira.client.test.ts`:
- Around line 463-490: Add a new negative regression test case in the test file
following the existing happy path test that verifies the getTask method rejects
cross-origin task locations. The test should invoke getTask with a URL that has
a different origin than the configured Jira instance (e.g., a URL from a
different domain) and assert that it fails with a jira.malformed error, ensuring
the SSRF protection guard at Line 381 in src/shared/jira/jira.client.ts cannot
regress silently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3073dab6-34e2-4172-9fee-f3a1b263ca0c

📥 Commits

Reviewing files that changed from the base of the PR and between efa7db0 and 2f17e90.

📒 Files selected for processing (26)
  • .gitignore
  • README.md
  • src/cli.test.ts
  • src/cli/cli.service.ts
  • src/errors.ts
  • src/export/export.service.test.ts
  • src/export/export.service.ts
  • src/export/jira.service.ts
  • src/import/import.formatter.ts
  • src/import/import.model.ts
  • src/import/import.plan.test.ts
  • src/import/import.plan.ts
  • src/import/import.service.test.ts
  • src/import/import.service.ts
  • src/import/index.ts
  • src/import/jira.service.test.ts
  • src/import/jira.service.ts
  • src/shared/app/app.model.ts
  • src/shared/artifact/artifact.model.ts
  • src/shared/artifact/artifact.reader.test.ts
  • src/shared/config/config.model.ts
  • src/shared/config/import.config.ts
  • src/shared/config/index.ts
  • src/shared/jira/jira.client.test.ts
  • src/shared/jira/jira.client.ts
  • src/shared/jira/jira.model.ts

Comment thread src/import/import.plan.ts
Comment thread src/import/import.service.ts
Comment thread src/import/jira.service.ts
Comment thread src/shared/jira/jira.client.ts
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.

Implement import command

1 participant