Back to Rocket Chat

todo-issue

scripts/todo-issue/README.md

8.4.07.6 KB
Original Source

todo-issue

Scans code for TODO comments and automatically creates, closes, updates, and references GitHub Issues.

Runs as a GitHub Actions workflow via Bun with a single dependency (parse-diff).

How it works

When code is pushed to develop, the script diffs the changes and:

  • Creates a new issue for each new TODO comment
  • Closes the issue when a TODO is removed
  • Updates the issue title when a TODO is edited (detected via similarity matching)
  • References an existing issue when a duplicate TODO is added (adds a comment instead of creating a duplicate)

Every issue created by the script receives the todo label, which is also used to efficiently query only relevant issues.

TODO syntax

Any comment style works (//, #, --, /* */, etc.) as long as only symbols and whitespace appear before the TODO keyword. The keyword is case-insensitive.

Examples

Minimal -- title only:

ts
// TODO: Fix the race condition in token refresh

Extracted data:

FieldValue
TitleFix the race condition in token refresh
Body(none)
Labelstodo

With body -- continuation lines using the same comment prefix:

ts
// TODO: Refactor the auth flow
// The current token refresh logic has race conditions
// when multiple tabs are open simultaneously

Extracted data:

FieldValue
TitleRefactor the auth flow
BodyThe current token refresh logic has race conditions
when multiple tabs are open simultaneously
Labelstodo

The body stops at the first line that doesn't share the same comment prefix or is empty.


With custom labels:

ts
// TODO: Make this button red [frontend] [ui]

Extracted data:

FieldValue
TitleMake this button red
Body(none)
Labelstodo, frontend, ui

Labels are extracted from [square brackets] at the end of the title. The todo label is always included.


Full example -- body + labels in different languages:

python
# TODO: Add retry logic for S3 uploads [infra] [backend]
# Currently fails silently on timeout
# See https://github.com/org/repo/issues/42

Extracted data:

FieldValue
TitleAdd retry logic for S3 uploads
BodyCurrently fails silently on timeout
See https://github.com/org/repo/issues/42
Labelstodo, infra, backend

Block comments:

ts
/**
 * TODO: Should we reinvent the wheel here?
 * We already have a good one in @rocket.chat/core
 */

Extracted data:

FieldValue
TitleShould we reinvent the wheel here?
BodyWe already have a good one in @rocket.chat/core
Labelstodo

Assignees

Mention GitHub usernames with @ to automatically assign the issue:

ts
// TODO: Fix flaky test @john-doe [testing]

Extracted data:

FieldValue
TitleFix flaky test
Body(none)
Labelstodo, testing
Assigneesjohn-doe

Mentions in the title are removed from the issue title. Mentions in the body are also collected as assignees but kept in the body text:

ts
// TODO: Migrate to new payments API
// @alice should review the Stripe integration
// @bob handles the webhook setup

Extracted data:

FieldValue
TitleMigrate to new payments API
Body@alice should review the Stripe integration
@bob handles the webhook setup
Labelstodo
Assigneesalice, bob

What is NOT captured

ts
// This is not a TODO because the keyword is not at the start after the prefix
// See the TODO documentation for more info

const todo = 'strings containing TODO are ignored';

// TODONT -- partial keyword matches are ignored

Trigger modes

The workflow supports four modes, configured via workflow_dispatch inputs or automatic push events.

Push (automatic)

Triggers on every push to develop. Compares BEFORE_SHA...GITHUB_SHA to detect added/removed TODOs.

SHA (manual)

Process a specific commit or range of commits.

InputBehavior
a1b2c3dDiffs commit against its parent (a1b2c3d~1...a1b2c3d)
a1b2c3d...f4e5d6aDiffs the full range

Path (manual)

Import all TODOs from a specific file or directory:

apps/meteor/client
packages/core-typings/src/IMessage.ts

Only creates issues (no close/update). Skips TODOs that already have a matching issue.

Import all (manual)

Scans the entire codebase for TODOs. Only creates issues for TODOs that don't already have a matching issue. Use with caution on large codebases.

Matching logic

The script compares found TODOs against existing issues using:

  1. Exact title match -- identical titles are considered the same TODO
  2. Similarity match -- titles within 80% Levenshtein similarity are considered the same TODO (catches typo fixes and small edits)

When a TODO is both added and deleted in the same diff:

  • Same title -- treated as a move (no action)
  • Similar title -- treated as an edit (updates the existing issue title)

When a new TODO matches an existing open issue, a reference comment is added to the issue instead of creating a duplicate.

Rate limiting

The script reads x-ratelimit-remaining and x-ratelimit-reset from GitHub API response headers and automatically waits when approaching the limit.

Project structure

scripts/todo-issue/
├── package.json
├── tsconfig.json
└── src/
    ├── index.ts        # Entry point, config loading, diff resolution, orchestration
    ├── types.ts        # Shared interfaces (Config, TodoItem, GitHubIssue, MatchResult)
    ├── diff.ts         # Diff parsing (parse-diff), TODO extraction, body/label parsing
    ├── matcher.ts      # Match found TODOs against existing issues
    ├── similarity.ts   # Levenshtein distance and similarity check
    └── github.ts       # GitHub API (REST + GraphQL), rate limiting, issue CRUD