Skip to content

Commit

Permalink
Add Markdown diff linter
Browse files Browse the repository at this point in the history
Add GitHub workflow that lints changed Markdown files and fails if the
issue is within the changed lines.

Signed-off-by: Ivan Valdes <[email protected]>
  • Loading branch information
ivanvc committed Aug 6, 2024
1 parent 5d9e9fe commit 89feba7
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 0 deletions.
24 changes: 24 additions & 0 deletions .github/workflows/markdown-diff-lint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
name: Lint Markdown file changes
on: [pull_request]
permissions: read-all

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
with:
fetch-depth: 0
- uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
- uses: tj-actions/changed-files@c65cd883420fd2eb864698a825fc4162dd94482c # v44.5.7
id: changed-files
with:
files: '**/*.md'
- run: npm install -g markdownlint-cli2
- env:
CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
BASE_REF: ${{ github.event.pull_request.base.ref }}
BASE_CLONE_URL: ${{ github.event.pull_request.base.repo.clone_url }}
HEAD_CLONE_URL: ${{ github.event.pull_request.head.repo.clone_url }}
run: make markdown-diff-lint
17 changes: 17 additions & 0 deletions .github/workflows/markdownlint-problem-matcher.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"problemMatcher": [
{
"owner": "markdownlint",
"pattern": [
{
"regexp": "^([^:]*):(\\d+):?(\\d+)?\\s([\\w-\\/]*)\\s(.*)$",
"file": 1,
"line": 2,
"column": 3,
"code": 4,
"message": 5
}
]
}
]
}
2 changes: 2 additions & 0 deletions .markdownlint-cli2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
config:
line-length: false # Allow lines longer than 80 characters.
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,10 @@ ifndef LATEST_VERSION
else
./scripts/update_release_version.sh "$(LATEST_VERSION)"
endif

.PHONY: markdown-diff-lint
markdown-diff-lint:
ifndef CHANGED_FILES
@echo "Warning: CHANGED_FILES is not specified, or empty"
endif
./scripts/markdown_diff_lint.sh "$(CHANGED_FILES)"
126 changes: 126 additions & 0 deletions scripts/markdown_diff_lint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#!/usr/bin/env bash
# This script runs markdownlint-cli2 on changed files.
# Usage: ./markdown_lint.sh <files to lint>

set -eo pipefail

if ! command markdownlint-cli2 dummy.md &>/dev/null; then
echo "markdownlint-cli2 needs to be installed."
echo "Install it by running npm install -g markdownlint-cli2"
exit 1
fi

if [ "$#" -eq 0 ]; then
echo "No provided files to check"
exit
fi

COLOR_RED='\033[0;31m'
COLOR_BOLD='\033[1m'
COLOR_ORANGE='\033[0;33m'
COLOR_NONE='\033[0m' # No Color

function log_error {
echo -n -e "${COLOR_BOLD}${COLOR_RED}$*${COLOR_NONE}\n"
}

function log_warning {
echo -n -e "${COLOR_ORANGE}$*${COLOR_NONE}\n"
}

CHANGED_FILES="$*"
GIT_REMOTE=${GIT_REMOTE:-origin}

if [ -z "${BASE_REF}" ]; then
echo "Empty base reference (\$BASE_REF), assuming: main"
BASE_REF=main
fi

if [ -z "${BASE_CLONE_URL}" ]; then
BASE_CLONE_URL="$(git remote get-url "${GIT_REMOTE}")"
echo "Empty base clone URL (\$BASE_CLONE_URL), assuming: ${BASE_CLONE_URL}"
fi

if [ -z "${HEAD_CLONE_URL}" ]; then
HEAD_CLONE_URL="${BASE_CLONE_URL}"
echo "Empty base clone URL (\$HEAD_CLONE_URL), assuming: ${HEAD_CLONE_URL}"
fi

MD_LINT_URL_PREFIX="https://github.com/DavidAnson/markdownlint/blob/main/doc/"

if [ "${BASE_CLONE_URL}" != "${HEAD_CLONE_URL}" ]; then
GIT_REMOTE=base
git remote add "${GIT_REMOTE}" "${BASE_CLONE_URL}"
git fetch "${GIT_REMOTE}" "${BASE_REF}"
trap 'git remote remove "${GIT_REMOTE}"' EXIT
fi

declare -A files_with_failures start_ranges end_ranges
for file in ${CHANGED_FILES}; do
# Find start and end ranges from changed files.
start_ranges=()
end_ranges=()
# From https://github.com/paleite/eslint-plugin-diff/blob/46c5bcf296e9928db19333288457bf2805aad3b9/src/git.ts#L8-L27
ranges=$(git diff "${GIT_REMOTE}"/"${BASE_REF}" \
--diff-algorithm=histogram \
--diff-filter=ACM \
--find-renames=100% \
--no-ext-diff \
--relative \
--unified=0 -- "${file}" | \
awk 'match($0, /^@@\s-[0-9,]+\s\+([0-9]+)(,([0-9]+))?/, m) { \
print m[1] ":" m[1] + ((m[3] == "") ? "0" : m[3]) }')
i=0
for range in ${ranges}; do
start_ranges["${i}"]=$(echo "${range}" | awk -F: '{print $1}')
end_ranges["${i}"]=$(echo "${range}" | awk -F: '{print $2}')
i=$((1 + i))
done
if [ -z "${ranges}" ]; then
start_ranges[0]=0
end_ranges[0]=0
fi

i=0
markdownlint-cli2 "${file}" 2>/dev/null || true
while IFS= read -r line; do
line_number=$(echo "${line}" | awk -F: '{print $2}' | awk '{print $1}')
while [ "${i}" -lt "${#end_ranges[@]}" ] && [ "${line_number}" -gt "${end_ranges["${i}"]}" ]; do
i=$((1 + i))
done
rule=$(echo "${line}" | awk 'match($2, /([^\/]+)/, m) {print tolower(m[1])}')
lint_error="${line} (${MD_LINT_URL_PREFIX}${rule}.md)"

if [ "${i}" -lt "${#start_ranges[@]}" ] && [ "${line_number}" -ge "${start_ranges["${i}"]}" ] && [ "${line_number}" -le "${end_ranges["${i}"]}" ]; then
# Inside range with changes, raise an error.
if [ -z "${GITHUB_ACTIONS}" ]; then
log_error "${lint_error}"
else
echo "::add-matcher::.github/workflows/markdownlint-problem-matcher.json"
echo "${lint_error}"
echo "::remove-matcher owner=markdownlint::"
fi
files_with_failures["${file}"]=1
else
# Outside of range, raise a warning.
if [ -z "${GITHUB_ACTIONS}" ]; then
log_warning "${lint_error}"
else
echo "::warning::${lint_error}"
fi
fi
done < <(markdownlint-cli2 "${file}" 2>&1 >/dev/null || true)
done

echo "Finished linting"

for file in "${!files_with_failures[@]}"; do
if [ -z "${GITHUB_ACTIONS}" ]; then
log_error "${file} has linting issues"
else
echo "::error::${file} has linting issues"
fi
done
if [ "${#files_with_failures[@]}" -gt "0" ]; then
exit 1
fi

0 comments on commit 89feba7

Please sign in to comment.