Skip to content

Commit 8f7ffcb

Browse files
committed
Merge remote-tracking branch 'upstream/main'
* upstream/main: Issue 13619 Make Citation relations text more clear. (#13620) Explain how to handle notifications (#13630) Fix scope of 'determine issue number' job (#13627) Add proper closing (#13626) Implement logic orchestration for Git Pull/Push operations (#13518) Make pattern for issue number more strict Fix "Cannot load file MultiMergeEntries.fxml" (#13624) Add Copy markdown to copy citation (#13387) Add ADR-0047 (#13621) Initial start of implementing a LSP for integrity checks (#13612) Refactor merge entries package structure (#13614) New Crowdin updates (#13616) BibEntry class no longer implements Cloneable (#13615) Fix dark mode in {} of Citation Relations tab of the entry editor (#13609) Update dependency org.kohsuke:github-api to v2.0-rc.4 (#13611) Fix setting of proxy without password (#13605)
2 parents fc0af37 + 796b419 commit 8f7ffcb

File tree

172 files changed

+4303
-219
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

172 files changed

+4303
-219
lines changed

.github/workflows/on-pr-opened-updated.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ jobs:
1111
runs-on: ubuntu-latest
1212
if: >
1313
(github.repository == 'JabRef/jabref') &&
14+
(github.event.pull_request.head.repo.full_name != 'JabRef/jabref') &&
1415
!(
1516
(github.actor == 'dependabot[bot]') ||
1617
(

.github/workflows/tests-pr.yml

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
path: pr_number.txt
2323

2424
check_title_format:
25-
name: PR title must not start with "Fix for issue <number>"
25+
name: PR title must not contain "issue <number>"
2626
if: github.actor != 'dependabot[bot]' && github.event.pull_request.head.repo.full_name != 'JabRef/jabref'
2727
runs-on: ubuntu-latest
2828
steps:
@@ -36,13 +36,8 @@ jobs:
3636
TITLE=$(gh pr view "${{ github.event.number }}" --json title --template '{{.title}}')
3737
echo "Title: $TITLE"
3838
39-
if echo "$TITLE" | grep -Eiq '^Fix for issue #?[0-9]+'; then
40-
echo "❌ Title starts with 'Fix for issue <number>' — not allowed."
41-
exit 1
42-
fi
43-
44-
if echo "$TITLE" | grep -Eiq '^Fixed the issue'; then
45-
echo "❌ Title starts with 'Fixed the issue' — not allowed."
39+
if echo "$TITLE" | grep -Eiq 'issue ?#?[0-9]+.+'; then
40+
echo "❌ Title contains 'issue <number>' — not allowed."
4641
exit 1
4742
fi
4843

.jbang/CheckoutPR.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
//JAVA 21+
2121
//RUNTIME_OPTIONS --enable-native-access=ALL-UNNAMED
2222

23-
//DEPS org.kohsuke:github-api:2.0-rc.3
23+
//DEPS org.kohsuke:github-api:2.0-rc.4
2424
//DEPS org.eclipse.jgit:org.eclipse.jgit.pgm:7.3.0.202506031305-r
2525

2626
public class CheckoutPR {

.jbang/JabLsLauncher.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
///usr/bin/env jbang "$0" "$@" ; exit $?
2+
3+
//DESCRIPTION jabls - start a bibtex languageserver
4+
5+
//JAVA 24
6+
//RUNTIME_OPTIONS --enable-native-access=ALL-UNNAMED
7+
8+
//SOURCES ../jabls-cli/src/main/java/org/jabref/languageserver/cli/ServerCli.java
9+
//FILES tinylog.properties=../jabls-cli/src/main/resources/tinylog.properties
10+
11+
//SOURCES ../jabls/src/main/java/org/jabref/languageserver/BibtexTextDocumentService.java
12+
//SOURCES ../jabls/src/main/java/org/jabref/languageserver/BibtexWorkspaceService.java
13+
//SOURCES ../jabls/src/main/java/org/jabref/languageserver/LSPLauncher.java
14+
//SOURCES ../jabls/src/main/java/org/jabref/languageserver/LSPServer.java
15+
16+
// REPOS mavencentral,snapshots=https://central.sonatype.com/repository/maven-snapshots/
17+
// REPOS mavencentral,mavencentralsnapshots=https://central.sonatype.com/repository/maven-snapshots/,s01oss=https://s01.oss.sonatype.org/content/repositories/snapshots/,oss=https://oss.sonatype.org/content/repositories,jitpack=https://jitpack.io,oss2=https://oss.sonatype.org/content/groups/public,ossrh=https://oss.sonatype.org/content/repositories/snapshots
18+
//REPOS mavencentral,mavencentralsnapshots=https://central.sonatype.com/repository/maven-snapshots/,s01oss=https://s01.oss.sonatype.org/content/repositories/snapshots/,oss=https://oss.sonatype.org/content/repositories,jitpack=https://jitpack.io,oss2=https://oss.sonatype.org/content/groups/public,ossrh=https://oss.sonatype.org/content/repositories/snapshots,raw=https://raw.githubusercontent.com/JabRef/jabref/refs/heads/main/jablib/lib/
19+
// REPOS mavencentral,jitpack=https://jitpack.io
20+
21+
// Choose one - both should work
22+
// https://central.sonatype.com/service/rest/repository/browse/maven-snapshots/org/jabref/jablib/
23+
//DEPS org.jabref:jablib:6.0-SNAPSHOT
24+
// https://jitpack.io/#jabref/jabref/main-SNAPSHOT
25+
// DEPS com.github.jabref:jabref:main-SNAPSHOT
26+
27+
//DEPS info.picocli:picocli:4.7.7
28+
//DEPS org.jspecify:jspecify:1.0.0
29+
30+
// from jabls
31+
//DEPS org.slf4j:slf4j-api:2.0.17
32+
//DEPS org.tinylog:slf4j-tinylog:2.7.0
33+
//DEPS org.tinylog:tinylog-impl:2.7.0
34+
//DEPS org.slf4j:jul-to-slf4j:2.0.17
35+
//DEPS org.apache.logging.log4j:log4j-to-slf4j:2.25.1
36+
//DEPS info.picocli:picocli:4.7.7
37+
//DEPS org.jabref:afterburner.fx:2.0.0
38+
//DEPS com.github.eclipse:lsp4j:0.24.0
39+
40+
/// This class is required for [jbang](https://www.jbang.dev/)
41+
public class JabLsLauncher {
42+
public static void main(String[] args) throws Exception {
43+
org.jabref.languageserver.cli.ServerCli.main(args);
44+
}
45+
}

.jbang/README.md

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
This directory contains JBang scripts for JabRef.
44
[JBang](https://www.jbang.dev/) allows for running Java applications without having a JDK installed (before).
55

6-
Three use cases:
6+
Four use cases:
77

88
- Try out any pull request with minimal installation. See [our blog entry](https://blog.jabref.org/2025/05/31/run-pr/) for details.
99
- Run JabKit - JabRef's CLI tool.
10+
- Run JabLs - JabRef's Language Server.
1011
- Run JabSrv - JabRef's HTTP server.
1112

1213
## Running JabKit without installation
@@ -16,8 +17,8 @@ By using [gg.cmd](https://github.com/eirikb/gg#ggcmd) you can "just run" JabKit
1617
1. Download `gg.cmd` from: <https://github.com/eirikb/gg#ggcmd>. `gg.cmd` is a "binary" running on macOS, Linux, and Windows. No need for different binaries on different operating systems.
1718
2. Run `gg.cmd`. This will download and use JBang as wrapper around running JabKit:
1819

19-
- Linux/macOS: Run `sh ./gg.cmd jbang jabkit@jabref --help`.
20-
- Windows: Run `gg.cmd jbang jabkit@jabref --help`.
20+
- Linux/macOS: Run `sh ./gg.cmd jbang jabkit@jabref`.
21+
- Windows: Run `gg.cmd jbang jabkit@jabref`.
2122

2223
You can also put `gg.cmd` on your `PATH` and make it executable.
2324
Then you enable `alias jabkit='gg.cmd jbang jabkit@jabref`.
@@ -27,27 +28,57 @@ Then you enable `alias jabkit='gg.cmd jbang jabkit@jabref`.
2728
If you have JBang installed, just run
2829

2930
```terminal
30-
jbang jabkit@jabref --help
31+
jbang jabkit@jabref
3132
```
3233

3334
You can also install `jabkit` permanently in your `PATH`:
3435

3536
1. [Install JBang](https://www.jbang.dev/download/). E.g., by `brew install jbangdev/tap/jbang` or `choco install jbang`
3637
2. Make `jabkit` available on the command line: `jbang app install jabkit@jabref`
37-
3. Run `jabkit --help`
38+
3. Run `jabkit`
3839

3940
[JBang takes care about updating JabKit automatically](https://github.com/orgs/jbangdev/discussions/1636#discussioncomment-6150992).
4041

42+
## Running JabLs
43+
44+
If you have JBang installed, just run following command
45+
46+
```terminal
47+
jbang jabls@jabref
48+
```
49+
50+
With `gg.cmd`:
51+
52+
```terminal
53+
sh ./gg.cmd jbang jabls@jabref
54+
```
55+
56+
With `npx`:
57+
58+
```terminal
59+
npx @jbangdev/jbang jabls@jabref
60+
```
61+
62+
One can add `--help` to see available options.
63+
4164
## Running JabSrv
4265

4366
If you have JBang installed, just run following command
4467

4568
```terminal
46-
jbang jabsrv@jabref --help
69+
jbang jabsrv@jabref
4770
```
4871

4972
With `gg.cmd`:
5073

5174
```terminal
52-
sh ./gg.cmd jbang jabsrv@jabref --help
75+
sh ./gg.cmd jbang jabsrv@jabref
5376
```
77+
78+
With `npx`:
79+
80+
```terminal
81+
npx @jbangdev/jbang jabsrv@jabref
82+
```
83+
84+
One can add `--help` to see available options. E.g., how to set another port and how to specify served libraries.

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
2121
- We added the field `monthfiled` to the default list of fields to resolve BibTeX-Strings for [#13375](https://github.com/JabRef/jabref/issues/13375)
2222
- We added a new ID based fetcher for [EuropePMC](https://europepmc.org/). [#13389](https://github.com/JabRef/jabref/pull/13389)
2323
- We added an initial [cite as you write](https://retorque.re/zotero-better-bibtex/citing/cayw/) endpoint. [#13187](https://github.com/JabRef/jabref/issues/13187)
24+
- We added "copy preview as markdown" feature. [#12552](https://github.com/JabRef/jabref/issues/12552)
2425
- In case no citation relation information can be fetched, we show the data providers reason. [#13549](https://github.com/JabRef/jabref/pull/13549)
2526

2627
### Changed
2728

29+
- We changed Citation Relations tab and gave tab panes more descriptive titles and tooltips. [#13619](https://github.com/JabRef/jabref/issues/13619)
2830
- We changed the name from Open AI Provider to Open AI (or API compatible). [#13585](https://github.com/JabRef/jabref/issues/13585)
2931
- We improved the citations relations caching by implementing an offline storage. [#11189](https://github.com/JabRef/jabref/issues/11189)
3032
- We added a tooltip to keywords that resemble Math Subject Classification (MSC) codes. [#12944](https://github.com/JabRef/jabref/issues/12944)
@@ -65,6 +67,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
6567

6668
### Fixed
6769

70+
- We fixed dark mode of BibTeX Source dialog in Citation Relations tab. [#13599](https://github.com/JabRef/jabref/issues/13599)
6871
- We fixed an issue where the LibreOffice integration did not support citation keys containing Unicode characters. [#13301](https://github.com/JabRef/jabref/issues/13301)
6972
- We fixed an issue where the "Search ShortScience" action did not convert LaTeX-formatted titles to Unicode.[#13418](https://github.com/JabRef/jabref/issues/13418)
7073
- We added a fallback for the "Convert to biblatex" cleanup when it failed to populate the `date` field if `year` contained a full date in ISO format (e.g., `2011-11-11`). [#11868](https://github.com/JabRef/jabref/issues/11868)
@@ -78,6 +81,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
7881
- We fixed an issue where the preview area in the "Select Style" dialog of the LibreOffice integration was too small to display full content. [#13051](https://github.com/JabRef/jabref/issues/13051)
7982
- We excluded specific fields (e.g., `comment`, `pdf`, `sortkey`) from the consistency check to reduce false positives [#13131](https://github.com/JabRef/jabref/issues/13131)
8083
- We fixed an issue where moved or renamed linked files in the file directory were not automatically relinked by the “search for unlinked files” feature. [#13264](https://github.com/JabRef/jabref/issues/13264)
84+
- We fixed an issue with proxy setup in the absence of a password. [#12412](https://github.com/JabRef/jabref/issues/12412)
8185
- We fixed an issue where the tab showing the fulltext search results was not displayed. [#12865](https://github.com/JabRef/jabref/issues/12865)
8286
- We fixed an issue showing an empty tooltip in maintable. [#11681](https://github.com/JabRef/jabref/issues/11681)
8387
- We fixed an issue displaying a warning if a file to open is not found. [#13430](https://github.com/JabRef/jabref/pull/13430)

build-logic/src/main/kotlin/org.jabref.gradle.base.dependency-rules.gradle.kts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,70 @@ extraJavaModuleInfo {
285285
module("com.github.javaparser:javaparser-symbol-solver-core", "com.github.javaparser.symbolsolver.core")
286286
module("net.sf.jopt-simple:jopt-simple", "jopt.simple")
287287

288+
// "com.github.eclipse:org.eclipse.lsp4j", "lsp4j"
289+
// - The name 'org.eclipse.lsp4j' is different than the name derived from the Jar file name 'lsp4j'; turn off 'failOnModifiedDerivedModuleNames' or explicitly allow override via 'overrideModuleName()'
290+
// - Not a module and no mapping defined: lsp4j-0.24.0.jar
291+
module("com.github.eclipse.lsp4j:org.eclipse.lsp4j", "lsp4j") {
292+
overrideModuleName()
293+
exportAllPackages()
294+
requireAllDefinedDependencies()
295+
// Note the missing "lsp4j" at the group
296+
mergeJar("com.github.eclipse:lsp4j")
297+
requires("com.google.gson")
298+
299+
}
300+
module("com.github.eclipse.lsp4j:org.eclipse.lsp4j.debug", "lsp4j.debug") {
301+
overrideModuleName()
302+
exportAllPackages()
303+
}
304+
module("com.github.eclipse.lsp4j:org.eclipse.lsp4j.generator", "lsp4j.generator") {
305+
overrideModuleName()
306+
exportAllPackages()
307+
}
308+
module("com.github.eclipse.lsp4j:org.eclipse.lsp4j.jsonrpc", "lsp4j.jsonrpc") {
309+
overrideModuleName()
310+
exportAllPackages()
311+
requires("com.google.gson")
312+
requires("java.logging")
313+
}
314+
module("com.github.eclipse.lsp4j:org.eclipse.lsp4j.jsonrpc.debug", "lsp4j.jsonrpc.debug") {
315+
overrideModuleName()
316+
exportAllPackages()
317+
}
318+
module("com.github.eclipse.lsp4j:org.eclipse.lsp4j.websocket", "lsp4j.websocket") {
319+
overrideModuleName()
320+
exportAllPackages()
321+
requireAllDefinedDependencies()
322+
}
323+
module("com.github.eclipse.lsp4j:org.eclipse.lsp4j.websocket.jakarta", "lsp4j.websocket.jakarta") {
324+
overrideModuleName()
325+
exportAllPackages()
326+
requireAllDefinedDependencies()
327+
}
328+
module("jakarta.websocket:jakarta.websocket-api", "jakarta.websocket") {
329+
overrideModuleName()
330+
exportAllPackages()
331+
}
332+
module("javax.websocket:javax.websocket-api", "javax.websocket") {
333+
overrideModuleName()
334+
exportAllPackages()
335+
}
336+
module("org.eclipse.xtend:org.eclipse.xtend", "xtend") {
337+
exportAllPackages()
338+
}
339+
module("org.eclipse.xtend:org.eclipse.xtend.lib", "xtend.lib") {
340+
overrideModuleName()
341+
exportAllPackages()
342+
}
343+
module("org.eclipse.xtend:org.eclipse.xtend.lib.macro", "xtend.lib.macro") {
344+
overrideModuleName()
345+
exportAllPackages()
346+
}
347+
module("org.eclipse.xtext:org.eclipse.xtext.xbase.lib", "xtext.xbase.lib") {
348+
overrideModuleName()
349+
exportAllPackages()
350+
}
351+
288352
module("com.tngtech.archunit:archunit-junit5-api", "com.tngtech.archunit.junit5.api") {
289353
exportAllPackages()
290354
requireAllDefinedDependencies()

build-logic/src/main/kotlin/org.jabref.gradle.feature.test.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ testlogger {
2828
showPassed = false
2929
showSkipped = false
3030

31-
showCauses = false
32-
showStackTraces = false
31+
showCauses = true
32+
showStackTraces = true
3333
}
3434

3535
configurations.testCompileOnly {

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ rewrite {
3737
requirementTracing {
3838
inputDirectories.setFrom(files("docs",
3939
"jablib/src/main/java", "jablib/src/test/java",
40+
"jabls/src/main/java", "jabls/src/test/java",
4041
"jabkit/src/main/java", "jabkit/src/test/java",
4142
"jabgui/src/main/java", "jabgui/src/test/java",
4243
"jabsrv/src/main/java", "jabsrv/src/test/java"

docs/code-howtos/git.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Git
2+
3+
## Why Semantic Merge?
4+
5+
In JabRef, we aim to minimize user interruptions when collaborating on the same `.bib` library file using Git. To achieve this, we go beyond Git’s default line-based syntactic merging and implement our own semantic merge logic that understands the structure of BibTeX entries.
6+
7+
This means:
8+
9+
* Even if Git detects conflicting lines,
10+
* JabRef is able to recognize that both sides are editing the same BibTeX entry,
11+
* And determine—at the field level—whether there is an actual semantic conflict.
12+
13+
## Merge Example
14+
15+
The following example illustrates a case where Git detects a conflict, but JabRef is able to resolve it automatically.
16+
17+
### Base Version
18+
19+
```bibtex
20+
@article{a,
21+
author = {don't know the author},
22+
doi = {xya},
23+
}
24+
25+
@article{b,
26+
author = {don't know the author},
27+
doi = {xyz},
28+
}
29+
```
30+
31+
### Bob's Side
32+
33+
Bob reorders the entries and updates the author field of entry b:
34+
35+
```bibtex
36+
@article{b,
37+
author = {author-b},
38+
doi = {xyz},
39+
}
40+
41+
@article{a,
42+
author = {don't know the author},
43+
doi = {xya},
44+
}
45+
```
46+
47+
### Alice's Side
48+
49+
Alice modifies the author field of entry a:
50+
51+
```bibtex
52+
@article{a,
53+
author = {author-a},
54+
doi = {xya},
55+
}
56+
57+
@article{b,
58+
author = {don't know the author},
59+
doi = {xyz},
60+
}
61+
```
62+
63+
### Merge Outcome
64+
65+
When Alice runs git pull, Git sees that both branches have modified overlapping lines (due to reordering and content changes) and reports a syntactic conflict.
66+
67+
However, JabRef is able to analyze the entries and determine that:
68+
69+
* Entry a was modified only by Alice.
70+
* Entry b was modified only by Bob.
71+
* There is no conflict at the field level.
72+
* The order of entries in the file does not affect BibTeX semantics.
73+
74+
Therefore, JabRef performs an automatic merge without requiring manual conflict resolution.
75+
76+
## Related Test Cases
77+
78+
The semantic conflict detection and merge resolution logic is covered by:
79+
80+
* `org.jabref.logic.git.util.SemanticMergerTest#patchDatabase`
81+
* `org.jabref.logic.git.util.SemanticConflictDetectorTest#semanticConflicts`.
82+
83+
## Conflict Scenarios
84+
85+
The following table describes when semantic merge in JabRef should consider a situation as conflict or not during a three-way merge.
86+
87+
| ID | Base | Local Change | Remote Change | Result |
88+
|------|----------------------------|------------------------------------|------------------------------------|--------|
89+
| T1 | Field present | (unchanged) | Field modified | No conflict. The local version remained unchanged, so the remote change can be safely applied. |
90+
| T2 | Field present | Field modified | (unchanged) | No conflict. The remote version did not touch the field, so the local change is preserved. |
91+
| T3 | Field present | Field changed to same value | Field changed to same value | No conflict. Although both sides changed the field, the result is identical—therefore, no conflict. |
92+
| T4 | Field present | Field changed to A | Field changed to B | Conflict. This is a true semantic conflict that requires resolution. |
93+
| T5 | Field present | Field deleted | Field modified | Conflict. One side deleted the field while the other updated it—this is contradictory. |
94+
| T6 | Field present | Field modified | Field deleted | Conflict. Similar to T5, one side deletes, the other edits—this is a conflict. |
95+
| T7 | Field present | (unchanged) | Field deleted | No conflict. Local did not modify anything, so remote deletion is accepted. |
96+
| T8 | Entry with fields A and B | Field A modified | Field B modified | No conflict. Changes are on separate fields, so they can be merged safely. |
97+
| T9 | Entry with fields A and B | Field order changed | Field order changed differently | No conflict. Field order is not semantically meaningful, so no conflict is detected. |
98+
| T10 | Entries A and B | Entry A modified | Entry B modified | No conflict. Modifications are on different entries, which are always safe to merge. |
99+
| T11 | Entry with existing fields | (unchanged) | New field added | No conflict. Remote addition can be applied without issues. |
100+
| T12 | Entry with existing fields | New field added with value A | New field added with value B | Conflict. One side added while the other side modified—there is a semantic conflict. |
101+
| T13 | Entry with existing fields | New field added | (unchanged) | No conflict. Safe to preserve the local addition. |
102+
| T14 | Entry with existing fields | New field added with value A | New field added with value A | No conflict. Even though both sides added it, the value is the same—no need for resolution. |
103+
| T15 | Entry with existing fields | New field added with value A | New field added with value B | Conflict. The same field is introduced with different values, which creates a conflict. |
104+
| T16 | (entry not present) | New entry with author A | New entry with author B | Conflict. Both sides created a new entry with the same citation key, but the fields differ. |
105+
| T17 | (entry not present) | New entry with identical fields | New entry with identical fields | No conflict. Both sides created a new entry with the same citation key and identical fields, so it can be merged safely. |

0 commit comments

Comments
 (0)