diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..3765039
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1 @@
+* @kamildziadek @viclovsky
\ No newline at end of file
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 482ca21..06121fb 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -11,13 +11,13 @@ $ git clone git@github.com:your-username/allure-kotlin.git
Then build the project (build requires JDK 1.6 or higher):
```bash
-$ ./gradlew build
+$ ./gradlew build -x :samples:junit4-android:testReleaseUnitTest -x :samples:junit4-android:testDebugUnitTest
```
Make your change. Add tests for your change. Make sure all the tests pass:
```bash
-$ ./gradlew test
+$ ./gradlew test -x :samples:junit4-android:testReleaseUnitTest -x :samples:junit4-android:testDebugUnitTest
```
Push your fork and submit a pull request.
\ No newline at end of file
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b2d3aa0..1555be6 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -18,4 +18,4 @@ jobs:
with:
java-version: 1.8
- name: "Build"
- run: ./gradlew build
+ run: ./gradlew build -x :samples:junit4-android:testReleaseUnitTest -x :samples:junit4-android:testDebugUnitTest
diff --git a/.github/workflows/label-verify.yml b/.github/workflows/label-verify.yml
new file mode 100644
index 0000000..ec0279c
--- /dev/null
+++ b/.github/workflows/label-verify.yml
@@ -0,0 +1,13 @@
+name: "Verify type labels"
+
+on:
+ pull_request:
+ types: [opened, labeled, unlabeled, synchronize]
+
+jobs:
+ triage:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: zwaldowski/match-label-action@v2
+ with:
+ allowed: 'type:new feature, type:improvement, type:bug'
\ No newline at end of file
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 0945670..f2ae7ff 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -14,7 +14,7 @@ jobs:
with:
java-version: 1.8
- name: "Build"
- run: ./gradlew build -Pversion=${GITHUB_REF:10}
+ run: ./gradlew build -x :samples:junit4-android:testReleaseUnitTest -x :samples:junit4-android:testDebugUnitTest -Pversion=${GITHUB_REF:10}
- name: "Publish"
run: ./gradlew publish -Pversion=${GITHUB_REF:10}
env:
diff --git a/allure-kotlin-android/src/main/java/io/qameta/allure/android/listeners/ExternalStoragePermissionsListener.kt b/allure-kotlin-android/src/main/java/io/qameta/allure/android/listeners/ExternalStoragePermissionsListener.kt
new file mode 100644
index 0000000..1500701
--- /dev/null
+++ b/allure-kotlin-android/src/main/java/io/qameta/allure/android/listeners/ExternalStoragePermissionsListener.kt
@@ -0,0 +1,11 @@
+package io.qameta.allure.android.listeners
+
+import io.qameta.allure.android.internal.requestExternalStoragePermissions
+import org.junit.runner.*
+import org.junit.runner.notification.*
+
+class ExternalStoragePermissionsListener : RunListener() {
+ override fun testRunStarted(description: Description?) {
+ requestExternalStoragePermissions()
+ }
+}
\ No newline at end of file
diff --git a/allure-kotlin-android/src/main/java/io/qameta/allure/android/runners/AllureAndroidJUnitRunners.kt b/allure-kotlin-android/src/main/java/io/qameta/allure/android/runners/AllureAndroidJUnitRunners.kt
index cd150e0..c5653f7 100644
--- a/allure-kotlin-android/src/main/java/io/qameta/allure/android/runners/AllureAndroidJUnitRunners.kt
+++ b/allure-kotlin-android/src/main/java/io/qameta/allure/android/runners/AllureAndroidJUnitRunners.kt
@@ -7,6 +7,7 @@ import androidx.test.runner.AndroidJUnitRunner
import io.qameta.allure.android.AllureAndroidLifecycle
import io.qameta.allure.android.internal.isDeviceTest
import io.qameta.allure.android.internal.requestExternalStoragePermissions
+import io.qameta.allure.android.listeners.ExternalStoragePermissionsListener
import io.qameta.allure.kotlin.Allure
import io.qameta.allure.kotlin.junit4.AllureJunit4
import org.junit.runner.*
@@ -29,7 +30,12 @@ class AllureAndroidJUnit4(clazz: Class<*>) : Runner(), Filterable, Sortable {
}
private fun createListener(): RunListener? =
- if (isDeviceTest()) createDeviceListener() else createRobolectricListener()
+ if (isDeviceTest()) {
+ requestExternalStoragePermissions()
+ createDeviceListener()
+ } else {
+ createRobolectricListener()
+ }
/**
* Creates listener for the tests running on a device.
@@ -44,7 +50,6 @@ class AllureAndroidJUnit4(clazz: Class<*>) : Runner(), Filterable, Sortable {
if (Allure.lifecycle == AllureAndroidLifecycle) return null
Allure.lifecycle = AllureAndroidLifecycle
- requestExternalStoragePermissions()
return AllureJunit4(AllureAndroidLifecycle)
}
@@ -72,17 +77,13 @@ open class AllureAndroidJUnitRunner : AndroidJUnitRunner() {
Allure.lifecycle = AllureAndroidLifecycle
val listenerArg = listOfNotNull(
arguments.getCharSequence("listener"),
+ ExternalStoragePermissionsListener::class.java.name,
AllureJunit4::class.java.name
).joinToString(separator = ",")
arguments.putCharSequence("listener", listenerArg)
super.onCreate(arguments)
}
- override fun onStart() {
- super.onStart()
- requestExternalStoragePermissions()
- }
-
}
/**
diff --git a/build.gradle.kts b/build.gradle.kts
index 649fc0f..45544e7 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -32,7 +32,8 @@ allprojects {
val gradleScriptDir by extra("${rootProject.projectDir}/gradle")
configure(subprojects
- .filter { !it.name.contains("android") }
+ .filter { !it.name.contains("android") }
+ .filter { it.parent?.name != "samples" }
) {
apply(plugin = "org.jetbrains.kotlin.jvm")
apply(from = "$gradleScriptDir/maven-publish.gradle")
diff --git a/samples/junit4-android/build.gradle.kts b/samples/junit4-android/build.gradle.kts
new file mode 100644
index 0000000..b2af226
--- /dev/null
+++ b/samples/junit4-android/build.gradle.kts
@@ -0,0 +1,54 @@
+plugins {
+ id("com.android.application")
+ id("kotlin-android")
+}
+
+android {
+ compileSdkVersion(Versions.Android.compileSdk)
+ defaultConfig {
+ applicationId = "io.qameta.allure.sample.junit4.android"
+ minSdkVersion(Versions.Android.minSdk)
+ targetSdkVersion(Versions.Android.targetSdk)
+ versionCode = 1
+ versionName = version as String
+
+ testInstrumentationRunner = "io.qameta.allure.android.runners.AllureAndroidJUnitRunner"
+ testInstrumentationRunnerArguments(mapOf("clearPackageData" to "true"))
+ }
+
+ buildTypes {
+ getByName("release") {
+ isMinifyEnabled = false
+ proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
+ }
+ }
+
+ sourceSets {
+ val sharedTestDir = "src/sharedTest/java"
+ getByName("test").java.srcDir(sharedTestDir)
+ getByName("androidTest").java.srcDir(sharedTestDir)
+ }
+
+ testOptions.unitTests.isIncludeAndroidResources = true
+}
+
+dependencies {
+ implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
+ implementation(kotlin("stdlib-jdk7", Versions.kotlin))
+
+ implementation("androidx.appcompat:appcompat:${Versions.Android.androidX}")
+ implementation("androidx.core:core-ktx:${Versions.Android.androidX}")
+
+ listOf(
+ project(":allure-kotlin-android"),
+ "androidx.test.ext:junit:${Versions.Android.Test.junit}",
+ "androidx.test:runner:${Versions.Android.Test.runner}",
+ "junit:junit:${Versions.junit4}",
+ "androidx.test.espresso:espresso-core:${Versions.Android.Test.espresso}"
+ ).forEach {
+ testImplementation(it)
+ androidTestImplementation(it)
+ }
+
+ testImplementation("org.robolectric:robolectric:${Versions.Android.Test.robolectric}")
+}
diff --git a/samples/junit4-android/proguard-rules.pro b/samples/junit4-android/proguard-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/samples/junit4-android/src/androidTest/resources/META-INF/services/io.qameta.allure.kotlin.listener.ContainerLifecycleListener b/samples/junit4-android/src/androidTest/resources/META-INF/services/io.qameta.allure.kotlin.listener.ContainerLifecycleListener
new file mode 100644
index 0000000..0812f09
--- /dev/null
+++ b/samples/junit4-android/src/androidTest/resources/META-INF/services/io.qameta.allure.kotlin.listener.ContainerLifecycleListener
@@ -0,0 +1 @@
+io.qameta.allure.android.listeners.LogcatContainerListener
\ No newline at end of file
diff --git a/samples/junit4-android/src/androidTest/resources/META-INF/services/io.qameta.allure.kotlin.listener.StepLifecycleListener b/samples/junit4-android/src/androidTest/resources/META-INF/services/io.qameta.allure.kotlin.listener.StepLifecycleListener
new file mode 100644
index 0000000..f5bb838
--- /dev/null
+++ b/samples/junit4-android/src/androidTest/resources/META-INF/services/io.qameta.allure.kotlin.listener.StepLifecycleListener
@@ -0,0 +1 @@
+io.qameta.allure.android.listeners.LogcatStepLifecycleListener
\ No newline at end of file
diff --git a/samples/junit4-android/src/androidTest/resources/META-INF/services/io.qameta.allure.kotlin.listener.TestLifecycleListener b/samples/junit4-android/src/androidTest/resources/META-INF/services/io.qameta.allure.kotlin.listener.TestLifecycleListener
new file mode 100644
index 0000000..b228228
--- /dev/null
+++ b/samples/junit4-android/src/androidTest/resources/META-INF/services/io.qameta.allure.kotlin.listener.TestLifecycleListener
@@ -0,0 +1 @@
+io.qameta.allure.android.listeners.LogcatTestLifecycleListener
\ No newline at end of file
diff --git a/samples/junit4-android/src/androidTest/resources/allure.properties b/samples/junit4-android/src/androidTest/resources/allure.properties
new file mode 100644
index 0000000..c858edb
--- /dev/null
+++ b/samples/junit4-android/src/androidTest/resources/allure.properties
@@ -0,0 +1,2 @@
+allure.results.directory=allure-results
+allure.link.issue.pattern=https://jira.domain-name.com/browse/{}
diff --git a/samples/junit4-android/src/debug/AndroidManifest.xml b/samples/junit4-android/src/debug/AndroidManifest.xml
new file mode 100644
index 0000000..45daac6
--- /dev/null
+++ b/samples/junit4-android/src/debug/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/junit4-android/src/main/AndroidManifest.xml b/samples/junit4-android/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..9ad841e
--- /dev/null
+++ b/samples/junit4-android/src/main/AndroidManifest.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/junit4-android/src/main/java/io/qameta/allure/sample/junit4/android/CrashActivity.kt b/samples/junit4-android/src/main/java/io/qameta/allure/sample/junit4/android/CrashActivity.kt
new file mode 100644
index 0000000..2831033
--- /dev/null
+++ b/samples/junit4-android/src/main/java/io/qameta/allure/sample/junit4/android/CrashActivity.kt
@@ -0,0 +1,36 @@
+package io.qameta.allure.sample.junit4.android
+
+import android.os.Bundle
+import android.widget.Button
+import androidx.annotation.VisibleForTesting
+import androidx.appcompat.app.AppCompatActivity
+import java.util.concurrent.Executors
+import java.util.concurrent.TimeUnit
+
+class CrashActivity : AppCompatActivity() {
+
+ private val crashImmediate: Button
+ get() = findViewById(R.id.button_crash_immediate)
+ private val crashAsync: Button
+ get() = findViewById(R.id.button_crash_async)
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_crash)
+
+ crashImmediate.setOnClickListener {
+ throw IllegalStateException("Crashing on purpose!")
+ }
+ crashAsync.setOnClickListener {
+ Executors.newSingleThreadExecutor().execute {
+ Thread.sleep(ASYNC_CRASH_TIME_MS)
+ throw IllegalStateException("Crashing async on purpose!")
+ }
+ }
+ }
+
+ companion object {
+ @VisibleForTesting
+ val ASYNC_CRASH_TIME_MS: Long = TimeUnit.SECONDS.toMillis(1)
+ }
+}
diff --git a/samples/junit4-android/src/main/java/io/qameta/allure/sample/junit4/android/SampleActivity.kt b/samples/junit4-android/src/main/java/io/qameta/allure/sample/junit4/android/SampleActivity.kt
new file mode 100644
index 0000000..936e71b
--- /dev/null
+++ b/samples/junit4-android/src/main/java/io/qameta/allure/sample/junit4/android/SampleActivity.kt
@@ -0,0 +1,19 @@
+package io.qameta.allure.sample.junit4.android
+
+import android.os.Bundle
+import android.widget.Button
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+
+class SampleActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_sample)
+
+ findViewById