Skip to content

feat: maniphest edit --parent/--unparent and --subtask/--unsubtask - #549

Merged
holmboe merged 1 commit into
mainfrom
t3679-maniphest-edit-add-remove
Sep 29, 2026
Merged

holmboe merged 1 commit into
mainfrom
t3679-maniphest-edit-add-remove

Conversation

@holmboe

@holmboe holmboe commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

Closes #548

maniphest edit could not link two tasks that both already exist: a parent/subtask edge could only be written while creating one of them (maniphest create --parent, or a create spec). So "an existing task belongs under an existing epic" had to be done in the web UI.

What changes

maniphest edit and phabfive edit take four new options:

  • --parent / --unparent add or remove a parent
  • --subtask / --unsubtask add or remove a subtask

Each takes a task monogram or task PHID, repeatable and comma-separated like --attach/--detach, and only a change is sent (parents.add/.remove, subtasks.add/.remove).

$ phabfive edit T3667 T3653 --parent=T3026 --unparent=T3015 --dry-run
[DRY RUN] Would apply to T3667:
  Parents: Added: T3026
  Parents: Removed: T3015
...
  • Resolved up front, once per batch. maniphest.edit accepts an edge to a PHID that does not exist, so this lookup is the only check. An unknown task stops the edit before anything is sent.
  • Local refusals. A task named as its own parent or subtask, or one task named as both a parent and a subtask, is refused for that task with a plain message. Otherwise the server answers Graph cycle detected (type=3, ...) with raw PHIDs. Longer cycles are still left to the server.
  • Retry. The four transactions join IDEMPOTENT_TRANSACTIONS: adding an existing edge or removing a missing one is a no-op.

Verified

  • Against the local Phorge: all four transactions accepted, removing a non-edge is a no-op, self-links and cycles are refused by the server, a bogus PHID is accepted (hence the lookup).
  • Not run against the Phabricator stand-in (make up VERSION=phabricator). The edge fields predate the fork, but that is unverified.
  • tests/test_edit_relations.py (31 unit tests), and a new e2e test test_edit_links_and_unlinks_existing_tasks, run against the local Phorge. Full suite, ruff and mypy are clean.

Mirrors T3679 on the Phabricator instance.

🤖 Generated with Claude Code

A parent/subtask edge could only be written while creating one of the two
tasks, so an existing task could not be put under an existing epic from
the CLI (T3679).

maniphest edit and phabfive edit take --parent and --subtask to add a
link and --unparent and --unsubtask to remove one: a task monogram or
PHID, repeatable and comma-separated like --attach and --detach, sent as
parents.add/.remove and subtasks.add/.remove with only what changes.

maniphest.edit accepts an edge to a PHID that does not exist, so every
task is resolved once for the batch before anything is sent. A task named
as its own parent or subtask, or as both a parent and a subtask, is
refused for that task rather than answered by the server's "Graph cycle
detected". The four transactions join IDEMPOTENT_TRANSACTIONS.

Closes #548

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@holmboe holmboe added enhancement New feature or request app:maniphest labels Sep 29, 2026
@holmboe
holmboe merged commit 1d93184 into main Sep 29, 2026
26 of 30 checks passed
@holmboe
holmboe deleted the t3679-maniphest-edit-add-remove branch September 29, 2026 08:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app:maniphest enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

maniphest edit: --parent/--unparent and --subtask/--unsubtask to link existing tasks

1 participant