<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Frederic Lemay</title>
    <description>The latest articles on DEV Community by Frederic Lemay (@fredericlemay).</description>
    <link>https://dev.to/fredericlemay</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F261122%2F1878ff5f-4db0-47b3-b4e7-1cea6db8830c.jpeg</url>
      <title>DEV Community: Frederic Lemay</title>
      <link>https://dev.to/fredericlemay</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fredericlemay"/>
    <language>en</language>
    <item>
      <title>Generate Table of Contents with GitHub Actions</title>
      <dc:creator>Frederic Lemay</dc:creator>
      <pubDate>Wed, 27 Nov 2019 08:29:54 +0000</pubDate>
      <link>https://dev.to/fredericlemay/generate-table-of-contents-with-github-actions-3a0b</link>
      <guid>https://dev.to/fredericlemay/generate-table-of-contents-with-github-actions-3a0b</guid>
      <description>&lt;p&gt;I love taking notes in Markdown and lately, I've been using &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; to write (and store) them.&lt;/p&gt;

&lt;p&gt;There are many advantages of using GitHub: accessible on different platforms, online, offline, Markdown support, editor agnostic, versioning, simple structure (files/folders), and free.&lt;/p&gt;

&lt;p&gt;However, one thing that is not supported out of the box is generating Table of Contents (TOC). With it, I can organize my notes differently and have many of them into a single Markdown file.&lt;/p&gt;

&lt;p&gt;Here is how I generate the Table of Contents for my notes using &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Make&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Compose&lt;/li&gt;
&lt;li&gt;GitHub account&lt;/li&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;li&gt;Terminal&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;My notes repository contains many files and folders but for the purpose of this blog post, I will keep everything as simple as possible. Below is the file structure of an example git repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tree -a
.
├── .git
│   ├── ...
├── Makefile
├── docker-compose.yml
├── story.md
└── package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The repository has one note written in Markdown called &lt;code&gt;story.md&lt;/code&gt; which has some random content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Story&lt;/span&gt;

&lt;span class="gu"&gt;## Introduction&lt;/span&gt;

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Praesent elementum tincidunt felis, condimentum accumsan nibh imperdiet nec.
Sed cursus justo eu purus rhoncus, id facilisis lorem semper.

&lt;span class="gu"&gt;## Development&lt;/span&gt;

Duis nunc arcu, bibendum quis turpis ut, dapibus feugiat massa.
Sed tempus tortor eget diam porta vulputate. Ut tempor iaculis suscipit.
Morbi scelerisque felis ac justo consectetur luctus.

&lt;span class="gu"&gt;## Conclusion&lt;/span&gt;

Nullam malesuada rutrum gravida. Vivamus sit amet fermentum odio.
Donec tincidunt ex odio, vitae convallis ante posuere nec.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since generating the Table of Contents is not a default option, I searched for a generator and found &lt;a href="https://github.com/thlorenz/doctoc" rel="noopener noreferrer"&gt;DocToc&lt;/a&gt;, a NodeJS module.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;DocToc: Generates table of contents for markdown files inside local git repository. Links are compatible with anchors generated by github or other sites.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To use DocToc, I created &lt;code&gt;package.json&lt;/code&gt; file and added the module as a development dependency.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mynotes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"doctoc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.4.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I often use Docker to ensure consistency between different platforms like, in this case, my laptop and GitHub. In the &lt;code&gt;docker-compose.yml&lt;/code&gt; file, I defined a service named &lt;code&gt;node&lt;/code&gt; which will be used to install DocToc and generate the TOC using the latest NodeJS Docker image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.7'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bind&lt;/span&gt;
        &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;."&lt;/span&gt;
        &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/opt/app&lt;/span&gt;
    &lt;span class="na"&gt;working_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/opt/app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last file is &lt;code&gt;Makefile&lt;/code&gt; which encapsulates the Docker Compose commands. The &lt;code&gt;deps&lt;/code&gt; target downloads the NodeJS Docker image and installs DocToc. The &lt;code&gt;generateTOC&lt;/code&gt; target generates the Table of Contents with DocToc inside a NodeJS Docker container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;deps&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    docker-compose pull node
    docker-compose run &lt;span class="nt"&gt;--rm&lt;/span&gt; node yarn &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="nl"&gt;generateTOC&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    docker-compose run &lt;span class="nt"&gt;--rm&lt;/span&gt; node yarn doctoc .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, to include the TOC to my notes, I simply run &lt;code&gt;make deps generateTOC&lt;/code&gt; in a terminal. The &lt;code&gt;story.md&lt;/code&gt; file is now updated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- START doctoc generated TOC please keep comment here to allow auto update --&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --&amp;gt;&lt;/span&gt;
