aboutsummaryrefslogtreecommitdiff
path: root/scripts/README.org
blob: 0f180c58382166d90c63cb3d00590edd73a47d66 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#+TITLE: Pearl Scripts
#+AUTHOR: Craig Jennings

* Purpose

This file is the single home for documentation about the helper scripts under
=scripts/=. These scripts aren't part of pearl.el itself. They're development
and setup tooling that sits alongside the package: workspace seeding, coverage
reporting, and whatever else lands here later. Each script gets its own heading
below with what it's for, how to run it, and any notes worth knowing before you
use it. When you add a script, add a heading here too.

* seed_pearl_workspace.py

** Purpose

Brings a Linear workspace up to Pearl's dogfooding conventions in one run:

- a "Pearl" team whose columns are the six Agile states (Icebox, Triage,
  Backlog, In Progress, Done, Canceled),
- a "Pearl" project inside that team,
- three Custom Views: Pearl Open Issues, Pearl Icebox, Pearl Inbox.

It's idempotent. It reconciles against whatever's already there by name, so a
second run changes nothing. It's reusable for us and for anyone standing up the
same setup.

** Usage

The script reads the Linear API key from the =LINEAR_API_KEY= environment
variable.

#+begin_src bash
  # preview the plan without changing anything
  LINEAR_API_KEY=lin_api_... python3 scripts/seed_pearl_workspace.py --dry-run

  # run it
  LINEAR_API_KEY=lin_api_... python3 scripts/seed_pearl_workspace.py
#+end_src

Run the tests with pytest:

#+begin_src bash
  pytest scripts/tests/test_seed_pearl_workspace.py
#+end_src

The personal key lives in a gitignored =apikey.txt= at the repo root, never in
the repo. A convenient way to pass it:

#+begin_src bash
  LINEAR_API_KEY="$(tr -d '[:space:]' < apikey.txt)" python3 scripts/seed_pearl_workspace.py
#+end_src

** Notes

- *Column types are chosen for board order.* Linear's board orders columns by
  type category first (backlog before unstarted), then by position within a
  category, so position alone can't move a column across a type boundary. To get
  Icebox, Triage, Backlog all left of In Progress in that order, Icebox and
  Triage are the backlog type and Backlog is the unstarted state (rendered last
  in the pre-work group). Backlog being the unstarted state also satisfies
  Linear's rule that a team keep one.

- *Reconcile, not create-from-scratch.* Linear's =teamCreate= seeds its own
  default columns, and Linear dedups state names case-insensitively, so a naive
  "create all six" run collides with the defaults. The script reconciles by
  name: it reuses a same-named (or default-aliased) state of the right type, and
  creates only what's genuinely missing. On a fresh team Icebox takes over the
  default backlog "Backlog" and Backlog takes over the unstarted "Todo".

- *Wrong-type columns are recreated.* A state's type is immutable
  (=workflowStateUpdate= takes name/color/description/position only), so a column
  found with the wrong type can't be fixed in place. The script creates a fresh
  state with the right type, moves the old state's issues onto it, and archives
  the old one. The phases are ordered so a new unstarted state exists before the
  old unstarted one is archived, and so a name is freed before another column
  reuses it. This is what lets a re-run heal a workspace seeded under the older
  type layout.

- *The Duplicate state is left alone.* It's reserved and Linear hides it in the
  board UI; the script reports it as a leftover rather than touching it.

- *Positions are set in a final pass with distinct nonzero values.* Linear
  ignores a 0.0 position and appends a freshly-created state at a high one, so
  the script sets positions after the states exist.

- *Grouping isn't set at view-create time.* Linear's =CustomViewCreateInput= has
  no grouping field, so Pearl Open Issues is created with its filter only. Group
  it by category in pearl with =pearl-set-grouping=, or in the Linear UI.

- *New issues default to Triage, not Backlog.* The script points the team's
  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

The batch helper behind =make coverage-summary=. It parses the SimpleCov JSON
that =make coverage= writes and prints a terminal summary: per-file covered and
total executable lines with a percent (worst-covered first), plus a
line-weighted project figure. Without it, =make coverage= reports little more
than the HTML report's file size.

** Usage

#+begin_src bash
  make coverage           # run tests with coverage, then print the summary
  make coverage-summary   # just re-print the summary from the last report
#+end_src

It's invoked from the Makefile (=coverage= and =coverage-summary= targets) with
=emacs -batch -L scripts -l coverage-summary=, so there's no need to call it
directly.