<?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>Forem: Jonas Brømsø</title>
    <description>The latest articles on Forem by Jonas Brømsø (@jonasbn).</description>
    <link>https://forem.com/jonasbn</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%2F25901%2F19913b8a-e625-4403-9321-e10d57e1bae7.jpg</url>
      <title>Forem: Jonas Brømsø</title>
      <link>https://forem.com/jonasbn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jonasbn"/>
    <language>en</language>
    <item>
      <title>punycode Release v0.15.0</title>
      <dc:creator>Jonas Brømsø</dc:creator>
      <pubDate>Tue, 30 Dec 2025 18:49:58 +0000</pubDate>
      <link>https://forem.com/jonasbn/punycode-release-v0150-4oo6</link>
      <guid>https://forem.com/jonasbn/punycode-release-v0150-4oo6</guid>
      <description>&lt;p&gt;I wanted to do some cleaning up my various repositories on GitHub, I did not get very far, before I got caught up looking and an old issue and an old branch.&lt;/p&gt;

&lt;p&gt;The issue (&lt;a href="https://github.com/jonasbn/punycode/issues/34" rel="noopener noreferrer"&gt;#34&lt;/a&gt;), was on problems with punycode and certain Unicode characters. I have attempted to wrap my head around this problem on a couple of occasions before, but never really got anywhere. But I had this old branch where I had started to look into it, so I decided to pick it up again.&lt;/p&gt;

&lt;p&gt;This is the description from the issue:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hey, Punycodes/Emojis containing Zero Width Joiner are not handled the right way.&lt;/p&gt;

&lt;p&gt;xn--8k8hlfr9n should be 🧑🏾‍🎨 not 🧑🏾🎨&lt;/p&gt;

&lt;p&gt;punycode 🧑🏾‍🎨 shows xn--1ug6825plhas9r instead of xn--8k8hlfr9n.&lt;/p&gt;

&lt;p&gt;Any chance to fix this?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After some digging into the Unicode Standard, I found that the Zero Width Joiner (ZWJ) is used to create compound characters by joining multiple characters together. In this case, the ZWJ is used to combine the base character (🧑🏾) with the additional character (🎨) to form a single compound character (🧑🏾‍🎨).&lt;/p&gt;

&lt;p&gt;I realized that the existing implementation of punycode did not account for the ZWJ when encoding and decoding characters. To fix this, I modified the encoding and decoding functions to handle the ZWJ.&lt;/p&gt;

&lt;p&gt;After implementing the changes, I tested the updated punycode implementation with various inputs, including those containing the ZWJ. The tests confirmed that the issue was resolved, and the correct punycode representation was generated for characters with ZWJ.&lt;/p&gt;

&lt;p&gt;In the branch I had started looking into exchaging the core library, since after all the client in &lt;a href="https://github.com/jonasbn/punycode" rel="noopener noreferrer"&gt;my repository&lt;/a&gt; is just a CLI client using existing implementations.&lt;/p&gt;

&lt;p&gt;With the lastest update, it can now output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./punycode xn--8k8hlfr9n
🧑🏾🎨
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./punycode xn--1ug6825plhas9r
🧑🏾‍🎨
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I checked the two decodings against online implementations, and they all agree on the same output.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dnschecker.org/idn-punycode-converter.php" rel="noopener noreferrer"&gt;https://dnschecker.org/idn-punycode-converter.php&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.punycoder.com/" rel="noopener noreferrer"&gt;https://www.punycoder.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://puny.codes/" rel="noopener noreferrer"&gt;https://puny.codes/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I believe my code is not doing it right.&lt;/p&gt;

&lt;p&gt;But if you re-read the original issue:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;xn--8k8hlfr9n should be 🧑🏾‍🎨 not 🧑🏾🎨&lt;/p&gt;

&lt;p&gt;punycode 🧑🏾‍🎨 shows xn--1ug6825plhas9r instead of xn--8k8hlfr9n.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So my client might still be doing it wrong, since it decodes &lt;code&gt;xn--8k8hlfr9n&lt;/code&gt; to 🧑🏾🎨, while the issue reporter expects it to decode to 🧑🏾‍🎨.&lt;/p&gt;

&lt;p&gt;But if I check it against the listed online implementations, my client is now aligned with these.&lt;/p&gt;

&lt;p&gt;I have closed the issue as a wont fix, since I believe the issue reporter has the report the wrong way around, but I have requested that if more information is available, they should re-open the issue or open a new one.&lt;/p&gt;

&lt;p&gt;The issue originates from 2023 and is part of my path to learning Go and you can also read from the documentation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This utility was created, when in the process of learning Go. I have worked in the DNS and domain name business for a decade so it was only natural to work on something I know when learning Go.&lt;/p&gt;

&lt;p&gt;This particular repository touched the following topics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learning to make CLI tools&lt;/li&gt;
&lt;li&gt;Making an executable distributable and installable component&lt;/li&gt;
&lt;li&gt;Reading data from the CLI&lt;/li&gt;
&lt;li&gt;Reading data from STDIN&lt;/li&gt;
&lt;li&gt;Testing a CLI tool / Main function in Go&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;So it might never be perfect, but it has served its purpose well and another solution could be to only handle the part with is relevant to DNS, which initself is only a subset of the full Unicode standard, but a rabbithole of it's own.&lt;/p&gt;

&lt;p&gt;Any suggestions or ideas for improvements are welcome, just open an issue or a pull request on &lt;a href="https://github.com/jonasbn/punycode" rel="noopener noreferrer"&gt;the repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The repository and tool chain had not been touched in a long time, so I had to make release &lt;code&gt;v0.16.0&lt;/code&gt; to get it working with the latest Go version and modules.&lt;/p&gt;

</description>
      <category>go</category>
      <category>opensource</category>
      <category>release</category>
    </item>
    <item>
      <title>Feature and Maintenance Release 0.56.0 of the GitHub Action for Checking Spelling</title>
      <dc:creator>Jonas Brømsø</dc:creator>
      <pubDate>Sat, 27 Dec 2025 16:58:45 +0000</pubDate>
      <link>https://forem.com/jonasbn/feature-and-maintenance-release-0560-of-the-github-action-for-checking-spelling-224</link>
      <guid>https://forem.com/jonasbn/feature-and-maintenance-release-0560-of-the-github-action-for-checking-spelling-224</guid>
      <description>&lt;p&gt;A &lt;a href="https://github.com/rojopolis/spellcheck-github-actions/issues/298" rel="noopener noreferrer"&gt;request&lt;/a&gt; was received for support for Portuguese for &lt;a href="https://github.com/rojopolis/spellcheck-github-actions" rel="noopener noreferrer"&gt;the GitHub Action for Checking Spelling&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Due to Christmas and work as I was not able to act as fast as with the &lt;a href="https://dev.to/jonasbn/maintenance-release-0550-of-the-github-action-for-checking-spelling-2j8j"&gt;last release&lt;/a&gt;, but today I found some time to make the release.&lt;/p&gt;

&lt;p&gt;The release includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support for Portuguese language including the Brazilian variant&lt;/li&gt;
&lt;li&gt;Update of the Docker base image&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So it is a combined feature and maintenance release and possibly the last of the year.&lt;/p&gt;

&lt;p&gt;There is another interesting feature request open, which I hope to get started on, so next year could start with another feature release:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rojopolis/spellcheck-github-actions/issues/285" rel="noopener noreferrer"&gt;"Summarize results as a markdown table"&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Change log for: &lt;a href="https://github.com/rojopolis/spellcheck-github-actions/releases/tag/0.56.0" rel="noopener noreferrer"&gt;&lt;code&gt;0.56.0&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  0.56.0, 2025-12-27, feature and maintenance release, update not required
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Support for Portuguese (Portugal and Brazil) for both Hunspell and Aspell, requested by: @mdiazgoncalves via issue &lt;a href="https://github.com/rojopolis/spellcheck-github-actions/issues/298" rel="noopener noreferrer"&gt;#298&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docker image updated to Python 3.14.2 trixie slim &lt;a href="https://docs.python.org/release/3.14.2/whatsnew/changelog.html" rel="noopener noreferrer"&gt;Release notes for Python 3.14.2&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>release</category>
      <category>opensource</category>
      <category>gha</category>
    </item>
    <item>
      <title>Maintenance Release 0.55.0 of the GitHub Action for Checking Spelling</title>
      <dc:creator>Jonas Brømsø</dc:creator>
      <pubDate>Fri, 28 Nov 2025 13:10:55 +0000</pubDate>
      <link>https://forem.com/jonasbn/maintenance-release-0550-of-the-github-action-for-checking-spelling-2j8j</link>
      <guid>https://forem.com/jonasbn/maintenance-release-0550-of-the-github-action-for-checking-spelling-2j8j</guid>
      <description>&lt;p&gt;A &lt;em&gt;quick&lt;/em&gt; maintenance release for &lt;a href="https://github.com/rojopolis/spellcheck-github-actions" rel="noopener noreferrer"&gt;the GitHub Action for Checking Spelling&lt;/a&gt; was made yesterday.&lt;/p&gt;

&lt;p&gt;The other day the repository got &lt;a href="https://github.com/rojopolis/spellcheck-github-actions/issues/293" rel="noopener noreferrer"&gt;a new issue&lt;/a&gt; which requested enabling of use of large Aspell dictionaries. &lt;/p&gt;

&lt;p&gt;The GitHub action however is just a wrapper for &lt;a href="https://facelessuser.github.io/pyspelling/" rel="noopener noreferrer"&gt;PySpelling&lt;/a&gt; so I sent the user in that direction, also because this was something I believe was more in the realm of PySpelling than the GitHub Action.&lt;/p&gt;

&lt;p&gt;Not long after a new release of PySpelling (&lt;code&gt;2.12.1&lt;/code&gt;) was made, so I reopened the issue, since I needed to update the action with the new release to meet the need of the user and the original request and it was easier to keep track of the request this way.&lt;/p&gt;

&lt;p&gt;Later the user wrote to me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Thanks! I’m amazed at how quickly the guy over at PySpelling made the change and release.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hmmmmm...&lt;/p&gt;

&lt;p&gt;I decided to step my game up and luckily I had an window of opportunity, so I made the release numbered &lt;code&gt;0.55.0&lt;/code&gt; which contains an update of the core component PySpelling from version &lt;code&gt;2.12.1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;At this time I am not sure how the Aspell setting for large dictionaries is enabled/configured, I have not been able to find any documentation on this, but at least the action is aligned with the core component - I hope this works out for the user.&lt;/p&gt;

&lt;p&gt;Change log for: &lt;a href="https://github.com/rojopolis/spellcheck-github-actions/releases/tag/0.55.0" rel="noopener noreferrer"&gt;&lt;code&gt;0.55.0&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  0.55.0, 2025-11-27, maintenance release, update not required
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Via an issue &lt;a href="https://github.com/rojopolis/spellcheck-github-actions/issues/293" rel="noopener noreferrer"&gt;#293&lt;/a&gt; from @shoverbj, an update to the core component &lt;strong&gt;PySpelling&lt;/strong&gt; from version 2.12.0 to version &lt;code&gt;2.12.1&lt;/code&gt; was made, this allows for use of large dictionaries with Aspell&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>opensource</category>
      <category>githubaction</category>
      <category>release</category>
    </item>
    <item>
      <title>Maintenance release 2.09 for the Perl Distribution Workflow</title>
      <dc:creator>Jonas Brømsø</dc:creator>
      <pubDate>Sun, 23 Nov 2025 09:49:50 +0000</pubDate>
      <link>https://forem.com/jonasbn/maintenance-release-209-for-the-perl-distribution-workflow-491a</link>
      <guid>https://forem.com/jonasbn/maintenance-release-209-for-the-perl-distribution-workflow-491a</guid>
      <description>&lt;p&gt;This release follows up on &lt;a href="https://dev.to/jonasbn/bug-fix-release-208-for-the-perl-distribution-workflow-172e"&gt;release 2.08&lt;/a&gt; and hopefully stabilizes the test suite even further.&lt;/p&gt;

&lt;p&gt;At the same time we are taking a first step towards the next major release by deprecating the use of XML configuration files. The preferred format for configuration files is now YAML. The XML support will be removed in a future major release, for now this is just a deprecation notice and several warnings from the test suite.&lt;/p&gt;

&lt;p&gt;When we did the last major release to version 2, see the blog post:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/jonasbn/major-release-2-of-the-perl-distribution-workflow-40e1"&gt;"Major Release 2 of the Perl Distribution Workflow"&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We caused some grievances for one of our users, afterwards we discussed that perhaps the distribution should have been renamed to Workflow2 to better reflect the breaking changes and to make a more clear distinction and separation. However, at the time we did not expect this to be a problem since we wanted to keep the distribution name simple and easy to remember. Instead we will try to communicate breaking changes more clearly in future major releases.&lt;/p&gt;

&lt;p&gt;But let's see how this pans out as we are slowly approaching the next major release and what we decide on moving forward.&lt;/p&gt;

&lt;p&gt;The challenge with Perl and version numbers is complex and now that the mentioned problems got sorted out, I do not believe we would experience them again and I for one want to avoid renaming the distribution in future major releases.&lt;/p&gt;

&lt;p&gt;The release is available on CPAN and GitHub:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/perl-workflow/perl-workflow/releases/tag/2.09" rel="noopener noreferrer"&gt;GitHub perl-workflow release 2.09&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Change log for Perl Workflow release 2.09.&lt;/p&gt;

&lt;h2&gt;
  
  
  2.09 2025-11-23 maintenance release, update not required
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Deprecation notice of use of XML configuration files, issue &lt;a href="https://github.com/perl-workflow/perl-workflow/issue/125" rel="noopener noreferrer"&gt;#125&lt;/a&gt; and deprecation notices implementation by &lt;a class="mentioned-user" href="https://dev.to/ehuelsmann"&gt;@ehuelsmann&lt;/a&gt; via PR &lt;a href="https://github.com/perl-workflow/perl-workflow/pull/256" rel="noopener noreferrer"&gt;#256&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;YAML configuration files are now the preferred format for configuration of Workflow instances. The XML implementation was based on &lt;a href="https://metacpan.org/pod/XML::Simple" rel="noopener noreferrer"&gt;XML::Simple&lt;/a&gt;, which itself has been discouraged for use for several years. The distribution still supports XML configuration files, but this support will be removed in a future unscheduled major release.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Improvements to test suite, PR &lt;a href="https://github.com/perl-workflow/perl-workflow/pull/275" rel="noopener noreferrer"&gt;#275&lt;/a&gt; by &lt;a class="mentioned-user" href="https://dev.to/ehuelsmann"&gt;@ehuelsmann&lt;/a&gt;. This is a follow up on release 2.08, since we spotted the issue in the tests running as part of the CI pipeline on GitHub&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>maintenance</category>
      <category>release</category>
      <category>perl</category>
    </item>
    <item>
      <title>Tooth to Tail</title>
      <dc:creator>Jonas Brømsø</dc:creator>
      <pubDate>Fri, 14 Nov 2025 17:31:07 +0000</pubDate>
      <link>https://forem.com/jonasbn/tooth-to-tail-4hj0</link>
      <guid>https://forem.com/jonasbn/tooth-to-tail-4hj0</guid>
      <description>&lt;p&gt;A development team consist of people with various roles and responsibilities. Over the cause of my career I have had many different roles ranging from developer, to release manager, scrum master, build engineer, occasional tester and finally product manger/owner. I have been called &lt;em&gt;bottleneck&lt;/em&gt; and &lt;em&gt;show-stopper&lt;/em&gt; and what I have observed is the difficulty of getting a team to be balanced.&lt;/p&gt;

&lt;p&gt;At some point I fell over the military term "Tooth to Tail Ratio" and I found it to be interesting in regards to the challenge of balancing a team, so you do not get too many bottlenecks, as for the show-stopper part, I believe it is my personality that sometimes question decisions and that is not always appreciated.&lt;/p&gt;

&lt;p&gt;The tooth to tail ratio is a military concept that describes the ratio of combat troops (tooth) to support personnel (tail) in a military force. A higher tooth to tail ratio indicates a larger proportion of combat troops, while a lower ratio indicates a larger proportion of support personnel. The concept is used to evaluate the efficiency and effectiveness of military forces, as well as to inform decisions about resource allocation and force structure.&lt;/p&gt;

&lt;p&gt;As a development team we are not exactly in a combat situation or necessarily in a military context, but thinking about team composition and team dynamics can be informed by the tooth to tail ratio concept. Since a balanced team with the right mix of skills and roles can help ensure that the team is able to deliver high-quality software efficiently and effectively.&lt;/p&gt;

&lt;p&gt;There are critics of the tooth to tail ratio concept, but this is within the military context, so at this time, we do not need to go into that.&lt;/p&gt;

&lt;p&gt;You can read more about tooth to tail ratio on &lt;a href="https://en.wikipedia.org/wiki/Tooth-to-tail_ratio" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The concept of tooth to tail ratio was interesting since it made me reflect on the challenges of balancing a development team. So if you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;identify the roles and responsibilities of team members&lt;/li&gt;
&lt;li&gt;assess the skills and expertise of team members&lt;/li&gt;
&lt;li&gt;evaluate the workload and capacity of team members&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then you can start to think about how to balance the team, based on numbers.&lt;/p&gt;

&lt;p&gt;Another approach which I do however find more interesting, which came from reflecting on the above, was finding back to the essence of the team concept. If you read the referenced wikipedia article, the following line is interesting:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;While both "tooth" and "tail" soldiers may find themselves in combat&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Meaning your might have a primary role, but you can be flexible and take on other roles as needed.&lt;/p&gt;

&lt;p&gt;And this is very interesting. I have tried to work with teams where we had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;developers&lt;/li&gt;
&lt;li&gt;testers&lt;/li&gt;
&lt;li&gt;release managers&lt;/li&gt;
&lt;li&gt;scrum masters&lt;/li&gt;
&lt;li&gt;product owners&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We are worked committed to finishing what we had defined as the goal of our sprint, the timebox set to accomplish a certain milestone/goal as a release or a feature set or similar.&lt;/p&gt;

&lt;p&gt;Assignments vary and you can estimate, but you should not rely to much estimates it is a planning tool IMHO and things might change. Sometimes things take longer or a colleague needs help and time is not spent where planned or some other external factor impacts execution of the plan.&lt;/p&gt;

&lt;p&gt;But in this team, the primary goal was to get the work done, and if that meant that a developer needed to help with testing, then that was what happened.&lt;/p&gt;

&lt;p&gt;This sounds formidable, but it is a culture and culture building and changes are hard. If you succeed though, you get a team that is flexible and can adapt to changing circumstances and has a very strong team spirit.&lt;/p&gt;

&lt;p&gt;We have a tendency to want to stick to our defined roles, I myself am guilty of this, but oftentimes it is very beneficial and educational to do something else, you gain a lot of insight from getting a different perspective.&lt;/p&gt;

&lt;p&gt;In software development, we often talk about getting close to the users, which is great, but what if you could start by understanding your team mates and their roles better.&lt;/p&gt;

&lt;p&gt;Tooth to tail is interesting, but perhaps the key is in breaking down the barriers between roles and responsibilities and creating a culture where everyone is committed to the team's success and bringing value to the customers/stakeholders. The roles in modern software development is are requires skills and expertise, to the primary role is of outmost importance, but being flexible and adaptable is a great skill to have as well.&lt;/p&gt;

&lt;p&gt;And numbers are interesting, but I guess it would be more valuable to do the numbers game on outcome and value rather than team organization..&lt;/p&gt;

&lt;p&gt;So let me end with another military term/slogan:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Improvise, Adapt, and Overcome"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Perhaps that will work, even in more peaceful settings.&lt;/p&gt;

</description>
      <category>rant</category>
      <category>teams</category>
      <category>sdlc</category>
    </item>
    <item>
      <title>Use Markdownlint for your documentation</title>
      <dc:creator>Jonas Brømsø</dc:creator>
      <pubDate>Thu, 13 Nov 2025 06:13:59 +0000</pubDate>
      <link>https://forem.com/jonasbn/use-markdownlint-for-your-documentation-5ln</link>
      <guid>https://forem.com/jonasbn/use-markdownlint-for-your-documentation-5ln</guid>
      <description>&lt;p&gt;This blog post is a TIL (Today I Learned) about using &lt;strong&gt;Markdownlint&lt;/strong&gt; as part of your documentation workflow on GitHub lifted from &lt;a href="https://jonasbn.github.io/til/" rel="noopener noreferrer"&gt;my TIL collection&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Markdownlint-CLI&lt;/strong&gt; is one of those all-round tools, which are always within grasp when you need them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I lint my markdown on the command line&lt;/li&gt;
&lt;li&gt;I lint my markdown my editor of choice VScode&lt;/li&gt;
&lt;li&gt;I lint my markdown as a GitHub Action as part of my CI pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So lets go over the GitHub Action part.&lt;/p&gt;

&lt;p&gt;When I set up a repository on GitHub, which going to hold a significant amount of Markdown, I add a Markdownlint configuration:&lt;/p&gt;

&lt;p&gt;In the root of the repository I add the file: &lt;code&gt;.markdownlint.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The moment I have done that, I can use the command line tool and my editor let's me know I entered &lt;em&gt;bad&lt;/em&gt; Markdown.&lt;/p&gt;

&lt;p&gt;Next step is configuring the action, so I add the following file to the directory: &lt;code&gt;.github/workflows/markdownlint.yml&lt;/code&gt;, I do this so all of the warnings and recommendations that Markdownlint I do not catch, gets captured as part of the continuous integration on GitHub.&lt;/p&gt;

&lt;p&gt;The file contents looks something along the lines of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Markdownlint Action&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;**/*.md'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.markdownlintignore'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.markdownlint.json'&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;**/*.md'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.markdownlintignore'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.markdownlint.json'&lt;/span&gt;

&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read-all&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Markdownlint&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8&lt;/span&gt; &lt;span class="c1"&gt;# v5.0.0&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Markdownlint&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nosborn/github-action-markdown-cli@508d6cefd8f0cc99eab5d2d4685b1d5f470042c1&lt;/span&gt; &lt;span class="c1"&gt;# v3.5.0&lt;/span&gt;
        &lt;span class="na"&gt;continue-on-error&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
          &lt;span class="na"&gt;config_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.markdownlint.json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The configuration has a lot of things going on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I have configured what triggers the linting process

&lt;ul&gt;
&lt;li&gt;Markdown files of course, if you name them differently lik: &lt;code&gt;*.mkdn&lt;/code&gt; etc. you need to take that into consideration&lt;/li&gt;
&lt;li&gt;But also changes to the tool chain:&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.markdownlint.json&lt;/code&gt; specifies our rules, so do we have changes to the rules we need a run&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.markdownlintignore&lt;/code&gt; a classical ignore file for Markdownlint, does this file have changes we need a run&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;The action only needs read permissions&lt;/li&gt;

&lt;li&gt;The &lt;code&gt;uses&lt;/code&gt; statements pointing to the actions used are pinned, which is a security recommendation&lt;/li&gt;

&lt;li&gt;I use &lt;code&gt;continue-on-error&lt;/code&gt; as Markdown linting errors are often not critical to the repository&lt;/li&gt;

&lt;li&gt;The &lt;code&gt;config_file&lt;/code&gt; parameter is for hwen you want to locate your configuration in another place to declutter the root of your repository, I just have it here for convenience, see more below&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The action uses &lt;code&gt;nosborn/github-action-markdown-cli&lt;/code&gt; can be found on the &lt;a href="https://github.com/marketplace/actions/markdownlint-cli" rel="noopener noreferrer"&gt;GitHub marketplace&lt;/a&gt; and since it is based on &lt;strong&gt;markdownlint-cli&lt;/strong&gt; I have no challenges with the configuration outlined above since it is the same configuration used for the CLI tool: &lt;code&gt;markdownlint&lt;/code&gt; and additionally &lt;strong&gt;VScode&lt;/strong&gt; via the plugin from the &lt;a href="https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint" rel="noopener noreferrer"&gt;VScode marketplace&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As I add more and more Markdown the warnings/recommendations start to appear and I adjust the configuration. For this repository is looks like this at the time of writing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ul-style"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"style"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dash"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"html"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"line-length"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fenced-code-language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"no-hard-tabs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"blanks-around-headings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ul-indent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"commands-show-output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"no-bare-urls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ol-prefix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"no-trailing-punctuation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"no-space-in-links"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"no-space-in-emphasis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"emphasis-style"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"style"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"underscore"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"strong-style"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"style"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"asterisk"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the rules I have configured I would like to emphasize:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;"ul-style": { "style": "dash" }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;"emphasis-style": { "style": "underscore" }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;"strong-style": { "style": "asterisk" }&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since Markdown is very flexible, I prefer to have a very uniform style, so I use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-&lt;/code&gt; (dash) for lists, why? this could also be: &lt;code&gt;+&lt;/code&gt; (plus) or &lt;code&gt;*&lt;/code&gt; (asterisk)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_&lt;/code&gt; (underscore) for italics/emphasis, why? - two consecutive underscores is also bold&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;*&lt;/code&gt; (asterisk) for bold/strong, why? - a single asterisk is emphasis, two is bold, asterisk surrounded by spaces is a bullet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There might be cases where I have to bend this rules, so I do that on a per repository basis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decluttering Your Repository Root Directory
&lt;/h2&gt;

&lt;p&gt;As your toolbox grow and your repository adopt more and more tooling, you might experience that your repository root directory clutters with all sort of repository specific configurations.&lt;/p&gt;

&lt;p&gt;Luckily the action can be configured to point to an alternative path for the configuration file.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;br&gt;
This below is not compatible with the intuitive and out of the box solution of having the &lt;code&gt;.markdownlint.json&lt;/code&gt; in the root directory for easy detection by the CLI tool or VScode.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;config_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.markdownlint.json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can move the file into a sub-directory, for example &lt;code&gt;.github/&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;config_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.github/markdownlint.json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Avoiding Markdownlint Conflicts
&lt;/h2&gt;

&lt;p&gt;Sometimes you adopt Markdown files from other projects and these might not adhere to your specific Markdown linting rule set and hence they will get reported as items for your attention.&lt;/p&gt;

&lt;p&gt;Examples of these files can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;License descriptions&lt;/li&gt;
&lt;li&gt;Code of Conduct Policy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Luckily &lt;strong&gt;Markdownlint-CLI&lt;/strong&gt; supports adding an ignore file as you know it from Git ignore files.&lt;/p&gt;

&lt;p&gt;An example for a &lt;code&gt;markdownlintignore&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LICENCE.md
CODE_OF_CONDUCT.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next step is telling the action about the location of the ignore file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;config_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.github/markdownlint.json"&lt;/span&gt;
    &lt;span class="na"&gt;ignore_path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.github/markdownlintignore"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This does mean that you might have some challenges in regards to the additional tooling, like VScode and the command line tool.&lt;/p&gt;

&lt;p&gt;AFAICT the VScode extension does not allow for configuring the path to the ignore file.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[!NOTE]&lt;br&gt;
Do note that the files moved to &lt;code&gt;.github&lt;/code&gt; has the dot removed, since there is not need to hide them as such, when the directory is hidden&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The CLI tool has the following options: &lt;code&gt;-p/--ignore-path&lt;/code&gt;, but these take path arguments and not the path to an ignore file, so some cluttering will occur.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources and References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/actions/markdownlint-cli" rel="noopener noreferrer"&gt;GitHub Marketplace: Markdownlint-CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint" rel="noopener noreferrer"&gt;VScode Marketplace: Markdownlint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.markdownguide.org/basic-syntax/" rel="noopener noreferrer"&gt;Markdownlint Specification&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>markdown</category>
      <category>markdownlint</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>Bug fix release 2.08 for the Perl Distribution Workflow</title>
      <dc:creator>Jonas Brømsø</dc:creator>
      <pubDate>Wed, 12 Nov 2025 16:13:43 +0000</pubDate>
      <link>https://forem.com/jonasbn/bug-fix-release-208-for-the-perl-distribution-workflow-172e</link>
      <guid>https://forem.com/jonasbn/bug-fix-release-208-for-the-perl-distribution-workflow-172e</guid>
      <description>&lt;p&gt;We got an issue reported by long term Perl user and &lt;a href="https://github.com/andk/pause/blob/master/doc/operating-model.md" rel="noopener noreferrer"&gt;PAUSE gatekeeper&lt;/a&gt; &lt;a href="https://github.com/andk" rel="noopener noreferrer"&gt;@ANDK&lt;/a&gt;, an issue had been observed and was reported via the smoke testing framework available as CPAN-testers.&lt;/p&gt;

&lt;p&gt;ANDK had debugged the issue, which is much appreciated, I was unable to reproduce it locally, but &lt;a class="mentioned-user" href="https://dev.to/ehuelsmann"&gt;@ehuelsmann&lt;/a&gt; was fast to provide a patch that we believe fixes the issue.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/perl-workflow/perl-workflow/releases/tag/2.08" rel="noopener noreferrer"&gt;GitHub perl-workflow release 2.08&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This kind of bugs are tricky, especially if you cannot reproduce them, but the area of the code pointed out by ANDK made sense, and Erik's patch also made sense - it is a fragile area of the code and it might be related to tests, but we want our tests and main code to be as robust as possible, so we can trust it.&lt;/p&gt;

&lt;p&gt;I am not sure this is a real &lt;a href="https://en.wikipedia.org/wiki/Heisenbug" rel="noopener noreferrer"&gt;heisenbug&lt;/a&gt;, but it does feel like it.&lt;/p&gt;

&lt;p&gt;Change log from the lastest release:&lt;/p&gt;

&lt;h2&gt;
  
  
  2.08 2025-11-12 bug fix release, update not required
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Fixed
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Issue: &lt;a href="https://github.com/perl-workflow/perl-workflow/issues/271" rel="noopener noreferrer"&gt;#271&lt;/a&gt; reported by &lt;a href="https://github.com/andk" rel="noopener noreferrer"&gt;@andk&lt;/a&gt;. Fixed via PR: &lt;a href="https://github.com/perl-workflow/perl-workflow/pull/272" rel="noopener noreferrer"&gt;#272&lt;/a&gt; by &lt;a class="mentioned-user" href="https://dev.to/ehuelsmann"&gt;@ehuelsmann&lt;/a&gt;
This issue was discovered by the CPAN smoke testers, the report can be found on &lt;a href="https://www.cpantesters.org/cpan/report/f9442cc8-bccd-11f0-b805-8614eb2737ae" rel="noopener noreferrer"&gt;CPAN Testers&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>release</category>
      <category>opensource</category>
      <category>perl</category>
    </item>
    <item>
      <title>Bug fix release 2.07 for the Perl Distribution Workflow</title>
      <dc:creator>Jonas Brømsø</dc:creator>
      <pubDate>Sat, 08 Nov 2025 10:35:26 +0000</pubDate>
      <link>https://forem.com/jonasbn/bug-fix-release-207-for-the-perl-distribution-workflow-2i86</link>
      <guid>https://forem.com/jonasbn/bug-fix-release-207-for-the-perl-distribution-workflow-2i86</guid>
      <description>&lt;p&gt;My fellow contributor &lt;a class="mentioned-user" href="https://dev.to/ehuelsmann"&gt;@ehuelsmann&lt;/a&gt; located a regression since we spun off 2.X from 1.X.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/perl-workflow/perl-workflow/releases/tag/2.07" rel="noopener noreferrer"&gt;GitHub perl-workflow release 2.07&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The regression was observed by &lt;a class="mentioned-user" href="https://dev.to/ehuelsmann"&gt;@ehuelsmann&lt;/a&gt; and he provided a PR with a fix.&lt;/p&gt;

&lt;p&gt;The regression was a change to return values and one of the interesting Perl discussions on whether to return &lt;code&gt;undef&lt;/code&gt; or just do &lt;code&gt;return&lt;/code&gt;. Anyway the fix reinstates the previous behavior and returns &lt;code&gt;undef&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here follows the change log for the bug fix release.&lt;/p&gt;

&lt;h2&gt;
  
  
  2.07 2025-11-08 bug fix release, update not required
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Fixed
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Issue: &lt;a href="https://github.com/perl-workflow/perl-workflow/issues/266" rel="noopener noreferrer"&gt;#266&lt;/a&gt; discovered by Erik Huelsmann. A regression introduced with 2.X releases. Fixed via PR: &lt;a href="https://github.com/perl-workflow/perl-workflow/pull/267" rel="noopener noreferrer"&gt;#267&lt;/a&gt; also by Erik Huelsmann&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>opensource</category>
      <category>perl</category>
      <category>release</category>
    </item>
    <item>
      <title>Feature Release 0.54.0 of the GitHub Action for Checking Spelling</title>
      <dc:creator>Jonas Brømsø</dc:creator>
      <pubDate>Wed, 05 Nov 2025 21:01:41 +0000</pubDate>
      <link>https://forem.com/jonasbn/feature-release-0540-of-the-github-action-for-checking-spelling-10ap</link>
      <guid>https://forem.com/jonasbn/feature-release-0540-of-the-github-action-for-checking-spelling-10ap</guid>
      <description>&lt;p&gt;A feature release for &lt;a href="https://github.com/rojopolis/spellcheck-github-actions" rel="noopener noreferrer"&gt;the GitHub Action for Checking Spelling&lt;/a&gt; has just been made.&lt;/p&gt;

&lt;p&gt;The release is numbered &lt;code&gt;0.54.0&lt;/code&gt; and contains an update of the core component PySpelling from version &lt;code&gt;2.11&lt;/code&gt; to &lt;code&gt;2.12&lt;/code&gt;. The update allows for the configuration parameters jobs to be set to: &lt;code&gt;0&lt;/code&gt; to allow for use of maximum number of cores.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;See the &lt;a href="https://facelessuser.github.io/pyspelling/configuration/" rel="noopener noreferrer"&gt;documentation for PySpelling&lt;/a&gt; and of course &lt;a href="https://github.com/rojopolis/spellcheck-github-actions/releases/tag/0.54.0" rel="noopener noreferrer"&gt;0.54.0&lt;/a&gt; of this action.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The support for this setting was introduced with &lt;a href="https://github.com/facelessuser/pyspelling/releases/tag/2.10.0" rel="noopener noreferrer"&gt;release 2.10 of PySpelling&lt;/a&gt;, which was adopted in release &lt;a href="https://github.com/rojopolis/spellcheck-github-actions/releases/tag/0.36.0" rel="noopener noreferrer"&gt;0.36.0&lt;/a&gt; of this action.&lt;/p&gt;

&lt;p&gt;Happy spellchecking on even more cores for all your spellcheck needs!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>githubaction</category>
      <category>release</category>
    </item>
    <item>
      <title>Maintenance Releases 0.53.0 of the GitHub Action for Checking Spelling</title>
      <dc:creator>Jonas Brømsø</dc:creator>
      <pubDate>Sun, 26 Oct 2025 13:07:24 +0000</pubDate>
      <link>https://forem.com/jonasbn/maintenance-releases-0530-of-the-github-action-for-checking-spelling-23fk</link>
      <guid>https://forem.com/jonasbn/maintenance-releases-0530-of-the-github-action-for-checking-spelling-23fk</guid>
      <description>&lt;p&gt;Another maintenance release for &lt;a href="https://github.com/rojopolis/spellcheck-github-actions" rel="noopener noreferrer"&gt;the GitHub Action for Checking Spelling&lt;/a&gt; has seen the light of day yesterday.&lt;/p&gt;

&lt;p&gt;The release is numbered &lt;code&gt;0.53.0&lt;/code&gt; and contains the following changes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update of Docker Python base image to &lt;code&gt;python:3.14.0-trixie-slim&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is both an update to Python version and OS version. So we have not moved from Debian Bookworm to Trixie and from Python 3.13.7 to Python 3.14.0.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://docs.python.org/release/3.14.0/whatsnew/changelog.html" rel="noopener noreferrer"&gt;Release notes for Python 3.14.0&lt;/a&gt; are available.&lt;/p&gt;

&lt;p&gt;The update originated in a PR from Dependabot &lt;a href="https://github.com/rojopolis/spellcheck-github-actions/pull/274" rel="noopener noreferrer"&gt;#274&lt;/a&gt;, the challenges with these PRs is that they only mention the checksums in short form and not the full details of the base image update, so getting the details requires some research.&lt;/p&gt;

&lt;p&gt;I outlined some of the challenges in an earlier &lt;a href="https://dev.to/jonasbn/weird-pr-for-python-base-docker-image-do-not-now-how-to-read-it-4c69"&gt;blog post&lt;/a&gt; and it used AI tooling to analyse DockerHub data to understand what was being offered via the PR.&lt;/p&gt;

&lt;p&gt;The case was the same for this PR, but this time I was better prepared and new what questions to ask, so after some prompting I got the details I needed with&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python version&lt;/li&gt;
&lt;li&gt;Docker image&lt;/li&gt;
&lt;li&gt;OS version&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And with some iterations on the builds I got a working Docker image for the action and I got it tested locally, before releasing and shipping.&lt;/p&gt;

&lt;p&gt;Since wasting AI credits is wasteful and the process somewhat repeatable, I asked the AI to generate a shell script that could be used to fetch the details from DockerHub, so I could use it next time a similar PR would show up, processing it would become significantly easier, faster and cheaper using a script doing the steps an AI would do and I would avoid the prompting.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>githubaction</category>
      <category>release</category>
    </item>
    <item>
      <title>Baseline - ported to Go</title>
      <dc:creator>Jonas Brømsø</dc:creator>
      <pubDate>Tue, 07 Oct 2025 17:31:20 +0000</pubDate>
      <link>https://forem.com/jonasbn/baseline-ported-to-go-4pep</link>
      <guid>https://forem.com/jonasbn/baseline-ported-to-go-4pep</guid>
      <description>&lt;p&gt;I got an idea for an application that would help me analysis the a large code base across multiple repositories using all your favorite text tools, my own being:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ag&lt;/li&gt;
&lt;li&gt;find&lt;/li&gt;
&lt;li&gt;xargs&lt;/li&gt;
&lt;li&gt;perl&lt;/li&gt;
&lt;li&gt;and so forth&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I blogged about the idea in &lt;a href="https://dev.to/jonasbn/baseline-a-parallel-git-universeconcept-for-easy-searching-k1m"&gt;Baseline a parallel Git Universe/Concept for Easy Searching&lt;/a&gt; and started working on a prototype.&lt;/p&gt;

&lt;p&gt;The first working version was a basic shell script, that utilized Git commands and it worked well enough for a first version.&lt;/p&gt;

&lt;p&gt;It did however lack features like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;repository discovery&lt;/li&gt;
&lt;li&gt;private repository support&lt;/li&gt;
&lt;li&gt;better UI/UX&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now I finally got some time to give it some more attention and recently I ported &lt;a href="https://github.com/jonasbn/baseline/blob/c1eaf2996a334565b29b6a7cfe9f8fda7a3f5e69/baseline.sh" rel="noopener noreferrer"&gt;the shell script&lt;/a&gt; to Go.&lt;/p&gt;

&lt;p&gt;Last version of the shell script was tagged as &lt;a href="https://github.com/jonasbn/baseline/releases/tag/v0.2.0" rel="noopener noreferrer"&gt;v0.2.0&lt;/a&gt; and I am now at a working Go version tagged as &lt;a href="https://github.com/jonasbn/baseline/releases/tag/v0.5.0" rel="noopener noreferrer"&gt;v0.5.0&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With version 0.5.0:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The UI/UX has been improved&lt;/li&gt;
&lt;li&gt;Repository discovery has been added, currently supporting:

&lt;ul&gt;
&lt;li&gt;GitHub (public and private)&lt;/li&gt;
&lt;li&gt;BitBucket (public and private)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;For now I have only scratched my own itch, so there might be variations to the above mentioned use cases the application do not support, so please consider this vary much pre-release software and do note that features might change in future releases and all use is at your own risk, but read the code, even though it is AI generated, it is still easy to read and understand.&lt;/p&gt;

&lt;p&gt;There is still a lot of work to do, many features to add and evaluating and testing the concept more. And about that the implementation has been implemented primarily using a coding agent.&lt;/p&gt;

&lt;p&gt;This speeds up the process and since I actually just needed this for some other work, it did not want for this to take up too much time.&lt;/p&gt;

&lt;p&gt;Next step for me is to add more features, but I want to use it some more for some real work, then I can decide on what to prioritize next.&lt;/p&gt;

&lt;p&gt;Right now I am pondering about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding a configuration file&lt;/li&gt;
&lt;li&gt;UI/UX improvements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since I do not think the UI/UX is quite there yet and I want to make it easier to understand what is going on,&lt;/p&gt;

&lt;p&gt;The addition of a configuration file would also make it easier to customize the behavior of the tool and would eliminate the high number of command line options.&lt;/p&gt;

&lt;p&gt;I will keep you posted on the progress, if you have suggestions or feedback, please let me know.&lt;/p&gt;

&lt;p&gt;You can find the project at: &lt;a href="https://github.com/jonasbn/baseline" rel="noopener noreferrer"&gt;GitHub: jonasbn/baseline&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>go</category>
      <category>opensource</category>
      <category>git</category>
      <category>cli</category>
    </item>
    <item>
      <title>WIP is waste</title>
      <dc:creator>Jonas Brømsø</dc:creator>
      <pubDate>Fri, 19 Sep 2025 19:01:03 +0000</pubDate>
      <link>https://forem.com/jonasbn/wip-is-waste-208n</link>
      <guid>https://forem.com/jonasbn/wip-is-waste-208n</guid>
      <description>&lt;p&gt;I have been referring to this article: &lt;a href="https://thoughtbot.com/blog/wip-is-waste" rel="noopener noreferrer"&gt;"WIP is waste"&lt;/a&gt; from Thoughtbot by Jared Turner on multiple occasions and sharing it with my colleages. I know it is an opinion piece, but it echoes my own experience and perspective on work, projects, and tasks.&lt;/p&gt;

&lt;p&gt;The article is short, but it carries some good material. The essence is to get tasks out of WIP (Work In Progress) as fast as possible, because the longer something is in WIP and just having something in WIP is wasted value and postponed outcome and opportunity.&lt;/p&gt;

&lt;p&gt;The article outlines these examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;It’s done, I’m just waiting on a review&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;It’s complete, I just need to do some final testing&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;It’s ready, I just need to merge and deploy&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the conclusions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Before a task is shipped it provides zero value.&lt;/li&gt;
&lt;li&gt;Any work in progress is pure cost.&lt;/li&gt;
&lt;li&gt;Two tasks in progress adds cost, for no value.&lt;/li&gt;
&lt;li&gt;Only after shipping do you create value. Always ship.&lt;/li&gt;
&lt;li&gt;One task shipped is infinitely better than 4 tasks “almost done”.&lt;/li&gt;
&lt;li&gt;Ship something of value first. Then begin something new.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My own experience and observations are variations of the examples above, so here are some additional examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;In a setup with multiple roles, hand over between roles causes delays&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Running too many things in parallel/multitasking causes delays&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Lack of focus causes delays&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Code in branches not merged is not value&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Pull Requests not reviewed and merged is not value&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Work not deployed is not value&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not to say that everything must be rushed through, but rather that the focus should be on getting things done and out of WIP as fast as possible. This also means that if something is not moving forward, it should be evaluated if it is worth continuing or if it should be terminated.&lt;/p&gt;

&lt;p&gt;Another good argument for getting things done, is that the work in the future, will be based is based on what be delivered now. Both the learnings and the actual deliverables. So the sooner something is delivered, the sooner it can be used as a foundation for further work.&lt;/p&gt;

&lt;p&gt;You need a balance between start and closing of tasks. If you start too many things, you will have too many things in WIP and not enough things done. If you close too many things, you will not have enough things in WIP to work on. You need to find a balance that works for you and your team.&lt;/p&gt;

&lt;p&gt;I have experienced a team, keeping starting too many bug fixes meaning that the bug fixes got delayed getting finished and deployed. A proper triage and prioritization of bug fixes, would have helped. Focusing on getting a few bug fixes done and deployed, would have been better than having many bug fixes in progress and fewer deployed and at some point the same bugs are being reported again and you end up in a bug administration soup.&lt;/p&gt;

&lt;p&gt;Another lack of focus example, was a collague keeping starting new initiatives and features, but when as they got developed and tested, they ended up not being deployed for several sprints awaiting UAT. It seemed as if the focus was on starting new things, but as it was started it was no longer interesting. Compared to other examples of WIP, this was very expensive, since the work was done.&lt;/p&gt;

&lt;p&gt;So my conclusions are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Focus on getting things done and out of WIP as fast as possible, keyword is focus&lt;/li&gt;
&lt;li&gt;If something is not moving forward, evaluate if it is worth continuing or if it should be terminated&lt;/li&gt;
&lt;li&gt;Prioritize and triage tasks to avoid too many things in WIP&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Focus on getting a few things progressing, completed and deployed, rather than many things in slow progress&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Find a balance between starting and closing tasks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use what is delivered as a foundation for further work&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>article</category>
      <category>reflection</category>
      <category>opinion</category>
      <category>work</category>
    </item>
  </channel>
</rss>
