git-code-debt


Namegit-code-debt JSON
Version 1.2.0 PyPI version JSON
download
home_pagehttps://github.com/asottile/git-code-debt
SummaryA dashboard for monitoring code debt in a git repository.
upload_time2025-10-10 17:17:33
maintainerNone
docs_urlNone
authorAnthony Sottile
requires_python>=3.10
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            [![build status](https://github.com/asottile/git-code-debt/actions/workflows/main.yml/badge.svg)](https://github.com/asottile/git-code-debt/actions/workflows/main.yml)
[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/asottile/git-code-debt/main.svg)](https://results.pre-commit.ci/latest/github/asottile/git-code-debt/main)

git-code-debt
=============

A dashboard for monitoring code debt in a git repository.


## Installation

```bash
pip install git-code-debt
```


## Usage


### Basic / tl;dr Usage

#### make a `generate_config.yaml`

```yaml
# required: repository to clone (can be anything `git clone` understands) even
# a repository already on disk
repo: git@github.com:asottile/git-code-debt

# required: database generation path
database: database.db

# optional: default False
skip_default_metrics: false

# optional: default []
metric_package_names: []

# optional: default ^$ (python regex) to exclude paths such as '^vendor/'
exclude: ^$
```

#### invoke the cli

```
# Generate code metric data (substitute your own repo path)
$ git-code-debt-generate
# Start the server
$ git-code-debt-server database.db
```

### Updating data on an existing database

Adding data to the database is as simple as running generate again.
`git-code-debt` will pick up in the git history from where data was generated
previously.

```
$ git-code-debt-generate
```

### Creating your own metrics

1. Create a python project which adds `git-code-debt` as a dependency.
2. Create a package where you'll write your metrics
3. Add your package to `metric_package_names` in your `generate_config.yaml`


The simplest way to write your own custom metrics is to extend
`git_code_debt.metrics.base.SimpleLineCounterBase`.


Here's what the base class looks like

```python

class SimpleLineCounterBase(DiffParserBase):
    # ...

    def should_include_file(self, file_diff_stat: FileDiffStat) -> bool:
        """Implement me to return whether a filename should be included.
        By default, this returns True.

        :param FileDiffStat file_diff_stat:
        """
        return True

    def line_matches_metric(self, line: bytes, file_diff_stat: FileDiffStat) -> bool:
        """Implement me to return whether a line matches the metric.

        :param bytes line: Line in the file
        :param FileDiffStat file_diff_stat:
        """
        raise NotImplementedError
```

Here's an example metric

```python
from git_code_debt.metrics.base import SimpleLineCounterBase


class Python__init__LineCount(SimpleLineCounterBase):
    """Counts the number of lines in __init__.py"""

    def should_include_file(self, file_diff_stat: FileDiffStat) -> bool:
        return file_diff_stat.filename == b'__init__.py'

    def line_matches_metric(self, line: bytes, file_diff_stat -> FileDiffStat) -> bool:
        # All lines in __init__.py match
        return True
```

An additional class is provided which feeds lines as text
(`SimpleLineCounterBase` presents them as `bytes`): `TextLineCounterBase`.
Here is an example metric using that base class:

```python
from git_code_debt.metrics.base import TextLineCounterBase


class XXXLineCount(TextLineCounterBase):
    """Counts the number of lines which are XXX comments"""

    def text_line_matches_metric(self, line: str, file_diff_stat: FileDiffStat) -> bool:
        return '# XXX' in line
```

More complex metrics can extend `DiffParserBase`

```python
class DiffParserBase(object):
    # Specify __metric__ = False to not be included (useful for base classes)
    __metric__ = False

    def get_metrics_from_stat(self, commit: Commit, file_diff_stats: Tuple[FileDiffStat, ...]) -> bool:
        """Implement me to yield Metric objects from the input list of
        FileStat objects.

        Args:
            commit - Commit object
            file_diff_stats - list of FileDiffStat objects

        Returns:
           generator of Metric objects
        """
        raise NotImplementedError

    def get_metrics_info(self) -> List[MetricInfo]:
        """Implement me to yield `MetricInfo` objects."""
        raise NotImplementedError
```


## Some screenshots

### Index
![Example screen index](https://raw.githubusercontent.com/asottile/git-code-debt/main/img/debt_screen_1.png)

### Graph
![Example screen graph](https://raw.githubusercontent.com/asottile/git-code-debt/main/img/debt_screen_2.png)

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/asottile/git-code-debt",
    "name": "git-code-debt",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": null,
    "author": "Anthony Sottile",
    "author_email": "asottile@umich.edu",
    "download_url": "https://files.pythonhosted.org/packages/57/14/f12ee2a994bc5035596527582fa03fdba084f01c74cf9e55ee655f81ea77/git_code_debt-1.2.0.tar.gz",
    "platform": null,
    "description": "[![build status](https://github.com/asottile/git-code-debt/actions/workflows/main.yml/badge.svg)](https://github.com/asottile/git-code-debt/actions/workflows/main.yml)\n[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/asottile/git-code-debt/main.svg)](https://results.pre-commit.ci/latest/github/asottile/git-code-debt/main)\n\ngit-code-debt\n=============\n\nA dashboard for monitoring code debt in a git repository.\n\n\n## Installation\n\n```bash\npip install git-code-debt\n```\n\n\n## Usage\n\n\n### Basic / tl;dr Usage\n\n#### make a `generate_config.yaml`\n\n```yaml\n# required: repository to clone (can be anything `git clone` understands) even\n# a repository already on disk\nrepo: git@github.com:asottile/git-code-debt\n\n# required: database generation path\ndatabase: database.db\n\n# optional: default False\nskip_default_metrics: false\n\n# optional: default []\nmetric_package_names: []\n\n# optional: default ^$ (python regex) to exclude paths such as '^vendor/'\nexclude: ^$\n```\n\n#### invoke the cli\n\n```\n# Generate code metric data (substitute your own repo path)\n$ git-code-debt-generate\n# Start the server\n$ git-code-debt-server database.db\n```\n\n### Updating data on an existing database\n\nAdding data to the database is as simple as running generate again.\n`git-code-debt` will pick up in the git history from where data was generated\npreviously.\n\n```\n$ git-code-debt-generate\n```\n\n### Creating your own metrics\n\n1. Create a python project which adds `git-code-debt` as a dependency.\n2. Create a package where you'll write your metrics\n3. Add your package to `metric_package_names` in your `generate_config.yaml`\n\n\nThe simplest way to write your own custom metrics is to extend\n`git_code_debt.metrics.base.SimpleLineCounterBase`.\n\n\nHere's what the base class looks like\n\n```python\n\nclass SimpleLineCounterBase(DiffParserBase):\n    # ...\n\n    def should_include_file(self, file_diff_stat: FileDiffStat) -> bool:\n        \"\"\"Implement me to return whether a filename should be included.\n        By default, this returns True.\n\n        :param FileDiffStat file_diff_stat:\n        \"\"\"\n        return True\n\n    def line_matches_metric(self, line: bytes, file_diff_stat: FileDiffStat) -> bool:\n        \"\"\"Implement me to return whether a line matches the metric.\n\n        :param bytes line: Line in the file\n        :param FileDiffStat file_diff_stat:\n        \"\"\"\n        raise NotImplementedError\n```\n\nHere's an example metric\n\n```python\nfrom git_code_debt.metrics.base import SimpleLineCounterBase\n\n\nclass Python__init__LineCount(SimpleLineCounterBase):\n    \"\"\"Counts the number of lines in __init__.py\"\"\"\n\n    def should_include_file(self, file_diff_stat: FileDiffStat) -> bool:\n        return file_diff_stat.filename == b'__init__.py'\n\n    def line_matches_metric(self, line: bytes, file_diff_stat -> FileDiffStat) -> bool:\n        # All lines in __init__.py match\n        return True\n```\n\nAn additional class is provided which feeds lines as text\n(`SimpleLineCounterBase` presents them as `bytes`): `TextLineCounterBase`.\nHere is an example metric using that base class:\n\n```python\nfrom git_code_debt.metrics.base import TextLineCounterBase\n\n\nclass XXXLineCount(TextLineCounterBase):\n    \"\"\"Counts the number of lines which are XXX comments\"\"\"\n\n    def text_line_matches_metric(self, line: str, file_diff_stat: FileDiffStat) -> bool:\n        return '# XXX' in line\n```\n\nMore complex metrics can extend `DiffParserBase`\n\n```python\nclass DiffParserBase(object):\n    # Specify __metric__ = False to not be included (useful for base classes)\n    __metric__ = False\n\n    def get_metrics_from_stat(self, commit: Commit, file_diff_stats: Tuple[FileDiffStat, ...]) -> bool:\n        \"\"\"Implement me to yield Metric objects from the input list of\n        FileStat objects.\n\n        Args:\n            commit - Commit object\n            file_diff_stats - list of FileDiffStat objects\n\n        Returns:\n           generator of Metric objects\n        \"\"\"\n        raise NotImplementedError\n\n    def get_metrics_info(self) -> List[MetricInfo]:\n        \"\"\"Implement me to yield `MetricInfo` objects.\"\"\"\n        raise NotImplementedError\n```\n\n\n## Some screenshots\n\n### Index\n![Example screen index](https://raw.githubusercontent.com/asottile/git-code-debt/main/img/debt_screen_1.png)\n\n### Graph\n![Example screen graph](https://raw.githubusercontent.com/asottile/git-code-debt/main/img/debt_screen_2.png)\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A dashboard for monitoring code debt in a git repository.",
    "version": "1.2.0",
    "project_urls": {
        "Homepage": "https://github.com/asottile/git-code-debt"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "a47ccdc68a30e0916875350d4bfaf642436aee7ae62a341f51f64fddaa9d40f4",
                "md5": "95e3fe585ed9a12ea9ce69ce4e6e0b4b",
                "sha256": "af295bd69f33fb6000549af0daae32cef5b2953831dafedf0ae92166712a0cdc"
            },
            "downloads": -1,
            "filename": "git_code_debt-1.2.0-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "95e3fe585ed9a12ea9ce69ce4e6e0b4b",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": ">=3.10",
            "size": 70046,
            "upload_time": "2025-10-10T17:17:32",
            "upload_time_iso_8601": "2025-10-10T17:17:32.021765Z",
            "url": "https://files.pythonhosted.org/packages/a4/7c/cdc68a30e0916875350d4bfaf642436aee7ae62a341f51f64fddaa9d40f4/git_code_debt-1.2.0-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "5714f12ee2a994bc5035596527582fa03fdba084f01c74cf9e55ee655f81ea77",
                "md5": "eec560b909f066e920342a543678cb78",
                "sha256": "c11caf38468960a1b71c13b90058a14a8614786d7a19d56cf1a6b1b580aff2fa"
            },
            "downloads": -1,
            "filename": "git_code_debt-1.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "eec560b909f066e920342a543678cb78",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 56016,
            "upload_time": "2025-10-10T17:17:33",
            "upload_time_iso_8601": "2025-10-10T17:17:33.252498Z",
            "url": "https://files.pythonhosted.org/packages/57/14/f12ee2a994bc5035596527582fa03fdba084f01c74cf9e55ee655f81ea77/git_code_debt-1.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-10 17:17:33",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "asottile",
    "github_project": "git-code-debt",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "git-code-debt"
}
        
Elapsed time: 1.24106s