diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ad947cb..1418b4d 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,4 +1,4 @@ -# Lints the QuPath script (LabConstrictorTools.groovy) with npm-groovy-lint (CodeNarc rules); the rules are set in .groovylintrc.json. +# Lints the QuPath script (the files listed in parts.txt, joined into one) with npm-groovy-lint (CodeNarc rules); the rules are set in .groovylintrc.json. # # The GUI tests in tests/ run in their own workflow, qupath-gui.yml. name: lint @@ -20,9 +20,27 @@ jobs: - uses: actions/setup-node@v4 with: node-version: "22" + - name: Part files stay below 600 lines (LabConstrictorTools.groovy is the grandfathered main script, from before the split) + run: | + RES=src/main/resources/org/cellmigrationlab/labconstrictor/qupath + status=0 + while IFS= read -r part || [ -n "$part" ]; do + [ -z "$part" ] || [ "$part" = "LabConstrictorTools.groovy" ] && continue + lines=$(wc -l < "$RES/$part") + echo "$part: $lines lines" + [ "$lines" -lt 600 ] || { echo "::error file=$RES/$part::$part has $lines lines (the limit is 600): split it into a new file and list it in parts.txt"; status=1; } + done < "$RES/parts.txt" + exit $status + - name: Join the script files (parts.txt) into the one script the extension runs + # CodeNarc reads one file at a time, so a class used from another file would not resolve: the joined text is what is linted + run: | + RES=src/main/resources/org/cellmigrationlab/labconstrictor/qupath + mkdir lint-input + { while IFS= read -r part || [ -n "$part" ]; do [ -z "$part" ] || { cat "$RES/$part"; echo; }; done < "$RES/parts.txt"; } > lint-input/LabConstrictorTools-all.groovy - name: Lint the script (fails on any finding) run: > npx --yes npm-groovy-lint@18.0.0 - --path src/main/resources/org/cellmigrationlab/labconstrictor/qupath + --path lint-input --files "**/*.groovy" + --config .groovylintrc.json --failon info diff --git a/README.md b/README.md index fd7feaa..a137add 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,9 @@ so QuPath never imports the app's packages and needs no Python of its own. Same 2. Drop `labconstrictor-qupath-0.1.0.jar` on the QuPath window (or into the QuPath extensions folder) and restart QuPath. 3. **Extensions > LabConstrictor tools...** -Without the jar: open `src/main/resources/org/cellmigrationlab/labconstrictor/qupath/LabConstrictorTools.groovy` in QuPath's Script Editor and run it. +Without the jar: the script is several files now (`src/main/resources/org/cellmigrationlab/labconstrictor/qupath/`, joined in the order of `parts.txt`; the first is the main script). `./build.sh` also writes `target/LabConstrictorTools-all.groovy`, all of them in one file: open that one in QuPath's Script Editor and run it. The main script alone no longer runs. + +Needs **labconstrictor-tools 0.3.0a1 or newer** in the app's environment (the run record and the clean-up use its helpers and its `prune` command). A run of an app with an older one is refused with `this app's labconstrictor-tools 0.2.0rc1 is older than the 0.3.0a1 this host needs: update it`. ## What it does * Pick an app and a tool. Numbers (range, unit), choices, checkboxes, text, files and folders become fields; parameters of a group sit under a heading, advanced ones in a collapsed section, optional ones without a default have a "set" box (unticked = the tool gets nothing), and `enabled_when` greys fields out. @@ -21,7 +23,8 @@ Without the jar: open `src/main/resources/org/cellmigrationlab/labconstrictor/qu * **Points** found in the image that is open in QuPath become a point annotation named `:` (replaced by the next run when the output declares `Replace()`); points of any other image are shown as a table. * "No match" is a message, not an error. Progress bar, Cancel (a tool that ignores it is killed after 3 s), worker kept between runs (or not), details of the last run, no worker left behind when the window closes. * **Trust checks** on every registry entry (same rules as the Python registry and the Fiji script): the entry names its five text fields; the app name is a plain name; the interpreter lies inside the install prefix (which is not a filesystem root); the entry and its schema file are owned by you (in a shared folder also by root) and not writable by group or others; the schema sits next to the entry; the interpreter, its folder and the prefix are not writable by everybody (a sticky folder like `/tmp` excepted); tool ids and parameter names are plain names, parameter names Python identifiers (a parameter name becomes a file name). An entry that fails is listed under "skipped" with its reason and never started. On Windows the owner and permission checks do not apply. -* Results are kept in `~/.labconstrictor/results/