From 9e95fe87e4ae9a4e5f2aedc9cf57df74a6190bad Mon Sep 17 00:00:00 2001 From: Desu Sai Venkat <48179357+desusai7@users.noreply.github.com> Date: Fri, 29 Sep 2023 11:25:43 +0530 Subject: [PATCH 1/4] fix: expose proguard rules as part of the v2 android reporter library to ensure safer builds (#322) Co-authored-by: Desu Sai Venkat --- rudderreporter/build.gradle | 2 +- rudderreporter/proguard-rules.pro | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/rudderreporter/build.gradle b/rudderreporter/build.gradle index 38c760fd5..5f6a58675 100644 --- a/rudderreporter/build.gradle +++ b/rudderreporter/build.gradle @@ -11,7 +11,7 @@ android { defaultConfig { minSdk library.min_sdk targetSdk library.target_sdk - + consumerProguardFiles 'proguard-rules.pro' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/rudderreporter/proguard-rules.pro b/rudderreporter/proguard-rules.pro index 481bb4348..e00012764 100644 --- a/rudderreporter/proguard-rules.pro +++ b/rudderreporter/proguard-rules.pro @@ -18,4 +18,20 @@ # If you keep the line number information, uncomment this to # hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file +#-renamesourcefileattribute SourceFile + +# Required for Web, Reporter, RudderJsonAdapter, MoshiRudderAdapter, GsonRudderAdapter, JacksonRudderAdapter Modules +-keep class com.rudderstack.rudderjsonadapter.RudderTypeAdapter { *; } +-keep class * extends com.rudderstack.rudderjsonadapter.RudderTypeAdapter + +# Required for Web, Models, Reporter, JacksonRudderAdapter Modules +-dontwarn com.fasterxml.jackson.annotation.JsonProperty + +# Required for Web, Reporter, MoshiRudderAdapter +-dontwarn com.squareup.moshi.Json + +# Required for Reporter Module +-dontwarn com.fasterxml.jackson.annotation.JsonIgnore +-keep class com.rudderstack.android.ruddermetricsreporterandroid.models.LabelEntity { *; } +-keep class com.rudderstack.android.ruddermetricsreporterandroid.models.MetricEntity { *; } +-keep class com.rudderstack.android.ruddermetricsreporterandroid.models.ErrorEntity { *; } \ No newline at end of file From 1b5e670d5b10fe640099dc11353ae746ea6035b0 Mon Sep 17 00:00:00 2001 From: Debanjan Chatterjee Date: Tue, 3 Oct 2023 12:15:32 +0530 Subject: [PATCH 2/4] fix: table not found in database. added locks (#326) fix: table not found in database. added locks chore: removed comments and logs --- .../com/rudderstack/android/repository/Dao.kt | 104 +++++++++++------- .../android/repository/RudderDatabaseTest.kt | 28 ++++- .../android/repository/models/SampleEntity.kt | 18 ++- .../DefaultRudderReporter.kt | 4 +- .../internal/DefaultReservoir.kt | 7 +- .../internal/DefaultSyncer.kt | 1 - .../internal/DefaultUploadMediator.kt | 4 +- 7 files changed, 112 insertions(+), 54 deletions(-) diff --git a/repository/src/main/java/com/rudderstack/android/repository/Dao.kt b/repository/src/main/java/com/rudderstack/android/repository/Dao.kt index 6392b4187..fa5ada768 100644 --- a/repository/src/main/java/com/rudderstack/android/repository/Dao.kt +++ b/repository/src/main/java/com/rudderstack/android/repository/Dao.kt @@ -22,7 +22,11 @@ import android.database.sqlite.SQLiteDatabase import com.rudderstack.android.repository.annotation.RudderEntity import com.rudderstack.android.repository.annotation.RudderField import com.rudderstack.android.repository.utils.getInsertedRowIdForConflictIgnore +import java.util.concurrent.BlockingQueue import java.util.concurrent.ExecutorService +import java.util.concurrent.LinkedBlockingQueue +import java.util.concurrent.TimeUnit +import java.util.concurrent.locks.ReentrantLock /** * Dao for accessing entities @@ -33,7 +37,7 @@ import java.util.concurrent.ExecutorService * @property executorService An executor service to run the database queries. * TODO create separate objects for database and content provider */ -class Dao internal constructor( +class Dao( internal val entityClass: Class, private val useContentProvider: Boolean, private val context: Context, @@ -45,6 +49,9 @@ class Dao internal constructor( private val DB_LOCK = Any(); } + private val todoLock = ReentrantLock(true) + private val insertionLock = ReentrantLock(true) + private //create fields statement val fields = entityClass.getAnnotation(RudderEntity::class.java)?.fields?.takeIf { it.isNotEmpty() } @@ -58,7 +65,7 @@ class Dao internal constructor( private var _db: SQLiteDatabase? = null get() = if (field?.isOpen == true) field else null - private var todoTransactions: MutableList = ArrayList(5) + private var todoTransactions: BlockingQueue = LinkedBlockingQueue() private val _dataChangeListeners = HashSet>() private val entityContentProviderUri by lazy { @@ -111,10 +118,10 @@ class Dao internal constructor( fun List.insertSync( conflictResolutionStrategy: ConflictResolutionStrategy = ConflictResolutionStrategy.CONFLICT_NONE ): List? { - return _db?.let { db -> + awaitDbInitialization() + return (_db?.let { db -> insertData(db, this, conflictResolutionStrategy).first - } - + }) } @@ -265,7 +272,13 @@ class Dao internal constructor( * @return all data and null if database is not ready yet */ fun getAllSync(): List? { - return _db?.let { getItems(it) } + awaitDbInitialization() + return (_db?.let { getItems(it) }) + } + + private fun awaitDbInitialization() { + todoLock.lock() + todoLock.unlock() } fun runGetQuery( @@ -297,6 +310,7 @@ class Dao internal constructor( limit: String? = null, offset: String? = null ): List? { + awaitDbInitialization() return getItems( _db ?: return null, columns, @@ -323,6 +337,7 @@ class Dao internal constructor( selection: String? = null, selectionArgs: Array? = null ): Long { + awaitDbInitialization() return if (useContentProvider) (context.contentResolver.query( entityContentProviderUri.build(), arrayOf("count(*)"), selection, selectionArgs, null @@ -351,20 +366,18 @@ class Dao internal constructor( synchronized(DB_LOCK) { if (!db.isOpen) return emptyList() to emptyList() } + insertionLock.lock() + val rowIdsToInsertedItems = processEntityInsertion(db, conflictResolutionStrategy, items) + insertionLock.unlock() + return rowIdsToInsertedItems + } - //we consider one key which is auto increment but not primary. - //These are special cases that needs to be handled here - //consider only one auto increment key - var (autoIncrementFieldName: String?, nextValue: Long) = fields.firstOrNull { - it.type == RudderField.Type.INTEGER && - it.isAutoInc /*&& !it.primaryKey*/ - }?.let { autoIncField -> - autoIncField.fieldName to getMaxIntValueForColumn( - db, - tableName, - autoIncField.fieldName - ) + 1L - } ?: (null to 0L) + private fun processEntityInsertion( + db: SQLiteDatabase, + conflictResolutionStrategy: ConflictResolutionStrategy, + items: List + ): Pair, List> { + var (autoIncrementFieldName: String?, nextValue: Long) = getAutoIncrementFieldToNextValue(db) var dbCount = if (conflictResolutionStrategy == ConflictResolutionStrategy.CONFLICT_IGNORE) getCountSync( db @@ -373,13 +386,11 @@ class Dao internal constructor( var returnedItems = listOf() if (!useContentProvider) synchronized(DB_LOCK) { -// beginTransaction() items.forEach { val contentValues = it.generateContentValues() if (autoIncrementFieldName != null) { contentValues.put(autoIncrementFieldName, nextValue) } -// contentValues. val insertedRowId = insertContentValues( db, @@ -414,6 +425,19 @@ class Dao internal constructor( return rowIds to returnedItems } + //we consider one key which is auto increment. + //consider only one auto increment key + private fun getAutoIncrementFieldToNextValue(db: SQLiteDatabase) = fields.firstOrNull { + it.type == RudderField.Type.INTEGER && + it.isAutoInc /*&& !it.primaryKey*/ + }?.let { autoIncField -> + autoIncField.fieldName to getMaxIntValueForColumn( + db, + tableName, + autoIncField.fieldName + ) + 1L + } ?: (null to 0L) + private fun ContentValues.toEntity(classOfT: Class): T? { return entityFactory.getEntity(classOfT, this.toMap()) } @@ -464,13 +488,14 @@ class Dao internal constructor( )?.let { it.lastPathSegment?.toLongOrNull() } ?: -1) - else + else { (database.openDatabase?.insertWithOnConflict( tableName, nullHackColumn, contentValues, conflictAlgorithm ) ?: -1) + } } @@ -529,6 +554,7 @@ class Dao internal constructor( private fun runTransactionOrDeferToCreation(queryTransaction: (SQLiteDatabase) -> Unit) { _db?.let { db -> + awaitDbInitialization() executorService.takeUnless { it.isShutdown }?.execute { queryTransaction.invoke(db) } @@ -538,16 +564,14 @@ class Dao internal constructor( queryTransaction.invoke(it) } }.also { - todoTransactions.add(it) + todoTransactions.put(it) } } } - internal fun setDatabase(sqLiteDatabase: SQLiteDatabase?) { - _db = sqLiteDatabase + fun setDatabase(sqLiteDatabase: SQLiteDatabase?) { if (sqLiteDatabase == null) return - //run all pending tasks executorService.execute { synchronized(DB_LOCK) { @@ -556,20 +580,33 @@ class Dao internal constructor( createIndexStmt(tableName, fields)?.apply { sqLiteDatabase.openDatabase?.execSQL(this) } + _db = sqLiteDatabase + todoLock.lock() } - todoTransactions.forEach { - executorService.takeUnless { it.isShutdown }?.submit(it) + while (todoTransactions.isNotEmpty()){ + try { + executorService.takeUnless { it.isShutdown }?.submit( + todoTransactions.poll( + 50, TimeUnit.MILLISECONDS + ) + ) + }catch (ex: InterruptedException){ + ex.printStackTrace() + } } + todoLock.unlock() } } fun execSqlSync(command: String) { + awaitDbInitialization() synchronized(DB_LOCK) { _db?.openDatabase?.execSQL(command) } } private fun beginTransaction() { + awaitDbInitialization() _db?.openDatabase?.beginTransaction() } @@ -604,27 +641,19 @@ class Dao internal constructor( private fun createTableStmt(tableName: String, fields: Array): String? { -// var isAutoIncKeyPresent = false -// var isAutoIncrementedKeyPrimaryKeySame = false val fieldsStmt = fields.map { -// if (it.isAutoInc) { -//// isAutoIncKeyPresent = true -// isAutoIncrementedKeyPrimaryKeySame = it.primaryKey -// } "'${it.fieldName}' ${it.type.notation}" + //field name and type // if primary and auto increment /*if (it.primaryKey && it.isAutoInc && it.type == RudderField.Type.INTEGER) " PRIMARY KEY AUTOINCREMENT" else "" +*/ if (!it.isNullable || it.primaryKey) " NOT NULL" else "" //specifying nullability, primary key cannot be null }.reduce { acc, s -> "$acc, $s" } val primaryKeyStmt = - /*if (isAutoIncrementedKeyPrimaryKeySame) "" else {*/ //auto increment is only available for one primary key fields.filter { it.primaryKey }.takeIf { !it.isNullOrEmpty() }?.map { it.fieldName }?.reduce { acc, s -> "$acc,$s" }?.let { "PRIMARY KEY ($it)" } ?: "" -// } val uniqueKeyStmt = fields.filter { it.isUnique }.takeIf { it.isNotEmpty() }?.joinToString(",") { it.fieldName @@ -632,8 +661,6 @@ class Dao internal constructor( "UNIQUE($it)" } - - return ("CREATE TABLE IF NOT EXISTS '$tableName' ($fieldsStmt ${if (primaryKeyStmt.isNotEmpty()) ", $primaryKeyStmt" else ""}" + "${if (!uniqueKeyStmt.isNullOrEmpty()) ", $uniqueKeyStmt" else ""})") } @@ -645,7 +672,6 @@ class Dao internal constructor( it.isNotEmpty() } ?: return null val indexFieldsStmt = indexedFields.map { -// it.indexName.takeIf { it.isNotEmpty() }?:"${it.fieldName}_idx" it.fieldName }.reduce { acc, s -> "$acc,$s" diff --git a/repository/src/test/java/com/rudderstack/android/repository/RudderDatabaseTest.kt b/repository/src/test/java/com/rudderstack/android/repository/RudderDatabaseTest.kt index 8e2a553d6..3d3befe21 100644 --- a/repository/src/test/java/com/rudderstack/android/repository/RudderDatabaseTest.kt +++ b/repository/src/test/java/com/rudderstack/android/repository/RudderDatabaseTest.kt @@ -66,7 +66,7 @@ class RudderDatabaseTest { val sampleDaoCheck = RudderDatabase.getDao(SampleEntity::class.java) MatcherAssert.assertThat(sampleDao, Matchers.equalTo(sampleDaoCheck)) MatcherAssert.assertThat(sampleAutoGenDao, Matchers.equalTo(sampleAutoGenDao)) - Thread.sleep(5000) +// Thread.sleep(5000) } @Test @@ -102,6 +102,32 @@ class RudderDatabaseTest { ) ) + } + @Test + fun testSyncInsertionAndGetSync() { + val sampleEntitiesToSave = listOf( + SampleEntity("abc", 10, listOf("12", "34", "56")), + SampleEntity("def", 20, listOf("78", "90", "12")) + ) + val sampleDao = RudderDatabase.getDao(SampleEntity::class.java) + //save data +// val isInserted = AtomicBoolean(false) + with(sampleDao) { + val rowIds = sampleEntitiesToSave.insertSync() + assertThat(rowIds, iterableWithSize(2)) + println("inserted: ${rowIds!!.size}") +// isInserted.set(true) + } +// Awaitility.await().atMost(5, TimeUnit.SECONDS).untilTrue(isInserted) + //getting the data + val savedData = with(sampleDao) { getAllSync() } + + MatcherAssert.assertThat( + savedData, allOf( + Matchers.iterableWithSize(2), contains(*sampleEntitiesToSave.toTypedArray()) + ) + ) + } @Test diff --git a/repository/src/test/java/com/rudderstack/android/repository/models/SampleEntity.kt b/repository/src/test/java/com/rudderstack/android/repository/models/SampleEntity.kt index 948dd2298..2fbed1b30 100644 --- a/repository/src/test/java/com/rudderstack/android/repository/models/SampleEntity.kt +++ b/repository/src/test/java/com/rudderstack/android/repository/models/SampleEntity.kt @@ -18,13 +18,17 @@ import android.content.ContentValues import com.rudderstack.android.repository.Entity import com.rudderstack.android.repository.annotation.RudderEntity import com.rudderstack.android.repository.annotation.RudderField +import com.rudderstack.android.repository.models.SampleEntity.Companion.FIELD_COUNT +import com.rudderstack.android.repository.models.SampleEntity.Companion.FIELD_ITEMS +import com.rudderstack.android.repository.models.SampleEntity.Companion.FIELD_NAME +import com.rudderstack.android.repository.models.SampleEntity.Companion.TABLE_NAME @RudderEntity( - "sample", + TABLE_NAME, [ - RudderField(RudderField.Type.TEXT, "name", true), - RudderField(RudderField.Type.INTEGER, "count", false), - RudderField(RudderField.Type.TEXT, "items", false), + RudderField(RudderField.Type.TEXT, FIELD_NAME, true), + RudderField(RudderField.Type.INTEGER, FIELD_COUNT, false), + RudderField(RudderField.Type.TEXT, FIELD_ITEMS, false), ], ) data class SampleEntity( @@ -32,6 +36,12 @@ data class SampleEntity( val count: Int, val items: List, ) : Entity { + companion object{ + const val TABLE_NAME = "sample" + const val FIELD_NAME = "name" + const val FIELD_COUNT = "count" + const val FIELD_ITEMS = "items" + } override fun generateContentValues(): ContentValues { return ContentValues(3).also { it.put("name", name) diff --git a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/DefaultRudderReporter.kt b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/DefaultRudderReporter.kt index 67922dab7..78c7807bf 100644 --- a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/DefaultRudderReporter.kt +++ b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/DefaultRudderReporter.kt @@ -209,11 +209,9 @@ class DefaultRudderReporter( ) { this.connectivity = connectivity this.backgroundTaskService = backgroundTaskService + connectivity.registerForNetworkChanges() } - init { - connectivity?.registerForNetworkChanges() - } override val metrics: Metrics get() = _metrics override val errorClient: ErrorClient diff --git a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/DefaultReservoir.kt b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/DefaultReservoir.kt index 25a979bcd..a1008db12 100644 --- a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/DefaultReservoir.kt +++ b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/DefaultReservoir.kt @@ -83,9 +83,10 @@ class DefaultReservoir @JvmOverloads constructor( if (useBigDec) { getLabelMaskForMetricWithBigDec(insertedIds) } else { - getLabelMaskForMetricWithLong(insertedIds).also { - println("label mask for metric ${metric.name} and labels $insertedIds is $it") - } + getLabelMaskForMetricWithLong(insertedIds) +// .also { +// println("label mask for metric ${metric.name} and labels $insertedIds is $it") +// } } } insertCounterWithLabelMask(metric, labelMaskForMetric) diff --git a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/DefaultSyncer.kt b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/DefaultSyncer.kt index 50ac4fc4b..c542254ad 100644 --- a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/DefaultSyncer.kt +++ b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/DefaultSyncer.kt @@ -135,7 +135,6 @@ class DefaultSyncer internal constructor( callback.invoke() } } - println("rescheduling : $this") thresholdCountDownTimer.scheduleAtFixedRate( periodicTaskScheduler, if (callbackOnStart) 0 else flushInterval, diff --git a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/DefaultUploadMediator.kt b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/DefaultUploadMediator.kt index 2b093aac1..36b4e8fdb 100644 --- a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/DefaultUploadMediator.kt +++ b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/DefaultUploadMediator.kt @@ -41,9 +41,7 @@ internal class DefaultUploadMediator( callback: (success : Boolean) -> Unit) { val requestMap = createRequestMap(metrics, error) webService.post(null,null, jsonAdapter.writeToJson(requestMap, - object: RudderTypeAdapter>() {}).also { - println(it) - }, METRICS_ENDPOINT, + object: RudderTypeAdapter>() {}), METRICS_ENDPOINT, object : RudderTypeAdapter>(){}, isGzipEnabled){ (it.status in 200..299).apply(callback) From 42e1ab4619f77c8c00f05a954dd5aff3cbcd3842 Mon Sep 17 00:00:00 2001 From: Debanjan Chatterjee Date: Tue, 3 Oct 2023 12:16:25 +0530 Subject: [PATCH 3/4] feat: add crash filter support rudder reporter (#324) feat: add crash filter filter only crashes and not errors --- .../Configuration.kt | 5 +- .../DefaultRudderReporter.kt | 4 +- .../error/CrashFilter.kt | 32 +++++++ .../error/DefaultErrorClient.java | 36 +++++-- .../error/ErrorClient.java | 2 + .../internal/error/ImmutableConfig.kt | 12 ++- .../error/CrashFilterTest.kt | 55 +++++++++++ .../error/ErrorEventTest.kt | 1 + .../internal/error/ImmutableConfigTest.kt | 95 +++++++++++++++++++ 9 files changed, 229 insertions(+), 13 deletions(-) create mode 100644 rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/error/CrashFilter.kt create mode 100644 rudderreporter/src/test/java/com/rudderstack/android/ruddermetricsreporterandroid/error/CrashFilterTest.kt create mode 100644 rudderreporter/src/test/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/error/ImmutableConfigTest.kt diff --git a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/Configuration.kt b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/Configuration.kt index 38f5b014a..49fc2fbb8 100644 --- a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/Configuration.kt +++ b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/Configuration.kt @@ -14,8 +14,8 @@ package com.rudderstack.android.ruddermetricsreporterandroid -import android.content.Context import com.rudderstack.android.ruddermetricsreporterandroid.error.BreadcrumbType +import com.rudderstack.android.ruddermetricsreporterandroid.error.CrashFilter import com.rudderstack.android.ruddermetricsreporterandroid.internal.DebugLogger import com.rudderstack.android.ruddermetricsreporterandroid.internal.error.MetadataState @@ -39,6 +39,9 @@ class Configuration(var libraryMetadata: LibraryMetadata) { var maxReportedThreads: Int = DEFAULT_MAX_REPORTED_THREADS var maxStringValueLength: Int = DEFAULT_MAX_STRING_VALUE_LENGTH + + var crashFilter : CrashFilter? = null + var discardClasses: Set = emptySet() var enabledReleaseStages: Set? = null var enabledBreadcrumbTypes: Set? = null diff --git a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/DefaultRudderReporter.kt b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/DefaultRudderReporter.kt index 78c7807bf..43532a1de 100644 --- a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/DefaultRudderReporter.kt +++ b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/DefaultRudderReporter.kt @@ -52,7 +52,7 @@ class DefaultRudderReporter( jsonAdapter: JsonAdapter, isMetricsEnabled: Boolean = true, isErrorEnabled: Boolean = true, - networkExecutor: ExecutorService = Executors.newCachedThreadPool(), + networkExecutor: ExecutorService? = null, backgroundTaskService: BackgroundTaskService? = null, useContentProvider: Boolean = false, isGzipEnabled: Boolean = true @@ -62,7 +62,7 @@ class DefaultRudderReporter( configuration, jsonAdapter, isMetricsEnabled, isErrorEnabled, - networkExecutor, + networkExecutor?:Executors.newCachedThreadPool(), backgroundTaskService ?: BackgroundTaskService(), useContentProvider, isGzipEnabled diff --git a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/error/CrashFilter.kt b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/error/CrashFilter.kt new file mode 100644 index 000000000..95c3bfcb4 --- /dev/null +++ b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/error/CrashFilter.kt @@ -0,0 +1,32 @@ +/* + * Creator: Debanjan Chatterjee on 21/09/23, 4:50 pm Last modified: 21/09/23, 4:50 pm + * Copyright: All rights reserved Ⓒ 2023 http://rudderstack.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.rudderstack.android.ruddermetricsreporterandroid.error + +fun interface CrashFilter { + fun shouldKeep(exc: Throwable): Boolean + companion object{ + @JvmStatic + fun generateWithKeyWords(keyWords: List): CrashFilter { + return CrashFilter { exc -> + exc.isValid(keyWords) + } + } + private fun Throwable.isValid(keyWords: List) : Boolean{ + return keyWords.any { message?.contains(it) == true } + || keyWords.any { stackTraceToString().contains(it) } + || cause?.isValid(keyWords) == true + } + } +} \ No newline at end of file diff --git a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/error/DefaultErrorClient.java b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/error/DefaultErrorClient.java index 5180dbc7d..d9709b2ba 100644 --- a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/error/DefaultErrorClient.java +++ b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/error/DefaultErrorClient.java @@ -196,6 +196,7 @@ public DefaultErrorClient(@NonNull Context context, immutableConfig = new ImmutableConfig(configuration.getLibraryMetadata(), configuration.getProjectPackages(), configuration.getEnabledBreadcrumbTypes(), configuration.getDiscardClasses(), + configuration.getCrashFilter(), NoopLogger.INSTANCE, configuration.getMaxBreadcrumbs(), configuration.getMaxPersistedEvents(), configuration.getEnabledReleaseStages(), "release", @@ -234,6 +235,7 @@ contextModule, new ConfigModule(contextModule, configuration), start(); } + private void start() { exceptionHandler.install(); registerComponentCallbacks(); @@ -277,7 +279,6 @@ private void registerComponentCallbacks() { void addObserver(StateObserver observer) { metadataState.addObserver(observer); breadcrumbState.addObserver(observer); -// deliveryDelegate.addObserver(observer); memoryTrimState.addObserver(observer); } @@ -285,7 +286,6 @@ void addObserver(StateObserver observer) { void removeObserver(StateObserver observer) { metadataState.removeObserver(observer); breadcrumbState.removeObserver(observer); -// deliveryDelegate.removeObserver(observer); memoryTrimState.removeObserver(observer); } @@ -308,9 +308,6 @@ public void notify(@NonNull Throwable exc) { logNull("notify"); return; } - if (immutableConfig.shouldDiscardError(exc)) { - return; - } SeverityReason severityReason = SeverityReason.newInstance(REASON_HANDLED_EXCEPTION); Metadata metadata = metadataState.getMetadata(); ErrorEvent event = new ErrorEvent(exc, immutableConfig, severityReason, metadata); @@ -522,6 +519,33 @@ public void enable(boolean enable) { } + private static boolean isExceptionValid(@NonNull List keywords, Throwable exc) { + if(keywords.isEmpty()) return true; + for (String keyword : keywords) { + if (exc.getMessage().contains(keyword)) { + return true; + } + if (exc.getStackTrace() != null && isStackTraceValid(exc, keyword)) { + return true; + } + } + if(exc.getCause() != null){ + return isExceptionValid(keywords, exc.getCause()); + } + return false; + } + + private static boolean isStackTraceValid(Throwable exc, String keyword) { + for (StackTraceElement element : exc.getStackTrace()) { + if (element.getClassName().contains(keyword) || + element.getFileName().contains(keyword) + || element.getMethodName().contains(keyword)) { + return true; + } + } + return false; + } + /** * Intended for internal use only - leaves a breadcrumb if the type is enabled for automatic @@ -543,7 +567,7 @@ private void leaveErrorBreadcrumb(@NonNull ErrorEvent event) { // Add a breadcrumb for this event occurring List errors = event.getErrors(); - if (errors.size() > 0) { + if (!errors.isEmpty()) { String errorClass = errors.get(0).getErrorClass(); String message = errors.get(0).getErrorMessage(); diff --git a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/error/ErrorClient.java b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/error/ErrorClient.java index 00052b656..d50f13e6a 100644 --- a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/error/ErrorClient.java +++ b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/error/ErrorClient.java @@ -57,4 +57,6 @@ void leaveBreadcrumb(@NonNull String message, * @param enable */ void enable(boolean enable); + + } diff --git a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/error/ImmutableConfig.kt b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/error/ImmutableConfig.kt index 0d22efbe7..fe4fc77e8 100644 --- a/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/error/ImmutableConfig.kt +++ b/rudderreporter/src/main/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/error/ImmutableConfig.kt @@ -24,6 +24,7 @@ import com.rudderstack.android.ruddermetricsreporterandroid.error.BreadcrumbType import com.rudderstack.android.ruddermetricsreporterandroid.Logger import com.rudderstack.android.ruddermetricsreporterandroid.Configuration import com.rudderstack.android.ruddermetricsreporterandroid.LibraryMetadata +import com.rudderstack.android.ruddermetricsreporterandroid.error.CrashFilter import com.rudderstack.android.ruddermetricsreporterandroid.internal.DebugLogger import com.rudderstack.android.ruddermetricsreporterandroid.internal.NoopLogger @@ -32,6 +33,7 @@ data class ImmutableConfig( val projectPackages: Collection, val enabledBreadcrumbTypes: Set?, val discardClasses: Collection, + val crashFilter: CrashFilter?, val logger: Logger, val maxBreadcrumbs: Int, val maxPersistedEvents: Int, @@ -47,6 +49,11 @@ data class ImmutableConfig( */ fun shouldDiscardError(exc: Throwable): Boolean { return shouldDiscardByReleaseStage() || shouldDiscardByErrorClass(exc) + || shouldDiscardByCrashFilter(exc) + } + + private fun shouldDiscardByCrashFilter(exc: Throwable): Boolean { + return crashFilter?.shouldKeep(exc) == false } /** @@ -98,10 +105,6 @@ internal fun convertToImmutableConfig( packageInfo: PackageInfo? = null, appInfo: ApplicationInfo? = null ): ImmutableConfig { -// val errorTypes = when { -// config.autoDetectErrors -> config.enabledErrorTypes.copy() -// else -> ErrorTypes(false) -// } return ImmutableConfig( libraryMetadata = config.libraryMetadata, @@ -115,6 +118,7 @@ internal fun convertToImmutableConfig( enabledBreadcrumbTypes = config.enabledBreadcrumbTypes?.toSet(), packageInfo = packageInfo, appInfo = appInfo, + crashFilter = config.crashFilter ) } internal fun sanitiseConfiguration( diff --git a/rudderreporter/src/test/java/com/rudderstack/android/ruddermetricsreporterandroid/error/CrashFilterTest.kt b/rudderreporter/src/test/java/com/rudderstack/android/ruddermetricsreporterandroid/error/CrashFilterTest.kt new file mode 100644 index 000000000..0997bde43 --- /dev/null +++ b/rudderreporter/src/test/java/com/rudderstack/android/ruddermetricsreporterandroid/error/CrashFilterTest.kt @@ -0,0 +1,55 @@ +/* + * Creator: Debanjan Chatterjee on 21/09/23, 6:17 pm Last modified: 21/09/23, 6:17 pm + * Copyright: All rights reserved Ⓒ 2023 http://rudderstack.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.rudderstack.android.ruddermetricsreporterandroid.error + +import org.junit.Test + +class CrashFilterTest { + @Test + fun `should return true if the exception message contains the keyword`() { + val crashFilter = CrashFilter.generateWithKeyWords(listOf("test")) + val exception = Exception("test") + assert(crashFilter.shouldKeep(exception)) + } + + @Test + fun `should return true if the causing message contains the keyword`() { + val crashFilter = CrashFilter.generateWithKeyWords(listOf("test")) + val exception = Exception("test_wrapper", Exception("test")) + assert(crashFilter.shouldKeep(exception)) + } + + @Test + fun `should return true if the stacktrace contains the keyword dracula`() { + val crashFilter = CrashFilter.generateWithKeyWords(listOf("dracula")) + val exception = Exception("some_exception", Exception("test")) + assert(crashFilter.shouldKeep(exception)) // this method name has dracula in it + } + + @Test + fun `should return false for empty keywords list `() { + val crashFilter = CrashFilter.generateWithKeyWords(emptyList()) + val exception = Exception("some_exception", Exception("test")) + assert(!crashFilter.shouldKeep(exception)) + } + + @Test + fun `should return false if the exception message or stacktrace doesn't contain the keyword`() { + val crashFilter = CrashFilter.generateWithKeyWords(listOf("dracula")) + val exception = Exception("some_exception", Exception("some_other_exception")) + assert(!crashFilter.shouldKeep(exception)) + } + +} \ No newline at end of file diff --git a/rudderreporter/src/test/java/com/rudderstack/android/ruddermetricsreporterandroid/error/ErrorEventTest.kt b/rudderreporter/src/test/java/com/rudderstack/android/ruddermetricsreporterandroid/error/ErrorEventTest.kt index c2b1e136d..9b9b2cdf4 100644 --- a/rudderreporter/src/test/java/com/rudderstack/android/ruddermetricsreporterandroid/error/ErrorEventTest.kt +++ b/rudderreporter/src/test/java/com/rudderstack/android/ruddermetricsreporterandroid/error/ErrorEventTest.kt @@ -59,6 +59,7 @@ abstract class ErrorEventTest { listOf("com.rudderstack.android"), setOf(BreadcrumbType.ERROR), listOf("com.rudderstack.android.MyClass"), + CrashFilter.generateWithKeyWords(listOf()), object : Logger {}, 15, 16, diff --git a/rudderreporter/src/test/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/error/ImmutableConfigTest.kt b/rudderreporter/src/test/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/error/ImmutableConfigTest.kt new file mode 100644 index 000000000..f52f3a86a --- /dev/null +++ b/rudderreporter/src/test/java/com/rudderstack/android/ruddermetricsreporterandroid/internal/error/ImmutableConfigTest.kt @@ -0,0 +1,95 @@ +/* + * Creator: Debanjan Chatterjee on 21/09/23, 6:37 pm Last modified: 21/09/23, 6:37 pm + * Copyright: All rights reserved Ⓒ 2023 http://rudderstack.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.rudderstack.android.ruddermetricsreporterandroid.internal.error + +import com.rudderstack.android.ruddermetricsreporterandroid.LibraryMetadata +import com.rudderstack.android.ruddermetricsreporterandroid.error.BreadcrumbType +import com.rudderstack.android.ruddermetricsreporterandroid.error.CrashFilter +import com.rudderstack.android.ruddermetricsreporterandroid.internal.NoopLogger +import org.junit.Assert.* + +import org.junit.Test + +class ImmutableConfigTest { + + @Test + fun `shouldDiscardError should return false for crashFilter with keywords`() { + val crashFilter = CrashFilter.generateWithKeyWords(listOf("test")) + val exception = Exception("test") + val immutableConfig = ImmutableConfig( + LibraryMetadata( + "test_lib", + "1.3.0", "14", "my_write_key" + ), + listOf("com.rudderstack.android"), + setOf(BreadcrumbType.ERROR), + emptyList(), + crashFilter, + NoopLogger, + 10, + 10, + null, + "test", + null, + null + ) + assertFalse(immutableConfig.shouldDiscardError(exception)) + } + @Test + fun `shouldDiscardError should return false for null crashFilter`() { + val exception = Exception("test") + val immutableConfig = ImmutableConfig( + LibraryMetadata( + "test_lib", + "1.3.0", "14", "my_write_key" + ), + listOf("com.rudderstack.android"), + setOf(BreadcrumbType.ERROR), + emptyList(), + null, + NoopLogger, + 10, + 10, + null, + "test", + null, + null + ) + assertFalse(immutableConfig.shouldDiscardError(exception)) + } + @Test + fun `shouldDiscardError should return true for empty keywords crashFilter`() { + val crashFilter = CrashFilter.generateWithKeyWords(emptyList()) + val exception = Exception("test") + val immutableConfig = ImmutableConfig( + LibraryMetadata( + "test_lib", + "1.3.0", "14", "my_write_key" + ), + listOf("com.rudderstack.android"), + setOf(BreadcrumbType.ERROR), + emptyList(), + crashFilter, + NoopLogger, + 10, + 10, + null, + "test", + null, + null + ) + assertTrue(immutableConfig.shouldDiscardError(exception)) + } +} \ No newline at end of file From edea37f4e6e533df2d00e03a429b0000b8db971c Mon Sep 17 00:00:00 2001 From: Debanjan Chatterjee Date: Tue, 3 Oct 2023 15:29:08 +0530 Subject: [PATCH 4/4] chore: sync versions and generate release logs Signed-off-by: Debanjan Chatterjee --- package-lock.json | 4 ++-- package.json | 2 +- repository/CHANGELOG.md | 15 +++++++++------ repository/CHANGELOG_LATEST.md | 7 ++++--- repository/gradle.properties | 4 ++-- repository/package-lock.json | 4 ++-- repository/package.json | 2 +- repository/project.json | 2 +- rudderreporter/CHANGELOG.md | 6 +++--- rudderreporter/CHANGELOG_LATEST.md | 7 +++++++ rudderreporter/gradle.properties | 4 ++-- rudderreporter/package-lock.json | 4 ++-- rudderreporter/package.json | 2 +- 13 files changed, 37 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7c18c9504..fce580ec8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@rudderstack/rudder-sdk-android-monorepo", - "version": "2.2.0", + "version": "2.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@rudderstack/rudder-sdk-android-monorepo", - "version": "2.2.0", + "version": "2.3.0", "license": "MIT", "dependencies": { "@rudderstack/android": "file: ./android", diff --git a/package.json b/package.json index 8ae0f80e6..15e48337f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rudderstack/rudder-sdk-android-monorepo", - "version": "2.2.0", + "version": "2.3.0", "description": "Rudder Android SDK monorepo", "keywords": [ "android", diff --git a/repository/CHANGELOG.md b/repository/CHANGELOG.md index 92106ed48..fcb11c5cd 100644 --- a/repository/CHANGELOG.md +++ b/repository/CHANGELOG.md @@ -2,7 +2,13 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). -## 0.1.0 (2023-09-19) +## 0.2.1 (2023-10-04) + +### Bug Fixes +* table not found in database. added locks ([#326](https://github.com/rudderlabs/rudder-sdk-android/issues/326)) ([1b5e670](https://github.com/rudderlabs/rudder-sdk-android/commit/1b5e670d5b10fe640099dc11353ae746ea6035b0)) + + +## 0.2.0 (2023-09-19) ### Features @@ -15,10 +21,7 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/s * manual release + last minute fixes ([#275](https://github.com/rudderlabs/rudder-sdk-android/issues/275)) ([a52e9f7](https://github.com/rudderlabs/rudder-sdk-android/commit/a52e9f7567eb494a83ed6f57f6bd36017afaf39b)), closes [#256](https://github.com/rudderlabs/rudder-sdk-android/issues/256) -## 0.2.0 (2023-09-19) - -### Features +## 0.1.0 (2023-08-01) -* error stats library implementation ([#307](https://github.com/rudderlabs/rudder-sdk-android/issues/307)) ([abc5a41](https://github.com/rudderlabs/rudder-sdk-android/commit/abc5a410affda77d99b731e645d38e18e6d05037)), closes [#271](https://github.com/rudderlabs/rudder-sdk-android/issues/271) -* metrics v2 ([#256](https://github.com/rudderlabs/rudder-sdk-android/issues/256)) ([c0b9639](https://github.com/rudderlabs/rudder-sdk-android/commit/c0b96397a14c5ff5baa3900804fd3b5b02d21304)) +* Initial Repository diff --git a/repository/CHANGELOG_LATEST.md b/repository/CHANGELOG_LATEST.md index 05ff31539..fd3051ef4 100644 --- a/repository/CHANGELOG_LATEST.md +++ b/repository/CHANGELOG_LATEST.md @@ -1,6 +1,7 @@ -## 0.1.0 (2023-08-01) +## 0.2.1 (2023-10-03) -### Features +### Bug Fixes + +* manual release + last minute fixes ([#275](https://github.com/rudderlabs/rudder-sdk-android/issues/275)) ([a52e9f7](https://github.com/rudderlabs/rudder-sdk-android/commit/a52e9f7567eb494a83ed6f57f6bd36017afaf39b)), closes [#256](https://github.com/rudderlabs/rudder-sdk-android/issues/256) -* metrics v2 ([#256](https://github.com/rudderlabs/rudder-sdk-android/issues/256)) ([c0b9639](https://github.com/rudderlabs/rudder-sdk-android/commit/c0b96397a14c5ff5baa3900804fd3b5b02d21304)) diff --git a/repository/gradle.properties b/repository/gradle.properties index c94c798cd..211ed3573 100644 --- a/repository/gradle.properties +++ b/repository/gradle.properties @@ -4,7 +4,7 @@ GROUP=com.rudderstack.android.sdk POM_PACKAGING=aar android.enableJetifier=true android.useAndroidX=true -VERSION_CODE=2 -VERSION_NAME=0.2.0 +VERSION_CODE=3 +VERSION_NAME=0.2.1 POM_NAME=ORM library by RudderStack for android POM_DESCRIPTION=ORM library used in Rudderstack SDK Version 2 for android \ No newline at end of file diff --git a/repository/package-lock.json b/repository/package-lock.json index 4526e4a2a..962ad9de4 100644 --- a/repository/package-lock.json +++ b/repository/package-lock.json @@ -1,12 +1,12 @@ { "name": "repository", - "version": "0.2.0", + "version": "0.2.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "repository", - "version": "0.2.0", + "version": "0.2.1", "license": "ISC" } } diff --git a/repository/package.json b/repository/package.json index 42f20cfa7..3c323eeb8 100644 --- a/repository/package.json +++ b/repository/package.json @@ -1,6 +1,6 @@ { "name": "repository", - "version": "0.2.0", + "version": "0.2.1", "description": "", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" diff --git a/repository/project.json b/repository/project.json index 1bdcf0d7a..6b076651d 100644 --- a/repository/project.json +++ b/repository/project.json @@ -39,7 +39,7 @@ "github": { "executor": "@jscutlery/semver:github", "options": { - "tag": "repository@0.2.0", + "tag": "repository@0.2.1", "notesFile": "./repository/CHANGELOG_LATEST.md" } }, diff --git a/rudderreporter/CHANGELOG.md b/rudderreporter/CHANGELOG.md index 7ee495c8f..5834ea60e 100644 --- a/rudderreporter/CHANGELOG.md +++ b/rudderreporter/CHANGELOG.md @@ -2,13 +2,13 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). -## 0.1.0 (2023-09-19) +## 0.3.0 (2023-10-03) ### Features -* error stats library implementation ([#307](https://github.com/rudderlabs/rudder-sdk-android/issues/307)) ([abc5a41](https://github.com/rudderlabs/rudder-sdk-android/commit/abc5a410affda77d99b731e645d38e18e6d05037)), closes [#271](https://github.com/rudderlabs/rudder-sdk-android/issues/271) -* metrics v2 ([#256](https://github.com/rudderlabs/rudder-sdk-android/issues/256)) ([c0b9639](https://github.com/rudderlabs/rudder-sdk-android/commit/c0b96397a14c5ff5baa3900804fd3b5b02d21304)) +* add crash filter support rudder reporter ([#324](https://github.com/rudderlabs/rudder-sdk-android/issues/324)) ([42e1ab4](https://github.com/rudderlabs/rudder-sdk-android/commit/42e1ab4619f77c8c00f05a954dd5aff3cbcd3842)) +* expose proguard rules as part of the v2 android reporter library to ensure safer builds ([#322](https://github.com/rudderlabs/rudder-sdk-android/issues/322)) ([9e95fe8](https://github.com/rudderlabs/rudder-sdk-android/commit/9e95fe87e4ae9a4e5f2aedc9cf57df74a6190bad)) ## 0.2.0 (2023-09-19) diff --git a/rudderreporter/CHANGELOG_LATEST.md b/rudderreporter/CHANGELOG_LATEST.md index 8b1378917..70cf5f063 100644 --- a/rudderreporter/CHANGELOG_LATEST.md +++ b/rudderreporter/CHANGELOG_LATEST.md @@ -1 +1,8 @@ +## 0.3.0 (2023-10-03) + + +### Features + +* add crash filter support rudder reporter ([#324](https://github.com/rudderlabs/rudder-sdk-android/issues/324)) ([42e1ab4](https://github.com/rudderlabs/rudder-sdk-android/commit/42e1ab4619f77c8c00f05a954dd5aff3cbcd3842)) +* expose proguard rules as part of the v2 android reporter library to ensure safer builds ([#322](https://github.com/rudderlabs/rudder-sdk-android/issues/322)) ([9e95fe8](https://github.com/rudderlabs/rudder-sdk-android/commit/9e95fe87e4ae9a4e5f2aedc9cf57df74a6190bad)) diff --git a/rudderreporter/gradle.properties b/rudderreporter/gradle.properties index a4ad2b0f4..9eacef847 100644 --- a/rudderreporter/gradle.properties +++ b/rudderreporter/gradle.properties @@ -4,7 +4,7 @@ GROUP=com.rudderstack.android.sdk POM_PACKAGING=aar android.enableJetifier=true android.useAndroidX=true -VERSION_CODE=2 -VERSION_NAME=0.2.0 +VERSION_CODE=3 +VERSION_NAME=0.3.0 POM_NAME=Rudderstack Stats Collection library for android POM_DESCRIPTION=Rudderstack Stats Collection library for android \ No newline at end of file diff --git a/rudderreporter/package-lock.json b/rudderreporter/package-lock.json index 4526e4a2a..3bfd06708 100644 --- a/rudderreporter/package-lock.json +++ b/rudderreporter/package-lock.json @@ -1,12 +1,12 @@ { "name": "repository", - "version": "0.2.0", + "version": "0.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "repository", - "version": "0.2.0", + "version": "0.3.0", "license": "ISC" } } diff --git a/rudderreporter/package.json b/rudderreporter/package.json index 42f20cfa7..0ca0938a6 100644 --- a/rudderreporter/package.json +++ b/rudderreporter/package.json @@ -1,6 +1,6 @@ { "name": "repository", - "version": "0.2.0", + "version": "0.3.0", "description": "", "scripts": { "test": "echo \"Error: no test specified\" && exit 1"