Skip to main content

Tarea 3 - Build Systems: Plugins

Hasta ahora, has trabajado con plugins que implementan Plugin<Project>, permitiendo aplicar configuraciones específicas a proyectos. Sin embargo, Gradle proporciona una interfaz más general llamada Plugin<PluginAware>. Esta interfaz es útil cuando quieres que tu plugin pueda aplicarse tanto a un Project como a Settings, permitiendo configurar aspectos específicos dependiendo del tipo de objeto al que se aplique.

Diferencias clave:

  • Plugin<Project>: Se aplica específicamente a proyectos Gradle, permitiendo configurar tareas, dependencias y extensiones a nivel de proyecto.
  • Plugin<Settings>: Se aplica al objeto Settings, permitiendo configurar aspectos globales del build, como los repositorios de plugins y convenciones de configuración para subproyectos.
  • Plugin<PluginAware>: Es una interfaz más general que puede aplicarse tanto a Project como a Settings. Te permite escribir un plugin que adapte su comportamiento dependiendo del tipo de objeto al que se aplique.

Ejemplo de plugin adaptable

import org.gradle.api.Plugin
import org.gradle.api.PluginAware
import org.gradle.api.Project
import org.gradle.api.initialization.Settings

class AdaptivePlugin : Plugin<PluginAware> {
override fun apply(target: PluginAware) {
when (target) {
is Project -> {
// Configuraciones específicas para proyectos
target.tasks.register("hello") {
doLast {
println("Hello from the Project!")
}
}
}
is Settings -> {
// Configuraciones específicas para settings
target.gradle.rootProject {
println("Configuring settings for the build.")
}
}
else -> {
throw IllegalArgumentException("Plugin can only be applied to Project or Settings.")
}
}
}
}

En este ejemplo, el plugin AdaptivePlugin verifica si el objeto al que se aplica es un Project o Settings y aplica configuraciones específicas en consecuencia.

Agregando dependencias y repositorios en el plugin

Es importante notar que los plugins implementados como clases no tienen acceso al catálogo de versiones de Gradle (libs.versions.toml). Por lo tanto, debes especificar las versiones de las dependencias directamente en el plugin.

Para agregar una dependencia a un objeto Project, puedes usar:

project.dependencies.add("implementation", "group:artifact:version")

Tarea

Supongamos que quieres hacer un bot de Telegram. Con el fin de hacer una buena separación entre la lógica de negocio y aplicación, decides separar el código en dos subproyectos: core y bot. El subproyecto core contendrá la lógica para interactuar con la API de Telegram como enviar mensajes, recibir actualizaciones, etc. El subproyecto bot contendrá la lógica de aplicación específica, como manejar la base de datos y recibir comandos por consola.

Para manejar la interacción con la API de Telegram, decides utilizar Kotlin Telegram Bot. Sin embargo, te das cuenta de que si el bot crece podrías tener que crear más módulos que interactúen con la API de Telegram. Por lo tanto, decides implementar un plugin de Gradle que permita configurar la dependencia de Kotlin Telegram Bot solamente en los subproyectos que lo necesiten.

P1. [2.5 pts] Manejo de repositorios y dependencias

Crea un plugin TelegramBotPlugin que implemente Plugin<PluginAware>. El plugin debe:

  • Si se aplica a Settings: Configurar el repositorio de JitPack con la URL https://jitpack.io.
  • Si se aplica a un Project: Agregar la dependencia io.github.kotlin-telegram-bot.kotlin-telegram-bot:telegram:6.2.0.
warning

Dado que los plugins implementados como clases no tienen acceso al catálogo de versiones, debes especificar la versión 6.2.0 directamente en el plugin.

P2. [3.5] Plugin para configurar Detekt

Te das cuenta de que podrías necesitar varios plugins de Detekt en tu proyecto, pero los plugins no serán los mismos para todos los módulos. Por lo tanto, decides crear un plugin pre-compilado que permita especificar qué plugins de Detekt se deben aplicar a cada subproyecto de forma independiente.

  1. [1 pt] Crea una extensión que te permita configurar una lista de plugins de Detekt.

  2. [1 pt] Crea un plugin pre-compilado que registre la extensión y aplique el plugin DetektPlugin, para esto necesitarás definir la siguiente dependencia:

    [libraries]
    # ...
    detekt = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version.ref = "detekt" }
  3. [1.5 pts] Haz que el plugin aplique los plugins de Detekt especificados en la extensión. Para esto, puedes hacer "detektPlugins"(plugin) dentro de un bloque dependencies, donde plugin es un String que contiene el nombre del plugin de Detekt. Por ejemplo:

    dependencies {
    "detektPlugins"("io.gitlab.arturbosch.detekt:detekt-formatting:1.18.1")
    "detektPlugins"("com.faire:faire-detekt-rules:0.2.4")
    }

Ejemplo de uso

plugins {
id("detekt.conventions")
}

detektConfig {
plugins = listOf(
"io.gitlab.arturbosch.detekt:detekt-formatting:1.18.1",
"com.faire:faire-detekt-rules:0.2.4"
)
}

Hint: Define el bloque dependencies dentro de un bloque afterEvaluate para que se aplique después de que se hayan configurado todas las dependencias.