Skip to content

Suree33/gh-pr-todo

Repository files navigation

gh-pr-todo

CI Downloads Ask DeepWiki

A GitHub CLI extension that extracts TODO-style comments from pull request diffs, helping you track action items and reminders in your code changes.

Features

  • PR-Focused Detection: Extracts TODO-style comments only from pull request diff additions
  • Syntax-Aware Parsing: Uses Tree-sitter for accurate comment detection in supported languages, with regex fallback for others
  • Configurable Marker Policy: Customize marker types, severities, and ignored types with CLI flags or YAML config
  • Config Initialization: Create project or global config files with gh pr-todo init
  • CI and GitHub Actions Support: Emit workflow annotations and fail CI only for marker types configured as error
  • Flexible Output: Colorized output with grouping, file-name-only, and count-only modes

Installation

gh ext install Suree33/gh-pr-todo

Prerequisites:

Usage

Basic Usage

Navigate to your repository with an open pull request and run:

gh pr-todo

Advanced Usage

You can specify PR numbers, URLs, or branches, and you can target another repository with -R/--repo or a PR URL:

# Specify a specific PR number
gh pr-todo 123

# Specify a PR from a different repository
gh pr-todo 456 -R owner/repo

# Specify a PR by URL
gh pr-todo https://github.com/owner/repo/pull/789

# Specify a branch
gh pr-todo feature-branch

# Specify a branch from a different repository
gh pr-todo feature-branch -R owner/repo

# Display only names of the files containing TODO-style comments
gh pr-todo --name-only

# Display only the number of TODO-style comments
gh pr-todo -c

# Group TODO-style comments by file (or type)
gh pr-todo --group-by file

# Override severities for one or more TODO types
# Format: --severity LEVEL=TYPE[,TYPE...]
gh pr-todo --severity warning=TODO,HACK --severity error=FIXME

# Ignore specific marker types from detection (affects all output modes)
gh pr-todo --ignore NOTE,HACK

Command Options

  • [<number> | <url> | <branch>]: Specify a PR by number, URL, or branch name
  • -R, --repo [HOST/]OWNER/REPO: Select another repository using the [HOST/]OWNER/REPO format (requires a PR number, URL, or branch argument)
  • --group-by: Group TODO-style comments by file or type
  • --name-only: Display only names of the files containing TODO-style comments. If both --name-only and --count are specified, --name-only takes precedence
  • -c, --count: Display only the number of TODO-style comments
  • --severity LEVEL=TYPE[,TYPE...]: Override severity for one or more TODO types; repeatable, whitespace-tolerant, and last assignment wins for duplicate types
  • --ignore TYPE[,TYPE...]: Ignore specified marker types; repeatable, case-insensitive, whitespace-tolerant. Ignored types are not detected or reported in any mode, including annotations and CI failure counts
  • -h, --help: Display help information
  • --no-ci-fail: Disable non-zero exit when error-level TODOs are found in CI (see below)

Initializing Configuration

Use gh pr-todo init to create a default configuration file. Without an explicit location, it prompts in terminals and falls back to a plain text prompt when redirected:

gh pr-todo init

For non-interactive scripts, pass a location:

gh pr-todo init --repo    # Project (.gh-pr-todo.yml)
gh pr-todo init --global  # user config dir/gh-pr-todo/config.yml

Prompted locations are:

  1. Project (.gh-pr-todo.yml) — repository-scoped config, created at the root of the current Git repository; shown in the interactive selector only when run inside a Git repository
  2. Global (user config dir/gh-pr-todo/config.yml) — global config, shared across all repos (typically $XDG_CONFIG_HOME/gh-pr-todo/config.yml on Linux, falling back to ~/.config/gh-pr-todo/config.yml; actual path depends on your OS)

If the selected config file already exists, init refuses to overwrite it unless --force is passed. --force can be combined with --repo or --global. --repo and --global are mutually exclusive, and using both returns an error. If you choose the repo-root location and .github/gh-pr-todo.yml exists, init reports it instead because that narrower config takes precedence over the root project config:

gh pr-todo init --force
gh pr-todo init --repo --force

The default configuration matches the runtime severity policy:

severity:
  notice:
    - TODO
    - NOTE
  warning:
    - FIXME
    - HACK
    - XXX
    - BUG
  error: []
ignore: []

Configuration File

Severity overrides and ignored types can be persisted in YAML configuration files. Config files use the following schema:

severity:
  notice|warning|error: [TYPE...]
ignore:
  - TYPE

Example (.gh-pr-todo.yml):

severity:
  warning:
    - TODO
  error:
    - FIXME
ignore:
  - NOTE

Config File Paths and Precedence

Config files use whole-file replacement by precedence: each existing file replaces the entire previous configuration. This applies to both severity overrides and ignored types.

Local files (in order of increasing precedence):

  1. User config dir gh-pr-todo/config.yml (global, shared across all repos; usually ~/.config/gh-pr-todo/config.yml on Linux)
  2. <repo>/.gh-pr-todo.yml (repository root)
  3. <repo>/.github/gh-pr-todo.yml (narrower repo scope)
  4. CLI --severity and --ignore flags (highest priority)

If a repo config file exists (root or .github), the global config is not applied. Within a repo, .github/gh-pr-todo.yml replaces .gh-pr-todo.yml entirely. CLI flags are applied on top of the resolved config.

Configured TODO types are automatically detected in PR diffs alongside the built-in types. You can define custom types like SECURITY or PERF and they will be recognized.

