You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3.1 KiB

+++ title = "Add --xml output format that wraps each ticket section in XML tags" priority = 4 status = "todo" ticket_type = "feature" dependencies = [] +++

Background

From nbd/TODO.md:

Add a --xml output format that prints tickets with XML around each section to make it easier to parse metadata.

Unlike --json (which is a complete, structured parse), the XML format adds lightweight tags around each metadata field in the human-readable output. This makes it trivial for scripts to extract specific fields using simple text tools (e.g., grep, sed, XPath) without pulling in a full JSON parser.

Intended XML format

For a single ticket (nbd read <id> --xml):

<ticket>
  <id>a3f9c2</id>
  <title>Fix login bug</title>
  <priority>8</priority>
  <status>in_progress</status>
  <type>bug</type>
  <dependencies>
    <dep>b7d41e</dep>
    <dep>c9e823</dep>
  </dependencies>
  <body>Users cannot log in with email addresses containing +</body>
</ticket>

For a list (nbd list --xml):

<tickets>
  <ticket>...</ticket>
  <ticket>...</ticket>
</tickets>

Implementation

src/main.rs

Add a global --xml flag to the Cli struct, parallel to --json:

/// Output XML instead of a human-readable table.
#[arg(long, global = true)]
xml: bool,

Precedence: if both --json and --xml are supplied, --json wins (or return an error — TBD, but JSON-first is simpler).

Pass cli.xml through dispatch to every command handler, alongside cli.json.

Each command handler signature gains an xml: bool parameter. When xml is true and json is false, call the new display::print_ticket_xml / display::print_list_xml functions.

src/display.rs

Add:

  • format_ticket_xml(ticket: &Ticket) -> String — serialises a single ticket as XML
  • print_ticket_xml(ticket: &Ticket) — wraps format_ticket_xml + println!
  • format_list_xml(tickets: &[Ticket]) -> String — wraps list in <tickets>
  • print_list_xml(tickets: &[Ticket])

XML escaping: at minimum, escape &, <, >, ", ' in field values. Use a small helper xml_escape(s: &str) -> String rather than pulling in an XML crate.

For dependencies: render each as a <dep> child element.

src/tests.rs

Add unit tests:

  • format_ticket_xml with a ticket that has special characters in the title and body (&, <, >)
  • format_ticket_xml with empty dependencies
  • format_ticket_xml with multiple dependencies
  • format_list_xml with zero and multiple tickets

tests/integration.rs

Add integration tests:

  • nbd read <id> --xml returns valid XML containing the ticket's fields
  • nbd list --xml returns valid XML wrapping multiple tickets
  • nbd create ... --xml returns the created ticket as XML
  • nbd update ... --xml returns the updated ticket as XML

Scope

All commands that support --json should also support --xml:

  • nbd create
  • nbd read
  • nbd list
  • nbd update
  • nbd ready
  • nbd next
  • nbd archive
  • nbd migrate
  • nbd graph (the JSON graph format has a defined structure; XML should mirror it)
  • nbd claude-md (wrap snippet in <snippet> tag)
  • nbd init (wrap root path in <init>)