Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
b6796fc
Version 5.3.2-rc1
gthea Oct 29, 2025
075cb85
WIP fused
gthea Oct 31, 2025
492ee25
WIP standalone / parent module
gthea Oct 31, 2025
3778c1e
Fix
gthea Oct 31, 2025
9038ecc
Consumer rules
gthea Nov 3, 2025
fb4eaeb
Restore
gthea Nov 4, 2025
2de6066
Remove unnecessary code
gthea Nov 4, 2025
4cf4c11
Publish working
gthea Nov 5, 2025
f2481d4
Signing task
gthea Nov 6, 2025
015ef86
Change version; expose SplitLogLevel
gthea Nov 6, 2025
eb4e6fb
Rename internal log level
gthea Nov 6, 2025
dceacb4
Merge branch 'development' into fused
gthea Nov 10, 2025
0fddefc
Restore log level
gthea Nov 10, 2025
4cac101
Update Logger tests
gthea Nov 10, 2025
1e0c0a1
Rename internal modules
gthea Nov 10, 2025
b6eb501
Clean up build.gradle
gthea Nov 10, 2025
4b13de6
Clean up
gthea Nov 10, 2025
2f9315a
Remove .module
gthea Nov 10, 2025
ed961c9
lint fix
gthea Nov 11, 2025
e5801de
Remove project/; refactor Gradle scripts
gthea Nov 12, 2025
d2bf298
Remove group and version in submodules
gthea Nov 12, 2025
33f8395
Scope Kotlin version override
gthea Nov 12, 2025
f0d24fb
Diffuse script enhancements
gthea Nov 14, 2025
89d9c94
Pipeline fix
gthea Nov 14, 2025
9d3831f
Update diffuse script
gthea Nov 14, 2025
9685552
Pull remote branches
gthea Nov 14, 2025
4c95ae3
New script
gthea Nov 14, 2025
3cc2e8e
events module
gthea Nov 14, 2025
e0af4b4
WIP
gthea Nov 14, 2025
cd6ac82
Renaming
gthea Nov 14, 2025
c06fc13
SplitEventsConfig
gthea Nov 18, 2025
99fc8c8
WIP
gthea Nov 20, 2025
3f3a4bb
Merge branch 'FME-11237_baseline' into events-poc
gthea Nov 20, 2025
0361384
Events module and interfaces
gthea Nov 20, 2025
68458c8
Jacoco fixes
gthea Nov 20, 2025
c4788d6
Remove missing dir from Sonar config
gthea Nov 20, 2025
a777140
Remove class
gthea Nov 20, 2025
4b8d1e2
Fix submodule coverage
gthea Nov 25, 2025
8e754ea
Fix coverage collection
gthea Nov 25, 2025
5e8e94f
Simplify sonarqube workflow
gthea Nov 25, 2025
c95de14
Add unregister method
gthea Nov 25, 2025
5da029d
Add libraries property in sonar
gthea Nov 25, 2025
8d02e78
SonarQube fix
gthea Nov 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 68 additions & 86 deletions .github/workflows/sonarqube.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,109 +40,91 @@ jobs:
# Build the project
./gradlew assembleDebug --stacktrace

# Run tests with coverage - allow test failures
./gradlew testDebugUnitTest jacocoTestReport --stacktrace
TEST_RESULT=$?
if [ $TEST_RESULT -ne 0 ]; then
echo "Some tests failed, but continuing to check for coverage data..."
# Even if tests fail, JaCoCo should generate a report with partial coverage
# from the tests that did pass
fi

- name: Prepare class files for SonarQube analysis
run: |
echo "Searching for compiled class files..."
# Run tests - continue even if some tests fail
./gradlew testDebugUnitTest --stacktrace || echo "Some tests failed, but continuing to generate coverage report..."

# Create the target directory
mkdir -p build/intermediates/runtime_library_classes_dir/debug
# Generate JaCoCo aggregate report separately (ensures it runs even if tests failed)
./gradlew jacocoRootReport --stacktrace

# Find all directories containing class files with better patterns
CLASS_DIRS=$(find build -name "*.class" -type f -exec dirname {} \; | sort -u | grep -E "(javac|kotlin-classes|runtime_library)" | head -10)

