Giter Site home page Giter Site logo

prokod / gradle-crossbuild-scala Goto Github PK

View Code? Open in Web Editor NEW
17.0 3.0 4.0 776 KB

Adds cross building functionality to Gradle for Scala based projects

License: Apache License 2.0

Groovy 99.83% Java 0.17%
gradle crossbuild-scala-plugins scala cross-compile cross-compilation

gradle-crossbuild-scala's People

Contributors

borissmidt avatar prokod avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

gradle-crossbuild-scala's Issues

Support for executing tests with a specific Scala version

The plugin documentation says the following for the latest version, 0.12.0.

Cross building for test/check tasks are not supported.

What are the current plans to support executing tests with a specific version of Scala? Do you potentially have this feature in the making? How would you envision this to work if someone were to support the feature?

I guess one could set up the logic themselves though I think it should be part of the plugin. This is roughly what should be generated from the plugin if you configured Scala 2.11 and 2.12. Notice, that I created different configuration per variant.

configurations {
    crossBuildScala_211TestImplementation
    crossBuildScala_211TestRuntimeClasspath.extendsFrom(crossBuildScala_211TestImplementation, crossBuildScala_211RuntimeClasspath)

    crossBuildScala_212TestImplementation
    crossBuildScala_212TestRuntimeClasspath.extendsFrom(crossBuildScala_212TestImplementation, crossBuildScala_212RuntimeClasspath)
}

dependencies {
    crossBuildScala_211TestImplementation 'junit:junit:4.12'
    crossBuildScala_211TestImplementation 'org.scalatest:scalatest_2.11:3.1.2'
    crossBuildScala_211TestImplementation 'org.scalatestplus:junit-4-12_2.11:3.1.2.0'

    crossBuildScala_212TestImplementation 'junit:junit:4.12'
    crossBuildScala_212TestImplementation 'org.scalatest:scalatest_2.12:3.1.2'
    crossBuildScala_212TestImplementation 'org.scalatestplus:junit-4-12_2.12:3.1.2.0'
}

task crossBuildScala_211Test(type: Test) {
    group = 'verification'
    description = 'Executes tests for the classes that have been compiled with Scala 2.11.'
    testClassesDirs = sourceSets.crossBuildScala_211.output.classesDirs
    classpath = configurations.crossBuildScala_211TestRuntimeClasspath
}

task crossBuildScala_212Test(type: Test) {
    group = 'verification'
    description = 'Executes tests for the classes that have been compiled with Scala 2.12.'
    testClassesDirs = sourceSets.crossBuildScala_212.output.classesDirs
    classpath = configurations.crossBuildScala_212TestRuntimeClasspath
}

For an implementation dependency the compile scope is used instead of runtime scope in the generated pom

Actual:
The generated pom uses the compile scope instead of runtime for dependencies declared as implementation.

Expected:
The generated pom uses the runtime scope for dependencies declared as implementation.

build.gradle

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

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

    crossBuild {
        scalaVersionsCatalog = ['2.12':'2.12.12', '2.13':'2.13.6']

        builds {
            scala {
                scalaVersions = ['2.12', '2.13'] 
                archive.appendixPattern = '_?'
            }
        }
    }

    repositories {
        mavenCentral()
    }

    publishing {
        publications {
            mavenLib(MavenPublication) {
                from components.java
            }

            crossBuildScala_212(MavenPublication) {
            }

            crossBuildScala_213(MavenPublication) {
            }
        }
    }
}

shared-testsupport-types/build.gradle (a subproject)

dependencies {
    implementation "org.scalatest:scalatest_2.13:3.2.7"
}
gradle-scala-crossbuild-playground/shared-testsupport$ ./gradlew clean build publishToMavenLocal

shared-testsupport-types/mavenLib/pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>shared-testsupport</groupId>
  <artifactId>shared-testsupport-types</artifactId>
  <version>unspecified</version>
  <dependencies>
    <dependency>
      <groupId>org.scalatest</groupId>
      <artifactId>scalatest_2.13</artifactId>
      <version>3.2.7</version>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
</project>

shared-testsupport-types/crossBuildScala_212/pom-default.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>shared-testsupport</groupId>
  <artifactId>shared-testsupport-types_2.12</artifactId>
  <version>unspecified</version>
  <packaging>pom</packaging>
  <dependencies>
    <dependency>
      <groupId>org.scalatest</groupId>
      <artifactId>scalatest_2.12</artifactId>
      <version>3.2.7</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.scala-lang</groupId>
      <artifactId>scala-library</artifactId>
      <version>2.12.13</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
</project>

Reproducer repo:
https://github.com/leozilla/gradle-scala-crossbuild-playground

Feature 'dependency validation'

Hey i had written some code in my free time to validate if all dependencies are not depending on a scala version without a scala version tag. This might be usefull for companies that just started to cross compile there libs.

def traceDependency(DependencyResult d, List<DependencyResult> dfrom) {
    def deps = d.from.dependents
    if (deps.size() == 0 || d.from.toString().startsWith("project")) {
        dfrom.plus(d.from).reverse().join(" -> ")
    } else {
        deps.collect { traceDependency(it, dfrom.plus(d.from)) }.flatten()
    }

}

