Created
June 13, 2019 17:48
-
-
Save JLLeitschuh/43f7a45ae9d5fe7f1f58722d265caacf to your computer and use it in GitHub Desktop.
Gradle Plugin Build logic to upload single files to JFrog Artifactory
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* ****************************************************************************** */ | |
// MIT License | |
// | |
// Copyright (c) 2019 Hewlett Packard Enterprise Development LP | |
// | |
// Permission is hereby granted, free of charge, to any person obtaining a copy | |
// of this software and associated documentation files (the "Software"), to deal | |
// in the Software without restriction, including without limitation the rights | |
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
// copies of the Software, and to permit persons to whom the Software is | |
// furnished to do so, subject to the following conditions: | |
// | |
// The above copyright notice and this permission notice shall be included in all | |
// copies or substantial portions of the Software. | |
// | |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
// SOFTWARE. | |
/* ****************************************************************************** */ | |
import org.gradle.api.Action | |
import org.gradle.api.DefaultTask | |
import org.gradle.api.NamedDomainObjectContainer | |
import org.gradle.api.Plugin | |
import org.gradle.api.Project | |
import org.gradle.api.Task | |
import org.gradle.api.credentials.PasswordCredentials | |
import org.gradle.api.file.RegularFileProperty | |
import org.gradle.api.model.ObjectFactory | |
import org.gradle.api.publish.plugins.PublishingPlugin | |
import org.gradle.api.tasks.Input | |
import org.gradle.api.tasks.InputFile | |
import org.gradle.api.tasks.Internal | |
import org.gradle.api.tasks.Nested | |
import org.gradle.api.tasks.PathSensitive | |
import org.gradle.api.tasks.PathSensitivity | |
import org.gradle.api.tasks.TaskAction | |
import org.gradle.kotlin.dsl.property | |
import org.jfrog.artifactory.client.ArtifactoryClientBuilder | |
import javax.inject.Inject | |
open class ArtifactoryExtension | |
@Inject | |
internal constructor( | |
project: Project | |
) { | |
val servers: NamedDomainObjectContainer<ArtifactoryServer> = | |
project.container(ArtifactoryServer::class.java) { | |
require(it.isNotBlank()) { | |
"Name of ${ArtifactoryServer::class.simpleName} can not be empty." | |
} | |
ArtifactoryServer( | |
name = it, | |
project = project | |
) | |
} | |
} | |
data class ArtifactoryServer | |
internal constructor( | |
val name: String, | |
/** | |
* The url of the Artifactory server. | |
*/ | |
var url: String? = null, | |
/** | |
* Configures the files to be uploaded. | |
*/ | |
val upload: NamedDomainObjectContainer<UploadDescriptor>, | |
internal val internalCredentials: CustomPasswordCredentials | |
) { | |
constructor( | |
name: String, | |
project: Project | |
) : this( | |
name = name, | |
upload = project.container(UploadDescriptor::class.java) { | |
require(it.isNotBlank()) { | |
"Name of ${UploadDescriptor::class.simpleName} can not be empty." | |
} | |
UploadDescriptor( | |
name = it, | |
file = project.objects.fileProperty() | |
) | |
}, | |
internalCredentials = project.objects.newInstance<CustomPasswordCredentials>() | |
) | |
/** | |
* Used to set the credentials to be used to upload the file to the Artifactory server. | |
*/ | |
val credentials: PasswordCredentials = internalCredentials | |
fun credentials(configure: Action<PasswordCredentials>) { | |
configure.execute(credentials) | |
} | |
} | |
data class UploadDescriptor( | |
val name: String, | |
/** | |
* The Artifactory repository the file should be uploaded to. | |
*/ | |
var repository: String? = null, | |
/** | |
* The destination on the Artifactory server that this file should be uploaded to. | |
*/ | |
var destinationDirectory: String? = null, | |
/** | |
* The file to be uploaded to the [destinationDirectory]. | |
*/ | |
val file: RegularFileProperty, | |
/** | |
* Specifies that this [file] has been built by a set of tasks. | |
* @see Task.dependsOn | |
*/ | |
var builtBy: Iterable<Any> = emptyList() | |
) { | |
/** | |
* Specifies that this [file] has been built by a set of tasks | |
* @see Task.dependsOn | |
*/ | |
fun builtBy(vararg tasks: Any) { | |
builtBy += listOf(*tasks) | |
} | |
} | |
open class ArtifactoryPlugin : Plugin<Project> { | |
companion object { | |
const val ARTIFACTORY_PUBLISH_TASK_NAME = "publishToArtifactory" | |
} | |
override fun apply(target: Project) { | |
target.plugins.apply(PublishingPlugin::class.java) | |
val extension = target.extensions | |
.create("artifactory", ArtifactoryExtension::class.java, target) | |
val publishToArtifactory = target.tasks.register(ARTIFACTORY_PUBLISH_TASK_NAME) { | |
group = PublishingPlugin.PUBLISH_TASK_GROUP | |
description = "Publishes all of the files that have been configured to Artifactory." | |
} | |
extension.servers.all { | |
val server = this | |
server.upload.all { | |
val descriptor = this | |
val publishFileToArtifactory = target.tasks | |
.register( | |
"publish${descriptor.name.capitalize()}To${server.name.capitalize()}ArtifactoryServer", | |
UploadToArtifactoryTask::class.java | |
) { | |
url.set(target.provider { server.url }) | |
repository.set(target.provider { requireNotNull(descriptor.repository) { "repository" } }) | |
credentials.set(target.provider { server.internalCredentials }) | |
destinationDirectory.set(target.provider { requireNotNull(descriptor.destinationDirectory) { "destinationDirectory" } }) | |
fileToUpload.set(descriptor.file) | |
dependsOn(target.provider { descriptor.builtBy }) | |
} | |
publishToArtifactory.configure { dependsOn(publishFileToArtifactory) } | |
} | |
} | |
target.tasks.named(PublishingPlugin.PUBLISH_LIFECYCLE_TASK_NAME).configure { | |
dependsOn(publishToArtifactory) | |
} | |
} | |
} | |
open class UploadToArtifactoryTask | |
@Inject | |
constructor( | |
objectFactory: ObjectFactory | |
) : DefaultTask() { | |
@get:Input | |
val url = objectFactory.stringProperty() | |
@get:Input | |
val repository = objectFactory.stringProperty() | |
@get:Nested | |
val credentials = objectFactory.property<CustomPasswordCredentials>() | |
@get:Input | |
val destinationDirectory = objectFactory.stringProperty() | |
@get:InputFile | |
@get:PathSensitive(PathSensitivity.RELATIVE) | |
val fileToUpload = objectFactory.fileProperty() | |
@TaskAction | |
fun doUpload() { | |
val artifactory = | |
ArtifactoryClientBuilder | |
.create() | |
.setUrl(url.get()) | |
.setUsername(requireNotNull(credentials.get().username) { "username" }) | |
.setPassword(requireNotNull(credentials.get().password) { "password" }) | |
.build() | |
val fileToUpload = fileToUpload.asFile.get() | |
// Add a trailing slash if one isn't present. | |
val destinationBase = destinationDirectory.get().let { | |
if (it.endsWith("/")) it else (it + "/") | |
} | |
val destinationPathFull = destinationBase + fileToUpload.name | |
val uploadedFile = | |
artifactory | |
.repository(repository.get()) | |
.upload(destinationPathFull, fileToUpload) | |
.bySha1Checksum() | |
.doUpload() | |
logger.lifecycle("File uploaded to: ${uploadedFile.uri}") | |
} | |
} | |
open class CustomPasswordCredentials | |
constructor( | |
@field:Internal | |
private var user: String? = null, | |
@field:Internal | |
private var pass: String? = null | |
) : PasswordCredentials { | |
@Inject | |
constructor() : this(null, null) | |
override fun setUsername(userName: String?) { | |
user = userName | |
} | |
@Input | |
override fun getUsername(): String? { | |
return user | |
} | |
@Input | |
override fun getPassword(): String? { | |
return pass | |
} | |
override fun setPassword(password: String?) { | |
pass = password | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment