8 Commits
Author SHA1 Message Date
Michael Burgess 81ff63a38d Build against latest Paper API and local MobArena; fix CI JDK/artifact upload
build / build (push) Successful in 3m31s
2026-08-06 22:40:32 -04:00
Michael Burgess 3e65b02d72 Fix Gitea CI: add JDK setup, drop unsupported cache action
build / build (push) Failing after 2m42s
2026-08-06 20:28:59 -04:00
Michael Burgess f8ba0e4efc Rename ssl config key to flags
build / build (push) Failing after 13s
2026-08-06 20:08:35 -04:00
Michael Burgess 6f74026514 Use raw JDBC parameter string instead of ssl boolean flag
build / build (push) Failing after 14s
2026-08-06 19:45:09 -04:00
Andreas Troelsen eb77193fbd Release 1.0. 2022-07-30 15:58:05 +02:00
Andreas Troelsen 2c65d88c62 Link to releases/actions in README.
After the first release we should be able to link to the `/latest` URL
just fine, so we'll just prep it now. We don't really want to maintain
an "official" test builds channel on Discord, so that's out as well.
2022-07-30 15:58:05 +02:00
Andreas Troelsen 627205d39a Qualify getTables() with catalog and schema.
Without these qualifiers, the tables returned by the metadata object
will include tables from _all_ databases in the database instance, which
is definitely not something we want. Not only does this pose a potential
performance impact, it can also return very false positives, which then
result in an (inaptly named) SQLSyntaxErrorException when the subsequent
query to the potentially non-existent table fails.

To reproduce the issue:

- Create two new, empty databases in a fresh MySQL/MariaDB instance.
- Point the extension at one of them.
- Spin up the server, let the extension initialize the database.
- Stop the server.
- Point the extension at the other database.
- Spin the server back up and watch it crash.

