Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
87 changes: 74 additions & 13 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,45 @@
#!groovy

class DockerParameters {

// 'docker build' would normally copy the whole build-dir to the container, changing the
// docker build directory avoids that overhead
def dir = 'docker'
def args = '--device /dev/kvm:/dev/kvm -v /var/local/container_shared/gradle_cache/$EXECUTOR_NUMBER:/home/user/.gradle -m=6.5G'
def label = 'LimitedEmulator'
def image = 'floriankanduth/paintroid_java17:latest'

}

def dockerParameters = new DockerParameters()

def startEmulator(String android_version, String stageName) {
sh 'adb start-server'
// creates a new avd, and if it already exists it does nothing.
sh "echo no | avdmanager create avd --force --name android${android_version}" + " --package 'system-images;android-${android_version};default;x86_64'"
sh "/home/user/android/sdk/emulator/emulator -no-window -no-boot-anim -noaudio -avd android${android_version} > ${stageName}_emulator.log 2>&1 &"
}

def waitForEmulatorAndPressWakeUpKey() {
sh 'adb devices'
sh 'timeout 5m adb wait-for-device'
sh '''#!/bin/bash
adb devices
timeout 5m adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1;
done'
echo "Emulator started"
'''
sh '''
adb shell settings put global window_animation_scale 0 &
adb shell settings put global transition_animation_scale 0 &
adb shell settings put global animator_duration_scale 0 &
'''


// In case the device went to sleep
sh 'adb shell input keyevent KEYCODE_WAKEUP'
}

def reports = 'Paintroid/build/reports'

// place the cobertura xml relative to the source, so that the source can be found
Expand All @@ -22,18 +62,32 @@ def useDebugLabelParameter(defaultLabel) {
return env.DEBUG_LABEL?.trim() ? env.DEBUG_LABEL : defaultLabel
}

def checkAnimationScale(scaleName) {
def output = sh(script: "adb shell settings get global ${scaleName}", returnStdout: true).trim()
if (output != "0" && output != "0.0") {
error("Animation scale '${scaleName}' is NOT disabled. Current value: ${output}")
} else {
echo("Animation scale '${scaleName}' is disabled (Value: ${output})")
}
}

