<?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: Matt Smith</title>
    <description>The latest articles on DEV Community by Matt Smith (@mattorb).</description>
    <link>https://dev.to/mattorb</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%2F280278%2F19ebfc6c-6250-4969-92d0-ad7007b1f03d.jpeg</url>
      <title>DEV Community: Matt Smith</title>
      <link>https://dev.to/mattorb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mattorb"/>
    <language>en</language>
    <item>
      <title>Github Action for Lighthouse</title>
      <dc:creator>Matt Smith</dc:creator>
      <pubDate>Wed, 05 Feb 2020 14:12:19 +0000</pubDate>
      <link>https://dev.to/mattorb/github-action-for-lighthouse-5ak1</link>
      <guid>https://dev.to/mattorb/github-action-for-lighthouse-5ak1</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8g_vLk08--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/02/james-wheeler-%40souvenirpixels-InOgamK2cuY-unsplash.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8g_vLk08--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/02/james-wheeler-%40souvenirpixels-InOgamK2cuY-unsplash.jpg" alt="Github Action for Lighthouse"&gt;&lt;/a&gt; photo credit: &lt;a href="https://unsplash.com/@souvenirpixels"&gt;james-wheeler&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After using a &lt;a href="https://mattorb.com/github-action-for-google-pagespeed-insights/"&gt;Github action to assess web page performance with Google PageSpeed&lt;/a&gt;, I found out that &lt;a href="https://bit.ly/lhpsi5"&gt;PageSpeed leverages a tool called Lighthouse&lt;/a&gt; for most of what it now provides.  When I was configuring a &lt;a href="https://mattorb.com/github-action-for-javascript-vulnerability-scan/"&gt;Github action to check for Javascript library security vulnerabilities&lt;/a&gt;, I remember it using a package called Lighthouse, too.&lt;/p&gt;

&lt;p&gt;🤔&lt;/p&gt;

&lt;p&gt;According to Google, the &lt;a href="https://github.com/GoogleChrome/lighthouse"&gt;Lighthouse project&lt;/a&gt; provides . . .&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Automated auditing, performance metrics, and best practices for the web"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;NOTE: This is the same suite of tests that execute when you launch Google Chrome and use the audits tab in Developer Tools, and the same suite of tests that now provide a large portion of what is reported back by Google PageSpeed.&lt;/p&gt;

&lt;p&gt;Some quick scouting on Github revealed some existing efforts focused around &lt;a href="https://github.com/andreasonny83/lighthouse-ci"&gt;making Lighthouse easier to plug in to CI/CD&lt;/a&gt; and &lt;a href="https://github.com/treosh/lighthouse-ci-action"&gt;packaging it into a Github Action&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For the purpose of asserting and maintaining a baseline performance level on &lt;a href="https://mattorb.com/"&gt;this site&lt;/a&gt;, we're going to try leveraging the &lt;a href="https://github.com/treosh/lighthouse-ci-action"&gt;Lighthouse Github Action&lt;/a&gt;.   Thanks to Aleksey and the contributors!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Github Action
&lt;/h2&gt;

&lt;p&gt;First step: add a workflow file &lt;em&gt;.github/workflows/lighthouse.yml&lt;/em&gt; in the Github repository which should trigger Lighthouse:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Lighthouse
on: 
  push:
    branches:
    - master
jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Audit URLs using Lighthouse
        uses: treosh/lighthouse-ci-action@v2
        with:
          urls: 'https://mattorb.com/'
      - name: Save results
        uses: actions/upload-artifact@v1
        with:
          name: lighthouse-results
          path: '.lighthouseci'

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After committing that workflow file, it executes, and we can go grab the artifact generated by lighthouse and see what our scores look like.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---3stXcgn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/02/Screen-Shot-2020-02-04-at-8.32.18-AM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---3stXcgn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/02/Screen-Shot-2020-02-04-at-8.32.18-AM.png" alt="Github Action for Lighthouse"&gt;&lt;/a&gt;Find Github action artifacts here&lt;/p&gt;

&lt;p&gt;That zip file contains both a json and html representation of the report.&lt;/p&gt;

&lt;p&gt;Inspecting the summary portion of the html report gives us overall scores in various areas and provides much more detail below that fold:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BJnlz7XC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/02/Screen-Shot-2020-02-04-at-8.28.11-AM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BJnlz7XC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/02/Screen-Shot-2020-02-04-at-8.28.11-AM.png" alt="Github Action for Lighthouse"&gt;&lt;/a&gt;Lighthouse scoring areas, summary. For breakdown and recommendations, see full report.&lt;/p&gt;

&lt;p&gt;Based on those numbers, decide where to &lt;em&gt;draw the line&lt;/em&gt; and set a threshold to not fall below in each of the categories.  Leave some room for variability in server performance though.  Nobody wants to be dealing with false alerts regularly.&lt;/p&gt;

