Skip to content

Commit

Permalink
Don't share state via NexusRepository
Browse files Browse the repository at this point in the history
- Remove stagingProfileId from close/release tasks as it is not needed
- Wire stagingRepositoryId for close/release task in plugin
- Remove mutable state from NexusRepository
- Rename CLI option to --staging-repository-id to make it more idiomatic
  • Loading branch information
marcphilipp committed Jan 11, 2020
1 parent 084a51a commit 6ce5c2b
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 168 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,7 @@ class NexusPublishPluginTests {
//and
stubCloseStagingRepoRequestWithSubsequentQueryAboutItsState(server, OVERRIDDEN_STAGED_REPOSITORY_ID)

val result = run("closeSonatypeStagingRepository", "--stagingRepositoryId=$OVERRIDDEN_STAGED_REPOSITORY_ID")
val result = run("closeSonatypeStagingRepository", "--staging-repository-id=$OVERRIDDEN_STAGED_REPOSITORY_ID")

assertSuccess(result, ":closeSonatypeStagingRepository")
assertCloseOfStagingRepo(server, OVERRIDDEN_STAGED_REPOSITORY_ID)
Expand All @@ -719,7 +719,7 @@ class NexusPublishPluginTests {
//and
stubReleaseStagingRepoRequestWithSubsequentQueryAboutItsState(server, OVERRIDDEN_STAGED_REPOSITORY_ID)

val result = run("releaseSonatypeStagingRepository", "--stagingRepositoryId=$OVERRIDDEN_STAGED_REPOSITORY_ID")
val result = run("releaseSonatypeStagingRepository", "--staging-repository-id=$OVERRIDDEN_STAGED_REPOSITORY_ID")

assertSuccess(result, ":releaseSonatypeStagingRepository")
assertReleaseOfStagingRepo(server, OVERRIDDEN_STAGED_REPOSITORY_ID)
Expand Down Expand Up @@ -762,36 +762,6 @@ class NexusPublishPluginTests {
assertGetStagingProfile(server, 1)
}

@Test
internal fun `close task should resolve stagingProfileId if not provided and keep it for release task`(@Wiremock server: WireMockServer) {
gradleRunner.withDebug(true)

writeDefaultSingleProjectConfiguration()
//and
buildGradle.append("""
nexusPublishing {
repositories {
sonatype {
nexusUrl = uri('${server.baseUrl()}')
//No staging profile defined
}
}
}
""")
//and
stubGetStagingProfilesForOneProfileIdGivenId(server, STAGING_PROFILE_ID)
stubCreateStagingRepoRequest(server, "/staging/profiles/$STAGING_PROFILE_ID/start", STAGED_REPOSITORY_ID)
stubCloseStagingRepoRequestWithSubsequentQueryAboutItsState(server)
stubReleaseStagingRepoRequestWithSubsequentQueryAboutItsState(server)

val result = run("closeSonatypeStagingRepository", "--stagingRepositoryId=$STAGED_REPOSITORY_ID", "releaseSonatypeStagingRepository")

assertSuccess(result, ":closeSonatypeStagingRepository")
assertSuccess(result, ":releaseSonatypeStagingRepository")
//and
assertGetStagingProfile(server, 1)
}

// TODO: To be used also in other tests
private fun writeDefaultSingleProjectConfiguration() {
projectDir.resolve("settings.gradle").write("""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,10 @@

package io.github.gradlenexus.publishplugin

import io.github.gradlenexus.publishplugin.internal.NexusClient
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.Optional
import org.gradle.kotlin.dsl.property
import java.time.Duration
import javax.inject.Inject
Expand All @@ -33,47 +28,23 @@ import javax.inject.Inject
abstract class AbstractNexusStagingRepositoryTask @Inject
constructor(objects: ObjectFactory, extension: NexusPublishExtension, repository: NexusRepository) : DefaultTask() {

@get:Optional
@get:Input
protected val packageGroup: Property<String> = objects.property()

@get:Internal
protected val clientTimeout: Property<Duration> = objects.property()

@get:Internal
protected val connectTimeout: Property<Duration> = objects.property()

//TODO: Expose externally as interface with getters only
@get:Nested
protected val repository: Property<NexusRepository> = objects.property()

init {
packageGroup.set(extension.packageGroup)
clientTimeout.set(extension.clientTimeout)
connectTimeout.set(extension.connectTimeout)
this.repository.set(repository)
this.onlyIf { extension.useStaging.getOrElse(false) }
@Internal
val clientTimeout = objects.property<Duration>().apply {
set(extension.clientTimeout)
}

protected fun determineAndCacheStagingProfileId(client: NexusClient): String {
//NexusRepository.stagingProfileId is already finalized by Gradle at a time tasks are executed - workaround with non-property values is needed
var stagingProfileId = repository.get().stagingRepositoryMutableTaskConfig.orNull?.profileId
?: repository.get().stagingProfileId.orNull
if (stagingProfileId == null) {
val packageGroup = packageGroup.get()
logger.debug("No stagingProfileId set, querying for packageGroup '{}'", packageGroup)
stagingProfileId = client.findStagingProfileId(packageGroup)
?: throw GradleException("Failed to find staging profile for package group: $packageGroup")
cacheStagingProfileIdForOtherTasks(stagingProfileId)
}
return stagingProfileId
@Internal
val connectTimeout = objects.property<Duration>().apply {
set(extension.connectTimeout)
}

private fun cacheStagingProfileIdForOtherTasks(stagingProfileId: String) {
repository.get().stagingRepositoryMutableTaskConfig.get().profileId = stagingProfileId
//TODO: Expose externally as interface with getters only
@Nested
val repository = objects.property<NexusRepository>().apply {
set(repository)
}

protected fun cacheStagingRepositoryForOtherTasks(stagingRepositoryId: String) {
repository.get().stagingRepositoryMutableTaskConfig.get().repositoryId = stagingRepositoryId
init {
this.onlyIf { extension.useStaging.getOrElse(false) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ package io.github.gradlenexus.publishplugin

import io.github.gradlenexus.publishplugin.internal.NexusClient
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.options.Option
import org.gradle.kotlin.dsl.property
Expand All @@ -30,25 +29,19 @@ open class CloseNexusStagingRepository @Inject
constructor(objects: ObjectFactory, extension: NexusPublishExtension, repository: NexusRepository) :
AbstractNexusStagingRepositoryTask(objects, extension, repository) {

@get:Nested
val stagingRepositoryConfig: Property<NexusStagingRepositoryMutableTaskConfig> = objects.property()
@Input
val stagingRepositoryId = objects.property<String>()

@Option(option = "stagingRepositoryId", description = "stagingRepositoryId to close")
@Option(option = "staging-repository-id", description = "staging repository id to close")
fun setStagingRepositoryId(stagingRepositoryId: String) {
stagingRepositoryConfig.get().repositoryId = stagingRepositoryId
}

init {
// TODO: Replace with convention() once only Gradle 5.1+ is supported
stagingRepositoryConfig.set(repository.stagingRepositoryMutableTaskConfig)
this.stagingRepositoryId.set(stagingRepositoryId)
}

@TaskAction
fun closeStagingRepo() {
val client = NexusClient(repository.get().nexusUrl.get(), repository.get().username.orNull, repository.get().password.orNull, clientTimeout.orNull, connectTimeout.orNull)
val stagingProfileId = determineAndCacheStagingProfileId(client)
logger.info("Closing staging repository with id '{}' for stagingProfileId '{}'", stagingRepositoryConfig.get().repositoryId, stagingProfileId)
client.closeStagingRepository(stagingRepositoryConfig.get().repositoryId!!) //should be checked by @Input
logger.info("Closing staging repository with id '{}'", stagingRepositoryId.get())
client.closeStagingRepository(stagingRepositoryId.get()) //should be checked by @Input
// TODO: Broken with real Nexus - waiting for effective execution is also required https://github.com/gradle-nexus/publish-plugin/issues/7
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,33 @@ package io.github.gradlenexus.publishplugin

import io.codearte.gradle.nexus.NexusStagingExtension
import io.github.gradlenexus.publishplugin.internal.NexusClient
import org.gradle.api.GradleException
import org.gradle.api.artifacts.repositories.MavenArtifactRepository
import org.gradle.api.model.ObjectFactory
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.property
import org.gradle.kotlin.dsl.the
import java.net.URI
import javax.inject.Inject

@Suppress("UnstableApiUsage")
open class InitializeNexusStagingRepository @Inject
constructor(objects: ObjectFactory, extension: NexusPublishExtension, repository: NexusRepository, private val serverUrlToStagingRepoUrl: MutableMap<URI, URI>) :
AbstractNexusStagingRepositoryTask(objects, extension, repository) {
constructor(
objects: ObjectFactory,
extension: NexusPublishExtension,
repository: NexusRepository,
private val serverUrlToStagingRepoUrl: MutableMap<URI, URI>,
private val stagingRepositoryId: (String) -> Unit
) : AbstractNexusStagingRepositoryTask(objects, extension, repository) {

@Optional
@Input
val packageGroup = objects.property<String>().apply {
set(extension.packageGroup)
}

@TaskAction
fun createStagingRepoAndReplacePublishingRepoUrl() {
Expand All @@ -40,10 +55,10 @@ constructor(objects: ObjectFactory, extension: NexusPublishExtension, repository
internal fun createStagingRepo(): URI {
return serverUrlToStagingRepoUrl.computeIfAbsent(repository.get().nexusUrl.get()) { serverUrl ->
val client = NexusClient(serverUrl, repository.get().username.orNull, repository.get().password.orNull, clientTimeout.orNull, connectTimeout.orNull)
val stagingProfileId = determineAndCacheStagingProfileId(client)
val stagingProfileId = determineStagingProfileId(client)
logger.info("Creating staging repository for stagingProfileId '{}'", stagingProfileId)
val stagingRepositoryIdAsString = client.createStagingRepository(stagingProfileId)
cacheStagingRepositoryForOtherTasks(stagingRepositoryIdAsString)
stagingRepositoryId.invoke(stagingRepositoryIdAsString)

//TODO: To be removed in next iteration
project.rootProject.plugins.withId("io.codearte.nexus-staging") {
Expand All @@ -61,6 +76,17 @@ constructor(objects: ObjectFactory, extension: NexusPublishExtension, repository
}
}

private fun determineStagingProfileId(client: NexusClient): String {
var stagingProfileId = repository.get().stagingProfileId.orNull
if (stagingProfileId == null) {
val packageGroup = packageGroup.get()
logger.debug("No stagingProfileId set, querying for packageGroup '{}'", packageGroup)
stagingProfileId = client.findStagingProfileId(packageGroup)
?: throw GradleException("Failed to find staging profile for package group: $packageGroup")
}
return stagingProfileId
}

private fun replacePublishingRepoUrl(url: URI) {
val publishing = project.the<PublishingExtension>()
val repository = publishing.repositories.getByName(repository.get().name) as MavenArtifactRepository
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,9 @@ package io.github.gradlenexus.publishplugin

import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.provider.Property
import org.gradle.kotlin.dsl.container
import org.gradle.kotlin.dsl.newInstance
import org.gradle.kotlin.dsl.property

import java.time.Duration

@Suppress("UnstableApiUsage")
Expand All @@ -32,19 +30,19 @@ open class NexusPublishExtension(project: Project) {
internal const val NAME = "nexusPublishing"
}

val useStaging: Property<Boolean> = project.objects.property<Boolean>().apply {
val useStaging = project.objects.property<Boolean>().apply {
set(project.provider { !project.version.toString().endsWith("-SNAPSHOT") })
}

val packageGroup: Property<String> = project.objects.property<String>().apply {
val packageGroup = project.objects.property<String>().apply {
set(project.provider { project.group.toString() })
}

val clientTimeout: Property<Duration> = project.objects.property<Duration>().apply {
val clientTimeout = project.objects.property<Duration>().apply {
set(Duration.ofMinutes(1))
}

val connectTimeout: Property<Duration> = project.objects.property<Duration>().apply {
val connectTimeout = project.objects.property<Duration>().apply {
set(Duration.ofMinutes(1))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import org.gradle.api.publish.plugins.PublishingPlugin
import org.gradle.api.tasks.TaskProvider
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.create
import org.gradle.kotlin.dsl.property
import org.gradle.kotlin.dsl.register
import org.gradle.kotlin.dsl.the
import org.gradle.kotlin.dsl.withType
Expand All @@ -55,16 +56,23 @@ class NexusPublishPlugin : Plugin<Project> {
val extension = project.extensions.create<NexusPublishExtension>(NexusPublishExtension.NAME, project)

extension.repositories.all {
val stagingRepositoryId = project.objects.property<String>()
project.tasks.register("publishTo${capitalizedName()}") {
description = "Publishes all Maven publications produced by this project to the '${this@all.name}' Nexus repository."
group = PublishingPlugin.PUBLISH_TASK_GROUP
}
project.tasks
.register<InitializeNexusStagingRepository>("initialize${capitalizedName()}StagingRepository", project.objects, extension, this, serverUrlToStagingRepoUrl)
.register<InitializeNexusStagingRepository>("initialize${capitalizedName()}StagingRepository", project.objects, extension, this, serverUrlToStagingRepoUrl, { id: String -> stagingRepositoryId.set(id) })
project.tasks
.register<CloseNexusStagingRepository>("close${capitalizedName()}StagingRepository", project.objects, extension, this)
.configure {
this.stagingRepositoryId.set(stagingRepositoryId)
}
project.tasks
.register<ReleaseNexusStagingRepository>("release${capitalizedName()}StagingRepository", project.objects, extension, this)
.configure {
this.stagingRepositoryId.set(stagingRepositoryId)
}
}
extension.repositories.whenObjectRemoved {
project.tasks.remove(project.tasks.named("publishTo${capitalizedName()}") as Any)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,46 +17,36 @@
package io.github.gradlenexus.publishplugin

import org.gradle.api.Project
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.Optional
import org.gradle.kotlin.dsl.property
import java.net.URI
import javax.inject.Inject

@Suppress("UnstableApiUsage")
open class NexusRepository @Inject constructor(@get:Input val name: String, project: Project) {
open class NexusRepository @Inject constructor(@Input val name: String, project: Project) {

@get:Input
val nexusUrl: Property<URI> = project.objects.property()
@Input
val nexusUrl = project.objects.property<URI>()

@get:Input
val snapshotRepositoryUrl: Property<URI> = project.objects.property()
@Input
val snapshotRepositoryUrl = project.objects.property<URI>()

@get:Optional
@get:Input
val username: Property<String> = project.objects.property<String>().apply {
@Optional
@Input
val username = project.objects.property<String>().apply {
set(project.provider { project.findProperty("${name}Username") as? String })
}

@get:Optional
@get:Input
val password: Property<String> = project.objects.property<String>().apply {
@Optional
@Input
val password = project.objects.property<String>().apply {
set(project.provider { project.findProperty("${name}Password") as? String })
}

@get:Optional
@get:Input
val stagingProfileId: Property<String> = project.objects.property()

@get:Internal
val stagingRepositoryMutableTaskConfig: Property<NexusStagingRepositoryMutableTaskConfig> = project.objects.property()

init {
// TODO: Replace with convention() once only Gradle 5.1+ is supported
stagingRepositoryMutableTaskConfig.set(NexusStagingRepositoryMutableTaskConfig.empty())
}
@Optional
@Input
val stagingProfileId = project.objects.property<String>()

internal fun capitalizedName(): String {
return name.capitalize()
Expand Down
Loading

0 comments on commit 6ce5c2b

Please sign in to comment.