refactor(ci): generalize commit linter api
Continues from47d1b82
as part of an effort to generalize Doom's CI for use outside this repo: - 'doom ci ...' commands now: - Run in the context of the local repo where they're run, rather than from Doom's install directory ($EMACSDIR). - Load the first of $REPO_ROOT/.github/ci.el, $DOOMDIR/cli.el, or $DOOMDIR/cli.el, before executing CI commands. This allows for per-project configuration, for example: - https://github.com/doomemacs/doomemacs/blob/master/.github/ci.el - https://github.com/doomemacs/themes/blob/master/.github/ci.el (Details may change post-3.0) - Scopeless commit types are now enforced in `doom-cli-commit-scopes`, rather than `doom-cli-commit-rules`. This lets you specify exceptions, like0597466261
. - `doom-cli-commit-scopes` now supports sub-lists, as an easy way to permit type-local scopes. E.g. To allow 'install' and 'faq' scopes only for 'docs:' commits. (add-to-list 'doom-cli-commit-scopes '(docs "install" "faq")) These sublists accepts predicates too. - Fixed the link to git conventions in the linter's failure/warning output, to point to our Discourse post. Ref: https://github.com/doomemacs/doomemacs/blob/master/.github/ci.el Ref: https://github.com/doomemacs/themes/blob/master/.github/ci.el Ref:0597466261
Amend:47d1b82382
This commit is contained in:
parent
10d00b7cc4
commit
4bae9ffa47
1 changed files with 46 additions and 21 deletions
|
@ -4,6 +4,15 @@
|
|||
"TODO"
|
||||
(unless target
|
||||
(user-error "No CI target given"))
|
||||
(when-let* ((ci-dir
|
||||
(or (locate-dominating-file default-directory ".github/ci.el")
|
||||
doom-private-dir))
|
||||
(ci-config
|
||||
(car (or (doom-glob ci-dir ".github/ci.el")
|
||||
(doom-glob ci-dir "ci.el")
|
||||
(doom-glob ci-dir "cli.el")))))
|
||||
(print! (info "Loading %s") (path ci-config))
|
||||
(load ci-config nil t t))
|
||||
(if-let (fn (intern-soft (format "doom-cli--ci-%s" target)))
|
||||
(apply fn args)
|
||||
(user-error "No known CI target: %S" target)))
|
||||
|
@ -64,14 +73,34 @@ Accapted value types can be one or more of ref, hash, url, username, or name.")
|
|||
Don't: \"bump(SCOPE): ...\"
|
||||
Do: \"bump: SCOPE\"")
|
||||
|
||||
(defvar doom-cli-commit-scopes '("ci")
|
||||
"A list of valid commit scopes as strings or functions.
|
||||
(defvar doom-cli-commit-scopes '("ci" doom-cli-enforce-scopeless-types)
|
||||
"A list of valid commit scopes as strings, predicate functions, or lists.
|
||||
|
||||
Functions should take two arguments: a single scope (symbol) and a commit plist
|
||||
representing the current commit being checked against. See
|
||||
`doom-cli-commit-core-rules' for possible values.")
|
||||
These are checked against each item in the comma-delimited scope field of the
|
||||
current commit's message. E.g. 'fix(foo,bar,baz): ...' => foo, bar and baz
|
||||
|
||||
Each element of this list can be one of:
|
||||
|
||||
- A string, compared literally against the scope's name.
|
||||
- A function predicate, taking two arguments (a scope as a symbol, and a plist
|
||||
containing information about the current commit--see `doom-cli-commit-scopes'
|
||||
for more about its structure). These predicates should:
|
||||
- Return non-nil to immediately pass a scope.
|
||||
- Throw a `user-error' to immediately fail the scope.
|
||||
- Return nil to continue with the checks in this list.
|
||||
- A list, denoting type-specific scopes. Its CAR is the type as a symbol, and
|
||||
its CDR is a nested list of scopes as strings/predicates. E.g.
|
||||
|
||||
'(docs \"faq\" \"install\" check-docs)")
|
||||
|
||||
(cl-defun doom-cli-enforce-scopeless-types (scope (&key type scopes summary &allow-other-keys))
|
||||
"Complain about scoped types that are incompatible with scopes"
|
||||
(when (memq type doom-cli-commit-scopeless-types)
|
||||
(user-error "Scopes for %s commits should go after the colon, not before"
|
||||
type)))
|
||||
|
||||
(defvar doom-cli-commit-rules
|
||||
;; TODO Extract into named functions
|
||||
(list (fn! (&key subject)
|
||||
"If a fixup/squash commit, don't lint this commit"
|
||||
(when (string-match "^\\(\\(?:fixup\\|squash\\)!\\|FIXUP\\|WIP\\) " subject)
|
||||
|
@ -112,25 +141,21 @@ representing the current commit being checked against. See
|
|||
(fail! "%S in summary should not be capitalized"
|
||||
(car (split-string summary " ")))))
|
||||
|
||||
(fn! (&key type scopes summary)
|
||||
"Complain about scoped types that are incompatible with scopes"
|
||||
(and scopes
|
||||
(memq type doom-cli-commit-scopeless-types)
|
||||
(fail! "Scopes for %s commits should go after the colon, not before"
|
||||
type)))
|
||||
|
||||
(fn! (&rest plist &key type scopes)
|
||||
"Ensure scopes are valid"
|
||||
(dolist (scope scopes)
|
||||
(condition-case e
|
||||
(or (cl-loop for rule in doom-cli-commit-scopes
|
||||
if (or (and (stringp rule)
|
||||
(string= rule scope))
|
||||
(and (functionp rule)
|
||||
(funcall rule scope plist)))
|
||||
return t)
|
||||
(fail! "Invalid scope: %s" scope))
|
||||
(user-error (fail! "%s" (error-message-string))))))
|
||||
(letf! (defun* check-rule (rule)
|
||||
(or (and (stringp rule)
|
||||
(string= rule scope))
|
||||
(and (functionp rule)
|
||||
(funcall rule scope plist))
|
||||
(and (listp rule)
|
||||
(eq type (car rule))
|
||||
(seq-find #'check-rule (cdr rule)))))
|
||||
(or (seq-find #'check-rule doom-cli-commit-scopes)
|
||||
(fail! "Invalid scope: %s" scope)))
|
||||
(user-error (fail! "%s" (error-message-string e))))))
|
||||
|
||||
(fn! (&key scopes)
|
||||
"Esnure scopes are sorted correctly"
|
||||
|
@ -387,7 +412,7 @@ Note: warnings are not considered failures.")
|
|||
(print! (success "There were no issues!"))
|
||||
(if (> warnings 0) (print! (warn "Warnings: %d" warnings)))
|
||||
(if (> failures 0) (print! (warn "Failures: %d" failures)))
|
||||
(print! "\nSee https://docs.doomemacs.org/-/conventions/git-commits")
|
||||
(print! "\nSee https://discourse.doomemacs.org/git-conventions")
|
||||
(unless (zerop failures)
|
||||
(throw 'exit 1)))
|
||||
t)))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue