Articles by Matthew ToleI occasionally write articles about web development.2020-10-11T00:00:00Zhttps://matthewtole.com/Matthew Tolehello@matthewtole.comEleventy, Markdown, and Tailwind CSS2020-05-18T00:00:00Zhttps://matthewtole.com/articles/eleventy-markdown-tailwind/<p>If you are building a website using <a href="https://11ty.dev/">Eleventy</a> and <a href="https://tailwindcss.com/">Tailwind CSS</a>, you might have come across a problem when you started trying to write Markdown content. As it states in the very top of the Tailwind documentation:</p>
<blockquote>
<p>Instead of opinionated predesigned components, Tailwind provides low-level utility classes that let you build completely custom designs without ever leaving your HTML.</p>
</blockquote>
<p>This is fantastic when you have full control over your HTML output, but becomes a bit of an issue when working with a lightweight markup language like Markdown.</p>
<p>To demonstrate what I'm talking about here is a rendering of part of this blog post before we fix the problem.</p>
<div class="my-4 border border-nord2">
<div class="flex items-center p-2 bg-nord2">
<div class="w-2 h-2 mr-1 bg-red-500 rounded-full"></div>
<div class="w-2 h-2 mr-1 bg-orange-400 rounded-full"></div>
<div class="w-2 h-2 mr-1 bg-green-500 rounded-full"></div>
</div>
<img src="https://matthewtole.com/static/images/articles/eleventy-markdown-tailwind.png" alt="Screenshot of the unstyled article" />
</div>
<p>As you can see, there's no styling being applied to any of the content, which makes it hard to read!</p>
<p>So, how can we fix this? I came up with two different approaches when building this site, and I've described them both below, with their pros and cons. Take a look and see if either of them might work for you.</p>
<h2>Create custom Tailwind components</h2>
<blockquote>
<p><strong>NOTE:</strong> This method only works if you are using Tailwind with PostCSS.</p>
</blockquote>
<p>Tailwind CSS encourages the utility first approach to CSS but does provide a mechanism for applying their styles in CSS, instead of HTML. This is intended to be used for small, commonly used components, but we can take advantage of it to style our Markdown content.</p>
<p>The <code>@apply</code> directive can be used to create CSS rules that are composed of Tailwind classes. For example, if you find yourself always using the same classes to make giant red text appear on the page, then instead of applying the Tailwind classes everywhere:</p>
<pre class="hljs"><code><span class="hljs-tag"><<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-4xl font-bold text-red-400"</span>></span>GIANT RED TEXT<span class="hljs-tag"></<span class="hljs-name">h1</span>></span>
</code></pre>
<p>You can create a new class that's built out of those class definitions, and use that everywhere.</p>
<pre class="hljs"><code><span class="hljs-selector-class">.big-red-text</span> {
<span class="hljs-keyword">@apply</span> text-<span class="hljs-number">4</span>xl text-red-<span class="hljs-number">400</span> font-bold;
}
</code></pre>
<pre class="hljs"><code><span class="hljs-tag"><<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"big-red-text"</span>></span>GIANT RED TEXT<span class="hljs-tag"></<span class="hljs-name">h1</span>></span>
</code></pre>
<blockquote>
<p>Check out the <a href="https://tailwindcss.com/docs/extracting-components#extracting-css-components-with-apply">Tailwind documentation</a> for the full details on how to use the <code>@apply</code> directive.</p>
</blockquote>
<p>So how can we use this technique for our Markdown content? Instead of creating CSS classes with the <code>@apply</code> directive, you can use them on HTML elements instead.</p>
<pre class="hljs"><code><span class="hljs-selector-class">.markdown</span> <span class="hljs-selector-tag">h1</span> {
<span class="hljs-keyword">@apply</span> text-<span class="hljs-number">4</span>xl text-red-<span class="hljs-number">400</span> font-bold;
}
<span class="hljs-selector-class">.markdown</span> <span class="hljs-selector-tag">a</span> {
<span class="hljs-keyword">@apply</span> text-blue-<span class="hljs-number">300</span>;
}
<span class="hljs-selector-class">.markdown</span> <span class="hljs-selector-tag">a</span><span class="hljs-selector-pseudo">:hover</span> {
<span class="hljs-keyword">@apply</span> underline;
}
</code></pre>
<p>Note that you cannot just use the pseudo-class prefixes as you would in your HTML, you have to specify them manually like you would in CSS.</p>
<p>You should also ensure that you put all of your Markdown CSS definitions under a class so that they don't leak out into the rest of your site. You probably don't want these rules to apply everywhere, just your Markdown content.</p>
<h3>Positives</h3>
<p>This technique is very versatile, allowing you the full flexibility of CSS combined with the utility of Tailwind.</p>
<p>The styles for your Markdown content live in your CSS files, which makes them easy to find and understand.</p>
<h3>Negatives</h3>
<p>The <code>@apply</code> directive is not intended to be used in this way, and should ideally be reserved for reusable components, not overriding the styles of base HTML elements.</p>
<p>Introducing new rules to your CSS will increase the size, although likely only by a very small amount.</p>
<h2>Add classes to the Markdown output</h2>
<p>Instead of adding new CSS rules, what if instead we could add the classes to the HTML output of the Markdown? Well, it turns out we can!</p>
<p>Eleventy gives you the ability to modify the library used to render Markdown content. You can even swap it out for an entirely different one if you like.</p>
<p>We don't need to go to that extreme for our needs, we can just use a plugin to add some classes to the output.</p>
<p>Eleventy ships with <a href="https://markdown-it.github.io/">markdown-it</a> out of the box. It's a very configurable Markdown parser that gives you full control over the rendering but it comes with pretty solid defaults to start with.</p>
<p>One of the many community-written plugins for markdown-it is called <a href="https://www.npmjs.com/package/@toycode/markdown-it-class">markdown-it-class</a> and it allows you to specify classes that get added to the HTML.</p>
<p>Before we can use the plugin, we first need to install it from npm.</p>
<pre class="hljs"><code><span class="hljs-meta">$</span><span class="bash"> npm install --save @toycode/markdown-it-class</span>
</code></pre>
<p>Then we need to add some code to our Eleventy config file to override the default Markdown parser. If you don't already have an Eleventy configuration file, start by creating it.</p>
<pre class="hljs"><code><span class="hljs-comment">// .eleventy.js</span>
<span class="hljs-built_in">module</span>.exports = <span class="hljs-function">(<span class="hljs-params">eleventyConfig</span>) =></span> {};
</code></pre>
<p>Import the markdown-it library and the markdown-it-class plugin.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> markdownIt = <span class="hljs-built_in">require</span>(<span class="hljs-string">'markdown-it'</span>);
<span class="hljs-keyword">const</span> markdownItClass = <span class="hljs-built_in">require</span>(<span class="hljs-string">'@toycode/markdown-it-class'</span>);
</code></pre>
<p>Define the mapping of HTML elements to classes. You can use strings for single classes, or arrays if you want to specify multiple classnames.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> mapping = {
<span class="hljs-attr">h1</span>: [<span class="hljs-string">'text-4xl'</span>, <span class="hljs-string">'text-red-400'</span>, <span class="hljs-string">'font-bold'</span>],
<span class="hljs-attr">a</span>: [<span class="hljs-string">'text-blue-300'</span>, <span class="hljs-string">'hover:underline'</span>],
};
</code></pre>
<p>In order to use the plugin, we have to create a new markdown-it instance and tell Eleventy to use it for handling Markdown files.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> md = markdownIt({ <span class="hljs-attr">linkify</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">html</span>: <span class="hljs-literal">true</span> });
md.use(markdownItClass, mapping);
eleventyConfig.setLibrary(<span class="hljs-string">'md'</span>, md);
</code></pre>
<p>Now when you build your site, the output of your Markdown files should look now include the Tailwind class names.</p>
<pre class="hljs"><code><span class="hljs-tag"><<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-4xl font-bold text-red-400"</span>></span>GIANT RED TEXT<span class="hljs-tag"></<span class="hljs-name">h1</span>></span>
<span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-blue-300 hover:underline"</span>></span>I'm a link!<span class="hljs-tag"></<span class="hljs-name">a</span>></span>
</code></pre>
<h3>Positives</h3>
<p>Adding the classes to the HTML that the Markdown library generates align well with the general philosophy of Tailwind.</p>
<p>This technique can be used even if you're not using Tailwind with PostCSS, such as loading it from a CDN. It also can be adapted to other atomic CSS libraries very easily.</p>
<h3>Negatives</h3>
<p>Having your Markdown content styles configured in the Eleventy configuration file makes them harder to reason about since they're not with the content <em>or</em> any of the other styles.</p>
<p>There are some limitations to the <code>markdown-it-class</code> plugin that I've found. It doesn't work with inline or block code elements.</p>
<p>You cannot have different styles for your elements depending on the context. For example, I wanted to have my inline code be styled differently if it's contained within a link.</p>
<h2>Conclusion</h2>
<p>While I would have preferred to go with the Markdown class solution, the limitations were too much for me, so for this site, I have decided to use custom Tailwind components in my CSS.</p>
<p>You can view the finished <a href="https://github.com/matthewtole/matthewtole.com/blob/master/src/_includes/postcss/styles.pcss">CSS file on Github</a> to see what I used to create the designs here.</p>
Shorthand class properties in Typescript2020-07-30T00:00:00Zhttps://matthewtole.com/articles/til-typescript-class-shorthand/<p>If you are like me and write Typescript code, you're probably very familiar with how to write classes. Here's an example of a class that you might write.</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Player</span> </span>{
<span class="hljs-keyword">private</span> name: <span class="hljs-built_in">string</span>;
<span class="hljs-keyword">private</span> age: <span class="hljs-built_in">number</span>;
<span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params">name: <span class="hljs-built_in">string</span>, age: <span class="hljs-built_in">number</span></span>)</span> {
<span class="hljs-built_in">this</span>.name = name;
<span class="hljs-built_in">this</span>.age = age;
}
<span class="hljs-keyword">public</span> isOld(): <span class="hljs-built_in">boolean</span> {
<span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.age >= <span class="hljs-number">65</span>;
}
}
</code></pre>
<p>At work today I stumbled across some code that I didn't quite understand, but after running some experiments on the <a href="https://www.typescriptlang.org/play/index.html#code/MYGwhgzhAEAK4E8CmAnaBvAUNawD2AdhAC4oCuwxeKAFAA4oCWAbmMUtAWALZIBc0EkwIBzADTQGLNhzAj+nMtwBGqAJQZs0AL6YtdMspCNg0RhADyIACY01A5XjwgkYAppw4USYmRTviAAtzADo5DgA+AF5oADYAVgBuLV1tIA">Typescript playground</a> and finding a random StackOverflow article talking about it, I realized I have discovered a shorthand way of declaring class properties in Typescript. The same Player class can be written like this.</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Player</span> </span>{
<span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> name: <span class="hljs-built_in">string</span>, <span class="hljs-keyword">private</span> age: <span class="hljs-built_in">number</span></span>)</span> {
<span class="hljs-comment">// Don't need anything here!</span>
}
<span class="hljs-keyword">public</span> isOld(): <span class="hljs-built_in">boolean</span> {
<span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.age >= <span class="hljs-number">65</span>;
}
}
</code></pre>
<p>By adding the scope of the properties to the constructor, it automatically creates properties on the class with the same name!</p>
<p>I couldn't find anything about this in the Typescript documentation, or many people using this, but I thought it was pretty cool and wanted to share.</p>
My testing philosophy2020-08-03T00:00:00Zhttps://matthewtole.com/articles/testing-philosophy/<p><strong>tl;dr</strong> The purpose of writing tests for your code is to protect it against accidental future breakages, not just to validate the current behavior.</p>
<h2>Background</h2>
<p>I have a Master's degree in Computer Forensics and spent the first four years of university working for a company that did, amongst other things, computer forensics. One of the most important principles of doing good computer forensics (and presumably all forensics) is to take really good notes on everything you do, as you are doing it.</p>
<p>For example, the first step in many computer forensic investigations is to remove the hard drive from a computer and image it (create a virtual clone of the entire disk). Before you touch the computer, you would need to note down any serial numbers you can see, maybe take photos of the case, etc. Then when you remove the drive, you would again record serial numbers and note down anything special or interesting about the drive. When you do the imaging, you would write down the time and date that you started, what version of the software or hardware you were using to clone the drive. When the drive was cloned, you would verify the clone by generating a hash for the original disk and the clone image and noting it down.</p>
<p>The general rule of thumb for note-taking was that "if you didn't write it down then it didn't happen". The idea is that if you were ever called to court to testify about your investigation, you would only be able to defend your actions if you had written them down at the time.</p>
<p>Thankfully I never had to go to court for any of the forensic investigations I did, but that principle has still stuck with me as I transitioned into my career as a software engineer. But now I apply it to thinking about what to write tests for.</p>
<h2>Why write tests</h2>
<p>When most people talk about writing tests, it's as a way to validate the behavior of a function or component. This is the principle behind things like Test Driven Development, where you write the tests first and then implement just enough code to get them to pass.</p>
<p>This is a perfectly valid reason to write tests, and for some parts of your code, it's absolutely vital to have good unit test coverage to ensure that all of the edge cases are validated. But I don't think this is the most important reason to write tests. For most of the code we write, it's so easy to manually check that it works that it seems pointless to write tests to validate it.</p>
<p>What is much more important is protected that functionality against accidental breakages in the future.</p>
<p>Here is an example of a React component and a corresponding test written using <a href="https://github.com/testing-library/react-testing-library">React Testing Library</a>.</p>
<pre class="hljs"><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> MyComponent: React.FC = <span class="hljs-function">() =></span> {
<span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag"><<span class="hljs-name">AwesomeButton</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{doSomethingCool}</span>></span>Click Me!<span class="hljs-tag"></<span class="hljs-name">AwesomeButton</span>></span></span>;
};
</code></pre>
<pre class="hljs"><code>describe(<span class="hljs-string">'MyComponent'</span>, <span class="hljs-function">() =></span> {
it(<span class="hljs-string">'should do something cool when the awesome button is clicked'</span>, <span class="hljs-function">() =></span> {
<span class="hljs-keyword">const</span> {getByText} = render(<span class="xml"><span class="hljs-tag"><<span class="hljs-name">MyComponent</span> /></span></span>);
fireEvent.click(getByText(<span class="hljs-string">'Click Me!'</span>));
expect(somethingCool).toHaveHappened();
});
});
</code></pre>
<p>If you think of tests purely as a way to verify the current behavior, then this might seem like a bit of a pointless test. But if you think about tests as a guarantee against future problems, then it makes a lot more sense. For example, the developer of the AwesomeButton component might decide that the onClick callback only fires on a double click. Without any tests, how would they know that this was going to break your feature? How would you know that the behavior changed until it was broken in production?</p>
<p>Obviously, this is a particularly contrived and overly simplistic example, but it demonstrates the underlying principle of the value of writing good tests. As I have repeatedly told folks who refused to write tests for their new feature, if something doesn't have tests, then I cannot guarantee that I won't break or disable it in the future.</p>
<h2>How I think about tests</h2>
<p>I have taken the mantra of note-taking from my computer forensic days and come up with an equivalent for testing code.</p>
<blockquote>
<p>If your code doesn't have tests, then it doesn't exist</p>
</blockquote>
<p>It's that simple. If your code doesn't have any tests, then how can you be sure it won't change, break, or completely disappear in the future? This has been demonstrated multiples times in my professional career. In one example, a coworker was doing a refactor of some code and accidentally left out a couple of lines of code that showed a prompt to users to encourage them to upgrade their account. This breakage went unnoticed for months and potentially cost the business over one million dollars in recurring revenue. How did this happen? There were zero tests for this functionality and so our team had no idea we had broken their behavior.</p>
<p>Writing good tests is hard, and for most of us, not that enjoyable, but it is vitally important. Not just to make sure you got the code right the first time, but to make sure it doesn't break in the future. Be nice to your future selves (or more likely, a future stranger) and write tests!</p>
Code reviews are for humans2020-09-26T00:00:00Zhttps://matthewtole.com/articles/code-reviews-are-for-humans/<p>Code reviews, diffs, pull requests. Whatever you call them, reviewing other people's code is one of the most vital skills to become a great software developer. At work, I average about 600 code reviews a year, which means I've spent a lot of time giving and thinking about code reviews over the last few years.</p>
<p>I have read many articles with advice on how to give better code reviews, and while I have agreed with them all to varying degrees, none of them have really covered the <em>why</em> of it all.</p>
<h2>Code reviews are for your users.</h2>
<p>If you are reviewing some code, it's almost certain that someone will use it. After all, what's the point of code that nobody uses? Whether they other developers who depend on your library, visitors to your web app, creators who are trying to make a living on your platform, or people who rely on your website for critical information, your users matter. In fact, they are the people who should matter the most.</p>
<p>When you are reviewing code, always keep your users at the front of your mind. Does this feature make your product better for your users? Will this make it easier or harder for them to achieve their goals?</p>
<h2>Code reviews are for the author.</h2>
<p>Until robots take over the programming jobs, the code you are reviewing was written by a person. It's especially important to remember this when pointing out mistakes or problems in the code. Your job is not to make the other person feel better, and you shouldn't avoid leaving feedback because it might avoid hurting their feelings. After all, remember that your users should be your highest priority, and bad code does not help them out. Instead, try and find less abrasive ways to phrase your feedback, always focussing on the code and not on the person.</p>
<p>The other way code reviews are about the person who wrote the code is that they are often the best way for them to learn new things. If you are a senior engineer or have more experience in the codebase, framework, or language than the person who wrote the code, it is your job to pass on the knowledge you've learned to help them grow into a better engineer.</p>
<h2>Code reviews are for your colleagues.</h2>
<p>The code you are reviewing is reasonably going to impact the other people who work at your company or organization. Code that is hard to understand or tricky to maintain will make other people's lives harder down the road. It's always tempting to accept small issues with the code, and sometimes that's the right choice, especially if you're on a deadline or building out an experimental feature. But technical debt stacks up fast, and it's always useful to think about what someone who joins the project a year from now might find confusing about the code you're reviewing.</p>
<p>There's another way in which your code reviews may affect your coworkers, and that's with code that causes problems for your business. While your users and coworkers should be your highest priority, if you allow code through that drives your business to lose money, it could end up with people losing their jobs.</p>
<h2>Code reviews are for you.</h2>
<p>This section is deliberately last because you are the least important person when it comes to code reviews. They are not an opportunity for you to show off how smart you are or to make yourself feel better by tearing other people down. You need to leave your ego at the door when doing code reviews. It doesn't matter if they've written code in a style that you don't like or that you could do it better. If the code is serving your users and makes your project better, without causing problems for your coworkers, then it's valid code.</p>
<p>When reviewing code written by other people, you should always be open to learning new things. If you see something you don't quite understand, or that you would have used a different approach to solve, ask the author about it. It could be that they know something you don't, and it's such a fantastic opportunity to grow as an engineer, whether you're new or you've been coding your entire life. If you do learn something code review, you should leave a comment letting them know. It might even spark a conversation about evolving your team coding guidelines.</p>
<h2>Conclusion</h2>
<p>When reviewing other people's code, remember that the people are more important than the code. Focus on your users and your coworkers, and it'll make it easier to decide whether or not you need to leave that comment.</p>
<h2>Extra reading</h2>
<p>I am a big fan of the <a href="https://conventionalcomments.org/">Conventional Comments</a> standard for formatting your code review feedback. Having a pattern you can follow when adding comments helps me avoid wasting time figuring out how to structure what I want to say.</p>
How I made my Github profile dynamic2020-10-11T00:00:00Zhttps://matthewtole.com/articles/dynamic-github-profile/<p>If you use Github, you've probably seen the new feature that lets you <a href="https://docs.github.com/en/free-pro-team@latest/github/setting-up-and-managing-your-github-profile/managing-your-profile-readme">customize your profile page</a> by creating a README file in a repository with the same name as your username. It's a really nice way to provide more context and show off what you've been working on.</p>
<p>Despite this being a relatively new feature, people have already built some really cool tools for enhancing your profiles, including <a href="https://arturssmirnovs.github.io/github-profile-readme-generator/">generators</a> and <a href="https://github.com/anuraghazra/github-readme-stats">dynamic images that show your Github stats</a>.</p>
<p>I wanted to keep my profile simple and clean, but I wanted it to always link to the most recently published blog post on my website. <s>I tried to find other projects that were doing the same thing but I couldn't find any, so I built it myself.</s> While writing this blog post I came across <a href="https://simonwillison.net/2020/Jul/10/self-updating-profile-readme/">this awesome project</a> from <a href="https://simonwillison.net/">Simon Willison</a>.</p>
<h2>Dynamic Profile</h2>
<p>The first thing I built was <a href="https://github.com/matthewtole/dynamic-profile"><code>dynamic-profile</code></a>, a small NPM CLI that takes a template markdown file and a configuration file and generates a README out of it. Currently it only supports the RSS feed feature but I plan on adding more things in the future.</p>
<p>As an example of how it works, here's a configuration file...</p>
<pre class="hljs"><code>{
<span class="hljs-attr">"feedUrl"</span>: <span class="hljs-string">"http://matthewtole.com/rss.xml"</span>
}
</code></pre>
<p>... and the corresponding template.</p>
<pre class="hljs"><code>[<span class="hljs-string">{{article.title}}</span>](<span class="hljs-link">{{article.link}}</span>)
</code></pre>
<p>When you run the script...</p>
<pre class="hljs"><code>npx github:matthewtole/dynamic-profile
</code></pre>
<p>... this is what will be output.</p>
<pre class="hljs"><code>[<span class="hljs-string">How I made my Github profile dynamic</span>](<span class="hljs-link">https://matthewtole.com/articles/dynamic-github-profile/</span>)
</code></pre>
<h2>Github Action</h2>
<p><a href="https://github.com/features/actions">Github Actions</a> allows you to write automated tasks for your repository in the form of workflows. You can use them to run automated tests on pull requests, auto-triage incoming issues, or even silly things like keeping your profile up to date. One of the powerful things about Github Actions is that it's really easy to share and re-use other people's actions, so you can build up really complex workflows without having to write any code.</p>
<p>This is the action I am <a href="https://github.com/matthewtole/matthewtole/blob/master/.github/workflows/blank.yml">currently using</a> for my profile repository.</p>
<pre class="hljs"><code><span class="hljs-attr">name:</span> <span class="hljs-string">Dynamic</span> <span class="hljs-string">Profile</span>
<span class="hljs-attr">on:</span>
<span class="hljs-attr">issues:</span>
<span class="hljs-attr">types:</span> [<span class="hljs-string">opened</span>]
<span class="hljs-attr">jobs:</span>
<span class="hljs-attr">build:</span>
<span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
<span class="hljs-attr">steps:</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">dynamic-profile</span>
<span class="hljs-attr">run:</span> <span class="hljs-string">npx</span> <span class="hljs-string">github:matthewtole/dynamic-profile;</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Push</span> <span class="hljs-string">changes</span>
<span class="hljs-attr">uses:</span> <span class="hljs-string">actions-go/push@v1</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Close</span> <span class="hljs-string">Issue</span>
<span class="hljs-attr">uses:</span> <span class="hljs-string">peter-evans/close-issue@v1.0.2</span>
</code></pre>
<p>When Github detects a new issue on the repository, it checks out the code to a temporary directory, then it runs my <code>dynamic-profile</code> script to update the README file. Then it pushes the changes back to Github and closes out the issue.</p>
<h2>IFTTT</h2>
<p>You might be wondering why the Github Action runs on a new issue. This is because that was the simplest way to connect it up to the last part of the puzzle, IFTTT. <a href="https://github.com/features/actions">If This Then That</a> is a web service that lets you build simple connections between two tools. For example, you could have it save <a href="https://ifttt.com/applets/rveqra5B">Facebook photos you get tagged in to Dropbox</a>, or get a <a href="https://ifttt.com/applets/YfkYtQB2">notification when the ISS is passing over your house</a>.</p>
<p>IFTTT has a Github integration, but the only thing it supports is creating issues. So that's what I did. When it detects a new entry in my RSS feed, it creates an issue on the profile repository, which triggers the Github Action.</p>
<h2>Next Steps</h2>
<p>The post you're reading right now is actually my first real world test of the entire system working end-to-end, so I might be spending some time debugging it when it inevitably goes wrong.</p>
<p>Once it's working, I want to add some more functionality to the <code>dynamic-profile</code> project and publish it to NPM with more generalizable instructions on using it for your own profile. If you have any feature requests please submit an issue on the <a href="https://github.com/matthewtole/dynamic-profile/issues">Github repository</a>.</p>