task validateScalaDependencies {
    doLast {
        def problems = project.subprojects.collect { subProject ->
            if (subProject.configurations.getNames().contains("runtimeClasspath")) {
                def dependencies = subProject.configurations.runtimeClasspath.incoming.getResolutionResult().getAllDependencies()

                def untaggedScalaDependenciesTraces = dependencies.findAll {
                    String[] groupNameVersion = it.from.toString().split(':')
                    String[] requestedGroupNameVersion = it.requested.toString().split(':')
                    //for dependnecies that depend on scala
                    (requestedGroupNameVersion[0] == "org.scala-lang"
                        // without a scala tag
                        && !(
                        groupNameVersion[1].endsWith("_2.12")
                            || groupNameVersion[1].endsWith("_2.11")
                            || groupNameVersion[1].endsWith("_2.10"))
                        //ignore projects
                        && !it.from.toString().startsWith("project")
                        //ignore scala libs
                        && groupNameVersion[0] != "org.scala-lang"
                    )
                }.collect {
                    "${it.from} traces: \n    -- ${traceDependency(it, [it.requested]).join("\n    -- ")}"
                }

                println("")
                if (untaggedScalaDependenciesTraces.size() != 0) {
                    println("${subProject.name} : CROSS COMPILATION ERRORS :(")
                    println("  * ${untaggedScalaDependenciesTraces.join("*")}")
                    return false
                } else {
                    println("${subProject.name} : IS OK :)")
                    return true
                }

            }
        }.contains(false)

        if(problems) {
            throw new GradleException("INVALID CROSS BUILD FAILED")
        }

    }
}

When defining cross build related publications have groupId default to project group

Right now to define a cross build related publications you need among others groupId

model {
  ...

  publications {
    crossBuild211(MavenPublication) {
      groupId = project.group
      artifactId = $.crossBuild.targetVersions.v211.artifactId
      artifact $.tasks.crossBuild211Jar
    }
  }
}

groupId can be safely default to project.group by the plugin with no need to explicitly set it

User created configurations which depend on cross build applied projects breaks build

Consider the following scenario:
multi module project with subproject :a and :b
:a has cross build plugin applied to it
:b is dependent on :a
:b contains new sourceSet integrationTest

When trying to build the project, the build fails in task :b:integrationTest because transitive _? (globed) dependencies brought by :a are not resolved correctly.

pom files created in a multi module project can contain wrong compile dependency

pom files created in a multi module project can contain wrong compile dependency for inter project artifacts depending on how the user composes build.gradle to use the plugin DSL.

Basically it drills down to how eagerly the plugin is being applied:

  • Eager: using crossBuild {} block directly under subprojects {} block in root project build.gradle.
  • Lazy: using, for instance, crossBuild {} block under subprojects {} block through a project.pluginManager.withPlugin {} block in root project build.gradle.

in Eager style v0.7.0 behaves as expected, while in Lazy style the plugin produces pom with default non Scala inter project artifact dependency.

Project tree

:app
|__:lib2

Correct Pom

    <dependency>
      <groupId>com.github.prokod.it</groupId>
      <artifactId>lib2_2.11</artifactId>
      <version>1.0-SNAPSHOT</version>
      <scope>compile</scope>
    </dependency>

Wrong Pom

    <dependency>
      <groupId>com.github.prokod.it</groupId>
      <artifactId>lib2</artifactId>
      <version>1.0-SNAPSHOT</version>
      <scope>compile</scope>
    </dependency>

could not resolve plugin artifact

Plugin [id: 'com.github.prokod.gradle-crossbuild-scala', version: '0.12.0'] was not found in any of the following sources:

  • Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
  • Plugin Repositories (could not resolve plugin artifact 'com.github.prokod.gradle-crossbuild-scala:com.github.prokod.gradle-crossbuild-scala.gradle.plugin:0.12.0')
    Searched in the following repositories:
    Gradle Central Plugin Repository

https://github.com/gabrieljones/crossbuild-hello/runs/1451175272?check_suite_focus=true
https://github.com/gabrieljones/crossbuild-hello/blob/64af4fc06da413108e5d9979a8b6fcc5f26ba811/build.gradle.kts

What did I do wrong?

Possible root cause for `SourceSet with name 'crossBuildScala_211' not found`

I am running into the following issue below for a project dependency that is not a Scala project and doesn't apply the plugin either. Do you have any idea what the root cause could be based on the stack trace? The error message bubbles up all the way to the Gradle core API. Unfortunately, I cannot reproduce the issue in the sample project of mine.

SourceSet with name 'crossBuildScala_211' not found.

* Try:
Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Exception is:
org.gradle.api.UnknownDomainObjectException: SourceSet with name 'crossBuildScala_211' not found.
	at org.gradle.api.internal.DefaultNamedDomainObjectCollection.createNotFoundException(DefaultNamedDomainObjectCollection.java:504)
	at org.gradle.api.internal.DefaultNamedDomainObjectCollection.getByName(DefaultNamedDomainObjectCollection.java:333)
	at org.gradle.api.NamedDomainObjectCollection$getByName$1.call(Unknown Source)
	at com.github.prokod.gradle.crossbuild.utils.SourceSetInsightsView.switchTo(SourceSetInsightsView.groovy:37)
	at com.github.prokod.gradle.crossbuild.utils.SourceSetInsightsView$switchTo$0.call(Unknown Source)
	at com.github.prokod.gradle.crossbuild.utils.DependencyInsights$_generateDetachedDefaultConfigurationsRecursivelyFor_closure12.doCall(DependencyInsights.groovy:231)
	at com.github.prokod.gradle.crossbuild.utils.DependencyInsights.generateDetachedDefaultConfigurationsRecursivelyFor(DependencyInsights.groovy:229)
	at com.github.prokod.gradle.crossbuild.utils.DependencyInsights.generateDetachedDefaultConfigurationsRecursivelyFor(DependencyInsights.groovy:200)
	at com.github.prokod.gradle.crossbuild.utils.DependencyInsights.generateDetachedDefaultConfigurationsRecursively(DependencyInsights.groovy:173)
	at com.github.prokod.gradle.crossbuild.utils.DependencyInsights.addDefaultConfigurationsToCrossBuildConfigurationRecursive(DependencyInsights.groovy:101)
	at com.github.prokod.gradle.crossbuild.utils.DependencyInsights$addDefaultConfigurationsToCrossBuildConfigurationRecursive$0.call(Unknown Source)
	at com.github.prokod.gradle.crossbuild.CrossBuildPlugin$_generateNonDefaultProjectTypeDependencies_closure13.doCall(CrossBuildPlugin.groovy:292)
	at com.github.prokod.gradle.crossbuild.CrossBuildPlugin.generateNonDefaultProjectTypeDependencies(CrossBuildPlugin.groovy:279)
	at com.github.prokod.gradle.crossbuild.CrossBuildPlugin$_apply_closure4.doCall(CrossBuildPlugin.groovy:72)

Support custom scalaTag (e.g _2.11, _2.12, _2.13) instead of _?

Hey I might have a hacky solution for a complex problem this plugin doesn't compose well with the play plugin.

So we have a project like

root
-- app (play plugin)
-- api (needs crossbuilding) 

But because i need to tag the dependencies as _? then the app sub project tells me hey i cannot resolve this dependency with _?. Because your plugin doesn't apply to the old play plugin.

So i simple solution would be to set the archive.appendixPattern to _2.11 and be done with it. But then the plugin complains that it cannot resolve the _2.11 for a 2.12 build.

So currently i resolved it by doing:

compile "com.company:commons-lib_2.11:${commonGrpcVersion}"
crossBuildV211CompileOnly "com.company:commons-lib_2.11:${commonGrpcVersion}"
 crossBuildV212CompileOnly "com.company:commons-lib_2.12:${commonGrpcVersion}"

But if this 'feature' was supported the i could just change a project to a cross compiled lib by just applying the plugin and no need to switch dependencies to the dependency with _? notation.

I tried play-framework but that disabled the tests for some weird reason (and it is out of the scope of this ticket)

Refine generated pom files dependencies scope

In current generated pom files for cross build publications, all dependencies are marked as runtimescope.
To improve on that, generated pom file should refine runtime scope to either compile or provided scopes

Could not resolve scala dependencies for main sourceSet

I have a gradle module with config like this:

import com.github.prokod.gradle.crossbuild.model.*

apply 'java-library'
apply 'com.github.prokod.gradle-crossbuild'

model {
    crossBuild {
        targetVersions {
            v211(ScalaVer) {
                value = '2.11'
            }
            v212(ScalaVer) {
                value = '2.12'
            }
        }

        scalaVersions = ['2.11':'2.11.12', '2.12':'2.12.8']
    }
}

dependencies {
    implementation 'org.scala-lang:scala-library:2.12.+'
    implementation 'org.scala-lang.modules:scala-xml_?:[1.0, 2.0['

    testImplementation 'org.scala-lang.modules:scala-java8-compat_?:[0.9,1.0['
    testImplementation "org.junit.jupiter:junit-jupiter-api:$jUnitVersion"
    testImplementation "org.junit.jupiter:junit-jupiter-params:$jUnitVersion"
    testImplementation "org.mockito:mockito-core:$mockitoVersion"
    testImplementation "org.mockito:mockito-junit-jupiter:$mockitoVersion"
    testImplementation "org.assertj:assertj-core:$assertjVersion"

    testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$jUnitVersion"
}

running gradle init command would resolve into this error:

Could not resolve: org.scala-lang.modules:scala-xml_?:[1.0, 2.0[
Could not resolve: org.scala-lang.modules:scala-java8-compat_?:[0.9,1.0[

Do you know what could possibly cause it? I'm using gradle 4.10.3

Calling crossBuildXXXJar tasks on a multi module project fails on Resource missing

Calling crossBuildXXXJar tasks on a multi module project fails on

Could not resolve all dependencies for configuration ':module:crossBuildXXXCompileClasspath'.
> Could not find org.scalatest:scalatest_?:3.0.1.
  Searched in the following locations:

It seems dependency resolution is inhibited for some cases and hence, 3rd lib Scala globed (_?) libs are not resolved correctly

Feature request: source folder per scala version.

Hey prokod,

I was thinking about the sbt feature where you can have a specific source folder per scala version to override some classes. This would make it easier to specialize libraries that span from 2.11 to 2.13.

i.e. if you have some library that exists for 2.11 and 2.12 and it broke its api when it switched to 2.12 to 2.13. Then you either have to drop 2.11 of stay at the older library version. But if you can override the classes to be different depending on the version then you can just resolve this issue.

Do you think this feature would be hard to implement? Would it be a welcoming PR?

Kind regards, Boris Smidt

Depenedncy resolution for test configurations are not par with the non-test ones

Most chances that dependency resolution of ? scala dependency under some test configuration (testCompile, testImplementation ...) will fail as it is not leveraging information from user intent (versions to cross compile to) and default scala version (through specific scala-library dependency in dependencies block)
Note: Non test configurations with ? scala dependencies do not have this issue

Cross building of multi module projects with deeper dependency graphs fails

When a multi project has couple of sub-projects with dependencies between them like so:

root
  cross-build sub-project A
  cross-build sub-project B
  cross-build sub-project C (C depends on A and B)
  cross-build sub-project D (D depends on C)

sub-project D cross build dependency resolution is failing to resolve cross build defined dependencies within sub-projects A and B

Publishing functionality doesn't seem to declare dependencies in generated POM

The integration with the maven-publish plugin doesn't seem to work as expected. If I expect a dependency in the project then I'd expect it to be added as transitive dependency to the generated POM file.

Consider the following example, as implemented here.

plugins {
    id 'com.github.prokod.gradle-crossbuild'
    id 'maven-publish'
}

...

dependencies {
    implementation 'org.apache.commons:commons-lang3:3.11'
}

publishing {
    publications {
        maven211(MavenPublication) {
            artifact crossBuildScala_211Jar
        }
    }
    repositories {
        maven {
            url = "$rootDir/repo"
        }
    }
}

Executing the publish task only generates the following pom.xml file without org.apache.commons:commons-lang3:3.11 as transitive dependency.

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.bmuschko</groupId>
  <artifactId>d</artifactId>
  <version>1.0.0</version>
</project>

Is this a bug of some sort? The docs make it sound like it should just work.

gradle 7 support.

Hey i have tried your plugin with gradle 7 sadly compile is removed and replaced by implementation.
so compileConfigurationName is now replaced implementationConfigurationName.
Possibly some other issues exist as wel.

Support notion of adding cross build items to sub modules

Right now when sub modules are configured for cross building using root project build.gradle, there is no way to add more cross build items in the sub modules themselves, Failing with the following exception:

* Exception is:
org.gradle.api.GradleScriptException: A problem occurred evaluating project ':lib'.
Caused by: org.gradle.api.internal.tasks.DefaultTaskContainer$DuplicateTaskException: Cannot add task 'crossBuildSpark230_211Jar' as a task with that name already exists.
at com.github.prokod.gradle.crossbuild.CrossBuildExtension$_realizeCrossBuildTasks_closure7.doCall(CrossBuildExtension.groovy:115)
...

Example of such project:

:root
|____:lib

root build.gradle

crossBuild {
  builds {
    spark230 {
      scalaVersions = ['2.11']
    }
  }
}

lib build.gradle

crossBuild {
  builds {
    v212
  }
}

cross building Jar tasks are not available from within `build.gradle`

As long as you are just using cross build DSL and use for publishing finally artifacts, things are OK.
But, if within you build.gradle build file you are trying to interact with some of the plugin auto created Jars you get task not found as it being generated in the afterEvaluate phase.

When using Gradle Kotlin scripts and using the Plugin's ext property Exception is raised

Stack trace:

*  Exception is:
org.gradle.internal.operations.BuildOperationInvocationException: java.util.Collections$SingletonMap
        at org.gradle.internal.operations.DefaultBuildOperationRunner.throwAsBuildOperationInvocationException(DefaultBuildOperationRunner.java:192)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.access$100(DefaultBuildOperationRunner.java:24)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:75)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
        at org.gradle.api.internal.project.BuildOperationCrossProjectConfigurator.lambda$runProjectConfigureAction$0(BuildOperationCrossProjectConfigurator.java:66)
        at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$applyToMutableState$0(DefaultProjectStateRegistry.java:360)
        at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.fromMutableState(DefaultProjectStateRegistry.java:378)
        at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.applyToMutableState(DefaultProjectStateRegistry.java:359)
        at org.gradle.api.internal.project.BuildOperationCrossProjectConfigurator.runProjectConfigureAction(BuildOperationCrossProjectConfigurator.java:66)
        at org.gradle.api.internal.project.BuildOperationCrossProjectConfigurator.access$100(BuildOperationCrossProjectConfigurator.java:32)
        at org.gradle.api.internal.project.BuildOperationCrossProjectConfigurator$BlockConfigureBuildOperation.run(BuildOperationCrossProjectConfigurator.java:111)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
        at org.gradle.api.internal.project.BuildOperationCrossProjectConfigurator.runBlockConfigureAction(BuildOperationCrossProjectConfigurator.java:62)
        at org.gradle.api.internal.project.BuildOperationCrossProjectConfigurator.subprojects(BuildOperationCrossProjectConfigurator.java:48)
        at org.gradle.api.internal.project.DefaultProject.subprojects(DefaultProject.java:726)
        at org.gradle.api.internal.project.DefaultProject.subprojects(DefaultProject.java:721)
        at Build_gradle.<init>(build.gradle.kts:22)
        at Program.execute(Unknown Source)
        at org.gradle.kotlin.dsl.execution.Interpreter$ProgramHost.eval(Interpreter.kt:532)
        at org.gradle.kotlin.dsl.execution.Interpreter$ProgramHost.evaluateSecondStageOf(Interpreter.kt:438)
        at Program.execute(Unknown Source)
        at org.gradle.kotlin.dsl.execution.Interpreter$ProgramHost.eval(Interpreter.kt:532)
        at org.gradle.kotlin.dsl.execution.Interpreter.eval(Interpreter.kt:184)
        at org.gradle.kotlin.dsl.provider.StandardKotlinScriptEvaluator.evaluate(KotlinScriptEvaluator.kt:115)
        at org.gradle.kotlin.dsl.provider.KotlinScriptPluginFactory$create$1.invoke(KotlinScriptPluginFactory.kt:51)
        at org.gradle.kotlin.dsl.provider.KotlinScriptPluginFactory$create$1.invoke(KotlinScriptPluginFactory.kt:36)
        at org.gradle.kotlin.dsl.provider.KotlinScriptPlugin.apply(KotlinScriptPlugin.kt:34)
        at org.gradle.configuration.BuildOperationScriptPlugin$1.run(BuildOperationScriptPlugin.java:65)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
        at org.gradle.configuration.BuildOperationScriptPlugin.lambda$apply$0(BuildOperationScriptPlugin.java:62)
        at org.gradle.configuration.internal.DefaultUserCodeApplicationContext.apply(DefaultUserCodeApplicationContext.java:44)
        at org.gradle.configuration.BuildOperationScriptPlugin.apply(BuildOperationScriptPlugin.java:62)
        at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$applyToMutableState$0(DefaultProjectStateRegistry.java:360)
        at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.fromMutableState(DefaultProjectStateRegistry.java:378)
        at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.applyToMutableState(DefaultProjectStateRegistry.java:359)
        at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:42)
        at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:26)
        at org.gradle.configuration.project.ConfigureActionsProjectEvaluator.evaluate(ConfigureActionsProjectEvaluator.java:35)
        at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.lambda$run$0(LifecycleProjectEvaluator.java:109)
        at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$applyToMutableState$0(DefaultProjectStateRegistry.java:360)
        at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$withProjectLock$2(DefaultProjectStateRegistry.java:408)
        at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:270)
        at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withProjectLock(DefaultProjectStateRegistry.java:408)
        at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.fromMutableState(DefaultProjectStateRegistry.java:389)
        at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.applyToMutableState(DefaultProjectStateRegistry.java:359)
        at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.run(LifecycleProjectEvaluator.java:100)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
        at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:72)
        at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:760)
        at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:151)
        at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.ensureConfigured(DefaultProjectStateRegistry.java:328)
        at org.gradle.execution.TaskPathProjectEvaluator.configure(TaskPathProjectEvaluator.java:33)
        at org.gradle.execution.TaskPathProjectEvaluator.configureHierarchy(TaskPathProjectEvaluator.java:47)
        at org.gradle.configuration.DefaultProjectsPreparer.prepareProjects(DefaultProjectsPreparer.java:50)
        at org.gradle.configuration.BuildTreePreparingProjectsPreparer.prepareProjects(BuildTreePreparingProjectsPreparer.java:64)
        at org.gradle.configuration.BuildOperationFiringProjectsPreparer$ConfigureBuild.run(BuildOperationFiringProjectsPreparer.java:52)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
        at org.gradle.configuration.BuildOperationFiringProjectsPreparer.prepareProjects(BuildOperationFiringProjectsPreparer.java:40)
        at org.gradle.initialization.VintageBuildModelController.lambda$prepareProjects$3(VintageBuildModelController.java:89)
        at org.gradle.internal.model.StateTransitionController.lambda$doTransition$12(StateTransitionController.java:227)
        at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:238)
        at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:226)
        at org.gradle.internal.model.StateTransitionController.lambda$transitionIfNotPreviously$10(StateTransitionController.java:201)
        at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:34)
        at org.gradle.internal.model.StateTransitionController.transitionIfNotPreviously(StateTransitionController.java:197)
        at org.gradle.initialization.VintageBuildModelController.prepareProjects(VintageBuildModelController.java:89)
        at org.gradle.initialization.VintageBuildModelController.prepareToScheduleTasks(VintageBuildModelController.java:71)
        at org.gradle.internal.build.DefaultBuildLifecycleController.lambda$prepareToScheduleTasks$2(DefaultBuildLifecycleController.java:134)
        at org.gradle.internal.model.StateTransitionController.lambda$doTransition$12(StateTransitionController.java:227)
        at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:238)
        at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:226)
        at org.gradle.internal.model.StateTransitionController.lambda$maybeTransition$9(StateTransitionController.java:187)
        at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:34)
        at org.gradle.internal.model.StateTransitionController.maybeTransition(StateTransitionController.java:183)
        at org.gradle.internal.build.DefaultBuildLifecycleController.prepareToScheduleTasks(DefaultBuildLifecycleController.java:132)
        at org.gradle.internal.buildtree.DefaultBuildTreeWorkPreparer.scheduleRequestedTasks(DefaultBuildTreeWorkPreparer.java:33)
        at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$doScheduleAndRunTasks$2(DefaultBuildTreeLifecycleController.java:89)
        at org.gradle.composite.internal.DefaultIncludedBuildTaskGraph.withNewWorkGraph(DefaultIncludedBuildTaskGraph.java:75)
        at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.doScheduleAndRunTasks(DefaultBuildTreeLifecycleController.java:88)
        at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$runBuild$4(DefaultBuildTreeLifecycleController.java:106)
        at org.gradle.internal.model.StateTransitionController.lambda$transition$6(StateTransitionController.java:166)
        at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:238)
        at org.gradle.internal.model.StateTransitionController.lambda$transition$7(StateTransitionController.java:166)
        at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:44)
        at org.gradle.internal.model.StateTransitionController.transition(StateTransitionController.java:166)
        at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.runBuild(DefaultBuildTreeLifecycleController.java:103)
        at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.scheduleAndRunTasks(DefaultBuildTreeLifecycleController.java:69)
        at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:31)
        at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
        at org.gradle.internal.buildtree.ProblemReportingBuildActionRunner.run(ProblemReportingBuildActionRunner.java:49)
        at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:69)
        at org.gradle.tooling.internal.provider.FileSystemWatchingBuildActionRunner.run(FileSystemWatchingBuildActionRunner.java:119)
        at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:41)
        at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.lambda$execute$0(RootBuildLifecycleBuildActionExecutor.java:40)
        at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:128)
        at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.execute(RootBuildLifecycleBuildActionExecutor.java:40)
        at org.gradle.internal.buildtree.DefaultBuildTreeContext.execute(DefaultBuildTreeContext.java:40)
        at org.gradle.launcher.exec.BuildTreeLifecycleBuildActionExecutor.lambda$execute$0(BuildTreeLifecycleBuildActionExecutor.java:65)
        at org.gradle.internal.buildtree.BuildTreeState.run(BuildTreeState.java:53)
        at org.gradle.launcher.exec.BuildTreeLifecycleBuildActionExecutor.execute(BuildTreeLifecycleBuildActionExecutor.java:65)
        at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor$3.call(RunAsBuildOperationBuildActionExecutor.java:61)
        at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor$3.call(RunAsBuildOperationBuildActionExecutor.java:57)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
        at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor.execute(RunAsBuildOperationBuildActionExecutor.java:57)
        at org.gradle.launcher.exec.RunAsWorkerThreadBuildActionExecutor.lambda$execute$0(RunAsWorkerThreadBuildActionExecutor.java:36)
        at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:270)
        at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:119)
        at org.gradle.launcher.exec.RunAsWorkerThreadBuildActionExecutor.execute(RunAsWorkerThreadBuildActionExecutor.java:36)
        at org.gradle.tooling.internal.provider.ContinuousBuildActionExecutor.execute(ContinuousBuildActionExecutor.java:103)
        at org.gradle.tooling.internal.provider.SubscribableBuildActionExecutor.execute(SubscribableBuildActionExecutor.java:64)
        at org.gradle.internal.session.DefaultBuildSessionContext.execute(DefaultBuildSessionContext.java:46)
        at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter$ActionImpl.apply(BuildSessionLifecycleBuildActionExecuter.java:100)
        at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter$ActionImpl.apply(BuildSessionLifecycleBuildActionExecuter.java:88)
        at org.gradle.internal.session.BuildSessionState.run(BuildSessionState.java:69)
        at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter.execute(BuildSessionLifecycleBuildActionExecuter.java:62)
        at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter.execute(BuildSessionLifecycleBuildActionExecuter.java:41)
        at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:63)
        at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:31)
        at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:58)
        at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:42)
        at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:47)
        at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:31)
        at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:65)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:29)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:78)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:75)
        at org.gradle.util.internal.Swapper.swap(Swapper.java:38)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:75)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:84)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52)
        at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
