All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bmuschko.gradle.docker.DockerSpringBootApplicationPlugin.groovy Maven / Gradle / Ivy

There is a newer version: 6.7.0
Show newest version
package com.bmuschko.gradle.docker

import com.bmuschko.gradle.docker.tasks.image.DockerBuildImage
import com.bmuschko.gradle.docker.tasks.image.DockerPushImage
import com.bmuschko.gradle.docker.tasks.image.Dockerfile
import groovy.transform.CompileStatic
import org.gradle.api.Action
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.file.CopySpec
import org.gradle.api.plugins.ExtensionAware
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Sync
import org.springframework.boot.loader.tools.MainClassFinder

import java.util.concurrent.Callable

import static com.bmuschko.gradle.docker.utils.ConventionPluginHelper.getMainJavaSourceSetOutput
import static com.bmuschko.gradle.docker.utils.ConventionPluginHelper.getRuntimeClasspathConfiguration

/**
 * @since 3.4.5
 */
@CompileStatic
class DockerSpringBootApplicationPlugin implements Plugin {
    public static final String SPRING_BOOT_APPLICATION_EXTENSION_NAME = 'springBootApplication'
    public static final String SYNC_BUILD_CONTEXT_TASK_NAME = 'dockerSyncBuildContext'
    public static final String DOCKERFILE_TASK_NAME = 'dockerCreateDockerfile'
    public static final String BUILD_IMAGE_TASK_NAME = 'dockerBuildImage'
    public static final String PUSH_IMAGE_TASK_NAME = 'dockerPushImage'

    @Override
    void apply(Project project) {
        project.plugins.apply(DockerRemoteApiPlugin)
        DockerExtension dockerExtension = project.extensions.getByType(DockerExtension)
        DockerSpringBootApplication dockerSpringBootApplication = configureExtension(project, dockerExtension)

        project.plugins.withType(JavaPlugin) {
            project.plugins.withId('org.springframework.boot') {
                Dockerfile createDockerfileTask = createDockerfileTask(project, dockerSpringBootApplication)
                Sync syncBuildContextTask = createSyncBuildContextTask(project, createDockerfileTask)
                createDockerfileTask.dependsOn syncBuildContextTask
                DockerBuildImage dockerBuildImageTask = createBuildImageTask(project, createDockerfileTask, dockerSpringBootApplication)
                createPushImageTask(project, dockerBuildImageTask)
            }
        }
    }

    private static DockerSpringBootApplication configureExtension(Project project, DockerExtension dockerExtension) {
        ((ExtensionAware) dockerExtension).extensions.create(SPRING_BOOT_APPLICATION_EXTENSION_NAME, DockerSpringBootApplication, project)
    }

    private static Sync createSyncBuildContextTask(Project project, Dockerfile createDockerfileTask) {
        project.tasks.create(SYNC_BUILD_CONTEXT_TASK_NAME, Sync, new Action() {
            @Override
            void execute(Sync sync) {
                sync.with {
                    group = DockerRemoteApiPlugin.DEFAULT_TASK_GROUP
                    description = "Copies the distribution resources to a temporary directory for image creation."
                    dependsOn project.tasks.getByName(JavaPlugin.CLASSES_TASK_NAME)
                    into(createDockerfileTask.destDir)
                    into('libs', new Action() {
                        @Override
                        void execute(CopySpec copySpec) {
                            copySpec.from(getRuntimeClasspathConfiguration(project))
                        }
                    })
                    into('resources', new Action() {
                        @Override
                        void execute(CopySpec copySpec) {
                            copySpec.from(getMainJavaSourceSetOutput(project).resourcesDir)
                        }
                    })
                    into('classes', new Action() {
                        @Override
                        void execute(CopySpec copySpec) {
                            copySpec.from(getMainJavaSourceSetOutput(project).classesDirs)
                        }
                    })
                }
            }
        })
    }

    private static Dockerfile createDockerfileTask(Project project, DockerSpringBootApplication dockerSpringBootApplication) {
        project.tasks.create(DOCKERFILE_TASK_NAME, Dockerfile, new Action() {
            @Override
            void execute(Dockerfile dockerfile) {
                dockerfile.with {
                    description = 'Creates the Docker image for the Spring Boot application.'
                    from(project.provider(new Callable() {
                        @Override
                        Dockerfile.From call() throws Exception {
                            new Dockerfile.From(dockerSpringBootApplication.baseImage.get())
                        }
                    }))
                    workingDir('/app')
                    copyFile(project.provider(new Callable() {
                        @Override
                        Dockerfile.File call() throws Exception {
                            if (new File(dockerfile.destDir.get().asFile, 'libs').isDirectory()) {
                                return new Dockerfile.File('libs', 'libs/')
                            }
                        }
                    }))
                    copyFile(project.provider(new Callable() {
                        @Override
                        Dockerfile.File call() throws Exception {
                            if (getMainJavaSourceSetOutput(project).resourcesDir.isDirectory()) {
                                return new Dockerfile.File('resources', 'resources/')
                            }
                        }
                    }))
                    copyFile('classes', 'classes/')
                    entryPoint(project.provider(new Callable>() {
                        @Override
                        List call() throws Exception {
                            ["java", "-cp", "/app/resources:/app/classes:/app/libs/*", getSpringApplicationMainClassName(project)]
                        }
                    }))
                    exposePort(dockerSpringBootApplication.ports)
                }
            }
        })
    }

    private static DockerBuildImage createBuildImageTask(Project project, Dockerfile createDockerfileTask, DockerSpringBootApplication dockerSpringBootApplication) {
        project.tasks.create(BUILD_IMAGE_TASK_NAME, DockerBuildImage, new Action() {
            @Override
            void execute(DockerBuildImage dockerBuildImage) {
                dockerBuildImage.with {
                    description = 'Builds the Docker image for the Spring Boot application.'
                    dependsOn createDockerfileTask
                    tags.add(determineImageTag(project, dockerSpringBootApplication))
                }
            }
        })
    }

    private static Provider determineImageTag(Project project, DockerSpringBootApplication dockerSpringBootApplication) {
        project.provider(new Callable() {
            @Override
            String call() throws Exception {
                if (dockerSpringBootApplication.tag.getOrNull()) {
                    return dockerSpringBootApplication.tag.get()
                }

                String tagVersion = project.version == 'unspecified' ? 'latest' : project.version
                String artifactAndVersion = "${project.name}:${tagVersion}".toLowerCase().toString()
                project.group ? "$project.group/$artifactAndVersion".toString() : artifactAndVersion
            }
        })
    }

    private static void createPushImageTask(Project project, DockerBuildImage dockerBuildImageTask) {
        project.tasks.create(PUSH_IMAGE_TASK_NAME, DockerPushImage, new Action() {
            @Override
            void execute(DockerPushImage dockerPushImage) {
                dockerPushImage.with {
                    description = 'Pushes created Docker image to the repository.'
                    dependsOn dockerBuildImageTask
                    imageName.set(project.provider(new Callable() {
                        @Override
                        String call() throws Exception {
                            dockerBuildImageTask.getTags().get().first() as String
                        }
                    }))
                }
            }
        })
    }

    private static String getSpringApplicationMainClassName(Project project) {
        for (File classesDir : getMainJavaSourceSetOutput(project).classesDirs) {
            String mainClassName = MainClassFinder.findSingleMainClass(classesDir, 'org.springframework.boot.autoconfigure.SpringBootApplication')

            if (mainClassName) {
                return mainClassName
            }
        }

        throw new IllegalStateException('Main class name could not be resolved')
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy