From 88da84f2ce342f006e8cfb3ec302cc9e32af0591 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Tue, 5 May 2026 03:28:49 -0500 Subject: build: add lint, compile, validate-parens, and :slow tag filter I want a stronger maintainer-discipline baseline as I take over more of this project, so I added four targets that are common in Emacs-Lisp packages. `make lint` runs `checkdoc`, `package-lint`, and `elisp-lint` over `org-drill.el`. It's informational for now and doesn't fail on findings, because the existing source has known docstring and style debt to clear. I'll re-tighten to a hard gate after the docstring pass is done. `make compile` byte-compiles the source with `byte-compile-error-on-warn nil`, matching the existing `build` target's leniency. `make validate-parens` is a fast structural check that surfaces the line of the offending paren without needing a full byte-compile pass. I also added a `:slow` tag filter to the default ERT runners. `test-unit`, `test-integration`, `test-file`, and `coverage` now run with `'(not (tag :slow))`. Tests tagged `:slow` get skipped on the fast feedback path. `test-name` is left alone, since a pattern argument means the user wants those tests run whether or not they're tagged slow. Cask gets `package-lint` and `elisp-lint` as development deps. `.gitignore` gets `*-autoloads.el` so the Cask build artifact stays out. --- .gitignore | 1 + Cask | 4 +++- Makefile | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 75 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index f7fabe8..c137921 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ org-drill.html todo.org /.ai/ /.coverage/ +/*-autoloads.el diff --git a/Cask b/Cask index c9ebcb2..5da2b9a 100644 --- a/Cask +++ b/Cask @@ -7,6 +7,8 @@ (development (depends-on "assess") - (depends-on "undercover")) + (depends-on "undercover") + (depends-on "package-lint") + (depends-on "elisp-lint")) (depends-on "org" "9.2") diff --git a/Makefile b/Makefile index 9f506b4..ef7ea60 100644 --- a/Makefile +++ b/Makefile @@ -42,10 +42,21 @@ DOCKER_TAG=26 COVERAGE_DIR = .coverage COVERAGE_FILE = $(COVERAGE_DIR)/simplecov.json +# Source file (single-file package) +SOURCE_FILE = org-drill.el + +# ERT selector that excludes tests tagged :slow. Applied to the +# default `make test-*' and `make coverage' loops so a slow integration +# suite doesn't dominate the fast feedback path. `make test-name' is +# left alone — if the user named a pattern, run it whether or not +# anything matches is tagged slow. +ERT_FAST_SELECTOR = (ert-run-tests-batch-and-exit '(not (tag :slow))) + .PHONY: help test test-all test-unit test-integration test-file test-name setup build clean clean-elc .PHONY: robot robot-all robot-basic robot-leitner robot-all-card robot-spanish robot-explainer .PHONY: docker-test test-cp test-git .PHONY: coverage coverage-clean +.PHONY: lint compile validate-parens # Default target help: @@ -67,6 +78,11 @@ help: @echo " make coverage - Generate simplecov JSON at $(COVERAGE_FILE)" @echo " make coverage-clean - Delete the coverage report file" @echo "" + @echo "Validation & Lint:" + @echo " make compile - Byte-compile $(SOURCE_FILE)" + @echo " make validate-parens - Check $(SOURCE_FILE) for unbalanced parens" + @echo " make lint - Run checkdoc + package-lint + elisp-lint" + @echo "" @echo "Advanced Targets:" @echo " make setup - Install dependencies via Cask" @echo " make build - Build package via Cask" @@ -123,7 +139,7 @@ test-unit: setup -l assess \ -l org-drill.el \ -l $$test \ - -f ert-run-tests-batch-and-exit || failed=$$((failed + 1)); \ + --eval "$(ERT_FAST_SELECTOR)" || failed=$$((failed + 1)); \ done; \ if [ $$failed -eq 0 ]; then \ echo "[✓] All unit tests passed"; \ @@ -170,7 +186,7 @@ endif -l assess \ -l org-drill.el \ -l $(TEST_DIR)/$(FILE) \ - -f ert-run-tests-batch-and-exit + --eval "$(ERT_FAST_SELECTOR)" @echo "[✓] Tests in $(FILE) complete" # Run specific test by name/pattern @@ -214,7 +230,7 @@ coverage: coverage-clean setup $(COVERAGE_DIR) -l $(TEST_DIR)/run-coverage-file.el \ -l org-drill.el \ -l $$test \ - -f ert-run-tests-batch-and-exit || failed=$$((failed + 1)); \ + --eval "$(ERT_FAST_SELECTOR)" || failed=$$((failed + 1)); \ done; \ if [ $$failed -gt 0 ]; then \ echo "[!] $$failed test file(s) failed during coverage run"; \ @@ -233,6 +249,58 @@ coverage-clean: $(COVERAGE_DIR): @mkdir -p $(COVERAGE_DIR) +# +# Validation & Lint +# + +# Byte-compile the source file. byte-compile-error-on-warn is left +# nil so existing warnings don't fail the target — match `make build' +# behavior. Tighten when the warning backlog is cleared. +compile: setup + @echo "[i] Byte-compiling $(SOURCE_FILE)..." + @$(EMACS_ENV) $(CASK) emacs --batch -q \ + --eval "(progn \ + (setq byte-compile-error-on-warn nil) \ + (batch-byte-compile))" $(SOURCE_FILE) + @echo "[✓] Compilation complete" + +# Fast structural check — `check-parens' surfaces the line of the +# offending paren without needing a full byte-compile pass. +validate-parens: + @echo "[i] Checking $(SOURCE_FILE) for unbalanced parentheses..." + @$(EMACS_BATCH) --eval "(condition-case err \ + (progn \ + (find-file \"$(SOURCE_FILE)\") \ + (check-parens) \ + (kill-emacs 0)) \ + (error (progn \ + (message \"ERROR: %s\" err) \ + (kill-emacs 1))))" + @echo "[✓] $(SOURCE_FILE) parens balance" + +# Run all three linters. Informational — does not exit non-zero on +# findings, since the existing source has known docstring and style +# debt to clear. Re-tighten to a hard gate after the docstring pass +# in todo.org is done. +lint: setup + @echo "[i] Running checkdoc + package-lint + elisp-lint on $(SOURCE_FILE)..." + @$(EMACS_ENV) $(CASK) emacs --batch -q \ + --eval "(progn \ + (require 'checkdoc) \ + (require 'package-lint nil t) \ + (require 'elisp-lint nil t) \ + (find-file \"$(SOURCE_FILE)\") \ + (when (featurep 'checkdoc) \ + (message \"-- checkdoc --\") \ + (checkdoc-current-buffer t)) \ + (when (featurep 'package-lint) \ + (message \"-- package-lint --\") \ + (package-lint-current-buffer)) \ + (when (featurep 'elisp-lint) \ + (message \"-- elisp-lint --\") \ + (elisp-lint-file \"$(SOURCE_FILE)\")))" || true + @echo "[i] Lint complete (informational — no hard failure)" + # # Robot Tests (Automated UI Tests) # -- cgit v1.2.3