In our last post we further refined our Boundary setup. Today we’ll be concentrating on ExDoc.
If you followed along with part 2 you can continue with the code from there. Otherwise you can grab today’s starting off point by:
Terminal
mkdir <some new directory>
cd <the new directory>
Terminal
git init
git remote add origin git@github.com:riebeekn/elixir_code_hygiene.git
git fetch origin e29178674c360d9017f49001d5c8a9354ffc5055
git reset --hard FETCH_HEAD
You should now see the following git history.
Terminal
git log --pretty=oneline
And now you can install the existing dependencies, and set up the database.
Terminal
mix deps.get
Terminal
mix do ecto.drop, ecto.create, ecto.migrate
Now let’s take a closer look at ExDoc
.
What we currently have
We currently have a default set-up of ExDoc
in our project, we can run the docs via a mix task:
Terminal
mix docs
And then view the docs.
Terminal
open doc/index.html
If we click the modules tab we’ll see docs for the various modules in our project.
Not bad! I think we could improve things with a bit of organization however.
Organizing the docs
We can provide some organization by updating the mix.exs
file.
We’ll make a number of changes to the mix file, let’s go over them one by one.
First off, let’s update the main project section.
/mix.exs
defmodule CodeHygiene.MixProject do
use Mix.Project
# these are new
@version "0.1.0"
@source_url "https://github.com/riebeekn/elixir_code_hygiene"
def project do
[
app: :code_hygiene,
# replaced hard-coded version with the @version attribute
version: @version,
elixir: "~> 1.12",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:boundary, :gettext] ++ Mix.compilers(),
start_permanent: Mix.env() == :prod,
aliases: aliases(),
deps: deps(),
test_coverage: [tool: ExCoveralls],
preferred_cli_env: [
coveralls: :test,
"coveralls.detail": :test,
"coveralls.post": :test,
"coveralls.html": :test
],
# these are also new
name: "Code Hygiene example app",
docs: docs()
]
end
...
We’ve added some attributes for the app version and source code location of the repo. We then add a name
and docs
attribute to the project
function. The docs
attribute calls out to a new function we’ll write which will handle the actual doc organization:
/mix.exs
defp docs do
[
main: "CodeHygiene",
assets: "docs/assets",
logo: "docs/assets/images/logo.svg",
source_ref: "v#{@version}",
source_url: @source_url,
formatters: ["html"],
groups_for_modules: groups_for_modules()
]
end
Everything is pretty self explanatory. We set an assets directory for any assets such as images we want to add to our docs; we set a logo for the docs; we set the default page for the docs (via the main
attribute); we set the version and source url of the repo the docs refer to; we specifiy that we only want to generate html
docs; and finally call out to a new function groups_for_modules
which will do the grouping of the docs.
We need to create the directories we’ve specified above:
Terminal
mkdir -p docs/assets/images
And we can throw this image into the docs/assets/images
folder, renaming it to logo.svg
Now lets create the groups_for_modules
function.
/mix.exs
defp groups_for_modules do
[
API: [
CodeHygiene,
CodeHygiene.Products,
CodeHygiene.Repo
],
Accounts: [
CodeHygiene.Accounts,
CodeHygiene.Accounts.UserNotifier,
CodeHygiene.Accounts.UserToken,
CodeHygiene.Accounts.User
],
"Accounts - Frontend": [
CodeHygieneWeb.UserAuth,
CodeHygieneWeb.UserConfirmationController,
CodeHygieneWeb.UserRegistrationController,
CodeHygieneWeb.UserResetPasswordController,
CodeHygieneWeb.UserSessionController,
CodeHygieneWeb.UserSettingsController
],
Phoenix: [
CodeHygieneWeb,
CodeHygieneWeb.Endpoint,
CodeHygieneWeb.ErrorHelpers,
CodeHygieneWeb.Gettext,
CodeHygieneWeb.LiveHelpers,
CodeHygieneWeb.Router,
CodeHygieneWeb.Router.Helpers
],
Schemas: [
CodeHygieneSchema,
CodeHygieneSchema.Product
]
]
end
Simple, we’re just providing some grouping for how our modules will display in the docs.
There are also a number of modules in our project that don’t currently have moduledocs
and which we want to exclude from the generated docs. We accomplish this by adding a @moduledoc false
attribute to these modules, for example:
/lib/code_hygiene_web/controllers/page_controller.ex
defmodule CodeHygieneWeb.PageController do
@moduledoc false
We need to add this attribute to the following files:
lib/code_hygiene_web/controllers/page_controller.ex
lib/code_hygiene_web/views/error_view.ex
lib/code_hygiene_web/views/layout_view.ex
lib/code_hygiene_web/views/page_view.ex
lib/code_hygiene_web/views/user_confirmation_view.ex
lib/code_hygiene_web/views/user_registration_view.ex
lib/code_hygiene_web/views/user_reset_password_view.ex
lib/code_hygiene_web/views/user_session_view.ex
lib/code_hygiene_web/views/user_settings_view.ex
Now we’ll see the docs are a little more organized:
Terminal
mix docs
open doc/index.html
Nice! We have a logo, name and version included in our docs and the modules are grouped in a logical manner.
Our final bit of exploration into the configuration of ExDoc
is to see how we can go about documenting things that aren’t modules.
Using ExDoc to document more than just modules
Say you have a developer guide for your project or some other sort of documentation that isn’t specific to a module but which you’d like to include in your docs. ExDoc
has you covered. First off let’s add a changelog to the project. We’ll just populate it with some fake entries.
Adding a CHANGELOG
Terminal
touch CHANGELOG.md
/CHANGELOG.md
# Change Log
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
## [1.0.3] - 2022-01-15
### Changed
- Changed stuff!
- Changed more stuff!
## [1.0.2] - 2021-12-15
### Fixed
- Fixed that terrible bug!
### Changed
- Updated the way something works.
### Added
- Added some new stuff!
## [1.0.1] - 2021-11-30
### Added
...
To reference this file in our docs, we need a new section in the docs
function, we’ll add a line to call out to an extras
function.
/mix.exs
defp docs do
[
main: "CodeHygiene",
assets: "docs/assets",
logo: "docs/assets/images/logo.svg",
source_ref: "v#{@version}",
source_url: @source_url,
formatters: ["html"],
groups_for_modules: groups_for_modules(),
extras: extras()
]
end
We then need to create the extras
function.
/mix.exs
defp extras do
[
"CHANGELOG.md"
]
end
And that’s it! You can use the same technique for adding any sort of file to the generated docs.
If we generate our docs we’ll see our CHANGELOG
show up under the Pages
tab.
The last thing we’ll look at is adding guides to our docs.
Adding guides
We can add guides to our docs via the extras function. We can further provide grouping for the guides via a groups_for_extras
function.
/mix.exs
defp docs do
[
main: "CodeHygiene",
assets: "docs/assets",
logo: "docs/assets/images/logo.svg",
source_ref: "v#{@version}",
source_url: @source_url,
formatters: ["html"],
groups_for_modules: groups_for_modules(),
extras: extras(),
groups_for_extras: groups_for_extras(),
]
end
defp extras do
[
"CHANGELOG.md",
# Guides
"docs/guides/dev_setup.md"
]
end
defp groups_for_extras do
[
Guides: ~r{guides/[^\/]+\.md}
]
end
Let’s now create our “guide”. All we are going to do is create a fake dev setup guide with some Lorem
text. We’ll also throw the Phoenix logo in there as well just to make sure assets link correctly from the docs.
So first, off we’ll create the markdown file for the guide.
Terminal
mkdir docs/guides
touch docs/guides/dev_setup.md
Now we’ll copy the Phoenix logo into the assets folder we created earlier.
Terminal
mkdir -p docs/assets/images/guides/dev_setup
cp priv/static/images/phoenix.png docs/assets/images/guides/dev_setup
And finally fill in some fake content.
/guides/dev_setup.md
# Dev Setup
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
<img src="assets/images/guides/dev_setup/phoenix.png" />
Let’s see what we got!
Terminal
mix docs
open doc/index.html
Looking good! That does it for our ExDoc
organization… now would be a good time to commit our changes, and then before bailing for the day let’s look at how we can host our docs online via GitHub.
Hosting the Docs on GitHub
Generating the documentation locally is fine, but it would be great if it was available online… and luckily this is very simple, we just need a new GitHub action.
We’ll create a new YAML
file for the action:
Terminal
touch .github/workflows/docs.yml
/.github/workflows/docs.yml
name: Publish docs
on:
push:
branches:
- main
jobs:
generateDocs:
name: Generate project documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
elixir-version: "1.13.3"
otp-version: "24.2"
- name: Build docs
uses: lee-dohm/generate-elixir-docs@v1
- name: Publish to Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./doc
This action will create a new branch called gh-pages
which will contain the docs. On any push to main
the docs will be regenerated and available online, pretty freaking neat!
Let’s try it out… if we push our code to GitHub we’ll see the new Publish docs
action we created.
And if we take a look at the branches in our repo, we now have a new gh_pages
branch.
To host the docs we need to go to the Settings –> Pages section of the GitHub repo and set the “source” for the GitHub Pages, we just set the branch to gh_pages
and keep the folder as root
.
After clicking save, we see a new GitHub action pages-build-deployment
is triggered.
After the action completes our docs are live!
Summary
That’s it for this series of posts on code hygiene tools. Getting these tools set up can take a bit of effort but IMO is well worth it!
Today’s code
If you want to retrieve the GitHub commit that corresponds to today’s code:
Terminal
mkdir <some new directory>
cd <the new directory>
Terminal
git init
git remote add origin git@github.com:riebeekn/elixir_code_hygiene.git
git fetch origin 600642de0ed22dc49c5d2ce66accb461960bce96
git reset --hard FETCH_HEAD
You should now see the expected git history.
Terminal
git log --pretty=oneline
Thanks for reading and I hope you enjoyed the post!
References
A couple of great resources I found helpful regarding how to get the most out of ExDoc
are: