DEV Community

Cover image for Link Tickets to Tests and Wiki in One Git Repo
Weiwen Weng
Weiwen Weng

Posted on Originally published at gitoza.com

Link Tickets to Tests and Wiki in One Git Repo

Most teams don't have a traceability problem. They have a glue problem.

The ticket is in Jira. The spec is in Confluence. The cases are in TestRail or Xray. Last week's run is a spreadsheet someone exported. Every "link" is a URL into another product, another login, another spinner. It looks fine in a slide deck. Day to day it rots: the wiki still points at a ticket that got closed and reopened under a new key; the TMS still lists cases for a story that never shipped.

There's a simpler pattern: keep the whole graph as files in one Git repo. Tickets, wiki pages, test cases, and runs are just YAML on disk. Following a link means opening a file—not waiting on three APIs to agree.

Four kinds of files, one tree

.gitoza/
  tasks/tickets/{project}/{ticket-id}.yaml
  wiki/{folders}/W-xxxxxx.yaml
  test/cases/{project}/…/{case-id}.yaml
  test/runs/R-XXXXXX/
Enter fullscreen mode Exit fullscreen mode

The id is the filename. Tickets look like AUTH-102.yaml. Wiki pages use W-… stems. Runs use readable R-… folder names. Requirement ids on tickets, cases, and runs are the same kind of string you'd put in a TMS field—except they live next to the body, in Git.

Releases can sit beside tickets if you want them. Optional. You don't need a fourth SaaS for the graph to exist.

How the links actually work

You don't paste Jira URLs into Confluence and hope.

In any Markdown body—ticket, wiki, case, or run—you insert a link that searches tickets and wiki pages and writes something like:

  • [[AUTH-102]] — opens the ticket
  • [[wiki:W-ABC123]] — opens the wiki page

Bare [[…]] is a ticket. Prefix wiki: for a page. Unresolved targets get an amber dotted underline, so you see the hole before you sync.

On the ticket itself, related lists come from the same ids: children, cases that test it, runs that cover it. Click a wiki link in a case or run and the page opens. No integration job. No "issue content" macro.

A wiki spec can look like this:

# Lockout after failed logins

Story: [[AUTH-102]]

See also [[wiki:W-ABC123|Auth overview]].
Enter fullscreen mode Exit fullscreen mode

A case carries a requirement_id (tickets and runs can too), so coverage is a field you can search—not a comment someone forgot to update.

Why the click feels instant

SaaS linking is a network sport. Open a story → wait for Confluence → wait for Xray → the related-issues panel flashes empty, then fills, then jumps.

When the YAML is already on disk, following a link is a local lookup. Search and related lists hit an index derived from the files—not a vendor round-trip. Offline still works. Ticket → wiki → run feels like switching files in an IDE, because that's basically what it is.

You still sync when you want the team to see changes. Browsing doesn't wait for that push.

Traceability without a second product

Vendor TMS tools win on links: story → cases → execution. File-based setups need the same discipline—just as fields and filenames, not as glue.

From To How
Wiki spec Ticket [[TICKET-ID]] in the body
Ticket Wiki [[wiki:W-…]]
Ticket Cases / runs requirement ids
Case or run Wiki wiki link in the body
Case Automation filename id tagged on Playwright / Robot

You don't get magic bi-directional sync with Jira out of a text file. You get a graph you can grep, review in a PR, and open with no account. People who push back on "tests in Git" usually aren't wrong about the missing piece: without stable ids and a UI that follows them, it feels incomplete next to Xray. The ids were never the hard part. Putting tickets and wiki in the same tree as the cases is.

The agent can walk the same graph

If the spec, the ticket, and the run are files, an AI IDE can already read them. Useful asks look more like:

  • Which open tickets in auth have no cases?
  • Does this run cover AUTH-102?
  • Which wiki page describes the lockout behavior?

No MCP setup per product. The graph is already in the repo.

What I built for this

I built a desktop app (Gitoza) around this layout: tickets, wiki, cases, and runs in one workspace, with a link picker and related lists on the ticket. Confirm changes before you push. Connect the product repo or a dedicated planning repo—the format doesn't care.

Create a ticket (filename is the id), add a wiki page, insert [[that-id]], put the same requirement id on a case, drop it in a run, click through. Sync when you're ready.

gitoza.com — free for personal use, no account.

Traceability that depends on three SaaS products is an integration project. Traceability that is filenames, [[links]], and requirement ids in one repo is just files.

Top comments (1)

Collapse
 
marcusykim profile image
Marcus Kim

Making the filename the stable ID turns AUTH-102.yaml from documentation into an addressable piece of the product graph, and the amber dotted underline for unresolved [[...]] links catches decay at authoring time instead of during an audit. Reusing requirement_id across cases and runs also makes coverage queryable without relying on someone to maintain a comment or spreadsheet. The main engineering tradeoff is schema evolution: once several teams generate and review this YAML, versioned schemas plus CI validation become essential so Git remains the source of truth rather than a collection of locally valid interpretations.