Skip to content

ianlewis/todos

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

todos

tests Codecov Go Report Card FOSSA Status OpenSSF Scorecard SLSA 3

todos is a fast unixy CLI tool that searches for TODO comments in code and prints them in various formats.

todos screenshot

See the FAQ for more info on the philosophy behind the project.

πŸ› οΈ Features

πŸš€ Installation

todos can be installed via multiple methods.

Install pre-built binaries

Download the slsa-verifier and verify it's checksum:

curl -sSLo slsa-verifier https://github.com/slsa-framework/slsa-verifier/releases/download/v2.6.0/slsa-verifier-linux-amd64 && \
echo "1c9c0d6a272063f3def6d233fa3372adbaff1f5a3480611a07c744e73246b62d  slsa-verifier" | sha256sum -c - && \
chmod +x slsa-verifier

Download and verify the todos binary and verify it's provenance:

curl -sSLo todos https://github.com/ianlewis/todos/releases/download/v0.13.0/todos-linux-amd64 && \
curl -sSLo todos.intoto.jsonl https://github.com/ianlewis/todos/releases/download/v0.13.0/todos-linux-amd64.intoto.jsonl && \
./slsa-verifier verify-artifact todos --provenance-path todos.intoto.jsonl --source-uri github.com/ianlewis/todos --source-tag v0.13.0 && \
chmod +x todos && \
cp todos ~/bin/

Install using npm

Install todos by installing the @ianlewis/todos package from npm:

npm install -g @ianlewis/todos

Verify the package signature:

npm audit signatures

Docker image

Download and run todos with Docker. You should use a specific version tag:

docker run --rm -t -v $(pwd):/src ghcr.io/ianlewis/todos:v0.13.0 /src

Verify the image attestation using cosign:

cosign verify-attestation \
  --type slsaprovenance \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-identity-regexp '^https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@refs/tags/v[0-9]+.[0-9]+.[0-9]+$' \
  --certificate-github-workflow-repository "ianlewis/todos" \
  --certificate-github-workflow-ref "refs/tags/v0.13.0" \
  ghcr.io/ianlewis/todos:v0.13.0

Aqua package

todos is available as an Aqua package. You can install it with the aqua CLI tool:

# Initialize Aqua configuration if you haven't already.
aqua init

# Add todos to your aqua.yaml.
aqua generate ianlewis/todos

Install from source

If you already have Go 1.20+ you can install the latest version using go install:

go install github.com/ianlewis/todos/cmd/todos

Install as a Go tool dependency

You can also install todos from source as a Go tool dependency.

go get -tool github.com/ianlewis/todos/cmd/todos

This will allow you to use todos in your project using the go tool command.

go tool github.com/ianlewis/todos/cmd/todos

Be aware though that there are a few downsides to using the Go tools approach.

  • This will compile todos locally and using your local Go version.
  • The dependencies used to compile todos may be different than those used to compile its releases and thus is not guaranteed to work.
  • It allows installation from the main branch, which may not be stable.
  • It's slower than binary installation.

πŸ“– Usage

Simply running todos will search TODO comments starting in the current directory.Here is an example running in a checkout of the Kubernetes codebase.

kubernetes$ todos
build/common.sh:346:# TODO: remove when 17.06.0 is not relevant anymore
build/lib/release.sh:148:# TODO: Docker images here
cluster/addons/addon-manager/kube-addons.sh:233:# TODO: Remove the first command in future release.
cluster/addons/calico-policy-controller/ipamblock-crd.yaml:41:# TODO: This nullable is manually added in. We should update controller-gen
cluster/addons/dns/kube-dns/kube-dns.yaml.base:119:# TODO: Set memory limits when we've profiled the container for large
...

See the use cases for more examples of how to use todos.

Supported Languages

todos supports a wide variety of languages and file formats. It detects the language of a file based on its extension, shebang line, or the contents of the file.

See SUPPORTED_LANGUAGES.md for a full list of supported languages and comment types.

TODO format

"TODO" comments are comments in code that mark a task that is intended to be done in the future.

For example:

// TODO(label): message text

