apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'com.google.protobuf' apply plugin: 'androidx.navigation.safeargs' apply plugin: 'org.jlleitschuh.gradle.ktlint' apply from: 'translations.gradle' apply plugin: 'org.jetbrains.kotlin.android' apply plugin: 'app.cash.exhaustive' apply plugin: 'kotlin-parcelize' apply from: 'static-ips.gradle' repositories { maven { url "https://raw.github.com/signalapp/maven/master/circular-progress-button/releases/" content { includeGroupByRegex "com\\.github\\.dmytrodanylyk\\.circular-progress-button\\.*" } } maven { url "https://raw.github.com/signalapp/maven/master/sqlcipher/release/" content { includeGroupByRegex "org\\.signal.*" } } maven { url "https://www.jitpack.io" } google() mavenCentral() mavenLocal() maven { url "https://dl.cloudsmith.io/qxAgwaeEE1vN8aLU/mobilecoin/mobilecoin/maven/" } jcenter { content { includeVersion "mobi.upod", "time-duration-picker", "1.1.3" includeVersion "cn.carbswang.android", "NumberPickerView", "1.0.9" includeVersion "com.takisoft.fix", "colorpicker", "0.9.1" includeVersion "com.codewaves.stickyheadergrid", "stickyheadergrid", "0.9.4" includeVersion "com.google.android", "flexbox", "0.3.0" } } } protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.18.0' } generateProtoTasks { all().each { task -> task.builtins { java { option "lite" } } } } } ktlint { // Use a newer version to resolve https://github.com/JLLeitschuh/ktlint-gradle/issues/507 version = "0.43.2" } def canonicalVersionCode = 1059 def canonicalVersionName = "5.39.3" def postFixSize = 100 def abiPostFix = ['universal' : 0, 'armeabi-v7a' : 1, 'arm64-v8a' : 2, 'x86' : 3, 'x86_64' : 4] def keystores = [ 'debug' : loadKeystoreProperties('keystore.debug.properties') ] def selectableVariants = [ 'nightlyProdSpinner', 'nightlyProdPerf', 'nightlyProdRelease', 'playProdDebug', 'playProdSpinner', 'playProdPerf', 'playProdRelease', 'playStagingDebug', 'playStagingSpinner', 'playStagingPerf', 'playStagingRelease', 'websiteProdSpinner', 'websiteProdRelease', ] android { buildToolsVersion BUILD_TOOL_VERSION compileSdkVersion COMPILE_SDK flavorDimensions 'distribution', 'environment' useLibrary 'org.apache.http.legacy' kotlinOptions { jvmTarget = "1.8" freeCompilerArgs = ["-Xallow-result-return-type"] } dexOptions { javaMaxHeapSize "4g" } signingConfigs { if (keystores.debug != null) { debug { storeFile file("${project.rootDir}/${keystores.debug.storeFile}") storePassword keystores.debug.storePassword keyAlias keystores.debug.keyAlias keyPassword keystores.debug.keyPassword } } } testOptions { execution 'ANDROIDX_TEST_ORCHESTRATOR' unitTests { includeAndroidResources = true } } lintOptions { checkReleaseBuilds false abortOnError true baseline file("lint-baseline.xml") disable "LintError" } sourceSets { test { java.srcDirs += "$projectDir/src/testShared" } androidTest { java.srcDirs += "$projectDir/src/testShared" } } compileOptions { coreLibraryDesugaringEnabled true sourceCompatibility JAVA_VERSION targetCompatibility JAVA_VERSION } packagingOptions { exclude 'LICENSE.txt' exclude 'LICENSE' exclude 'NOTICE' exclude 'asm-license.txt' exclude 'META-INF/LICENSE' exclude 'META-INF/NOTICE' exclude 'META-INF/proguard/androidx-annotations.pro' } defaultConfig { versionCode canonicalVersionCode * postFixSize versionName canonicalVersionName minSdkVersion MINIMUM_SDK targetSdkVersion TARGET_SDK multiDexEnabled true vectorDrawables.useSupportLibrary = true project.ext.set("archivesBaseName", "Signal"); buildConfigField "long", "BUILD_TIMESTAMP", getLastCommitTimestamp() + "L" buildConfigField "String", "GIT_HASH", "\"${getGitHash()}\"" buildConfigField "String", "SIGNAL_URL", "\"https://chat.signal.org\"" buildConfigField "String", "STORAGE_URL", "\"https://storage.signal.org\"" buildConfigField "String", "SIGNAL_CDN_URL", "\"https://cdn.signal.org\"" buildConfigField "String", "SIGNAL_CDN2_URL", "\"https://cdn2.signal.org\"" buildConfigField "String", "SIGNAL_CONTACT_DISCOVERY_URL", "\"https://api.directory.signal.org\"" buildConfigField "String", "SIGNAL_CDSI_URL", "\"https://cdsi.staging.signal.org\"" buildConfigField "String", "SIGNAL_SERVICE_STATUS_URL", "\"uptime.signal.org\"" buildConfigField "String", "SIGNAL_KEY_BACKUP_URL", "\"https://api.backup.signal.org\"" buildConfigField "String", "SIGNAL_SFU_URL", "\"https://sfu.voip.signal.org\"" buildConfigField "String[]", "SIGNAL_SFU_INTERNAL_NAMES", "new String[]{\"Test\", \"Staging\"}" buildConfigField "String[]", "SIGNAL_SFU_INTERNAL_URLS", "new String[]{\"https://sfu.test.voip.signal.org\", \"https://sfu.staging.voip.signal.org\"}" buildConfigField "String", "CONTENT_PROXY_HOST", "\"contentproxy.signal.org\"" buildConfigField "int", "CONTENT_PROXY_PORT", "443" buildConfigField "String[]", "SIGNAL_SERVICE_IPS", service_ips buildConfigField "String[]", "SIGNAL_STORAGE_IPS", storage_ips buildConfigField "String[]", "SIGNAL_CDN_IPS", cdn_ips buildConfigField "String[]", "SIGNAL_CDN2_IPS", cdn2_ips buildConfigField "String[]", "SIGNAL_CDS_IPS", cds_ips buildConfigField "String[]", "SIGNAL_KBS_IPS", kbs_ips buildConfigField "String[]", "SIGNAL_SFU_IPS", sfu_ips buildConfigField "String[]", "SIGNAL_CONTENT_PROXY_IPS", content_proxy_ips buildConfigField "String", "SIGNAL_AGENT", "\"OWA\"" buildConfigField "String", "CDS_MRENCLAVE", "\"c98e00a4e3ff977a56afefe7362a27e4961e4f19e211febfbb19b897e6b80b15\"" buildConfigField "String", "CDSI_MRENCLAVE", "\"42e36b74794abe612d698308b148ff8a7dc5fdc6ad28d99bc5024ed6ece18dfe\"" buildConfigField "org.thoughtcrime.securesms.KbsEnclave", "KBS_ENCLAVE", "new org.thoughtcrime.securesms.KbsEnclave(\"0cedba03535b41b67729ce9924185f831d7767928a1d1689acb689bc079c375f\", " + "\"187d2739d22be65e74b65f0055e74d31310e4267e5fac2b1246cc8beba81af39\", " + "\"ee19f1965b1eefa3dc4204eb70c04f397755f771b8c1909d080c04dad2a6a9ba\")" buildConfigField "org.thoughtcrime.securesms.KbsEnclave[]", "KBS_FALLBACKS", "new org.thoughtcrime.securesms.KbsEnclave[] {" + "new org.thoughtcrime.securesms.KbsEnclave(\"fe7c1bfae98f9b073d220366ea31163ee82f6d04bead774f71ca8e5c40847bfe\", " + "\"fe7c1bfae98f9b073d220366ea31163ee82f6d04bead774f71ca8e5c40847bfe\", " + "\"a3baab19ef6ce6f34ab9ebb25ba722725ae44a8872dc0ff08ad6d83a9489de87\")" + "}" buildConfigField "String", "UNIDENTIFIED_SENDER_TRUST_ROOT", "\"BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF\"" buildConfigField "String", "ZKGROUP_SERVER_PUBLIC_PARAMS", "\"AMhf5ywVwITZMsff/eCyudZx9JDmkkkbV6PInzG4p8x3VqVJSFiMvnvlEKWuRob/1eaIetR31IYeAbm0NdOuHH8Qi+Rexi1wLlpzIo1gstHWBfZzy1+qHRV5A4TqPp15YzBPm0WSggW6PbSn+F4lf57VCnHF7p8SvzAA2ZZJPYJURt8X7bbg+H3i+PEjH9DXItNEqs2sNcug37xZQDLm7X36nOoGPs54XsEGzPdEV+itQNGUFEjY6X9Uv+Acuks7NpyGvCoKxGwgKgE5XyJ+nNKlyHHOLb6N1NuHyBrZrgtY/JYJHRooo5CEqYKBqdFnmbTVGEkCvJKxLnjwKWf+fEPoWeQFj5ObDjcKMZf2Jm2Ae69x+ikU5gBXsRmoF94GXQ==\"" buildConfigField "String[]", "LANGUAGES", "new String[]{\"" + autoResConfig().collect { s -> s.replace('-r', '_') }.join('", "') + '"}' buildConfigField "int", "CANONICAL_VERSION_CODE", "$canonicalVersionCode" buildConfigField "String", "DEFAULT_CURRENCIES", "\"EUR,AUD,GBP,CAD,CNY\"" buildConfigField "String", "GIPHY_API_KEY", "\"3o6ZsYH6U6Eri53TXy\"" buildConfigField "String", "SIGNAL_CAPTCHA_URL", "\"https://signalcaptchas.org/registration/generate.html\"" buildConfigField "String", "RECAPTCHA_PROOF_URL", "\"https://signalcaptchas.org/challenge/generate.html\"" buildConfigField "String", "BUILD_DISTRIBUTION_TYPE", "\"unset\"" buildConfigField "String", "BUILD_ENVIRONMENT_TYPE", "\"unset\"" buildConfigField "String", "BUILD_VARIANT_TYPE", "\"unset\"" buildConfigField "String", "BADGE_STATIC_ROOT", "\"https://updates2.signal.org/static/badges/\"" buildConfigField "String", "STRIPE_PUBLISHABLE_KEY", "\"pk_live_6cmGZopuTsV8novGgJJW9JpC00vLIgtQ1D\"" ndk { abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' } resConfigs autoResConfig() splits { abi { enable true reset() include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' universalApk true } } testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunnerArguments clearPackageData: 'true' } buildTypes { debug { if (keystores['debug'] != null) { signingConfig signingConfigs.debug } isDefault true minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard/proguard-firebase-messaging.pro', 'proguard/proguard-google-play-services.pro', 'proguard/proguard-jackson.pro', 'proguard/proguard-sqlite.pro', 'proguard/proguard-appcompat-v7.pro', 'proguard/proguard-square-okhttp.pro', 'proguard/proguard-square-okio.pro', 'proguard/proguard-rounded-image-view.pro', 'proguard/proguard-glide.pro', 'proguard/proguard-shortcutbadger.pro', 'proguard/proguard-retrofit.pro', 'proguard/proguard-webrtc.pro', 'proguard/proguard-klinker.pro', 'proguard/proguard-retrolambda.pro', 'proguard/proguard-okhttp.pro', 'proguard/proguard-ez-vcard.pro', 'proguard/proguard.cfg' testProguardFiles 'proguard/proguard-automation.pro', 'proguard/proguard.cfg' buildConfigField "String", "BUILD_VARIANT_TYPE", "\"Debug\"" } spinner { initWith debug isDefault false minifyEnabled false matchingFallbacks = ['debug'] buildConfigField "String", "BUILD_VARIANT_TYPE", "\"Spinner\"" } release { minifyEnabled true proguardFiles = buildTypes.debug.proguardFiles buildConfigField "String", "BUILD_VARIANT_TYPE", "\"Release\"" } perf { initWith debug isDefault false debuggable false minifyEnabled true matchingFallbacks = ['debug'] buildConfigField "String", "BUILD_VARIANT_TYPE", "\"Perf\"" } } productFlavors { play { dimension 'distribution' isDefault true ext.websiteUpdateUrl = "null" buildConfigField "boolean", "PLAY_STORE_DISABLED", "false" buildConfigField "String", "NOPLAY_UPDATE_URL", "$ext.websiteUpdateUrl" buildConfigField "String", "BUILD_DISTRIBUTION_TYPE", "\"play\"" } website { dimension 'distribution' ext.websiteUpdateUrl = "https://updates.signal.org/android" buildConfigField "boolean", "PLAY_STORE_DISABLED", "true" buildConfigField "String", "NOPLAY_UPDATE_URL", "\"$ext.websiteUpdateUrl\"" buildConfigField "String", "BUILD_DISTRIBUTION_TYPE", "\"website\"" } nightly { dimension 'distribution' versionNameSuffix "-nightly-untagged-${getDateSuffix()}" ext.websiteUpdateUrl = "null" buildConfigField "boolean", "PLAY_STORE_DISABLED", "false" buildConfigField "String", "NOPLAY_UPDATE_URL", "$ext.websiteUpdateUrl" buildConfigField "String", "BUILD_DISTRIBUTION_TYPE", "\"nightly\"" } prod { dimension 'environment' isDefault true buildConfigField "String", "MOBILE_COIN_ENVIRONMENT", "\"mainnet\"" buildConfigField "String", "BUILD_ENVIRONMENT_TYPE", "\"Prod\"" } staging { dimension 'environment' applicationIdSuffix ".staging" buildConfigField "String", "SIGNAL_URL", "\"https://chat.staging.signal.org\"" buildConfigField "String", "STORAGE_URL", "\"https://storage-staging.signal.org\"" buildConfigField "String", "SIGNAL_CDN_URL", "\"https://cdn-staging.signal.org\"" buildConfigField "String", "SIGNAL_CDN2_URL", "\"https://cdn2-staging.signal.org\"" buildConfigField "String", "SIGNAL_CONTACT_DISCOVERY_URL", "\"https://api-staging.directory.signal.org\"" buildConfigField "String", "SIGNAL_KEY_BACKUP_URL", "\"https://api-staging.backup.signal.org\"" buildConfigField "String", "CDS_MRENCLAVE", "\"c98e00a4e3ff977a56afefe7362a27e4961e4f19e211febfbb19b897e6b80b15\"" buildConfigField "org.thoughtcrime.securesms.KbsEnclave", "KBS_ENCLAVE", "new org.thoughtcrime.securesms.KbsEnclave(\"dd6f66d397d9e8cf6ec6db238e59a7be078dd50e9715427b9c89b409ffe53f99\", " + "\"4200003414528c151e2dccafbc87aa6d3d66a5eb8f8c05979a6e97cb33cd493a\", " + "\"ee19f1965b1eefa3dc4204eb70c04f397755f771b8c1909d080c04dad2a6a9ba\")" buildConfigField "org.thoughtcrime.securesms.KbsEnclave[]", "KBS_FALLBACKS", "new org.thoughtcrime.securesms.KbsEnclave[] {" + "new org.thoughtcrime.securesms.KbsEnclave(\"823a3b2c037ff0cbe305cc48928cfcc97c9ed4a8ca6d49af6f7d6981fb60a4e9\", " + "\"16b94ac6d2b7f7b9d72928f36d798dbb35ed32e7bb14c42b4301ad0344b46f29\", " + "\"a3baab19ef6ce6f34ab9ebb25ba722725ae44a8872dc0ff08ad6d83a9489de87\")" + "}" buildConfigField "String", "UNIDENTIFIED_SENDER_TRUST_ROOT", "\"BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx\"" buildConfigField "String", "ZKGROUP_SERVER_PUBLIC_PARAMS", "\"ABSY21VckQcbSXVNCGRYJcfWHiAMZmpTtTELcDmxgdFbtp/bWsSxZdMKzfCp8rvIs8ocCU3B37fT3r4Mi5qAemeGeR2X+/YmOGR5ofui7tD5mDQfstAI9i+4WpMtIe8KC3wU5w3Inq3uNWVmoGtpKndsNfwJrCg0Hd9zmObhypUnSkfYn2ooMOOnBpfdanRtrvetZUayDMSC5iSRcXKpdlukrpzzsCIvEwjwQlJYVPOQPj4V0F4UXXBdHSLK05uoPBCQG8G9rYIGedYsClJXnbrgGYG3eMTG5hnx4X4ntARBgELuMWWUEEfSK0mjXg+/2lPmWcTZWR9nkqgQQP0tbzuiPm74H2wMO4u1Wafe+UwyIlIT9L7KLS19Aw8r4sPrXQ==\"" buildConfigField "String", "MOBILE_COIN_ENVIRONMENT", "\"testnet\"" buildConfigField "String", "SIGNAL_CAPTCHA_URL", "\"https://signalcaptchas.org/staging/registration/generate.html\"" buildConfigField "String", "RECAPTCHA_PROOF_URL", "\"https://signalcaptchas.org/staging/challenge/generate.html\"" buildConfigField "String", "BUILD_ENVIRONMENT_TYPE", "\"Staging\"" buildConfigField "String", "STRIPE_PUBLISHABLE_KEY", "\"pk_test_sngOd8FnXNkpce9nPXawKrJD00kIDngZkD\"" } } android.applicationVariants.all { variant -> variant.outputs.each { output -> if (output.baseName.contains('nightly')) { output.versionCodeOverride = canonicalVersionCode * postFixSize + 5 def tag = getCurrentGitTag() if (tag != null && tag.length() > 0) { if (tag.startsWith("v")) { tag = tag.substring(1) } output.versionNameOverride = tag } } else { output.outputFileName = output.outputFileName.replace(".apk", "-${variant.versionName}.apk") def abiName = output.getFilter("ABI") ?: 'universal' def postFix = abiPostFix.get(abiName, 0) if (postFix >= postFixSize) throw new AssertionError("postFix is too large") output.versionCodeOverride = canonicalVersionCode * postFixSize + postFix } } } android.variantFilter { variant -> def distribution = variant.getFlavors().get(0).name def environment = variant.getFlavors().get(1).name def buildType = variant.buildType.name def fullName = distribution + environment.capitalize() + buildType.capitalize() if (!selectableVariants.contains(fullName)) { variant.setIgnore(true) } } } dependencies { implementation libs.androidx.core.ktx implementation libs.androidx.fragment.ktx lintChecks project(':lintchecks') coreLibraryDesugaring libs.android.tools.desugar implementation (libs.androidx.appcompat) { version { strictly '1.2.0' } } implementation libs.androidx.window implementation libs.androidx.recyclerview implementation libs.material.material implementation libs.androidx.legacy.support implementation libs.androidx.cardview implementation libs.androidx.preference implementation libs.androidx.legacy.preference implementation libs.androidx.gridlayout implementation libs.androidx.exifinterface implementation libs.androidx.constraintlayout implementation libs.androidx.multidex implementation libs.androidx.navigation.fragment.ktx implementation libs.androidx.navigation.ui.ktx implementation libs.androidx.lifecycle.extensions implementation libs.androidx.lifecycle.viewmodel.savedstate implementation libs.androidx.lifecycle.common.java8 implementation libs.androidx.lifecycle.reactivestreams.ktx implementation libs.androidx.camera.core implementation libs.androidx.camera.camera2 implementation libs.androidx.camera.lifecycle implementation libs.androidx.camera.view implementation libs.androidx.concurrent.futures implementation libs.androidx.autofill implementation libs.androidx.biometric implementation libs.androidx.sharetarget implementation (libs.firebase.messaging) { exclude group: 'com.google.firebase', module: 'firebase-core' exclude group: 'com.google.firebase', module: 'firebase-analytics' exclude group: 'com.google.firebase', module: 'firebase-measurement-connector' } implementation libs.google.play.services.maps implementation libs.google.play.services.auth implementation libs.bundles.exoplayer implementation libs.conscrypt.android implementation libs.signal.aesgcmprovider implementation project(':libsignal-service') implementation project(':paging') implementation project(':core-util') implementation project(':glide-config') implementation project(':video') implementation project(':device-transfer') implementation project(':image-editor') implementation project(':donations') implementation project(':contacts') implementation project(':qr') implementation libs.libsignal.android implementation libs.google.protobuf.javalite implementation(libs.mobilecoin) { exclude group: 'com.google.protobuf' } implementation(libs.signal.argon2) { artifact { type = "aar" } } implementation libs.signal.ringrtc implementation libs.leolin.shortcutbadger implementation libs.emilsjolander.stickylistheaders implementation libs.jpardogo.materialtabstrip implementation libs.apache.httpclient.android implementation libs.photoview implementation libs.glide.glide implementation libs.roundedimageview implementation libs.materialish.progress implementation libs.greenrobot.eventbus implementation libs.waitingdots implementation libs.floatingactionbutton implementation libs.google.zxing.android.integration implementation libs.time.duration.picker implementation libs.google.zxing.core implementation (libs.subsampling.scale.image.view) { exclude group: 'com.android.support', module: 'support-annotations' } implementation (libs.numberpickerview) { exclude group: 'com.android.support', module: 'appcompat-v7' } implementation (libs.android.tooltips) { exclude group: 'com.android.support', module: 'appcompat-v7' } implementation (libs.android.smsmms) { exclude group: 'com.squareup.okhttp', module: 'okhttp' exclude group: 'com.squareup.okhttp', module: 'okhttp-urlconnection' } implementation libs.stream implementation (libs.colorpicker) { exclude group: 'com.android.support', module: 'appcompat-v7' exclude group: 'com.android.support', module: 'recyclerview-v7' } implementation libs.lottie implementation libs.stickyheadergrid implementation libs.circular.progress.button implementation libs.signal.android.database.sqlcipher implementation libs.androidx.sqlite implementation (libs.google.ez.vcard) { exclude group: 'com.fasterxml.jackson.core' exclude group: 'org.freemarker' } implementation libs.dnsjava spinnerImplementation project(":spinner") spinnerImplementation libs.square.leakcanary testImplementation testLibs.junit.junit testImplementation testLibs.assertj.core testImplementation testLibs.mockito.core testImplementation testLibs.mockito.kotlin testImplementation testLibs.androidx.test.core testImplementation (testLibs.robolectric.robolectric) { exclude group: 'com.google.protobuf', module: 'protobuf-java' } testImplementation testLibs.robolectric.shadows.multidex testImplementation (testLibs.bouncycastle.bcprov.jdk15on) { force = true } testImplementation testLibs.hamcrest.hamcrest testImplementation(testFixtures(project(":libsignal-service"))) androidTestImplementation testLibs.androidx.test.ext.junit androidTestImplementation testLibs.espresso.core androidTestImplementation testLibs.androidx.test.core androidTestImplementation testLibs.androidx.test.core.ktx androidTestImplementation testLibs.androidx.test.ext.junit.ktx testImplementation testLibs.espresso.core implementation libs.kotlin.stdlib.jdk8 implementation libs.kotlin.reflect implementation libs.jackson.module.kotlin implementation libs.rxjava3.rxandroid implementation libs.rxjava3.rxkotlin implementation libs.rxdogtag androidTestUtil 'androidx.test:orchestrator:1.4.1' } def getLastCommitTimestamp() { if (!(new File('.git').exists())) { return System.currentTimeMillis().toString() } new ByteArrayOutputStream().withStream { os -> def result = exec { executable = 'git' args = ['log', '-1', '--pretty=format:%ct'] standardOutput = os } return os.toString() + "000" } } def getGitHash() { if (!(new File('.git').exists())) { return "abcd1234" } def stdout = new ByteArrayOutputStream() exec { commandLine 'git', 'rev-parse', '--short', 'HEAD' standardOutput = stdout } return stdout.toString().trim() } def getCurrentGitTag() { if (!(new File('.git').exists())) { return '' } def stdout = new ByteArrayOutputStream() exec { commandLine 'git', 'tag', '--points-at', 'HEAD' standardOutput = stdout } def output = stdout.toString().trim() if (output != null && output.size() > 0) { def tags = output.split('\n').toList() return tags.stream().filter(t -> t.contains('nightly')).findFirst().orElse(tags.get(0)) } else { return null } } tasks.withType(Test) { testLogging { events "failed" exceptionFormat "full" showCauses true showExceptions true showStackTraces true } } def loadKeystoreProperties(filename) { def keystorePropertiesFile = file("${project.rootDir}/${filename}") if (keystorePropertiesFile.exists()) { def keystoreProperties = new Properties() keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) return keystoreProperties; } else { return null; } } def getDateSuffix() { def date = new Date() def formattedDate = date.format('yyyy-MM-dd-HH:mm') return formattedDate }