Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
47a4af1cc0 | |||
61b60cfbaf | |||
![]() |
a2a1ede6b7 | ||
b157c2c194 | |||
b094db4615 | |||
![]() |
a81d9ed65e | ||
cfecc02cad | |||
c41072785c | |||
64c1d0e743 | |||
73a279f24a | |||
944138280d | |||
1c34fe3715 | |||
154e774296 | |||
c5d4d2d059 | |||
a150ed4958 | |||
![]() |
415abbc47b |
3
.gitignore
vendored
@ -1 +1,2 @@
|
||||
.DS_Store
|
||||
.DS_Store
|
||||
/classes
|
||||
|
4
.idea/sq_2024.iml
generated
@ -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>
|
||||
|
93
README.md
@ -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.
|
Before Width: | Height: | Size: 357 KiB |
Before Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 400 KiB |
Before Width: | Height: | Size: 457 B |
Before Width: | Height: | Size: 832 B |
Before Width: | Height: | Size: 140 B |
Before Width: | Height: | Size: 127 B |
Before Width: | Height: | Size: 605 B |
Before Width: | Height: | Size: 856 B |
Before Width: | Height: | Size: 589 B |
Before Width: | Height: | Size: 135 B |
Before Width: | Height: | Size: 75 B |
Before Width: | Height: | Size: 71 B |
Before Width: | Height: | Size: 471 B |
Before Width: | Height: | Size: 340 B |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 71 B |
4
dicegame/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
.gradle/
|
||||
.idea/
|
||||
src/build/
|
||||
target/
|
4
dicegame/META-INF/MANIFEST.MF
Normal file
@ -0,0 +1,4 @@
|
||||
Manifest-Version: 1.0
|
||||
Class-Path: .
|
||||
Main-Class: WuerfelspielGUI
|
||||
|
5
dicegame/src/dicegame/logic/DiceInteraction.java
Normal file
@ -0,0 +1,5 @@
|
||||
package dicegame.logic;
|
||||
|
||||
public interface DiceInteraction {
|
||||
public int changeDiceState(int diceIndex) throws SelectionException;
|
||||
}
|
276
dicegame/src/dicegame/logic/Logic.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
7
dicegame/src/dicegame/logic/SelectionException.java
Normal file
@ -0,0 +1,7 @@
|
||||
package dicegame.logic;
|
||||
|
||||
public class SelectionException extends Exception {
|
||||
SelectionException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
608
dicegame/src/dicegame/view/GUI.java
Normal 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
39
jabref/.devcontainer/devcontainer.json
Normal 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
@ -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
|
28
jabref/.git-blame-ignore-revs
Normal 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
@ -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
@ -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
|
81
jabref/.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal 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
|
8
jabref/.github/ISSUE_TEMPLATE/config.yml
vendored
Normal 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!
|
23
jabref/.github/ISSUE_TEMPLATE/suggestion-for-improvement.md
vendored
Normal 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
@ -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
@ -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
@ -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]`.
|
31
jabref/.github/workflows/add-greeting-to-issue.yml
vendored
Normal 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! 🚀
|
44
jabref/.github/workflows/add-to-projects.yml
vendored
Normal 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
@ -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}}
|
37
jabref/.github/workflows/check-links.yml
vendored
Normal 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
@ -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
|
271
jabref/.github/workflows/deployment-arm64.yml
vendored
Normal 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 }}/
|
281
jabref/.github/workflows/deployment-jdk-ea.yml
vendored
Normal 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
|