Skip to content

prokod/gradle-crossbuild-scala

Repository files navigation

Gradle crossbuild Scala plugin

Build Status codecov Automated Release Notes by gren Gradle Plugin Portal

Features

  • Scala3 support Seamlessly cross building of both Scala 2.x and Scala 3.x with unified DSL.
  • Multi-module projects support Supports both simple projects and multi-module projects.
    In multi-module projects support mixed cases where only some of the modules needs cross compiling.
  • Powerful DSL Plugin DSL can be written once for all subprojects using subprojects {} block.
    Specific DSL definition can be afterward added to individual subprojects.
    It supports shorthands to avoid repetitions.
    Operates in both eager and lazy (wrapped in pluginManager.withPlugin {} block) apply modes.
  • Multi-aspect cross building Supports cross building for Scala aspect and on top of that any other custom aspect, for instance Spark. Further details multi-aspect cross building
  • Integrates with maven-publish plugin When used, can be leveraged to publish cross building artifacts.
  • Implicit/Explicit scala lib dependency declaration Supports declaring both
    simple case implicit implementation 3rd-party-scala-lib_2.12 type of dependencies
    and also finer granular explicit crossBuildSpark24_212Implementation spark-streaming-kafka-0-10_2.12 type of dependencies.
  • Applied easily on existing projects As the plugin maintains a strict separation between main source set configurations and crossBuildXYZ ones, a simple non-cross build project can be easily and gradually transformed to a cross build one.
  • Testing support As mentioned above strict separation of source sets, keeps main source set test configurations intact.

Shortcomings

  • test/check tasks are supported for default-variant of Scala version only.
  • publishing for source/javadoc jars are supported for default-variant of Scala version only.

Getting the plugin

Using the plugins DSL

plugins {
    id "com.github.prokod.gradle-crossbuild-scala" version "0.16.0"
}

Using legacy buildscript

buildscript {
    dependencies {
        classpath("com.github.prokod:gradle-crossbuild-scala:0.16.0")
    }
}

Quick start

Recommended cross building apply strategy

This is especially true for multi-module projects but not just.

  • Wire up your build scripts in the project in such a way that you are able to successfully build it for single scala version.

    Note Do not worry in this stage about publishing artifacts as cross building with publishing is supported by the plugin.
    It will be somewhat wasted effort to do that here and then modify it to the cross build scenario.

  • After that add the cross building plugin without changing any of the internal and external dependencies. Follow base step - getting the plugin and then configure it further using the following guidelines: plugin configuration options and basic plugin configuration

    Note If you have to change your dependencies because of applying the plugin and trying explicitly gradle build, something is fishy.
    You see, the plugin is designed in such a way that it borrows from the state of the project's dependency tree already in place without changing it. It then adds a somewhat parallel dependency tree for each of the cross building variants.

  • To configure the plugin efficiently please follow Multi module projects apply patterns.

    Note From version 0.12.x there is no need to have any special glob pattern to express cross build dependency for implementation/api/runtime/... configurations - the plugin will add a correct dependency resolution according to the provided crossBuild {} plugin dsl block.
    Up to version 0.11.x (inclusive) use the '?' question mark to express cross build dependency inside implementation/api/runtime/... configurations.
    Use the provided explicit crossBuildXYZImplementation/api/Runtime/... configuration when you need a finer granularity in expressing the cross build dependencies

  • Publish cross building artifacts, for that please take a look at publishing

    Note cross build artifact naming is governed by archive.appendixPattern which by default is _? meaning for example, that module lib will be resolved to lib_2.11/_2.12/... according to the correlating crossBuild {} plugin dsl block

  • To test that everything works as expected:

    1. gradle build - which runs build and tests for a single Scala version - default one.
    2. gradle crossBuildAssemble - which builds ans assembles all cross build into respective artifacts.
    3. gradle publishToMavenLocal - which goes from cross building, artifact creation (as above) and then publishing to local maven.

    Note Look under build/libs , ~/.m2/repository/... respectively, to assert the end result is the one you have wished for. crossBuildAssemble task is available from version 0.15.0

Multi-module projects and applying cross build plugin only for some

