office --new creates the Paperclip project; the two clean tests written step by step

This commit is contained in:
Sam
2026-11-12 09:36:37 +11:00
parent d2cf643eca
commit 08a4b4e822
9 changed files with 691 additions and 1 deletions

View File

@@ -28,7 +28,10 @@ import tuios # noqa: E402
def parse(argv):
opts = {"folder": ".", "project": "", "session": "", "dry": "--dry" in argv,
"host": "", "no_switch": "--no-switch" in argv}
"host": "", "no_switch": "--no-switch" in argv, "new": ""}
for i, a in enumerate(argv):
if a == "--new" and i + 1 < len(argv):
opts["new"] = argv[i + 1]
args = [a for a in argv if not a.startswith("--")]
if args:
opts["folder"] = args[0]
@@ -42,6 +45,45 @@ def parse(argv):
return opts
def create_project(name, folder, dry):
"""Create a Paperclip project for a folder, with the worktree policy set.
Adopting a folder that Paperclip has never heard of needed two steps before:
make the project in the browser, then run this command. One command is enough.
"""
body = {
"name": name,
"description": "Adopted from %s by bin/office." % folder,
"status": "backlog",
"workspace": {"name": name, "sourceType": "git_repo", "cwd": folder, "isPrimary": True},
"executionWorkspacePolicy": {
"enabled": True,
"defaultMode": "isolated_workspace",
"allowIssueOverride": True,
"workspaceStrategy": {"type": "git_worktree", "baseRef": "main",
"branchTemplate": "{{issue.identifier}}-{{slug}}"},
},
}
if dry:
h.say("would create Paperclip project %r for %s" % (name, folder))
return "(dry run)"
try:
created = h.api("POST", "/api/companies/%s/projects" % h.COMPANY, body)
except h.Refused as exc:
# A project with that name may already exist; adopting it is the right
# thing to do then, not a failure.
try:
for p in h.api("GET", "/api/companies/%s/projects" % h.COMPANY):
if p.get("name") == name:
h.say("project: %s (already in Paperclip)" % name)
return p["id"]
except h.Refused:
pass
raise exc
h.say("project: %s created (%s)" % (name, created.get("id")))
return created.get("id")
def ensure_session(session, folder):
"""Make the session exist. It cannot be shown from here, and that is fine.
@@ -126,6 +168,13 @@ def main():
# so one command takes a person from a folder to a working layout. TUIOS has
# the verb for exactly this; asking the person to run `tuios new` first was
# the step everyone forgot.
if opts["dry"]:
h.say("would create a Paperclip project %r for %s" % (opts["new"] or opts["project"], folder))
h.say("would write %s" % os.path.join(folder, ".harness", "harness.toml"))
h.say("would create or reuse session %r and build eight panes there" % session)
h.say("dry run: nothing was written")
return 0
if not opts["no_switch"]:
ensure_session(session, folder)
@@ -133,6 +182,11 @@ def main():
# Only a note, because the panes are built by the machine that owns them.
h.say("host: %s (build the pages there)" % host)
if opts["new"]:
ref = create_project(opts["new"], folder, opts["dry"])
if not ref:
return 1
opts["project"] = ref
ref = opts["project"]
if not ref and pj.exists(folder):
ref = pj.load(folder)["paperclip"]["project"]