Milestones 4 and 5: project layer, review gate and serial merge, all measured
This commit is contained in:
109
bin/project-reset
Executable file
109
bin/project-reset
Executable file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Start a project again: close its pages, remove its worktrees, keep its work.
|
||||
|
||||
bin/project-reset <folder> --dry-run
|
||||
bin/project-reset <folder> --yes
|
||||
bin/project-reset <folder> --yes --delete-folder
|
||||
|
||||
What it removes, and nothing else:
|
||||
|
||||
- the project's screen panes in its TUIOS session (the shell pane stays, so
|
||||
the session survives)
|
||||
- the git worktrees Paperclip made for the project's tasks, and the branches
|
||||
those tasks were on
|
||||
|
||||
What it leaves alone: the folder, its `.harness`, its git history, and every
|
||||
Paperclip record — tasks, comments, runs, cost. Paperclip owns those, so a reset
|
||||
here cannot erase the history of what happened; it only clears the machinery.
|
||||
|
||||
`--delete-folder` is the only destructive option and it asks for the folder name
|
||||
to be typed. Without it, nothing outside git and TUIOS is touched.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, os.path.join(HERE, "lib"))
|
||||
import harness as h # noqa: E402
|
||||
import tuios # noqa: E402
|
||||
import project as pj # noqa: E402
|
||||
|
||||
PAGES = ["tree", "reply", "log", "new"]
|
||||
|
||||
|
||||
def main():
|
||||
argv = sys.argv[1:]
|
||||
args = [a for a in argv if not a.startswith("--")]
|
||||
if not args:
|
||||
h.say("usage: bin/project-reset <folder> [--dry-run] [--yes] [--delete-folder]")
|
||||
return 2
|
||||
folder = os.path.abspath(os.path.expanduser(args[0]))
|
||||
dry = "--dry-run" in argv
|
||||
yes = "--yes" in argv
|
||||
delete_folder = "--delete-folder" in argv
|
||||
|
||||
cfg = pj.load(folder)
|
||||
pj.check_machine(cfg)
|
||||
session = cfg["session"]
|
||||
project_id = cfg["paperclip"]["project"]
|
||||
|
||||
tasks = pj.active_tasks(project_id)
|
||||
worktrees = []
|
||||
for t in tasks:
|
||||
full = h.api("GET", "/api/issues/%s" % t["id"])
|
||||
ws = full.get("currentExecutionWorkspace") or {}
|
||||
if ws.get("cwd"):
|
||||
worktrees.append((t["identifier"], ws["cwd"], ws.get("branchName") or ""))
|
||||
|
||||
h.say("project: %s" % project_id)
|
||||
h.say("folder: %s" % folder)
|
||||
h.say("session: %s" % session)
|
||||
h.say("")
|
||||
h.say("would remove:")
|
||||
h.say(" panes: %s in %s" % (", ".join(PAGES), session))
|
||||
for ref, cwd, branch in worktrees:
|
||||
h.say(" worktree: %s (%s, branch %s)" % (cwd, ref, branch or "none"))
|
||||
if delete_folder:
|
||||
h.say(" the folder: %s (including .harness and git history)" % folder)
|
||||
h.say("kept: the Paperclip project, its tasks, comments, runs and cost")
|
||||
|
||||
if dry:
|
||||
h.say("")
|
||||
h.say("dry run: nothing was removed")
|
||||
return 0
|
||||
|
||||
if not yes:
|
||||
h.say("")
|
||||
h.say("Type the folder name to continue: %s" % os.path.basename(folder))
|
||||
typed = input("> ").strip()
|
||||
if typed != os.path.basename(folder):
|
||||
h.say("nothing was removed")
|
||||
return 1
|
||||
|
||||
for name in PAGES:
|
||||
if tuios.close_pane(name, session):
|
||||
h.say("closed pane %s" % name)
|
||||
|
||||
repo = folder
|
||||
for ref, cwd, branch in worktrees:
|
||||
code, out = h.run(["git", "-C", repo, "worktree", "remove", "--force", cwd])
|
||||
h.say("worktree %s: %s" % (ref, "removed" if code == 0 else out.strip()[:120]))
|
||||
if branch:
|
||||
code, out = h.run(["git", "-C", repo, "branch", "-D", branch])
|
||||
h.say("branch %s: %s" % (branch, "deleted" if code == 0 else out.strip()[:120]))
|
||||
|
||||
if delete_folder:
|
||||
h.say("")
|
||||
h.say("Type the folder name again to delete %s: " % folder)
|
||||
typed = input("> ").strip()
|
||||
if typed != os.path.basename(folder):
|
||||
h.say("folder kept")
|
||||
return 0
|
||||
code, out = h.run(["rm", "-rf", folder])
|
||||
h.say("folder %s" % ("deleted" if code == 0 else "not deleted: " + out.strip()))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
h.main_guard(main)
|
||||
Reference in New Issue
Block a user