<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Devsecops on dwmkerr.com</title><link>https://dwmkerr.com/categories/devsecops/</link><description>Recent content in Devsecops on dwmkerr.com</description><generator>Hugo -- gohugo.io</generator><language>en-uk</language><managingEditor>Dave Kerr</managingEditor><copyright>Copright &amp;copy; Dave Kerr</copyright><lastBuildDate>Sun, 25 Sep 2022 00:00:00 +0000</lastBuildDate><atom:link href="https://dwmkerr.com/categories/devsecops/index.xml" rel="self" type="application/rss+xml"/><item><title>A simple Makefile 'help' command</title><link>https://dwmkerr.com/makefile-help-command/</link><pubDate>Sun, 25 Sep 2022 00:00:00 +0000</pubDate><guid>https://dwmkerr.com/makefile-help-command/</guid><description>&lt;p&gt;In this article I&amp;rsquo;m going to show you how to add a &lt;code&gt;make help&lt;/code&gt; command to your makefiles that quickly and easily shows simple documentation for your commands:&lt;/p&gt;
&lt;p&gt;&lt;img src="./images/demo.svg" alt="Screen recording of the &amp;lsquo;makefile help&amp;rsquo; command in action"&gt;&lt;/p&gt;
&lt;p&gt;To add the &lt;code&gt;help&lt;/code&gt; command to your makefile, add a recipe like so:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-make" data-lang="make"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.PHONY&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; help
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;help&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Show help for each of the Makefile recipes.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; @grep -E &lt;span style="color:#e6db74"&gt;&amp;#39;^[a-zA-Z0-9 -]+:.*#&amp;#39;&lt;/span&gt; Makefile | sort | &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; read -r l; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; printf &lt;span style="color:#e6db74"&gt;&amp;#34;\033[1;32m&lt;/span&gt;$$&lt;span style="color:#e6db74"&gt;(echo &lt;/span&gt;$$&lt;span style="color:#e6db74"&gt;l | cut -f 1 -d&amp;#39;:&amp;#39;)\033[00m:&lt;/span&gt;$$&lt;span style="color:#e6db74"&gt;(echo &lt;/span&gt;$$&lt;span style="color:#e6db74"&gt;l | cut -f 2- -d&amp;#39;#&amp;#39;)\n&amp;#34;&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now just make sure that each of your recipes has a comment that follows the recipe name, which will be used as its documentation. For example, my &lt;a href="https://github.com/dwmkerr/dwmkerr.com"&gt;website repository&lt;/a&gt; has the following recipes in the makefile:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-make" data-lang="make"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;default&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; help
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.PHONY&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; help
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;help&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Show help for each of the Makefile recipes.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; @grep -E &lt;span style="color:#e6db74"&gt;&amp;#39;^[a-zA-Z0-9 -]+:.*#&amp;#39;&lt;/span&gt; Makefile | sort | &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; read -r l; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; printf &lt;span style="color:#e6db74"&gt;&amp;#34;\033[1;32m&lt;/span&gt;$$&lt;span style="color:#e6db74"&gt;(echo &lt;/span&gt;$$&lt;span style="color:#e6db74"&gt;l | cut -f 1 -d&amp;#39;:&amp;#39;)\033[00m:&lt;/span&gt;$$&lt;span style="color:#e6db74"&gt;(echo &lt;/span&gt;$$&lt;span style="color:#e6db74"&gt;l | cut -f 2- -d&amp;#39;#&amp;#39;)\n&amp;#34;&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.PHONY&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; setup
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;setup&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Setup tools required for local development.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; brew install hugo
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hugo version
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; git submodule update --init --recursive --remote
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.PHONY&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; newpost
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;newpost&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Create a new post.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cd dwmkerr.com; hugo new posts/my-first-post.md
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.PHONY&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; serve
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serve&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Serve the site locally for testing.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cd dwmkerr.com; hugo server --baseURL &lt;span style="color:#e6db74"&gt;&amp;#34;http://localhost/&amp;#34;&lt;/span&gt; --buildDrafts -v --debug
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.PHONY&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; build &lt;span style="color:#75715e"&gt;# Build the site.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;build&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cd dwmkerr.com; hugo --minify
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this setup, you can just enter &lt;code&gt;make&lt;/code&gt;, or &lt;code&gt;make help&lt;/code&gt;, to see the output below:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ make help
help: Show help for each of the Makefile recipes.
newpost: Create a new post.
serve: Serve the site locally for testing.
setup: Setup tools required for local development.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Simple! You can find the code at:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/dwmkerr/makefile-help"&gt;https://github.com/dwmkerr/makefile-help&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it Works&lt;/h2&gt;
&lt;p&gt;This project was inspired by the project &lt;a href="https://github.com/FalcoSuessgott/golang-cli-template"&gt;&lt;code&gt;golang-cli-template&lt;/code&gt;&lt;/a&gt;, which I noticed had this cool feature of showing help for the makefile commands.&lt;/p&gt;
&lt;p&gt;I built my own version of the command, which is a little bit more verbose, but I think a little easier to read and parse. I&amp;rsquo;ve also included the original version, with a link to the source in the &lt;a href="https://github.com/dwmkerr/makefile-help"&gt;&lt;code&gt;makefile-help&lt;/code&gt;&lt;/a&gt; repo.&lt;/p&gt;
&lt;p&gt;Essentially, the code simply:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Searches for recipes - these are lines that start with text, have a colon and a hash symbol&lt;/li&gt;
&lt;li&gt;Goes through each recipe found, extracts the recipe name and documentation comment&lt;/li&gt;
&lt;li&gt;Write each of the recipe names and its documentation to the console&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="testing-scripts"&gt;Testing Scripts&lt;/h2&gt;
&lt;p&gt;I wanted to make sure that if I improve on the script over time, or add different versions, the code won&amp;rsquo;t break. There&amp;rsquo;s a test script, which is a simple shell script that runs the two help commands and assets the output is as expected.&lt;/p&gt;
&lt;p&gt;At the time of writing, the shell script looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/usr/bin/env bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;set -e
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;recipes&lt;span style="color:#f92672"&gt;=(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;help&amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;help-compact&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Some colour codes for formatting.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;green&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;\033[1;32m&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;red&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;\033[1;31m&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;reset&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;\033[00m&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Default to success for the result of tests.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;result&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; recipe in &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;recipes[@]&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Create the path to the expected output file.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; expected_output&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;./test-cases/&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;recipe&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;-expected-output.txt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; ! -f &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;expected_output&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf &lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;red&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;FAIL&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;reset&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] &amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;recipe&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39; failed, test file &amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;expected_output&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39; not found\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;elif&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;make &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;recipe&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;cat &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;expected_output&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf &lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;green&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;PASS&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;reset&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] &amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;recipe&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39; passed\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf &lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;red&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;FAIL&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;reset&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] &amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;recipe&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39; failed\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Return the exit code.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;exit &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;result&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One thing that is nice about the tests is that they are incorporated into a GitHub Action, which runs the tests using Ubuntu, MacOS and Windows, and tests on both Bash and the generic &lt;code&gt;sh&lt;/code&gt; shell.&lt;/p&gt;
&lt;p&gt;This uses the following features of GitHub actions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources"&gt;Runner Images&lt;/a&gt; - predefined images are made available by GitHub for various operating systems&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsshell"&gt;Shell Specificity&lt;/a&gt; - GitHub actions allow you to specify the shell used for a step&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs"&gt;GitHub Action Matrix Strategies&lt;/a&gt; - A matrix of operating systems is specified, to avoid duplicating the pipeline steps for each supported operating system&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This project provides a nice template or starting point if you want to build a simple shell script with some basic testing features.&lt;/p&gt;
&lt;h2 id="further-reading"&gt;Further Reading&lt;/h2&gt;
&lt;p&gt;If you found this interesting, you might enjoy &lt;a href="https://effective-shell.com"&gt;Effective Shell&lt;/a&gt; - My free online book of shell techniques.&lt;/p&gt;</description><category>CodeProject</category></item></channel></rss>