diff options
Diffstat (limited to 'scripts/seed_pearl_workspace.py')
| -rw-r--r-- | scripts/seed_pearl_workspace.py | 37 |
1 files changed, 29 insertions, 8 deletions
diff --git a/scripts/seed_pearl_workspace.py b/scripts/seed_pearl_workspace.py index 434a995..4e29b76 100644 --- a/scripts/seed_pearl_workspace.py +++ b/scripts/seed_pearl_workspace.py @@ -4,7 +4,7 @@ Brings a workspace to: - a "Pearl" team whose columns are the six Agile states - (Icebox, Triage Queue, Backlog, In Progress, Done, Canceled), + (Icebox, Triage, Backlog, In Progress, Done, Canceled), - a "Pearl" project inside that team, - three Custom Views: Pearl Open Issues, Pearl Icebox, Pearl Inbox. @@ -15,7 +15,7 @@ live, not assumed): teamCreate seeds its own default columns, a team must keep an unstarted state, and the Duplicate state is reserved. So this script never archives. It renames Linear's defaults into the six Agile columns -- keeping Backlog / In Progress / Done / Canceled, and repurposing the unstarted Todo as -Triage Queue -- and creates only the genuinely-new Icebox. Linear's reserved +Triage -- and creates only the genuinely-new Icebox. Linear's reserved Duplicate state is left alone (it's hidden in the board UI); the script reports any other leftover column for you to tidy. @@ -23,7 +23,7 @@ Positions are set in a second pass with distinct nonzero values, because Linear ignores a 0.0 position and appends a freshly-created state at a high one. Two notes on the result: - - Triage Queue is Linear's "unstarted" type, so pearl's grouped view (which + - Triage is Linear's "unstarted" type, so pearl's grouped view (which orders by state type, then position) lists it after the backlog columns, even though the Linear board itself keeps your column order. - CustomViewCreateInput has no grouping field, so Pearl Open Issues is created @@ -47,11 +47,11 @@ TEAM_KEY = "PEARL" PROJECT_NAME = "Pearl" # The six Agile columns. `sources` names the Linear default state a column is -# reconciled from when it isn't present by its own name yet (Triage Queue takes +# reconciled from when it isn't present by its own name yet (Triage takes # over the unstarted Todo). Positions are distinct and nonzero. TARGET_STATES = [ {"name": "Icebox", "type": "backlog", "color": "#bec2c8", "position": 1.0, "sources": []}, - {"name": "Triage Queue", "type": "unstarted", "color": "#e2e2e2", "position": 2.0, + {"name": "Triage", "type": "unstarted", "color": "#e2e2e2", "position": 2.0, "sources": ["Todo"]}, {"name": "Backlog", "type": "backlog", "color": "#95a2b3", "position": 3.0, "sources": []}, {"name": "In Progress", "type": "started", "color": "#f2c94c", "position": 4.0, "sources": []}, @@ -60,6 +60,10 @@ TARGET_STATES = [ "sources": ["Cancelled"]}, ] +# New issues should land in the intake column, not Backlog. The team's +# defaultIssueState is pointed here after the columns reconcile. +INTAKE_STATE = "Triage" + VIEW_NAMES = ["Pearl Open Issues", "Pearl Icebox", "Pearl Inbox"] @@ -72,7 +76,7 @@ def desired_views(project_id): {"name": "Pearl Icebox", "filterData": {**proj, "state": {"name": {"eq": "Icebox"}}}}, {"name": "Pearl Inbox", - "filterData": {**proj, "state": {"name": {"eq": "Triage Queue"}}}}, + "filterData": {**proj, "state": {"name": {"eq": "Triage"}}}}, ] @@ -141,7 +145,7 @@ class LinearClient: def find_team(self): data = self.execute( - "query Teams { teams { nodes { id key name " + "query Teams { teams { nodes { id key name defaultIssueState { id } " "states { nodes { id name type position } } } } }", {}) return next((t for t in data["teams"]["nodes"] if t["name"] == TEAM_NAME), None) @@ -172,6 +176,12 @@ class LinearClient: "{ workflowStateUpdate(id: $id, input: $input) { success } }", {"id": state_id, "input": {"name": name, "position": position}}) + def set_default_issue_state(self, team_id, state_id): + self.execute( + "mutation TeamUpdate($id: String!, $input: TeamUpdateInput!) " + "{ teamUpdate(id: $id, input: $input) { success } }", + {"id": team_id, "input": {"defaultIssueStateId": state_id}}) + def find_project(self): data = self.execute("query Projects { projects { nodes { id name } } }", {}) return next((p for p in data["projects"]["nodes"] if p["name"] == PROJECT_NAME), None) @@ -204,11 +214,14 @@ def seed(client): if team is None: team = client.create_team() states = client.team_states(team["id"]) # re-fetch: defaults aren't in the create reply + current_default = None else: states = team.get("states", {}).get("nodes", []) + current_default = (team.get("defaultIssueState") or {}).get("id") team_id = team["id"] states_created = [] + resolved = {} for entry in reconcile_state_plan(states): target, match_id = entry["target"], entry["match_id"] if match_id is None: @@ -217,8 +230,15 @@ def seed(client): # Set name + position in one update; a freshly-created state needs the # position pass because Linear appends it at a high position otherwise. client.update_state(match_id, target["name"], target["position"]) + resolved[target["name"]] = match_id leftover = leftover_state_names(states) + # New issues should default to the intake column, not Backlog. + intake_id = resolved.get(INTAKE_STATE) + default_set = bool(intake_id) and intake_id != current_default + if default_set: + client.set_default_issue_state(team_id, intake_id) + project = client.find_project() or client.create_project(team_id) project_id = project["id"] @@ -230,7 +250,8 @@ def seed(client): views_created.append(spec["name"]) return {"team": team_id, "project": project_id, "states_created": states_created, - "views_created": views_created, "leftover_states": leftover} + "views_created": views_created, "leftover_states": leftover, + "default_issue_state": INTAKE_STATE if default_set else "unchanged"} def main(argv=None): |