&lt;span class="gs"&gt;**Table of Contents**&lt;/span&gt;  &lt;span class="ge"&gt;*generated with [DocToc](https://github.com/thlorenz/doctoc)*&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Story&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;#story&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;    -&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Introduction&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;#introduction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;    -&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Development&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;#development&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;    -&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Conclusion&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;#conclusion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- END doctoc generated TOC please keep comment here to allow auto update --&amp;gt;&lt;/span&gt;

&lt;span class="gh"&gt;# Story&lt;/span&gt;

&lt;span class="gu"&gt;## Introduction&lt;/span&gt;

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Praesent elementum tincidunt felis, condimentum accumsan nibh imperdiet nec.
Sed cursus justo eu purus rhoncus, id facilisis lorem semper.

&lt;span class="gu"&gt;## Development&lt;/span&gt;

Duis nunc arcu, bibendum quis turpis ut, dapibus feugiat massa.
Sed tempus tortor eget diam porta vulputate. Ut tempor iaculis suscipit.
Morbi scelerisque felis ac justo consectetur luctus.

&lt;span class="gu"&gt;## Conclusion&lt;/span&gt;

Nullam malesuada rutrum gravida. Vivamus sit amet fermentum odio.
Donec tincidunt ex odio, vitae convallis ante posuere nec.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Et voilà! I then commit my changes to &lt;code&gt;master&lt;/code&gt;, push, and view them on GitHub.&lt;/p&gt;

&lt;p&gt;This works well on a computer where tools like Make, Docker, and Compose are installed. I could even go furter and automate the process with &lt;a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks" rel="noopener noreferrer"&gt;Git Hooks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, what if I write on a tablet or directly on GitHub website? The Table of Contents will likely get out of date. Wouldn't be great to get it generated no matter where the notes are written from? GitHub Actions to the rescue!&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub Actions
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt; makes it easy to automate all your software workflows, now with world-class CI/CD. Build, test, and deploy your code right from GitHub. Make code reviews, branch management, and issue triaging work the way you want.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Below is the structure of the example git repository with GitHub Actions included.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tree -a
.
├── .git
│   ├── ...
├── .github
│   └── workflows
│       └── generate_toc.yml
├── Makefile
├── docker-compose.yml
├── story.md
└── package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I defined a workflow in the &lt;code&gt;.github/workflows/generate_toc.yml&lt;/code&gt; file to generate the Table of Contents whenever I push to &lt;code&gt;master&lt;/code&gt; branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Generate TOC&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;generateTOC&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v1&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Generate TOC&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;make deps generateTOC&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Auto commit&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stefanzweifel/git-auto-commit-action@v2.1.0&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;commit_message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Apply automatic changes - TOC generated&lt;/span&gt;
        &lt;span class="na"&gt;branch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This workflow checks out the repository on a &lt;code&gt;master&lt;/code&gt; branch push event, runs the command &lt;code&gt;make deps generateTOC&lt;/code&gt; to generate the Table of Contents, and finally, commits the changes automatically to &lt;code&gt;master&lt;/code&gt; with the GitHub Action named &lt;a href="https://github.com/marketplace/actions/auto-commit-changed-files" rel="noopener noreferrer"&gt;git-auto-commit-action&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;From the GitHub repository, I can see my Generate TOC workflow being executed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fwbfkk9nykth2mnvz362n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fwbfkk9nykth2mnvz362n.png" alt="GitHhub Workflows" width="800" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And see the automated commit with the Table of Contents updated from the workflow right after I updated my notes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Faouej6wbteq53ovfgq86.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Faouej6wbteq53ovfgq86.png" alt="GitHub Commits" width="800" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;I am more than happy that GitHub Actions supports Make, Docker, and Compose. I could develop and test locally some parts of my workflow, and feel confident that they will work on GitHub. And now, I can write my notes from anywhere and get the Table of Contents magically updated. This is a simple use case but there are many Actions that can just be "plug &amp;amp; play" to create more sophisticated workflows.&lt;/p&gt;






&lt;p&gt;Liked this blog post? Checkout &lt;a href="https://3musketeers.io" rel="noopener noreferrer"&gt;3musketeers.io&lt;/a&gt; to learn more about how to build, test, and deploy your apps from anywhere, the same way!&lt;/p&gt;



&lt;p&gt;&lt;em&gt;Disclaimer: Do your own research before using this solution and do not store sensitive information in plain text on GitHub.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>github</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
