From 3b1b29036f42a59e1d7fd742e0a5deef2baf0c7e Mon Sep 17 00:00:00 2001 From: Neelkanth Kaushik Date: Mon, 12 May 2025 22:26:35 +0530 Subject: [PATCH 1/9] This commit will update the okhttp version to 4.12.0 in pom.xml. This update is done to fix the Github issue #503. (#505) * This commit will update the okhttp version to 4.12.0 in pom.xml. okhttp-4.12.0 uses okio-3.6.0. This update is done to fix the Github issue #503. * This commit upgrades Kotlin from 1.7.20 to 1.9.0 in pom.xml. This is done to address the CI workflow errors because okhttp-4.12.0 is pulling okio-3.6.0 which is compiled using Kotlin 1.9.0 but the our SDK's pom.xml is expecting Kotlin metadata compiled with Kotlin 1.7.20. --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9a716e1f..39ce738d 100644 --- a/pom.xml +++ b/pom.xml @@ -28,14 +28,14 @@ UTF-8 8 - 1.7.20 + 1.9.0 2.27.2 2.9.0 1.10.1 3.0.1 2.9.1 - 4.10.0 + 4.12.0 4.10.0 33.3.1-jre 1.0.0 From fca4a60a23a71d33cd9f17e59012b919007b1f75 Mon Sep 17 00:00:00 2001 From: Artem Shubovych Date: Tue, 13 May 2025 03:05:53 +1000 Subject: [PATCH 2/9] Bump retrofit to fix CVEe (#504) Co-authored-by: Michael Grosse Huelsewiesche --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 39ce738d..a324471e 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ 8 1.9.0 2.27.2 - 2.9.0 + 2.11.0 1.10.1 3.0.1 From c57a583b235c9a4dcdb5d0d298dc4b4533ce3190 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 May 2025 15:20:06 -0400 Subject: [PATCH 3/9] Bump com.google.guava:guava from 33.3.1-jre to 33.4.0-jre (#500) Bumps [com.google.guava:guava](https://github.com/google/guava) from 33.3.1-jre to 33.4.0-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Michael Grosse Huelsewiesche --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a324471e..8d0424e9 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,7 @@ 2.9.1 4.12.0 4.10.0 - 33.3.1-jre + 33.4.0-jre 1.0.0 2.7.5 0.6.0.20150202 From 82dfde29ef78fd8c1aa4175e04d1a4a6af6dda2a Mon Sep 17 00:00:00 2001 From: Neelkanth Kaushik Date: Wed, 3 Dec 2025 05:27:57 +0530 Subject: [PATCH 4/9] Patch for Github issue #524 (#526) * Patch for Github issue #524 --- .../analytics/internal/AnalyticsClient.java | 105 ++++++++++++++++-- 1 file changed, 95 insertions(+), 10 deletions(-) diff --git a/analytics/src/main/java/com/segment/analytics/internal/AnalyticsClient.java b/analytics/src/main/java/com/segment/analytics/internal/AnalyticsClient.java index f7560004..2430cd1e 100644 --- a/analytics/src/main/java/com/segment/analytics/internal/AnalyticsClient.java +++ b/analytics/src/main/java/com/segment/analytics/internal/AnalyticsClient.java @@ -25,7 +25,9 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; @@ -42,6 +44,8 @@ public class AnalyticsClient { private static final Charset ENCODING = StandardCharsets.UTF_8; private Gson gsonInstance; private static final String instanceId = UUID.randomUUID().toString(); + private static final int WAIT_FOR_THREAD_COMPLETE_S = 5; + private static final int TERMINATION_TIMEOUT_S = 1; static { Map library = new LinkedHashMap<>(); @@ -67,6 +71,7 @@ public class AnalyticsClient { private final ScheduledExecutorService flushScheduler; private final AtomicBoolean isShutDown; private final String writeKey; + private volatile Future looperFuture; public static AnalyticsClient create( HttpUrl uploadUrl, @@ -130,7 +135,9 @@ public AnalyticsClient( this.currentQueueSizeInBytes = 0; - if (!isShutDown.get()) looperExecutor.submit(new Looper()); + if (!isShutDown.get()) { + this.looperFuture = looperExecutor.submit(new Looper()); + } flushScheduler = Executors.newScheduledThreadPool(1, threadFactory); flushScheduler.scheduleAtFixedRate( @@ -218,6 +225,8 @@ public void shutdown() { // we can shutdown the flush scheduler without worrying flushScheduler.shutdownNow(); + // Wait for the looper to complete processing before shutting down executors + waitForLooperCompletion(); shutdownAndWait(looperExecutor, "looper"); shutdownAndWait(networkExecutor, "network"); @@ -226,19 +235,81 @@ public void shutdown() { } } + /** + * Wait for the looper to complete processing all messages before proceeding with shutdown. This + * prevents the race condition where the network executor is shut down before the looper finishes + * submitting all batches. + */ + private void waitForLooperCompletion() { + if (looperFuture != null) { + try { + // Wait for the looper to complete processing the STOP message and finish + // Use a reasonable timeout to avoid hanging indefinitely + looperFuture.get(WAIT_FOR_THREAD_COMPLETE_S, TimeUnit.SECONDS); + log.print(VERBOSE, "Looper completed successfully."); + } catch (Exception e) { + log.print(ERROR, e, "Error waiting for looper to complete."); + // Cancel the looper if it's taking too long or if there's an error + if (!looperFuture.isDone()) { + looperFuture.cancel(true); + log.print(VERBOSE, "Looper was cancelled due to timeout or error."); + } + } + } + } + public void shutdownAndWait(ExecutorService executor, String name) { + boolean isLooperExecutor = name != null && name.equalsIgnoreCase("looper"); try { executor.shutdown(); - final boolean executorTerminated = executor.awaitTermination(1, TimeUnit.SECONDS); - - log.print( - VERBOSE, - "%s executor %s.", - name, - executorTerminated ? "terminated normally" : "timed out"); + boolean terminated = executor.awaitTermination(TERMINATION_TIMEOUT_S, TimeUnit.SECONDS); + if (terminated) { + log.print(VERBOSE, "%s executor terminated normally.", name); + return; + } + if (isLooperExecutor) { // Handle looper - network should finish on its own + // not terminated within timeout -> force shutdown + log.print( + VERBOSE, + "%s did not terminate in %d seconds; requesting shutdownNow().", + name, + TERMINATION_TIMEOUT_S); + List dropped = executor.shutdownNow(); // interrupts running tasks + log.print( + VERBOSE, + "%s shutdownNow returned %d queued tasks that never started.", + name, + dropped.size()); + + // optional short wait to give interrupted tasks a chance to exit + boolean terminatedAfterForce = + executor.awaitTermination(TERMINATION_TIMEOUT_S, TimeUnit.SECONDS); + log.print( + VERBOSE, + "%s executor %s after shutdownNow().", + name, + terminatedAfterForce ? "terminated" : "still running (did not terminate)"); + + if (!terminatedAfterForce) { + // final warning — investigate tasks that ignore interrupts + log.print( + ERROR, + "%s executor still did not terminate; tasks may be ignoring interrupts.", + name); + } + } } catch (InterruptedException e) { + // Preserve interrupt status and attempt forceful shutdown log.print(ERROR, e, "Interrupted while stopping %s executor.", name); Thread.currentThread().interrupt(); + if (isLooperExecutor) { + List dropped = executor.shutdownNow(); + log.print( + VERBOSE, + "%s shutdownNow invoked after interrupt; %d tasks returned.", + name, + dropped.size()); + } } } @@ -299,8 +370,22 @@ public void run() { "Batching %s message(s) into batch %s.", batch.batch().size(), batch.sequence()); - networkExecutor.submit( - BatchUploadTask.create(AnalyticsClient.this, batch, maximumRetries)); + try { + networkExecutor.submit( + BatchUploadTask.create(AnalyticsClient.this, batch, maximumRetries)); + } catch (RejectedExecutionException e) { + log.print( + ERROR, + e, + "Failed to submit batch %s to network executor during shutdown. Batch will be lost.", + batch.sequence()); + // Notify callbacks about the failure + for (Message msg : batch.batch()) { + for (Callback callback : callbacks) { + callback.failure(msg, e); + } + } + } currentBatchSize.set(0); messages.clear(); From 4326150f0b973eea2a8bf14ca5cbc06e455bf61c Mon Sep 17 00:00:00 2001 From: Neelkanth Kaushik Date: Wed, 3 Dec 2025 05:36:09 +0530 Subject: [PATCH 5/9] Applying patch for LIBRARIES-2720 (#517) * Created ISO8601InstantAdapter.java file * Fixed CI errors * Spotless Fix * Changed version in pom.xml * Revert - Changed version in pom.xml because of failing test cases --------- Co-authored-by: Michael Grosse Huelsewiesche --- .../analytics/gson/ISO8601InstantAdapter.java | 37 +++++++++++++++++++ .../segment/analytics/gson/Iso8601Utils.java | 7 ++++ .../java/com/segment/analytics/Analytics.java | 3 ++ 3 files changed, 47 insertions(+) create mode 100644 analytics-core/src/main/java/com/segment/analytics/gson/ISO8601InstantAdapter.java diff --git a/analytics-core/src/main/java/com/segment/analytics/gson/ISO8601InstantAdapter.java b/analytics-core/src/main/java/com/segment/analytics/gson/ISO8601InstantAdapter.java new file mode 100644 index 00000000..c21638ad --- /dev/null +++ b/analytics-core/src/main/java/com/segment/analytics/gson/ISO8601InstantAdapter.java @@ -0,0 +1,37 @@ +package com.segment.analytics.gson; + +import com.google.gson.*; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.lang.reflect.Type; +import java.time.Instant; + +/** + * A {@link JsonSerializer} that formats {@link Instant} objects into iso8601 formatted strings, and + * {@link JsonDeserializer} that parses iso8601 formatted strings into {@link Instant} objects. + */ +public class ISO8601InstantAdapter extends TypeAdapter + implements JsonSerializer, JsonDeserializer { + @Override + public JsonElement serialize(Instant src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(Iso8601Utils.format(src)); // ISO 8601 format + } + + @Override + public Instant deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + return Instant.parse(json.getAsString()); + } + + @Override + public void write(JsonWriter out, Instant value) throws IOException { + out.value(value == null ? null : value.toString()); + } + + @Override + public Instant read(JsonReader in) throws IOException { + String str = in.nextString(); + return str == null ? null : Instant.parse(str); + } +} diff --git a/analytics-core/src/main/java/com/segment/analytics/gson/Iso8601Utils.java b/analytics-core/src/main/java/com/segment/analytics/gson/Iso8601Utils.java index 9504a641..95ca5286 100644 --- a/analytics-core/src/main/java/com/segment/analytics/gson/Iso8601Utils.java +++ b/analytics-core/src/main/java/com/segment/analytics/gson/Iso8601Utils.java @@ -16,6 +16,7 @@ package com.segment.analytics.gson; import com.google.gson.JsonParseException; +import java.time.Instant; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; @@ -277,4 +278,10 @@ private static int indexOfNonDigit(String string, int offset) { } return string.length(); } + + /** Returns {@code date} formatted as yyyy-MM-ddThh:mm:ss.sssZ */ + static String format(Instant instant) { + // Format the instant + return String.valueOf(instant.getEpochSecond()); + } } diff --git a/analytics/src/main/java/com/segment/analytics/Analytics.java b/analytics/src/main/java/com/segment/analytics/Analytics.java index 81af36c7..9b88de8c 100644 --- a/analytics/src/main/java/com/segment/analytics/Analytics.java +++ b/analytics/src/main/java/com/segment/analytics/Analytics.java @@ -4,11 +4,13 @@ import com.google.gson.GsonBuilder; import com.segment.analytics.gson.AutoValueAdapterFactory; import com.segment.analytics.gson.ISO8601DateAdapter; +import com.segment.analytics.gson.ISO8601InstantAdapter; import com.segment.analytics.http.SegmentService; import com.segment.analytics.internal.AnalyticsClient; import com.segment.analytics.internal.AnalyticsVersion; import com.segment.analytics.messages.Message; import com.segment.analytics.messages.MessageBuilder; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -362,6 +364,7 @@ public Analytics build() { gsonBuilder .registerTypeAdapterFactory(new AutoValueAdapterFactory()) + .registerTypeAdapter(Instant.class, new ISO8601InstantAdapter()) .registerTypeAdapter(Date.class, new ISO8601DateAdapter()); Gson gson = gsonBuilder.create(); From b00f95156f5013f68ad29ce8a29e6c4af2519a46 Mon Sep 17 00:00:00 2001 From: Michael Grosse Huelsewiesche Date: Tue, 2 Dec 2025 19:16:46 -0500 Subject: [PATCH 6/9] Updating changelog for 3.5.2 release (#506) * Updating changelog for 3.5.2 release * [maven-release-plugin] prepare release analytics-parent-3.5.2 * [maven-release-plugin] prepare for next development iteration --- CHANGELOG.md | 5 ++++- analytics-cli/pom.xml | 2 +- analytics-core/pom.xml | 2 +- analytics-sample/pom.xml | 2 +- analytics-spring-boot-starter/pom.xml | 2 +- analytics/pom.xml | 2 +- pom.xml | 2 +- 7 files changed, 10 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fa7e873..3bfb6679 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ -# Verion 3.5.1 (Feb 21, 2024) +# Version 3.5.2 (May 12, 2025) +- [Chore] Depenency upgrades + +# Version 3.5.1 (Feb 21, 2024) - [Chore] Dependency upgrades - [New](https://github.com/segmentio/analytics-java/pull/471) BlockingFlush, deregister parties upon message completion - [New](https://github.com/segmentio/analytics-java/pull/476) Added wk size to message size calc along with a buffer diff --git a/analytics-cli/pom.xml b/analytics-cli/pom.xml index 0f474c60..d4341f18 100644 --- a/analytics-cli/pom.xml +++ b/analytics-cli/pom.xml @@ -6,7 +6,7 @@ analytics-parent com.segment.analytics.java - 3.5.2-SNAPSHOT + 3.5.3-SNAPSHOT analytics-cli diff --git a/analytics-core/pom.xml b/analytics-core/pom.xml index b3ff7932..f3dc3d23 100644 --- a/analytics-core/pom.xml +++ b/analytics-core/pom.xml @@ -6,7 +6,7 @@ com.segment.analytics.java analytics-parent - 3.5.2-SNAPSHOT + 3.5.3-SNAPSHOT analytics-core diff --git a/analytics-sample/pom.xml b/analytics-sample/pom.xml index 273519df..8151af27 100644 --- a/analytics-sample/pom.xml +++ b/analytics-sample/pom.xml @@ -6,7 +6,7 @@ analytics-parent com.segment.analytics.java - 3.5.2-SNAPSHOT + 3.5.3-SNAPSHOT analytics-sample diff --git a/analytics-spring-boot-starter/pom.xml b/analytics-spring-boot-starter/pom.xml index 6e01b6ce..d5d70478 100644 --- a/analytics-spring-boot-starter/pom.xml +++ b/analytics-spring-boot-starter/pom.xml @@ -6,7 +6,7 @@ com.segment.analytics.java analytics-parent - 3.5.2-SNAPSHOT + 3.5.3-SNAPSHOT analytics-spring-boot-starter diff --git a/analytics/pom.xml b/analytics/pom.xml index 127fd658..0ef7606b 100644 --- a/analytics/pom.xml +++ b/analytics/pom.xml @@ -6,7 +6,7 @@ com.segment.analytics.java analytics-parent - 3.5.2-SNAPSHOT + 3.5.3-SNAPSHOT analytics diff --git a/pom.xml b/pom.xml index 8d0424e9..22316d4b 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ com.segment.analytics.java analytics-parent - 3.5.2-SNAPSHOT + 3.5.3-SNAPSHOT pom Analytics for Java (Parent) The hassle-free way to add analytics to your Android app. From abb47619e36be7b28bbc979df64ea140701c418b Mon Sep 17 00:00:00 2001 From: Michael Grosse Huelsewiesche Date: Wed, 3 Dec 2025 12:52:00 -0500 Subject: [PATCH 7/9] Updating changelog for 3.5.3 and fixing verify errors (#528) --- CHANGELOG.md | 4 ++++ .../main/java/com/segment/analytics/http/UploadResponse.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bfb6679..32676a9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# Version 3.5.3 (Dec 3, 2025) +- [New](https://github.com/segmentio/analytics-java/pull/526) Improved shutdown process +- [New](https://github.com/segmentio/analytics-java/pull/517) Support (de)serializing Instant objects to support newer java versions + # Version 3.5.2 (May 12, 2025) - [Chore] Depenency upgrades diff --git a/analytics-core/src/main/java/com/segment/analytics/http/UploadResponse.java b/analytics-core/src/main/java/com/segment/analytics/http/UploadResponse.java index e91be413..ed41a2ca 100644 --- a/analytics-core/src/main/java/com/segment/analytics/http/UploadResponse.java +++ b/analytics-core/src/main/java/com/segment/analytics/http/UploadResponse.java @@ -7,4 +7,8 @@ @AutoGson public abstract class UploadResponse { public abstract boolean success(); + + public static UploadResponse create(boolean success) { + return new AutoValue_UploadResponse(success); + } } From 1eb13a35b0ebef8278a804fff50e8ff7d117eb22 Mon Sep 17 00:00:00 2001 From: Michael Grosse Huelsewiesche Date: Mon, 12 Jan 2026 12:09:40 -0500 Subject: [PATCH 8/9] Release/3.5.4 (#530) * Updating release for new sonatype repository * Updating changelog * Update release plugin (#529) * Changing release plugin * [maven-release-plugin] prepare release analytics-parent-3.5.4 * [maven-release-plugin] prepare for next development iteration * Moving gpg signing to release deploy --- .buildscript/deploy_snapshot.sh | 2 +- .buildscript/settings.xml | 7 +- .gitignore | 4 +- CHANGELOG.md | 3 + RELEASING.md | 2 +- analytics-cli/pom.xml | 32 +- .../src/main/kotlin/cli/JavadocStub.java | 8 + analytics-core/effective-analytics-core.xml | 633 ++++++++++++++++++ analytics-core/pom.xml | 52 +- analytics-sample/pom.xml | 30 +- analytics-spring-boot-starter/pom.xml | 30 +- analytics/pom.xml | 41 +- pom.xml | 81 ++- 13 files changed, 896 insertions(+), 29 deletions(-) create mode 100644 analytics-cli/src/main/kotlin/cli/JavadocStub.java create mode 100644 analytics-core/effective-analytics-core.xml diff --git a/.buildscript/deploy_snapshot.sh b/.buildscript/deploy_snapshot.sh index e02d3c73..2d98a91b 100755 --- a/.buildscript/deploy_snapshot.sh +++ b/.buildscript/deploy_snapshot.sh @@ -23,6 +23,6 @@ elif [ "$CIRCLE_BRANCH" != "$BRANCH" ]; then echo "Skipping snapshot deployment: wrong branch. Expected '$BRANCH' but was '$CIRCLE_BRANCH'." else echo "Deploying snapshot..." - mvn clean source:jar javadoc:jar deploy --settings=".buildscript/settings.xml" -Dmaven.test.skip=true + mvn clean source:jar javadoc:jar deploy --settings=".buildscript/settings.xml" -Dmaven.test.skip=true -Dgpg.skip=true echo "Snapshot deployed!" fi diff --git a/.buildscript/settings.xml b/.buildscript/settings.xml index 97ec83d7..81d298ff 100644 --- a/.buildscript/settings.xml +++ b/.buildscript/settings.xml @@ -1,12 +1,7 @@ - sonatype-nexus-snapshots - ${env.CI_DEPLOY_USERNAME} - ${env.CI_DEPLOY_PASSWORD} - - - sonatype-nexus-staging + central ${env.CI_DEPLOY_USERNAME} ${env.CI_DEPLOY_PASSWORD} diff --git a/.gitignore b/.gitignore index ea323992..4041df6b 100644 --- a/.gitignore +++ b/.gitignore @@ -128,4 +128,6 @@ atlassian-ide-plugin.xml .classpath .project .settings/ -.factorypath \ No newline at end of file +.factorypath + +.vscode diff --git a/CHANGELOG.md b/CHANGELOG.md index 32676a9e..74b4fe12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +# Version 3.5.4 (Dec 5, 2025) +- Updating release for new sonatype repository + # Version 3.5.3 (Dec 3, 2025) - [New](https://github.com/segmentio/analytics-java/pull/526) Improved shutdown process - [New](https://github.com/segmentio/analytics-java/pull/517) Support (de)serializing Instant objects to support newer java versions diff --git a/RELEASING.md b/RELEASING.md index 744ce63c..5d59be70 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -5,4 +5,4 @@ Releasing 2. Update the `CHANGELOG.md` for the impending release. 3. `mvn clean release:clean` 4. `mvn release:prepare release:perform` - 5. Visit [Sonatype Nexus](https://oss.sonatype.org/) and promote the artifact. + 4. Visit the [Maven Central Portal](https://central.sonatype.com/publishing/deployments) to review and publish the release. diff --git a/analytics-cli/pom.xml b/analytics-cli/pom.xml index d4341f18..67e1d4b9 100644 --- a/analytics-cli/pom.xml +++ b/analytics-cli/pom.xml @@ -6,16 +6,45 @@ analytics-parent com.segment.analytics.java - 3.5.3-SNAPSHOT + 3.5.5-SNAPSHOT + com.segment.analytics.java analytics-cli + 3.5.5-SNAPSHOT Analytics Java CLI + Command-line interface for Segment Analytics for Java. + https://github.com/segmentio/analytics-java + + + + The MIT License (MIT) + http://opensource.org/licenses/MIT + + + + + https://github.com/segmentio/analytics-java/ + scm:git:https://github.com/segmentio/analytics-java.git + scm:git:git@github.com:segmentio/analytics-java.git + analytics-parent-3.5.4 + + + + + segment + Segment + Segment + https://segment.com + + + org.jetbrains.kotlin kotlin-stdlib + ${kotlin.version} com.segment.analytics.java @@ -25,6 +54,7 @@ com.offbytwo docopt + ${docopt.version} diff --git a/analytics-cli/src/main/kotlin/cli/JavadocStub.java b/analytics-cli/src/main/kotlin/cli/JavadocStub.java new file mode 100644 index 00000000..403beaa7 --- /dev/null +++ b/analytics-cli/src/main/kotlin/cli/JavadocStub.java @@ -0,0 +1,8 @@ +package cli; + +/** + * Placeholder class to generate a Javadoc JAR for the CLI artifact. + */ +public final class JavadocStub { + private JavadocStub() {} +} diff --git a/analytics-core/effective-analytics-core.xml b/analytics-core/effective-analytics-core.xml new file mode 100644 index 00000000..3cb09524 --- /dev/null +++ b/analytics-core/effective-analytics-core.xml @@ -0,0 +1,633 @@ + + + + + + + + + + + + + + + 4.0.0 + + com.segment.analytics.java + analytics-parent + 3.5.4 + + com.segment.analytics.java + analytics-core + 3.5.5-SNAPSHOT + Analytics for Java (Core) + Core runtime for Segment Analytics for Java. + https://github.com/segmentio/analytics-java + + + The MIT License (MIT) + http://opensource.org/licenses/MIT + + + + + segment + Segment + Segment + https://segment.com + + + + scm:git:https://github.com/segmentio/analytics-java.git + scm:git:git@github.com:segmentio/analytics-java.git + analytics-parent-3.5.4 + https://github.com/segmentio/analytics-java/ + + + GitHub Issues + https://github.com/segmentio/analytics-java/issues + + + 3.24.2 + 1.10.1 + 1.0.0 + 1.2.0 + 0.6.0.20150202 + 3.0.1 + 2.9.1 + 33.4.0-jre + 8 + 4.13.2 + 1.9.0 + 4.10.0 + true + 4.11.0 + 4.12.0 + UTF-8 + 2.11.0 + 2.27.2 + 2.7.5 + + + + + com.squareup.retrofit2 + retrofit + 2.11.0 + + + com.squareup.retrofit2 + converter-gson + 2.9.0 + + + com.squareup.retrofit2 + retrofit-mock + 2.11.0 + + + com.google.auto.value + auto-value + 1.10.1 + provided + + + com.google.auto.value + auto-value-annotations + 1.10.1 + + + com.google.code.findbugs + findbugs + 3.0.1 + + + com.google.code.gson + gson + 2.9.1 + + + com.squareup.okhttp3 + okhttp + 4.12.0 + + + com.squareup.okhttp3 + logging-interceptor + 4.10.0 + + + com.google.guava + guava + 33.4.0-jre + + + com.segment.backo + backo + 1.0.0 + + + junit + junit + 4.13.2 + + + com.squareup.burst + burst-junit4 + 1.2.0 + + + com.squareup.burst + burst + 1.2.0 + + + org.assertj + assertj-core + 3.24.2 + + + org.mockito + mockito-core + 4.11.0 + + + com.offbytwo + docopt + 0.6.0.20150202 + + + org.jetbrains.kotlin + kotlin-stdlib + 1.9.0 + + + + + + com.squareup.retrofit2 + retrofit + 2.11.0 + compile + + + com.google.code.gson + gson + 2.9.1 + compile + + + com.google.code.findbugs + findbugs + 3.0.1 + provided + + + com.google.auto.value + auto-value + 1.10.1 + provided + + + com.google.auto.value + auto-value-annotations + 1.10.1 + compile + + + com.google.guava + guava + 33.4.0-jre + provided + + + jakarta.annotation + jakarta.annotation-api + 2.1.1 + compile + + + javax.annotation + javax.annotation-api + 1.3.2 + compile + + + junit + junit + 4.13.2 + test + + + com.squareup.burst + burst-junit4 + 1.2.0 + test + + + com.squareup.burst + burst + 1.2.0 + test + + + org.assertj + assertj-core + 3.24.2 + test + + + org.mockito + mockito-core + 4.11.0 + test + + + + + + false + + central + Central Repository + https://repo.maven.apache.org/maven2 + + + + + + never + + + false + + central + Central Repository + https://repo.maven.apache.org/maven2 + + + + /Users/michaelgh/dev/analytics-java/analytics-core/src/main/java + /Users/michaelgh/dev/analytics-java/analytics-core/src/main/scripts + /Users/michaelgh/dev/analytics-java/analytics-core/src/test/java + /Users/michaelgh/dev/analytics-java/analytics-core/target/classes + /Users/michaelgh/dev/analytics-java/analytics-core/target/test-classes + + + /Users/michaelgh/dev/analytics-java/analytics-core/src/main/resources + + + + + /Users/michaelgh/dev/analytics-java/analytics-core/src/test/resources + + + /Users/michaelgh/dev/analytics-java/analytics-core/target + analytics-core-3.5.5-SNAPSHOT + + + + maven-antrun-plugin + 1.3 + + + maven-assembly-plugin + 2.2-beta-5 + + + maven-dependency-plugin + 2.8 + + + maven-release-plugin + 2.5.3 + + + maven-compiler-plugin + 3.11.0 + + true + 8 + 8 + true + + + + com.diffplug.spotless + spotless-maven-plugin + 2.27.2 + + + + 1.5 + + + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + org.codehaus.mojo + templating-maven-plugin + [1.0-alpha-3,) + + filter-sources + filter-test-sources + + + + + true + true + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + [1.0.0,) + + enforce + + + + + + + + + + + + + + + org.sonatype.central + central-publishing-maven-plugin + 0.9.0 + true + + + injected-central-publishing + deploy + + publish + + + central + + + + + central + + + + maven-deploy-plugin + 3.0.0 + + true + + + + maven-assembly-plugin + 2.2-beta-5 + + + + com.segment.analytics.Analytics + + + + jar-with-dependencies + + + + + org.codehaus.mojo + cobertura-maven-plugin + 2.7 + + + html + xml + + + + + + maven-surefire-plugin + 3.2.5 + + + default-test + test + + test + + + false + + + + + false + + + + maven-source-plugin + 3.3.1 + + + attach-sources + + jar-no-fork + + + + + + maven-javadoc-plugin + 3.6.3 + + + attach-javadocs + + jar + + + + + + maven-gpg-plugin + 3.2.7 + + + sign-artifacts + verify + + sign + + + + + + maven-clean-plugin + 3.2.0 + + + default-clean + clean + + clean + + + + + + maven-resources-plugin + 3.3.0 + + + default-testResources + process-test-resources + + testResources + + + + default-resources + process-resources + + resources + + + + + + maven-jar-plugin + 3.3.0 + + + default-jar + package + + jar + + + + + + maven-compiler-plugin + 3.11.0 + + + default-compile + compile + + compile + + + true + 8 + 8 + true + + + + default-testCompile + test-compile + + testCompile + + + true + 8 + 8 + true + + + + + true + 8 + 8 + true + + + + maven-install-plugin + 3.1.0 + + + default-install + install + + install + + + + + + maven-site-plugin + 3.12.1 + + + default-site + site + + site + + + /Users/michaelgh/dev/analytics-java/analytics-core/target/site + + + org.apache.maven.plugins + maven-project-info-reports-plugin + + + + + + default-deploy + site-deploy + + deploy + + + /Users/michaelgh/dev/analytics-java/analytics-core/target/site + + + org.apache.maven.plugins + maven-project-info-reports-plugin + + + + + + + /Users/michaelgh/dev/analytics-java/analytics-core/target/site + + + org.apache.maven.plugins + maven-project-info-reports-plugin + + + + + + + + /Users/michaelgh/dev/analytics-java/analytics-core/target/site + + diff --git a/analytics-core/pom.xml b/analytics-core/pom.xml index f3dc3d23..e2db32c3 100644 --- a/analytics-core/pom.xml +++ b/analytics-core/pom.xml @@ -6,38 +6,72 @@ com.segment.analytics.java analytics-parent - 3.5.3-SNAPSHOT + 3.5.5-SNAPSHOT + com.segment.analytics.java analytics-core + 3.5.5-SNAPSHOT Analytics for Java (Core) + Core runtime for Segment Analytics for Java. + https://github.com/segmentio/analytics-java + + + + The MIT License (MIT) + http://opensource.org/licenses/MIT + + + + + https://github.com/segmentio/analytics-java/ + scm:git:https://github.com/segmentio/analytics-java.git + scm:git:git@github.com:segmentio/analytics-java.git + analytics-parent-3.5.4 + + + + + segment + Segment + Segment + https://segment.com + + + com.squareup.retrofit2 retrofit + ${retrofit.version} com.google.code.gson gson + ${gson.version} com.google.code.findbugs findbugs + ${findbugs.version} provided com.google.auto.value auto-value + ${auto.version} provided com.google.auto.value auto-value-annotations + ${auto.version} com.google.guava guava + ${guava.version} provided @@ -45,30 +79,46 @@ jakarta.annotation-api 2.1.1 + + javax.annotation + javax.annotation-api + 1.3.2 + + + + javax.annotation + javax.annotation-api + 1.3.2 + junit junit + ${junit.version} test com.squareup.burst burst-junit4 + ${burst.version} test com.squareup.burst burst + ${burst.version} test org.assertj assertj-core + ${assertj.version} test org.mockito mockito-core + ${mockito.version} test diff --git a/analytics-sample/pom.xml b/analytics-sample/pom.xml index 8151af27..4794d406 100644 --- a/analytics-sample/pom.xml +++ b/analytics-sample/pom.xml @@ -6,12 +6,40 @@ analytics-parent com.segment.analytics.java - 3.5.3-SNAPSHOT + 3.5.5-SNAPSHOT + com.segment.analytics.java analytics-sample + 3.5.5-SNAPSHOT Analytics Sample + Sample application demonstrating Segment Analytics for Java. + https://github.com/segmentio/analytics-java + + + + The MIT License (MIT) + http://opensource.org/licenses/MIT + + + + + https://github.com/segmentio/analytics-java/ + scm:git:https://github.com/segmentio/analytics-java.git + scm:git:git@github.com:segmentio/analytics-java.git + analytics-parent-3.5.4 + + + + + segment + Segment + Segment + https://segment.com + + + com.segment.analytics.java diff --git a/analytics-spring-boot-starter/pom.xml b/analytics-spring-boot-starter/pom.xml index d5d70478..4ebc8959 100644 --- a/analytics-spring-boot-starter/pom.xml +++ b/analytics-spring-boot-starter/pom.xml @@ -6,12 +6,40 @@ com.segment.analytics.java analytics-parent - 3.5.3-SNAPSHOT + 3.5.5-SNAPSHOT + com.segment.analytics.java analytics-spring-boot-starter + 3.5.5-SNAPSHOT Spring Boot starter for Segment Analytics for Java + Spring Boot auto-configuration for Segment Analytics for Java. + https://github.com/segmentio/analytics-java + + + + The MIT License (MIT) + http://opensource.org/licenses/MIT + + + + + https://github.com/segmentio/analytics-java/ + scm:git:https://github.com/segmentio/analytics-java.git + scm:git:git@github.com:segmentio/analytics-java.git + analytics-parent-3.5.4 + + + + + segment + Segment + Segment + https://segment.com + + + diff --git a/analytics/pom.xml b/analytics/pom.xml index 0ef7606b..05e36fbb 100644 --- a/analytics/pom.xml +++ b/analytics/pom.xml @@ -6,12 +6,40 @@ com.segment.analytics.java analytics-parent - 3.5.3-SNAPSHOT + 3.5.5-SNAPSHOT + com.segment.analytics.java analytics + 3.5.5-SNAPSHOT Analytics for Java + The hassle-free way to add analytics to your Java app. + https://github.com/segmentio/analytics-java + + + + The MIT License (MIT) + http://opensource.org/licenses/MIT + + + + + https://github.com/segmentio/analytics-java/ + scm:git:https://github.com/segmentio/analytics-java.git + scm:git:git@github.com:segmentio/analytics-java.git + analytics-parent-3.5.4 + + + + + segment + Segment + Segment + https://segment.com + + + com.segment.analytics.java @@ -21,51 +49,62 @@ com.squareup.okhttp3 okhttp + ${okhttp.version} com.squareup.okhttp3 logging-interceptor + ${logging.version} com.squareup.retrofit2 converter-gson + 2.9.0 com.squareup.retrofit2 retrofit-mock + ${retrofit.version} com.google.code.findbugs findbugs + ${findbugs.version} provided com.segment.backo backo + ${backo.version} junit junit + ${junit.version} test com.squareup.burst burst-junit4 + ${burst.version} test com.squareup.burst burst + ${burst.version} test org.assertj assertj-core + ${assertj.version} test org.mockito mockito-core + ${mockito.version} test diff --git a/pom.xml b/pom.xml index 22316d4b..70cfe8b4 100644 --- a/pom.xml +++ b/pom.xml @@ -3,20 +3,23 @@ 4.0.0 - - org.sonatype.oss - oss-parent - 7 - - com.segment.analytics.java analytics-parent - 3.5.3-SNAPSHOT + 3.5.5-SNAPSHOT pom Analytics for Java (Parent) The hassle-free way to add analytics to your Android app. https://github.com/segmentio/analytics-java + + + segment + Segment + Segment + https://segment.com + + + analytics-core analytics @@ -42,6 +45,9 @@ 2.7.5 0.6.0.20150202 + + true + 4.13.2 1.2.0 @@ -53,7 +59,7 @@ https://github.com/segmentio/analytics-java/ scm:git:https://github.com/segmentio/analytics-java.git scm:git:git@github.com:segmentio/analytics-java.git - HEAD + analytics-parent-3.5.4 @@ -240,16 +246,21 @@ + + org.sonatype.central + central-publishing-maven-plugin + 0.9.0 + true + + central + + org.apache.maven.plugins - maven-release-plugin - 2.5.3 + maven-deploy-plugin + 3.0.0 - true - - pom.xml - .buildscript/settings.xml - + true @@ -287,6 +298,46 @@ false + + org.apache.maven.plugins + maven-source-plugin + 3.3.1 + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.6.3 + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 3.2.7 + + + sign-artifacts + deploy + + sign + + + + From 3d4dd86e6ed760c61503d3808aa2cb55f21ef904 Mon Sep 17 00:00:00 2001 From: Michael Grosse Huelsewiesche Date: Wed, 18 Feb 2026 16:14:56 -0500 Subject: [PATCH 9/9] E2e cli for cross-SDK tests (#532) * Add e2e-cli module for analytics-java - Kotlin CLI using Gson for JSON parsing - Separate from existing analytics-cli to avoid disruption - Added to parent pom.xml modules * Add E2E test workflow Runs sdk-e2e-tests suite against the e2e-cli to verify SDK behavior. * Add E2E_TEST_SUITES to e2e workflow for selective test execution * Adding README.md for e2e-cli * Add E2E_TESTS_TOKEN for private sdk-e2e-tests repo checkout Per-SDK config and convenience script for the generic test runner in sdk-e2e-tests. Run ./e2e-cli/run-e2e.sh to build and test locally. Replace hardcoded env vars and direct npm test call with ./scripts/run-tests.sh which reads e2e-config.json for test configuration. This ensures CI uses the same config as local runs. Co-authored-by: Claude Opus 4.6 --- .github/workflows/e2e-tests.yml | 70 ++++++++++++ e2e-cli/README.md | 54 ++++++++++ e2e-cli/e2e-config.json | 7 ++ e2e-cli/pom.xml | 91 ++++++++++++++++ e2e-cli/run-e2e.sh | 41 +++++++ e2e-cli/src/main/kotlin/cli/Main.kt | 159 ++++++++++++++++++++++++++++ pom.xml | 1 + 7 files changed, 423 insertions(+) create mode 100644 .github/workflows/e2e-tests.yml create mode 100644 e2e-cli/README.md create mode 100644 e2e-cli/e2e-config.json create mode 100644 e2e-cli/pom.xml create mode 100755 e2e-cli/run-e2e.sh create mode 100644 e2e-cli/src/main/kotlin/cli/Main.kt diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml new file mode 100644 index 00000000..2e83d68e --- /dev/null +++ b/.github/workflows/e2e-tests.yml @@ -0,0 +1,70 @@ +# E2E Tests for analytics-java +# Copy this file to: analytics-java/.github/workflows/e2e-tests.yml +# +# This workflow: +# 1. Checks out the SDK and sdk-e2e-tests repos +# 2. Builds the SDK and e2e-cli +# 3. Runs the e2e test suite + +name: E2E Tests + +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + workflow_dispatch: # Allow manual trigger + +jobs: + e2e-tests: + runs-on: ubuntu-latest + + steps: + - name: Checkout SDK + uses: actions/checkout@v4 + with: + path: sdk + + - name: Checkout sdk-e2e-tests + uses: actions/checkout@v4 + with: + repository: segmentio/sdk-e2e-tests + token: ${{ secrets.E2E_TESTS_TOKEN }} + path: sdk-e2e-tests + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '11' + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Build Java SDK and e2e-cli + working-directory: sdk + run: mvn package -pl e2e-cli -am -DskipTests + + - name: Find e2e-cli jar + id: find-jar + working-directory: sdk + run: | + JAR_PATH=$(find e2e-cli/target -name "e2e-cli-*-jar-with-dependencies.jar" | head -1) + echo "jar_path=$JAR_PATH" >> $GITHUB_OUTPUT + + - name: Run E2E tests + working-directory: sdk-e2e-tests + run: | + ./scripts/run-tests.sh \ + --sdk-dir "${{ github.workspace }}/sdk/e2e-cli" \ + --cli "java -jar ${{ github.workspace }}/sdk/${{ steps.find-jar.outputs.jar_path }}" + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: e2e-test-results + path: sdk-e2e-tests/test-results/ + if-no-files-found: ignore diff --git a/e2e-cli/README.md b/e2e-cli/README.md new file mode 100644 index 00000000..b319749e --- /dev/null +++ b/e2e-cli/README.md @@ -0,0 +1,54 @@ +# analytics-java e2e-cli + +E2E test CLI for the [analytics-java](https://github.com/segmentio/analytics-java) SDK. Accepts a JSON input describing events and SDK configuration, sends them through the real SDK, and outputs results as JSON. + +Built with Kotlin (JVM) and packaged as a fat jar via Maven. + +## Setup + +```bash +mvn package -pl e2e-cli -am +``` + +## Usage + +```bash +java -jar e2e-cli/target/e2e-cli-*-jar-with-dependencies.jar --input '{"writeKey":"...", ...}' +``` + +## Input Format + +```jsonc +{ + "writeKey": "your-write-key", // required + "apiHost": "https://...", // optional — SDK default if omitted + "sequences": [ // required — event sequences to send + { + "delayMs": 0, + "events": [ + { "type": "track", "event": "Test", "userId": "user-1" } + ] + } + ], + "config": { // optional + "flushAt": 250, + "flushInterval": 10000, + "maxRetries": 3, + "timeout": 15 + } +} +``` + +Note: Java is a server-side SDK — there is no CDN settings fetch, so `cdnHost` does not apply. + +## Output Format + +```json +{ "success": true, "sentBatches": 1 } +``` + +On failure: + +```json +{ "success": false, "error": "description", "sentBatches": 0 } +``` diff --git a/e2e-cli/e2e-config.json b/e2e-cli/e2e-config.json new file mode 100644 index 00000000..db3d0167 --- /dev/null +++ b/e2e-cli/e2e-config.json @@ -0,0 +1,7 @@ +{ + "sdk": "java", + "test_suites": "basic", + "auto_settings": false, + "patch": null, + "env": {} +} diff --git a/e2e-cli/pom.xml b/e2e-cli/pom.xml new file mode 100644 index 00000000..b5782b8f --- /dev/null +++ b/e2e-cli/pom.xml @@ -0,0 +1,91 @@ + + + + 4.0.0 + + + analytics-parent + com.segment.analytics.java + 3.5.5-SNAPSHOT + + + com.segment.analytics.java + e2e-cli + 3.5.5-SNAPSHOT + Analytics Java E2E CLI + + E2E testing CLI for Segment Analytics for Java. + + + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlin.version} + + + com.segment.analytics.java + analytics + ${project.version} + + + org.jetbrains.kotlinx + kotlinx-serialization-json + 1.4.1 + + + + + src/main/kotlin + + + + kotlin-maven-plugin + org.jetbrains.kotlin + ${kotlin.version} + + + kotlinx-serialization + + + + + org.jetbrains.kotlin + kotlin-maven-serialization + ${kotlin.version} + + + + + compile + compile + + compile + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + jar-with-dependencies + + + + cli.MainKt + + + + + + package + + single + + + + + + + diff --git a/e2e-cli/run-e2e.sh b/e2e-cli/run-e2e.sh new file mode 100755 index 00000000..782df0e8 --- /dev/null +++ b/e2e-cli/run-e2e.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# +# Run E2E tests for analytics-java +# +# Prerequisites: Java 11+, Maven, Node.js 18+ +# +# Usage: +# ./run-e2e.sh [extra args passed to run-tests.sh] +# +# Override sdk-e2e-tests location: +# E2E_TESTS_DIR=../my-e2e-tests ./run-e2e.sh +# + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SDK_ROOT="$SCRIPT_DIR/.." +E2E_DIR="${E2E_TESTS_DIR:-$SDK_ROOT/../sdk-e2e-tests}" + +echo "=== Building analytics-java e2e-cli ===" + +# Build SDK and e2e-cli +cd "$SDK_ROOT" +mvn package -pl e2e-cli -am -DskipTests + +# Find the built jar +CLI_JAR=$(find "$SDK_ROOT/e2e-cli/target" -name "e2e-cli-*-jar-with-dependencies.jar" | head -1) +if [[ -z "$CLI_JAR" ]]; then + echo "Error: Could not find e2e-cli jar" + exit 1 +fi +echo "Found jar: $CLI_JAR" + +echo "" + +# Run tests +cd "$E2E_DIR" +./scripts/run-tests.sh \ + --sdk-dir "$SCRIPT_DIR" \ + --cli "java -jar $CLI_JAR" \ + "$@" diff --git a/e2e-cli/src/main/kotlin/cli/Main.kt b/e2e-cli/src/main/kotlin/cli/Main.kt new file mode 100644 index 00000000..6db10cbd --- /dev/null +++ b/e2e-cli/src/main/kotlin/cli/Main.kt @@ -0,0 +1,159 @@ +package cli + +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import com.segment.analytics.Analytics +import com.segment.analytics.Callback +import com.segment.analytics.messages.* +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicBoolean + +data class CLIOutput( + val success: Boolean, + val error: String? = null, + val sentBatches: Int = 0 +) + +data class CLIConfig( + val flushAt: Int? = null, + val flushInterval: Long? = null, + val maxRetries: Int? = null, + val timeout: Int? = null +) + +data class EventSequence( + val delayMs: Long = 0, + val events: List> +) + +data class CLIInput( + val writeKey: String, + val apiHost: String, + val sequences: List, + val config: CLIConfig? = null +) + +private val gson = Gson() + +fun main(args: Array) { + var output = CLIOutput(success = false, error = "Unknown error") + + try { + // Parse --input argument + val inputIndex = args.indexOf("--input") + if (inputIndex == -1 || inputIndex + 1 >= args.size) { + throw IllegalArgumentException("Missing required --input argument") + } + + val inputJson = args[inputIndex + 1] + val input = gson.fromJson(inputJson, CLIInput::class.java) + + val flushAt = input.config?.flushAt ?: 20 + val flushIntervalMs = input.config?.flushInterval ?: 10000L + + val flushLatch = CountDownLatch(1) + val hasError = AtomicBoolean(false) + var errorMessage: String? = null + + val analytics = Analytics.builder(input.writeKey) + .endpoint(input.apiHost) + .flushQueueSize(flushAt) + .flushInterval(maxOf(flushIntervalMs, 1000L), TimeUnit.MILLISECONDS) + .callback(object : Callback { + override fun success(message: Message?) { + // Event sent successfully + } + + override fun failure(message: Message?, throwable: Throwable?) { + hasError.set(true) + errorMessage = throwable?.message + } + }) + .build() + + // Process event sequences + for (seq in input.sequences) { + if (seq.delayMs > 0) { + Thread.sleep(seq.delayMs) + } + + for (event in seq.events) { + sendEvent(analytics, event) + } + } + + // Flush and shutdown + analytics.flush() + analytics.shutdown() + + output = if (hasError.get()) { + CLIOutput(success = false, error = errorMessage, sentBatches = 0) + } else { + CLIOutput(success = true, sentBatches = 1) + } + + } catch (e: Exception) { + output = CLIOutput(success = false, error = e.message ?: e.toString()) + } + + println(gson.toJson(output)) +} + +fun sendEvent(analytics: Analytics, event: Map) { + val type = event["type"] as? String + ?: throw IllegalArgumentException("Event missing 'type' field") + + val userId = event["userId"] as? String ?: "" + val anonymousId = event["anonymousId"] as? String + val messageId = event["messageId"] as? String + @Suppress("UNCHECKED_CAST") + val traits = event["traits"] as? Map ?: emptyMap() + @Suppress("UNCHECKED_CAST") + val properties = event["properties"] as? Map ?: emptyMap() + val eventName = event["event"] as? String + val name = event["name"] as? String + val groupId = event["groupId"] as? String + val previousId = event["previousId"] as? String + + val messageBuilder: MessageBuilder<*, *> = when (type) { + "identify" -> { + IdentifyMessage.builder().apply { + traits(traits) + } + } + "track" -> { + TrackMessage.builder(eventName ?: "Unknown Event").apply { + properties(properties) + } + } + "page" -> { + PageMessage.builder(name ?: "Unknown Page").apply { + properties(properties) + } + } + "screen" -> { + ScreenMessage.builder(name ?: "Unknown Screen").apply { + properties(properties) + } + } + "alias" -> { + AliasMessage.builder(previousId ?: "") + } + "group" -> { + GroupMessage.builder(groupId ?: "").apply { + traits(traits) + } + } + else -> throw IllegalArgumentException("Unknown event type: $type") + } + + if (userId.isNotEmpty()) { + messageBuilder.userId(userId) + } + if (anonymousId != null) { + messageBuilder.anonymousId(anonymousId) + } + + analytics.enqueue(messageBuilder) +} diff --git a/pom.xml b/pom.xml index 70cfe8b4..d873d8ba 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,7 @@ analytics-sample analytics-cli analytics-spring-boot-starter + e2e-cli