Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c9be643
PAINTROID-786 Update Gradle Plugin to 8.9.1
foenabua Apr 13, 2025
2462f3c
disable antiAlias in Paint object for test
foenabua Jun 14, 2025
0fd2a86
ignore toast tests
foenabua Oct 4, 2025
6b27448
Update to AGP-8 and Android-15 (API 35+)
khalid-nasralla Oct 29, 2025
0e7a28e
Merge pull request #1354 from khalid-nasralla/PAINTROID-786-801
ThorstenBandel Nov 25, 2025
1b1da2f
Version name and version code update for 2.14.0
ThorstenBandel Nov 25, 2025
f633008
changed Java Version in Jenkinsfile
ThorstenBandel Nov 26, 2025
88cd670
changed to wildcards for archiving artifacts
ThorstenBandel Nov 26, 2025
db15995
changed to wildcards for archiving artifacts in aab build
ThorstenBandel Dec 4, 2025
48de418
changed artifact file format to aab for aab files
ThorstenBandel Dec 4, 2025
8b3101d
changed proguard rules to not obfuscate serializables.
ThorstenBandel Dec 4, 2025
3917de3
changed more proguard rules to not obfuscate other elements.
ThorstenBandel Dec 4, 2025
220c7cd
reverted progurad changes
ThorstenBandel Dec 4, 2025
b9869c1
copied build type config from release to signed release to disable pr…
ThorstenBandel Dec 7, 2025
a9090f9
changed app config for building signed release for debugging
ThorstenBandel Dec 7, 2025
6521a85
added signed release elements and areadded minifier and shrinked reso…
ThorstenBandel Dec 7, 2025
e594546
added StringConcatFactory to proguard
ThorstenBandel Dec 9, 2025
fbdc3ac
changed StringConcatFactory in proguard to keep instead of ignorewarn
ThorstenBandel Dec 9, 2025
612f178
changed StringConcatFactory in proguard to be more exact
ThorstenBandel Dec 9, 2025
dfffd31
Changed build to not obfuscate
ThorstenBandel Dec 11, 2025
9d79f88
added compiler agruments to not serialize StringConcatFactory with pr…
ThorstenBandel Dec 11, 2025
05886b3
Updating values to check for kryo
ThorstenBandel Dec 11, 2025
2d7eb39
Use new media library for Import image tool
khalid-nasralla Dec 28, 2025
270f8e1
Merge pull request #1358 from khalid-nasralla/PAINTROID-803
ThorstenBandel Jan 14, 2026
13d895b
Update build.gradle
ThorstenBandel Jan 14, 2026
d8fc22b
Merge pull request #1353 from khalid-nasralla/PAINTROID-786-801
ThorstenBandel Jan 14, 2026
ea74a68
PAINTROID-804 App crashes when working with color related tools
khalid-nasralla Feb 4, 2026
8f3d7ff
PAINTROID-805 Clip area leaves outside lines in image
khalid-nasralla Feb 4, 2026
79b5d18
Merge pull request #1362 from khalid-nasralla/PAINTROID-804
ThorstenBandel Feb 6, 2026
853ce3c
Merge pull request #1363 from khalid-nasralla/PAINTROID-805
ThorstenBandel Feb 6, 2026
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
139 changes: 107 additions & 32 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,42 @@
#!groovy

def reports = 'Paintroid/build/reports'
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'
}

// NOTE: use module-agnostic report roots
def reportsGlobRoot = '**/build/reports'

// place the cobertura xml relative to the source, so that the source can be found
def javaSrc = 'Paintroid/src/main/java'
Expand All @@ -13,27 +49,41 @@ def junitAndCoverage(String jacocoXmlFile, String coverageName, String javaSrcLo
cleanWs patterns: [[pattern: testPattern, type: 'INCLUDE']]

String coverageFile = "$javaSrcLocation/coverage_${coverageName}.xml"
// Convert the JaCoCo coverate to the Cobertura XML file format.
// Convert the JaCoCo coverage to the Cobertura XML file format.
// This is done since the Jenkins JaCoCo plugin does not work well.
sh "./buildScripts/cover2cover.py '$jacocoXmlFile' '$coverageFile'"
sh "./buildScripts/cover2cover.py '${jacocoXmlFile}' '${coverageFile}'"
}

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 All @@ -53,48 +103,55 @@ pipeline {
stage('Build Debug-APK') {
steps {
sh "./gradlew -Pindependent='#$env.BUILD_NUMBER $env.BRANCH_NAME' assembleDebug"
archiveArtifacts 'app/build/outputs/apk/debug/paintroid-debug*.apk'
plot csvFileName: 'dexcount.csv', csvSeries: [[displayTableFlag: false, exclusionValues: '', file: 'Paintroid/build/outputs/dexcount/*.csv', inclusionFlag: 'OFF', url: '']], group: 'APK Stats', numBuilds: '180', style: 'line', title: 'dexcount'
// archive the app debug APK
archiveArtifacts artifacts: 'app/build/outputs/apk/debug/*.apk', fingerprint: true, onlyIfSuccessful: true
plot csvFileName: 'dexcount.csv',
csvSeries: [[displayTableFlag: false, exclusionValues: '', file: 'app/build/outputs/dexcount/*.csv', inclusionFlag: 'OFF', url: '']],
group: 'APK Stats', numBuilds: '180', style: 'line', title: 'dexcount'
}
}

stage('Build with Catroid') {
when {
expression {
params.BUILD_WITH_CATROID
}
expression { params.BUILD_WITH_CATROID }
}

steps {
sh './gradlew publishToMavenLocal -Psnapshot'
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'
}
}
}

stage('Static Analysis') {
steps {
// Ensure the tools actually run and generate reports
sh './gradlew pmd checkstyle lint detekt'
}

post {
always {
recordIssues aggregatingResults: true, enabledForFailure: true, qualityGates: [[threshold: 1, type: 'TOTAL', unstable: true]],
tools: [androidLintParser(pattern: "$reports/lint*.xml"),
checkStyle(pattern: "$reports/checkstyle.xml"),
pmdParser(pattern: "$reports/pmd.xml"),
detekt(pattern: "$reports/detekt/detekt.xml")]
// Use module-agnostic patterns so we don't miss files
recordIssues(
aggregatingResults: true,
enabledForFailure: true,
qualityGates: [[threshold: 1, type: 'TOTAL', unstable: true]],
tools: [
androidLintParser(pattern: "${reportsGlobRoot}/lint-results-*.xml,${reportsGlobRoot}/lint-*.xml,${reportsGlobRoot}/lint/*.xml"),
checkStyle(pattern: "${reportsGlobRoot}/checkstyle.xml"),
pmdParser(pattern: "${reportsGlobRoot}/pmd.xml"),
detekt(pattern: "${reportsGlobRoot}/detekt/detekt.xml")
]
)
}
}
}
Expand All @@ -107,39 +164,57 @@ pipeline {
}
post {
always {
junitAndCoverage "$reports/jacoco/jacocoTestDebugUnitTestReport/jacoco.xml", 'unit', javaSrc
// Most modules (app or Paintroid) will end up with this path
junitAndCoverage "**/build/reports/jacoco/jacocoTestDebugUnitTestReport/jacoco.xml", 'unit', javaSrc
}
}
}

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 as String, 'device_tests')
waitForEmulatorAndPressWakeUpKey()
script {
checkAnimationScale("window_animation_scale")
checkAnimationScale("transition_animation_scale")
checkAnimationScale("animator_duration_scale")
}
// FIX: reference env var correctly
sh "./gradlew disableAnimations -PenableCoverage -Pjenkins -Pemulator=android${ANDROID_VERSION} -Pci createDebugCoverageReport -i"
}
}
post {
always {
sh '/home/user/android/sdk/platform-tools/adb logcat -d > logcat.txt'
sh './gradlew stopEmulator'
junitAndCoverage "$reports/coverage/debug/report.xml", 'device', javaSrc
junitAndCoverage "**/build/reports/coverage/debug/report.xml", 'device', javaSrc
archiveArtifacts 'logcat.txt'
}
}
}
}

post {
always {
step([$class: 'CoberturaPublisher', autoUpdateHealth: false, autoUpdateStability: false, coberturaReportFile: "$javaSrc/coverage*.xml", failUnhealthy: false, failUnstable: false, maxNumberOfBuilds: 0, onlyStable: false, sourceEncoding: 'ASCII', zoomCoverageChart: false, failNoReports: false])
step([$class: 'CoberturaPublisher',
autoUpdateHealth: false,
autoUpdateStability: false,
coberturaReportFile: "${javaSrc}/coverage*.xml",
failUnhealthy: false, failUnstable: false, maxNumberOfBuilds: 0,
onlyStable: false, sourceEncoding: 'ASCII',
zoomCoverageChart: false, failNoReports: false])
}
}
}
}

post {
always {
step([$class: 'LogParserPublisher', failBuildOnError: true, projectRulePath: 'buildScripts/log_parser_rules', unstableOnWarning: true, useProjectRule: true])
step([$class: 'LogParserPublisher',
failBuildOnError: true,
projectRulePath: 'buildScripts/log_parser_rules',
unstableOnWarning: true,
useProjectRule: true])
}
changed {
notifyChat()
Expand Down
6 changes: 3 additions & 3 deletions Jenkinsfile.releaseAPK
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
pipeline {
agent {
docker {
image 'catrobat/catrobat-paintroid:stable'
image 'floriankanduth/paintroid_java17:latest'
args '--device /dev/kvm:/dev/kvm -v /var/local/container_shared/gradle_cache/$EXECUTOR_NUMBER:/home/user/.gradle -m=6.5G'
label 'LimitedEmulator'
alwaysPull true
Expand Down Expand Up @@ -58,7 +58,7 @@ pipeline {
'''
}
}
archiveArtifacts artifacts: 'app/build/outputs/apk/signedRelease/paintroid-signedRelease.apk', fingerprint: true
archiveArtifacts artifacts: 'app/build/**/**/**/*.apk', fingerprint: true
archiveArtifacts artifacts: 'app/build/outputs/mapping/signedRelease/mapping.txt', fingerprint: true
}
}
Expand All @@ -78,7 +78,7 @@ pipeline {
'''
}
}
archiveArtifacts artifacts: 'app/build/outputs/bundle/signedRelease/paintroid-signedRelease.apk', fingerprint: true
archiveArtifacts artifacts: 'app/build/outputs/bundle/*/*.aab', fingerprint: true
}
}

Expand Down
Loading