Earlier this year I wrote about the challenges I faced creating a Terraform module. I mentioned then that I was leveraging terraform-docs and GitHub Actions to automate documentation, but a full workflow walkthrough was out of that post's scope.
This post, however, is entirely focused on automated documentation.
If you're looking for an easy way to save time, enforce documentation formatting standards, or ensure documentation is kept up-to-date - my autodoc workflow is a great place to start.
The Workflow
The workflow starts by defining a name, a start condition, and a host that will execute the job.
name: "Autodoc Workflow - Terraform-docs"
on:
pull_request:
jobs:
tfdocs:
runs-on: ubuntu-latest
On a pull request, GitHub Actions will provision a Ubuntu VM with the latest OS version considered "stable" by GitHub.
Note: The
-latest
runner images are the latest stable images that GitHub provides, and might not be the most recent version of the operating system available from the operating system vendor.
Repo clone
Now that the job has been defined, the first step will clone the repository down to the runner. More specifically, it will pull the PR head from Actions context.
steps:
- name: Pull request checkout
uses: actions/checkout@v3
id: checkout
with:
ref: ${{ github.event.pull_request.head.ref }}
With a local copy of the code now available, the runner can update the documentation.
Generating documentation
This step uses the terraform-docs action to update the README.md.
- name: README.md generation
uses: terraform-docs/gh-actions@main
id: tfdocs
with:
config-file: terraform-docs.yaml
working-dir: .
output-file: README.md
output-method: inject
git-push: "true"
If you'd prefer to install the CLI tool on the runner and execute the commands directly from the shell, other installation options exist.
Action arguments
The terraform-docs action accepts many arguments, but the five below are used by this workflow.
- config-file accepts the terraform-docs config file.
- working-dir specifies the location of the terraform files.
- output-file defines the name of the generated/updated doc.
-
output-method accepts print, replace, or inject. If other content (e.g. content not generated by terraform-docs) exists within the README.md file, you'll want to use inject. Inject updates the existing file and places the newly created documentation between the hardcoded delimiters
<!-- BEGIN_TF_DOCS -->
and<!-- END_TF_DOCS -->
. - git-push is set to "true" and adds the newly updated document to the pull request.
Markdown formatting
GitHub understands markdown formatting in readme files, posts, and comments. The terraform-docs.yaml file specifies markdown output to take advantage of this.
formatter: "markdown table"
You can find the full example terraform-docs.yaml file here.
Resulting output
This is what the README.md file looks like after the pull request is merged:
Premerge Review
Now that the README.md has been updated, approvers will want to review the changes prior to merging branches.
The next two steps will post updated content to pull request review thread for the approver's convenience.
Echoing contents
The output step echoes the file content into a standard GitHub environmental variable, github_env.
- name: Output README.md
id: output
run: |
echo 'readme<<EOF' >> $GITHUB_ENV
echo "$(<README.md)" >> $GITHUB_ENV
echo 'EOF' >> $GITHUB_ENV
Escape characters
Streaming output of the file into a variable will strip the content of "escape characters", including newline. To preserve these special characters, $(<README.md) is wrapped in double quotes.
echo "$(<README.md)"
Multiline strings
Action's requirements surrounding environmental variables restrict the use of multiline strings. "EOF" (end of file) is used as the delimiter to circumvent this restriction.
echo 'readme<<EOF' >> $GITHUB_ENV
echo "$(<README.md)" >> $GITHUB_ENV
echo 'EOF' >> $GITHUB_ENV
The updated markdown content can now be used in the next step.
Pull request comment
The last step in the workflow creates a comment on the pull request thread in GitHub with the script action.
A fine-grained token grants access to the repository. It is stored as the secret GH_TOKEN.
- name: Pull request comment
id: comment
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GH_TOKEN }}
script: |
const output = `Terraform-docs has updated the README.md.
${process.env.readme}`
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
})
The markdown stored in the previous step is referenced with ${process.env.readme}.
After the job is completed, this is what the comment looks like:
Wrapping up
The job is complete and the documentation has been updated! If you'd like to test this workflow yourself, fork and modify my example module - Configure the repository permissions, modify a new branch, and kick off a pull request to see it in action.
If you're interested in learning more about terraform-docs, checkout their user guide or drop by their slack.
Thanks for taking the time read this post!
Top comments (0)