pipeline {
environment {
ANDROID_VERSION = 33
ADB_INSTALL_TIMEOUT = 60
}

parameters {
string name: 'DEBUG_LABEL', defaultValue: '', description: 'For debugging when entered will be used as label to decide on which slaves the jobs will run.'
booleanParam name: 'BUILD_WITH_CATROID', defaultValue: false, description: 'When checked then the current Paintroid build will be built with the current develop branch of Catroid'
string name: 'CATROID_BRANCH', defaultValue: 'develop', description: 'The branch which to build catroid with, when BUILD_WITH_CATROID is checked.'
}

agent {
docker {
image 'catrobat/catrobat-paintroid:stable'
args '--device /dev/kvm:/dev/kvm -v /var/local/container_shared/gradle_cache/$EXECUTOR_NUMBER:/home/user/.gradle -m=6.5G'
label 'LimitedEmulator'
docker {
image dockerParameters.image
args dockerParameters.args
label dockerParameters.label
alwaysPull true
}
}
Expand Down Expand Up @@ -70,14 +124,14 @@ pipeline {
sh 'rm -rf Catroid; mkdir Catroid'
dir('Catroid') {
git branch: params.CATROID_BRANCH, url: 'https://github.com/Catrobat/Catroid.git'
sh "rm -f catroid/src/main/libs/*.aar"
sh "mv -f ../colorpicker/build/outputs/aar/colorpicker-debug.aar catroid/src/main/libs/colorpicker-LOCAL.aar"
sh "mv -f ../Paintroid/build/outputs/aar/Paintroid-debug.aar catroid/src/main/libs/Paintroid-LOCAL.aar"
sh 'rm -f catroid/src/main/libs/*.aar'
sh 'mv -f ../colorpicker/build/outputs/aar/colorpicker-debug.aar catroid/src/main/libs/colorpicker-LOCAL.aar'
sh 'mv -f ../Paintroid/build/outputs/aar/Paintroid-debug.aar catroid/src/main/libs/Paintroid-LOCAL.aar'
}
renameApks("${env.BRANCH_NAME}-${env.BUILD_NUMBER}")
dir('Catroid') {
archiveArtifacts "catroid/src/main/libs/*.aar"
sh "./gradlew assembleCatroidDebug"
archiveArtifacts 'catroid/src/main/libs/*.aar'
sh './gradlew assembleCatroidDebug'
archiveArtifacts 'catroid/build/outputs/apk/catroid/debug/catroid-catroid-debug.apk'
}
}
Expand Down Expand Up @@ -114,9 +168,16 @@ pipeline {

stage('Device Tests') {
steps {
sh "echo no | avdmanager create avd --force --name android28 --package 'system-images;android-28;default;x86_64'"
sh "/home/user/android/sdk/emulator/emulator -no-window -no-boot-anim -noaudio -avd android28 > /dev/null 2>&1 &"
sh './gradlew -PenableCoverage -Pjenkins -Pemulator=android28 -Pci createDebugCoverageReport -i'
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
startEmulator(ANDROID_VERSION, 'device_tests')
waitForEmulatorAndPressWakeUpKey()
script {
checkAnimationScale("window_animation_scale")
checkAnimationScale("transition_animation_scale")
checkAnimationScale("animator_duration_scale")
}
sh "./gradlew disableAnimations -PenableCoverage -Pjenkins -Pemulator=android${android_version} -Pci createDebugCoverageReport -i"
}
}
post {
always {
Expand Down Expand Up @@ -145,4 +206,4 @@ pipeline {
notifyChat()
}
}
}
}
49 changes: 25 additions & 24 deletions Paintroid/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@
*/

apply plugin: 'com.android.library'
apply plugin: 'com.hiya.jacoco-android'
apply plugin: "com.mxalbert.gradle.jacoco-android"
apply plugin: 'com.getkeepsafe.dexcount'
apply plugin: 'kotlin-android'
apply plugin: 'org.catrobat.gradle.androidemulators'
apply plugin: 'maven-publish'

apply from: 'gradle/adb_tasks.gradle'
apply from: 'gradle/code_quality_tasks.gradle'
apply from: 'gradle/emulator.gradle'

emulators {
install project.hasProperty('installSdk')
Expand All @@ -51,14 +52,14 @@ emulators {
}

jacoco {
toolVersion = "0.8.7"
toolVersion = "0.8.10"
}

jacocoAndroidUnitTestReport {
csv.enabled false
html.enabled true
xml.enabled true
destination project.getBuildDir().getPath() + "/reports/jacoco/jacocoTestDebugUnitTestReport"
csv.required = false
html.required = true
xml.required = true
destination = project.getBuildDir().getPath() + "/reports/jacoco/jacocoTestDebugUnitTestReport"
}

android {
Expand All @@ -68,8 +69,6 @@ android {
minSdkVersion rootProject.ext.androidMinSdkVersion
targetSdkVersion rootProject.ext.androidTargetSdkVersion
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
versionCode rootProject.ext.androidVersionCode
versionName rootProject.ext.androidVersionName
}

compileOptions {
Expand All @@ -85,36 +84,39 @@ android {
signedRelease {
}
debug {
testCoverageEnabled = project.hasProperty('enableCoverage')
enableUnitTestCoverage = 'project.hasProperty(\'enableCoverage\')'
enableAndroidTestCoverage = 'project.hasProperty(\'enableCoverage\')'
// Multidex is required as espresso and mockito/bytebuddy are adding more functions
// than should be allowed by law.
// See https://github.com/mockito/mockito/issues/1112
multiDexEnabled true
}
}

lintOptions {
// specific ignores should be defined via lint.xml file
lintConfig file('config/lint.xml')
ignore 'ClickableViewAccessibility', 'StaticFieldLeak', 'GradleDependency', 'OldTargetApi', 'LintBaseline'
textReport true
xmlReport true
htmlReport true
xmlOutput file("build/reports/lint-report.xml")
htmlOutput file("build/reports/lint-report.html")
}

testOptions {
unitTests.returnDefaultValues = true
animationsDisabled = true
}

packagingOptions {
resources {
excludes += ['META-INF/AL2.0', 'META-INF/LGPL2.1', "**/attach_hotspot_windows.dll"]
merges += ['META-INF/licenses/ASM']
}
}

namespace 'org.catrobat.paintroid'
lint {
htmlOutput file('build/reports/lint-report.html')
htmlReport true
ignore 'ClickableViewAccessibility', 'StaticFieldLeak', 'GradleDependency', 'OldTargetApi', 'LintBaseline'
lintConfig file('config/lint.xml')
textReport true
xmlOutput file('build/reports/lint-report.xml')
xmlReport true
}
buildFeatures {
buildConfig true
}
}

dependencies {
Expand All @@ -137,16 +139,15 @@ dependencies {
implementation 'com.jraska:falcon:2.2.0'

testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:2.18.3'
testImplementation 'org.mockito:mockito-core:3.6.28'
testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0'

androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.3'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test:rules:1.1.1'
androidTestImplementation 'org.mockito:mockito-android:3.6.28'
androidTestImplementation 'org.mockito:mockito-android:5.15.2'
androidTestImplementation 'tools.fastlane:screengrab:2.1.0'
androidTestImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0'

androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.0'
Expand Down
10 changes: 5 additions & 5 deletions Paintroid/gradle/code_quality_tasks.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ dependencies {
detektPlugins "io.gitlab.arturbosch.detekt:detekt-formatting:1.20.0"
}

task checkstyle(type: Checkstyle) {
tasks.register('checkstyle', Checkstyle) {
configFile file('config/checkstyle.xml')
source '.'
include '**/*.java', '**/*.kt', '**/*.xml', '**/*.gradle'
Expand All @@ -47,12 +47,12 @@ task checkstyle(type: Checkstyle) {
ignoreFailures false

reports {
xml.enabled = true
xml.required = true
xml.destination file("build/reports/checkstyle.xml")
}
}

task pmd(type: Pmd) {
tasks.register('pmd', Pmd) {
ruleSetFiles = files('config/pmd.xml')
ruleSets = []

Expand All @@ -63,8 +63,8 @@ task pmd(type: Pmd) {
ignoreFailures false

reports {
xml.enabled = true
html.enabled = true
xml.required = true
html.required = true
xml.destination file("build/reports/pmd.xml")
}
}
Expand Down
27 changes: 27 additions & 0 deletions Paintroid/gradle/emulator.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Paintroid: An image manipulation application for Android.
* Copyright (C) 2010-2025 The Catrobat Team
* (<http://developer.catrobat.org/credits>)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

tasks.register('disableAnimations') {
it.group 'android'
doLast {
'adb shell settings put global window_animation_scale 0'.execute()
'adb shell settings put global transition_animation_scale 0'.execute()
'adb shell settings put global animator_duration_scale 0'.execute()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class OraFileIntentTest {
val bitmap = Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888)
val contentValues = ContentValues()
contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, "testfile.ora")
contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/*")
contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/png")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ import android.app.Activity
import android.app.usage.UsageStatsManager
import android.content.Context
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import org.catrobat.paintroid.MainActivity
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RequiresApi(api = Build.VERSION_CODES.P)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.P)
@RunWith(AndroidJUnit4::class)
class CorrectStandbyBucketBehaviourTests {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.rule.ActivityTestRule
import androidx.test.rule.GrantPermissionRule
import org.catrobat.paintroid.MainActivity
import org.catrobat.paintroid.R
import org.catrobat.paintroid.colorpicker.HSVColorPickerView
Expand All @@ -47,6 +48,7 @@ import org.catrobat.paintroid.common.CATROBAT_IMAGE_ENDING
import org.catrobat.paintroid.common.PAINTROID_PICTURE_NAME
import org.catrobat.paintroid.common.PAINTROID_PICTURE_PATH
import org.catrobat.paintroid.test.espresso.util.DrawingSurfaceLocationProvider
import org.catrobat.paintroid.test.espresso.util.EspressoUtils
import org.catrobat.paintroid.test.espresso.util.UiInteractions
import org.catrobat.paintroid.test.espresso.util.UiMatcher
import org.catrobat.paintroid.test.espresso.util.wrappers.ColorPickerViewInteraction
Expand All @@ -72,6 +74,8 @@ class ColorDialogIntegrationTest {
var launchActivityRule = ActivityTestRule(
MainActivity::class.java
)
@get:Rule
val grantPermissionRule: GrantPermissionRule = EspressoUtils.grantPermissionRulesVersionCheck()

@get:Rule
var launchActivityRuleWithIntent = IntentsTestRule(
Expand Down
Loading