{"id":13554427,"url":"https://github.com/asottile/git-code-debt","last_synced_at":"2025-05-14T21:06:45.817Z","repository":{"id":11842936,"uuid":"14399837","full_name":"asottile/git-code-debt","owner":"asottile","description":"A dashboard for monitoring code debt in a git repository.","archived":false,"fork":false,"pushed_at":"2025-03-31T21:00:19.000Z","size":872,"stargazers_count":595,"open_issues_count":3,"forks_count":36,"subscribers_count":19,"default_branch":"main","last_synced_at":"2025-04-13T18:44:34.087Z","etag":null,"topics":["git","technical-debt"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/asottile.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"asottile"}},"created_at":"2013-11-14T16:05:41.000Z","updated_at":"2025-03-31T21:00:22.000Z","dependencies_parsed_at":"2023-11-14T03:28:55.512Z","dependency_job_id":"c58fffb1-6b51-4608-a403-377f80e86d94","html_url":"https://github.com/asottile/git-code-debt","commit_stats":{"total_commits":466,"total_committers":8,"mean_commits":58.25,"dds":0.2725321888412017,"last_synced_commit":"eb34406ca05b1825adcefbadb5c719eaee09499a"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asottile%2Fgit-code-debt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asottile%2Fgit-code-debt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asottile%2Fgit-code-debt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asottile%2Fgit-code-debt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/asottile","download_url":"https://codeload.github.com/asottile/git-code-debt/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254227612,"owners_count":22035669,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["git","technical-debt"],"created_at":"2024-08-01T12:02:47.667Z","updated_at":"2025-05-14T21:06:40.805Z","avatar_url":"https://github.com/asottile.png","language":"Python","funding_links":["https://github.com/sponsors/asottile"],"categories":["Python"],"sub_categories":[],"readme":"[![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) -\u003e 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) -\u003e 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) -\u003e bool:\n        return file_diff_stat.filename == b'__init__.py'\n\n    def line_matches_metric(self, line: bytes, file_diff_stat -\u003e FileDiffStat) -\u003e 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) -\u003e 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, ...]) -\u003e 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) -\u003e 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","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasottile%2Fgit-code-debt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fasottile%2Fgit-code-debt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasottile%2Fgit-code-debt/lists"}