Caused by: java.lang.CloneNotSupportedException: java.util.Collections$SingletonMap
        at com.github.prokod.gradle.crossbuild.model.ExtUpdateEvent.<init>(ExtUpdateEvent.groovy:29)
        at com.github.prokod.gradle.crossbuild.model.Build.setExt(Build.groovy:117)
        at Build_gradle$1$1$1.execute(build.gradle.kts:39)
        at Build_gradle$1$1$1.execute(build.gradle.kts:1)
        at org.gradle.api.internal.AbstractNamedDomainObjectContainer.create(AbstractNamedDomainObjectContainer.java:80)
        at Build_gradle$1$1.execute(build.gradle.kts:35)
        at com.github.prokod.gradle.crossbuild.CrossBuildExtension.builds(CrossBuildExtension.groovy:88)
        at Build_gradle$1.execute(build.gradle.kts:33)
        at Build_gradle$1.execute(build.gradle.kts:1)
        at org.gradle.api.internal.DefaultMutationGuard$2.execute(DefaultMutationGuard.java:44)
        at org.gradle.internal.Actions.with(Actions.java:249)
        at org.gradle.api.internal.project.BuildOperationCrossProjectConfigurator$1.run(BuildOperationCrossProjectConfigurator.java:69)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        ... 184 more

