Compare commits

...

16 Commits
ueb03 ... main

Author SHA1 Message Date
47a4af1cc0
add .gitignore 2025-01-16 11:30:29 +01:00
61b60cfbaf
add .gitignore 2025-01-15 21:03:49 +01:00
0nlineSam
a2a1ede6b7 Updated jabref to hash 6af91b9 2025-01-11 12:30:11 +01:00
b157c2c194
shell.nix: switch to stable
build with JavaFX broken on unstable
2025-01-11 09:22:05 +01:00
b094db4615
shell.nix: pinned nixpkgs 2025-01-11 08:50:36 +01:00
0nlineSam
a81d9ed65e Import dicegame 2025-01-09 12:22:17 +01:00
cfecc02cad
import news example b 2024-12-07 12:09:18 +01:00
c41072785c
import news example 2024-12-07 10:30:42 +01:00
64c1d0e743
import ueb05_news_example 2024-11-24 17:07:25 +01:00
73a279f24a
shell.nix: docs 2024-11-24 14:15:11 +01:00
944138280d
shell.nix: Gradle runs JabRef 🚀 2024-11-24 13:06:49 +00:00
1c34fe3715
shell.nix: IntelliJ runs JabRef 🚀 2024-11-24 13:04:42 +00:00
154e774296
import jabref with submodules 2024-11-23 18:45:52 +01:00
c5d4d2d059
add shell.nix 2024-11-23 18:11:20 +01:00
a150ed4958
rm built files 2024-11-23 18:10:57 +01:00
Artem Semenovykh
415abbc47b import jabref 2024-11-16 11:43:42 +01:00
14091 changed files with 1487687 additions and 105 deletions

3
.gitignore vendored
View File

@ -1 +1,2 @@
.DS_Store
.DS_Store
/classes

4
.idea/sq_2024.iml generated
View File

@ -2,7 +2,9 @@
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/classes" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>

View File

