com.palantir.gradle.docker.PalantirDockerPlugin.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-docker Show documentation
Show all versions of gradle-docker Show documentation
Palantir open source project
/*
* (c) Copyright 2020 Palantir Technologies Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.palantir.gradle.docker
import java.util.regex.Pattern
import javax.inject.Inject
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.PublishArtifact
import org.gradle.api.internal.artifacts.publish.ArchivePublishArtifact
import org.gradle.api.internal.attributes.ImmutableAttributesFactory
import org.gradle.api.logging.LogLevel
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
import org.gradle.api.model.ObjectFactory
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.Delete
import org.gradle.api.tasks.Exec
import org.gradle.api.tasks.bundling.Zip
class PalantirDockerPlugin implements Plugin {
private static final Logger log = Logging.getLogger(PalantirDockerPlugin.class)
private static final Pattern LABEL_KEY_PATTERN = Pattern.compile('^[a-z0-9.-]*$')
private final ObjectFactory objectFactory
private final ImmutableAttributesFactory attributesFactory
@Inject
PalantirDockerPlugin(ObjectFactory objectFactory, ImmutableAttributesFactory attributesFactory) {
this.objectFactory = objectFactory
this.attributesFactory = attributesFactory
}
@Override
void apply(Project project) {
DockerExtension ext = project.extensions.create('docker', DockerExtension, project)
if (!project.configurations.findByName('docker')) {
project.configurations.create('docker')
}
Delete clean = project.tasks.create('dockerClean', Delete, {
group = 'Docker'
description = 'Cleans Docker build directory.'
})
Copy prepare = project.tasks.create('dockerPrepare', Copy, {
group = 'Docker'
description = 'Prepares Docker build directory.'
dependsOn clean
})
Exec exec = project.tasks.create('docker', Exec, {
group = 'Docker'
description = 'Builds Docker image.'
dependsOn prepare
})
Task tag = project.tasks.create('dockerTag', {
group = 'Docker'
description = 'Applies all tags to the Docker image.'
dependsOn exec
})
Exec push = project.tasks.create('dockerPush', Exec, {
group = 'Docker'
description = 'Pushes named Docker image to configured Docker Hub.'
dependsOn tag
})
Task pushAllTags = project.tasks.create('dockerTagsPush', {
group = 'Docker'
description = 'Pushes all tagged Docker images to configured Docker Hub.'
})
Zip dockerfileZip = project.tasks.create('dockerfileZip', Zip, {
group = 'Docker'
description = 'Bundles the configured Dockerfile in a zip file'
})
PublishArtifact dockerArtifact = new ArchivePublishArtifact(dockerfileZip)
Configuration dockerConfiguration = project.getConfigurations().getByName('docker')
dockerConfiguration.getArtifacts().add(dockerArtifact)
project.getComponents().add(new DockerComponent(dockerArtifact, dockerConfiguration.getAllDependencies(),
objectFactory, attributesFactory))
project.afterEvaluate {
ext.resolvePathsAndValidate()
String dockerDir = "${project.buildDir}/docker"
clean.delete dockerDir
prepare.with {
with ext.copySpec
from(ext.resolvedDockerfile) {
rename { fileName ->
fileName.replace(ext.resolvedDockerfile.getName(), 'Dockerfile')
}
}
into dockerDir
}
exec.with {
workingDir dockerDir
commandLine buildCommandLine(ext)
dependsOn ext.getDependencies()
logging.captureStandardOutput LogLevel.INFO
logging.captureStandardError LogLevel.ERROR
}
Map tags = ext.namedTags.collectEntries { taskName, tagName ->
[generateTagTaskName(taskName), [
tagName: tagName,
tagTask: { -> tagName }
]]
}
if (!ext.tags.isEmpty()) {
ext.tags.each { unresolvedTagName ->
String taskName = generateTagTaskName(unresolvedTagName)
if (tags.containsKey(taskName)) {
throw new IllegalArgumentException("Task name '${taskName}' is existed.")
}
tags[taskName] = [
tagName: unresolvedTagName,
tagTask: { -> computeName(ext.name, unresolvedTagName) }
]
}
}
tags.each { taskName, tagConfig ->
Exec tagSubTask = project.tasks.create('dockerTag' + taskName, Exec, {
group = 'Docker'
description = "Tags Docker image with tag '${tagConfig.tagName}'"
workingDir dockerDir
commandLine 'docker', 'tag', "${-> ext.name}", "${-> tagConfig.tagTask()}"
dependsOn exec
})
tag.dependsOn tagSubTask
Exec pushSubTask = project.tasks.create('dockerPush' + taskName, Exec, {
group = 'Docker'
description = "Pushes the Docker image with tag '${tagConfig.tagName}' to configured Docker Hub"
workingDir dockerDir
commandLine 'docker', 'push', "${-> tagConfig.tagTask()}"
dependsOn tagSubTask
})
pushAllTags.dependsOn pushSubTask
}
push.with {
workingDir dockerDir
commandLine 'docker', 'push', "${-> ext.name}"
}
dockerfileZip.with {
from(ext.resolvedDockerfile)
}
}
}
private List buildCommandLine(DockerExtension ext) {
List buildCommandLine = ['docker', 'build']
if (ext.noCache) {
buildCommandLine.add '--no-cache'
}
if (ext.getNetwork() != null) {
buildCommandLine.addAll('--network', ext.network)
}
if (!ext.buildArgs.isEmpty()) {
for (Map.Entry buildArg : ext.buildArgs.entrySet()) {
buildCommandLine.addAll('--build-arg', "${buildArg.getKey()}=${buildArg.getValue()}")
}
}
if (!ext.labels.isEmpty()) {
for (Map.Entry label : ext.labels.entrySet()) {
if (!label.getKey().matches(LABEL_KEY_PATTERN)) {
throw new GradleException(String.format("Docker label '%s' contains illegal characters. " +
"Label keys must only contain lowercase alphanumberic, `.`, or `-` characters (must match %s).",
label.getKey(), LABEL_KEY_PATTERN.pattern()))
}
buildCommandLine.addAll('--label', "${label.getKey()}=${label.getValue()}")
}
}
if (ext.pull) {
buildCommandLine.add '--pull'
}
buildCommandLine.addAll(['-t', "${-> ext.name}", '.'])
return buildCommandLine
}
@Deprecated
private static String computeName(String name, String tag) {
int firstAt = tag.indexOf("@")
String tagValue
if (firstAt > 0) {
tagValue = tag.substring(firstAt + 1, tag.length())
} else {
tagValue = tag
}
if (tagValue.contains(':') || tagValue.contains('/')) {
// tag with ':' or '/' -> force use the tag value
return tagValue
} else {
// tag without ':' and '/' -> replace the tag part of original name
int lastColon = name.lastIndexOf(':')
int lastSlash = name.lastIndexOf('/')
int endIndex;
// image_name -> this should remain
// host:port/image_name -> this should remain.
// host:port/image_name:v1 -> v1 should be replaced
if (lastColon > lastSlash) endIndex = lastColon
else endIndex = name.length()
return name.substring(0, endIndex) + ":" + tagValue
}
}
@Deprecated
private static String generateTagTaskName(String name) {
String tagTaskName = name
int firstAt = name.indexOf("@")
if (firstAt > 0) {
// Get substring of task name
tagTaskName = name.substring(0, firstAt)
} else if (firstAt == 0) {
// Task name must not be empty
throw new GradleException("Task name of docker tag '${name}' must not be empty.")
} else if (name.contains(':') || name.contains('/')) {
// Tags which with repo or name must have a task name
throw new GradleException("Docker tag '${name}' must have a task name.")
}
StringBuffer sb = new StringBuffer(tagTaskName)
// Uppercase the first letter of task name
sb.replace(0, 1, tagTaskName.substring(0, 1).toUpperCase());
return sb.toString()
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy