Refine JabKit CLI: positional input argument and check command group#15759
Conversation
Group the consistency and integrity checks under a new `check` parent command (`jabkit check consistency`, `jabkit check integrity`) and default `check integrity` to the txt output format. Accept the input file as a positional argument on every input-taking subcommand via a shared InputOption mixin; `--input` is kept as an alias. This supersedes ADR-0045 (ADR-0057) for increased convenience while preserving cross-command consistency. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add a BibliographyConsistencyCheckResultErrorFormatWriter producing line-oriented `file:line:column: message` output, mirroring the integrity check's errorformat writer. One line is emitted per deviating field of a reported entry. Make `errorformat` the default output format for both `jabkit check` subcommands. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
jabkit check <file> now runs the consistency and integrity checks together. The shared check logic is extracted into static execute() methods so the parent check command and the consistency/integrity subcommands reuse it. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the "errorformat"/"txt"/"csv" string literals in the `check` commands with `FORMAT_*` constants on `Check`. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Align the `?`/`:` operators under the first operand to match the JabRef code style. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
@InAnYan I thought too complicated regarding the JBang tests - with some more effort on the CI, the test should be straight forward - see |
Review Summary by Qodo(Agentic_describe updated until commit e415751)Refine JabKit CLI: positional input argument, check command grouping, and errorformat output
WalkthroughsDescription• Restructure jabkit CLI with new check parent command grouping consistency and integrity checks • Accept input files as positional arguments with --input as backward-compatible alias • Add errorformat output format to consistency check, making it default for both checks • Support running both checks together via jabkit check <file> without subcommand • Refactor commands to use shared InputOption mixin and return exit codes consistently Diagramflowchart LR
A["CLI Input"] -->|"positional or --input"| B["InputOption Mixin"]
B --> C["Check Parent Command"]
C -->|"consistency"| D["CheckConsistency"]
C -->|"integrity"| E["CheckIntegrity"]
C -->|"no subcommand"| F["Run Both Checks"]
D --> G["errorformat/txt/csv Output"]
E --> G
F --> G
File Changes1. jabkit/src/main/java/org/jabref/toolkit/commands/Check.java
|
Code Review by Qodo
1. Null passed to getFieldRange
|
| if (inputFile == null) { | ||
| System.out.println("Specify a subcommand (consistency, integrity) or an input file."); | ||
| return 0; |
There was a problem hiding this comment.
1. Unlocalized check console message 📘 Rule violation ⚙ Maintainability
Check.call() prints a hardcoded user-facing message instead of using the project localization mechanism. This prevents translation and violates the localization standard for user-visible messages.
Agent Prompt
## Issue description
A user-facing CLI message is printed as a hardcoded English string, bypassing JabRef localization.
## Issue Context
Other `jabkit` commands print user-visible output via `Localization.lang(...)`. The new `check` command should follow the same convention.
## Fix Focus Areas
- jabkit/src/main/java/org/jabref/toolkit/commands/Check.java[44-46]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
There was a problem hiding this comment.
I am not sure if we should translate JabKit in the first place - opinions?
| - name: Build JBang scripts and run launchers | ||
| uses: ./.github/actions/jbang-check |
There was a problem hiding this comment.
2. Jbang main job missing setup 🐞 Bug ☼ Reliability
The jbang-main workflow job invokes a local composite action without checking out the repository or installing JDK/JBang, so it will fail on main. The same workflow’s jbang-pr job still performs checkout and setup, making this a main-branch-only regression.
Agent Prompt
### Issue description
The `jbang-main` job calls `./.github/actions/jbang-check` but does not run `actions/checkout` and does not install JDK/JBang (previously done via `./.github/actions/setup-gradle`). Local composite actions require the repo to be present in the workspace, and the `jbang-check` action assumes `jbang` is available.
### Issue Context
`jbang-pr` still performs checkout and uses `setup-gradle` (which installs JDK and JBang), but `jbang-main` no longer does.
### Fix Focus Areas
- .github/workflows/tests-code.yml[381-388]
- .github/actions/jbang-check/action.yml[1-25]
- .github/actions/setup-gradle/action.yml[14-44]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
There was a problem hiding this comment.
This installs JDK and Jbang -> false positive
Emit findings as `file:line:column:citationKey[:field]: message` in both the integrity and consistency error-format writers. Entry-level findings carry only the citation key; field-level findings add the field name. Document the format as req~jabkit.cli.check-errorformat-output~1 and link it from the writers. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Extract the duplicated import-and-validate block from CheckConsistency and CheckIntegrity into JabKit.importBibtexLibrary, which returns an ImportOutcome record. Callers no longer unwrap an Optional. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Remove IntegrityCheckResultTxtWriter. The integrity check's `txt` output format is now an alias for `errorformat`; `csv` is unchanged. The consistency check keeps its tabular `txt` output. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
One step per launcher in the jbang-check action, so a failure points precisely at the offending launcher. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Wrap the "Specify a subcommand ..." and PDF format-option messages in Localization.lang and add the keys to JabRef_en.properties. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Print the --format validation error to System.err and convert PdfUpdate to Callable<Integer> so usage and import errors exit with code 2. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Route user-facing error and usage messages in the jabkit commands to System.err, and convert the remaining Runnable commands to Callable<Integer> so failures exit with code 2 instead of 0. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Update the expected lines to the file:line:column:citationKey:field format the writer now produces. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Persistent review updated to latest commit e415751 |
| uses: actions/checkout@v6 | ||
| with: | ||
| submodules: 'false' | ||
| submodules: 'true' |
There was a problem hiding this comment.
yeah - context
- name: Publish jablib to the local Maven repository
run: ./gradlew -PprojVersion=6.0 :jablib:publishToMavenLocal
jablib needs submodules.
| for (IntegrityMessage message : messages) { | ||
| ParserResult.Range fieldRange = parserResult.getFieldRange(message.entry(), message.field()); | ||
| writer.append("%s:%d:%d: %s\n".formatted( | ||
| // Entry-level findings (e.g. on the citation key itself) carry only the citation key; | ||
| // field-level findings additionally carry the field name. | ||
| String location = message.entry().getCitationKey().orElse(""); | ||
| Field field = message.field(); | ||
| if (field != null && field != InternalField.KEY_FIELD) { | ||
| location += ":" + field.getName(); |
There was a problem hiding this comment.
1. Null passed to getfieldrange 📘 Rule violation ≡ Correctness
IntegrityCheckResultErrorFormatWriter.writeFindings() calls parserResult.getFieldRange(message.entry(), message.field()) before checking whether message.field() is null, which can trigger a NullPointerException for entry-level findings. This violates the requirement to not pass null to methods unless explicitly required.
Agent Prompt
## Issue description
`IntegrityCheckResultErrorFormatWriter.writeFindings()` calls `ParserResult.getFieldRange(...)` with `message.field()` even when it can be `null`, which can cause a NullPointerException.
## Issue Context
The code already treats `message.field()` as potentially `null` (see the `field != null` check), but the null-sensitive call happens before that check.
## Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/integrity/IntegrityCheckResultErrorFormatWriter.java[26-40]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
There was a problem hiding this comment.
I added @Nullmarked and checked all callers --> false positive
CheckIntegrity.execute() always returned 0, so `jabkit check integrity` and `jabkit check FILE` could not report integrity findings via exit status, letting CI pass with integrity problems. Return 1 when findings exist (0 = none, 1 = findings, 2/3 = error), matching CheckConsistency. The parent `check` command propagates the worst code via Math.max. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
JabKitTest > checkIntegrity() FAILED JabKitTest > checkWithoutSubcommandRunsBothChecks() FAILED |
* upstream/main: Update PULL_REQUEST_TEMPLATE.md (#15788) New Crowdin updates (#15787) Update heylogs to 0.18.0 and use github-actions format (#15786) Grand refactoring of the AI features (#15688) Chore(deps): Bump com.fasterxml:aalto-xml in /versions (#15782) Chore(deps): Bump org.junit:junit-bom from 6.0.3 to 6.1.0 in /versions (#15783) Fix default value for unwanted characters (#15743) Fix runner tag Fix runner for JBang (PR) Fix duplicate finder progress counter incrementing on empty queue polls (#15781) Refine JabKit CLI: positional input argument and check command group (#15759) Ignore exception in unregisterListener to prevent exception (#15761) Fix wrong usage of "key" (#15779) Fix Hayagriva export to nest identifiers under serial-number (#15750)
…abRef#15759) * Fix description * Fix typos * Refine JabKit CLI: positional input + check command group Group the consistency and integrity checks under a new `check` parent command (`jabkit check consistency`, `jabkit check integrity`) and default `check integrity` to the txt output format. Accept the input file as a positional argument on every input-taking subcommand via a shared InputOption mixin; `--input` is kept as an alias. This supersedes ADR-0045 (ADR-0057) for increased convenience while preserving cross-command consistency. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Add errorformat output to the consistency check Add a BibliographyConsistencyCheckResultErrorFormatWriter producing line-oriented `file:line:column: message` output, mirroring the integrity check's errorformat writer. One line is emitted per deviating field of a reported entry. Make `errorformat` the default output format for both `jabkit check` subcommands. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Move JabKit CLI changelog entries to "Added" and link PR JabRef#15759 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Run both checks when jabkit check given a file without a subcommand jabkit check <file> now runs the consistency and integrity checks together. The shared check logic is extracted into static execute() methods so the parent check command and the consistency/integrity subcommands reuse it. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Extract jabkit check output-format constants Replace the "errorformat"/"txt"/"csv" string literals in the `check` commands with `FORMAT_*` constants on `Check`. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Fix ternary indentation in InputOption Align the `?`/`:` operators under the first operand to match the JabRef code style. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Add mavenlocal * Refine JBang checks * Pin JBang scripts to Java 25 * Refine check worfklow * Use citationKey:field segments in check errorformat output Emit findings as `file:line:column:citationKey[:field]: message` in both the integrity and consistency error-format writers. Entry-level findings carry only the citation key; field-level findings add the field name. Document the format as req~jabkit.cli.check-errorformat-output~1 and link it from the writers. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Factor out file import/validation in the check commands Extract the duplicated import-and-validate block from CheckConsistency and CheckIntegrity into JabKit.importBibtexLibrary, which returns an ImportOutcome record. Callers no longer unwrap an Optional. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Drop the integrity check txt writer, alias txt to errorformat Remove IntegrityCheckResultTxtWriter. The integrity check's `txt` output format is now an alias for `errorformat`; `csv` is unchanged. The consistency check keeps its tabular `txt` output. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Format switch case labels in CheckIntegrity Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Split launcher --help checks into separate steps One step per launcher in the jbang-check action, so a failure points precisely at the offending launcher. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Localize the jabkit subcommand messages Wrap the "Specify a subcommand ..." and PDF format-option messages in Localization.lang and add the keys to JabRef_en.properties. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Make pdf update fail with a non-zero exit on a bad --format Print the --format validation error to System.err and convert PdfUpdate to Callable<Integer> so usage and import errors exit with code 2. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Send CLI errors to System.err with non-zero exit codes Route user-facing error and usage messages in the jabkit commands to System.err, and convert the remaining Runnable commands to Callable<Integer> so failures exit with code 2 instead of 0. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Fix consistency errorformat writer test assertions Update the expected lines to the file:line:column:citationKey:field format the writer now produces. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Add JBang setup for jbang check * More powerful runner for :jabkit:runJabKitPortableSmokeTest * Fix NPE * Fix handling of "null" * Signal integrity findings with a non-zero exit code CheckIntegrity.execute() always returned 0, so `jabkit check integrity` and `jabkit check FILE` could not report integrity findings via exit status, letting CI pass with integrity problems. Return 1 when findings exist (0 = none, 1 = findings, 2/3 = error), matching CheckConsistency. The parent `check` command propagates the worst code via Math.max. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Fix test * Remove non-useful test --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Related issues and pull requests
No related issue — CLI ergonomics refinement.
PR Description
This PR refines the
jabkitCLI: subcommands now accept the input file as a positional argument (with--inputkept as an alias), the consistency and integrity checks are grouped under a newcheckcommand, andjabkit check consistencygains anerrorformatoutput format that is now the default for bothchecksubcommands. The intent is a more intuitive command-line experience while keeping backward compatibility via the--inputalias.All in all, this moves towards
lint, but this can be a next step to do this cleanly. For now, I think,checkis a good thing?!before
after
Steps to test
jabkitand runjabkit check integrity references.bib— the input file is accepted positionally.jabkit check consistency references.bib— output is emitted inerrorformat(file:line:column: message).--input references.bibstill works as an alias for the positional argument.AI usage
Claude Code (model claude-opus-4-7).
Checklist
CHANGELOG.mdin a way that can be understood by the average user (if change is visible to the user)