Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .codespell-dict
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sectoin->section
File renamed without changes.
75 changes: 75 additions & 0 deletions .github/scripts/codespell_annotations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import argparse
import subprocess
import re
import sys


def _parse_args():
parser = argparse.ArgumentParser(description="Runs codespell and creates GitHub annotations for any errors found.")
parser.add_argument(
"--exclude-file",
type=str,
help="Path to a file containing exclude patterns for codespell."
)

parser.add_argument(
"--dictionary",
action='append',
type=str,
help="Path to a file containing custom spelling corrections for codespell or '-' for default dictionary."
)
parser.add_argument(
"--skip",
type=str,
help="Comma-separated list of files/folders to skip for codespell."
)

return parser.parse_args()


def run_codespell_and_create_annotations(args):
"""
Runs codespell with provided arguments and formats its output as GitHub annotations.
"""
command = ["codespell", ".", "--quiet-level", "3"]
if args.exclude_file:
command.extend(["--exclude-file", args.exclude_file])
if args.skip:
command.extend(["--skip", args.skip])
if args.dictionary:
for dict_path in args.dictionary:
command.extend(["--dictionary", dict_path])

print(f"Running command: {' '.join(command)}")

# Execute the command
result = subprocess.run(command, capture_output=True, text=True)

# If codespell printed anything, it means there are errors
if result.stdout:
errors_output = result.stdout.strip()

error_pattern = re.compile(r"^(.*):(\d+): (\w+) ==> (.*)$")

print("Spelling errors found. Creating annotations...")
error_count = 0
for line in errors_output.split('\n'):
match = error_pattern.match(line)
if match:
file_path, line_num, wrong_word, suggestion = match.groups()
# This is the magic line that creates the annotation in GitHub
title="Spelling error"
message = f"{wrong_word} -> {suggestion}"
if file_path.startswith("./"):
file_path = file_path[2:]
print(f"::error file={file_path},line={line_num},title={title}::{message}")
error_count += 1

if error_count > 0:
sys.exit(1)
else:
print("✅ No spelling errors found.")


if __name__ == "__main__":
run_codespell_and_create_annotations(_parse_args())
32 changes: 19 additions & 13 deletions .github/workflows/spell-check.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
# GitHub Action to automate the identification of common misspellings in text files.
# https://github.com/codespell-project/actions-codespell
# https://github.com/codespell-project/codespell
name: codespell
on: [pull_request]
name: Check Spelling

permissions:
contents: read
on: [pull_request]

jobs:
codespell:
if: github.repository == 'cellml/libcellml'
name: Check for spelling errors
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: codespell-project/actions-codespell@v2
- name: Check out code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
check_filenames: true
skip: ./.git,./tests/gtest/include/gtest/gtest.h,./tests/gtest/src/gtest-all.cc,./src/dtds/mathml2/*
exclude_file: .codespellexclude
python-version: '3.x'

- name: Install codespell
run: pip install codespell

- name: Create spelling annotations
run: |
python .github/scripts/codespell_annotations.py \
--exclude-file .codespell-exclude \
--skip ./.git,.codespell-dict,./tests/gtest/include/gtest/gtest.h,./tests/gtest/src/gtest-all.cc,./src/dtds/mathml2/* \
--dictionary .codespell-dict \
--dictionary -
Loading