Allowing more then one cross build task per single Scala version

So the DSL as it is now (candidate v0.5)

crossBuild {
   scalaVersions = ['2.11':'2.11.12', '2.12':'2.12.8']
        
   builds {
      spark240_211 {
         archive.appendixPattern = '-2-4-0_?'
      }
      spark243_212 {
         archive.appendixPattern = '2-4-1_?'
      }
   }
}

The plugin is not supporting yet the ability to do the following:

crossBuild {
   scalaVersions = ['2.11':'2.11.12', '2.12':'2.12.8']
        
   builds {
      spark240_211 {
         archive.appendixPattern = '-2-4-0_?'
      }
      spark243_211 {
         archive.appendixPattern = '2-4-3_?'
      }
      spark243_212 {
         archive.appendixPattern = '2-4-3_?'
      }
   }
}

Major overhaul - bringing correctness, better testability and simplification

Proposal:

  • Refrain of using extendsFrom to be able to better separate between main and crossbuild configurations allowing for better control. Leveraging detached configurations containing filtered dependency set being added to sourceset based crossbuild configurations
  • Inter project dependencies for cross building using Gradle's best practices See Project jar dependencies and Declaring project dependency. Leveraging Producer Configuration with an artifact output as part of its definition
  • A more targeted Dependency resolution for cross building configurations See Dependency management attribute based matching. Leveraging Dependency attributesSchema and Compatibility/Disambiguation Rules
  • Simplifying Pom file creation and coupling more to the corresponding crossbuild configuration. To base Pom aiding configurations creation based on resolved compile/runtime classpath configurations
  • Improved testablity of the project Adding reporting tasks to visualize the path from assembled cross build configuration to it s resolved state using consumable format like JSON

