{"id":17771708,"url":"https://github.com/akoutmos/doctor","last_synced_at":"2025-04-13T00:47:44.751Z","repository":{"id":33603475,"uuid":"150648163","full_name":"akoutmos/doctor","owner":"akoutmos","description":"Ensure that your Elixir project documentation is healthy","archived":false,"fork":false,"pushed_at":"2024-04-03T11:13:12.000Z","size":179,"stargazers_count":169,"open_issues_count":11,"forks_count":14,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-05-01T15:46:26.099Z","etag":null,"topics":["documentation-coverage","typespecs"],"latest_commit_sha":null,"homepage":"","language":"Elixir","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/akoutmos.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":["akoutmos"]}},"created_at":"2018-09-27T21:10:11.000Z","updated_at":"2024-06-18T19:53:20.303Z","dependencies_parsed_at":"2024-06-18T19:53:18.338Z","dependency_job_id":"ef55df3e-38f6-4550-885a-5e8327802ca9","html_url":"https://github.com/akoutmos/doctor","commit_stats":{"total_commits":94,"total_committers":8,"mean_commits":11.75,"dds":"0.19148936170212771","last_synced_commit":"4f418227bd20a8c75e604993e2b1ab7ef5eec8e0"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akoutmos%2Fdoctor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akoutmos%2Fdoctor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akoutmos%2Fdoctor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akoutmos%2Fdoctor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/akoutmos","download_url":"https://codeload.github.com/akoutmos/doctor/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248650435,"owners_count":21139672,"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":["documentation-coverage","typespecs"],"created_at":"2024-10-26T21:35:14.381Z","updated_at":"2025-04-13T00:47:44.725Z","avatar_url":"https://github.com/akoutmos.png","language":"Elixir","funding_links":["https://github.com/sponsors/akoutmos"],"categories":[],"sub_categories":[],"readme":"# Doctor\n\n[![Module Version](https://img.shields.io/hexpm/v/doctor.svg?style=for-the-badge)](https://hex.pm/packages/doctor)\n[![Doctor CI](https://img.shields.io/github/actions/workflow/status/akoutmos/doctor/master.yml?label=Build%20Status\u0026style=for-the-badge\u0026branch=master)](https://github.com/akoutmos/doctor/actions)\n[![Coverage Status](https://img.shields.io/coverallsCoverage/github/akoutmos/doctor.svg?branch=master\u0026style=for-the-badge)](https://coveralls.io/github/akoutmos/doctor?branch=master)\n[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg?style=for-the-badge)](https://hexdocs.pm/doctor/)\n[![Total Download](https://img.shields.io/hexpm/dt/doctor.svg?style=for-the-badge)](https://hex.pm/packages/doctor)\n[![License](https://img.shields.io/hexpm/l/doctor.svg?style=for-the-badge)](https://github.com/akoutmos/doctor/blob/master/LICENSE)\n\nEnsure that your documentation is healthy with Doctor! This library contains a mix task that you can run against your\nproject to generate a documentation coverage report. Items which are reported on include: the presence of module docs,\nwhich functions do/don't have docs, which functions do/don't have typespecs, and if your struct modules provide\ntypespecs. You can generate a `.doctor.exs` config file to specify what thresholds are acceptable for your project. If\ndocumentation coverage drops below your specified thresholds, the `mix doctor` task will return a non zero exit status.\n\nThe primary motivation with this tool is to have something simple which can be hooked up into CI to ensure that project\ndocumentation standards are respected and upheld. This is particular useful in a team environment when you want to\nmaintain a minimum threshold for documentation coverage.\n\n## Installation\n\nAdding `:doctor` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:doctor, \"~\u003e 0.22.0\", only: :dev}\n  ]\nend\n```\n\nDocumentation can be found at [https://hexdocs.pm/doctor](https://hexdocs.pm/doctor).\n\n## Comparison with other tools\n\nThere are a few tools in the Elixir ecosystem that overlap slightly in functionality with Doctor. It is useful for\nyou to know how Doctor differs from these tools and some use cases that Doctor serves.\n\n**Credo**\n\n[Credo](https://github.com/rrrene/credo) is a phenomenal library that can be used to perform a wide range of\nstatic analysis checks against your codebase. It can check for lingering `IO.inspect()` statements, it can check for\nunsafe atom conversions, and it can also check that the cyclomatic complexity of control statements is within a\nparticular range to name a few.\n\nThe one area where Doctor and Credo do overlap is that with either tool you have the capability to\nenforce that `@moduledoc` attributes are present in modules. Given that this is the only overlap between the two tools,\nI generally use both in my projects and perform both validations during CI/CD.\n\n**Inch**\n\n[Inch](https://github.com/rrrene/inch_ex) is another great tool written by René Föhring that is specifically\ncatered to analyzing a project's documentation (very much like Doctor). Inch will scan your project's source files and\ncheck for the presence of function documentation and report back to you what grade it thinks your project has earned.\n\nInch does not appear to support checking for function typespecs, returning non-zero status codes when validation fails,\ntuning thresholds via a configuration file, or checking for struct module typespecs. On the other hand, these were\nthings that were important to me personally and so I wrote Doctor to fill that void. In a team context, I find Doctor to\nbe invaluable in ensuring that a project maintains a certain level of documentation by failing CI/CD if certain\nthresholds have not been met.\n\nIf I have misrepresented any of the aforementioned libraries...feel free to open up an issue :).\n\n## Usage\n\nDoctor comes with 2 mix tasks. One to run the documentation coverage report, and another to generate a `.doctor.exs` config file.\n\nTo run the doctor mix task and generate a report, run: `mix doctor`.\nTo generate a `.doctor.exs` config file with defaults, run: `mix doctor.gen.config`.\nTo get help documentation, run `mix help doctor` and `mix help doctor.gen.config`. The outputs of those help menus can be seen here:\n\nRunning `mix help doctor` yields:\n\n```terminal\n                                   mix doctor\n\nDoctor is a command line utility that can be used to ensure that your project\ndocumentation remains healthy. For more in depth documentation on Doctor or to\nfile bug/feature requests, please check out https://github.com/akoutmos/doctor.\n\nThe mix doctor command supports the following CLI flags (all of these options\nand more are also configurable from your .doctor.exs file). The following CLI\nflags are supported:\n\n    --full       When generating a Doctor report of your project, use\n                 the Doctor.Reporters.Full reporter.\n\n    --short      When generating a Doctor report of your project, use\n                 the Doctor.Reporters.Short reporter.\n\n    --summary    When generating a Doctor report of your project, use\n                 the Doctor.Reporters.Summary reporter.\n\n    --raise      If any of your modules fails Doctor validation, then\n                 raise an error and return a non-zero exit status.\n\n    --failed     If set only the failed modules will be reported. Works with\n                 --full and --short options.\n\n    --umbrella   By default, in an umbrella project, each app will be\n                 evaluated independently against the specified thresholds\n                 in your .doctor.exs file. This flag changes that behavior\n                 by aggregating the results of all your umbrella apps,\n                 and then comparing those results to the configured\n                 thresholds.\n```\n\nRunning `mix help doctor.gen.config` yields:\n\n```terminal\n                             mix doctor.gen.config\n\nDoctor is a command line utility that can be used to ensure that your project\ndocumentation remains healthy. For more in depth documentation on Doctor or to\nfile bug/feature requests, please check out https://github.com/akoutmos/doctor.\n\nThe mix doctor.gen.config command can be used to create a .doctor.exs file with\nthe default Doctor settings. The default file contents are:\n\n    %Doctor.Config{\n      ignore_modules: [],\n      ignore_paths: [],\n      min_module_doc_coverage: 40,\n      min_module_spec_coverage: 0,\n      min_overall_doc_coverage: 50,\n      min_overall_moduledoc_coverage: 100,\n      min_overall_spec_coverage: 0,\n      exception_moduledoc_required: true,\n      raise: false,\n      reporter: Doctor.Reporters.Full,\n      struct_type_spec_required: true,\n      umbrella: false\n    }\n```\n\n## Configuration\n\nBelow is a sample `.doctor.exs` file with some sample values for the various fields:\n\n```elixir\n%Doctor.Config{\n  ignore_modules: [],\n  ignore_paths: [],\n  min_module_doc_coverage: 40,\n  min_module_spec_coverage: 0,\n  min_overall_doc_coverage: 50,\n  min_overall_moduledoc_coverage: 100,\n  min_overall_spec_coverage: 0,\n  exception_moduledoc_required: true,\n  raise: false,\n  reporter: Doctor.Reporters.Full,\n  struct_type_spec_required: true,\n  umbrella: false\n}\n```\n\nFor the reporter field, the following reporters included with Doctor:\n\n- `Doctor.Reporters.Full`\n- `Doctor.Reporters.Short`\n- `Doctor.Reporters.Summary`\n\n## Sample reports\n\nReport created for Doctor itself:\n\n```text\n$ mix doctor\nDoctor file found. Loading configuration.\n---------------------------------------------------------------------------------------------------------------------------------------------------------------------------\nDoc Cov  Spec Cov  Module                                   File\nFunctions  No Docs  No Specs  Module Doc  Struct Spec\n100%     0%        Doctor.CLI                               lib/cli/cli.ex                                            2\n0        2         Yes         N/A\n100%     0%        Doctor.Config                            lib/config.ex                                             3\n0        3         Yes         Yes\n100%     0%        Doctor.Docs                              lib/docs.ex                                               1\n0        1         Yes         Yes\nN/A      N/A       Doctor                                   lib/doctor.ex                                             0\n0        0         Yes         N/A\n100%     100%      Mix.Tasks.Doctor                         lib/mix/tasks/doctor.ex                                   1\n0        0         Yes         N/A\n100%     0%        Mix.Tasks.Doctor.Gen.Config              lib/mix/tasks/doctor.gen.config.ex                        1\n0        1         Yes         N/A\n100%     0%        Doctor.ModuleInformation                 lib/module_information.ex                                 4\n0        4         Yes         Yes\n100%     0%        Doctor.ModuleReport                      lib/module_report.ex                                      1\n0        1         Yes         Yes\n100%     0%        Doctor.ReportUtils                       lib/report_utils.ex                                       9\n0        9         Yes         N/A\nN/A      N/A       Doctor.Reporter                          lib/reporter.ex                                           0\n0        0         Yes         N/A\n100%     0%        Doctor.Reporters.Full                    lib/reporters/full.ex                                     1\n0        1         Yes         N/A\n100%     0%        Doctor.Reporters.OutputUtils             lib/reporters/output_utils.ex                             1\n0        1         Yes         N/A\n100%     0%        Doctor.Reporters.Short                   lib/reporters/short.ex                                    1\n0        1         Yes         N/A\n100%     0%        Doctor.Reporters.Summary                 lib/reporters/summary.ex                                  1\n0        1         Yes         N/A\n100%     0%        Doctor.Specs                             lib/specs.ex                                              1\n0        1         Yes         Yes\n---------------------------------------------------------------------------------------------------------------------------------------------------------------------------\nSummary:\n\nPassed Modules: 15\nFailed Modules: 0\nTotal Doc Coverage: 100.0%\nTotal Spec Coverage: 3.7%\n\nDoctor validation has passed!\n```\n\nReport created for Phoenix:\n\n```text\n$ mix doctor\nDoctor file not found. Using defaults.\n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------\nDoc Cov  Spec Cov  Module                                   File                                                                  Functions  No Docs  No Specs  Module Doc\n100%     0%        Mix.Phoenix                              lib/mix/phoenix.ex                                                    18         0        18        YES\n0%       0%        Mix.Phoenix.Context                      lib/mix/phoenix/context.ex                                            6          6        6         YES\n63%      0%        Mix.Phoenix.Schema                       lib/mix/phoenix/schema.ex                                             8          3        8         YES\n100%     0%        Mix.Tasks.Compile.Phoenix                lib/mix/tasks/compile.phoenix.ex                                      2          0        2         YES\n100%     0%        Mix.Tasks.Phx.Digest.Clean               lib/mix/tasks/phx.digest.clean.ex                                     1          0        1         YES\n100%     0%        Mix.Tasks.Phx.Digest                     lib/mix/tasks/phx.digest.ex                                           1          0        1         YES\n100%     0%        Mix.Tasks.Phx                            lib/mix/tasks/phx.ex                                                  1          0        1         YES\n100%     0%        Mix.Tasks.Phx.Gen.Cert                   lib/mix/tasks/phx.gen.cert.ex                                         2          0        2         YES\n100%     0%        Mix.Tasks.Phx.Gen.Channel                lib/mix/tasks/phx.gen.channel.ex                                      1          0        1         YES\n86%      14%       Mix.Tasks.Phx.Gen.Context                lib/mix/tasks/phx.gen.context.ex                                      7          1        6         YES\n100%     17%       Mix.Tasks.Phx.Gen.Embedded               lib/mix/tasks/phx.gen.embedded.ex                                     6          0        5         YES\n100%     0%        Mix.Tasks.Phx.Gen.Html                   lib/mix/tasks/phx.gen.html.ex                                         4          0        4         YES\n100%     0%        Mix.Tasks.Phx.Gen.Json                   lib/mix/tasks/phx.gen.json.ex                                         4          0        4         YES\n100%     0%        Mix.Tasks.Phx.Gen.Presence               lib/mix/tasks/phx.gen.presence.ex                                     1          0        1         YES\n100%     14%       Mix.Tasks.Phx.Gen.Schema                 lib/mix/tasks/phx.gen.schema.ex                                       7          0        6         YES\n100%     0%        Mix.Tasks.Phx.Gen.Secret                 lib/mix/tasks/phx.gen.secret.ex                                       1          0        1         YES\n100%     0%        Mix.Tasks.Phx.Routes                     lib/mix/tasks/phx.routes.ex                                           1          0        1         YES\n100%     0%        Mix.Tasks.Phx.Server                     lib/mix/tasks/phx.server.ex                                           1          0        1         YES\n100%     0%        Phoenix                                  lib/phoenix.ex                                                        3          0        3         YES\n100%     17%       Phoenix.Channel                          lib/phoenix/channel.ex                                                12         0        10        YES\n100%     18%       Phoenix.Channel.Server                   lib/phoenix/channel/server.ex                                         17         0        14        YES\n100%     0%        Phoenix.CodeReloader                     lib/phoenix/code_reloader.ex                                          2          0        2         YES\n40%      0%        Phoenix.CodeReloader.Proxy               lib/phoenix/code_reloader/proxy.ex                                    5          3        5         YES\n33%      0%        Phoenix.CodeReloader.Server              lib/phoenix/code_reloader/server.ex                                   6          4        6         YES\n88%      25%       Phoenix.Config                           lib/phoenix/config.ex                                                 8          1        6         YES\n100%     52%       Phoenix.Controller                       lib/phoenix/controller.ex                                             42         0        20        YES\n100%     0%        Phoenix.Controller.Pipeline              lib/phoenix/controller/pipeline.ex                                    6          0        6         YES\n100%     100%      Phoenix.Digester                         lib/phoenix/digester.ex                                               2          0        0         YES\n100%     0%        Phoenix.Endpoint                         lib/phoenix/endpoint.ex                                               25         0        25        YES\n100%     0%        Phoenix.Endpoint.Cowboy2Adapter          lib/phoenix/endpoint/cowboy2_adapter.ex                               3          0        3         YES\n0%       0%        Phoenix.Endpoint.Cowboy2Handler          lib/phoenix/endpoint/cowboy2_handler.ex                               5          5        5         YES\n100%     0%        Phoenix.Endpoint.CowboyAdapter           lib/phoenix/endpoint/cowboy_adapter.ex                                2          0        2         YES\n0%       0%        Phoenix.Endpoint.CowboyWebSocket         lib/phoenix/endpoint/cowboy_websocket.ex                              8          8        8         YES\n100%     0%        Phoenix.Endpoint.RenderErrors            lib/phoenix/endpoint/render_errors.ex                                 3          0        3         YES\n93%      0%        Phoenix.Endpoint.Supervisor              lib/phoenix/endpoint/supervisor.ex                                    15         1        15        YES\n0%       0%        Phoenix.Endpoint.Watcher                 lib/phoenix/endpoint/watcher.ex                                       2          2        2         YES\nNA       NA        Plug.Exception.Phoenix.ActionClauseErro  lib/phoenix/exceptions.ex                                             0          0        0         NO\nNA       NA        Phoenix.NotAcceptableError               lib/phoenix/exceptions.ex                                             0          0        0         YES\n100%     0%        Phoenix.MissingParamError                lib/phoenix/exceptions.ex                                             1          0        1         YES\n0%       0%        Phoenix.ActionClauseError                lib/phoenix/exceptions.ex                                             2          2        2         NO\n60%      0%        Phoenix.Logger                           lib/phoenix/logger.ex                                                 5          2        5         YES\n83%      100%      Phoenix.Naming                           lib/phoenix/naming.ex                                                 6          1        0         YES\nNA       NA        Phoenix.Param.Map                        lib/phoenix/param.ex                                                  0          0        0         NO\nNA       NA        Phoenix.Param.Integer                    lib/phoenix/param.ex                                                  0          0        0         NO\nNA       NA        Phoenix.Param.BitString                  lib/phoenix/param.ex                                                  0          0        0         NO\nNA       NA        Phoenix.Param.Atom                       lib/phoenix/param.ex                                                  0          0        0         NO\nNA       NA        Phoenix.Param.Any                        lib/phoenix/param.ex                                                  0          0        0         NO\n0%       0%        Phoenix.Param                            lib/phoenix/param.ex                                                  1          1        1         YES\n100%     0%        Phoenix.Presence                         lib/phoenix/presence.ex                                               17         0        17        YES\nNA       NA        Phoenix.Router.NoRouteError              lib/phoenix/router.ex                                                 0          0        0         YES\n100%     0%        Phoenix.Router                           lib/phoenix/router.ex                                                 11         0        11        YES\n100%     0%        Phoenix.Router.ConsoleFormatter          lib/phoenix/router/console_formatter.ex                               1          0        1         YES\n95%      0%        Phoenix.Router.Helpers                   lib/phoenix/router/helpers.ex                                         20         1        20        YES\n100%     0%        Phoenix.Router.Resource                  lib/phoenix/router/resource.ex                                        1          0        1         YES\n100%     20%       Phoenix.Router.Route                     lib/phoenix/router/route.ex                                           5          0        4         YES\n100%     0%        Phoenix.Router.Scope                     lib/phoenix/router/scope.ex                                           9          0        9         YES\nNA       NA        Phoenix.Socket.InvalidMessageError       lib/phoenix/socket.ex                                                 0          0        0         YES\n57%      0%        Phoenix.Socket                           lib/phoenix/socket.ex                                                 14         6        14        YES\nNA       NA        Phoenix.Socket.Reply                     lib/phoenix/socket/message.ex                                         0          0        0         YES\n100%     0%        Phoenix.Socket.Message                   lib/phoenix/socket/message.ex                                         1          0        1         YES\nNA       NA        Phoenix.Socket.Broadcast                 lib/phoenix/socket/message.ex                                         0          0        0         YES\n50%      0%        Phoenix.Socket.PoolSupervisor            lib/phoenix/socket/pool_supervisor.ex                                 4          2        4         YES\nNA       NA        Phoenix.Socket.Serializer                lib/phoenix/socket/serializer.ex                                      0          0        0         YES\n0%       0%        Phoenix.Socket.V1.JSONSerializer         lib/phoenix/socket/serializers/v1_json_serializer.ex                  3          3        3         YES\n0%       0%        Phoenix.Socket.V2.JSONSerializer         lib/phoenix/socket/serializers/v2_json_serializer.ex                  3          3        3         YES\n100%     0%        Phoenix.Socket.Transport                 lib/phoenix/socket/transport.ex                                       6          0        6         YES\nNA       NA        Phoenix.Template.UndefinedError          lib/phoenix/template.ex                                               0          0        0         YES\n100%     45%       Phoenix.Template                         lib/phoenix/template.ex                                               11         0        6         YES\n0%       0%        Phoenix.Template.EExEngine               lib/phoenix/template/eex_engine.ex                                    1          1        1         YES\nNA       NA        Phoenix.Template.Engine                  lib/phoenix/template/engine.ex                                        0          0        0         YES\n0%       0%        Phoenix.Template.ExsEngine               lib/phoenix/template/exs_engine.ex                                    1          1        1         YES\nNA       NA        Phoenix.ChannelTest.NoopSerializer       lib/phoenix/test/channel_test.ex                                      0          0        0         YES\n100%     11%       Phoenix.ChannelTest                      lib/phoenix/test/channel_test.ex                                      19         0        17        YES\n100%     94%       Phoenix.ConnTest                         lib/phoenix/test/conn_test.ex                                         17         0        1         YES\n100%     0%        Phoenix.Token                            lib/phoenix/token.ex                                                  2          0        2         YES\n67%      0%        Phoenix.Transports.LongPoll              lib/phoenix/transports/long_poll.ex                                   3          1        3         YES\n50%      0%        Phoenix.Transports.LongPoll.Server       lib/phoenix/transports/long_poll_server.ex                            4          2        4         YES\n0%       0%        Phoenix.Transports.WebSocket             lib/phoenix/transports/websocket.ex                                   2          2        2         YES\n100%     0%        Phoenix.View                             lib/phoenix/view.ex                                                   9          0        9         YES\n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------\nSummary:\n\nPassed Modules: 72\nFailed Modules: 7\nTotal Doc Coverage: 85.1%\nTotal Spec Coverage: 15.3%\n\nDoctor validation has passed!\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakoutmos%2Fdoctor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fakoutmos%2Fdoctor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakoutmos%2Fdoctor/lists"}