&lt;p&gt;Create a &lt;em&gt;.github/lighthouse/lighthouserc.json&lt;/em&gt; file in the repository with Lighthouse assertions you want to enforce:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "ci": {
    "assert": {
      "assertions": {
        "categories:performance": ["error", {"minScore": 0.90}],
        "categories:accessibility": ["error", {"minScore": 0.80}],
        "categories:best-practices": ["error", {"minScore": 0.92}],
        "categories:seo": ["error", {"minScore": 0.90}]
      }
    }
  }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Configure the stanza in the Github Action at &lt;em&gt;.github/workflows/lighthouse.yml&lt;/em&gt; to enact those assertions by pointing it to that config file:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✂️ 

    steps:
      - uses: actions/checkout@v1
      - name: Audit URLs using Lighthouse
        uses: treosh/lighthouse-ci-action@v2
        with:
          urls: 'https://mattorb.com/'
          configPath: '.github/lighthouse/lighthouserc.json' # Assertions config file 

✂️ 

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next time the action executes, it will check that we don't drop below these thresholds.  &lt;/p&gt;

&lt;p&gt;If one of those assertions fails, it will fail the workflow with a message:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Pp-hZM9C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/02/Screen-Shot-2020-02-04-at-8.45.18-AM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Pp-hZM9C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/02/Screen-Shot-2020-02-04-at-8.45.18-AM.png" alt="Github Action for Lighthouse"&gt;&lt;/a&gt;Failing to meet the performance criteria&lt;/p&gt;