@ -1,93 +0,0 @@
# Software Quality
## Getting started
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
## Add your files
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
```
cd existing_repo
git remote add origin https://gitlab.uni-marburg.de/tadjikys/software-quality.git
git branch -M main
git push -uf origin main
```
## Integrate with your tools
- [ ] [Set up project integrations](https://gitlab.uni-marburg.de/tadjikys/software-quality/-/settings/integrations)
## Collaborate with your team
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
## Test and Deploy
Use the built-in continuous integration in GitLab.
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
***
# Editing this README
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template.
## Suggestions for a good README
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
## Name
Choose a self-explaining name for your project.
## Description
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
## Badges
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
## Visuals
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
## Installation
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
## Usage
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
## Support
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
## Roadmap
If you have ideas for releases in the future, it is a good idea to list them in the README.
## Contributing
State if you are open to contributions and what your requirements are for accepting them.
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
## Authors and acknowledgment
Show your appreciation to those who have contributed to the project.
## License
For open source projects, say how it is licensed.
## Project status
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 357 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 400 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 605 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 856 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 589 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 471 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 B

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
dicegame/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.gradle/
.idea/
src/build/
target/

View File

@ -0,0 +1,4 @@
Manifest-Version: 1.0
Class-Path: .
Main-Class: WuerfelspielGUI

View File

@ -0,0 +1,5 @@
package dicegame.logic;
public interface DiceInteraction {
public int changeDiceState(int diceIndex) throws SelectionException;
}

View File

@ -0,0 +1,276 @@
package dicegame.logic;
import java.util.Random;
public class Logic implements DiceInteraction {
public static final int DICE_NUMBER = 6;
public static final int DEFAULT_PLAYER_NUMBER = 2;
public static final int DEFAULT_ROUNDS = 10;
private static final int DIE_UNFIXED = 0;
private static final int DIE_TEMP_FIXED = 1;
private static final int DIE_FIXED = 2;
private boolean gameIsRunning;
private boolean playerCanThrowDice;
private int currentPlayer;
private int roundNumber;
private int roundPoints;
private int maxRounds = DEFAULT_ROUNDS;
private int[] points = new int[2];
private String[] names = new String[2];
private int[] dicePips = new int[6];
private int[] diceFixed = new int[6];
private Random random;
public Logic(Random random) {
this.random = random;
}
public void startGame() {
this.resetGame();
this.gameIsRunning = true;
this.playerCanThrowDice = true;
this.roundNumber = 1;
this.currentPlayer = 0;
}
public String rollDice() {
if (!this.gameIsRunning) {
return "Das Spiel läuft aktuell nicht!";
} else {
if (this.isAllDiceFixed()) {
this.resetDice();
}
for(int i = 0; i < DICE_NUMBER; ++i) {
if (this.diceFixed[i] == DIE_TEMP_FIXED) {
this.diceFixed[i] = DIE_FIXED;
} else if (this.diceFixed[i] == DIE_UNFIXED) {
this.dicePips[i] = this.random.nextInt(6) + 1;
}
}
if (this.isScoringPipsAvailable()) {
this.playerCanThrowDice = true;
} else {
this.playerCanThrowDice = false;
this.roundPoints = 0;
}
return null;
}
}
public boolean isScoringPipsAvailable() {
for(int i = 0; i < DICE_NUMBER; ++i) {
if (this.diceFixed[i] != DIE_FIXED && (this.dicePips[i] == 5 || this.dicePips[i] == 1)) {
return true;
}
}
return false;
}
private boolean isAllDiceFixed() {
for(int i = 0; i < DICE_NUMBER; ++i) {
if (this.diceFixed[i] == DIE_UNFIXED) {
return false;
}
}
return true;
}
public String checkIfGameCanStart() {
if (this.gameIsRunning) {
return "Das Spiel läuft bereits!";
} else {
for(int i = 0; i < DEFAULT_PLAYER_NUMBER; ++i) {
if (this.names[i] == null || this.names[i].trim().length() < 2) {
return "Spieler " + (i + 1) + " hat noch keinen Namen!";
}
}
return null;
}
}
public void resetGame() {
this.roundNumber = 0;
this.roundPoints = 0;
this.resetDice();
this.resetPoints();
}
public void finishRound() {
this.resetDice();
int[] var10000 = this.points;
int var10001 = this.currentPlayer;
var10000[var10001] += this.roundPoints;
this.roundPoints = 0;
this.currentPlayer = ++this.currentPlayer % DEFAULT_PLAYER_NUMBER;
if (this.currentPlayer == 0) {
if (this.roundNumber == this.maxRounds) {
this.gameIsRunning = false;
} else {
++this.roundNumber;
}
}
}
private void resetDice() {
for(int i = 0; i < DICE_NUMBER; ++i) {
this.diceFixed[i] = DIE_UNFIXED;
}
}
private void resetPoints() {
for(int i = 0; i < DEFAULT_PLAYER_NUMBER; ++i) {
this.points[i] = 0;
}
}
public int getRoundNumber() {
return this.roundNumber;
}
public int getRoundPoints() {
return this.roundPoints;
}
public boolean isDieFixed(int dieIndex) {
return this.diceFixed[dieIndex] != DIE_UNFIXED;
}
public boolean isAtLeastOneDieFixedInCurrentThrow() {
for(int i = 0; i < DICE_NUMBER; ++i) {
if (this.diceFixed[i] == DIE_TEMP_FIXED) {
return true;
}
}
return false;
}
private int countTempFixedByPips(int pips) {
int count = 0;
for(int i = 0; i < DICE_NUMBER; ++i) {
if (this.diceFixed[i] == DIE_TEMP_FIXED && this.dicePips[i] == pips) {
++count;
}
}
return count;
}
public int getDiePips(int dieIndex) {
return this.dicePips[dieIndex];
}
public int getMaxRounds() {
return this.maxRounds;
}
public String setMaxRounds(int maxRounds) {
if (this.gameIsRunning) {
return "Rundenzahl kann nicht während eines Spiels verändert werden!";
} else {
this.maxRounds = maxRounds;
return null;
}
}
public int getPoints(int playerIndex) {
return this.points[playerIndex];
}
public String getName(int playerIndex) {
return this.names[playerIndex];
}
public String setName(int playerIndex, String name) {
if (this.gameIsRunning) {
return "Ein Spielername kann nicht während eines Spiels verändert werden!";
} else {
this.names[playerIndex] = name;
return null;
}
}
public boolean isPlayerCanThrowDice() {
return this.playerCanThrowDice;
}
public boolean isGameIsRunning() {
return this.gameIsRunning;
}
public int getCurrentPlayer() {
return this.currentPlayer;
}
@Override
public int changeDiceState(int diceIndex) throws SelectionException {
if (this.diceFixed[diceIndex] == DIE_UNFIXED) {
setDieFixed(diceIndex);
} else {
setDieUnfixed(diceIndex);
}
return roundPoints;
}
private void setDieFixed(int dieIndex) throws SelectionException {
int c;
if (this.dicePips[dieIndex] == 1) {
c = this.countTempFixedByPips(1);
if (c != 2 && c != 5) {
this.roundPoints += 100;
} else {
this.roundPoints -= 200;
this.roundPoints += 1000;
}
this.diceFixed[dieIndex] = DIE_TEMP_FIXED;
} else if (this.dicePips[dieIndex] == 5) {
c = this.countTempFixedByPips(5);
if (c != 2 && c != 5) {
this.roundPoints += 50;
} else {
this.roundPoints -= 100;
this.roundPoints += 500;
}
this.diceFixed[dieIndex] = DIE_TEMP_FIXED;
} else {
throw new SelectionException("Es können nur 1'en und 5'en fixiert werden!");
}
}
private void setDieUnfixed(int dieIndex) throws SelectionException {
int c;
if (this.dicePips[dieIndex] == 1) {
c = this.countTempFixedByPips(1);
if (c != 3 && c != 6) {
this.roundPoints -= 100;
} else {
this.roundPoints -= 1000;
this.roundPoints += 200;
}
this.diceFixed[dieIndex] = DIE_UNFIXED;
} else if (this.dicePips[dieIndex] == 5) {
c = this.countTempFixedByPips(5);
if (c != 3 && c != 6) {
this.roundPoints -= 50;
} else {
this.roundPoints -= 500;
this.roundPoints += 100;
}
this.diceFixed[dieIndex] = DIE_UNFIXED;
}
}
}

View File

@ -0,0 +1,7 @@
package dicegame.logic;
public class SelectionException extends Exception {
SelectionException(String msg) {
super(msg);
}
}

View File

@ -0,0 +1,608 @@
package dicegame.view;
import dicegame.logic.SelectionException;
import dicegame.logic.Logic;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
public final class GUI extends JFrame implements ActionListener {
private final Logic logic;
private static final long serialVersionUID = 1L;
private JPanel jContentPane = null;
private JPanel panelHead = null;
private JPanel panelMain = null;
private JTextField textfieldS1Name = null;
private JLabel labelS1Name = null;
private JLabel labelS2Name = null;
private JTextField textfieldS2Name = null;
private JPanel panelSpieler1 = null;
private JPanel panelSpieler2 = null;
private JLabel labelS1Points = null;
private JLabel labelS1PointsValue = null;
private JLabel labelS2Points = null;
private JLabel labelS2PointsValue = null;
private JPanel panelGoButton = null;
private JButton buttonGo = null;
private JPanel panelRound = null;
private JLabel labelRound = null;
private JLabel labelRoundValue = null;
private JPanel panelDice = null;
private JToggleButton toggleDie1 = null;
private JToggleButton toggleDie2 = null;
private JToggleButton toggleDie3 = null;
private JToggleButton toggleDie4 = null;
private JToggleButton toggleDie5 = null;
private JToggleButton toggleDie6 = null;
private JPanel panelActions = null;
private JPanel panelRoundPoints = null;
private JLabel labelRoundPoints = null;
private JLabel labelRoundPointsValue = null;
private JPanel panelActionsButtons = null;
private JButton buttonRoll = null;
private JButton buttonReady = null;
private JPanel panelDiceActions = null;
private JPanel panelStatus = null;
private JLabel labelStatus = null;
private JPanel getPanelHead() {
if (this.panelHead == null) {
BorderLayout borderLayout3 = new BorderLayout();
borderLayout3.setHgap(3);
borderLayout3.setVgap(3);
this.labelS2Name = new JLabel();
this.labelS2Name.setText("Spieler 2 :");
this.labelS2Name.setFont(new Font("Dialog", 0, 12));
this.labelS2Name.setToolTipText("");
this.labelS1Name = new JLabel();
this.labelS1Name.setText("Spieler 1 :");
this.labelS1Name.setFont(new Font("Dialog", 0, 12));
this.panelHead = new JPanel();
this.panelHead.setLayout(borderLayout3);
this.panelHead.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0));
this.panelHead.add(this.getPanelSpieler1(), "West");
this.panelHead.add(this.getPanelSpieler2(), "East");
this.panelHead.add(this.getPanelGoButton(), "South");
}
return this.panelHead;
}
private JPanel getPanelMain() {
if (this.panelMain == null) {
BorderLayout borderLayout1 = new BorderLayout();
borderLayout1.setVgap(5);
GridLayout gridLayout3 = new GridLayout();
gridLayout3.setRows(3);
gridLayout3.setColumns(1);
this.panelMain = new JPanel();
this.panelMain.setEnabled(true);
this.panelMain.setBorder(BorderFactory.createEtchedBorder(0));
this.panelMain.setLayout(borderLayout1);
this.panelMain.add(this.getPanelRound(), "North");
this.panelMain.add(this.getPanelDiceActions(), "Center");
}
return this.panelMain;
}
private JTextField getTextfieldS1Name() {
if (this.textfieldS1Name == null) {
this.textfieldS1Name = new JTextField();
this.textfieldS1Name.setColumns(10);
this.textfieldS1Name.setName("");
this.textfieldS1Name.setToolTipText("Name des ersten Spielers, bestehend aus mindestens 2 Zeichen");
this.textfieldS1Name.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
GUI.this.textfieldS2Name.grabFocus();
}
});
this.textfieldS1Name.addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent e) {
GUI.this.logic.setName(0, GUI.this.textfieldS1Name.getText());
String s = GUI.this.logic.checkIfGameCanStart();
if (s != null) {
GUI.this.labelStatus.setText(s);
GUI.this.buttonGo.setEnabled(false);
} else {
GUI.this.buttonGo.setEnabled(true);
GUI.this.labelStatus.setText(" ");
}
}
});
}
return this.textfieldS1Name;
}
private JTextField getTextfieldS2Name() {
if (this.textfieldS2Name == null) {
this.textfieldS2Name = new JTextField();
this.textfieldS2Name.setColumns(10);
this.textfieldS2Name.setName("");
this.textfieldS2Name.setToolTipText("Name des zweiten Spielers, bestehend aus mindestens 2 Zeichen");
this.textfieldS2Name.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
GUI.this.buttonGo.grabFocus();
}
});
this.textfieldS2Name.addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent e) {
GUI.this.logic.setName(1, GUI.this.textfieldS2Name.getText());
String s = GUI.this.logic.checkIfGameCanStart();
if (s != null) {
GUI.this.labelStatus.setText(s);
GUI.this.buttonGo.setEnabled(false);
} else {
GUI.this.buttonGo.setEnabled(true);
GUI.this.labelStatus.setText(" ");
}
}
});
}
return this.textfieldS2Name;
}
private JPanel getPanelSpieler1() {
if (this.panelSpieler1 == null) {
GridLayout gridLayout21 = new GridLayout();
gridLayout21.setRows(2);
this.labelS1PointsValue = new JLabel();
this.labelS1PointsValue.setText("0");
this.labelS1PointsValue.setFont(new Font("Dialog", 1, 14));
GridLayout gridLayout1 = new GridLayout();
gridLayout1.setRows(2);
gridLayout1.setColumns(2);
this.labelS1Points = new JLabel();
this.labelS1Points.setText("Punkte :");
this.labelS1Points.setFont(new Font("Dialog", 0, 12));
GridLayout gridLayout = new GridLayout();
gridLayout.setRows(2);
gridLayout.setColumns(2);
this.panelSpieler1 = new JPanel();
this.panelSpieler1.setLayout(gridLayout21);
this.panelSpieler1.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
this.panelSpieler1.add(this.labelS1Name, (Object)null);
this.panelSpieler1.add(this.getTextfieldS1Name(), (Object)null);
this.panelSpieler1.add(this.labelS1Points, (Object)null);
this.panelSpieler1.add(this.labelS1PointsValue, (Object)null);
}
return this.panelSpieler1;
}
private JPanel getPanelSpieler2() {
if (this.panelSpieler2 == null) {
this.labelS2PointsValue = new JLabel();
this.labelS2PointsValue.setText("0");
this.labelS2PointsValue.setFont(new Font("Dialog", 1, 14));
this.labelS2Points = new JLabel();
this.labelS2Points.setText("Punkte :");
this.labelS2Points.setFont(new Font("Dialog", 0, 12));
GridLayout gridLayout2 = new GridLayout();
gridLayout2.setRows(2);
gridLayout2.setColumns(2);
this.panelSpieler2 = new JPanel();
this.panelSpieler2.setLayout(gridLayout2);
this.panelSpieler2.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
this.panelSpieler2.add(this.labelS2Name, (Object)null);
this.panelSpieler2.add(this.getTextfieldS2Name(), (Object)null);
this.panelSpieler2.add(this.labelS2Points, (Object)null);
this.panelSpieler2.add(this.labelS2PointsValue, (Object)null);
}
return this.panelSpieler2;
}
private JPanel getPanelGoButton() {
if (this.panelGoButton == null) {
this.panelGoButton = new JPanel();
this.panelGoButton.setLayout(new GridBagLayout());
this.panelGoButton.setEnabled(true);
this.panelGoButton.add(this.getButtonGo(), new GridBagConstraints());
}
return this.panelGoButton;
}
private JButton getButtonGo() {
if (this.buttonGo == null) {
this.buttonGo = new JButton();
this.buttonGo.setName("");
this.buttonGo.setEnabled(false);
this.buttonGo.setText(" Spiel starten ");
this.buttonGo.addActionListener(this);
}
return this.buttonGo;
}
private JPanel getPanelRound() {
if (this.panelRound == null) {
this.labelRoundValue = new JLabel();
this.labelRoundValue.setText("0");
this.labelRoundValue.setFont(new Font("Dialog", 0, 12));
this.labelRound = new JLabel();
this.labelRound.setText("Runde ");
this.labelRound.setFont(new Font("Dialog", 0, 12));
this.panelRound = new JPanel();
this.panelRound.setLayout(new FlowLayout());
this.panelRound.add(this.labelRound, (Object)null);
this.panelRound.add(this.labelRoundValue, (Object)null);
}
return this.panelRound;
}
private JPanel getPanelDice() {
if (this.panelDice == null) {
GridLayout gridLayout5 = new GridLayout();
gridLayout5.setRows(1);
gridLayout5.setHgap(20);
gridLayout5.setVgap(1);
gridLayout5.setColumns(6);
this.panelDice = new JPanel();
this.panelDice.setPreferredSize(new Dimension(346, 26));
this.panelDice.setBorder(BorderFactory.createEmptyBorder(5, 3, 5, 0));
this.panelDice.setLayout(gridLayout5);
this.panelDice.add(this.getToggleDie1(), (Object)null);
this.panelDice.add(this.getToggleDie2(), (Object)null);
this.panelDice.add(this.getToggleDie3(), (Object)null);
this.panelDice.add(this.getToggleDie4(), (Object)null);
this.panelDice.add(this.getToggleDie5(), (Object)null);
this.panelDice.add(this.getToggleDie6(), (Object)null);
}
return this.panelDice;
}
private JToggleButton getToggleDie1() {
if (this.toggleDie1 == null) {
this.toggleDie1 = new JToggleButton();
this.toggleDie1.setText("1");
this.toggleDie1.setEnabled(false);
this.toggleDie1.addActionListener(this);
}
return this.toggleDie1;
}
private JToggleButton getToggleDie2() {
if (this.toggleDie2 == null) {
this.toggleDie2 = new JToggleButton();
this.toggleDie2.setText("2");
this.toggleDie2.setEnabled(false);
this.toggleDie2.addActionListener(this);
}
return this.toggleDie2;
}
private JToggleButton getToggleDie3() {
if (this.toggleDie3 == null) {
this.toggleDie3 = new JToggleButton();
this.toggleDie3.setText("3");
this.toggleDie3.setEnabled(false);
this.toggleDie3.addActionListener(this);
}
return this.toggleDie3;
}
private JToggleButton getToggleDie4() {
if (this.toggleDie4 == null) {
this.toggleDie4 = new JToggleButton();
this.toggleDie4.setText("4");
this.toggleDie4.setEnabled(false);
this.toggleDie4.addActionListener(this);
}
return this.toggleDie4;
}
private JToggleButton getToggleDie5() {
if (this.toggleDie5 == null) {
this.toggleDie5 = new JToggleButton();
this.toggleDie5.setText("5");
this.toggleDie5.setEnabled(false);
this.toggleDie5.addActionListener(this);
}
return this.toggleDie5;
}
private JToggleButton getToggleDie6() {
if (this.toggleDie6 == null) {
this.toggleDie6 = new JToggleButton();
this.toggleDie6.setText("6");
this.toggleDie6.setEnabled(false);
this.toggleDie6.addActionListener(this);
}
return this.toggleDie6;
}
private JPanel getPanelActions() {
if (this.panelActions == null) {
BorderLayout borderLayout2 = new BorderLayout();
borderLayout2.setVgap(0);
borderLayout2.setHgap(0);
this.panelActions = new JPanel();
this.panelActions.setLayout(borderLayout2);
this.panelActions.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
this.panelActions.add(this.getPanelRoundPoints(), "West");
this.panelActions.add(this.getPanelActionsButtons(), "East");
}
return this.panelActions;
}
private JPanel getPanelRoundPoints() {
if (this.panelRoundPoints == null) {
this.labelRoundPointsValue = new JLabel();
this.labelRoundPointsValue.setText("0");
this.labelRoundPoints = new JLabel();
this.labelRoundPoints.setText("Punkte des aktuellen Zuges : ");
this.labelRoundPoints.setFont(new Font("Dialog", 0, 12));
this.panelRoundPoints = new JPanel();
this.panelRoundPoints.setLayout(new GridBagLayout());
this.panelRoundPoints.add(this.labelRoundPoints, new GridBagConstraints());
this.panelRoundPoints.add(this.labelRoundPointsValue, new GridBagConstraints());
}
return this.panelRoundPoints;
}
private JPanel getPanelActionsButtons() {
if (this.panelActionsButtons == null) {
GridLayout gridLayout6 = new GridLayout();
gridLayout6.setRows(2);
gridLayout6.setHgap(0);
gridLayout6.setVgap(6);
gridLayout6.setColumns(1);
this.panelActionsButtons = new JPanel();
this.panelActionsButtons.setLayout(gridLayout6);
this.panelActionsButtons.add(this.getButtonRoll(), (Object)null);
this.panelActionsButtons.add(this.getButtonReady(), (Object)null);
}
return this.panelActionsButtons;
}
private JButton getButtonRoll() {
if (this.buttonRoll == null) {
this.buttonRoll = new JButton();
this.buttonRoll.setText("Würfeln");
this.buttonRoll.setEnabled(false);
this.buttonRoll.addActionListener(this);
}
return this.buttonRoll;
}
private JButton getButtonReady() {
if (this.buttonReady == null) {
this.buttonReady = new JButton();
this.buttonReady.setText("Zug beenden");
this.buttonReady.setEnabled(false);
this.buttonReady.addActionListener(this);
}
return this.buttonReady;
}
private JPanel getPanelDiceActions() {
if (this.panelDiceActions == null) {
BorderLayout borderLayout = new BorderLayout();
borderLayout.setHgap(5);
borderLayout.setVgap(5);
this.panelDiceActions = new JPanel();
this.panelDiceActions.setLayout(borderLayout);
this.panelDiceActions.add(this.getPanelDice(), "Center");
this.panelDiceActions.add(this.getPanelActions(), "South");
}
return this.panelDiceActions;
}
private JPanel getPanelStatus() {
if (this.panelStatus == null) {
this.labelStatus = new JLabel();
this.labelStatus.setText(" ");
this.labelStatus.setToolTipText("");
this.labelStatus.setFont(new Font("Arial", 0, 12));
this.panelStatus = new JPanel();
this.panelStatus.setLayout(new BorderLayout());
this.panelStatus.setBorder(BorderFactory.createBevelBorder(1));
this.panelStatus.add(this.labelStatus, "North");
}
return this.panelStatus;
}
public GUI() {
this.initialize();
this.logic = new Logic(new Random());
this.logic.resetGame();
}
private void initialize() {
this.setSize(478, 311);
this.setResizable(false);
this.setDefaultCloseOperation(3);
this.setName("mainFrame");
this.setContentPane(this.getJContentPane());
this.setTitle("Dings");
}
private JPanel getJContentPane() {
if (this.jContentPane == null) {
BorderLayout borderLayout4 = new BorderLayout();
borderLayout4.setHgap(3);
borderLayout4.setVgap(2);
this.jContentPane = new JPanel();
this.jContentPane.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2));
this.jContentPane.setLayout(borderLayout4);
this.jContentPane.add(this.getPanelHead(), "North");
this.jContentPane.add(this.getPanelMain(), "Center");
this.jContentPane.add(this.getPanelStatus(), "South");
}
return this.jContentPane;
}
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source != this.textfieldS1Name && source != this.textfieldS2Name) {
if (source == this.buttonGo) {
this.logic.startGame();
this.labelStatus.setText(" ");
this.buttonGo.setEnabled(false);
this.textfieldS1Name.setEditable(false);
this.textfieldS2Name.setEditable(false);
this.buttonReady.setEnabled(true);
this.labelS2PointsValue.setText(String.valueOf(this.logic.getPoints(1)));
this.labelS1PointsValue.setText(String.valueOf(this.logic.getPoints(0)));
this.syncRoundInfoToGui();
this.logic.rollDice();
this.syncLogicDiceToGui();
this.toggleDie1.setEnabled(true);
this.toggleDie2.setEnabled(true);
this.toggleDie3.setEnabled(true);
this.toggleDie4.setEnabled(true);
this.toggleDie5.setEnabled(true);
this.toggleDie6.setEnabled(true);
} else if (source == this.buttonReady) {
this.logic.finishRound();
this.syncRoundInfoToGui();
if (this.logic.isGameIsRunning()) {
this.logic.rollDice();
this.syncLogicDiceToGui();
}
} else if (source == this.buttonRoll) {
if (!this.logic.isAtLeastOneDieFixedInCurrentThrow()) {
this.labelStatus.setText("Wenigstens ein Würfel muss fixiert sein.");
} else {
String s = this.logic.rollDice();
if (s != null) {
this.labelStatus.setText(s);
} else {
this.syncLogicDiceToGui();
}
}
} else if (source == this.toggleDie1) {
this.toggleDie(this.toggleDie1, 0);
} else if (source == this.toggleDie2) {
this.toggleDie(this.toggleDie2, 1);
} else if (source == this.toggleDie3) {
this.toggleDie(this.toggleDie3, 2);
} else if (source == this.toggleDie4) {
this.toggleDie(this.toggleDie4, 3);
} else if (source == this.toggleDie5) {
this.toggleDie(this.toggleDie5, 4);
} else if (source == this.toggleDie6) {
this.toggleDie(this.toggleDie6, 5);
}
}
}
private void toggleDie(JToggleButton die, int dieIndex) {
String result = null;
this.labelStatus.setText(" ");
try {
int resultingPoints = this.logic.changeDiceState(dieIndex);
this.labelRoundPointsValue.setText(String.valueOf(resultingPoints));
} catch (SelectionException e) {
die.setSelected(!die.isSelected());
this.labelStatus.setText(e.getMessage());
}
}
private void syncRoundInfoToGui() {
if (this.logic.isGameIsRunning()) {
this.labelRoundValue.setText(String.valueOf(this.logic.getRoundNumber()));
this.labelRoundPointsValue.setText(String.valueOf(this.logic.getRoundPoints()));
if (this.logic.getCurrentPlayer() == 0) {
this.labelS1Name.setForeground(Color.GREEN);
this.labelS2Name.setForeground(Color.BLACK);
this.labelS2PointsValue.setText(String.valueOf(this.logic.getPoints(1)));
} else {
this.labelS2Name.setForeground(Color.GREEN);
this.labelS1Name.setForeground(Color.BLACK);
this.labelS1PointsValue.setText(String.valueOf(this.logic.getPoints(0)));
}
} else {
this.labelS2Name.setForeground(Color.BLACK);
this.labelS1Name.setForeground(Color.BLACK);
this.textfieldS1Name.setEditable(true);
this.textfieldS2Name.setEditable(true);
this.labelStatus.setText("Das Spiel ist beendet!");
this.buttonReady.setEnabled(false);
this.buttonRoll.setEnabled(false);
this.buttonGo.setEnabled(true);
this.toggleDie1.setEnabled(false);
this.toggleDie2.setEnabled(false);
this.toggleDie3.setEnabled(false);
this.toggleDie4.setEnabled(false);
this.toggleDie5.setEnabled(false);
this.toggleDie6.setEnabled(false);
}
}
private void syncLogicDiceToGui() {
this.syncLogicDieToGui(this.toggleDie1, 0);
this.syncLogicDieToGui(this.toggleDie2, 1);
this.syncLogicDieToGui(this.toggleDie3, 2);
this.syncLogicDieToGui(this.toggleDie4, 3);
this.syncLogicDieToGui(this.toggleDie5, 4);
this.syncLogicDieToGui(this.toggleDie6, 5);
this.buttonRoll.setEnabled(this.logic.isPlayerCanThrowDice());
this.labelRoundPointsValue.setText(String.valueOf(this.logic.getRoundPoints()));
}
private void syncLogicDieToGui(JToggleButton die, int dieIndex) {
die.setText(String.valueOf(this.logic.getDiePips(dieIndex)));
if (this.logic.isDieFixed(dieIndex)) {
die.setForeground(Color.BLUE);
die.setSelected(true);
} else {
die.setForeground(Color.BLACK);
die.setSelected(false);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
GUI thisClass = new GUI();
thisClass.setDefaultCloseOperation(3);
thisClass.setVisible(true);
}
});
}
}