By qualifying the `getTables()` call with the catalog and schema of the
underlying connection object, we limit the search to _just_ that catalog
and schema, which is what we wanted all along. According to the method
documentation, the args are _patterns_, where `%` matches substrings and
`_` matches "any character". So by being hyper-specific, we shouldn't
get any more false positives. In testing on MySQL and MariaDB, only the
`catalog` value is non-null (matches the database name), while `schema`
remains null.
2022-07-30 15:58:05 +02:00
Andreas Troelsen 3f7796772e Upgrade Mockito to 3.12.2.
This fixes an issue with the mock maker not running properly on recent
versions of the JVM, and it also matches the version in the base plugin.
2022-07-30 12:10:50 +02:00
10 changed files with 109 additions and 43 deletions
+11 -7
View File
@@ -15,19 +15,23 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Cache dependencies - name: Set up JDK
uses: actions/cache@v2 uses: actions/setup-java@v4
with: with:
path: ~/.m2/repository distribution: temurin
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} java-version: '25'
restore-keys: |
${{ runner.os }}-maven- - name: Checkout MobArena
run: git clone --depth 1 https://git.tss3.us/skywalker3200/MobArena.git ../MobArena
- name: Publish MobArena to local Maven repo
run: cd ../MobArena && ./gradlew publishToMavenLocal --no-daemon
- name: Build, test, package - name: Build, test, package
run: ./mvnw -B package --file pom.xml run: ./mvnw -B package --file pom.xml
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v3
with: with:
name: MobArenaStats.jar name: MobArenaStats.jar
path: target/MobArenaStats.jar path: target/MobArenaStats.jar
+6 -2
View File
@@ -9,8 +9,12 @@ It hooks into MobArena's command handler to provide commands for querying and ma
## Getting Started ## Getting Started
Download a copy of the latest MobArenaStats build and place it in your server's `plugins` folder. Download a copy of MobArenaStats from one of these release channels:
You can grab a build from the _Artifacts_ section of the latest run of the [build workflow](https://github.com/mobarena/MobArenaStats/actions/workflows/build.yml) in GitHub Actions, or you can join the MobArena Discord server and grab one from the `#test-builds` channel.
- Stable (recommended): [Latest release](https://github.com/mobarena/MobArenaStats/releases/latest)
- Dev (experimental): [Latest build](https://github.com/mobarena/MobArenaStats/actions/workflows/build.yml)
Place the jar-file in your server's `plugins` folder like you would any other plugin.
Start your server and let the plugin load. Start your server and let the plugin load.
It will generate a default `config.yml` file and set up a default SQLite data store. It will generate a default `config.yml` file and set up a default SQLite data store.
+13 -19
View File
@@ -6,7 +6,7 @@
<groupId>org.mobarena</groupId> <groupId>org.mobarena</groupId>
<artifactId>mobarena-stats</artifactId> <artifactId>mobarena-stats</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.0</version>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -34,19 +34,19 @@
<version>2.2.1</version> <version>2.2.1</version>
</dependency> </dependency>
<!-- https://hub.spigotmc.org/nexus/content/groups/public/org/spigotmc/spigot-api/ --> <!-- https://repo.papermc.io/repository/maven-public/io/papermc/paper/paper-api/ -->
<dependency> <dependency>
<groupId>org.spigotmc</groupId> <groupId>io.papermc.paper</groupId>
<artifactId>spigot-api</artifactId> <artifactId>paper-api</artifactId>
<version>1.17-R0.1-SNAPSHOT</version> <version>26.2.build.84-stable</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- https://jitpack.io/#garbagemule/MobArena --> <!-- Built and installed locally from F:\skywalker3200\MobArena via `./gradlew publishToMavenLocal` -->
<dependency> <dependency>
<groupId>com.github.garbagemule</groupId> <groupId>com.garbagemule</groupId>
<artifactId>MobArena</artifactId> <artifactId>MobArena</artifactId>
<version>b99713f1</version> <version>0.109.1-tss3</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@@ -86,7 +86,7 @@
<dependency> <dependency>
<groupId>org.mockito</groupId> <groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId> <artifactId>mockito-junit-jupiter</artifactId>
<version>3.11.2</version> <version>3.12.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@@ -133,13 +133,8 @@
<repositories> <repositories>
<repository> <repository>
<id>spigot-repo</id> <id>papermc</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url> <url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository> </repository>
</repositories> </repositories>
@@ -157,8 +152,7 @@
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version> <version>3.8.1</version>
<configuration> <configuration>
<source>11</source> <release>25</release>
<target>11</target>
</configuration> </configuration>
</plugin> </plugin>
@@ -171,7 +165,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version> <version>3.6.2</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
+61
View File
@@ -0,0 +1,61 @@
#----------------------------------------------------------------------
# The store is where all the collected data is kept. Different store
# types are supported:
#
# - sqlite: stores stats in an SQLite database
# - mysql: stores stats in a MySQL/MariaDB database
# - csv: stores stats in local CSV files
#
# Stores may require configuration of additional properties, such as
# file paths or database credentials.
#----------------------------------------------------------------------
store:
#--------------------------------------------------------------------
# Which type of store to use.
#
# Changing this value will _not_ result in an automatic conversion
# of existing store data. To transfer data to a different store,
# make an export of the current store first, then change type and
# import the exported data.
#
type: mysql
#--------------------------------------------------------------------
#--------------------------------------------------------------------
# SQLite store properties
#
# - filename: name of the database file, relative to plugin folder
#
#filename: stats.db
#--------------------------------------------------------------------
#--------------------------------------------------------------------
# MySQL/MariaDB store properties
#
# - host: where the database instance is hosted
# - port: database port number
# - database: name of the database (must exist!)
# - username: username of a valid database user
# - password: password of a valid database user
# - flags: extra JDBC connection parameters, appended to the URL as-is
# (e.g. 'verifyServerCertificate=false&sslmode=required').
# Leave blank/omit to append no extra parameters.
#
host: localhost
port: 3306
database: mobarena_stats
username: mobarena
password: 'change-me'
flags: 'verifyServerCertificate=false&sslmode=required'
#--------------------------------------------------------------------
#--------------------------------------------------------------------
# CSV store properties
#
# - folder: where to store data files, relative to plugin folder
# - separator: symbol to separate fields and values with
#
#folder: data
#separator: ';'
#--------------------------------------------------------------------
@@ -70,8 +70,10 @@ class SchemaMigrator {
// (available via the underlying JDBC connection object) to find // (available via the underlying JDBC connection object) to find
// out if the schema migrations table exists. // out if the schema migrations table exists.
Connection connection = handle.getConnection(); Connection connection = handle.getConnection();
String catalog = connection.getCatalog();
String schema = connection.getSchema();
DatabaseMetaData meta = connection.getMetaData(); DatabaseMetaData meta = connection.getMetaData();
try (ResultSet tables = meta.getTables(null, null, "schema_migrations", null)) { try (ResultSet tables = meta.getTables(catalog, schema, "schema_migrations", null)) {
while (tables.next()) { while (tables.next()) {
String name = tables.getString("TABLE_NAME"); String name = tables.getString("TABLE_NAME");
if (name.equals("schema_migrations")) { if (name.equals("schema_migrations")) {
@@ -29,11 +29,11 @@ public class MariadbStatsStore {
String host = config.getString("host", "localhost"); String host = config.getString("host", "localhost");
int port = config.getInt("port", 3306); int port = config.getInt("port", 3306);
String database = config.getString("database", "mobarena_stats"); String database = config.getString("database", "mobarena_stats");
boolean ssl = config.getBoolean("ssl", false); String flags = config.getString("flags", "");
String params = "useSSL=" + ssl; String url = "jdbc:mariadb://" + host + ":" + port + "/" + database;
return "jdbc:mariadb://" + host + ":" + port + "/" + database + "?" + params; return flags.isEmpty() ? url : url + "?" + flags;
} }
} }
@@ -27,11 +27,11 @@ public class MysqlStatsStore {
String host = config.getString("host", "localhost"); String host = config.getString("host", "localhost");
int port = config.getInt("port", 3306); int port = config.getInt("port", 3306);
String database = config.getString("database", "mobarena_stats"); String database = config.getString("database", "mobarena_stats");
boolean ssl = config.getBoolean("ssl", false); String flags = config.getString("flags", "");
String params = "useSSL=" + ssl; String url = "jdbc:mysql://" + host + ":" + port + "/" + database;
return "jdbc:mysql://" + host + ":" + port + "/" + database + "?" + params; return flags.isEmpty() ? url : url + "?" + flags;
} }
} }
+3 -2
View File
@@ -38,14 +38,15 @@ store:
# - database: name of the database (must exist!) # - database: name of the database (must exist!)
# - username: username of a valid database user # - username: username of a valid database user
# - password: password of a valid database user # - password: password of a valid database user
# - ssl: whether to use SSL for database connections # - flags: extra JDBC connection parameters, appended to the URL as-is
# (e.g. 'verifyServerCertificate=false&sslmode=required')
# #
#host: localhost #host: localhost
#port: 3306 #port: 3306
#database: '' #database: ''
#username: '' #username: ''
#password: '' #password: ''
#ssl: false #flags: ''
#-------------------------------------------------------------------- #--------------------------------------------------------------------
#-------------------------------------------------------------------- #--------------------------------------------------------------------
@@ -16,7 +16,7 @@ class MariadbStatsStoreTest {
String result = MariadbStatsStore.getUrl(config); String result = MariadbStatsStore.getUrl(config);
String expected = "jdbc:mariadb://localhost:3306/mobarena_stats?useSSL=false"; String expected = "jdbc:mariadb://localhost:3306/mobarena_stats";
assertThat(result, equalTo(expected)); assertThat(result, equalTo(expected));
} }
@@ -26,11 +26,11 @@ class MariadbStatsStoreTest {
config.set("host", "stats.example.com"); config.set("host", "stats.example.com");
config.set("port", 1337); config.set("port", 1337);
config.set("database", "mastats"); config.set("database", "mastats");
config.set("ssl", true); config.set("flags", "verifyServerCertificate=false&sslmode=required");
String result = MariadbStatsStore.getUrl(config); String result = MariadbStatsStore.getUrl(config);
String expected = "jdbc:mariadb://stats.example.com:1337/mastats?useSSL=true"; String expected = "jdbc:mariadb://stats.example.com:1337/mastats?verifyServerCertificate=false&sslmode=required";
assertThat(result, equalTo(expected)); assertThat(result, equalTo(expected));
} }
@@ -16,7 +16,7 @@ class MysqlStatsStoreTest {
String result = MysqlStatsStore.getUrl(config); String result = MysqlStatsStore.getUrl(config);
String expected = "jdbc:mysql://localhost:3306/mobarena_stats?useSSL=false"; String expected = "jdbc:mysql://localhost:3306/mobarena_stats";
assertThat(result, equalTo(expected)); assertThat(result, equalTo(expected));
} }
@@ -26,11 +26,11 @@ class MysqlStatsStoreTest {
config.set("host", "stats.example.com"); config.set("host", "stats.example.com");
config.set("port", 1337); config.set("port", 1337);
config.set("database", "mastats"); config.set("database", "mastats");
config.set("ssl", true); config.set("flags", "verifyServerCertificate=false&sslmode=required");
String result = MysqlStatsStore.getUrl(config); String result = MysqlStatsStore.getUrl(config);
String expected = "jdbc:mysql://stats.example.com:1337/mastats?useSSL=true"; String expected = "jdbc:mysql://stats.example.com:1337/mastats?verifyServerCertificate=false&sslmode=required";
assertThat(result, equalTo(expected)); assertThat(result, equalTo(expected));
} }