&lt;p&gt;You can fail the workflow based on overall scores or make even finer grained assertions using items called out in the detail of the report.  Check out the &lt;a href="https://github.com/GoogleChrome/lighthouse-ci/blob/master/docs/assertions.md"&gt;Lighthouse CI documentation on assertions&lt;/a&gt; for examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Going Further
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Run a &lt;a href="https://github.com/GoogleChrome/lighthouse-ci"&gt;Lighthouse CI server&lt;/a&gt; to provide tracking of these metrics over time in a purpose built solution for that.&lt;/li&gt;
&lt;li&gt;Use multiple runs to average out server performance and draw more manageable thresholds.
&lt;/li&gt;
&lt;li&gt;Use the concept of a &lt;a href="https://web.dev/use-lighthouse-for-performance-budgets/"&gt;page performance budget&lt;/a&gt; to set guide-rails and limits around size and quantity of external (think .js and .css) resources.&lt;/li&gt;
&lt;li&gt;Shift left and assess a site change while it is still in the PR stage &lt;/li&gt;
&lt;li&gt;Design specific test suites and set unique performance/seo requirements based on what kind of page is being probed.&lt;/li&gt;
&lt;li&gt;Leverage a &lt;a href="https://github.com/ampproject/amp-toolbox/tree/master/packages/lighthouse-plugin-amp"&gt;Lighthouse plugin&lt;/a&gt; to assess pages that have opinionated and strict design requirements for their target platforms (i.e. - &lt;a href="https://en.wikipedia.org/wiki/Accelerated_Mobile_Pages"&gt;AMP&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>performance</category>
      <category>softwaredelivery</category>
      <category>development</category>
    </item>
    <item>
      <title>Github Action for Javascript Vulnerability Scanning</title>
      <dc:creator>Matt Smith</dc:creator>
      <pubDate>Wed, 29 Jan 2020 14:44:17 +0000</pubDate>
      <link>https://dev.to/mattorb/github-action-for-javascript-vulnerability-scanning-572e</link>
      <guid>https://dev.to/mattorb/github-action-for-javascript-vulnerability-scanning-572e</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--712Zn3nX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/01/gisela-bonanno-%40gise_bon-a073XCeYm1U-unsplash.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--712Zn3nX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/01/gisela-bonanno-%40gise_bon-a073XCeYm1U-unsplash.jpg" alt="Github Action for Javascript Vulnerability Scanning"&gt;&lt;/a&gt; photo credit: &lt;a href="https://unsplash.com/@gise_bon"&gt;gisela-bonanno&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Part of what is served by &lt;a href="https://mattorb.com"&gt;this&lt;/a&gt; web site includes 3rd party javascript libraries.    The libraries included in a page are a mash-up of libraries and dependencies from a few    sources.  &lt;/p&gt;

&lt;p&gt;Those libraries occasionally have security vulnerabilities disclosed.  In our last post, we put in &lt;a href="https://mattorb.com/github-action-for-google-pagespeed-insights/"&gt;automatic checks&lt;/a&gt; around performance of the site.   Now, let's do something to detect &lt;a href="https://snyk.io/vuln/search?q=jquery&amp;amp;type=any"&gt;Javascript library vulnerabilities&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Github Action
&lt;/h2&gt;

&lt;p&gt;I found &lt;a href="https://github.com/lirantal/is-website-vulnerable"&gt;this project&lt;/a&gt; and whipped up the &lt;a href="https://github.com/mattorb/is-website-vulnerable/pull/1"&gt;changes necessary&lt;/a&gt; to turn it into a Github Action.   Thanks Liran!  Thanks too to &lt;a href="https://snyk.io"&gt;Snyk&lt;/a&gt;, which provides the vulnerability list.&lt;/p&gt;

&lt;p&gt;I adapted an existing Docker container, wrapping a Github action around it.   One way to do this without overly leaking the Github Actions contract in to the container design is to map Github action parameters to environment variables and args that are agnostic and already expected by the container like so:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;env:
     SCAN_URL: ${{ inputs.scan-url }} 

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;... where &lt;code&gt;inputs.scan-url&lt;/code&gt; comes from the Github Action contract (as a  'parameter')  and  'SCAN_URL' is an environment variable that already works with the existing Docker container.   This is in contrast to having the container need to understand how to look for 'INPUT_' prefixed vars that a Github Action provides by default (ref: &lt;a href="https://help.github.com/en/actions/automating-your-workflow-with-github-actions/metadata-syntax-for-github-actions#inputs"&gt;github docs&lt;/a&gt;).  If you don't want to, or can't modify the existing docker container, this is an option.  &lt;/p&gt;

&lt;p&gt;The container &lt;em&gt;does&lt;/em&gt; still need to exit with an error to cause a Github Action to fail though.   I had to modify the underlying Javascript code to accommodate that.  There would not be much value in an automatic check that always passes.&lt;/p&gt;

&lt;p&gt;Now that we have the action, we use it by creating a workflow file in &lt;em&gt;.github/workflows/javascript_vulnerability_check.yml :&lt;/em&gt;&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Test site for publicly known js vulnerabilities

on: 
  push:
    branches:
    - master # Check on every commit to master
  schedule:
    - cron: '0 13 * * 6' # Check once a week regardless of commits
  repository_dispatch:
jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - name: Testing for public javascript library vulnerabilities 
        uses: mattorb/is-website-vulnerable@github-action_v1 # until PR to original repo is merged
        with:
          scan-url: "https://mattorb.com"

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With that in place, we see the following check run after each commit, and once a week for good measure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oLM9v7-d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/01/Screen-Shot-2020-01-29-at-8.18.07-AM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oLM9v7-d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/01/Screen-Shot-2020-01-29-at-8.18.07-AM.png" alt="Github Action for Javascript Vulnerability Scanning"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Shift security left!
&lt;/h2&gt;

&lt;p&gt;So.  Awesome.&lt;/p&gt;

&lt;p&gt;Now we have &lt;em&gt;at least&lt;/em&gt; have some awareness if any of the following happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A change we make introduces a library with a vulnerability&lt;/li&gt;
&lt;li&gt;A change introduced by 3rd party dependency introduces a library with a vulnerability&lt;/li&gt;
&lt;li&gt;No change is made at all, but a vulnerability is discovered and published for a JS library we were already using.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Automatic checks for the win!&lt;/p&gt;

</description>
      <category>security</category>
      <category>softwaredelivery</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Github Action for Google PageSpeed Insights</title>
      <dc:creator>Matt Smith</dc:creator>
      <pubDate>Mon, 27 Jan 2020 14:38:20 +0000</pubDate>
      <link>https://dev.to/mattorb/github-action-for-google-pagespeed-insights-3gle</link>
      <guid>https://dev.to/mattorb/github-action-for-google-pagespeed-insights-3gle</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PvfSOg_n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/01/riccardo-pierri-%40riccardopierri-bDsrGJFZnfs-unsplash.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PvfSOg_n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/01/riccardo-pierri-%40riccardopierri-bDsrGJFZnfs-unsplash.jpg" alt="Github Action for Google PageSpeed Insights"&gt;&lt;/a&gt; photo credit: &lt;a href="https://unsplash.com/@riccardopierri"&gt;zbysiu-rodak&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lately, I have been making more broad sweeping changes to &lt;a href="https://mattorb.com"&gt;this&lt;/a&gt; site.  I want to ensure that I don't accidentally make a change which slows down the site – especially the homepage.  Keeping a web site performant has many benefits including better user experience and affecting search engine rankings.&lt;/p&gt;

&lt;p&gt;Google provides a tool call &lt;a href="https://developers.google.com/speed/pagespeed/insights/"&gt;PageSpeed Insights&lt;/a&gt; to analyze how quickly a page loads and renders on desktops and mobile devices.  According to Google:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;PageSpeed Insights analyzes the content of a web page, then generates suggestions to make that page faster.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It also calculates an overall score.&lt;/p&gt;

&lt;p&gt;For this site, I want to start by setting a baseline and then regularly measure to make sure I don't do something to drop the score below that baseline performance level.  For now, we're only measuring the performance of the homepage.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Github Action
&lt;/h2&gt;

&lt;p&gt;I found &lt;a href="https://github.com/JakePartusch/psi-action"&gt;this project&lt;/a&gt; which provides a Github Action to run PageSpeed Insights.  Thanks Jake!&lt;/p&gt;

&lt;p&gt;I wired it up to my blog's Github repo by defining a workflow file &lt;em&gt;.github/workflows/pagespeedinsights.yml&lt;/em&gt;:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Check Site Performance with PageSpeed Insights

on: 
  push:
    branches:
    - master
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Running Page Speed Insights
        uses: JakePartusch/psi-action@v1
        with:
          url: "https://mattorb.com"

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It kicks off after each commit to the repo.   Example results below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nB9m0nDO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/01/Screen-Shot-2020-01-24-at-8.12.12-AM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nB9m0nDO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/01/Screen-Shot-2020-01-24-at-8.12.12-AM.png" alt="Github Action for Google PageSpeed Insights"&gt;&lt;/a&gt;Desktop PageSpeed Insights for mattorb.com&lt;/p&gt;

&lt;p&gt;The overall 'performance' desktop score of 99 out of 100 is &lt;em&gt;really good&lt;/em&gt;.  Nice!     I can't take credit for that.   The hard work of the &lt;a href="https://ghost.org"&gt;Ghost team&lt;/a&gt; and the &lt;a href="https://github.com/TryGhost/Casper/graphs/contributors"&gt;contributors&lt;/a&gt; to the default 'Casper' theme put us there.&lt;/p&gt;

&lt;p&gt;Now, let us iterate and see what we put together!  &lt;/p&gt;

&lt;p&gt;See the &lt;em&gt;#comments&lt;/em&gt; in the snippets below, which mark what is  changing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Raise the threshold
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Check Site Performance with PageSpeed Insights

on: 
  push:
    branches:
    - master
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Running Page Speed Insights
        uses: JakePartusch/psi-action@v1
        with:
          url: "https://mattorb.com"
          threshold: 96 # &amp;lt;--- default was 70

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This fails the build if if the overall performance score drops below this number.  I'm leaving a tiny bit a wiggle room here for volatility in server response times.&lt;/p&gt;

&lt;h3&gt;
  
  
  Measure after each blog post
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
on: 
  push:
    branches:
    - master
  repository_dispatch: # &amp;lt;-- External event hook
...

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We have our Ghost based blog wired up to post a Github &lt;em&gt;repository_dispatch&lt;/em&gt; event to trigger a Github action for new/updated posts.  See the &lt;a href="https://mattorb.com/broken-links-muffet-github-actions/"&gt;end of this post&lt;/a&gt; for more detail.  This is relevant when you are &lt;em&gt;not&lt;/em&gt; doing static site generation or have a content management system that manifests changes into a page.  In those cases, you need something event based to retrigger an assessment after the site content changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Measure once a week
&lt;/h3&gt;

&lt;p&gt;Our web site has some external dependencies and the rules we are measuring against that can evolve outside our immediate control.   To catch any unexpected changes in those things, do this once a week, even if we change nothing on our site.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
on: 
  push:
    branches:
    - master
  schedule:
    - cron: '0 13 * * 6' # &amp;lt;---- once a week
  repository_dispatch:
...

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Hat tip to crontab.guru re: &lt;a href="https://crontab.guru/#0_13_*_*_6"&gt;0 13 * * 6&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Measure both desktop and mobile page speed
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
    steps:
      - name: Running Page Speed Insights (Mobile) # &amp;lt;-- new step
        uses: JakePartusch/psi-action@v1
        id: psi_mobile                     
        with:
          url: "https://mattorb.com"
          threshold: 90 # &amp;lt;-- distinct threshold
          strategy: mobile # &amp;lt;-- different strategy
      - name: Running Page Speed Insights (Desktop)
        uses: JakePartusch/psi-action@v1
        id: psi_desktop                    
        with:
          url: "https://mattorb.com"
          threshold: 96
          strategy: desktop               
...

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you use an action with the same 'uses' clause, twice, you have to give each step a unique 'id'.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Here's the workflow file for my Github Action, in full:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Check Site Performance with Page Speed Insights

on: 
  push:
    branches:
    - master
  schedule:
    - cron: '0 13 * * 6'
  repository_dispatch:
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Running Page Speed Insights (Mobile)
        uses: mattorb/psi-action@v1
        id: psi_mobile
        with:
          url: "https://mattorb.com"
          threshold: 90
          strategy: mobile
      - name: Running Page Speed Insights (Desktop)
        uses: mattorb/psi-action@v1
        id: psi_desktop
        with:
          url: "https://mattorb.com"
          threshold: 96
          strategy: desktop

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For every commit, every blog post, every theme change, and once a week a mobile and desktop Page Speed Assessment measures how the &lt;a href="https://mattorb.com/"&gt;mattorb.com&lt;/a&gt; home page  performs and alerts us if something degrades significantly.&lt;/p&gt;

&lt;p&gt;We also get history of the results of the performance measurements stored in the actions tab on Github, which can be super helpful in understanding which of the several things that is measured has degraded in performance.&lt;/p&gt;

&lt;p&gt;When you browse to examine those results you can see this level of detail:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5RjB0hbL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/01/Screen-Shot-2020-01-24-at-8.13.39-AM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5RjB0hbL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/01/Screen-Shot-2020-01-24-at-8.13.39-AM.png" alt="Github Action for Google PageSpeed Insights"&gt;&lt;/a&gt;Mobile Page Speed Insights for mattorb.com&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9_Iu84O_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/01/Screen-Shot-2020-01-24-at-8.12.12-AM-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9_Iu84O_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2020/01/Screen-Shot-2020-01-24-at-8.12.12-AM-1.png" alt="Github Action for Google PageSpeed Insights"&gt;&lt;/a&gt;Desktop Page Speed Insights for mattorb.com&lt;/p&gt;

&lt;p&gt;Fun stuff!  Some potential improvements lie in the 'Opportunities' section of the report and making something run this test on several (or all) pages throughout the site.&lt;/p&gt;

&lt;p&gt;Performance is one of those things that is a lot easier to keep going once you have a baseline established and some tools to help track and understand what causes changes in it.&lt;/p&gt;

</description>
      <category>performance</category>
      <category>softwaredelivery</category>
      <category>monitoring</category>
      <category>alerting</category>
    </item>
    <item>
      <title>CI your MacOS dotfiles with GitHub Actions!</title>
      <dc:creator>Matt Smith</dc:creator>
      <pubDate>Mon, 02 Dec 2019 06:00:00 +0000</pubDate>
      <link>https://dev.to/mattorb/ci-your-macos-dotfiles-with-github-actions-17a8</link>
      <guid>https://dev.to/mattorb/ci-your-macos-dotfiles-with-github-actions-17a8</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmattorb.com%2Fcontent%2Fimages%2F2019%2F09%2Fgoran-ivos-%40goran_ivos-yBEyYR8wps-unsplash.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmattorb.com%2Fcontent%2Fimages%2F2019%2F09%2Fgoran-ivos-%40goran_ivos-yBEyYR8wps-unsplash.jpg" alt="CI your MacOS dotfiles with GitHub Actions!"&gt;&lt;/a&gt; photo credit: &lt;a href="https://unsplash.com/@goran_ivos" rel="noopener noreferrer"&gt;goran-ivos&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dependencies that you can't or won't pin versions of in a reliable persistent cache, have the potential for drift.  Such is the life of &lt;a href="https://github.com/mattorb/dotfiles" rel="noopener noreferrer"&gt;my dotfiles repo&lt;/a&gt;.  I &lt;em&gt;don't want&lt;/em&gt; to pin most things there.  It is an outlier relative to what you might normally set up to produce the most consistent, reliable build process.   For dotfiles, I want to lean way in towards making sure they stay current even if it breaks once in a while in exchange for that posture.&lt;/p&gt;

&lt;p&gt;One of the challenges of making sure a dotfiles repo continues to function correctly on a clean machine is that running through them for the first time, in a clean environment, is a rare activity.  It generally only happens when I am configuring a new laptop or others are installing it for the first time.  &lt;/p&gt;

&lt;p&gt;If I could do a clean install on a more regular basis, it would decrease the chance that little breakages are piling up over time.  This is where a most basic form of continuous integration comes in.&lt;/p&gt;

&lt;p&gt;I am starting with a sanity test . . .&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can the install script execute, start to finish, without error?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have already seen this break when a dependency is renamed or when I introduce a subtle syntax error that someone finds in a fork when they try to run everything clean for the first time.  I want to catch those issues as quickly as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub Actions for MacOS dotfiles CI
&lt;/h2&gt;

&lt;p&gt;When perusing the &lt;a href="https://help.github.com/en/articles/about-github-actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt; documentation, I noticed they included the ability to run an action on a MacOS VM!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;wat.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For free.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;wat.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For open source repositories.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;oh, yah ok.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Still . . . In case you are not aware, getting a hosted MacOS VM, while possible, is generally not cheap relative to other server options.  The fact that Github is offering [free] to run Mac workloads for opensource projects is a cause for celebration.&lt;/p&gt;

&lt;p&gt;Ok.  Let's get to the meat of it:  GitHub Actions are behaviors you define in a yaml file checked in to the repository itself.  &lt;/p&gt;

&lt;p&gt;To get started I defined a 'Smoke Test CI' workflow in &lt;em&gt;.github/workflows/smoke.yml&lt;/em&gt; in my dotfiles repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Smoke Test CI

on: [push]

jobs:
  build:

    runs-on: macOS-latest

    steps:
    - uses: actions/checkout@v1
    - name: Execute full install
      run: ./setup.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every single push to the dotfiles repo provisions a temporary MacOS VM, checks out the code with git, and executes the full install of the dotfiles (via ./&lt;em&gt;setup.sh&lt;/em&gt;).  &lt;/p&gt;

&lt;p&gt;The results for the builds that are triggered are in the Actions tab for that Repository on Github:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmattorb.com%2Fcontent%2Fimages%2F2019%2F09%2FScreen-Shot-2019-09-10-at-8.42.30-AM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmattorb.com%2Fcontent%2Fimages%2F2019%2F09%2FScreen-Shot-2019-09-10-at-8.42.30-AM.png" alt="CI your MacOS dotfiles with GitHub Actions!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and you can drill in to see the results of each step and the logs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmattorb.com%2Fcontent%2Fimages%2F2019%2F09%2FScreen-Shot-2019-09-10-at-8.43.03-AM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmattorb.com%2Fcontent%2Fimages%2F2019%2F09%2FScreen-Shot-2019-09-10-at-8.43.03-AM.png" alt="CI your MacOS dotfiles with GitHub Actions!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it!&lt;/p&gt;

&lt;p&gt;Getting this set up has already caught &lt;a href="https://github.com/mattorb/dotfiles/pull/2" rel="noopener noreferrer"&gt;some bugs&lt;/a&gt;.**&lt;/p&gt;

&lt;p&gt;_**One caveat: For a small handful of things, I had to detect that I was running inside a GitHub action and skip over them because they required privileges that were locked down or not available on that VM.  Prudently, Github provides some default environment variables in the VM when running inside a Github Action.  I used those as a clue to skip them.  _&lt;/p&gt;

</description>
      <category>dotfiles</category>
      <category>productivity</category>
      <category>macos</category>
      <category>devops</category>
    </item>
    <item>
      <title>Goodbye Broken links: Ghost + Muffet + Github Actions</title>
      <dc:creator>Matt Smith</dc:creator>
      <pubDate>Mon, 04 Nov 2019 14:36:06 +0000</pubDate>
      <link>https://dev.to/mattorb/goodbye-broken-links-ghost-muffet-github-actions-3lao</link>
      <guid>https://dev.to/mattorb/goodbye-broken-links-ghost-muffet-github-actions-3lao</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WfASTBei--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2019/11/zbysiu-rodak-%40zbigniew-t7OJIAs4Gqw-unsplash.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WfASTBei--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2019/11/zbysiu-rodak-%40zbigniew-t7OJIAs4Gqw-unsplash.jpg" alt="Goodbye Broken links: Ghost + Muffet + Github Actions"&gt;&lt;/a&gt; photo credit: &lt;a href="https://unsplash.com/@zbigniew"&gt;zbysiu-rodak&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How big of let down is it when you are reading a web page, find something interesting enough to click on and are subsequently dropped down the &lt;em&gt;404 Not Found&lt;/em&gt; hole?&lt;/p&gt;

&lt;p&gt;Often the maintainer of a site does not even know what is broken – especially for content oriented sites which have a healthy amount of outbound links.&lt;/p&gt;

&lt;p&gt;Much like broken and flaky tests, compiler warnings, test coverage, code quality and consistent configuration+tooling across promotion environments, the sooner you establish  [&lt;em&gt;Picard voice&lt;/em&gt;] "&lt;a href="https://www.google.com/url?sa=t&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=web&amp;amp;cd=2&amp;amp;cad=rja&amp;amp;uact=8&amp;amp;ved=2ahUKEwiXyKDtiMnlAhUKRa0KHRevCAcQtwIwAXoECAEQAQ&amp;amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DtleSnj4OD0g&amp;amp;usg=AOvVaw3neNFcvkrhBTkNvNW3LZ1k"&gt;the line must be drawn here&lt;/a&gt;", the better off you are.   Once you have a set standard of what is acceptable and good visiblity to what is crossing that line, you have a fighting chance of understanding where to invest to maintain that standard or improve it.&lt;/p&gt;

&lt;p&gt;For a blog like &lt;a href="https://mattorb.com/"&gt;this one&lt;/a&gt;, hyperlinks can break a few different ways.   Internal links can be broken from the start due to unforced errors (i.e. - typos) or software upgrades.  Links going out to other sites can drift into a broken state due to an external site making changes or being taken offline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Muffet
&lt;/h2&gt;

&lt;p&gt;I wanted to see how &lt;em&gt;&lt;a href="https://mattorb.com/"&gt;this site&lt;/a&gt;&lt;/em&gt; was doing and had recently stumbled on &lt;a href="https://www.google.com/url?sa=t&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=web&amp;amp;cd=1&amp;amp;cad=rja&amp;amp;uact=8&amp;amp;ved=2ahUKEwi9jMz0hMnlAhVKiqwKHSsHAiIQFjAAegQICBAC&amp;amp;url=https%3A%2F%2Fgithub.com%2Fraviqqe%2Fmuffet&amp;amp;usg=AOvVaw0HbHz4-7R7AlucvQ8231HE"&gt;Muffet&lt;/a&gt;, a &lt;em&gt;supa&lt;/em&gt;-fast, open source, Go-based broken link checker.  &lt;/p&gt;

&lt;p&gt;The first time I ran Muffet, I discovered an embarrassingly long list of broken links here.&lt;/p&gt;

&lt;p&gt;Here are some choice examples from a trimmed down version of that first run:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ muffet https://mattorb.com

96
https://mattorb.com/swift-2-to-5/amp/
97
    404 https://mattorb.com/swift-2-to-5/swift%20half%20open%20range
103
https://mattorb.com/fuzzy-find-github-repository/
104
    404 https://mattorb.com/fuzzy-find-github-repository/GitHubAPIv3%7CGitHubDeveloperGuide
105
    404 https://mattorb.com/fuzzy-find-github-repository/github.com/shurcooL/githubv4

$
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How to read this output&lt;/strong&gt; : By default, Muffet only puts broken links in the output.  Hierarchy is expressed through indention:  so #97 above is a link that was walked while parsing the page at #96.   The unindented number is a counter of links checked, and the indented numbers are HTTP return codes (404 = not found).  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;All of the link issues above were unforced errors as far as I can tell.   Additionally, the stuff I trimmed out included errors for images that had gone missing and links to external sites that were no longer valid.  &lt;/p&gt;

&lt;p&gt;Awesome!  We now have a way to assess the whole site for broken links.  The problem is we just found a whole bunch of broken things all at once, which means a whole bunch of work to fix them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prefer small fixes right away
&lt;/h2&gt;

&lt;p&gt;Next time a link breaks, I want to be fixing just that one thing and be done -- rather than looking at a large pile of issues that have accumulated over a longer period of time.&lt;/p&gt;

&lt;p&gt;Ideally, I want broken links assessed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatically, before publishing new content – to catch unforced errors before they go live&lt;/li&gt;
&lt;li&gt;Automatically, on configuration changes and software upgrades – to catch unexpected interactions of new software and existing content&lt;/li&gt;
&lt;li&gt;Automatically, on a schedule – to catch drift in the health of links to external party sites&lt;/li&gt;
&lt;li&gt;On demand, to confirm I have fixed issues after making changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having a place to trigger the workload which executes a broken link checker manually or programmatically, record the results, and notify me when things break would hit all my needs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mattorb.com/ci-your-dotfiles-with-github-actions/"&gt;After my other recent experiment with a Github Action&lt;/a&gt;, that seemed like a good candidate.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Github Action for Muffet
&lt;/h2&gt;

&lt;p&gt;Always Google first, to see if someone else has already done similar work.&lt;/p&gt;

&lt;p&gt;I found an &lt;a href="https://github.com/peaceiris/actions-muffet"&gt;archived&lt;/a&gt; Github repo from &lt;em&gt;peaceiris&lt;/em&gt; that had a Muffet Github action. I have no idea why he/she archived it, but it seems to work fine, so I &lt;a href="https://github.com/mattorb/actions-muffet"&gt;forked it&lt;/a&gt; to keep a copy.&lt;/p&gt;

&lt;p&gt;To use that action from our project [checked in to a Github repo], I added a workflow at &lt;em&gt;.github/workflows/checklinks.yml&lt;/em&gt; :&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: checklinks

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: Check links on site
      uses: mattorb/actions-muffet@v1.3.1
      with: 
        args: &amp;gt;
          --timeout 20 
          https://mattorb.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This sets up triggering Muffet to check for broken links on every push to git master.  It builds the needed action via a Docker build of the Github repo &lt;em&gt;mattorb/actions-muffet&lt;/em&gt;, tag &lt;em&gt;1.3.1&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As noted earlier, sometimes external links go bad due to changes outside our  awareness, so below we add a schedule stanza to trigger this check regularly as well:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: checklinks

on: 
  push:
    branches:
    - master
  schedule:
    - cron: '0 13 * * 6'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: Check links on site
      uses: mattorb/actions-muffet@v1.3.1
      with: 
        args: &amp;gt;
          --timeout 20 
          https://mattorb.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, in addition to executing on pushes to master, that cron schedule sets this check to happen automatically once a week. ('&lt;em&gt;0 13 * * 6' == 1pm on Saturdays&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;When it fails, Github sends you an e-mail.  (default settings)&lt;/p&gt;

&lt;p&gt;Also, this handy badge can be placed at the top of README.md in the git repo, or on the site itself:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/mattorb/blog/actions?workflow=checklinks"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9zWYIj6H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/mattorb/blog/workflows/checklinks/badge.svg" alt="Goodbye Broken links: Ghost + Muffet + Github Actions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That badge is live, so hopefully it reads 'passing' when you are reading this article!  For how to make one, see the &lt;a href="https://help.github.com/en/github/automating-your-workflow-with-github-actions/configuring-a-workflow#adding-a-workflow-status-badge-to-your-repository"&gt;Github docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At this point, we have a Github Action in place that will be kicked off for a few scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Manually triggered via the Github web UI&lt;/li&gt;
&lt;li&gt;Automatically triggered via the a push the git repo master&lt;/li&gt;
&lt;li&gt;Automatically triggered once a week&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For all the ways you can trigger Github Actions, see &lt;a href="https://help.github.com/en/github/automating-your-workflow-with-github-actions/events-that-trigger-workflows"&gt;here&lt;/a&gt;.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Going Further
&lt;/h2&gt;

&lt;p&gt;One of those GitHub Action triggers that I'm particularly interested in, since my blog workflow has not moved over to a static generation approach yet: &lt;a href="https://developer.github.com/v3/repos/#create-a-repository-dispatch-event"&gt;repository_dispatch&lt;/a&gt;.  It is still in developer preview but offers a way to trigger a Github Action workflow based on an external events.  &lt;/p&gt;

&lt;p&gt;Ghost has webhooks that can be triggered for various types of modifications:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PZb44TGG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2019/11/Screen-Shot-2019-11-01-at-8.40.07-AM-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PZb44TGG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2019/11/Screen-Shot-2019-11-01-at-8.40.07-AM-1.png" alt="Goodbye Broken links: Ghost + Muffet + Github Actions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tying one or more of those to triggering the Github Action via a &lt;a href="https://developer.github.com/v3/repos/#create-a-repository-dispatch-event"&gt;repository_dispatch&lt;/a&gt; event will require building something to either receive the Ghost JSON webhook Payload and post the Github expected JSON payload, or extending Ghost itself with a custom webhook integration for repository dispatch – a small future project.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/mattorb/generate-github-repository-dispatch"&gt;Here&lt;/a&gt; is a quick stab at that in Go.  I point Ghost webhooks at it for the '&lt;em&gt;New post published&lt;/em&gt;' and '&lt;em&gt;Published post updated&lt;/em&gt;' events to trigger broken link checking on those two events.   It is a bit naive in that it scans the whole site every time a new post is published.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>testing</category>
      <category>go</category>
    </item>
    <item>
      <title>Site Reliability Engineering Book Trio</title>
      <dc:creator>Matt Smith</dc:creator>
      <pubDate>Mon, 16 Sep 2019 13:37:40 +0000</pubDate>
      <link>https://dev.to/mattorb/site-reliability-engineering-book-trio-13ok</link>
      <guid>https://dev.to/mattorb/site-reliability-engineering-book-trio-13ok</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kEQjrZ8v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2019/09/timothy-muza-%40timothymuza-4F42IqLRjf4-unsplash.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kEQjrZ8v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mattorb.com/content/images/2019/09/timothy-muza-%40timothymuza-4F42IqLRjf4-unsplash.jpg" alt="Site Reliability Engineering Book Trio"&gt;&lt;/a&gt; photo credit: &lt;a href="https://unsplash.com/@timothymuza"&gt;timothy-muza&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What works for Google, what works for Facebook, and what works for Netflix may not be the right thing for the rest of us.   Putting too much weight behind the opinions of a few large organizations can bite you.  The same is true of charting a path forward based on the experience of a few individuals, without being aware of the broader landscape.  This is why I'm a huge fan of studies that are more broadly based, like &lt;a href="https://www.amazon.com/Accelerate-Software-Performing-Technology-Organizations/dp/1942788339"&gt;Accelerate&lt;/a&gt; and the accompanying yearly State of DevOps reports.  Do what works in your context, but stay informed of what is working well for others, to make better and better choices as you go.&lt;/p&gt;

&lt;p&gt;One particular area that has been getting more refined is Site Reliabilty Engineering.  There are three great books I read over the last year that provide a peak into some experiences and experiments.&lt;/p&gt;

&lt;p&gt;This trio of books is a treasure trove of ideas, techniques, practices, and organizational approaches for improving both the delivery of value to production, and how the teams around that are organized:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.amazon.com/Site-Reliability-Engineering-Production-Systems/dp/149192912X"&gt;Site Reliability Engineering: How Google Runs Production Systems&lt;/a&gt;, &lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/Site-Reliability-Workbook-Practical-Implement/dp/1492029505/"&gt;The Site Reliability Engineering Workbook: Practical Ways to Implement SRE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.amazon.com/Seeking-SRE-Conversations-Running-Production/dp/1491978864"&gt;Seeking SRE: Conversations About Running Production Systems at Scale&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;SRE is all about applying a software development mindset to infrastructure and operations.&lt;/p&gt;

&lt;p&gt;I particularly enjoyed 'Seeking SRE' which is a series of essays.  Each chapter stands on its own, and several are based on years of history and experience reports at well known companies.&lt;/p&gt;

</description>
      <category>sre</category>
      <category>devops</category>
      <category>books</category>
    </item>
  </channel>
</rss>
