aboutsummaryrefslogtreecommitdiff
path: root/scripts/README.org
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-06 23:53:52 -0500
committerCraig Jennings <c@cjennings.net>2026-06-06 23:53:52 -0500
commitfef03a1f4f19c45a31928989aecb4ff8a47cea4a (patch)
tree88ad9fa1dad62f4d63f2f3ad0b65a14b39d9079f /scripts/README.org
parent4a4b1bc974a3fdb4d88af3ee575786ca363696e2 (diff)
downloadpearl-fef03a1f4f19c45a31928989aecb4ff8a47cea4a.tar.gz
pearl-fef03a1f4f19c45a31928989aecb4ff8a47cea4a.zip
feat(scripts): import an org backlog into the Pearl workspace
I had 44 open tasks in the org backlog and no way to get them into Linear short of typing each one in by hand. This adds a script that reads the level-2 TODO/DOING headings under the "Pearl Open Work" section and creates one issue per task. The priority cookie maps to Linear priority, a [#D] "someday" task lands in Icebox and the rest in Backlog, tags become labels (missing ones created), and the heading body becomes the description. The discuss/next/cleanup/pearl workflow tags are dropped rather than turned into labels. It skips a task whose title already exists, so a re-run only fills in what's missing, and the two umbrella headings plus the Resolved section are left out. Same shape as the seed script: a pure parser and mapper with no I/O, behind a thin GraphQL client that's the only network boundary, so a fake transport routing on the operation name covers the import end to end. 8 tests across parse, mapping, and the import flow.
Diffstat (limited to 'scripts/README.org')
-rw-r--r--scripts/README.org56
1 files changed, 56 insertions, 0 deletions
diff --git a/scripts/README.org b/scripts/README.org
index e6bacd2..5d5ab6d 100644
--- a/scripts/README.org
+++ b/scripts/README.org
@@ -82,6 +82,62 @@ the repo. A convenient way to pass it:
default new-issue state at Triage (the intake column) after the columns
reconcile, so a fresh issue lands there.
+* import_org_backlog.py
+
+** Purpose
+
+Imports an org-mode backlog into the Pearl Linear workspace. It reads the
+level-2 =TODO=/=DOING= headings under the "Pearl Open Work" section and creates
+one Linear issue per task, carrying the priority, tags, and body across.
+
+The mapping:
+
+- priority cookie =[#A]= .. =[#D]= becomes Linear priority Urgent .. Low,
+- a =[#D]= "someday" task lands in Icebox, everything above it in Backlog,
+- tags become labels (missing ones are created); the =discuss=, =next=,
+ =cleanup=, and =pearl= workflow markers are dropped rather than turned into
+ labels,
+- the heading body becomes the issue description, minus the property drawer and
+ any sub-entries.
+
+It's idempotent: a task whose title already exists is skipped, so a re-run only
+fills in what's missing. The two umbrella headings (the dogfooding parent and
+the manual-testing checklist) and everything under the Resolved section are left
+out.
+
+** Usage
+
+The script reads the Linear API key from =LINEAR_API_KEY= and takes the org file
+as its argument.
+
+#+begin_src bash
+ # preview the tasks without creating anything
+ python3 scripts/import_org_backlog.py todo.org --dry-run
+
+ # run it
+ LINEAR_API_KEY="$(tr -d '[:space:]' < apikey.txt)" python3 scripts/import_org_backlog.py todo.org
+#+end_src
+
+Run the tests with pytest:
+
+#+begin_src bash
+ pytest scripts/tests/test_import_org_backlog.py
+#+end_src
+
+** Notes
+
+- *Dry-run first.* =--dry-run= parses the file and prints each task with its
+ target state and surviving labels, plus the full label set it would create. It
+ touches the network only on a real run, so it's the safe way to confirm scope
+ before importing.
+
+- *Idempotent by title.* The skip check matches on exact issue title. Editing a
+ task's title in the org file and re-running creates a second issue rather than
+ updating the first, so treat titles as stable once imported.
+
+- *Tags are matched case-insensitively.* An existing =Bug= label is reused for a
+ =:bug:= tag; only genuinely new labels are created.
+
* coverage-summary.el
** Purpose