Defining a project dependency for a specific Scala version

Say I work on the multi-project build with two subprojects: a and b. a applies the com.github.prokod.gradle-crossbuild plugin and builds the code for the Scala versions 2.11 and 2.12. The project b uses code from project a, therefore defines a project dependency. Is there a way to express right now that the project should be depend on the artifact of a built with just Scala version 2.11 or 2.12 and its transitive closure of dependencies? Here's a sample project with the setup I described.

I guess the following could work but it's poor practice. Here, I am depending on the artifact directly.

b/build.gradle:

dependencies {
    crossBuildScala_211Implementation project.files(project(':a').tasks.crossBuildScala_211Jar.archiveFile.getAsFile())
    crossBuildScala_212Implementation project.files(project(':a').tasks.crossBuildScala_212Jar.archiveFile.getAsFile())
}

The proper way would be to define an "outgoing" artifact and add that to a consumable configuration. Am I just missing which configuration that is? The workaround could be to define this myself in project a and then reference it in project b but this logic should really live in the plugin.

a/build.gradle:

configurations {
    consumable211Jar {
        canBeConsumed = true
        canBeResolved = false
    }
    consumable212Jar {
        canBeConsumed = true
        canBeResolved = false
    }
}

artifacts {
    consumable211Jar(crossBuildScala_211Jar)
    consumable212Jar(crossBuildScala_212Jar)
}

b/build.gradle:

dependencies {
    crossBuildScala_211Implementation project(path: ':a', configuration: 'consumable211Jar')
    crossBuildScala_212Implementation project(path: ':a', configuration: 'consumable212Jar')
}

I could find anything about it in the plugin documentation. Any pointers would be highly-appreciated.

scala version mix-up from inter project artifacts results in a wrong compilepath

In a multi module project, when observing compile path of one of the project's modules that has project() dependency on another module on the project, the default module artifact is observed to be in the classpath instead of the Scala specific one. This is observed when both modules should be cross compiled.
For instance:

:app
|__:lib

app_2.12 classpath contains lib.jar and not lib_2.12.jar

cross-compile imports

My code depends on "import scala.jdk.CollectionConverters." in Scala 2.13 which is predecesed by "import collection.CollectionConverters." in Scala 2.11.

Any hints on how, if at all possible, I could resolve that?

Current maintenance and development effort of plugin

I'd like to get a feeling for how active this project still is. I opened a couple of issues and would like to see them addressed. This could potentially mean that I'd submit a PR for one or all of the issues. Before I do so, I want to ensure the project is still actively maintained and will ship new releases.

Thanks for your feedback. I appreciate it and keep up the good work!

CompileOnly not picked up to multiple scala versions.

Because i have a weird way of dooing gradle builds and i apply the scala-crossbuild plugin in an afterEvaluate setting.

It seems that at that point it doens't pick up the compileOnly dependenceis for multiples scala versiosn.
So i have to state the compileOnly for each version for it to work.

dependecnies{
        compileOnly  project(":common")
        crossBuildV211CompileOnly project(":common")
        crossBuildV212CompileOnly project(":common")
}

stack overflow

Hey i really like your plugin over the adtran one since this one gives you clearly new tasks where you can depend on.

I however get a stack overflow in if i try to import our project after configuring this plugin in the eager fashion for a multi module project.

it has a stack overflow if a in the following case.