View File

@ -0,0 +1,39 @@
{
"name": "Java",
"image": "mcr.microsoft.com/devcontainers/base:debian",
"customizations": {
"vscode": {
"extensions": [
"vscjava.vscode-java-pack",
"vscjava.vscode-gradle",
"shengchen.vscode-checkstyle",
"DavidAnson.vscode-markdownlint"
]
}
},
// Source code generation needs to be done before hand-over to VS Code.
// Otherwise, the Java extension will go mad.
"onCreateCommand": "./gradlew testClasses --console=plain --no-daemon",
// Forward the vncPort and noVNC port.
// They are provided by desktop-lite:
// https://github.com/devcontainers/features/tree/main/src/desktop-lite#options
"forwardPorts": [5901, 6080],
// Need to connect as root otherwise we run into issues with gradle.
// default option is "vscode". More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "root",
"features": {
// Adds a lightweight desktop that can be accessed using a VNC viewer or the web
"ghcr.io/devcontainers/features/desktop-lite:1": {},
// Install java.
// See https://github.com/devcontainers/features/tree/main/src/java#options for details.
"ghcr.io/devcontainers/features/java:1": {
"version": "21.0.1-librca",
"installGradle": false,
"jdkDistro": "librca"
}
}
}

13
jabref/.editorconfig Normal file
View File