From version 0.11.x the plugin supports multi-module projects where only some modules have cross build plugin applied to.
This helps with cases where some modules depend on legacy plugins that do not play nicely with the cross build plugin like legacy play plugin for instance :)
Thanks borissmidt for the collaboration on that.

Cross building - basic plugin configuration

Applying the plugin

  1. Apply the plugin and use the provided DSL. For example:

    archivesBaseName = 'lib'
    
    apply plugin: 'com.github.prokod.gradle-crossbuild-scala'
    
    crossBuild {
        builds {
            v211
            v212
        }
    }

    Note Another variant which might appeal aesthetically better to some

    archivesBaseName = 'lib'
    
    apply plugin: 'com.github.prokod.gradle-crossbuild-scala'
    
    crossBuild {
        builds {
            scala {
                scalaVersions = ['2.11', '2.12']
            }
        }
    }
    dependencies {
        implementation ("com.google.protobuf:protobuf-java:$protobufVersion")
        implementation ("joda-time:joda-time:$jodaVersion")
        // Scala 2.12 is the default cross built Scala version
        // the plugin replaces the default based on the Scala version being built
        implementation ("org.scalaz:scalaz_2.12:$scalazVersion")
    }

    Note Up to version 0.11.x (inclusive) 3rd party Scala lib dependencies are expressed using '?' question mark (when using implicit pattern type dependencies)

    dependencies {
        implementation ("com.google.protobuf:protobuf-java:$protobufVersion")
        implementation ("joda-time:joda-time:$jodaVersion")
        // The question mark is being replaced based on the Scala version being built
        implementation ("org.scalaz:scalaz_?:$scalazVersion")
    }
  2. gradle tasks

    gradle-crossbuild plugin adds the following user faced tasks to the project crossBuild211Classes, crossBuild211Jar, crossBuild212Classes, crossBuild212Jar based on the plugin DSL builds {} block

    > ./gradlew tasks
    
    ------------------------------------------------------------
    All tasks runnable from root project
    ------------------------------------------------------------
    
    Build tasks
    -----------
    assemble - Assembles the outputs of this project.
    build - Assembles and tests this project.
    buildDependents - Assembles and tests this project and all projects that depend on it.
    buildNeeded - Assembles and tests this project and all projects it depends on.
    classes - Assembles main classes.
    clean - Deletes the build directory.
    crossBuildV211Classes - Assembles cross build v211 classes.
    crossBuildV211Jar - Assembles a jar archive containing 211 classes
    crossBuildV212Classes - Assembles cross build v212 classes.
    crossBuildV212Jar - Assembles a jar archive containing 212 classes
    jar - Assembles a jar archive containing the main classes.
    testClasses - Assembles test classes.
    ...
  3. gradle crossBuildV211Jar crossBuildV212Jar ...

    > ./gradlew crossBuildV211Jar crossBuildV212Jar
    ...
    Tasks to be executed: [task ':compileCrossBuildV211Java', task ':compileCrossBuildV211Scala', task ':processCrossBuildV211Resources', task ':crossBuildV211Classes', task ':crossBuildV211Jar', task ':compileCrossBuildV212Java', task ':compileCrossBuildV212Scala', task ':processCrossBuildV212Resources', task ':crossBuildV212Classes', task ':crossBuildV212Jar']
    ...
    :crossBuildV211Jar (Thread[Connection worker,5,main]) completed. Took 0.04 secs.
    ...
    :crossBuildV212Jar (Thread[Connection worker,5,main]) completed. Took 0.007 secs.
    
    > ls ./build/libs
    lib_2.11.jar  lib_2.12.jar

