Skip to content

feat(import): support issue dependencies in linear CSV import - #1250

Open
SomSamantray wants to merge 3 commits into
linear:masterfrom
SomSamantray:feat/issue-dependencies-import
Open

SomSamantray wants to merge 3 commits into
linear:masterfrom
SomSamantray:feat/issue-dependencies-import

Conversation

@SomSamantray

Copy link
Copy Markdown

Summary

Linear CSV import can now carry issue dependencies. Add optional Blocks and Blocked By columns; each reference resolves to another issue in the same import file, and once every issue is created the links are wired as blocks relations.

A reference that cannot be resolved is a hard error, raised before any issue, team, or label is created. Self-references, dependencies declared in both directions, and duplicate row Ids are rejected the same way. This keeps a re-run from ever duplicating a half-imported backlog, because a bad file never gets far enough to create anything.

Design notes

  • Resolution matches first on the row Id column, then on a case-insensitive title. A dependency expressed in both columns (row A Blocks=B plus row B Blocked By=A) is deduplicated to a single relation.
  • Relation and issue creation share one rate-limit retry wrapper, and the created issue id is read synchronously from the mutation payload rather than issuing a second GraphQL fetch per issue.
  • @linear/sdk already exposes createIssueRelation with a blocks relation type; no SDK change was needed.

Validation

pnpm --filter './packages/import' test passes 27 tests across 3 files (12 pre-existing plus new coverage for parsing, resolution, dedupe, and the validation errors). Typecheck and lint are clean.

Unapplied review findings

  • P2 - packages/import/src/importIssues.ts - Title normalization differs between the importer (strips a leading quote from formula-safe titles) and the resolver (only trims/lowercases), so a reference to a formula-like title can silently fail. Suggested fix: one shared normalization function used for both indexing and matching.
  • P2 - packages/import/src/importIssues.ts - The CreatedIssueIds | undefined union threads an invariant guard through the creation loop, allocating a throwaway Map per issue on dependency-free imports. Suggested fix: hoist the branch so the Map is created once only when dependencies exist.
  • P2 - packages/import/src/importIssues.ts - The rate-limit retry wrapper re-throws while the issue loop re-wraps its call site in an identical catch-and-throw; error.type is read untyped. Suggested fix: an onRetry hook plus type narrowing.
  • P2 - packages/import/src/importIssues.ts - A dependency reference to an archived row (dropped by the importer) aborts the whole import before anything is created. The user must hand-edit the CSV. Suggested fix: warn and skip edges that reference an excluded archived row.
  • P2 - packages/import/src/importIssues.ts - The relation-creation phase (direction of ids, success === false abort, missing-id skip) is not exercised by any test; createRelations is not exported and there is no LinearClient mock harness in the package.
  • P2 - packages/import/src/importIssues.ts - A relation-phase failure (a relation rejected after all issues exist) leaves a partial graph whose natural recovery (re-running the CSV) duplicates every issue. Suggested fix: aggregate relation failures into one error that warns issues were already created.
  • P3 - packages/import/src/importIssues.ts - The rate-limit retry sleeps a fixed 60s and ignores the SDK's parsed retryAfter / requestsResetAt. Suggested fix: honor the server reset hint when present.

Review run: 20260903-091604-01e96716

SomSamantray and others added 3 commits September 3, 2026 09:03
Add optional Blocks and Blocked By columns to the Linear CSV importer so
a backlog can be bootstrapped with its block graph already wired.

References are resolved against the other issues in the same import file
before anything is created, matching first on the row Id column and then
on a case-insensitive title match. An unresolvable or ambiguous reference
aborts the import before any issue is created, so a re-run never
duplicates a half-imported backlog. After creation, the resolved pairs
are emitted as issueRelationCreate mutations with a blocks type, swapping
the ids for Blocked By references. Pairs are canonicalized and
deduplicated so a dependency expressed in both columns is created once,
and each relation result's success flag is checked before the import
reports success.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Address code-review findings on the CSV dependency import feature:

- Resolve and validate dependency references before any workspace mutation
  (team/label/issue creation), so a malformed graph aborts cleanly.
- Reject duplicate row Ids, self-references, and dependencies declared in
  both directions instead of silently collapsing or mis-binding them.
- Check the createIssue success flag and created issue id, throwing when
  the API rejects an issue, so a partial graph is never reported as a
  successful import.
- Add a shared rate-limit retry wrapper for issue and relation creation and
  read the created issue id synchronously instead of issuing a second
  GraphQL fetch per issue.
- Cover Blocked By parsing and the new validation errors in unit tests.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
@changeset-bot

changeset-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: fb0477f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@linear/import Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

This branch has not been deployed

No deployments
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