Remote Config Precedence

When targeting another repository with --repo or a PR URL, remote configuration is resolved with the following precedence:

  1. Remote PR head branch config
  2. Remote PR base branch config
  3. Remote default branch config
  4. Global local config, only when no remote config exists
  5. CLI --severity and --ignore flags (highest priority)

For each remote scope, .github/gh-pr-todo.yml replaces .gh-pr-todo.yml entirely. A remote config file replaces the global config entirely; global config is only used as a fallback when no remote config exists.

Ignoring Marker Types

The ignore config key lists marker types to exclude entirely from detection. Ignored types are not parsed or reported in any mode:

  • Default output
  • --count
  • --name-only
  • --group-by file or --group-by type
  • GitHub Actions annotations
  • CI failure counts

Example:

# .gh-pr-todo.yml
severity:
  warning:
    - TODO
  error:
    - FIXME
ignore:
  - NOTE
  - HACK

This config makes the tool ignore NOTE and HACK markers while still detecting TODO and FIXME. Ignored types can be built-in or custom and take precedence over severity: even if a type has error severity, ignoring it removes it from detection entirely.

Use the CLI --ignore flag to extend the ignore set temporarily:

gh pr-todo --ignore NOTE,HACK

CI Mode

When the CI environment variable is truthy (e.g. 1, true, parsed via Go's strconv.ParseBool), gh pr-todo exits with status 1 if any error-level TODO-style comments are detected in the PR diff. By default, no built-in keyword type is mapped to error-level, so gh pr-todo does not fail CI based on default keywords alone. Use configuration files or --severity to promote recognized TODO keywords to error when you want CI failures, for example --severity error=FIXME. GITHUB_ACTIONS=true (set by the GitHub Actions runner) is treated as CI=true even when CI is missing or falsy.

# GitHub Actions example — CI=true is set automatically
- run: gh pr-todo ${{ github.event.pull_request.number }}

Pass --no-ci-fail to suppress non-zero exit even when error-level TODOs exist:

gh pr-todo --count --severity error=FIXME --no-ci-fail

GitHub Actions Annotations

When GITHUB_ACTIONS=true (set automatically by the GitHub Actions runner), gh pr-todo additionally emits workflow commands so each TODO appears as an annotation on the workflow run and pull request:

Default annotation severities:

  • TODO, NOTE::notice annotations
  • FIXME, HACK, XXX, BUG::warning annotations

You can override them with configuration files or --severity, for example:

  • --severity warning=TODO,NOTE
  • --severity error=FIXME

Annotations reflect the resolved severity of each keyword and are independent of CI exit behavior: warning annotations are displayed but do not cause a non-zero exit by default. Only error-level TODOs cause CI failure.

Each annotation is anchored to the file and line of the TODO, with the keyword used as the annotation title. Regular human-readable output is still printed, and the spinner is suppressed to keep Actions logs clean.

Workflow commands are only emitted in the default mode. The machine-readable modes --count and --name-only keep their plain output unchanged so that count=$(gh pr-todo --count) and similar shell pipelines stay reliable in Actions.

Example Output

✔ Fetching PR diff...

Found 3 TODO-style comment(s)

* src/api/users.go:42
  // TODO: Add input validation for email format

* components/Header.tsx:15
  // FIXME: Memory leak in event listener cleanup

* docs/setup.md:8
  <!-- NOTE: Update this section after v2.0 release -->

Supported Comment Formats

The tool recognizes TODO-style comments in various formats:

Format Example
C-style // TODO: Fix this bug
C-style block /* HACK: Quick fix for demo */
Shell/Python # FIXME: Optimization needed
HTML/XML <!-- NOTE: Review this section -->
Assembly/Config ; XXX: Temporary workaround

Supported Keywords

Default Keywords

  • TODO
  • FIXME
  • HACK
  • NOTE
  • XXX
  • BUG

Custom Keywords

Additional keywords can be defined via configuration files or the --severity CLI flag. Any custom type assigned a severity will be detected in PR diffs alongside the default keywords. For example:

# .gh-pr-todo.yml
severity:
  error:
    - SECURITY
  warning:
    - PERF

This configures SECURITY and PERF as recognized TODO markers.

Validation Rules

  • Severity keys (notice, warning, error) are case-insensitive.
  • Empty lists (warning: []) are allowed and ignored.
  • A TODO type must not appear under multiple severity levels in the same file.
  • The old TYPE: level format is not supported.

Development

Building from Source

git clone https://github.com/Suree33/gh-pr-todo.git
cd gh-pr-todo
go build -o gh-pr-todo .

Project Structure

├── main.go              # CLI entry point
├── internal/
│   ├── config/
│   │   ├── config.go    # YAML config parsing and local loading
│   │   └── remote.go    # Remote config loading
│   ├── github/
│   │   └── client.go    # GitHub API client (diffs, file contents, remote config)
│   ├── output/
│   │   ├── printer.go   # Terminal output rendering
│   │   └── workflow.go  # GitHub Actions annotation commands
│   └── parser.go        # Diff parsing logic (Tree-sitter + regex)
├── pkg/
│   └── types/
│       ├── groupby.go   # GroupBy enum
│       └── todo.go      # TODO type definitions

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the terms specified in the LICENSE file.

Issues & Feature Requests

Found a bug or have a feature idea? Please open an issue on GitHub.

About

GitHub CLI extension to list TODO-style comments in a pull request's diff.

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages