Gradle 8.1: Delombok, google-java-format 적용

2023-06-05

들어가며

이전 글#의 후속 내용이다.

Gradle 8.1

sources variant의 구현부를 또다시 한번 보자.

gradle/gradle@v8.1.0/subprojects/plugins/src/main/java/org/gradle/api/plugins/internal/DefaultJavaPluginExtension.java#L231-L248

public void withSourcesJar() {
    maybeEmitMissingJavaComponentDeprecation("withSourcesJar()");

    if (project.getPlugins().hasPlugin(JavaPlugin.class)) {
        JavaPluginHelper.getJavaComponent(project).enableSourcesJarVariant();
    } else {
        SourceSet main = getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME);
        JvmPluginsHelper.createDocumentationVariantWithArtifact(
            main.getSourcesElementsConfigurationName(),
            null,
            SOURCES,
            ImmutableList.of(),
            main.getSourcesJarTaskName(),
            main.getAllSource(),
            project
        );
    }
}

else 쪽만 따라 하면 (중간 단계야 더 있겠지만 결과적으로) publish에 sourcesJar dependency가 생기지 않는다. SNAPSHOT으로 테스트해 볼 때는 발견하지 못했고 한 개의 릴리즈가 나가고 나서야 알았다.

if쪽의 enableJavadocJarVariant를 따라가 보자.

gradle/gradle@v8.1.0/subprojects/plugins/src/main/java/org/gradle/jvm/component/internal/DefaultJvmSoftwareComponent.java#L298-L312

public void enableSourcesJarVariant() {
    if (project.getConfigurations().findByName(sourceSet.getSourcesElementsConfigurationName()) != null) {
        return;
    }
    Configuration sourcesVariant = JvmPluginsHelper.createDocumentationVariantWithArtifact(
        sourceSet.getSourcesElementsConfigurationName(),
        null,
        SOURCES,
        ImmutableList.of(),
        sourceSet.getSourcesJarTaskName(),
        sourceSet.getAllSource(),
        (ProjectInternal) project
    );
    addVariantsFromConfiguration(sourcesVariant, new JavaConfigurationVariantMapping("runtime", true));
}

addVariantsFromConfiguration가 핵심이다. 정리하면 아래와 같다.

import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.plugins.internal.JavaConfigurationVariantMapping
import org.gradle.api.plugins.internal.JvmPluginsHelper
import org.gradle.jvm.component.internal.DefaultJvmSoftwareComponent

plugins {
    // 생략
}

/**
 * @see org.gradle.api.plugins.internal.DefaultJavaPluginExtension#withSourcesJar DefaultJavaPluginExtension.withSourcesJar
 * @see DefaultJvmSoftwareComponent#enableSourcesJarVariant
 */
java {
    def main = sourceSets.main
    def sourcesVariant = JvmPluginsHelper.createDocumentationVariantWithArtifact(
            main.sourcesElementsConfigurationName,
            null,
            DocsType.SOURCES,
            [],
            main.sourcesJarTaskName,
            main.delombokTask,
            project as ProjectInternal)
    (components.java as DefaultJvmSoftwareComponent).addVariantsFromConfiguration(sourcesVariant, new JavaConfigurationVariantMapping('runtime', true))
}

compileJava {
    // 생략
}

delombok.finalizedBy tasks.named('googleJavaFormat')

googleJavaFormat {
    // 생략
}

원본 코드와 유사하게 (8.1에서 변경된) org.gradle.api.plugins.internal.JavaPluginHelper.getJavaComponent(project)를 사용할 수도 있지만, 어차피 addVariantsFromConfiguration 인식하려면 DefaultJvmSoftwareComponent로 잡아줘야 하는 것은 동일해서 그냥 간단한 형태로 사용한다.

Task Tree

gradle-task-tree라는 좋은 플러그인을 발견하여 사용해 보았다.

addVariantsFromConfiguration 없을 때

:publish
\--- :publishGprPublicationToGitHubPackagesRepository
     +--- :generateMetadataFileForGprPublication
     |    \--- :jar
     |         +--- :classes
     |         |    +--- :compileGroovy
     |         |    |    \--- :compileJava
     |         |    |         +--- :delombok
     |         |    |         |    \--- :generateEffectiveLombokConfig
     |         |    |         +--- :generateEffectiveLombokConfig *
     |         |    |         \--- :processResources
     |         |    +--- :compileJava *
     |         |    \--- :processResources *
     |         +--- :compileGroovy *
     |         \--- :compileJava *
     +--- :generatePomFileForGprPublication
     \--- :jar *


(*) - subtree omitted (printed previously)

addVariantsFromConfiguration 있을 때

:publish
\--- :publishGprPublicationToGitHubPackagesRepository
     +--- :generateMetadataFileForGprPublication
     |    +--- :jar
     |    |    +--- :classes
     |    |    |    +--- :compileGroovy
     |    |    |    |    \--- :compileJava
     |    |    |    |         +--- :delombok
     |    |    |    |         |    \--- :generateEffectiveLombokConfig
     |    |    |    |         +--- :generateEffectiveLombokConfig *
     |    |    |    |         \--- :processResources
     |    |    |    +--- :compileJava *
     |    |    |    \--- :processResources *
     |    |    +--- :compileGroovy *
     |    |    \--- :compileJava *
     |    \--- :sourcesJar
     |         \--- :delombok *
     +--- :generatePomFileForGprPublication
     +--- :jar *
     \--- :sourcesJar *


(*) - subtree omitted (printed previously)

확실히 task dependency가 생겼음을 알 수 있다.

2023-07-11 추가: Gradle 8.2

구현이 달라지지는 않아서 업그레이드에 실패할 일은 없고, 단지 참고할 Javadoc 링크만 바뀌었다.

- * @see DefaultJvmSoftwareComponent#enableSourcesJarVariant
+ * @see DefaultJvmSoftwareComponent#withSourcesJar
+ * @see org.gradle.api.plugins.jvm.internal.DefaultJvmFeature#withSourcesJar DefaultJvmFeature.withSourcesJar

-    def sourcesVariant = JvmPluginsHelper.createDocumentationVariantWithArtifact(
+    def sourcesElements = JvmPluginsHelper.createDocumentationVariantWithArtifact(

-    (components.java as DefaultJvmSoftwareComponent).addVariantsFromConfiguration(sourcesVariant, new JavaConfigurationVariantMapping('runtime', true))
+    (components.java as DefaultJvmSoftwareComponent).addVariantsFromConfiguration(sourcesElements, new JavaConfigurationVariantMapping('runtime', true))

2024-03-27 추가: Gradle 8.6

구현이 아주 약간 바뀌었다.

gradle/gradle@f10ab27/platforms/jvm/plugins-java-base/src/main/java/org/gradle/api/plugins/internal/JvmPluginsHelper.java#L136-R136

     def sourcesElements = JvmPluginsHelper.createDocumentationVariantWithArtifact(
             main.sourcesElementsConfigurationName,
             null,
             DocsType.SOURCES,
-            [],
+            [] as Set,
             main.sourcesJarTaskName,
             main.delombokTask,
             project as ProjectInternal)

나오며

자꾸 바뀌어 번거롭다. 아예 기능으로 만들고 기여하고 싶은데 니즈가 그만큼 있을지도 잘 모르겠고 규모도 좀 커 보인다.

돌아가기