@ -0,0 +1,13 @@
root = true
[*]
charset = utf-8
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.{fxml,java,properties,sh}]
end_of_line = lf
[*.md]
trim_trailing_whitespace = false

View File

@ -0,0 +1,28 @@
# Automatic code reformatting
c5bcad738fe6e8dfcb62442a426c2778241515a1
# net.sf.jabref -> org.jabref
b2ad6eb279f5def38fa21be12cb5dd4545c1ba1a
dd385f4ad6dc9251bfdb1c0b75ded402f680b32a
a6e80311c6376c973b5860658f6e4ace7a3fd1f4
648a4703e80ac0dbe1ff044f354bc0e332e4064d
ac08c6a2c55e1600bf5072c0ea2e6aac920b915d
ec863166cf4f38a1a6bcc80a607fd33299b815aa
8c61577e4377746fc064db2a136bb68968cd4055
0ef3228f0c1334ff203d4ea5e698e3ad88cb7089
ce939b4ef19ca856e7ecac08275cf1ca764207b6
7f1a8069d03737c202bcb7ce352b3755c6a36f5f
dbd0cfbc8177ada414e89da038cd014657d48ed3
bc7ea00c8cc3ec9ec8b1a799b0dd96513bc51404
9a5cff44aa1e0d4b737296a30b97f7f384c8b885
bf81b595a77f0f7f254872be6f05a063c44528d8
277b40c9e79e0158d272de33e24fa7fc06af91bf
662dd326d212ecfd336a00214e969145ec501c5a
33f040cfbb16111ada117f858e98d606a6bee4fd
29fe730f64eeb62ff9de10fcb460a63297e24be6
# This commit should not exist
185d7345946c29a2a4e2726c912be0c4db4810b9
# Resulted in this problematic merge commits
7e1645978b3028df5e65af19f0f819ddfd0f24aa
a31f396765492ac12eaab228e33eb9d22487403b

14
jabref/.gitattributes vendored Normal file
View File

@ -0,0 +1,14 @@
# unix line endings at unix files
gradlew text eol=lf
*.sh text eol=lf
# windows line endings at windows files
*.bat text eol=crlf
# ensure that line endings of *.bib, *.fxml, *.java, *.properties are normalized to LF
*.bib text eol=lf
*.fxml text eol=lf
*.java text eol=lf
*.properties text eol=lf
CHANGELOG.md merge=union

12
jabref/.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: JabRef
patreon: # Patreon user account
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: JabRef
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: https://github.com/JabRef/jabref/wiki/Donations # Replace with a single custom sponsorship URL

View File