Note

  • When defining builds {} block, a shorthand convention can be used for default values.
    To be able to use that, build item should be named by the following convention, for example:
    xyz211 is translated to { "build": { "scalaVersions": ["2.11"], "name": "xyz211" ... }
  • test/check tasks are not being cross compiled, and they use the default Scala version.
    If a user would like to run tests with different Scala versions, he needs to change the relevant scala-library library version and neighbouring 3rd party scala dependencies in build.gradle

Cross building with publishing

Leveraging gradle maven-publish plugin

  1. Apply the plugin and add maven-publish plugin. For example:

    apply plugin: 'com.github.prokod.gradle-crossbuild-scala'
    apply plugin: 'maven-publish'
    
    group = 'x.y.z'
    archivesBaseName = 'lib'
    
    crossBuild {
        builds {
            v211
        }
    }
    
    // 'maven-publish' plugin usage for publishing crossbuild artifacts
    publishing {
        publications {
            // Create a publication
            crossBuildV211(MavenPublication) {
                // By default groupId equals group
                groupId = 'x.y.z'
                // By default artifactId is set to crossBuildJar task `baseName`
                artifactId = 'lib_2.11'
                // crossbuild plugin provide with a software component per crossbuild version
                from components.crossBuildV211
            }
        }
    }
    
    // ...
  2. gradle tasks

    Notice that now the following publish related user faced tasks are added to the project:

    > ./gradlew tasks
    
    ------------------------------------------------------------
    All tasks runnable from project :lib
    ------------------------------------------------------------
    ...
    Publishing tasks
    ----------------
    generatePomFileForCrossBuild211Publication - Generates the Maven POM file for publication 'crossBuild211'.
    publish - Publishes all publications produced by this project.
    publishCrossBuild211PublicationToMavenLocal - Publishes Maven publication 'crossBuild211' to the local Maven repository.
    publishToMavenLocal - Publishes all Maven publications produced by this project to the local Maven cache.
  3. gradle publishToMavenLocal

    > ./gradlew publishToMavenLocal
    ...
    Tasks to be executed: [task ':compileCrossBuild211Java', task ':compileCrossBuild211Scala', task ':processCrossBuild211Resources', task ':crossBuild211Classes', task ':crossBuild211Jar', task ':generatePomFileForCrossBuild211Publication', task ':publishCrossBuild211PublicationToMavenLocal', task ':publishToMavenLocal']
    Tasks to be executed: [task ':compileCrossBuild211Java', task ':compileCrossBuild211Scala', task ':processCrossBuild211Resources', task ':crossBuild211Classes', task ':crossBuild211Jar', task ':generatePomFileForCrossBuild211Publication', task ':publishCrossBuild211PublicationToMavenLocal', task ':publishToMavenLocal']
    ...

Note

  • Using pluginManager 'gradle-crossbuild' plugin leverages Gradle's pluginManager To update 'maven-publish' cross-build related publications
  • Beware, Behind the scenes the software components and the publications are decoupled, the logical linkage between a cross built software component and the publication is made by giving the publication item a name of the following convention crossBuildXYZ(MavenPublication) where XYZ is the build name from builds {} block following the pattern examples in table under SourceSet/s column.

Gradle software components for Scala

The java plugin is providing the users with a java software component that later can be used to publish artifacts.
Similarly the cross build plugin does the same and provide the users with a software component per scala version.
The plugin is relying on maven-publish plugin to generate pom file based on the software component you have indicated in your publication.
The provided software component names for each Scala version is exactly matching the provided sourceset for each Scala version defined see Build scenarios table.

Note Up to plugin version 0.15.x included, adding a publication required the user to add an artifact entry to the publication block. From plugin version 0.16.x onward, adding a publication requires using from components instead

overriding plugin's internal pom.withXml

The plugin handles pom generation in an opinionated way and augment the output pom xml as needed per Scala version.
If one wants to add more transformations on top, he can do that by providing his own pom.withXml handler for the relevant publications.

An example for a custom pom.withXml handler:

crossBuild {
    builds {
        scala {
            scalaVersions = ['2.10', '2.11']
        }
    }
}

publishing {
    publications {
        maven(MavenPublication) {
            from components.java
        }
        crossBuildScala_210(MavenPublication) {
            from components.crossBuildScala_210

            pom.withXml { xml ->
                def dependenciesNode = xml.asNode().dependencies?.getAt(0)

                def dependencyNode = dependenciesNode.appendNode('dependency')
                dependencyNode.appendNode('groupId', 'org.apache.spark')
                dependencyNode.appendNode('artifactId', 'spark-sql_2.10')
                dependencyNode.appendNode('version', '1.6.3')
                dependencyNode.appendNode('scope', 'provided')
            }
        }
        crossBuildScala_211(MavenPublication) {
            from components.crossBuildScala_211
        }
    }
}

In this example, we add some arbitrary provided scope dependency to the generated pom.

Note

  • Up to plugin version 0.15.x included, publishing was handled almost exclusively by the plugin when it comes to generating the pom xml dependencies section.
  • From plugin version 0.16.x onward this has been changed and now most of the heavy lifting is done by the maven-publish plugin.
  • As a result, from plugin 0.16.x onward, when providing your own pom.withXml handler, the crossbild plugin does not skip its internal handler anymore

Cross building - configuration options (DSL Reference)

targetVersionItem.archiveAppendix, crossBuild.scalaVersionsCatalog, crossBuild211XYZ pre defined configurations

apply plugin: 'com.github.prokod.gradle-crossbuild-scala'

crossBuild {
    scalaVersionsCatalog = ['2.11':'2.11.12', '2.12':'2.12.17', '2.13':'2.13.10', '3':'3.2.2']

    archive.appendixPattern = '_?'                  // Default appendix pattern for all builds

    targetCompatibility.strategy = 'default'        // Default JVM target compatibility strategy oneof
                                                    // default/smart/strict
    builds {
        v210
        v211 {
            scalaVersions = ['2.11']                // By default derived from build name in short hand
                                                    // build name
            archive.appendixPattern = '_?'          // By default the value is "_?"
                                                    // In the default case will yield '_2.11'
                                                    // If different from upper level config, it will override it.
            targetCompatibility.strategy = 'default'// By default the value is 'default'
                                                    // If different from upper level config, it will override it.
            ext = [:]                               // By default empty Map
                                                    // Once populated entries are propagated
                                                    // as SourceSet ExtraProperties
        }
    }
}
dependencies {
    implementation ("com.google.protobuf:protobuf-java:$protobufVersion")
    implementation ("joda-time:joda-time:$jodaVersion")
    implementation ("org.scalaz:scalaz_2.11:$scalazVersion")
    implementation ('org.scala-lang:scala-library:2.11.12')                        // 2.11 is the 'default' building flavour Scala version
    
    compileOnly ('org.apache.spark:spark-sql_2.11:2.2.1')
    crossBuildV210CompileOnly ('org.apache.spark:spark-sql_2.10:1.6.3')            // A configuration auto generated by the plugin
    crossBuildV211CompileOnly ('org.apache.spark:spark-sql_2.11:2.2.1')            // A configuration auto generated by the plugin
}

default-variant

In the above example, spark version of the dependency specified for compileOnly configuration which we refer here as default-variant, is important for build, test/check standard tasks.
The other dependencies specified for Scala versions 2.10, 2.11 respectively (crossBuild210CompileOnly, crossBuild211CompileOnly), will be used only for crossBuild210Jar, crossBuild211Jar tasks, and other corresponding task variants (publishCrossBuild210PublicationToMavenLocal, publishCrossBuild211PublicationToMavenLocal ...) which can be referred as cross-build-variants

Note

  • Backward compatibility maintained behaviours (still):
    • Dependency with question mark Scala tag e.g. org.scalaz:scalaz_?:$scalazVersion is being replaced based on the Scala version being built
    • Derived from previous point, scala-library library is needed for test/check tasks in case '?' dependencies are declared
  • If crossBuild.scalaVersionsCatalog is not defined, a default one will be used (might get outdated).
  • Per build item in builds {} block, Scala version(s) is set either by explicitly setting a build scalaVersions or implicitly through a build name.
    See the different build scenarios for more details
  • Declaring cross building dependencies explicitly:
crossBuild {
  builds {
    v210
    v211
  }
}

dependencies {
  compileOnly ('org.apache.spark:spark-sql_2.11:2.2.1')
  crossBuildV210CompileOnly ('org.apache.spark:spark-sql_2.10:1.6.3')
  crossBuildV211CompileOnly ('org.apache.spark:spark-sql_2.11:2.2.1')
}

The plugin DSL defines in the above crossBuild {} block two cross building variants. One for Scala 2.10 and one for 2.11.
When declaring explicit cross building dependency, for instance when using Spark or Kafka 3rd party libraries, when dependency library name contains platform version, All the different variants should be declared, like shown above.

  • The plugin provides predefined sourceSets and configurations which are linked to the matching pre generated Jar tasks like so:
    (sourceSet)crossBuild211 -> (task)crossBuild211Jar -> (configuration)crossBuild211Implementation, (configuration)crossBuild211CompileOnly, ...

Scala 3 cross building

From plugin version 0.15.0 Scala 3 is supported

targetCompatibilty.strategy

As Scala 3 default JVM for later Scala 3.x versions changed to Java 11 and to support any new developments in that area,
the plugin DSL was extended to support JVM targetCompatibility through strategy

  • The available values: default/smart/strict
  • default strategy In this strategy, the Scala compiler will try to adhere to the targetCompatibility JVM version.
    If the targetCompatibility is not supported by the Scala version to be compiled, the default JVM for that compilation is changed to the default JVM for that specific Scala version.
  • smart strategy In this strategy, if the targetCompatibility is not supported by the Scala version to be compiled, the default JVM for that compilation is changed to the latest JVM for that specific Scala version.
  • strict strategy In this strategy, if the targetCompatibility is not supported by the Scala version to be compiled, the build is stopped

Note

  1. Gradle supports scala 3 compilation (via zinc) - beware that Gradle 5.x is not supporting Scala 3 compilation
  2. If you want to use Scala 3 instead of the scala-library dependency you should add the scala3-library_3 dependency.
    However, for the sake of the cross building across Scala 2/3 the plugin takes care of modifying the scala library dependency accordingly, internally

Multi-aspect cross building and Extra Properties propagation per aspects combination

  • Cross building DSL programmatically - In the next code snippet you can observe how programmatically we are generating cross builds using the plugin DSL.
  • Extra properties per cross build - Not only the cross building is described in a programmatic manner, you can also observe that specific unique meta data for each cross build permutation is generated using the plugin's ext entry

    Note The plugin injects a default extra property that holds the value of the respective Scala Compiler Version, named scalaCompilerVersion. This feature is supported in the plugin from version 0.14.x onwards.

// ...

subprojects {
    apply plugin: 'com.github.prokod.gradle-crossbuild-scala'
    apply plugin: 'maven-publish'

    crossBuild {
        scalaVersionsCatalog = ["2.13": "2.13.8", "2.12": "2.12.15"]

        def sparkVersionsForBoth = ["3.3.0", "3.2.1", "3.2.0"]
        def sparkVersionsFor2_12 = ["3.1.3", "3.1.2", "3.1.1", "3.1.0", "3.0.3", "3.0.2", "3.0.1", "3.0.0"]

        builds {
            for (spark in sparkVersionsForBoth) {
                create(spark) {
                    scalaVersions = ["2.12", "2.13"]
                    archive.appendixPattern = "-${spark}_?"
                    ext = ['sparkVersion':spark]
                }
            }

            for (spark in sparkVersionsFor2_12) {
                create(spark) {
                    scalaVersions = ["2.12"]
                    archive.appendixPattern = "-${spark}_?"
                    ext = ['sparkVersion':spark]
                }
            }
        }
    }
    
    dependencies {
        implementation "org.scala-lang:scala-library:2.13.8"
    }
}

Scala Version Specific Source

  • Each sourceSet that the plugin creates based on the DSL is assigned with its own main Scala source dir.

    Note Gradle's intrinsic convention. Supported in the plugin from version 0.14.x onwards

    For instance, if a sourceSet id is crossBuild211 then the source dir by convention is src/crossBuild211/scala

  • We can now combine the previous topic of multi-aspect cross building with the current topic and provide powerful way of maintaing differnet cross builds not only with their differences in library dependencies but also with their code differences

    Note The plugin handles cases where some class is present in both /src/main/scala and /src/<crossBuildSourceSetId>/scala. The original class in /src/main/scala is being excluded from the compile task for the relevant cross build

  • Together with previous code snippet, the following one shows an example of leveraging jcp plugin to modify code per given cross build ext based meta data

import com.igormaznitsa.jcp.gradle.JcpTask

plugins {
    id 'com.igormaznitsa.jcp'
}

group = 'com.github.prokod.it'
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

sourceSets.findAll { it.name.startsWith('crossBuild') }.each { sourceSet ->
    def compileTaskName = sourceSet.getCompileTaskName('scala')

    def spark = sourceSet.ext.sparkVersion
    def sparkStripped = spark.replaceAll('\\.', '')
    def scala = sourceSet.ext.scalaCompilerVersion
    def sparkMinor = spark.substring(0, spark.lastIndexOf('.'))
    def scalaCompat = scala.substring(0, scala.lastIndexOf('.'))
    def scalaCompatStripped = scalaCompat.replaceAll('\\.', '')
    
    // Here we use the preprocessing step done via jcp to generate compatible source code for the specific cross build
    // based on vars populated through the sourceSet ExtaProperties from previous code sinppet
    tasks.register("preprocess_${sourceSet.name}", JcpTask) {
        sources = sourceSets.main.scala.srcDirs
        target = file("src/${sourceSet.name}/scala")
        clearTarget = true
        fileExtensions = ["java", "scala"]

        vars = ["spark": spark, "sparkMinor": sparkMinor, "scala": scala, "scalaCompat": scalaCompat]
        outputs.upToDateWhen { target.get().exists() }
    }

    // Here we make tasks dependency so preprocessing will kick in at the right moment
    project.tasks.findByName(sourceSet.getCompileTaskName('scala')).with { ScalaCompile t ->
        t.dependsOn tasks.findByName("preprocess_${sourceSet.name}")
    }

    // Here we add in a programmatic way dependencies per cross build.
    // SourceSet ExtraProperties are leveraged again for that
    project.dependencies.add(sourceSet.getImplementationConfigurationName(), [group: "org.apache.spark", name: "spark-sql_${scalaCompat}", version: "${spark}"])

    // Here we add in a programmatic way publication per cross build.
    publishing {
        publications {
            create("crossBuild${sparkStripped}_${scalaCompatStripped}", MavenPublication) {
                afterEvaluate {
                    artifact project.tasks.findByName("crossBuild${sparkStripped}_${scalaCompatStripped}Jar")
                }
            }
        }
    }
}

builds {} -> Gradle SourceSets, Configurations and Tasks

The following table shows some commonly build scenarios expressed through the plugin DSL and how they are actually resolved

build scenario SourceSet/s Configuration/s Task/s
v210
crossBuildV210
  • crossBuildV210Implementation
  • crossBuildV210Api
  • crossBuildV210CompileOnly
  • crossBuildV210Runtime
  • crossBuildV210CompileClasspath
  • JavaPlugin -> crossBuildV210Java
  • ScalaPlugin -> crossBuildV210Scala
  • crossBuildV210Jar
v211 {
scalaVersions = ['2.11', '2.12']
}
crossBuildV211_211, crossBuildV211_212
  • crossBuildV211_211Implementation
    ...
  • crossBuildV211_212Implementation
    ...
  • JavaPlugin -> crossBuildV211_211Java, crossBuildV211_212Java
  • ScalaPlugin -> crossBuildV211_211Scala, crossBuildV211_212Scala
  • crossBuildV211_211Jar, crossBuildV211_212Jar
v213 {
scalaVersions = ['2.13']
}
crossBuildV213
  • crossBuildV213Implementation
    ...
  • JavaPlugin -> crossBuildV213Java
  • ScalaPlugin -> crossBuildV213Scala
  • crossBuildV213Jar
spark24 {
scalaVersions = ['2.11', '2.12']
}
crossBuildSpark24_211, crossBuildSpark24_212
  • crossBuildSpark24_211Implementation
    ...
  • crossBuildSpark24_212Implementation
    ...
  • JavaPlugin -> crossBuildSpark24_211Java, crossBuildSpark24_212Java
  • ScalaPlugin -> crossBuildSpark24_211Scala, crossBuildSpark24_212Scala
  • crossBuildSpark24_211Jar, crossBuildSpark24_212Jar

implementation configuration and java-library plugin

  • implementation configuration (java plugin) and api configuration (java-library plugin) are both supported by the cross build plugin. Cross build variants for the implementation/api configurations will be added to the cross build projects.
  • When using the cross build plugin in a Multi module project, a suggestion is to read java-library plugin doc beforehand, to better understand how Gradle treats dependencies with relation to configurations. This is highly recommended also for newcomers from Maven, where compile/runtime concepts are used.
  • api configuration is supported from version 0.13.0

Multi-module project plugin apply patterns

To apply cross building to a multi-module project use one of the following suggested layouts:

Layout 1 (a.k.a lazy apply)

  • In the root project build.gradle:
plugins {
    id "com.github.prokod.gradle-crossbuild-scala" version '0.12.0' apply false
}

allprojects {
    apply plugin: 'base'
    group = 'x.y.z'
    version = '1.0-SNAPSHOT'

    repositories {
        mavenCentral()
    }

    pluginManager.withPlugin('com.github.prokod.gradle-crossbuild-scala') {
        crossBuild {

            scalaVersionsCatalog = ['2.11':'2.11.12', '2.12':'2.12.8']

            builds {
                spark240_211
                spark243_212
            }
        }
    }

    pluginManager.withPlugin('maven-publish') {
        publishing {
            publications {
                crossBuildSpark240_211(MavenPublication) {
                    artifact crossBuildSpark240_211Jar
                }
                crossBuildSpark243_212(MavenPublication) {
                    artifact crossBuildSpark243_212Jar
                }
            }
        }
    }
}
  • In subprojects' build.gradle:
apply plugin: 'com.github.prokod.gradle-crossbuild-scala'

// ...

Layout 2 (a.k.a eager apply)

  • In the root project build.gradle:
plugins {
    id "com.github.prokod.gradle-crossbuild-scala" version '0.15.0' apply false
}

allprojects {
    group = 'x.y.z'
    version = '1.0-SNAPSHOT'

    repositories {
        mavenCentral()
    }
}

subprojects {
    apply plugin: 'com.github.prokod.gradle-crossbuild-scala'
    apply plugin: 'maven-publish'

    crossBuild {

        scalaVersionsCatalog = ['2.11':'2.11.12', '2.12':'2.12.8']

        builds {
            spark233_211 {
                archive.appendixPattern = '-2-3-3_?'
            }
            spark243 {
                scalaVersions = ['2.11', '2,12']
                archive.appendixPattern = '-2-4-3_?'
            }
        }
    }

    publishing {
        publications {
            crossBuildSpark233_211(MavenPublication) {
                artifact crossBuildSpark233_211Jar
            }
            crossBuildSpark243_211(MavenPublication) {
                artifact crossBuildSpark243_211Jar
            }
            crossBuildSpark243_212(MavenPublication) {
                artifact crossBuildSpark243_212Jar
            }
        }
    }
}

Supported Gradle versions

plugin version Tested Gradle versions Tested JVM Tested Scala Compilers
0.16.x 5.6.4*, 6.9.4*, 7.6.2, 8.3 8, 11 2.10.0-2.13.x
3.0.0 - 3.2.x
0.15.x 5.6.4*, 6.9.4*, 7.6.1, 8.0.2 8, 11 2.10.0-2.13.x
3.0.0 - 3.2.x
0.14.x 5.6.4, 6.9.2, 7.3.3 8 2.10.0-2.13.x
0.13.x 5.6.4, 6.9.2, 7.3.3 8 2.10.0-2.13.x
0.12.x 4.10.3, 5.6.4, 6.5 8
0.11.x 4.10.3, 5.6.4, 6.5 8
0.10.x 4.10.3, 5.6.4, 6.0.1 8
0.9.x 4.2, 4.10.3, 5.4.1 8
0.4.x 2.14, 3.0, 4.1 8
    • Scala 3 is supported officially by Gradle from version 7.3 onward

Contributing

  • This project uses gitflow process. PRs should be done against develop branch
  • PRs to develop should be style checked/tested locally by running ./gradlew clean check

Building

  • refer to github actions used by this repo