Declarative Gradle - November 2024 Update

In November 2024, we announced the second Early Access Preview (EAP 2) of Declarative Gradle. Learn more about the release, try out the samples and share your feedback!

Table of Contents

Introduction #

A year ago, we announced a new experimental project called Declarative Gradle. That blog post presented our vision for a declarative model for Gradle. It also introduced our concept of a developer-centric software definition. This was followed by the first Early Access Preview release in July 2024, accompanied by the First Look at Declarative Gradle blog post. The first EAP introduced a configuration model called Software Types, a new Declarative Configuration Language (DCL), and demonstrated the potential for tooling improvements and better IDE support.

It is now easier to try Declarative Gradle. The first EAP was based on separate Declarative Gradle prototype plugins. These prototype plugins implement Software Types wrapping existing plugins like Android Gradle Plugin (AGP) and Kotlin Multiplatform (KMP), making them usable from DCL. Since then, we’ve worked with the Android Studio team to expose their existing model of the Android Gradle Plugin as a Software Type directly in DCL to demonstrate Declarative Gradle on a real-world plugin with elaborate DSL. We also experimented with other IDEs and enhanced gradle init to generate starter projects that use DCL. With those efforts concluded, we are happy to announce the second EAP release!

This blog post provides an update on the project’s progress and outlines how you can provide feedback and influence our next steps.

Declarative Gradle is still in an experimental stage and is not ready for production use. We are providing a second early access preview to gather more feedback from the community. We invite you to try out the samples and the demo applications and to share your feedback.

Declarative Gradle - November 2024 Update

Official Android Software Type Preview #

We worked with the Android Studio team to enable the Android Gradle Plugin (AGP) to expose its existing models, aka. Project extensions, directly as Software Types, to make them available in DCL. The new AGP ecosystem plugin now exposes androidApp and androidLibrary Software Types, which you can use to quickly define a project:

build.gradle.dcl

androidApp {
  compileSdk = 35
  defaultConfig {
    minSdk = 29
    targetSdk = 35
    testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
  }
}

This means that the existing AGP models can benefit from all DCL features. The build definition is declarative, common configuration can be expressed via a declarative settings file, the IDE support is working as intended, and tools can work with the build definition.

Here is how a sample build declares common configuration in a DCL settings file:

settings.gradle.dcl

// [SNIP] pluginManagement { repositories }

plugins {
  id("com.android.ecosystem").version("8.9.0-dev")
}

defaults {
  androidLibrary {
    compileSdk = 35
  }
  androidApp {
    compileSdk = 35
    defaultConfig {
      minSdk = 29
      targetSdk = 35
      testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }
  }
}

And how sub-projects declare specific configurations in their DCL files:

lib/build.gradle.dcl

androidLibrary {
  namespace = "com.example.lib"
}

app/build.gradle.dcl

androidApp {
  namespace = "com.example.app"
}

Note that this is not available in regular AGP releases. To use this you need to use special AGP nightlies. Also, note that some parts of the AGP model are not available yet for DCL configuration. See below how to try this yourself.

New DCL Language Features #

We evolved the DCL language with two new features: enum properties and containers.

It is now possible for Software Types to expose properties with enum values and to assign them concisely in DCL files. This new feature is based on Kotlin’s KEEP-379 Improve resolution using expected type. Assignments of enum values to properties use unqualified references. Qualified references are explicitly unsupported. Here is how it looks:

lib/build.gradle.dcl

androidLibrary {
  compileOptions {
    // Unqualified reference to JavaVersion.VERSION_17 in property assignment
    sourceCompatibility = VERSION_17 
  }
}

Likewise, it is now possible for Software Types to expose NamedDomainObjectContainer<T> nested objects and to configure their elements in DCL files. There is only one way to configure the elements of containers in DCL, using a function with “register or configure” semantics. Here is how it looks on the AGP model for Android build types:

lib/build.gradle.dcl

androidLibrary {
  buildTypes {
    buildType("debug") {
      isMinifyEnabled = false
    }
    buildType("release") {
      isMinifyEnabled = true
    }
  }
}

Updated IDE Support

The Android Studio team has also brought support for these two features to Android Studio. Syntax highlighting and code completion work as intended, as shown in the following screencast:

In the video above you can see that thanks to the strictness of DCL, the IDE assistance is exempt of noise. Code completion only suggests the properties and nested blocks available in the current scope.

The IntelliJ IDEA team at JetBrains also integrated the same support for DCL into their IDE.

Configuring Software Types from Kotlin DSL #

Software Types are the cornerstone of a developer-first declarative build definition, allowing authors to streamline configuration for common deliverables like Java libraries or Android applications. This feature has received great feedback from the community and as an experiment, we would like to make it available for build scripts defined via Kotlin DSL.

In this second EAP, we made it possible to configure Software Types from Gradle’s Kotlin DSL. Given the DCL language is a strict subset of the Kotlin language, it is not a surprise that a Kotlin DSL file declaring the configuration of a Software Type looks the very same as a DCL file declaring the same configuration:

build.gradle.kts

javaApplication {
    mainClass = "com.example.Main"
    dependencies {
        implementation("com.google.guava:guava:31.0-jre")
    }
}

build.gradle.dcl

