Gradle 设置以处理具有相同代码库但不同依赖项的两种部署类型

Gradle setup to handle two deployment types with the same code base but different dependencies

我正在开发一个新的 Web 应用程序项目,它必须 运行 在分布式环境中,以及一个良好的旧 "throw everything in a war file and run it on a tomcat" 环境中。 两个版本的代码完全相同,只有一个小的 if/else 子句来处理不同的调用类型。

但是,我现在正在为 gradle 设置而苦苦挣扎。我有两个服务,我们称之为 "DAO" 和 "Connector" 作为例子。 DAO 使用连接器从数据源检索数据。 在分布式模式下,DAO 必须依赖 Connector:api,因为 DAO 应该只知道 said API,作为其他地方的实现 运行。 在捆绑模式下,DAO 必须依赖 Connector:bundle,因为所有内容都必须进入单个 war 文件。

我们生成的所有 jar 都使用 maven-publish 插件发布在我们内部的 nexus 3 服务器上。我们目前正在使用 gradle 版本 4.10.3,DAO 项目是一个更大的多项目设置的一部分,由紧密耦合的模块组成,而连接器是供另一个应用程序使用的共享服务。

为了完成这些事情,我尝试了很多想法。他们中的大多数都是完全错误的,所以我不会在这里谈论他们。我现在得到的是一个多发布设置。

  publishing {
    publications {
      dist(MavenPublication) {
        alias false
        from components.java
        afterEvaluate {
          artifact apiJar
        }
      }
      bundle(MavenPublication) {
        alias true
        from components.java
        afterEvaluate {
          artifactId "${artifactId}-bundle"
        }
      }
    }
    repositories {...}
}

此设置现在生成 2 套 pom 文件和 jar 文件。一个用于连接器-api.jar,一个用于连接器-bundle.jar

在 DAO 依赖设置中,我现在必须使用 if 块来决定设置什么依赖:

gradle.taskGraph.whenReady { graph ->
    if (graph.hasTask(generatePomFileForBundlePublication)){
      dependencies {
        implementation "com.example:Connector-bundle:1.0.0"
      }
    }
    else {
      dependencies {
        implementation "com.example:Connector:1.0.0:api"
      }
    }
  }
}

但是,这会导致我在开发时不再拥有该库的问题。所以我无条件地添加了 api-dependency。

这确实有些工作,但现在生成的 pom 文件总是在里面有 api-依赖关系,当我构建捆绑版本时它有两个依赖关系。

完成了这么长的解释,这是我的问题:
有没有更好的方法来代替这个......拼凑? 如果没有,我至少可以处理依赖重复问题吗?当我构建捆绑版本时,我不希望有 api-package。它充其量是冗余的,最坏的情况是它增加了更多冗余依赖项。不能像上面说的有条件的加,因为我失去了对API开发的能力,不想一直手动加减。

感谢任何帮助,因为我完全没有想法。

PS: alias的使用是为了解决maven-publish插件在多项目环境下使用多发布的问题(参见https://github.com/gradle/gradle/issues/1061

好吧,在摒弃我所有的先入之见并创建了一个 gradle 原型之后,我找到了一个可行的解决方案。这就是我所做的:

首先我添加了一个新的 属性 到 gradle.properties mode=dist
这使我能够通过 if(mode == "dist")else 块拆分我的依赖项。作为一个例子:

dependencies {
  if (mode == "dist"){
    implementation "com.example:Connector:1.0.0:api" 
  } else {
    implementation "com.example:Connector-bundle:1.0.0"
  }
}

多亏了这个设置,gradle 默认情况下就像我处于分发模式一样,这意味着我总是加载 API 库,而不是完整的东西。

接下来,我创建了一个自定义任务 publishBundle,我在其中设置 mode = "lib" 并执行整个构建和发布过程。例如:

task publishBundle {
  mode = "lib"
  dependsOn "build"
  dependsOn "publishBundlePublicationToNexusRepository"
}

最后一次调整必须在发布配置中进行。在这里我也必须添加正确的模式值:

  publishing {
    publications {
      dist(MavenPublication) {
        mode = "dist"
        alias false
        from components.java
        afterEvaluate {
          artifact apiJar
        }
      }
      bundle(MavenPublication) {
        mode = "lib"
        alias true
        from components.java
        afterEvaluate {
          artifactId "${artifactId}-bundle"
        }
      }
    }
    repositories {...}
  }

有了这个,正常的构建和发布过程将遵循分布式方法,而 publishBundle 任务创建和发布包。在我们的存储库中,我们现在有两个连接器项目:connector 和 connector-bundle,这意味着我们可以根据所处的模式处理不同的依赖项。

感觉还是拼凑的,不过可以想象我的要求实在是太...特别了。