From 04d00d8dbb9bcac9c6114cd36c113bdfa8c04b1d Mon Sep 17 00:00:00 2001 From: noidcoffee Date: Sat, 2 May 2026 16:56:33 -0400 Subject: [PATCH 1/4] Replaced Gson with Jackson --- .github/workflows/build.yml | 26 +++++ .gitignore | 1 + build.gradle.kts | 6 +- gradle/libs.versions.toml | 3 + src/main/java/gg/hoglin/sdk/Hoglin.java | 107 ++++++++++++++---- .../sdk/models/analytic/RecordedAnalytic.java | 5 +- .../sdk/models/experiment/ExperimentData.java | 22 ++-- .../models/experiment/ExperimentVariant.java | 12 +- .../sdk/serialization/HoglinAdapter.java | 19 ---- .../serialization/InstantDeserializer.java | 20 ++++ .../sdk/serialization/InstantSerializer.java | 31 ++--- .../gg/hoglin/sdk/task/AnalyticBatchTask.java | 16 ++- 12 files changed, 176 insertions(+), 92 deletions(-) create mode 100644 .github/workflows/build.yml delete mode 100644 src/main/java/gg/hoglin/sdk/serialization/HoglinAdapter.java create mode 100644 src/main/java/gg/hoglin/sdk/serialization/InstantDeserializer.java diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..7aaa584 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,26 @@ +name: Build + +on: + push: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Environment Variables + run: echo "VERSION=${GITHUB_SHA}" >> $GITHUB_ENV + + - name: Build with Gradle Cache + uses: burrunan/gradle-cache-action@v3 + with: + gradle-version: '9.4.0' + arguments: build \ No newline at end of file diff --git a/.gitignore b/.gitignore index 573e847..c3b4ef7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea/ .gradle/ build/ +/gradle.properties diff --git a/build.gradle.kts b/build.gradle.kts index a73cf17..68a2b53 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,4 +1,3 @@ -import org.gradle.internal.serialize.graph.codec import java.net.URI plugins { @@ -9,16 +8,15 @@ plugins { } group = "gg.hoglin" -version = "1.2.1" +version = System.getenv("VERSION") ?: "dev" repositories { mavenCentral() } dependencies { - implementation(libs.gson) implementation(libs.unirest.core) - implementation(libs.unirest.gson) + implementation(libs.unirest.jackson) implementation(libs.slf4j) implementation(libs.commons.codec) compileOnly(libs.lombok) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f484e46..c0a0621 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,6 +7,7 @@ jetbrains-annotations = "24.0.0" autoservice = "1.1.1" slf4j = "2.0.17" commons-codec = "1.20.0" +jackson = "3.1.2" [plugins] shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } @@ -16,7 +17,9 @@ lombok = { module = "org.projectlombok:lombok", version.ref = "lombok" } gson = { module = "com.google.code.gson:gson", version.ref = "gson" } unirest-core = { module = "com.konghq:unirest-java-core", version.ref = "unirest" } unirest-gson = { module = "com.konghq:unirest-modules-gson", version.ref = "unirest" } +unirest-jackson = { module = "com.konghq:unirest-modules-jackson", version.ref = "unirest" } jetbrains-annotations = { module = "org.jetbrains:annotations", version.ref = "jetbrains-annotations" } autoservice = { module = "com.google.auto.service:auto-service", version.ref = "autoservice" } slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" } commons-codec = { module = "commons-codec:commons-codec", version.ref = "commons-codec" } +jackson = { module = "tools.jackson.core:jackson-databind", version.ref = "jackson" } \ No newline at end of file diff --git a/src/main/java/gg/hoglin/sdk/Hoglin.java b/src/main/java/gg/hoglin/sdk/Hoglin.java index b4ea37b..38f5e74 100644 --- a/src/main/java/gg/hoglin/sdk/Hoglin.java +++ b/src/main/java/gg/hoglin/sdk/Hoglin.java @@ -1,8 +1,13 @@ package gg.hoglin.sdk; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonSyntaxException; +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.core.JacksonException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; import gg.hoglin.sdk.models.analytic.Analytic; import gg.hoglin.sdk.models.analytic.NamedAnalytic; import gg.hoglin.sdk.models.analytic.RecordedAnalytic; @@ -11,7 +16,8 @@ import gg.hoglin.sdk.models.experiment.ExperimentEvaluationResponse; import gg.hoglin.sdk.models.visualization.ImportedSnapshotEvaluation; import gg.hoglin.sdk.models.visualization.SnapshotImport; -import gg.hoglin.sdk.serialization.HoglinAdapter; +import gg.hoglin.sdk.serialization.InstantDeserializer; +import gg.hoglin.sdk.serialization.InstantSerializer; import gg.hoglin.sdk.strategy.HoglinRetryStrategy; import gg.hoglin.sdk.task.AnalyticBatchTask; import gg.hoglin.sdk.task.ExperimentFetchTask; @@ -115,10 +121,10 @@ public class Hoglin implements Closeable { private UnirestInstance httpClient; /** - * The Gson instance used for serialization and deserialization + * The Jackson instance used for serialization and deserialization */ @ToString.Exclude - @Builder.Default @NotNull private Gson gson = createDefaultGson(); + @Builder.Default @NotNull private ObjectMapper objectMapper = createDefaultObjectMapper(); /** * The event queue for storing recorded analytics before they are sent to the Hoglin API @@ -202,7 +208,13 @@ public void refreshExperimentCache() { logger.error("Failed to refresh experiment cache: {}", response.getBody()); } - final ExperimentData[] experiments = gson.fromJson(response.getBody(), ExperimentData[].class); + final ExperimentData[] experiments; + try { + experiments = objectMapper.readValue(response.getBody(), ExperimentData[].class); + } catch (JsonProcessingException e) { + logger.error("Failed to deserialize experiment payload: {}", response.getBody(), e); + return; + } experimentCache.clear(); for (final ExperimentData experiment : experiments) { @@ -226,9 +238,19 @@ public Map getExperiments() { final ArrayList> events = new ArrayList<>(eventQueue); eventQueue.clear(); - final HttpResponse response = httpClient.put("/analytics/" + serverKey) - .body(gson.toJson(events)) - .asString(); + final HttpResponse response; + try { + response = httpClient.put("/analytics/" + serverKey) + .body(objectMapper.writeValueAsBytes(events)) + .asString(); + } catch (JsonProcessingException e) { + // If you're a developer making custom events, and this gets thrown, it means your custom tracked analytics are invalid. + // Chances are, you may be using types that don't have built in serialization, + // and if that is the case, just write a custom serializer and register it with the Jackson ObjectMapper instance under the Hoglin loader. + // Thank you for your attention to this matter :) + logger.error("Failed to serialize tracked events", e); + return null; + } if (requeueFailedFlushes && !response.isSuccess()) { trackMany(events); @@ -328,8 +350,14 @@ public HttpResponse importSnapshot(final UUID snapshotId, @Nullable fina throw new IllegalStateException("Attempted to import visualization snapshot whilst closed"); } - final RequestBodyEntity request = httpClient.post("/visualizations/" + serverKey + "/import") - .body(gson.toJson(new SnapshotImport(snapshotId, name, preventDuplicate))); + final RequestBodyEntity request; + try { + request = httpClient.post("/visualizations/" + serverKey + "/import") + .body(objectMapper.writeValueAsBytes(new SnapshotImport(snapshotId, name, preventDuplicate))); + } catch (JsonProcessingException e) { + logger.error("Failed to serialize snapshot", e); + throw new RuntimeException("Snapshot failed to serialize, this should never happen, so there is something very wrong in the code"); + } return request.asString(); } @@ -419,7 +447,12 @@ public boolean isSnapshotImported(final UUID snapshotId) { return new ImportedSnapshotEvaluation(false, null); } - return gson.fromJson(response.getBody(), ImportedSnapshotEvaluation.class); + try { + return objectMapper.readValue(response.getBody(), ImportedSnapshotEvaluation.class); + } catch (JsonProcessingException e) { + logger.error("Failed to deserialize snapshot payload: {}", response.getBody(), e); + throw new RuntimeException(e); + } } /** @@ -496,7 +529,14 @@ public boolean evaluateExperiment(final String experimentId, @NotNull final UUID logger.error("Failed to evaluate experiment {} for player {}: {}", experimentId, playerUUID, constructErrorDescription(response)); return false; } - ExperimentEvaluationResponse expEvalResp = gson.fromJson(response.getBody(), ExperimentEvaluationResponse.class); + + ExperimentEvaluationResponse expEvalResp; + try { + expEvalResp = objectMapper.readValue(response.getBody(), ExperimentEvaluationResponse.class); + } catch (JsonProcessingException e) { + logger.error("Failed to deserialize payload for experiment {} for player {}: {}", experimentId, experimentId, response.getBody(), e); + return false; + } // Add to cache Map map = participationCache.computeIfAbsent(playerUUID, k -> new ConcurrentHashMap<>()); @@ -555,23 +595,24 @@ public HttpResponse evaluateExperimentRaw(final String experimentId, fin public String constructErrorDescription(final HttpResponse response) { final String httpStatus = "(HTTP " + response.getStatus()+ "): "; try { - final ApiErrorResponse error = gson.fromJson(response.getBody(), ApiErrorResponse.class); + final ApiErrorResponse error = objectMapper.readValue(response.getBody(), ApiErrorResponse.class); return httpStatus + error.parsedDescription(); - } catch (final JsonSyntaxException e) { + } catch (final JacksonException e) { return httpStatus + "Received unstructured error response: " + response.getBody(); } catch (final Exception e) { return httpStatus + "An unexpected error occurred while processing the response: " + response.getBody() + " e: " + e.getMessage(); } } - @SuppressWarnings("rawtypes") - private static Gson createDefaultGson() { - final GsonBuilder builder = new GsonBuilder(); - final ServiceLoader adapters = ServiceLoader.load(HoglinAdapter.class, Hoglin.class.getClassLoader()); - for (final HoglinAdapter adapter : adapters) { - builder.registerTypeAdapter(adapter.getType(), adapter); - } - return builder.create(); + private static ObjectMapper createDefaultObjectMapper() { + ObjectMapper objectMapper = new ObjectMapper().setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); + + SimpleModule module = new SimpleModule(); + module.addSerializer(Instant.class, new InstantSerializer()); + module.addDeserializer(Instant.class, new InstantDeserializer()); + objectMapper.registerModule(module); + + return objectMapper; } private static UnirestInstance createDefaultHttpClient(final String baseUrl) { @@ -627,6 +668,24 @@ private HoglinBuilder closed(final boolean closed) { private HoglinBuilder autoFlushTask(final ScheduledFuture autoFlushTask) { return this; } + + /** + * Helper for adding custom serializers to the Jackson instance. + * The idea is that people are incentivized to not use a custom Jackson instance. + * + * @param serializer Object serializer + * @param deserializer Object deserializer + * @return This instance + * @param Class type + */ + public HoglinBuilder addCustomSerializer(JsonSerializer serializer, JsonDeserializer deserializer) { + SimpleModule module = new SimpleModule(); + module.addSerializer(serializer); + module.addDeserializer(serializer.handledType(), deserializer); + + this.objectMapper$value.registerModule(module); + return this; + } } } diff --git a/src/main/java/gg/hoglin/sdk/models/analytic/RecordedAnalytic.java b/src/main/java/gg/hoglin/sdk/models/analytic/RecordedAnalytic.java index fe98540..f4a31ae 100644 --- a/src/main/java/gg/hoglin/sdk/models/analytic/RecordedAnalytic.java +++ b/src/main/java/gg/hoglin/sdk/models/analytic/RecordedAnalytic.java @@ -1,6 +1,7 @@ package gg.hoglin.sdk.models.analytic; -import com.google.gson.annotations.SerializedName; +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import lombok.experimental.Accessors; @@ -13,7 +14,7 @@ @Data @Accessors(fluent = true) public class RecordedAnalytic { - @SerializedName("event_type") private final String eventType; + @JsonProperty("event_type") private final String eventType; private final Instant timestamp; private final T properties; } diff --git a/src/main/java/gg/hoglin/sdk/models/experiment/ExperimentData.java b/src/main/java/gg/hoglin/sdk/models/experiment/ExperimentData.java index e4d0421..b9ebfb0 100644 --- a/src/main/java/gg/hoglin/sdk/models/experiment/ExperimentData.java +++ b/src/main/java/gg/hoglin/sdk/models/experiment/ExperimentData.java @@ -1,6 +1,6 @@ package gg.hoglin.sdk.models.experiment; -import com.google.gson.annotations.SerializedName; +import com.fasterxml.jackson.annotation.JsonProperty; import gg.hoglin.sdk.Hoglin; import lombok.Data; import org.apache.commons.codec.digest.MurmurHash3; @@ -21,14 +21,14 @@ public class ExperimentData { /** Experiment triggers */ public enum Trigger { - @SerializedName("join") + @JsonProperty("join") JOIN, - @SerializedName("first_join") + @JsonProperty("first_join") FIRST_JOIN, - @SerializedName("purchase") + @JsonProperty("purchase") PURCHASE, // This type is not yet implemented on the API side - @SerializedName("custom") + @JsonProperty("custom") CUSTOM, } @@ -42,17 +42,17 @@ public enum Trigger { /** The date this experiment was created */ @NotNull - @SerializedName("created_at") + @JsonProperty("created_at") private final Instant createdAt; /** The internal numerical ID of the server this experiment is associated with */ @NotNull - @SerializedName("server_id") + @JsonProperty("server_id") private final Integer serverId; /** The alphanumerical identifier for this experiment - used when querying */ @NotNull - @SerializedName("experiment_id") + @JsonProperty("experiment_id") private final String experimentId; /** A description explaining what this experiment is aimed to accomplish */ @@ -65,7 +65,7 @@ public enum Trigger { /** A percentage of users that should get this experiment */ @NotNull - @SerializedName("rollout_percentage") + @JsonProperty("rollout_percentage") private final Integer rolloutPercentage; /** An allowlist of UUIDs that have access to this experiment */ @@ -74,12 +74,12 @@ public enum Trigger { /** The trigger for the experiment */ @NotNull - @SerializedName("experiment_trigger") + @JsonProperty("experiment_trigger") private final Trigger trigger; /** The actions taken for variants of the experiment */ @NotNull - @SerializedName("experiment_variants") + @JsonProperty("experiment_variants") private final Map variants; /** diff --git a/src/main/java/gg/hoglin/sdk/models/experiment/ExperimentVariant.java b/src/main/java/gg/hoglin/sdk/models/experiment/ExperimentVariant.java index d927b16..9a03832 100644 --- a/src/main/java/gg/hoglin/sdk/models/experiment/ExperimentVariant.java +++ b/src/main/java/gg/hoglin/sdk/models/experiment/ExperimentVariant.java @@ -1,6 +1,6 @@ package gg.hoglin.sdk.models.experiment; -import com.google.gson.annotations.SerializedName; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import org.jetbrains.annotations.NotNull; @@ -13,9 +13,9 @@ public class ExperimentVariant { * The variants of the experiment, which at the moment are only control and exposed (A / B) */ public enum Variant { - @SerializedName("control") + @JsonProperty("control") CONTROL, - @SerializedName("exposed") + @JsonProperty("exposed") EXPOSED, } @@ -24,11 +24,11 @@ public enum Variant { * At the moment, the system is designed to have only one action per variant. */ public enum Action { - @SerializedName("run_console_command") + @JsonProperty("run_console_command") RUN_CONSOLE_COMMAND, - @SerializedName("run_command_as_player") + @JsonProperty("run_command_as_player") RUN_COMMAND_AS_PLAYER, - @SerializedName("send_message") + @JsonProperty("send_message") SEND_MESSAGE, } diff --git a/src/main/java/gg/hoglin/sdk/serialization/HoglinAdapter.java b/src/main/java/gg/hoglin/sdk/serialization/HoglinAdapter.java deleted file mode 100644 index 600c228..0000000 --- a/src/main/java/gg/hoglin/sdk/serialization/HoglinAdapter.java +++ /dev/null @@ -1,19 +0,0 @@ -package gg.hoglin.sdk.serialization; - -import com.google.gson.TypeAdapter; - -/** - * Interface for Hoglin serialization adapters. Used for autoservicing of GSON adapters. - * - * @see InstantSerializer - * @param the type of object this adapter handles - */ -public abstract class HoglinAdapter extends TypeAdapter { - - /** - * Returns the type of object this adapter handles. - * @return the class type of the object - */ - public abstract Class getType(); - -} diff --git a/src/main/java/gg/hoglin/sdk/serialization/InstantDeserializer.java b/src/main/java/gg/hoglin/sdk/serialization/InstantDeserializer.java new file mode 100644 index 0000000..62da577 --- /dev/null +++ b/src/main/java/gg/hoglin/sdk/serialization/InstantDeserializer.java @@ -0,0 +1,20 @@ +package gg.hoglin.sdk.serialization; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; + +import java.io.IOException; +import java.time.Instant; + +public class InstantDeserializer extends JsonDeserializer { + + @Override + public Instant deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + if (p.getCurrentToken() == JsonToken.VALUE_NULL) { + return null; + } + return Instant.parse(p.getValueAsString()); + } +} diff --git a/src/main/java/gg/hoglin/sdk/serialization/InstantSerializer.java b/src/main/java/gg/hoglin/sdk/serialization/InstantSerializer.java index 0084c3d..0be0fe5 100644 --- a/src/main/java/gg/hoglin/sdk/serialization/InstantSerializer.java +++ b/src/main/java/gg/hoglin/sdk/serialization/InstantSerializer.java @@ -1,35 +1,20 @@ package gg.hoglin.sdk.serialization; -import com.google.auto.service.AutoService; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; import java.time.Instant; -@AutoService(HoglinAdapter.class) -public class InstantSerializer extends HoglinAdapter { +public class InstantSerializer extends JsonSerializer { + @Override - public void write(final JsonWriter out, final Instant value) throws IOException { + public void serialize(Instant value, JsonGenerator gen, SerializerProvider serializers) throws IOException { if (value == null) { - out.nullValue(); + gen.writeNull(); } else { - out.value(value.toString()); - } - } - - @Override - public Instant read(final JsonReader reader) throws IOException { - if (reader.peek() == JsonToken.NULL) { - reader.nextNull(); - return null; + gen.writeString(value.toString()); } - return Instant.parse(reader.nextString()); - } - - @Override - public Class getType() { - return Instant.class; } } diff --git a/src/main/java/gg/hoglin/sdk/task/AnalyticBatchTask.java b/src/main/java/gg/hoglin/sdk/task/AnalyticBatchTask.java index cde538b..9bcc522 100644 --- a/src/main/java/gg/hoglin/sdk/task/AnalyticBatchTask.java +++ b/src/main/java/gg/hoglin/sdk/task/AnalyticBatchTask.java @@ -1,5 +1,6 @@ package gg.hoglin.sdk.task; +import com.fasterxml.jackson.core.JsonProcessingException; import gg.hoglin.sdk.Hoglin; import gg.hoglin.sdk.models.analytic.RecordedAnalytic; import lombok.RequiredArgsConstructor; @@ -34,9 +35,15 @@ public void run() { } CompletableFuture.supplyAsync(() -> - hoglin.httpClient().put("/analytics/" + hoglin.serverKey()) - .body(hoglin.gson().toJson(events)) - .asString(), hoglin.executor() + { + try { + return hoglin.httpClient().put("/analytics/" + hoglin.serverKey()) + .body(hoglin.objectMapper().writeValueAsBytes(events)) + .asString(); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + }, hoglin.executor() ).thenAccept(response -> { if (response.isSuccess()) return; if (hoglin.requeueFailedFlushes()) { @@ -45,6 +52,9 @@ public void run() { } else { logger.error("Failed to flush {} queued events: {}", take, hoglin.constructErrorDescription(response)); } + }).exceptionally(e -> { + logger.error("Failed to flush {} queued events, serialization failure, will not requeue: {}", take, e.getMessage(), e); + return null; }); } } From 0da337a9856109303747232225a8e3b510dbea21 Mon Sep 17 00:00:00 2001 From: noidcoffee Date: Sat, 2 May 2026 17:07:33 -0400 Subject: [PATCH 2/4] Suppress doc errors (also moved lombok to gradle plugin idk) --- build.gradle.kts | 4 ++-- gradle/libs.versions.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 68a2b53..44cffe4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,6 +5,7 @@ plugins { `maven-publish` alias(libs.plugins.shadow) + alias(libs.plugins.lombok) } group = "gg.hoglin" @@ -19,10 +20,8 @@ dependencies { implementation(libs.unirest.jackson) implementation(libs.slf4j) implementation(libs.commons.codec) - compileOnly(libs.lombok) compileOnly(libs.jetbrains.annotations) compileOnly(libs.autoservice) - annotationProcessor(libs.lombok) annotationProcessor(libs.autoservice) } @@ -34,6 +33,7 @@ java { tasks.javadoc { val options = options as StandardJavadocDocletOptions options.addStringOption("tag", "apiNote:a:API Note:") + options.addStringOption("Xdoclint:none", "-quiet") // to really suppress all the doc errors // Needed to suppress errors caused by Lombok autogenerated members isFailOnError = false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c0a0621..9c6ed32 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] shadow = "8.3.0" -lombok = "1.18.38" +lombok = "9.5.0" gson = "2.13.1" unirest = "4.4.5" jetbrains-annotations = "24.0.0" @@ -11,9 +11,9 @@ jackson = "3.1.2" [plugins] shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } +lombok = { id = "io.freefair.lombok", version.ref = "lombok" } [libraries] -lombok = { module = "org.projectlombok:lombok", version.ref = "lombok" } gson = { module = "com.google.code.gson:gson", version.ref = "gson" } unirest-core = { module = "com.konghq:unirest-java-core", version.ref = "unirest" } unirest-gson = { module = "com.konghq:unirest-modules-gson", version.ref = "unirest" } From 8981dc6c5f523f9a559069d90b61b8ba364e8aa5 Mon Sep 17 00:00:00 2001 From: noidcoffee Date: Mon, 11 May 2026 11:37:44 -0400 Subject: [PATCH 3/4] Add build and release action --- .github/workflows/release.yml | 44 +++++++++++++++++++++++++++++++++++ build.gradle.kts | 2 +- 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..e1a92ae --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,44 @@ +name: Build and Release + +on: + push: + tags: + - "*" + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Environment Variables + run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + + - name: Build with Gradle Cache + uses: burrunan/gradle-cache-action@v3 + with: + gradle-version: '9.4.0' + arguments: | + build + publish + env: + REPO_URL: ${{ secrets.MAVEN_URL }} + REPO_USER: ${{ secrets.MAVEN_USERNAME }} + REPO_PASS: ${{ secrets.MAVEN_PASSWORD }} + + - name: Publish GitHub Release + id: github_release + uses: softprops/action-gh-release@v2 + with: + files: build/SDK-${GITHUB_REF#refs/tags/}-*.jar + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/build.gradle.kts b/build.gradle.kts index 44cffe4..d1a82aa 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -58,7 +58,7 @@ publishing { repositories { maven { name = "Hoglin" - url = URI("https://maven.hoglin.gg/releases") + url = URI(findProperty("repo.waypoint.url") as String? ?: System.getenv("REPO_URL")) credentials { username = findProperty("repo.waypoint.username") as String? ?: System.getenv("REPO_USER") password = findProperty("repo.waypoint.password") as String? ?: System.getenv("REPO_PASS") From 181cf2209c6a20c10911e2f875383a398a4dcaf2 Mon Sep 17 00:00:00 2001 From: noidcoffee Date: Mon, 11 May 2026 11:40:09 -0400 Subject: [PATCH 4/4] Add envvars to test build so build gradle loads properly --- .github/workflows/build.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7aaa584..cc0bd0b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,4 +23,8 @@ jobs: uses: burrunan/gradle-cache-action@v3 with: gradle-version: '9.4.0' - arguments: build \ No newline at end of file + arguments: build + env: + REPO_URL: ${{ secrets.MAVEN_URL }} + REPO_USER: ${{ secrets.MAVEN_USERNAME }} + REPO_PASS: ${{ secrets.MAVEN_PASSWORD }} \ No newline at end of file