For TODO comments to be more easily parsed keep in mind the following:

  • Spaces between the comment start and 'TODO' is optional (e.g. //TODO: some comment)
  • TODOs should have a colon if a message is present so it can be distinguished from normal comments.
  • TODOs can be prefixed with @ (e.g. // @TODO: comment)
  • Comments can be on the same line with other code (e.g. x = f() // TODO: call f)
  • Line comment start sequences can be repeated (e.g. //// TODO: some comment)
  • TODO comments can be in multi-line comments, however only the single line where the TODO occurs is printed for multi-line comments.

TODO type variants

There a few variants of this type of comment that are in wide use.

  • TODO: A general TODO comment indicating something that is to be done in the future.
  • FIXME: Something that is broken that needs to be fixed in the code.
  • BUG: A bug in the code that needs to be fixed.
  • HACK: This code is a "hack"; a hard to understand or brittle piece of code. It could use a cleanup.
  • XXX: Danger! Similar to "HACK". Modifying this code is dangerous. It
  • COMBAK: Something you should "come back" to.

TODO,FIXME,BUG,HACK,XXX,COMBAK are supported by default. You can change this with the --todo-types flag.

TODO examples

TODO comments can include some optional metadata. Here are some examples:

  • A naked TODO comment.

    // TODO
  • A TODO comment with an explanation message

    // TODO: Do something.
  • A TODO comment with a linked bug or issue and optional message

    // TODO(github.com/ianlewis/todos/issues/8): Do something.
  • A TODO comment with a username and optional message. This type is discouraged as it links the issue to a specific developer but can be helpful temporarily when making changes to a PR. Linking to issues is recommended for permanent comments.

    // TODO(ianlewis): Do something.

Use cases

Tracking TODOs in code can help you have a cleaner and healthier code base. Here are some basic use cases.

Finding all TODOs in your project

You can use the todos to find TODO comments in your code and print them out. Running it will search the directory tree starting at the current directory by default. By default, it ignores files that are in "VCS" directories (such as.git or .hg) and vendored code (such as node_modules, vendor, and third_party).

$ todos
main.go:27:// TODO(#123): Return a proper exit code.
main.go:28:// TODO(ianlewis): Implement the main method.

Running on sub-directories or files

You can run todos on sub-directories or individual files by passing them on the command line.

kubernetes$ todos hack/ Makefile
hack/e2e-internal/e2e-cluster-size.sh:32:#TODO(colhom): spec and implement federated version of this
hack/ginkgo-e2e.sh:118:# TODO(kubernetes/test-infra#3330): Allow NODE_INSTANCE_GROUP to be
hack/lib/golang.sh:456:# TODO: This symlink should be relative.
hack/lib/protoc.sh:119:# TODO: switch to universal binary when updating to 3.20+
hack/lib/util.sh:337:# TODO(lavalamp): Simplify this by moving pkg/api/v1 and splitting pkg/api,
...

Outputting JSON

todos can produce output in JSON format for more complicated processing.

kubernetes$ todos -o json
{"path":"build/common.sh","type":"TODO","text":"# TODO: remove when 17.06.0 is not relevant anymore","label":"","message":"remove when 17.06.0 is not relevant anymore","line":346,"comment_line":346}
{"path":"build/lib/release.sh","type":"TODO","text":"# TODO: Docker images here","label":"","message":"Docker images here","line":148,"comment_line":148}
{"path":"cluster/addons/addon-manager/kube-addons.sh","type":"TODO","text":"# TODO: Remove the first command in future release.","label":"","message":"Remove the first command in future release.","line":233,"comment_line":233}
{"path":"cluster/addons/calico-policy-controller/ipamblock-crd.yaml","type":"TODO","text":"# TODO: This nullable is manually added in. We should update controller-gen","label":"","message":"This nullable is manually added in. We should update controller-gen","line":41,"comment_line":41}
{"path":"cluster/addons/dns/kube-dns/kube-dns.yaml.base","type":"TODO","text":"# TODO: Set memory limits when we've profiled the container for large","label":"","message":"Set memory limits when we've profiled the container for large","line":119,"comment_line":119}
...
kubernetes$ # Get all the unique files with TODOs that Tim Hockin owns.
kubernetes$ todos -o json | jq -r '. | select(.label = "thockin") | .path' | uniq

Finding authors of TODOs (EXPERIMENTAL)

You can use the --blame flag to find the author of a TODO comment. This will use git blame to find the latest author of the line where the TODO comment occurs. However, this can be slow for large repositories (#1519).

$ todos --blame
.github/workflows/schedule.scorecard.yml:80:Ian Lewis <ian@ianlewis.org>:# TODO: Remove the next line for private repositories with GitHub Advanced Security.
.golangci.yml:172:Ian Lewis <ian@ianlewis.org>:# TODO(#1725): Reduce package average complexity.
Makefile:525:Ian Lewis <ian@ianlewis.org>:# TODO: remove when todos v0.13.0 is released. \
cmd/todos/app.go:42:Ian Lewis <ianlewis@google.com>:// TODO(github.com/urfave/cli/issues/1809): Remove init func when upstream bug is fixed.
internal/scanner/languages.go:37:Ian Lewis <ian@ianlewis.org>:// TODO(#1686): Refactor language config global variables.
internal/scanner/languages.go:143:Ian Lewis <ian@ianlewis.org>:// TODO(#1686): Refactor LanguagesConfig global variable.
...

Documenting tasks

You can use the output of todos to create documentation of tasks.

For example, this creates a simple markdown document:

$ (
    echo "# TODOs" && \
    echo && \
    todos --exclude-dir .venv --output json | \
        jq -r 'if (.label | startswith("#")) then "- [ ] \(.label) \(.message)" else empty end' | \
        uniq
) > todos.md

$ cat todos.md
# TODOs

- [ ] #1546 Support @moduledoc
- [ ] #96 Use a *Config
- [ ] #96 Use []*Comment and go-cmp
- [ ] #1627 Support OCaml nested comments.
- [ ] #1540 Read this closed string as a comment.
- [ ] #1545 Generate Go code rather than loading YAML at runtime.

Running on GitHub Actions

If run as part of a GitHub action todos will function much like a linter and output GitHub workflow commands which will add check comments to PRs.

kubernetes$ todos -o github Makefile
::warning file=Makefile,line=313::# TODO(thockin): Remove this in v1.29.
::warning file=Makefile,line=504::#TODO: make EXCLUDE_TARGET auto-generated when there are other files in cmd/

An example workflow might look like the following. todos will output GitHub Actions workflow commands by default when running on GitHub Actions:

on:
    pull_request:
        branches: [main]
    workflow_dispatch:

permissions: {}

jobs:
    todos:
        runs-on: ubuntu-latest
        permissions:
            contents: read
        steps:
            - uses: actions/checkout@v3
            - uses: slsa-framework/slsa-verifier/actions/installer@v2.7.0
            - name: install todos
              run: |
                  set -euo pipefail

                  curl -sSLo todos \
                    https://github.com/ianlewis/todos/releases/download/v0.13.0/todos-linux-amd64 && \
                  curl -sSLo todos.intoto.jsonl \
                    https://github.com/ianlewis/todos/releases/download/v0.13.0/todos-linux-amd64.intoto.jsonl && \
                  slsa-verifier verify-artifact todos \
                    --provenance-path todos.intoto.jsonl \
                    --source-uri github.com/ianlewis/todos \
                    --source-tag v0.13.0 && \
                  rm -f slsa-verifier && \
                  chmod +x todos

            - name: run todos
              run: |
                  ./todos .

Re-open prematurely closed GitHub issues

Sometimes issues get closed before all of the relevant code is updated. You can use todos to re-open issues where TODO comments that reference the issue still exist in the code.

// TODO(#123): Still needs work.

See ianlewis/todo-issue-reopener for more information.

Show TODOs in your editor

You can use todos with efm-langserver find and manage TODOs in files opened in your favorite editor with LSP server support. This is useful for quickly finding and jumping to TODOs in your code.

For example, in Neovim you can use the following configuration to show TODOs in the quickfix window and jump to them. Install efm-langserver (via Mason etc.) and add the following to your LSP server Neovim configuration.

local lspconfig = require("lspconfig")

local todos = {
    prefix = "todos",
    lintCommand = "todos",
    lintStdin = true,
    lintIgnoreExitCode = true,
    lintSeverity = 2, -- 2 = warning
    lintFormats = {
        "%f:%l:%m",
    },
}

lspconfig.efm.setup({
    settings = {
        rootMarkers = { ".git/" },

        languages = {
            -- Add todos to each language.
            sh = { todos },
            bash = { todos },
            conf = { todos },
            gitignore = { todos },
            -- Merge with any existing configuration.
            html = { --[[ prettier, ]] todos },
            css = { --[[ prettier, stylelint, ]] todos },
            lua = { --[[ stylua, selene, ]] todos },
            python = { todos },
            rust = { todos },
            go = { todos },
            javascript = { --[[ prettier, ]] todos },
            -- ...
        },
    }
})

πŸ”§ Related projects

πŸ“š FAQ

Why use this?

Tracking TODOs in code can help you have a cleaner and healthier code base.

  1. It can help you realize when issues you thought were complete actually require some additional work (See ianlewis/todo-issue-reopener).
  2. It makes it easier for contributors to find areas of the code that need work.
  3. It makes it easier for contributors to find the relevant code for an issue.

Why not just use grep or rg?

grep and rg are amazing and very fast tools. However, there are a few reasons why you might use todos.

  1. grep and rg don't have much knowledge of code and languages so it's difficult to differentiate between comments and code. todos will ignore matches in code and only prints TODOs found it comments. It also ignores matches that occur in strings.
  2. grep doesn't know about repository structure. It doesn't have inherent knowledge of VCS directories (e.g. .git) or vendored dependencies. It can't make use of .gitignore or other hints.
  3. todos can output JSON with parsed values from the TODOs. This gives users an easy way to search for TODOs with their username, or with a specific issue number.

🀝 Contributing

See CONTRIBUTING.md for contributor documentation.

About

Parse TODO and FIXME comments from code

Topics

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors 4

  •  
  •  
  •  
  •