Posted on

Sometimes I wonder... am I the only one with this tiny little obsession for consistency in how I write Markdown files? Hell no! See the folks behind markdownlint, they definitely have the same itch. With this linter and its CLI, gone are the chaotic days of incongruous Markdown files. Now, I can sleep better again, and you can too! (Not based on scientific evidence... but who knows?)

Don't go sleep yet though, let's start lintin' those pesky Markdown files with markdownlint. You'll even see how this can be nicely added to a project's continuous integration (CI) with GitHub Actions.

1, 2, 3 ― Lint!

You don't run before you walk, ehm... I mean you don't lint Markdown files before you install markdownlint's CLI:

npm install [email protected] --global

Done? Great! In a repository with some Markdown files, execute this command to lint them all:

markdownlint-cli2 '**/*.md' '#vendor'

In the snippet above, I showcase how you can exclude a directory. Any file under the vendor directory won't be linted. You can omit this part if you don't need it.

Now you tell me "What's the point of having a tool if I cannot make it my own?". After all, it's your files and repositories, your rules! Just put them in .markdownlint.yml...

# Default state for all rules
default: true

# Trailing punctuation in headings
MD026:
  # The following punctuation characters aren't accepted in headings
  # This differs from the default configuration by accepting exclamation marks in headings
  punctuation: ".,;:。,;:"

And if this isn't enough for you... go wild with the rules, the world is yours!

Time for a Bit of (GitHub) Action(s)

So you have a GitHub repository, maybe two or even more (impressive!), and they all got some Markdown files you want to lint? It's your lucky day ― automate this with a sweet continuous integration built with GitHub Actions. Create the file .github/workflows/lint.yml with this YAML:

name: Lint

on:
  # Run this workflow when a commit is pushed to `main`
  push:
    branches:
      - main
  # Run this workflow on any PR targeting `main`
  pull_request:
    branches:
      - main

jobs:
  lint:
    runs-on: ubuntu-24.04
    steps:
      # https://github.com/actions/checkout
      - uses: actions/checkout@v4
      # https://github.com/actions/setup-node
      - uses: actions/setup-node@v4
      - name: Install CLI for markdownlint
        run: npm install [email protected] --global
      - name: Lint Markdown files, while excluding anything under the node_modules directories (which is generated by `npm install` above)
        run: markdownlint-cli2 "**/*.md" "#node_modules"

Every commit pushed to main and PRs targeting main will now lint Markdown files automatically in your continuous integration. Automation is the best!

A Bit Too Eager?

Maybe markdownlint is sometimes a bit too trigger-happy? Calm it down for a few lines, like in this example below:

<!-- markdownlint-disable -->
Markdown which doesn't satisfy some *markdownlint* rule(s).
<!-- markdownlint-enable -->

Do You Even Lint?

Yes, you do now! Linting Markdown files, then having this run with GitHub Actions, it's awesome. Keep those files in check, while I subtly go to bed... I did hint about getting a better sleep now 🥳. But in all seriousness, enjoy your day!