All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
name.remal.gradle_plugins.plugins.publish.gradle_plugin_portal.PublishToGradlePluginPortalRepository.kt Maven / Gradle / Ivy
package name.remal.gradle_plugins.plugins.publish.gradle_plugin_portal
import com.gradle.protocols.ServerResponseBase
import com.gradle.publish.Hasher
import com.gradle.publish.OAuthHttpClient
import com.gradle.publish.protocols.v1.models.ClientPostRequest
import com.gradle.publish.protocols.v1.models.publish.*
import com.gradle.publish.upload.Uploader
import name.remal.*
import name.remal.gradle_plugins.dsl.*
import name.remal.gradle_plugins.dsl.extensions.*
import name.remal.gradle_plugins.dsl.utils.retryIO
import name.remal.gradle_plugins.plugins.publish.BasePublishToMavenRepository
import org.gradle.api.tasks.TaskAction
import org.gradle.util.GradleVersion
import java.io.File
import java.lang.System.getProperty
import java.net.URI
import java.net.URL
import kotlin.text.isNotEmpty
import kotlin.text.toLowerCase
import kotlin.text.trim
@BuildTask
class PublishToGradlePluginPortalRepository : BasePublishToMavenRepository() {
private val alreadyPublishedPlugins: List by lazy { repository.plugins.filter { isPluginPublished(it.id!!, publication.version) } }
private val notPublishedPlugins: List by lazy { repository.plugins.toMutableList().also { it.removeAll(alreadyPublishedPlugins) } }
private fun isPluginPublished(pluginId: String, version: String): Boolean {
val url = URL("https://plugins.gradle.org/plugin/${encodeURIComponent(pluginId)}/${encodeURIComponent(version)}")
return retryIO { 200 == url.fetchHttpStatus() }
}
init {
onlyIf {
if (repository.publishKey.isNullOrEmpty()) {
throw IllegalStateException("Repository ${repository.name} doesn't have ${GradlePluginPortalRepository::publishKey.name} property set")
}
if (repository.publishSecret.isNullOrEmpty()) {
throw IllegalStateException("Repository ${repository.name} doesn't have ${GradlePluginPortalRepository::publishSecret.name} property set")
}
return@onlyIf true
}
onlyIf { _ ->
if (SNAPSHOT_REGEX.containsMatchIn(publication.version)) {
logWarn("SNAPSHOT version can't be published to {}", repository.name)
return@onlyIf false
} else {
return@onlyIf true
}
}
onlyIf {
parseExtendedPluginProperties()
checkThatPluginIdsAreUnique()
validateArtifacts()
alreadyPublishedPlugins.forEach { logWarn("Plugin {} has been already published", it.id) }
return@onlyIf notPublishedPlugins.isNotEmpty()
}
}
private fun parseExtendedPluginProperties() {
publication.artifacts.filter { it.classifier.isNullOrEmpty() }.forEach forEachArtifact@{ artifact ->
project.autoFileTree(artifact.file)
.include("META-INF/gradle-plugins/*.properties")
.forEach forEachPluginProps@{ pluginPropsFile ->
val pluginId = pluginPropsFile.nameWithoutExtension
val pluginProps = loadProperties(pluginPropsFile)
if ("true" == pluginProps[IS_HIDDEN_DESCRIPTOR_KEY]) return@forEachPluginProps
val pluginInfo = repository.plugins.firstOrNull { it.id == pluginId }
?: repository.plugins.createWithOptionalUniqueSuffix(pluginId) { it.id = pluginId }
if (pluginInfo.displayName.isNullOrEmpty()) {
pluginProps.getProperty(DISPLAY_NAME_PLUGIN_DESCRIPTOR_KEY).nullIfEmpty()?.let { pluginInfo.displayName = it }
}
if (pluginInfo.description.isNullOrEmpty()) {
pluginInfo.description = listOf(
pluginProps.getProperty(DESCRIPTION_PLUGIN_DESCRIPTOR_KEY),
pluginProps.getProperty(MIN_GRADLE_VERSION_PLUGIN_DESCRIPTOR_KEY)?.let { "Min Gradle version: $it." },
pluginProps.getProperty(MAX_GRADLE_VERSION_PLUGIN_DESCRIPTOR_KEY)?.let { "Max Gradle version: $it." }
)
.asSequence()
.filterNotNull()
.map(String::trim)
.filter(String::isNotEmpty)
.joinToString(" ")
}
if (pluginInfo.websiteUrl.isNullOrEmpty()) {
pluginProps.getProperty(WEBSITE_PLUGIN_DESCRIPTOR_KEY).nullIfEmpty()?.let { pluginInfo.websiteUrl = it }
}
pluginProps.getProperty(TAGS_PLUGIN_DESCRIPTOR_KEY).default().splitToSequence(',', ';')
.map(String::trim)
.filter(String::isNotEmpty)
.forEach { pluginInfo.tags.add(it) }
}
}
}
private fun checkThatPluginIdsAreUnique() {
repository.plugins.groupBy(PluginInfo::id).forEach { id, infos ->
if (2 <= infos.size) {
throw IllegalStateException("There are ${infos.size} plugins with ID $id")
}
}
}
private fun validateArtifacts() {
publication.artifacts.filter { it.classifier.isNullOrEmpty() }.forEach forEachArtifact@{ artifact ->
val mappings = buildMap {
project.autoFileTree(artifact.file)
.include("META-INF/gradle-plugins/*.properties")
.visitFiles {
val pluginId = it.nameWithoutExtension
val pluginProps = loadProperties(it.open())
val implementationClassName = pluginProps.getProperty(IMPLEMENTATION_CLASS_PLUGIN_DESCRIPTOR_KEY).nullIfEmpty()
?: throw IllegalStateException("$IMPLEMENTATION_CLASS_PLUGIN_DESCRIPTOR_KEY property can't be found in ${it.relativePath}")
put(pluginId, implementationClassName)
}
}
val allClassNames = buildSet {
project.autoFileTree(artifact.file).include("**/*.class").visitFiles {
add(resourceNameToClassName(it.relativePath.toString()))
}
}
mappings.forEach { pluginId, implementationClassName ->
if (implementationClassName !in allClassNames) {
throw IllegalStateException("Implementation class $implementationClassName for plugin $pluginId can't be found in ${artifact.file}")
}
}
}
}
private val buildMetadata: BuildMetadata = BuildMetadata(GradleVersion.current().version)
private val pomUrl: String? by lazy { pomDocument.rootElement.getChild("url", POM_NAMESPACE)?.textTrim.nullIfEmpty() }
private val pomScmUrl: String? by lazy { pomDocument.rootElement.getChild("scm", POM_NAMESPACE)?.getChild("url", POM_NAMESPACE)?.textTrim.nullIfEmpty() }
private val mavenCoordinates: PublishMavenCoordinates by lazy { PublishMavenCoordinates(publication.groupId, publication.artifactId, publication.version) }
private val publishArtifacts: Map by lazy {
buildMap {
publication.artifacts.forEach { artifact ->
val type = ArtifactType.find(artifact.extension, artifact.classifier) ?: return@forEach
val hash: String = artifact.file.inputStream().use { Hasher.hash(it) }
put(PublishArtifact(type.name, hash), artifact.file)
}
run {
val pomFile = pomFile
val hash: String = pomFile.inputStream().use { sha256(it) }
put(PublishArtifact(ArtifactType.POM.name, hash), pomFile)
}
}
}
@TaskAction
protected fun doPublish() {
val publishResponses = mutableListOf()
notPublishedPlugins.forEach { plugin ->
logLifecycle("Publishing plugin {} version {}", plugin.id, publication.version)
val request = PublishNewVersionRequest().also {
it.buildMetadata = buildMetadata
it.pluginId = plugin.id ?: throw IllegalStateException("Plugin ID is not set for plugin ${plugin.id}")
it.pluginVersion = publication.version
it.displayName = plugin.displayName?.trim().nullIfEmpty() ?: plugin.id
it.description = plugin.description?.trim().nullIfEmpty() ?: plugin.id
it.tags = plugin.tags.map(String::toLowerCase)
it.webSite = plugin.websiteUrl.nullIfEmpty() ?: repository.websiteUrl.nullIfEmpty() ?: pomUrl ?: throw IllegalStateException("Website URL is not set for plugin ${plugin.id}")
it.vcsUrl = plugin.vcsUrl.nullIfEmpty() ?: repository.vcsUrl.nullIfEmpty() ?: pomScmUrl ?: throw IllegalStateException("VCS URL is not set for plugin ${plugin.id}")
it.mavenCoordinates = mavenCoordinates
it.artifacts = publishArtifacts.keys.toList()
it.webSite = it.webSite.replace("\${pluginId}", it.pluginId)
it.vcsUrl = it.vcsUrl.replace("\${pluginId}", it.pluginId)
}
val response = retryIO { sendGradlePortalRequest(request) }
publishResponses.add(response)
}
if (publishResponses.isEmpty()) {
logWarn("No plugins were published")
return
}
run {
val uploadURLs: Map = publishResponses.first().publishTo
publishArtifacts.forEach { publishArtifact, file ->
val uploadURL = uploadURLs[publishArtifact.hash]
if (uploadURL == null) {
logWarn("Skipping upload of artifact {} as it has been previously uploaded", project.rootProject.relativePath(file))
return@forEach
}
logLifecycle("Uploading artifact {}", project.rootProject.relativePath(file))
logInfo("Uploading artifact {} to {}", project.rootProject.relativePath(file), uploadURL)
retryIO { Uploader.putFile(file, uploadURL) }
}
}
publishResponses.forEach { publishResponse ->
val activateRequest = publishResponse.nextRequest
logLifecycle("Activating plugin {} version {}", activateRequest.pluginId, activateRequest.version)
retryIO { sendGradlePortalRequest(activateRequest) }
}
}
private fun sendGradlePortalRequest(request: ClientPostRequest): Response {
val baseURI = URI(
getProperty("gradle.portal.url").nullIfEmpty()
?: project.findProperty("gradle.portal.url").unwrapProviders()?.toString().nullIfEmpty()
?: "https://plugins.gradle.org"
)
if (isInfoLogEnabled) {
logInfo("Requesting POST {}: {}", baseURI.resolve(request.requestProtocolURL()), request.postJsonString)
}
val client = OAuthHttpClient(baseURI.toString(), repository.publishKey, repository.publishSecret)
val response: Response? = client.send(request)
if (isInfoLogEnabled) {
logInfo("Response: {}", response?.convertToJsonString())
}
if (response == null) {
throw PublishingToGradlePluginPortalException("Did not get a response from server")
} else if (response.hasFailed()) {
throw PublishingToGradlePluginPortalException(buildString {
append("Request failed")
if (!response.errorMessage.isNullOrEmpty()) {
append(". Server responded with: ").append(response.errorMessage)
}
})
}
response.errorMessage.nullIfEmpty()?.let { logError("{}", it) }
when (response) {
is PublishNewVersionResponse -> response.warningMessage.nullIfEmpty()?.let { logWarn("{}", it) }
is PublishActivateResponse -> response.successMessage.nullIfEmpty()?.let { logLifecycle("{}", it) }
}
return response
}
}