javaApplication {
    mainClass = "com.example.Main"
    dependencies {
        implementation("com.google.guava:guava:31.0-jre")
    }
}

With the Kotlin DSL, you can still add some imperative custom build logic around the Software Type declaration. If the .gradle.kts file is purely declaratively configuring a Software Type, then Gradle will use the DCL interpreter to evaluate the file. Otherwise the Kotlin compiler will be used and the compiled script executed as usual.

To enable Software Types and DCL support in Kotlin DSL scripts, you need to set a Gradle property in your gradle.properties file:

gradle.properties

org.gradle.kotlin.dsl.dcl=true

Adding this capability is essential to allow for a gradual migration to Software Types and DCL in the future. We plan to add the same capability to our Groovy DSL down the road.

Example - Now In Android

Leveraging this new capability, we reworked our fork of the NowInAndroid sample application build to use Software Types in all of its projects. Some of its projects are fully declarative and use Software Types from the DCL language; others that still require some custom build logic on top of the declarative parts use Software Types from Kotlin DSL build scripts.

Here’s an example of a Kotlin DSL script configuring the androidLibrary Software Type declaratively but also defining and registering an ad-hoc task imperatively:

core/datastore-proto/build.gradle.kts

androidLibrary {
    namespace = "com.google.samples.apps.nowinandroid.core.datastore.proto"
    protobuf {
        enabled = true
        option = "lite"
    }
}

// Define and register a misc one-off task imperatively
abstract class PrintProtobufTasks : DefaultTask() {
    @get:Input abstract val protoTasks: Property<String>
    @TaskAction
    fun printTasks() {
        println("Protobuf tasks report:\n${protoTasks.get()}")
    }
}
tasks.register("protobufTasks", PrintProtobufTasks::class) {
    protoTasks = tasks.filter { task ->
        task.name.lowercase().contains("proto")
    }.joinToString("\n")
}

You can look at the core/datastore-proto/build.gradle.kts file in more detail in the NowInAndroid repository to see how to configure Android Gradle Plugins options that are not yet supported with DCL.

Going forward, we will investigate how to make migration as seamless as possible, how IDE support can be tweaked to be helpful along the way, and how we can preserve the flexibility of quickly prototyping imperative build logic directly in build files thanks to the Kotlin DSL support for Software Types.

Support for VS Code and Eclipse IDE #

Having DCL support in Android Studio and IntelliJ IDEA is nice, but we want Declarative Gradle to get first-class support in all modern IDEs. So, we worked on a Language Server for DCL using the Language Server Protocol (LSP) - a standard protocol that other IDEs and developer tools can use. Additionally, we built integrations for Visual Studio Code (VS Code) and the Eclipse IDE.

Both VS Code and Eclipse integrations support syntax highlighting, semantic errors, and code completion at the same level as Android Studio or IntelliJ IDEA, as shown above. The VS Code integration also support our build definition mutation framework, which we demonstrated in July using a demonstration client application. The available mutations are surfaced in the IDE editor as actions the user can take directly on the DCL files.

Here is a screencast of the DCL language support in VS Code:

Here is a screencast of the DCL language support in the Eclipse IDE:

Generating Declarative Builds #

In order to make it easier for you to try out Declarative Gradle, you can now generate your own application or library projects using Software Types and DCL via gradle init.

An experimental system property has been added to Gradle to add new things that gradle init can generate. Together with this post we ship generators for Java, Kotlin and Android projects based on our prototype plugins.

Continue reading for instructions on how to use this.

Try Declarative Gradle Today #

You can try all the above today by generating new Declarative Gradle builds with gradle init, checking out sample repositories, and installing a special version of Android Studio or IntelliJ IDEA, the Declarative Gradle experimental feature for the Eclipse IDE, or our Declarative Gradle extension for Visual Studio Code. You’ll find instructions for doing all this on the declarative.gradle.org website.

Try Declarative Gradle

After you’ve tried things out, we’d appreciate it if you could submit your feedback. This should only take a few minutes and is anonymous unless you choose to provide your email address.

What’s Next? #

Our goal is to incubate Software Types and Declarative Configuration Language (DCL) in 2025 as core Gradle features. Before that, we plan to release another EAP in early 2025, to address the feedback from early adopters. It is a great time to share your feedback! See the public Declarative Gradle Roadmap to learn more about the target milestones.

Over the next few months, we will be working on validating the Software Types concept and associated APIs by implementing several use cases. Our focus is on the extensibility and composability of Software Types to add new features. Gradle plugins should be able to extend existing Software Types and collaborate with each other. For example, a Jacoco Gradle plugin would augment base JVM plugins to add code coverage capabilities and configuration, and a Compose plugin would augment the Android plugin to add Jetpack Compose capabilities and configuration.

We aim to make Declarative Gradle usable in real projects, as soon as possible, to enable quality feedback while still remaining experimental. At the moment, there are major missing features that are blocking you from using Declarative Gradle in real-world projects, such as being able to add and configure tests. We are working on adding such missing capabilities. Similarly, we’re advancing support for the existing AGP model to ensure projects using it declaratively are fully functional. The goal is to be able to build an Android application that can be published to the Google Play store using Declarative Gradle in the next EAP. This includes adding testing support and expanding DCL language features.

Learn More #

Discuss