{
project("A") {
 dependencies{
   compile project("B")
 }
}

project("B") {
 dependencies{
   testCompile project("A")
 }
}

So the tests of project B depend on project A but project A has a compile dependency on project B. Which is a valid configuration. In our project Project "B" are test utils used in multiple other projects.

Change dependency resolution rules for 'compile' inherited dependencies with explicit Scala version

Current faulty plugin behavior:
'compile' inherited dependencies with explicit Scala version i.e compile 'org.apache.flink:flink-connector-kafka-0.10_2.11:1.4.1' are handled by dependency resolution where the Scala version suffix of the dependency name is changed to the required one i.e org.apache.flink:flink-connector-kafka-0.10_2.11:1.4.1 => org.apache.flink:flink-connector-kafka-0.10_2.12:1.4.1.
This behavior might lead to build error Could not resolve all dependencies for configuration ... as this library might not exist.
Expected behavior:
'compile' inherited dependencies with explicit Scala version should get excluded from non matching cross build configs.

Support java-library configurations

The old compile and runtime configurations are obsolete, and are planned to be removed in Gradle 7.0: gradle/gradle#8585 (comment)

While 7.0 is still a bit far from being released, the effects of the deprecation are already there. In particular, the implementation configuration generates dependencies in POM with the runtime scope, and the proper way to avoid it is to use the api configuration.

I see in the docs that the api configuration is not supported, but are there plans to add support for it eventually?

Possible memory leak

For a larger project i get jvm out of heap memory on the gradle deamon. when i connect using visual jvm i see that the main consumers are

com.github.prokod.gradle.crossbuild.ResolutionStrategyConfigurer$_applyForLinkWith_closure1$_closure11$_closure12$_closure13	159,204,864 B (14%)	2,487,576 (8.2%)

com.github.prokod.gradle.crossbuild.ResolutionStrategyConfigurer$_applyForLinkWith_closure1$_closure11$_closure12 | 140078848 | 2501408
-- | -- | --

the heapdump is however too big put into this report.

Should be sufficient to have root module containing scala lib to inference the default Scala version for the project

Extracted from discussion in PR #87

Caused by: java.util.NoSuchElementException: Cannot access first() element from an empty Iterable
	at com.github.prokod.gradle.crossbuild.CrossBuildPlugin$_globDependencyTranslationForMainSourceSetsConfigurations_closure9$_closure16.doCall(CrossBuildPlugin.groovy:149)
	at com.github.prokod.gradle.crossbuild.CrossBuildPlugin$_globDependencyTranslationForMainSourceSetsConfigurations_closure9.doCall(CrossBuildPlugin.groovy:113)
	at com.github.prokod.gradle.crossbuild.CrossBuildPlugin.globDependencyTranslationForMainSourceSetsConfigurations(CrossBuildPlugin.groovy:102)
	at com.github.prokod.gradle.crossbuild.CrossBuildPlugin$_apply_closure3.doCall(CrossBuildPlugin.groovy:63)
	at org.gradle.configuration.internal.DefaultListenerBuildOperationDecorator$BuildOperationEmittingClosure$1.lambda$run$0(DefaultListenerBuildOperationDecorator.java:180)
	at org.gradle.configuration.internal.DefaultUserCodeApplicationContext.reapply(DefaultUserCodeApplicationContext.java:60)
	at org.gradle.configuration.internal.DefaultListenerBuildOperationDecorator$BuildOperationEmittingClosure$1.run(DefaultListenerBuildOperationDecorator.java:177)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92)
	at org.gradle.configuration.internal.DefaultListenerBuildOperationDecorator$BuildOperationEmittingClosure.doCall(DefaultListenerBuildOperationDecorator.java:174)
	at org.gradle.listener.ClosureBackedMethodInvocationDispatch.dispatch(ClosureBackedMethodInvocationDispatch.java:41)
	at org.gradle.listener.ClosureBackedMethodInvocationDispatch.dispatch(ClosureBackedMethodInvocationDispatch.java:25)
	at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:42)
	at org.gradle.internal.event.BroadcastDispatch$SingletonDispatch.dispatch(BroadcastDispatch.java:231)
	at org.gradle.internal.event.BroadcastDispatch$SingletonDispatch.dispatch(BroadcastDispatch.java:150)
	at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:58)
	at org.gradle.internal.event.BroadcastDispatch$CompositeDispatch.dispatch(BroadcastDispatch.java:325)
	at org.gradle.internal.event.BroadcastDispatch$CompositeDispatch.dispatch(BroadcastDispatch.java:235)
	at org.gradle.internal.event.ListenerBroadcast.dispatch(ListenerBroadcast.java:141)
	at org.gradle.internal.event.ListenerBroadcast.dispatch(ListenerBroadcast.java:37)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
	at com.sun.proxy.$Proxy29.afterEvaluate(Unknown Source)
	at org.gradle.configuration.project.LifecycleProjectEvaluator$NotifyAfterEvaluate$1.execute(LifecycleProjectEvaluator.java:186)
	at org.gradle.configuration.project.LifecycleProjectEvaluator$NotifyAfterEvaluate$1.execute(LifecycleProjectEvaluator.java:183)
	at org.gradle.api.internal.project.DefaultProject.stepEvaluationListener(DefaultProject.java:1446)
	at org.gradle.configuration.project.LifecycleProjectEvaluator$NotifyAfterEvaluate.run(LifecycleProjectEvaluator.java:192)

Oke i can tell you the cause

this gives the error (pseudo code)

project("A"){
 apply plugin  "crossbuil"
 compile `scalaLib:2.11.12`
}

project("B"){

 apply plugin "crossbuil"
  compile project("A")
}

works fine:

project("A"){
 apply plugin  "crossbuil"
 compile `scalaLib:2.11.12`
}

project("B"){

 apply plugin "crossbuil"
  compile project("A")
 compile `scalaLib:2.11.12`
}

Question: How to pass on extra information to subprojects?

I'm currently trying to apply this plugin to my Gradle project which should support a LOT of Spark versions and for some of those separate Scala versions. (Basically everything Apache has released for Spark 3.0.0+)
My setup in the parent project looks something like:

subprojects {
    apply(plugin = "com.github.prokod.gradle-crossbuild-scala")

    crossBuild {
        scalaVersionsCatalog = mapOf(
            "2.13" to "2.13.8",
            "2.12" to "2.12.15",
        )

        builds {
            for (spark in sparkVersionsForBoth)
                create(spark) {
                    scalaVersions = mutableSetOf("2.12", "2.13")
                }

            for (spark in sparkVersionsFor2_12)
                create(spark) {
                    scalaVersions = mutableSetOf("2.12")
                }
        }
    }
}

However, due to the complexity of the project, we cannot just swap out the scala/spark version and expect everything to work. There are some issues that can only be solved by replacing some pieces of code since some classes we use are only present from Spark 3.2+. To solve this, we use JCP. However, that plugin needs to pass on some variables like:

tasks.preprocess {
    ...
    vars.set("spark" to sparkVersion, "scala" to scalaVersion)
}

Now my question is, how can I pass on these versions based on which cross building variant is happening?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.