@ -0,0 +1,81 @@
name: "Bug report"
description: Create a report to help us improve
body:
- type: markdown
attributes:
value:
"Please use the GitHub issue tracker only for bug reports.
Feature requests, questions and general feedback is now handled at http://discourse.jabref.org.
Please make sure you looked into our [list of existing issues](https://github.com/jabref/JabRef/issues) before creating a new issue to avoid duplicates!"
- type: dropdown
attributes:
label: JabRef version
options:
- "5.15 (latest release)"
- Latest development branch build (please note build date below)
- Other (please describe below)
description: The version as shown in the about dialog.
validations:
required: true
- type: dropdown
attributes:
label: Operating system
multiple: false
options:
- Windows
- GNU / Linux
- macOS
- Other (please describe below)
validations:
required: true
- type: input
attributes:
label: Details on version and operating system
description: OS Version, distribution, desktop environment, older JabRef version etc.
placeholder: Ubuntu 21.04 with Plasma 5.22 / Windows 10 21H1 / macOS 10.14
validations:
required: false
- type: checkboxes
attributes:
label: Checked with the latest development build (copy version output from About dialog)
description: |
Please always test if the bug is still reproducible in the latest development version. We are constantly improving JabRef and some bugs may already be fixed. If you already use a development version, ensure that you use the latest one.
You can download the latest development build at: https://builds.jabref.org/main/ . **Please make a backup of your library before you try out this version.**
options:
- label: I made a backup of my libraries before testing the latest development version.
required: true
- label: I have tested the latest development version and the problem persists
required: true
- type: textarea
attributes:
label: Steps to reproduce the behaviour
description: A clear and concise description of what the bug is and how to make it occur.
value: |
1. ...
2. ...
3. ...
validations:
required: true
- type: textarea
attributes:
label: Appendix
description: "If applicable: An excerpt of the bibliography file, a screenshot, an excerpt of log (available in the error console) etc."
value: |
...
<details>
<summary>Log File</summary>
```
Paste an excerpt of your log file here
```
</details>
validations:
required: false

View File

@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Help
url: https://discourse.jabref.org/c/help/
about: Questions and requests for help are handled at https://discourse.jabref.org
- name: Feature requests
url: https://discourse.jabref.org/c/features/
about: If you are missing an important feature? Let us know!

View File

@ -0,0 +1,23 @@
---
name: Suggestion for improvement
about: Suggest an enhancement
title: ''
labels: ''
assignees: ''
---
<!--
Please use the GitHub issue tracker only for bug reports and smaller suggestions for improvements.
Requests for completely new features, questions and general feedback is now handled at http://discourse.jabref.org.
Thanks!
-->
**Is your suggestion for improvement related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Additional context**
Add any other context or screenshots about the feature request here.

21
jabref/.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,21 @@
<!--
Describe the changes you have made here: what, why, ...
Link the issue that will be closed, e.g., "Closes #333".
If your PR closes a koppor issue, link it using its URL, e.g., "Closes https://github.com/koppor/jabref/issues/47".
"Closes" is a keyword GitHub uses to link PRs with issues; do not change it.
Don't reference an issue in the PR title because GitHub does not support auto-linking there.
-->
### Mandatory checks
<!--
- Go through the list below. Please don't remove any items.
- [x] done; [ ] not done / not applicable
-->
- [ ] Change in `CHANGELOG.md` described in a way that is understandable for the average user (if applicable)
- [ ] Tests created for changes (if applicable)
- [ ] Manually tested changed features in running JabRef (always required)
- [ ] Screenshots added in PR description (for UI changes)
- [ ] [Checked developer's documentation](https://devdocs.jabref.org/): Is the information available and up to date? If not, I outlined it in this pull request.
- [ ] [Checked documentation](https://docs.jabref.org/): Is the information available and up to date? If not, I created an issue at <https://github.com/JabRef/user-documentation/issues> or, even better, I submitted a pull request to the documentation repository.

31
jabref/.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,31 @@
version: 2
updates:
- package-ecosystem: gradle
directory: "/"
schedule:
interval: weekly
labels:
- "dependencies"
ignore:
- dependency-name: com.microsoft.azure:applicationinsights-core
versions:
- ">= 2.5.a" # Blocked by https://github.com/microsoft/ApplicationInsights-Java/issues/1155
- dependency-name: com.microsoft.azure:applicationinsights-logging-log4j2
versions:
- ">= 2.5.a" # Blocked by https://github.com/microsoft/ApplicationInsights-Java/issues/1155
- package-ecosystem: gradle
directory: "buildSrc/"
schedule:
interval: weekly
labels:
- "dependencies"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: weekly
labels:
- "dependencies"
- package-ecosystem: "gitsubmodule"
directory: "/"
schedule:
interval: weekly

36
jabref/.github/ghprcomment.yml vendored Normal file
View File

@ -0,0 +1,36 @@
- jobName: Checkstyle
message: |
Your code currently does not meet [JabRef's code guidelines](https://devdocs.jabref.org/getting-into-the-code/guidelines-for-setting-up-a-local-workspace/intellij-13-code-style.html).
We use [Checkstyle](https://checkstyle.sourceforge.io/) to identify issues.
The tool reviewdog already placed comments on GitHub to indicate the places. See the tab "Files" in you PR.
Please carefully follow [the setup guide for the codestyle](https://devdocs.jabref.org/getting-into-the-code/guidelines-for-setting-up-a-local-workspace/intellij-13-code-style.html).
Afterwards, please [run checkstyle locally](https://devdocs.jabref.org/getting-into-the-code/guidelines-for-setting-up-a-local-workspace/intellij-13-code-style.html#run-checkstyle) and fix the issues.
You can check review dog's comments at the tab "Files changed" of your pull request.
- jobName: OpenRewrite
message: |
Your code currently does not meet JabRef's code guidelines.
We use [OpenRewrite](https://docs.openrewrite.org/) to ensure "modern" Java coding practices.
The issues found can be **automatically fixed**.
Please execute the gradle task *`rewriteRun`*, check the results, commit, and push.
You can check the detailed error output by navigating to your pull request, selecting the tab "Checks", section "Tests" (on the left), subsection "OpenRewrite".
- jobName: Modernizer
message: |
Your code currently does not meet JabRef's code guidelines.
We use [Gradle Modernizer Plugin](https://github.com/andygoossens/gradle-modernizer-plugin#gradle-modernizer-plugin) to ensure "modern" Java coding practices.
Please fix the detected errors, commit, and push.
You can check the detailed error output by navigating to your pull request, selecting the tab "Checks", section "Tests" (on the left), subsection "Modernizer".
- jobName: Markdown
message: |
You modified Markdown (`*.md`) files and did not meet JabRef's rules for consistently formatted Markdown files.
To ensure consistent styling, we have [markdown-lint](https://github.com/DavidAnson/markdownlint) in place.
[Markdown lint's rules](https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#rules) help to keep our Markdown files consistent within this repository and consistent with the Markdown files outside here.
You can check the detailed error output by navigating to your pull request, selecting the tab "Checks", section "Tests" (on the left), subsection "Markdown".
- jobName: CHANGELOG.md
message: |
While the PR was in progress, a new version of JabRef has been released.
You have to merge `upstream/main` and move your entry in `CHANGELOG.md` up to the section `## [Unreleased]`.

View File

@ -0,0 +1,31 @@
name: Add greeting to issues for first time contributors
on:
issues:
types:
- labeled
pull_request_target:
types:
- labeled
jobs:
GreetingFirstTimeCodeContribution:
if: ${{ github.event.label.name == 'FirstTimeCodeContribution' }}
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: GreetingFirstTimeCodeContribution
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.issue.number || github.event.pull_request.number }}
body: |
Welcome to the vibrant world of open-source development with JabRef!
Newcomers, we're excited to have you on board. Start by exploring our [Contributing](https://github.com/JabRef/jabref/blob/main/CONTRIBUTING.md) guidelines, and don't forget to check out our [workspace setup guidelines](https://devdocs.jabref.org/getting-into-the-code/guidelines-for-setting-up-a-local-workspace) to get started smoothly.
In case you encounter failing tests during development, please check our [developer FAQs](https://devdocs.jabref.org/code-howtos/faq.html)!
Having any questions or issues? Feel free to ask here on GitHub. Need help setting up your local workspace? Join the conversation on [JabRef's Gitter chat](https://gitter.im/JabRef/jabref). And don't hesitate to open a (draft) pull request early on to show the direction it is heading towards. This way, you will receive valuable feedback.
Happy coding! 🚀

View File

@ -0,0 +1,44 @@
name: Add to Project on Label
on:
issues:
types: [labeled]
permissions:
issues: write
jobs:
add-to-project:
runs-on: ubuntu-latest
steps:
- name: "good first issue"
if: "${{ github.event.label.name == 'good first issue' }}"
env:
GH_TOKEN: ${{ secrets.GH_TOKEN_PROJECT_ITEM_ADD }}
run: |
ISSUE_URL=$(jq --raw-output .issue.html_url "$GITHUB_EVENT_PATH")
gh project item-add 5 --owner JabRef --url $ISSUE_URL
- name: needs-refinement
if: github.event.label.name == 'needs-refinement'
env:
GH_TOKEN: ${{ secrets.GH_TOKEN_PROJECT_ITEM_ADD }}
run: |
ISSUE_URL=$(jq --raw-output .issue.html_url "$GITHUB_EVENT_PATH")
gh project item-add 15 --owner JabRef --url $ISSUE_URL
- name: "status: freeze"
if: "${{ github.event.label.name == 'status: freeze' }}"
env:
GH_TOKEN: ${{ secrets.GH_TOKEN_PROJECT_ITEM_ADD }}
run: |
ISSUE_URL=$(jq --raw-output .issue.html_url "$GITHUB_EVENT_PATH")
gh project item-add 9 --owner JabRef --url $ISSUE_URL
- name: ui
if: "${{ github.event.label.name == 'ui' }}"
env:
GH_DEBUG: api
GH_TOKEN: ${{ secrets.GH_TOKEN_PROJECT_ITEM_ADD }}
run: |
ISSUE_URL=$(jq --raw-output .issue.html_url "$GITHUB_EVENT_PATH")
echo $ISSUE_URL
gh project item-add 8 --owner JabRef --url $ISSUE_URL

34
jabref/.github/workflows/automerge.yml vendored Normal file
View File

@ -0,0 +1,34 @@
name: Auto Merge
on: [pull_request_target, workflow_dispatch]
permissions:
contents: write
pull-requests: write
jobs:
automerge:
runs-on: ubuntu-latest
# Run only if PR is inside JabRef's main repository and created by dependabot or by an update workflow
if: >
(github.repository == 'JabRef/jabref') &&
(github.event.pull_request.head.repo.full_name == 'JabRef/jabref') &&
(
(github.actor == 'dependabot[bot]') ||
(
startsWith(github.event.pull_request.title, '[Bot] ') ||
startsWith(github.event.pull_request.title, 'Bump ') ||
startsWith(github.event.pull_request.title, 'New Crowdin updates') ||
startsWith(github.event.pull_request.title, 'Update Gradle Wrapper from')
)
)
steps:
- name: Approve PR
run: gh pr review --approve "$PR_URL"
env:
PR_URL: ${{github.event.pull_request.html_url}}
GITHUB_TOKEN: ${{secrets.GH_TOKEN_JABREF_MACHINE_PR_APPROVE}}
- name: Merge PR
run: gh pr merge --auto --squash "$PR_URL"
env:
PR_URL: ${{github.event.pull_request.html_url}}
GITHUB_TOKEN: ${{secrets.GH_TOKEN_UPDATE_GRADLE_WRAPPER}}

View File

@ -0,0 +1,37 @@
name: Check external href links in the documentation
on:
push:
paths:
- '.github/workflows/check-links.yml'
- '.lycheeignore'
- 'lychee.toml'
- '**/*.md'
schedule:
# Run on the first of each month at 9:00 AM (See https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html#tag_20_25_07)
- cron: "0 9 1 * *"
workflow_dispatch:
concurrency:
group: "${{ github.workflow }}-${{ github.head_ref || github.ref }}"
cancel-in-progress: true
jobs:
lychee:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
show-progress: 'false'
- name: Restore lychee cache
uses: actions/cache@v4
with:
path: .lycheecache
key: cache-lychee-${{ github.sha }}
restore-keys: cache-lychee-
- name: Link Checker
id: lychee
uses: lycheeverse/lychee-action@v1.10.0
with:
fail: true
args: --accept '200,201,202,203,204,403,429,500' --max-concurrency 1 --cache --no-progress --exclude-all-private './**/*.md'

44
jabref/.github/workflows/cleanup-pr.yml vendored Normal file
View File

@ -0,0 +1,44 @@
name: Cleanup after PR
on:
pull_request:
types: [closed]
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- name: Cancel deployment run
uses: styfle/cancel-workflow-action@0.12.1
with:
ignore_sha: true
workflow_id: 9813 # workflow "Deployment"
- name: Check secrets presence
id: checksecrets
shell: bash
run: |
if [ "$BUILDJABREFPRIVATEKEY" == "" ]; then
echo "secretspresent=NO" >> $GITHUB_OUTPUT
echo "❌ Secret BUILDJABREFPRIVATEKEY not present"
else
echo "secretspresent=YES" >> $GITHUB_OUTPUT
echo "✔️ Secret BUILDJABREFPRIVATEKEY present"
fi
env:
BUILDJABREFPRIVATEKEY: ${{ secrets.buildJabRefPrivateKey }}
- name: Delete folder on builds.jabref.org
if: steps.checksecrets.outputs.secretspresent == 'YES'
uses: appleboy/ssh-action@v1.0.3
with:
script: rm -rf /var/www/builds.jabref.org/www/pull/${{ github.event.pull_request.number }} || true
host: build-upload.jabref.org
port: 9922
username: jrrsync
key: ${{ secrets.buildJabRefPrivateKey }}
- name: Update PR comment
if: steps.checksecrets.outputs.secretspresent == 'YES'
uses: thollander/actions-comment-pull-request@v2
with:
comment_tag: download-link
message: The build for this PR is no longer available. Please visit <https://builds.jabref.org/main/> for the latest build.
mode: upsert

View File

@ -0,0 +1,271 @@
name: Deployment (macOS/ARM64)
on:
push:
branches:
- main
- main-release
paths-ignore:
- 'docs/**'
- 'src/test/**'
- 'README.md'
tags:
- '*'
pull_request:
merge_group:
workflow_dispatch:
inputs:
notarization:
type: boolean
required: false
default: false
env:
SpringerNatureAPIKey: ${{ secrets.SpringerNatureAPIKey }}
AstrophysicsDataSystemAPIKey: ${{ secrets.AstrophysicsDataSystemAPIKey }}
IEEEAPIKey: ${{ secrets.IEEEAPIKey }}
BiodiversityHeritageApiKey: ${{ secrets.BiodiversityHeritageApiKey}}
OSXCERT: ${{ secrets.OSX_SIGNING_CERT }}
GRADLE_OPTS: -Xmx4g -Dorg.gradle.daemon=false -Dorg.gradle.vfs.watch=false
JAVA_OPTS: -Xmx4g
concurrency:
group: "${{ github.workflow }}-${{ github.head_ref || github.ref }}"
cancel-in-progress: true
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: macos-14
displayName: macOS (ARM64)
suffix: '_arm64'
runs-on: ${{ matrix.os }}
outputs:
major: ${{ steps.gitversion.outputs.Major }}
minor: ${{ steps.gitversion.outputs.Minor }}
branchname: ${{ steps.gitversion.outputs.branchName }}
name: Create installer and portable version for ${{ matrix.displayName }}
steps:
- name: Check secrets presence
id: checksecrets
shell: bash
run: |
if [ "$BUILDJABREFPRIVATEKEY" == "" ]; then
echo "secretspresent=NO" >> $GITHUB_OUTPUT
echo "❌ Secret BUILDJABREFPRIVATEKEY not present"
else
echo "secretspresent=YES" >> $GITHUB_OUTPUT
echo "✔️ Secret BUILDJABREFPRIVATEKEY present"
fi
env:
BUILDJABREFPRIVATEKEY: ${{ secrets.buildJabRefPrivateKey }}
- name: Fetch all history for all tags and branches
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: 'true'
show-progress: 'false'
- name: Install GitVersion
uses: gittools/actions/gitversion/setup@v3.0.0
with:
versionSpec: "5.x"
- name: Run GitVersion
id: gitversion
uses: gittools/actions/gitversion/execute@v3.0.0
- name: Setup JDK
uses: actions/setup-java@v4
with:
java-version: 21.0.2
distribution: 'temurin'
- name: Clean up keychain
run: |
security delete-keychain signing_temp.keychain ${{runner.temp}}/keychain/notarization.keychain || true
- name: Setup OSX key chain on macOS-arm
if: (steps.checksecrets.outputs.secretspresent == 'YES')
uses: slidoapp/import-codesign-certs@1923310662e8682dd05b76b612b53301f431cd5d
with:
p12-file-base64: ${{ secrets.OSX_SIGNING_CERT }}
p12-password: ${{ secrets.OSX_CERT_PWD }}
keychain-password: jabref
- name: Setup OSX key chain on OSX for app id cert
if: (steps.checksecrets.outputs.secretspresent == 'YES')
uses: slidoapp/import-codesign-certs@1923310662e8682dd05b76b612b53301f431cd5d
with:
p12-file-base64: ${{ secrets.OSX_SIGNING_CERT_APPLICATION }}
p12-password: ${{ secrets.OSX_CERT_PWD }}
create-keychain: false
keychain-password: jabref
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
gradle-home-cache-cleanup: true
- name: Prepare merged jars and modules dir (macOS)
run: ./gradlew -i -PprojVersion="${{ steps.gitversion.outputs.AssemblySemVer }}" -PprojVersionInfo="${{ steps.gitversion.outputs.InformationalVersion }}" prepareModulesDir
- name: Build dmg (macOS)
if: (steps.checksecrets.outputs.secretspresent == 'YES')
shell: bash
run: |
jpackage \
--module org.jabref/org.jabref.Launcher \
--module-path ${{env.JAVA_HOME}}/jmods/:build/jlinkbase/jlinkjars \
--add-modules org.jabref,org.jabref.merged.module \
--add-modules jdk.incubator.vector \
--dest build/distribution \
--app-content buildres/mac/jabrefHost.py \
--app-content buildres/mac/native-messaging-host \
--name JabRef \
--app-version ${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }} \
--verbose \
--mac-sign \
--vendor "JabRef e.V." \
--mac-package-identifier JabRef \
--mac-package-name JabRef \
--type dmg --mac-signing-key-user-name "JabRef e.V. (6792V39SK3)" \
--mac-package-signing-prefix org.jabref \
--mac-entitlements buildres/mac/jabref.entitlements \
--icon src/main/resources/icons/jabref.icns \
--resource-dir buildres/mac \
--file-associations buildres/mac/bibtexAssociations.properties \
--jlink-options --bind-services \
--java-options --add-exports=javafx.base/com.sun.javafx.event=org.jabref.merged.module \
--java-options --add-exports=javafx.controls/com.sun.javafx.scene.control=org.jabref.merged.module \
--java-options --add-opens=javafx.graphics/javafx.scene=org.jabref.merged.module \
--java-options --add-opens=javafx.controls/javafx.scene.control=org.jabref.merged.module \
--java-options --add-opens=javafx.controls/javafx.scene.control.skin=org.jabref.merged.module \
--java-options --add-opens=javafx.controls/com.sun.javafx.scene.control=org.jabref.merged.module \
--java-options --add-opens=javafx.controls/javafx.scene.control=org.jabref \
--java-options --add-exports=javafx.base/com.sun.javafx.event=org.jabref \
--java-options --add-exports=javafx.controls/com.sun.javafx.scene.control=org.jabref \
--java-options --add-opens=javafx.graphics/javafx.scene=org.jabref \
--java-options --add-opens=javafx.controls/javafx.scene.control=org.jabref \
--java-options --add-opens=javafx.controls/com.sun.javafx.scene.control=org.jabref \
--java-options --add-opens=javafx.base/javafx.collections=org.jabref \
--java-options --add-opens=javafx.base/javafx.collections.transformation=org.jabref \
--java-options --add-modules=jdk.incubator.vector
- name: Build pkg (macOS)
if: (steps.checksecrets.outputs.secretspresent == 'YES')
shell: bash
run: |
jpackage \
--module org.jabref/org.jabref.Launcher \
--module-path ${{env.JAVA_HOME}}/jmods/:build/jlinkbase/jlinkjars \
--add-modules org.jabref,org.jabref.merged.module \
--add-modules jdk.incubator.vector \
--dest build/distribution \
--app-content buildres/mac/jabrefHost.py \
--app-content buildres/mac/native-messaging-host \
--name JabRef \
--app-version ${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }} \
--verbose \
--mac-sign \
--vendor "JabRef e.V." \
--mac-package-identifier JabRef \
--mac-package-name JabRef \
--type pkg --mac-signing-key-user-name "JabRef e.V. (6792V39SK3)" \
--mac-package-signing-prefix org.jabref \
--mac-entitlements buildres/mac/jabref.entitlements \
--icon src/main/resources/icons/jabref.icns \
--resource-dir buildres/mac \
--file-associations buildres/mac/bibtexAssociations.properties \
--jlink-options --bind-services \
--java-options --add-exports=javafx.base/com.sun.javafx.event=org.jabref.merged.module \
--java-options --add-exports=javafx.controls/com.sun.javafx.scene.control=org.jabref.merged.module \
--java-options --add-opens=javafx.graphics/javafx.scene=org.jabref.merged.module \
--java-options --add-opens=javafx.controls/javafx.scene.control=org.jabref.merged.module \
--java-options --add-opens=javafx.controls/com.sun.javafx.scene.control=org.jabref.merged.module \
--java-options --add-opens=javafx.controls/javafx.scene.control=org.jabref \
--java-options --add-exports=javafx.base/com.sun.javafx.event=org.jabref \
--java-options --add-exports=javafx.controls/com.sun.javafx.scene.control=org.jabref \
--java-options --add-opens=javafx.graphics/javafx.scene=org.jabref \
--java-options --add-opens=javafx.controls/javafx.scene.control=org.jabref \
--java-options --add-opens=javafx.controls/com.sun.javafx.scene.control=org.jabref \
--java-options --add-opens=javafx.base/javafx.collections=org.jabref \
--java-options --add-opens=javafx.base/javafx.collections.transformation=org.jabref \
--java-options --add-modules=jdk.incubator.vector
- name: Rename files with arm64 suffix as well
if: (steps.checksecrets.outputs.secretspresent == 'YES')
shell: bash
run: |
mv build/distribution/JabRef-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}.dmg build/distribution/JabRef-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}-arm64.dmg
mv build/distribution/JabRef-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}.pkg build/distribution/JabRef-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}-arm64.pkg
- name: Setup rsync (macOS)
if: ${{ (!startsWith(github.ref, 'refs/heads/gh-readonly-queue')) && (steps.checksecrets.outputs.secretspresent == 'YES') && ((matrix.os == 'macos-14') && !((startsWith(github.ref, 'refs/tags/') || inputs.notarization == true))) }}
run: brew install rsync
- name: Setup SSH key
if: ${{ (steps.checksecrets.outputs.secretspresent == 'YES') && (!startsWith(github.ref, 'refs/heads/gh-readonly-queue')) && ((matrix.os != 'macos-14') || !((startsWith(github.ref, 'refs/tags/') || (inputs.notarization == true)))) }}
run: |
echo "${{ secrets.buildJabRefPrivateKey }}" > sshkey
chmod 600 sshkey
- name: Upload to builds.jabref.org (linux, macOS)
# macOS: Negated condition of "Upload to GitHub workflow artifacts store (macOS)"
# Reason: We either upload the non-notarized files - or notarize the files later (and upload these later)
# needs to be on one line; multi line does not work
if: ${{ (!startsWith(github.ref, 'refs/heads/gh-readonly-queue')) && (steps.checksecrets.outputs.secretspresent == 'YES') && ((matrix.os == 'ubuntu-latest') || ((matrix.os == 'macos-14') && !((startsWith(github.ref, 'refs/tags/') || inputs.notarization == true)))) }}
shell: bash
run: |
rsync -rt --chmod=Du=rwx,Dg=rx,Do=rx,Fu=rw,Fg=r,Fo=r --itemize-changes --stats --rsync-path="mkdir -p /var/www/builds.jabref.org/www/${{ steps.gitversion.outputs.branchName }} && rsync" -e 'ssh -p 9922 -i sshkey -o StrictHostKeyChecking=no' build/distribution/ jrrsync@build-upload.jabref.org:/var/www/builds.jabref.org/www/${{ steps.gitversion.outputs.branchName }}/
- name: Upload to GitHub workflow artifacts store (macOS)
if: (matrix.os == 'macos-14') && (steps.checksecrets.outputs.secretspresent == 'YES') && (startsWith(github.ref, 'refs/tags/') || inputs.notarization == true)
uses: actions/upload-artifact@v4
with:
# tbn = to-be-notarized
name: JabRef-macOS-arm-tbn
path: build/distribution
compression-level: 0 # no compression
- name: Upload to GitHub workflow artifacts store
if: (steps.checksecrets.outputs.secretspresent != 'YES')
uses: actions/upload-artifact@v4
with:
# tbn = to-be-notarized
name: JabRef-${{ matrix.os }}
path: build/distribution
compression-level: 0 # no compression
notarize: # outsourced in a separate job to be able to rerun if this fails for timeouts
name: macOS notarization-arm
runs-on: macos-14
needs: [build]
if: ${{ startsWith(github.ref, 'refs/tags/') || inputs.notarization == true }}
steps:
- name: Check secrets presence
id: checksecrets
shell: bash
run: |
if [ "$BUILDJABREFPRIVATEKEY" == "" ]; then
echo "secretspresent=NO" >> $GITHUB_OUTPUT
echo "❌ Secret BUILDJABREFPRIVATEKEY not present"
else
echo "secretspresent=YES" >> $GITHUB_OUTPUT
echo "✔️ Secret BUILDJABREFPRIVATEKEY present"
fi
env:
BUILDJABREFPRIVATEKEY: ${{ secrets.buildJabRefPrivateKey }}
- name: Download from GitHub workflow artifacts store (macOS)
if: (steps.checksecrets.outputs.secretspresent == 'YES')
uses: actions/download-artifact@master
with:
name: JabRef-macOS-arm-tbn
path: build/distribution/
- name: Notarize dmg
if: (steps.checksecrets.outputs.secretspresent == 'YES')
shell: bash
run: |
xcrun notarytool store-credentials "notarytool-profile" --apple-id "vorstand@jabref.org" --team-id "6792V39SK3" --password "${{ secrets.OSX_NOTARIZATION_APP_PWD }}"
xcrun notarytool submit build/distribution/JabRef-${{ needs.build.outputs.major }}.${{ needs.build.outputs.minor }}-arm64.dmg --keychain-profile "notarytool-profile" --wait
xcrun stapler staple build/distribution/JabRef-${{ needs.build.outputs.major }}.${{ needs.build.outputs.minor }}-arm64.dmg
- name: Notarize pkg
if: (steps.checksecrets.outputs.secretspresent == 'YES')
shell: bash
run: |
xcrun notarytool store-credentials "notarytool-profile" --apple-id "vorstand@jabref.org" --team-id "6792V39SK3" --password "${{ secrets.OSX_NOTARIZATION_APP_PWD }}"
xcrun notarytool submit build/distribution/JabRef-${{ needs.build.outputs.major }}.${{ needs.build.outputs.minor }}-arm64.pkg --keychain-profile "notarytool-profile" --wait
xcrun stapler staple build/distribution/JabRef-${{ needs.build.outputs.major }}.${{ needs.build.outputs.minor }}-arm64.pkg
- name: Upload to builds.jabref.org
if: (steps.checksecrets.outputs.secretspresent == 'YES')
shell: bash
run: |
echo "${{ secrets.buildJabRefPrivateKey }}" > sshkey
chmod 600 sshkey
rsync -rt --chmod=Du=rwx,Dg=rx,Do=rx,Fu=rw,Fg=r,Fo=r --itemize-changes --stats --rsync-path="mkdir -p /var/www/builds.jabref.org/www/${{ needs.build.outputs.branchname }} && rsync" -e 'ssh -p 9922 -i sshkey -o StrictHostKeyChecking=no' build/distribution/ jrrsync@build-upload.jabref.org:/var/www/builds.jabref.org/www/${{ needs.build.outputs.branchname }}/

View File

@ -0,0 +1,281 @@
# This workflow is a clone of "deployment.yml"
# The difference is that this workflow uses JDK early access builds (jdk-ea) to check the build of JabRef
# We separated this from the main workflow as we do not want to check on each PR if the JDK build, but only on main
name: Deployment (JDK early access builds)
on:
schedule:
- cron: "0 18 * * 1"
pull_request:
paths:
- .github/workflows/deployment-jdk-ea.yml
- build.gradle
workflow_dispatch:
inputs:
notarization:
type: boolean
required: false
default: false
env:
SpringerNatureAPIKey: ${{ secrets.SpringerNatureAPIKey }}
AstrophysicsDataSystemAPIKey: ${{ secrets.AstrophysicsDataSystemAPIKey }}
IEEEAPIKey: ${{ secrets.IEEEAPIKey }}
BiodiversityHeritageApiKey: ${{ secrets.BiodiversityHeritageApiKey}}
OSXCERT: ${{ secrets.OSX_SIGNING_CERT }}
GRADLE_OPTS: -Xmx4g -Dorg.gradle.vfs.watch=false
JAVA_OPTS: -Xmx4g
concurrency:
group: "${{ github.workflow }}-${{ github.head_ref || github.ref }}"
cancel-in-progress: true
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest, buildjet-8vcpu-ubuntu-2204-arm]
jdk: [22]
javafx: [23]
include:
- os: ubuntu-latest
displayName: linux
archivePortable: tar -c -C build/distribution JabRef | pigz --rsyncable > build/distribution/JabRef-portable_linux.tar.gz && rm -R build/distribution/JabRef
- os: windows-latest
displayName: windows
archivePortable: 7z a -r build/distribution/JabRef-portable_windows.zip ./build/distribution/JabRef && rm -R build/distribution/JabRef
- os: buildjet-8vcpu-ubuntu-2204-arm
displayName: "linux-arm"
archivePortable: "tar -c -C build/distribution JabRef | pigz --rsyncable > build/distribution/JabRef-portable_linux-arm64.tar.gz && rm -R build/distribution/JabRef"
- os: macos-latest
displayName: macOS
archivePortable: "brew install pigz && tar -c -C build/distribution JabRef.app | pigz --rsyncable > build/distribution/JabRef-portable_macos.tar.gz && rm -R build/distribution/JabRef.app"
runs-on: ${{ matrix.os }}
outputs:
major: ${{ steps.gitversion.outputs.Major }}
minor: ${{ steps.gitversion.outputs.Minor }}
branchname: ${{ steps.gitversion.outputs.branchName }}
name: "JDK ${{ matrix.jdk }}: ${{ matrix.displayName }} JavaFX ${{ matrix.javafx }}"
steps:
- name: Check secrets presence
id: checksecrets
shell: bash
run: |
if [ "$BUILDJABREFPRIVATEKEY" == "" ]; then
echo "secretspresent=NO" >> $GITHUB_OUTPUT
echo "❌ Secret BUILDJABREFPRIVATEKEY not present"
else
echo "secretspresent=YES" >> $GITHUB_OUTPUT
echo "✔️ Secret BUILDJABREFPRIVATEKEY present"
fi
env:
BUILDJABREFPRIVATEKEY: ${{ secrets.buildJabRefPrivateKey }}
- name: Fetch all history for all tags and branches
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: 'true'
show-progress: 'false'
- name: Install pigz and cache (linux)
if: (matrix.os == 'ubuntu-latest') || (matrix.os == 'buildjet-8vcpu-ubuntu-2204-arm')
uses: awalsh128/cache-apt-pkgs-action@master
with:
packages: pigz
version: 1.0
- name: Install GitVersion
uses: gittools/actions/gitversion/setup@v3.0.0
with:
versionSpec: "5.x"
- name: Run GitVersion
id: gitversion
uses: gittools/actions/gitversion/execute@v3.0.0
# JDK
- name: 'Set up JDK ${{ matrix.jdk }}'
uses: actions/setup-java@v4
with:
java-version: ${{ matrix.jdk }}
distribution: 'temurin'
- name: 'Set JDK${{ matrix.jdk }} env var'
shell: bash
run: echo "JDK${{ matrix.jdk }}=$JAVA_HOME" >> $GITHUB_ENV
- name: 'Set JDK${{ matrix.jdk }} in toolchain (linux, Windows)'
if: (matrix.os != 'macos-latest')
shell: bash
run: |
sed -i 's/JavaLanguageVersion.of(.*)/JavaLanguageVersion.of(${{ matrix.jdk }})/' build.gradle
sed -i 's/JavaVersion.VERSION_(.*)/JavaVersion.VERSION_(${{ matrix.jdk }})/' build.gradle
- name: 'Set JDK${{ matrix.jdk }} in toolchain (macOS)'
if: (matrix.os == 'macos-latest')
shell: bash
run: |
sed -i'.bak' 's/JavaLanguageVersion.of(.*)/JavaLanguageVersion.of(${{ matrix.jdk }})/' build.gradle
sed -i'.bak' 's/JavaVersion.VERSION_(.*)/JavaVersion.VERSION_(${{ matrix.jdk }})/' build.gradle
# JavaFX
- name: Download and extract JavaFX ${{ matrix.javafx }}
if: (matrix.os != 'buildjet-8vcpu-ubuntu-2204-arm')
shell: bash
run: |
cd javafx
curl --no-progress-meter https://jdk.java.net/javafx${{ matrix.javafx }}/ > javafx.html
case "${{ matrix.os }}" in
"ubuntu-latest")
OS="linux"
EXTRACT="tar xzf *.tar.gz"
EXT="tar.gz"
;;
"buildjet-8vcpu-ubuntu-2204-arm")
OS="linux"
EXTRACT="tar xzf *.tar.gz"
EXT="tar.gz"
echo "There are no ARM EA builds"
exit 0
;;
"windows-latest")
OS="windows"
EXTRACT="unzip -qq *.zip"
EXT="zip"
;;
"macos-latest")
OS="macos"
EXTRACT="tar xzf *.tar.gz"
EXT="tar.gz"
;;
*)
echo "Unsupported OS"
exit 1
;;
esac
echo "OS set to $OS"
URL_SDK=$(grep -o "https://download.java.net/java/.*/javafx.*${OS}-x64_bin-sdk.${EXT}" javafx.html | head -n 1)
echo "Downloading $URL_SDK..."
curl -OJ --no-progress-meter $URL_SDK
$EXTRACT
rm *.$EXT
URL_JMODS=$(grep -o "https://download.java.net/java/.*/javafx.*${OS}-x64_bin-jmods.${EXT}" javafx.html | head -n 1)
echo "Downloading $URL_JMODS..."
curl -OJ --no-progress-meter $URL_JMODS
$EXTRACT
rm *.$EXT
- name: 'Set JavaFX ${{ matrix.javafx }} (linux, Windows)'
if: (matrix.os != 'macos-latest') && (matrix.os != 'buildjet-8vcpu-ubuntu-2204-arm')
run: |
sed -i '/javafx {/{n;s#version = ".*"#sdk = "javafx/javafx-sdk-${{ matrix.javafx }}"#}' build.gradle
sed -i "s#jlink {#jlink { addExtraModulePath 'javafx/javafx-jmods-${{ matrix.javafx }}'#" build.gradle
cat build.gradle
- name: 'Set JavaFX ${{ matrix.javafx }} (macOS)'
if: (matrix.os == 'macos-latest') && (matrix.os != 'buildjet-8vcpu-ubuntu-2204-arm')
run: |
sed -i '.bak' -e '/javafx {/{n' -e 's#version = ".*"#sdk = "javafx/javafx-sdk-${{ matrix.javafx }}"#;}' build.gradle
sed -i '.bak' -e "s#jlink {#jlink { addExtraModulePath 'javafx/javafx-jmods-${{ matrix.javafx }}'#" build.gradle
cat build.gradle
- name: 'Set JavaFX ${{ matrix.javafx }} (linux-arm)'
if: (matrix.os == 'buildjet-8vcpu-ubuntu-2204-arm')
# No JavaFX EA build for ARM at https://jdk.java.net/javafx23/, therefore using Maven Central artifact
run: |
curl -s "https://search.maven.org/solrsearch/select?q=g:org.openjfx+AND+a:javafx&rows=10&core=gav" > /tmp/versions.json
jq '[.response.docs[] | select(.v | test(".*-ea\\+.*")) | select(.v | test("^17|^18|^19|^20|^21|^22") | not) | {version: .v}] | group_by(.version | capture("^(?<major>\\d+).*").major) | map(max_by(.version))' < /tmp/versions.json > /tmp/versions-latest.json
JAVAFX=$(jq -r '.[-1].version' /tmp/versions-latest.json)
echo "Using JavaFX ${JAVAFX}"
sed -i "/javafx {/{n;s#version = \".*\"#version = \"${JAVAFX}\"#}" build.gradle && cat build.gradle
# Gradle
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: 21
distribution: 'temurin'
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
with:
gradle-home-cache-cleanup: true
- name: Prepare merged jars and modules dir
# prepareModulesDir is executing a build, which should run through even if no upload to builds.jabref.org is made
if: (steps.checksecrets.outputs.secretspresent == 'NO')
run: ./gradlew -i -PprojVersion="${{ steps.gitversion.outputs.AssemblySemVer }}" -PprojVersionInfo="${{ steps.gitversion.outputs.InformationalVersion }}" prepareModulesDir
- name: Set up macOS key chain
if: (matrix.os == 'macos-latest') && (steps.checksecrets.outputs.secretspresent == 'YES')
uses: slidoapp/import-codesign-certs@1923310662e8682dd05b76b612b53301f431cd5d
with:
p12-file-base64: ${{ secrets.OSX_SIGNING_CERT }}
p12-password: ${{ secrets.OSX_CERT_PWD }}
keychain-password: jabref
- name: Set up macOS key chain for app id cert
if: (matrix.os == 'macos-latest') && (steps.checksecrets.outputs.secretspresent == 'YES')
uses: slidoapp/import-codesign-certs@1923310662e8682dd05b76b612b53301f431cd5d
with:
p12-file-base64: ${{ secrets.OSX_SIGNING_CERT_APPLICATION }}
p12-password: ${{ secrets.OSX_CERT_PWD }}
create-keychain: false
keychain-password: jabref
- name: Build runtime image and installer
shell: bash
run: ./gradlew -i -PprojVersion="${{ steps.gitversion.outputs.AssemblySemVer }}" -PprojVersionInfo="${{ steps.gitversion.outputs.InformationalVersion }}" jpackage jlinkZip
- name: Package application image
shell: bash
run: ${{ matrix.archivePortable }}
- name: Rename files
if: (matrix.os != 'macos-latest')
shell: pwsh
run: |
get-childitem -Path build/distribution/* | rename-item -NewName {$_.name -replace "${{ steps.gitversion.outputs.AssemblySemVer }}","${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}"}
get-childitem -Path build/distribution/* | rename-item -NewName {$_.name -replace "portable","${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}-portable"}
- name: Repack deb file for Debian
if: (matrix.os == 'ubuntu-latest')
shell: bash
run: |
cd build/distribution
ar x jabref_${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}_amd64.deb
zstd -d < control.tar.zst | xz > control.tar.xz
zstd -d < data.tar.zst | xz > data.tar.xz
ar -m -c -a sdsd jabref_${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}_amd64_repackaged.deb debian-binary control.tar.xz data.tar.xz
rm debian-binary control.tar.* data.tar.*
mv -f jabref_${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}_amd64_repackaged.deb jabref_${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}_amd64.deb
- name: Rename files with JDK version
shell: bash
run: |
for file in build/distribution/*.*; do
base=${file%.*}
ext=${file##*.}
mv "$file" "${base}-jdk${{ matrix.jdk }}-javafx${{ matrix.javafx }}.${ext}"
done
# Upload
- name: Set up rsync (macOS)
if: (matrix.os == 'macos-latest') && (steps.checksecrets.outputs.secretspresent == 'YES') && (github.ref == 'refs/heads/main')
run: brew install rsync
- name: Set up rsync (Windows)
if: (matrix.os == 'windows-latest') && (steps.checksecrets.outputs.secretspresent == 'YES') && (github.ref == 'refs/heads/main')
# We want to have rsync available at this place to avoid uploading and downloading from GitHub artifact store (taking > 5 minutes in total)
# We cannot use "action-rsyncer", because that requires Docker which is unavailable on Windows
# We cannot use "setup-rsync", because that does not work on Windows
# We do not use egor-tensin/setup-cygwin@v4, because it replaces the default shell
run: choco install --no-progress rsync
- name: Set up SSH key
if: (steps.checksecrets.outputs.secretspresent == 'YES') && (github.ref == 'refs/heads/main')
run: |
echo "${{ secrets.buildJabRefPrivateKey }}" > sshkey
chmod 600 sshkey
- name: Upload to builds.jabref.org (Windows)
if: (matrix.os == 'windows-latest') && (steps.checksecrets.outputs.secretspresent == 'YES') && (github.ref == 'refs/heads/main')
shell: cmd
# for rsync installed by chocolatey, we need the ssh.exe delivered with that installation
run: |
rsync -rt --chmod=Du=rwx,Dg=rx,Do=rx,Fu=rw,Fg=r,Fo=r --itemize-changes --stats --rsync-path="mkdir -p /var/www/builds.jabref.org/www/jdk-ea && rsync" -e 'C:\ProgramData\chocolatey\lib\rsync\tools\bin\ssh.exe -p 9922 -i sshkey -o StrictHostKeyChecking=no' build/distribution/ jrrsync@build-upload.jabref.org:/var/www/builds.jabref.org/www/jdk-ea/
- name: Upload to builds.jabref.org (linux, macOS)
if: (matrix.os != 'windows-latest') && (steps.checksecrets.outputs.secretspresent == 'YES') && (github.ref == 'refs/heads/main')
shell: bash
run: |
rsync -rt --chmod=Du=rwx,Dg=rx,Do=rx,Fu=rw,Fg=r,Fo=r --itemize-changes --stats --rsync-path="mkdir -p /var/www/builds.jabref.org/www/jdk-ea && rsync" -e 'ssh -p 9922 -i sshkey -o StrictHostKeyChecking=no' build/distribution/ jrrsync@build-upload.jabref.org:/var/www/builds.jabref.org/www/jdk-ea/
- name: Upload to GitHub workflow artifacts store
if: (steps.checksecrets.outputs.secretspresent != 'YES') || (github.ref != 'refs/heads/main')
uses: actions/upload-artifact@v4
with:
name: JabRef-${{ matrix.os }}
path: build/distribution
compression-level: 0 # no compression

Some files were not shown because too many files have changed in this diff Show More