chore: Convetion Plugins introduccion [VPNAND-2527]

This commit is contained in:
Alexander Talledo
2026-02-13 15:07:01 +01:00
committed by MargeBot
parent fc0874ed0c
commit d28fc5a7e6
17 changed files with 423 additions and 54 deletions

View File

@@ -37,7 +37,7 @@ buildscript {
}
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.proton.vpn.android.application)
alias(libs.plugins.android.compose.screenshot)
alias(libs.plugins.androidx.baselineprofile)
alias(libs.plugins.androidx.room)
@@ -45,7 +45,6 @@ plugins {
alias(libs.plugins.detekt)
alias(libs.plugins.jacoco)
alias(libs.plugins.jaredsburrows.gradle.license)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.kotlin.parcelize)
alias(libs.plugins.kotlin.serialization)
@@ -143,8 +142,6 @@ def debugKeystorePath = System.getenv("DEBUG_KEYSTORE_FILE")
android {
namespace "com.protonvpn.android"
testNamespace 'com.protonvpn'
ndkVersion rootProject.ext.compileNdkVersion
compileSdk rootProject.ext.compileSdkVersion
useLibrary 'org.apache.http.legacy'
signingConfigs {
if (debugKeystorePath) {
@@ -163,8 +160,6 @@ android {
}
defaultConfig {
applicationId appId
minSdkVersion rootProject.ext.minSdkVersion // See also build flavors.
targetSdkVersion 35
multiDexEnabled true
versionName helpers.fullVersionName
versionCode helpers.getVersionCode()
@@ -387,17 +382,15 @@ android {
// Adds exported schema location as test app assets.
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
}
compileOptions {
targetCompatibility JavaVersion.VERSION_17
sourceCompatibility JavaVersion.VERSION_17
coreLibraryDesugaringEnabled = true
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString()
freeCompilerArgs += [
"-Xopt-in=kotlin.RequiresOptIn"
]
freeCompilerArgs += ["-Xopt-in=kotlin.RequiresOptIn"]
}
lint {
// In our process we might temporarily have extra translations that will get removed on
// next update.

1
build-logic/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2026 Proton AG
*
* This file is part of ProtonVPN.
*
* ProtonVPN is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonVPN 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonVPN. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
`kotlin-dsl`
}
group = "com.protonvpn.android.build.logic"
dependencies {
compileOnly(libs.android.tools.build.gradle)
compileOnly(libs.kotlin.gradle.plugin)
}
gradlePlugin {
plugins {
register("android-application") {
id = "me.proton.vpn.android.application"
implementationClass = "com.protonvpn.android.build.logic.plugins.ProtonVpnAndroidApplicationConventionPlugin"
}
register("android-library") {
id = "me.proton.vpn.android.library"
implementationClass = "com.protonvpn.android.build.logic.plugins.ProtonVpnAndroidLibraryConventionPlugin"
}
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2026 Proton AG
*
* This file is part of ProtonVPN.
*
* ProtonVPN is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonVPN 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonVPN. If not, see <https://www.gnu.org/licenses/>.
*/
rootProject.name = "build-logic"
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2026 Proton AG
*
* This file is part of ProtonVPN.
*
* ProtonVPN is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonVPN 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonVPN. If not, see <https://www.gnu.org/licenses/>.
*/
package com.protonvpn.android.build.logic.domain.config
import org.gradle.api.JavaVersion
internal object AndroidConfig {
internal const val COMPILE_SDK_VERSION = 36
internal const val MIN_SDK_VERSION = 26
internal const val TARGET_SDK_VERSION = 35
internal const val NDK_VERSION = "28.1.13356709"
internal val CompileJavaVersion: JavaVersion = JavaVersion.VERSION_17
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2026 Proton AG
*
* This file is part of ProtonVPN.
*
* ProtonVPN is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonVPN 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonVPN. If not, see <https://www.gnu.org/licenses/>.
*/
package com.protonvpn.android.build.logic.domain.dependencies
internal enum class PluginDependency(internal val alias: String) {
AndroidApplication(alias = "android-application"),
AndroidLibrary(alias = "android-library"),
KotlinAndroid(alias = "kotlin-android"),
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2026 Proton AG
*
* This file is part of ProtonVPN.
*
* ProtonVPN is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonVPN 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonVPN. If not, see <https://www.gnu.org/licenses/>.
*/
package com.protonvpn.android.build.logic.domain.plugins
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
import com.protonvpn.android.build.logic.domain.config.AndroidConfig
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
internal abstract class AndroidApplicationConventionPlugin : ConventionPlugin() {
protected fun Project.configureAndroidApplication() {
extensions.configure<BaseAppModuleExtension> {
compileSdk = AndroidConfig.COMPILE_SDK_VERSION
ndkVersion = AndroidConfig.NDK_VERSION
defaultConfig {
minSdk = AndroidConfig.MIN_SDK_VERSION
targetSdk = AndroidConfig.TARGET_SDK_VERSION
}
compileOptions {
sourceCompatibility = AndroidConfig.CompileJavaVersion
targetCompatibility = AndroidConfig.CompileJavaVersion
}
}
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2026 Proton AG
*
* This file is part of ProtonVPN.
*
* ProtonVPN is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonVPN 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonVPN. If not, see <https://www.gnu.org/licenses/>.
*/
package com.protonvpn.android.build.logic.domain.plugins
import com.android.build.api.dsl.LibraryExtension
import com.protonvpn.android.build.logic.domain.config.AndroidConfig
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
internal abstract class AndroidLibraryConventionPlugin : ConventionPlugin() {
protected fun Project.configureAndroidLibrary() {
extensions.configure<LibraryExtension> {
compileSdk = AndroidConfig.COMPILE_SDK_VERSION
ndkVersion = AndroidConfig.NDK_VERSION
defaultConfig {
minSdk = AndroidConfig.MIN_SDK_VERSION
}
compileOptions {
sourceCompatibility = AndroidConfig.CompileJavaVersion
targetCompatibility = AndroidConfig.CompileJavaVersion
}
}
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (c) 2026 Proton AG
*
* This file is part of ProtonVPN.
*
* ProtonVPN is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonVPN 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonVPN. If not, see <https://www.gnu.org/licenses/>.
*/
package com.protonvpn.android.build.logic.domain.plugins
import com.protonvpn.android.build.logic.domain.dependencies.PluginDependency
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.api.plugins.PluginAware
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
internal abstract class ConventionPlugin : Plugin<Project> {
protected fun Project.applyPlugins(vararg pluginDependencies: PluginDependency) {
pluginDependencies.forEach { pluginDependency ->
applyPlugin(pluginDependency = pluginDependency)
}
}
protected fun Project.applyPlugin(pluginDependency: PluginDependency) {
getVersionCatalogsPlugin(pluginAlias = pluginDependency.alias).also { plugin ->
applyPlugin(pluginId = plugin.pluginId)
}
}
private fun PluginAware.applyPlugin(pluginId: String) {
apply(plugin = pluginId)
}
protected fun Project.configureKotlinOptions() {
tasks.withType(type = KotlinJvmCompile::class) {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_17)
}
}
}
private fun Project.getVersionCatalogsPlugin(pluginAlias: String) = getVersionCatalogs()
.findPlugin(pluginAlias)
.get()
.get()
private fun Project.getVersionCatalogs() = extensions
.getByType<VersionCatalogsExtension>()
.named(VERSION_CATALOGS_CONTAINER_NAME)
private companion object {
private const val VERSION_CATALOGS_CONTAINER_NAME = "libs"
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2026 Proton AG
*
* This file is part of ProtonVPN.
*
* ProtonVPN is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonVPN 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonVPN. If not, see <https://www.gnu.org/licenses/>.
*/
package com.protonvpn.android.build.logic.plugins
import com.protonvpn.android.build.logic.domain.dependencies.PluginDependency
import com.protonvpn.android.build.logic.domain.plugins.AndroidApplicationConventionPlugin
import org.gradle.api.Project
internal class ProtonVpnAndroidApplicationConventionPlugin : AndroidApplicationConventionPlugin() {
override fun apply(project: Project) = with(receiver = project) {
applyPlugins(
pluginDependencies = arrayOf(
PluginDependency.AndroidApplication,
PluginDependency.KotlinAndroid,
)
)
configureAndroidApplication()
configureKotlinOptions()
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2026 Proton AG
*
* This file is part of ProtonVPN.
*
* ProtonVPN is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonVPN 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonVPN. If not, see <https://www.gnu.org/licenses/>.
*/
package com.protonvpn.android.build.logic.plugins
import com.protonvpn.android.build.logic.domain.dependencies.PluginDependency
import com.protonvpn.android.build.logic.domain.plugins.AndroidLibraryConventionPlugin
import org.gradle.api.Project
internal class ProtonVpnAndroidLibraryConventionPlugin : AndroidLibraryConventionPlugin() {
override fun apply(project: Project) = with(receiver = project) {
applyPlugins(
pluginDependencies = arrayOf(
PluginDependency.AndroidLibrary,
PluginDependency.KotlinAndroid,
)
)
configureAndroidLibrary()
configureKotlinOptions()
}
}

View File

@@ -42,10 +42,7 @@ plugins {
}
project.ext {
minSdkVersion = 26
minSdkVersionAmazon = 25 // Fire OS 6, see VPNAND-1914.
compileSdkVersion = 36
compileNdkVersion = "28.1.13356709"
}
allprojects {

View File

@@ -92,6 +92,7 @@ airbnb-lottie = { group = "com.airbnb.android", name = "lottie", version.ref = "
airbnb-lottie-compose = { group = "com.airbnb.android", name = "lottie-compose", version.ref = "airbnb-lottie-version" }
android-flexbox = { group = "com.google.android.flexbox", name = "flexbox", version.ref = "android-flexbox-version" }
android-material = { group = "com.google.android.material", name = "material", version.ref = "android-material-version" }
android-tools-build-gradle = { group = "com.android.tools.build", name = "gradle", version.ref = "agp-version" }
android-tools-desugar-jdk-libs = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "android-tools-version" }
androidx-activity-ktx = { group = "androidx.activity", name = "activity-ktx", version.ref = "androidx-activity-version" }
androidx-arch-core-testing = { group = "androidx.arch.core", name = "core-testing", version.ref = "androidx-arch-core-version" }
@@ -184,6 +185,7 @@ google-truth = { group = "com.google.truth", name = "truth", version.ref = "goog
java-jna = { group = "net.java.dev.jna", name = "jna", version.ref = "java-jna-version" }
junit = { group = "junit", name = "junit", version.ref = "junit-version" }
kotlin-bom = { group = "org.jetbrains.kotlin", name = "kotlin-bom", version.ref = "kotlin-version" }
kotlin-gradle-plugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin" }
kotlin-test = { group = "org.jetbrains.kotlin", name = "kotlin-test" }
kotlin-test-junit = { group = "org.jetbrains.kotlin", name = "kotlin-test-junit" }
kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinx-coroutines-version" }
@@ -317,5 +319,7 @@ kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", versi
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp-version" }
owasp-dependencycheck = { id = "org.owasp.dependencycheck", version.ref = "owasp-dependencycheck-version" }
proton-core-env-config = { id = "me.proton.core.gradle-plugins.environment-config", version.ref = "proton-core-env-config-version" }
proton-vpn-android-application = { id = "me.proton.vpn.android.application" }
proton-vpn-android-library = { id = "me.proton.vpn.android.library" }
sentry = { id = "io.sentry.android.gradle", version.ref = "sentry-plugin-version" }
triplet-play = { id = "com.github.triplet.play", version.ref = "triplet-play-version" }

View File

@@ -20,15 +20,13 @@ import groovy.json.StringEscapeUtils
*/
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.proton.vpn.android.application)
}
def debugKeystorePath = file(new File(rootDir, "app/${System.getenv("DEBUG_KEYSTORE_FILE")}"))
android {
namespace "com.protonvpn.android.release_tests"
compileSdk rootProject.ext.compileSdkVersion
signingConfigs {
release {
@@ -41,8 +39,6 @@ android {
defaultConfig {
applicationId "com.protonvpn.android.release_tests"
minSdkVersion rootProject.ext.minSdkVersion
targetSdk 35
versionCode 1
versionName "1.0"
def lokiEndpoint = System.getenv("LOKI_ENDPOINT")
@@ -63,6 +59,7 @@ android {
buildFeatures {
buildConfig = true
}
buildTypes {
release {
minifyEnabled false
@@ -70,13 +67,6 @@ android {
signingConfig signingConfigs.release
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString()
}
}
dependencies {

View File

@@ -20,6 +20,8 @@
rootProject.name = "ProtonVPN"
pluginManagement {
includeBuild("build-logic")
repositories {
val mavenCachePkgUrl = System.getenv("MAVEN_CACHE_PKG_URL")
if (!mavenCachePkgUrl.isNullOrBlank()) {

View File

@@ -18,20 +18,15 @@
*/
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.dagger.hilt)
alias(libs.plugins.ksp)
alias(libs.plugins.proton.vpn.android.library)
}
apply plugin: 'dagger.hilt.android.plugin'
android {
namespace 'com.protonvpn.test.shared'
compileSdk rootProject.ext.compileSdkVersion
defaultConfig {
minSdk rootProject.ext.minSdkVersionAmazon
consumerProguardFiles "consumer-rules.pro"
}
@@ -78,16 +73,13 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
coreLibraryDesugaringEnabled = true
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString()
freeCompilerArgs += [
"-Xopt-in=kotlin.RequiresOptIn"
]
freeCompilerArgs += ["-Xopt-in=kotlin.RequiresOptIn"]
}
}

View File

@@ -1,16 +1,30 @@
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
}
/*
* Copyright (c) 2026 Proton AG
*
* This file is part of ProtonVPN.
*
* ProtonVPN is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonVPN 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonVPN. If not, see <https://www.gnu.org/licenses/>.
*/
val minSdkVersion: Int by rootProject.extra
plugins {
alias(libs.plugins.proton.vpn.android.library)
}
android {
namespace = "com.protonvpn.android.ui_automator_test_util"
compileSdk = 36
defaultConfig {
minSdk = minSdkVersion
consumerProguardFiles("consumer-rules.pro")
}
@@ -23,13 +37,6 @@ android {
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString()
}
}
dependencies {