diff --git a/README.md b/README.md index f0b4108..3b296d9 100644 --- a/README.md +++ b/README.md @@ -50,30 +50,30 @@ your secrets for Cachix. Read the CI customization section. # Table of Contents -- [Creating Packages](#orgdbe452f) -- [Using ERK for development](#orgac601cf) - - [Loading and re-loading your package](#orga0cf377) - - [Jumping to files](#org396eda3) - - [Run tests](#orgcda3976) - - [Duplicating CI Locally](#org3dacc44) - - [Find Files](#org4970f85) -- [File contents and structure](#org8ce5e2c) - - [Setting Up Your Github Repository](#orge370d02) -- [Customizing CI](#orgad90c4f) -- [Licensing, Developer Certificate of Origin](#orgbccb740) -- [Publishing to MELPA](#org89cc5b7) - - [Creating the recipe](#orgc42570c) - - [Testing package build](#org8509443) - - [Testing stable package build](#orgf82d903) - - [MELPA Lints](#org0496004) -- [Maintaining versions](#org2c1191b) -- [Package scope and relation to other work](#orge7e095a) - - [Dependency Management](#org5df7fa9) - - [Discovering and Running Tests & Lints](#orgdcccbf5) - - [Comparisons](#orgbfd286f) -- [Contributing](#orgbaa1077) -- [Footnote on FSF and Emacs Core Licensing](#orgd1e7ded) -- [Shout-outs](#org0f2ed06) +- [Creating Packages](#org55d6c6f) +- [Using ERK for development](#org8df953f) + - [Loading and re-loading your package](#org832dbac) + - [Jumping to files](#org6cd8dde) + - [Run tests](#org59f2f7b) + - [Duplicating CI Locally](#org512e00a) + - [Find Files](#orgd13d7b8) +- [File contents and structure](#orgd91f6b8) + - [Setting Up Your Github Repository](#org2b43980) +- [Customizing CI](#org6f4bf92) +- [Licensing, Developer Certificate of Origin](#org5d1d80d) +- [Publishing to MELPA](#orgf9492cc) + - [Creating the recipe](#org1bcced8) + - [Testing package build](#orgea41cb1) + - [Testing stable package build](#org6975475) + - [MELPA Lints](#orgef6e69d) +- [Maintaining versions](#org90c8308) +- [Package scope and relation to other work](#org74f808b) + - [Dependency Management](#org7e7eab5) + - [Discovering and Running Tests & Lints](#orgdc8001e) + - [Comparisons](#orgccbe76b) +- [Contributing](#org729e175) +- [Footnote on FSF and Emacs Core Licensing](#orga0697b8) +- [Shout-outs](#orgd54722e) # Creating Packages @@ -92,7 +92,7 @@ ask you for: `erk-new` also calls `erk-rename-relicense` to rename all of the files, string replace names, and re-license to GPL3. It also changes the author and resets -the git history. Now just follow the steps in [finish setting up](#orge370d02). Have fun! +the git history. Now just follow the steps in [finish setting up](#org2b43980). Have fun! # Using ERK for development @@ -220,10 +220,10 @@ directories. You can copy this checklist to your org agenda files: -- [X] Create a repository (from [install](#orgb10843e) instructions) +- [X] Create a repository (from [install](#org97f4634) instructions) - [ ] Create an empty GitHub repository configure it as your git remote - [ ] Set up your git commit signing (and verification so that it's obvious) - **and** [sign-off](#orgbccb740) so that it will be hypothetically [straightforward](README.md) for for FSF + **and** [sign-off](#org5d1d80d) so that it will be hypothetically [straightforward](README.md) for for FSF to pull in your changes if they later change to DCO instead of copyright assignment. - [ ] Sign up for [cachix](https://app.cachix.org/) and, create a binary cache with API tokens and public @@ -243,7 +243,7 @@ You can copy this checklist to your org agenda files: **Note**, Python is used to run a DCO check script, nothing more. - [ ] Get your package working, pushed, actions run, and CI badges all green -- [ ] [Publish](#org89cc5b7) to MELPA +- [ ] [Publish](#orgf9492cc) to MELPA - [ ] Make a post on [reddit](https://reddit.com/r/emacs/) and [mastodon](https://emacs.ch/) about your new package @@ -538,16 +538,13 @@ Non-exhaustive list of changes that are very welcome: - Expose trivial options where a structural choice has limited them unnecessarily - Behave the same, but with a less complicated code -- Guix or other pure dependency management support +- More templates, such as those for dynamic modules or using different CI Changes will likely be rejected if it is aimed at: - Non-elisp interfaces meant for invocation outside of Emacs or with scripting implemented in a language besides elisp. - Managing dependencies outside of Nix (or other pure dependency management) - expressions -- CI infrastructure support for non-Actions infrastructure (which cannot be - tested in this repo) - Backwards compatibility for Emacs two versions behind next release. Master, current stable release, and release - 1 are the only versions being supported - pre-flake Nix support diff --git a/doc/README.org b/doc/README.org index 22fbeb8..52ee2a6 100644 --- a/doc/README.org +++ b/doc/README.org @@ -180,16 +180,13 @@ answer all the questions. - Expose trivial options where a structural choice has limited them unnecessarily - Behave the same, but with a less complicated code - - Guix or other pure dependency management support + - More templates, such as those for dynamic modules or using different CI Changes will likely be rejected if it is aimed at: - Non-elisp interfaces meant for invocation outside of Emacs or with scripting implemented in a language besides elisp. - Managing dependencies outside of Nix (or other pure dependency management) - expressions - - CI infrastructure support for non-Actions infrastructure (which cannot be - tested in this repo) - Backwards compatibility for Emacs two versions behind next release. Master, current stable release, and release - 1 are the only versions being supported - pre-flake Nix support diff --git a/lisp/erk.el b/lisp/erk.el index 8956c7b..6dd073d 100644 --- a/lisp/erk.el +++ b/lisp/erk.el @@ -233,8 +233,11 @@ Returns FUN if it's bound and within the project." "Return a list of the elisp files in DIR. Ignore autoloads." (->> - (directory-files dir nil (rx ".el" string-end)) - (--reject (string-match-p (rx "autoloads.el" string-end) it)))) + (directory-files dir nil (rx (literal ".el") string-end)) + (--reject (string-match-p (rx (literal "autoloads.el") line-end) it)) + ;; flycheck creates a short-lived file starting with flycheck_ + ;; Will heisenbug you. + (--reject (string-match-p (rx line-start (literal "flycheck_")) it)))) (defun erk--dir-features (dir) "Return list of features provided by elisp files in DIR. @@ -357,12 +360,22 @@ for development, and being lenient for degenerate cases is fine." ;; back into elisp files (find-file (erk--project-root-feature-file))))) +(defun erk--last-defname () + "Return previous definition and name. +Returns nil if we don't know what kind of definition it is or +what to do with it (yet). Returns `(def . name)' form." + (save-excursion + (beginning-of-defun) + (pcase-let* ((`(,def ,name) + (funcall load-read-function (current-buffer)))) + (cons def name)))) + (defun erk--insert-test (fun buffer) "Insert test named TEST-SYMBOL for FUN into BUFFER." (pop-to-buffer buffer) ;; If the buffer is open and the point is near a defun already, just slam in a ;; test. If not, put the test in at the end. - (if (erk--last-defname) + (if (eq (car (erk--last-defname)) 'ert-deftest) (progn (beginning-of-defun) (forward-sexp)) @@ -371,21 +384,13 @@ for development, and being lenient for degenerate cases is fine." (backward-sexp) (backward-sexp) (forward-sexp))) + ;; TODO test templates configuration (let ((before (format "\n\n(ert-deftest %s-test ()\n (should (%s" fun fun)) (after ")))")) (insert before) (save-excursion - (insert after)))) - -(defun erk--last-defname () - "Return previous definition and name. -Returns nil if we don't know what kind of definition it is or -what to do with it (yet). Returns `(def . name)' form." - (save-excursion - (beginning-of-defun) - (pcase-let* ((`(,def ,name) - (funcall load-read-function (current-buffer)))) - (cons def name)))) + (insert after)) + (recenter))) (defun erk--make-test-symbol (symbol) "Convert defun SYMBOL into test symbol." @@ -417,8 +422,9 @@ corresponding `defun' are supported." (progn (erk-reload-project-tests) (when (ert-test-boundp test-name) test-name))))) (if test - (progn (ert-find-test-other-window test) - (forward-sexp)) + (progn (find-function-do-it test 'ert--test 'switch-to-buffer) + (forward-sexp) + (recenter)) (let ((test-buffer (erk-jump-features))) (when (y-or-n-p (format "%s not found. Create? " test-name)) @@ -431,13 +437,10 @@ corresponding `defun' are supported." (if def (progn (find-function-do-it def nil 'switch-to-buffer) - (forward-sexp)) - (progn (erk-jump-features) - (user-error "Definition not found: %s" def-name))))) + (forward-sexp) + (recenter)) + (progn (erk-jump-features))))) (_ - (user-error - "No compatible def before point. def: %s name: %s" - def name) (erk-jump-features))))) (defun erk--last-test () @@ -478,26 +481,31 @@ Will reload all features and test features." (defun erk-ert-project-results-buffer () "Return an ERT buffer name based on project name.") +(defun erk--get-ert-test-symbols () + "Return all defined ERT test symbols. +Does not reload." + (let ((test-features (erk--test-features))) + (->> test-features + (-map #'symbol-file) + (--map (cdr (assoc it load-history))) + (-flatten-n 1) + (--filter (eq 'define-symbol-props (car it))) + (-map #'cdr) + (-flatten-n 2) + (--filter (plist-get (symbol-plist it) 'ert--test))))) + (defun erk-ert-project-selector () "Return a selector for just this project's ERT test. This selector generates the symbols list before that selector will run, so new features or new symbols only available after reload will not be picked up. Run this after any necessary feature reloading." - (let* ((test-features (erk--test-features)) - (test-symbols (->> test-features - (-map #'symbol-file) - (--map (cdr (assoc it load-history))) - (-flatten-n 1) - (--filter (eq 'define-symbol-props (car it))) - (-map #'cdr) - (-flatten-n 2)))) - (message "test-symbols: %s" test-symbols) - `(satisfies ,(lambda (test) - (member (ert-test-name test) test-symbols))))) + `(member ,@(erk--get-ert-test-symbols))) ;;;###autoload (defun erk-ert-project () + ;; TODO select failed, automatically when there are failed figure out how to + ;; offer up tags as options. See `ert-select-tests', but it's just okay "Run Ert interactively, with selector for this project." (interactive) (erk-reload-project-package) diff --git a/test/erk-test.el b/test/erk-test.el index 933d971..e816aa6 100644 --- a/test/erk-test.el +++ b/test/erk-test.el @@ -93,7 +93,7 @@ (ert-deftest erk-jump-features-test () ;; jump to feature when in tests (should - (save-excursion + (save-window-excursion ;; test normally executes in a temporary buffer but `erk-jump-features' ;; relies on `current-buffer'. (find-file (erk--project-root-feature-file)) @@ -101,17 +101,28 @@ (string-match-p "test" default-directory))) ;; jump to tests when in feature (should - (save-excursion + (save-window-excursion (find-file (concat (erk--test-directory) "erk-test.el")) (erk-jump-features) (string-match-p "lisp" default-directory))) ;; jump to feature when in root (should - (save-excursion + (save-window-excursion (find-file (concat (erk--project-root) "README.md")) (erk-jump-features) (string-match-p "lisp" default-directory)))) +(ert-deftest erk-jump-defs-test () + (should + (save-window-excursion + (find-file (concat (erk--project-elisp-dir) + "/erk.el")) + (save-excursion + (goto-char (point-min)) + (search-forward "(defun erk-jump-defs") + (erk-jump-defs) + (string-match-p "erk-test.el" (buffer-file-name (current-buffer))))))) + (ert-deftest erk--project-elisp-dir-test () (should (erk--project-elisp-dir))) @@ -137,6 +148,7 @@ (should (erk--project-contains-p (erk--project-root-feature-file)))) (ert-deftest erk-clone-test () + :tags '("slow") (let ((enable-local-variables nil) (clone-root (make-temp-file "erk-clone-test-" t))) (erk-clone (cdr (assoc 'erk-basic erk-templates)) @@ -150,6 +162,7 @@ (delete-directory clone-root t))) (ert-deftest erk-new-test () + :tags '("slow") (let ((enable-local-variables nil) (erk-after-new-hook (when (require 'magit nil t) '(magit-status)))