if [ -z "$CLASS_DIRS" ]; then
echo "WARNING: No class files found in the build directory!"
echo "Searching in all build subdirectories..."
find build -name "*.class" -type f | head -20
# Log report location for debugging
REPORT_PATH="build/reports/jacoco/jacocoRootReport/jacocoRootReport.xml"
if [ -f "$REPORT_PATH" ]; then
echo "✓ JaCoCo report generated at: $REPORT_PATH ($(wc -c < "$REPORT_PATH") bytes)"
else
echo "Found class files in the following directories:"
echo "$CLASS_DIRS"

# Copy classes from all relevant directories, not just the first one
for CLASS_DIR in $CLASS_DIRS; do
if [ -d "$CLASS_DIR" ] && [ "$(find "$CLASS_DIR" -name "*.class" | wc -l)" -gt 0 ]; then
echo "Copying classes from $CLASS_DIR"
cp -r "$CLASS_DIR"/* build/intermediates/runtime_library_classes_dir/debug/ 2>/dev/null || echo "Failed to copy from $CLASS_DIR"
fi
done

# Verify the target directory now has class files
CLASS_COUNT=$(find build/intermediates/runtime_library_classes_dir/debug -name "*.class" | wc -l)
echo "Target directory now contains $CLASS_COUNT class files"
echo "✗ JaCoCo report was NOT generated at: $REPORT_PATH"
fi

# Update sonar-project.properties with all found class directories
echo "" >> sonar-project.properties
echo "# Additional binary paths found during build" >> sonar-project.properties
if [ -n "$CLASS_DIRS" ]; then
# Convert newlines to commas for sonar.java.binaries
BINARY_PATHS=$(echo "$CLASS_DIRS" | tr '\n' ',' | sed 's/,$//')
echo "sonar.java.binaries=build/intermediates/runtime_library_classes_dir/debug,$BINARY_PATHS" >> sonar-project.properties
- name: Verify class files and coverage data for SonarQube analysis
run: |
echo "=== Verifying Build Artifacts for SonarQube ==="
echo ""

echo "Checking compiled class files for each module:"
for module in main events logger; do
MODULE_CLASSES_DIR="${module}/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes"
if [ -d "$MODULE_CLASSES_DIR" ]; then
CLASS_COUNT=$(find "$MODULE_CLASSES_DIR" -name "*.class" | wc -l)
echo " ✓ ${module}: Found $CLASS_COUNT class files in $MODULE_CLASSES_DIR"
else
echo " ✗ ${module}: Class directory not found: $MODULE_CLASSES_DIR"
fi
done

echo ""
echo "Checking JaCoCo coverage report:"
if [ -f build/reports/jacoco/jacocoRootReport/jacocoRootReport.xml ]; then
REPORT_SIZE=$(wc -c < build/reports/jacoco/jacocoRootReport/jacocoRootReport.xml)
PACKAGE_COUNT=$(grep -c "<package" build/reports/jacoco/jacocoRootReport/jacocoRootReport.xml || echo "0")
CLASS_COUNT=$(grep -c "<class" build/reports/jacoco/jacocoRootReport/jacocoRootReport.xml || echo "0")
LINE_COUNT=$(grep -c "<line" build/reports/jacoco/jacocoRootReport/jacocoRootReport.xml || echo "0")
COVERED_LINES=$(grep -c 'ci="1"' build/reports/jacoco/jacocoRootReport/jacocoRootReport.xml || echo "0")

echo " ✓ JaCoCo report found: build/reports/jacoco/jacocoRootReport/jacocoRootReport.xml"
echo " - Size: $REPORT_SIZE bytes"
echo " - Packages: $PACKAGE_COUNT"
echo " - Classes: $CLASS_COUNT"
echo " - Lines: $LINE_COUNT"
echo " - Covered lines: $COVERED_LINES"

# Check if events module coverage is present
if grep -q 'package name="io/harness/events"' build/reports/jacoco/jacocoRootReport/jacocoRootReport.xml; then
echo " ✓ Events module (io/harness/events) coverage found in report"
else
echo " ✗ WARNING: Events module coverage NOT found in report"
fi
else
echo "sonar.java.binaries=build/intermediates/runtime_library_classes_dir/debug" >> sonar-project.properties
echo " ✗ JaCoCo report file not found"
fi

echo "Checking for JaCoCo report files..."
find build -name "*.xml" | grep jacoco || echo "No JaCoCo XML files found"
find build -name "*.exec" | grep jacoco || echo "No JaCoCo exec files found"

echo "Contents of JaCoCo report directory:"
ls -la build/reports/jacoco/jacocoTestReport/ || echo "Directory not found"


echo ""
echo "Checking test execution results:"
echo "Checking JaCoCo execution data for each module:"
for module in main events logger; do
EXEC_FILE="${module}/build/jacoco/testDebugUnitTest.exec"
if [ -f "$EXEC_FILE" ]; then
EXEC_SIZE=$(wc -c < "$EXEC_FILE")
echo " ✓ ${module}: Found execution data ($EXEC_SIZE bytes) in $EXEC_FILE"
else
echo " ✗ ${module}: Execution data not found: $EXEC_FILE"
fi
done

echo ""
echo "Test execution summary:"
TEST_RESULT_FILES=$(find build -name "TEST-*.xml" 2>/dev/null)
if [ -n "$TEST_RESULT_FILES" ]; then
echo "Found test result files:"
echo "$TEST_RESULT_FILES"
# Count total tests, failures, errors
TOTAL_TESTS=$(cat $TEST_RESULT_FILES | grep -o 'tests="[0-9]*"' | cut -d'"' -f2 | awk '{sum+=$1} END {print sum}')
TOTAL_FAILURES=$(cat $TEST_RESULT_FILES | grep -o 'failures="[0-9]*"' | cut -d'"' -f2 | awk '{sum+=$1} END {print sum}')
TOTAL_ERRORS=$(cat $TEST_RESULT_FILES | grep -o 'errors="[0-9]*"' | cut -d'"' -f2 | awk '{sum+=$1} END {print sum}')
echo "Test summary: $TOTAL_TESTS tests, $TOTAL_FAILURES failures, $TOTAL_ERRORS errors"
else
echo "No test result files found"
fi

echo ""
echo "Checking JaCoCo report content:"
if [ -f build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml ]; then
echo "Report file size: $(wc -c < build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml) bytes"
echo "First 500 chars of report:"
head -c 500 build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml
echo ""
echo ""
echo "Counting coverage elements:"
grep -c "<package" build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml || echo "No packages found"
grep -c "<class" build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml || echo "No classes found"
grep -c "<method" build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml || echo "No methods found"
grep -c "<line" build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml || echo "No lines found"
grep -c 'ci="1"' build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml || echo "No covered lines found"
echo " Tests: $TOTAL_TESTS | Failures: $TOTAL_FAILURES | Errors: $TOTAL_ERRORS"
else
echo "JaCoCo report file not found"
echo " No test result files found"
fi

echo ""
echo "Checking binary directories specified in sonar-project.properties:"
echo "build/intermediates/runtime_library_classes_dir/debug:"
ls -la build/intermediates/runtime_library_classes_dir/debug || echo "Directory not found"

echo ""
echo "Checking all available class directories:"
find build -path "*/build/*" -name "*.class" | head -n 10 || echo "No class files found"

echo ""
echo "Final sonar-project.properties content:"
echo "SonarQube configuration (sonar-project.properties):"
cat sonar-project.properties
echo ""
echo "=== Verification Complete ==="

- name: SonarCloud Scan
uses: SonarSource/sonarqube-scan-action@v6
Expand Down
53 changes: 44 additions & 9 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ buildscript {

apply plugin: 'com.android.fused-library'
apply plugin: 'com.vanniktech.maven.publish'
apply from: "$rootDir/gradle/jacoco-root.gradle"

ext {
splitVersion = '5.4.3-rc4'
Expand All @@ -33,16 +34,49 @@ allprojects {
}
}

// The SonarQube Gradle plugin is NOT yet compatible with AGP 9.0
// Using CLI scanner wrapper as workaround until plugin is updated

// Define exclusions for JaCoCo coverage
def coverageExclusions = [
'**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*.*',
'**/*Test*.*',
'android/**/*.*'
]
// Sonar task that wraps the CLI scanner (uses sonar-project.properties)
tasks.register('sonar') {
group = 'verification'
description = 'Run SonarQube analysis (uses sonar-scanner CLI for AGP 9.0 compatibility)'

dependsOn 'jacocoRootReport'

doLast {
def sonarToken = System.getProperty('sonar.token') ?: project.findProperty('sonar.token')
def sonarHost = System.getProperty('sonar.host.url') ?: project.findProperty('sonar.host.url') ?: 'https://sonarcloud.io'
def sonarOrg = System.getProperty('sonar.organization') ?: project.findProperty('sonar.organization')

if (!sonarToken) {
throw new GradleException('SonarQube token required')
}

// Find sonar-scanner
def scannerPath = ['sonar-scanner', '/opt/homebrew/bin/sonar-scanner', '/usr/local/bin/sonar-scanner']
.find { path ->
try {
def proc = new ProcessBuilder(path, '--version').redirectErrorStream(true).start()
return proc.waitFor() == 0
} catch (Exception e) { return false }
}

if (!scannerPath) {
throw new GradleException('sonar-scanner not found. Install with: brew install sonar-scanner')
}

println "Running sonar-scanner..."
def cmd = [scannerPath, "-Dsonar.token=${sonarToken}", "-Dsonar.host.url=${sonarHost}"]
if (sonarOrg) cmd.add("-Dsonar.organization=${sonarOrg}")
cmd.add("-Dsonar.projectVersion=${splitVersion}")

def proc = new ProcessBuilder(cmd).directory(rootDir).inheritIO().start()
if (proc.waitFor() != 0) {
throw new GradleException("sonar-scanner failed")
}
}
}

androidFusedLibrary {
namespace = 'io.split.android.android_client'
Expand Down Expand Up @@ -106,6 +140,7 @@ repositories {
dependencies {
include project(':main')
include project(':logger')
include project(':events')
}

def splitPOM = {
Expand Down
1 change: 1 addition & 0 deletions events/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
21 changes: 21 additions & 0 deletions events/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
plugins {
id 'com.android.library'
}

apply from: "$rootDir/gradle/common-android-library.gradle"

android {
namespace 'io.harness.events'

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

dependencies {
implementation libs.annotation

testImplementation libs.junit4
testImplementation libs.mockitoCore
}
Empty file added events/consumer-rules.pro
Empty file.
21 changes: 21 additions & 0 deletions events/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
4 changes: 4 additions & 0 deletions events/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

</manifest>
12 changes: 12 additions & 0 deletions events/src/main/java/io/harness/events/EventDelivery.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.harness.events;

/**
* Interface for event delivery.
*
* @param <E> event type
* @param <M> metadata type
*/
public interface EventDelivery<E, M> {

void deliver(EventHandler<E, M> eventHandler, E event, M metadata);
}
13 changes: 13 additions & 0 deletions events/src/main/java/io/harness/events/EventHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.harness.events;

/**
* Interface for event handlers. This represents a callback
* that will be executed when an event is triggered.
*
* @param <E> event type
* @param <M> metadata type
*/
public interface EventHandler<E, M> {

void handle(E event, M metadata);
}
50 changes: 50 additions & 0 deletions events/src/main/java/io/harness/events/EventsManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package io.harness.events;

import androidx.annotation.Nullable;

/**
* Interface for events manager.
*
* @param <E> external events type
* @param <I> internal events type
* @param <M> metadata type
*/
public interface EventsManager<E, I, M> {

/**
* Registers a handler to be executed when the event is triggered.
*
* @param event event to register
* @param handler handler to execute when the event is triggered
*/
void register(E event, EventHandler<E, M> handler);

/**
* Unregisters all registered handlers for an event.
*
* @param event event to unregister handlers for
*/
void unregister(E event);

/**
* Notifies an internal event has occurred.
*
* @param event internal event to notify
* @param metadata optional metadata
*/
void notifyInternalEvent(I event, @Nullable M metadata);

/**
* Checks if the event has already been triggered.
*
* @param event event to check
* @return whether event has been triggered
*/
boolean eventAlreadyTriggered(E event);

/**
* Destroys the events manager.
* This should be called when the events manager is no longer needed.
*/
void destroy();
}
Loading
Loading