The communications platform that puts data protection first.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
Rocket.Chat/scripts/todo-issue/README.md

225 lines
7.6 KiB

# todo-issue
Scans code for `TODO` comments and automatically creates, closes, updates, and references GitHub Issues.
Runs as a GitHub Actions workflow via [Bun](https://bun.sh/) 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:
| Field | Value |
| ------ | ----------------------------------------- |
| Title | `Fix the race condition in token refresh` |
| Body | _(none)_ |
| Labels | `todo` |
---
**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:
| Field | Value |
| ------ | ----------------------------------------------------------------------------------------------------- |
| Title | `Refactor the auth flow` |
| Body | `The current token refresh logic has race conditions`<br>`when multiple tabs are open simultaneously` |
| Labels | `todo` |
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:
| Field | Value |
| ------ | ------------------------ |
| Title | `Make this button red` |
| Body | _(none)_ |
| Labels | `todo`, `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:
| Field | Value |
| ------ | ------------------------------------------------------------------------------------ |
| Title | `Add retry logic for S3 uploads` |
| Body | `Currently fails silently on timeout`<br>`See https://github.com/org/repo/issues/42` |
| Labels | `todo`, `infra`, `backend` |
---
**Block comments:**
```ts
/**
* TODO: Should we reinvent the wheel here?
* We already have a good one in @rocket.chat/core
*/
```
Extracted data:
| Field | Value |
| ------ | ------------------------------------------------- |
| Title | `Should we reinvent the wheel here?` |
| Body | `We already have a good one in @rocket.chat/core` |
| Labels | `todo` |
---
### Assignees
Mention GitHub usernames with `@` to automatically assign the issue:
```ts
// TODO: Fix flaky test @john-doe [testing]
```
Extracted data:
| Field | Value |
| --------- | ----------------- |
| Title | `Fix flaky test` |
| Body | _(none)_ |
| Labels | `todo`, `testing` |
| Assignees | `john-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:
| Field | Value |
| --------- | --------------------------------------------------------------------------------- |
| Title | `Migrate to new payments API` |
| Body | `@alice should review the Stripe integration`<br>`@bob handles the webhook setup` |
| Labels | `todo` |
| Assignees | `alice`, `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.
| Input | Behavior |
| ------------------- | ------------------------------------------------------- |
| `a1b2c3d` | Diffs commit against its parent (`a1b2c3d~1...a1b2c3d`) |
| `a1b2c3d...f4e5d6a` | Diffs 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
```