Bug Tracking for GitHub Issues, Without Paying for Jira

· 5 min read · Joshua Carbajosa

Most advice about bug tracking assumes you have a bug tracker. If your team lives in GitHub, you already do — it's the Issues tab, and it is genuinely good at the job. What GitHub doesn't give you is the thing that happens before a bug exists: a record of what was tested, what passed, and what nobody checked.

That gap is why teams end up shopping for Jira and a test management add-on, and then discover the add-on costs more than the tracker. This post is about closing the gap without doing that.

What GitHub Issues already does well

Worth being clear about, because the answer is "more than people give it credit for":

  • Issue templates give every bug the same shape — steps, expected, actual.
  • Labels carry severity and area, and they're filterable.
  • Milestones group work by release.
  • Closing keywords (Fixes #482 in a PR body) link the fix to the report and close it on merge, which is the single most useful automation in any tracker.
  • Projects give you a board if you want one.

For a team of three to fifteen engineers, that is a complete bug tracker. If you're evaluating Jira purely to get a better place to put bugs, you are probably not going to be happier.

What it doesn't do

GitHub tracks defects. It has no concept of a test.

Concretely, there is no built-in answer to any of these:

  • Which checks are we supposed to run before a release?
  • Did anyone run them this time?
  • Which ones passed, and when?
  • Is the thing that broke last month still fixed?
  • What do I send the person asking "is this safe to ship?"

A closed issue tells you a bug was fixed once. It does not tell you the fix is still holding, because nothing re-runs the check. That's the difference between bug tracking and test management, and it's the reason "we use GitHub Issues" quietly turns into "we test whatever we remember to test."

Teams usually patch this with a spreadsheet. Spreadsheets don't fail builds and they don't complain when a row goes stale, so trust in them erodes about two releases after someone forgets to update one.

A workflow that keeps GitHub as the bug tracker

The fix is not to replace Issues. It's to put a thin test-execution layer in front of it, so that failures arrive in GitHub already written up.

1. Write the test cases down somewhere durable

Start with the checks a person actually performs before a release. Not unit tests — those already run in CI. The manual ones: signup works, checkout works, the expired card is rejected, the export downloads.

Each case needs a title, steps, an expected result, and a priority. Twenty cases covering your critical paths beats two hundred covering everything, and you will actually run twenty.

2. Run the suite as a unit, not as a checklist

A run is one pass through the suite at a point in time. It has a date, a person, and a result for every case: pass, fail, or blocked. Recording it as a unit is what makes the history useful later — you can ask "what did we check before v2.4?" and get an answer.

The important part is that a skipped case is visible. A checklist where someone stopped halfway looks identical to one nobody started.

3. File failures as issues, with the steps already in them

This is where the two systems meet. When a case fails, the bug report is already written — it's the test case. The steps to reproduce are the steps you just followed, and the expected result is the one you just didn't get.

Copying that into a GitHub issue by hand is the step everyone skips at 6pm on a release day, which is how failures go unreported. Whatever you use, make this automatic.

A template that matches the shape of a test case helps:

---
name: Failed test case
about: A check that failed during a release run
labels: bug, from-test-run
---

**Case:** <!-- the test case title -->
**Run:** <!-- which release run -->

### Steps
1.
2.

### Expected

### Actual

Add a from-test-run label and you can filter for regressions found during sign-off specifically, which is a genuinely different population from bugs reported by users.

4. Publish one report per release

The last mile is the conversation. Someone always asks whether it's safe to ship, and the honest answer has three parts: what passed, what failed, and what's still open.

That answer should be a link, not a message in a thread. A link can be re-read by someone who wasn't in the channel, and it doesn't get scrolled away.

When you actually do need Jira

It's worth stating plainly, because a post like this can read as anti-Jira and that isn't the point.

Jira earns its keep when several teams need to coordinate on the same backlog, when you need real workflow customisation and approvals, or when someone outside engineering — support, compliance, an auditor — needs to live in the tracker without being handed a GitHub account. Those are real needs, and Jira is good at them.

What doesn't earn its keep is adopting Jira and a test management add-on purely to answer "what did we test," when your code, your PRs, and your bugs are all already in GitHub. That's two subscriptions and a second place to look, bought to solve a problem that sits between them.

Where Signoff fits

Signoff is the layer described above. You write suites of test cases, run them before a release, and each failure files itself as an issue in the GitHub repo you already use — steps and expected result filled in — or as a ticket in Jira if that's where your team is instead. At the end you get one link that says what passed, what didn't, and what's still open.

The bug tracker stays where it is. Nobody has to adopt a second one.

If it's useful, you can also paste a PR diff and get a draft checklist of cases to review before anything saves — helpful when the change is bigger than your existing suite covers.

The short version

If you're on GitHub and shopping for a bug tracker, you probably don't need one. If you're shopping because you can't answer "what was tested before we shipped," that's a different problem, and it's the one worth solving — just not by buying a second tracker to sit next to the one you have.