创建定义插件和依赖项的自定义插件

时间:2020-02-04 13:17:58

标签: spring-boot gradle

我的组织为许多项目使用相同的Gradle插件和依赖项。我的自定义插件知识很薄弱,但是我想做的是将这些插件和依赖项包装到一个独立的插件中。我坚持了解如何将插件所需的插件/依赖项与我想在使用项目中使用的插件/依赖项区分开。这是一个基于gradle custom plugin docs和一些information about storing the plugin in a maven repo to allow it to automatically download dependencies的简单示例:

// build.gradle from standalone plugin
plugins {
  id 'java-gradle-plugin'
  id 'maven-publish'

  // these ones I don't need in the plugin, just in the project where I apply the plugin
  id 'war'
  id 'org.springframework.boot' version '2.2.4.RELEASE'
  id 'io.spring.dependency-management' version '1.0.9.RELEASE'
  id 'org.asciidoctor.convert' version '1.5.8'
}

group = 'org.sample'
version = '1.0.0'

publishing {
  repositories {
    maven {
      url "../maven-repo"
    }
  }
}

gradlePlugin {
  plugins {
    greeting {
      id = "org.sample.greeter"
      implementationClass = "org.sample.GreetingPlugin"
    }
  }
}

dependencies {
  implementation gradleApi() // I think I need this for the imports in GreetingPlugin.java
  implementation localGroovy() // I think I would need this if GreetingPlugin was written in Groovy

  // these ones I don't need in the plugin, just in the project where I apply the plugin
  implementation 'org.springframework.boot:spring-boot-starter-web'
  testImplementation 'org.springframework.boot:spring-boot-starter-test' {
    exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
  }
  testImplementation 'org.junit.jupiter:junit-jupiter-engine'
}

// this is only needed in the project where I apply the plugin
// I believe this should be in the GreetingPlugin.java file though
test {
 useJUnitPlatform()
}

和支持类...

package org.sample;

import org.gradle.api.DefaultTask;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.tasks.TaskAction;

class Greeting Plugin implements Plugin<Project> {
  @Override
  public void apply(Project project) {
    project.getTasks().create("hello", MyTask.class);
  }

  public static class MyTask extends DefaultTask {
    @TaskAction
    public void myTask() {
      System.out.println("Hello, World!");
    }    
  }
}

在我要使用该插件的项目中,我具有以下文件:

// settings.gradle
pluginManagement {
  repositories {
    maven {
      url "../maven-repo"
    }
    gradlePluginPortal()
  }
}
// build.gradle
plugins {
  id 'org.sample.greeter' version '1.0.0'
}

我的想法是,以这种方式使用插件,项目将继承插件代码中列出的插件和依赖项。我想我已经接近了,就像我./gradlew publish看到插件被应用时一样,但它不喜欢spring-starter-web依赖项没有版本(我知道一个多项目gradle仓库,我需要在mavenBOM中包含dependencyManagement块,所以这可能是关键吗?)我试图遵循SpringBoot gradle plugin进行深入了解,但这对我来说有点太复杂了。 >

那么,这是创建包含内置插件/依赖项的独立插件的正确方法吗?为什么Spring依赖管理器不应用版本控制?


编辑:我遵循了@Alan Hay的链接,而不是自定义插件,而是尝试使用“应用自”。但是,它仍然不起作用。这是基于该方法的文件:

// build.gradle from 'parent' build.gradle
plugins {
  id 'war'
  id 'org.springframework.boot' version '2.2.4.RELEASE'
  id 'io.spring.dependency-management' version '1.0.9.RELEASE'
  id 'org.asciidoctor.convert' version '1.5.8'
}

dependencies {
  implementation 'org.springframework.boot:spring-boot-starter-web'
  testImplementation 'org.springframework.boot:spring-boot-starter-test' {
    exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
  }
  testImplementation 'org.junit.jupiter:junit-jupiter-engine'
}

test {
 useJUnitPlatform()
}

并尝试引用另一个项目,这是文件中的唯一一行:

apply from: '<path-to-above>/build.gradle'

此错误如下:

  script '<path-to-above>/build.gradle': 15: Only Project build scripts can contain plugins {} blocks

  See https://docs.gradle.org/5.5.1/userguide/plugins.html#sec:plugins_block for information on the plugins {} block

   @ line 15, column 1.
     plugins {
     ^

  1 error

1 个答案:

答案 0 :(得分:0)

当需要在多个独立项目中共享相同的构建逻辑时,首选独立的二进制插件。此外,良好的插件设计可将功能与常规功能区分开。在这种情况下,该功能由Gradle和某些第三方插件提供,但是您要在此插件的顶部添加自己的约定。

在实现此功能时,您实际上需要将代码向下推一层。 build.gradle中需要配置的所有内容都必须包含在插件的源代码中。会影响构建脚本的类路径的任何内容(即buildscript { }plugins { })都属于插件的依赖项。插件中的plugins { }块仅应具有构建插件所需的构建插件。

// build.gradle from standalone plugin

// plugins {} should contain only plugins you need in the build of the plugin itself
plugins {
  id 'java-gradle-plugin'
  id 'maven-publish'
}

group = 'org.sample'
version = '1.0.0'

dependencies {
  implementation gradleApi()

  // Dependencies for plugins you will apply to the target build
  implementation 'io.spring.gradle:dependency-management-plugin:1.0.9.RELEASE'
  implementation 'org.asciidoctor:asciidoctor-gradle-jvm:2.4.0'
  implementation 'org.springframework.boot:spring-boot-gradle-plugin:2.2.4.RELEASE'
}

gradlePlugin {
  plugins {
    greeting {
      id = "org.sample.greeter"
      implementationClass = "org.sample.GreetingPlugin"
    }
  }
}

publishing {
  repositories {
    maven {
      url "../maven-repo"
    }
  }
}
package org.sample;

import org.gradle.api.DefaultTask;
import org.gradle.api.Plugin;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.Project;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.testing.Test;

class Greeting Plugin implements Plugin<Project> {

  @Override
  public void apply(Project project) {

    // Apply plugins to the project (already on the classpath)
    project.getPluginManager().apply("war");
    project.getPluginManager().apply("org.springframework.boot");
    project.getPluginManager().apply("io.spring.dependency-management");
    project.getPluginManager().apply(" org.asciidoctor.convert");

    // Dependencies that you need for the code in the project that this plugin is applied
    DependencyHandler dependencies = project.getDependencies();
    dependencies.add(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME, "org.springframework.boot:spring-boot-starter-web");
    dependencies.add(JavaPlugin.TEST_IMPLEMENTATION_CONFIGURATION_NAME, "org.junit.jupiter:junit-jupiter-engine");
    dependencies.add(JavaPlugin.TEST_IMPLEMENTATION_CONFIGURATION_NAME, springBootStarterTest(dependencies));

    projects.getTasks().withType(Test.class, test -> {
      test.useJUnitPlatform();
    });
  }

  private Dependency springBootStarterTest(DependencyHandler dependencies) {
    Map<String, String> exclude = new HashMap<>();
    exclude.put("group", "org.junit.vintage");
    exclude.put("module", "junit-vintage-engine");
    return ((ModuleDependency) dependencies.module("org.springframework.boot:spring-boot-starter-test")).exclude(exclude);
  }

}

由于使用Java编写,因此更为冗长,但在功能上等同于将其放入项目的build.gradle

plugins {
  id 'war'
  id 'org.springframework.boot' version '2.2.4.RELEASE'
  id 'io.spring.dependency-management' version '1.0.9.RELEASE'
  id 'org.asciidoctor.convert' version '1.5.8'
}

dependencies {
  implementation 'org.springframework.boot:spring-boot-starter-web'
  testImplementation 'org.springframework.boot:spring-boot-starter-test' {
    exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
  }
  testImplementation 'org.junit.jupiter:junit-jupiter-engine'
}

test {
 useJUnitPlatform()
}