Skip to content

mristin/opinionated-csharp-todos

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Opinionated-csharp-todos

Check Coverage Status Nuget

Opinionated-csharp-todos inspects that your TODO comments follow a pattern.

Motivation

It is quite messy to have a variety of TODO comment styles in your code:

  • New developers are confused as which style they should use.

    For example, if you mix case, is it // todo or // Todo or // TODO?

    → You want a uniform style throught your code base.

  • The set of the prefixes is not well-defined. Certain tools support by default only a limited set of prefixes.

    For example, Microsoft Visual Studio supports by default
    HACK, TODO, UNDONE and UnresolvedMergeConflict (see this page). On the other hand, JetBrains Rider supports by default TODO and BUG (see this page). Both tools support adding custom prefixes (a.k.a, tags or tokens).

    → You want to have a separate IDE-independent tool which ensures that the established convention is followed in the code base. Best if done in continuous integration.

  • Bare TODOs can be daunting in larger code bases with multiple contributors. Single // TODO without further information such as the author and the date of the comment can be confusing or even overwhelming, especially to new developers.

    For example, if you have to work on a part of the code base with a highly relevant TODO, how are you supposed to contact the person who left it there to gain further insights and background knowledge?

    While using git blame might a be a solution up to a certain degree, this does not work whenever the copy/pasted code includes the TODOs. This situation often happens in refactorings when the "refactorer" is not the author of the code.

    → You want the information about the author and the time stamp included in the TODOs. This additional information should be structured in an uniform manner.

  • Structured information is necessary for further processing. Bare TODOs bar that possibility.

    For example, imagine you would like to create an additional tool to analyze the TODOs and create Github issues automatically. You might want to include the information such as timestamp, due date, author and issue tag in the TODO.

    → Though complex examination of the comment structure is out-of-scope for Opinionated-csharp-todos, it is a good idea to check that the TODO comments at least match the expected patterns and inform the developer as soon as possible if some of the comments do not match.

Related Tools

IDEs and extensions. While popular IDEs support the TODO comments themselves (e.g., Task lists in Visual Studio) and also provide ground for many extensions (e.g., this extension and that extension), these tools are difficult or impossible to put into the continuous integration since they lack a command-line interface.

At best, you could use them to re-format and inspect the TODOs manually.

TODOs-as-a-service. There is a service, Tickgit, that you connect with the repository to inspect your TODOs and extract the extra information such as the author and the time stamp using git blame. Unfortunately, this typically breaks even in smaller teams whenever the person refactoring is not the author of the original code.

Command-line tools. We searched nuget.org when we started developing the tool (July 2020). There were only a few related tools, none of which could enforce arbitrary patterns:

  • DatedTodo inspects the TODOs, parses the due date and raises an alarm if some of the TODOs are due.

  • TodoCommentReporter is a Roslyn diagnostic analyzer that reports the TODOs in your code base.

  • FixMe emits the TODO comments during the build.

Installation

Opinionated-csharp-todos is available as a dotnet tool.

Either install it globally:

dotnet tool install -g OpinionatedCsharpTodos

or locally (if you use tool manifest, see this Microsoft tutorial):

dotnet tool install OpinionatedCsharpTodos

Usage

Overview

To obtain an overview of the command-line arguments, use --help:

dotnet doctest-csharp --help
OpinionatedCsharpTodos:
  Examines and collects the TODOs from your C# code.

Usage:
  OpinionatedCsharpTodos [options]

Options:
  -i, --inputs <inputs> (REQUIRED)               Glob patterns of the files to be inspected
  -e, --excludes <excludes>                      Glob patterns of the files to be excluded from inspection
  --prefixes <prefixes>                          Prefix regular expressions marking the TODOs. [Default: ^TODO ^BUG ^HACK]
  --disallowed-prefixes <disallowed-prefixes>    Prefix regular expressions which should not occur. [Default: ^DONT-CHECK-IN ^Todo ^todo ^ToDo ^Bug ^bug ^Hack ^hack]
  --suffixes <suffixes>                          Suffix regular expressions that TODOs must conform to. [Default: ^ \([^)]+, [0-9]{4}-[0-9]{2}-[0-9]{2}\): .]
  --case-insensitive                             If set, the regular expressions are applied as case-insensitive
  --report-path <report-path>                    If set, outputs the TODOs as a JSON (the path '-' denotes STDOUT).
  --verbose                                      If set, makes the console output more verbose
  --version                                      Show version information
  -?, -h, --help                                 Show help and usage information

Inputs and Excludes

You run opinionated-csharp-todos through dotnet.

To obtain help:

dotnet opinionated-csharp-todos --help

You specify the files containing TODOs using glob patterns:

dotnet opinionated-csharp-todos --inputs "SomeProject/**/*.cs"

Multiple patterns are also possible (we use '\' for line continuation here):

dotnet opinionated-csharp-todos \
    --inputs "SomeProject/**/*.cs" \
        "AnotherProject/**/*.cs"

Sometimes you need to exclude files, e.g., when your solution contains third-party code which you do not want to scan.

You can provide the glob pattern for the files to be excluded with --excludes:

dotnet opinionated-csharp-todos \
    --inputs "**/*.cs" \
    --excludes "**/obj/**"

Patterns

The comments are inspected based on their prefix and their suffix. Namely, opnionated-csharp-todos considers only comments which match a certain set of prefix patterns.

If the comment matches one of the special prefixes (given in --prefixes, see below), the remainder of the comment (the suffix) needs to match one of the suffix patterns (given in --suffixes, see below). Otherwise, the comment is reported as invalid.

Additionally, you can specify a list of disallowed prefixes (given in --disallowed-prefixes, see below), so that all comments matching those are also reported as invalid. The disallowed prefixes are particularly useful if you want to mark parts of the code which should not be checked in into the version control (e.g, // DONT-CHECK-IN) or if you want to enforce consistency in prefixes (e.g., disallow // todo).

Prefixes are specified as regular expressions using --prefixes .

For example, if you only want to scan for // TODO and // BUG:

dotnet opinionated-csharp-todos \
    --inputs "**/*.cs" \
    --prefixes "^TODO" "^BUG"

Disallowed prefixes. You can make opinionated-csharp-comments fail whenever one of the disallowed prefixes is encountered specified as regular expressions using --disallowed-prefixes.

This is particularly handy if you want to include the tool in your pre-commit checks to make sure you do not check in, say, unfinished work.

For example, if you want the tool to fail on // DONT-CHECK-IN and // DEBUG:

dotnet opinionated-csharp-todos \
    --inputs "**/*.cs" \
    --disallowed-prefixes "^DONT-CHECK-IN" "^DEBUG"

Suffixes are usually also required to follow the convention(s). You can specify the patterns as regular expressions using --suffix.

For example, to enforce suffix to match // TODO (mristin, 2020-07-20): ...:

dotnet opinionated-csharp-todos \
    --inputs "**/*.cs" \
    --suffixes '^ \([^)]+, [0-9]{4}-[0-9]{2}-[0-9]{2}\): '

We provide the defaults for --prefixes, --disallowed-prefixes and --suffixes which probably work in most of the cases:

  • --prefixes: ^TODO, ^BUG, ^HACK
  • --disallowed-prefixes: ^DONT-CHECK-IN, ^Todo, ^todo, ^ToDo, ^Bug, ^bug, ^Hack, ^hack
  • --suffixes: ^ \([^)]+, [0-9]{4}-[0-9]{2}-[0-9]{2}\): .

Report

Opinionated-csharp-todos scans the files and reports the collected TODOs to the standard output as text. In cases where you would like to post-process the results, you can save the report as a JSON file using --report-path.

For example:

dotnet opinionated-csharp-todos \
    --inputs "**/*.cs" \
    --report-path /tmp/some-report.json

If you provide -, the JSON report is written to the standard output:

dotnet opinionated-csharp-todos \
    --inputs "**/*.cs" \
    --report-path -

Recipes

Opinionated-csharp-todos is based on matching prefixes and suffixes using regular expressions. This logic is quite limiting and often you would like to further refine the checks and post-process the collected TODOs.

We provide two recipes to demonstrate how you can further use the JSON report downstream.

Badges

The script recipes/powershell/RenderBadge.ps1 uses https://shields.io to render the number of TODOs to SVG badges. If you include this script in your continuous integration, you can put up the badge to let the users know the state of the code base.

Task List

The script recipes/powershell/RenderTaskList.ps1 renders the TODOs as markdown grouped by the corresponding source files. By specifying an URL prefix it automatically links the location of the TODOs to the code base.

Thus you can use this task list for a rudimentary task management and navigate the TODOs.

Contributing

Feature requests, bug reports etc. are highly welcome! Please submit a new issue.

If you want to contribute in code, please see CONTRIBUTING.md.

Versioning

We follow Semantic Versioning. The version X.Y.Z indicates:

  • X is the major version (backward-incompatible w.r.t. command-line arguments),
  • Y is the minor version (backward-compatible), and
  • Z is the patch version (backward-compatible bug fix).