Skip to content

Commit

Permalink
Partially refactor to use more idiomatic Gradle (#241)
Browse files Browse the repository at this point in the history
* Set NexusRepository defaults in plugin

* Use managed properties in NexusRepository

* Set NexusPublishExtension defaults in plugin

* Use managed properties in NexusPublishExtension

* Remove usage of Project from NexusPublishExtension

* Set defaults for TransitionCheckOptions in plugin

* Use managed properties in TransitionCheckOptions

* Set AbstractNexusStagingRepositoryTask defaults in plugin

* Set AbstractTransitionNexusStagingRepositoryTask defaults in plugin

* Use managed properties in AbstractNexusStagingRepositoryTask

* Use managed properties in AbstractTransitionNexusStagingRepositoryTask

* Avoid task configuration
  • Loading branch information
3flex authored Jul 7, 2023
1 parent 2c8b3c1 commit 5850613
Show file tree
Hide file tree
Showing 12 changed files with 94 additions and 90 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package io.github.gradlenexus.publishplugin

import org.gradle.api.DefaultTask
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
Expand All @@ -26,32 +27,25 @@ import java.time.Duration
import javax.inject.Inject

abstract class AbstractNexusStagingRepositoryTask @Inject
constructor(objects: ObjectFactory, extension: NexusPublishExtension, repository: NexusRepository) : DefaultTask() {
constructor(objects: ObjectFactory, repository: NexusRepository) : DefaultTask() {

@Internal
val clientTimeout = objects.property<Duration>().apply {
set(extension.clientTimeout)
}
@get:Internal
abstract val clientTimeout: Property<Duration>

@Internal
val connectTimeout = objects.property<Duration>().apply {
set(extension.connectTimeout)
}
@get:Internal
abstract val connectTimeout: Property<Duration>

// TODO: Expose externally as interface with getters only
@Nested
val repository = objects.property<NexusRepository>().apply {
set(repository)
}

@Input
val repositoryDescription = objects.property<String>().apply {
set(extension.repositoryDescription)
}
@get:Input
abstract val repositoryDescription: Property<String>

private val useStaging = objects.property<Boolean>().apply {
set(extension.useStaging)
}
@get:Internal
internal abstract val useStaging: Property<Boolean>

init {
this.onlyIf { useStaging.getOrElse(false) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import io.github.gradlenexus.publishplugin.internal.StagingRepository
import io.github.gradlenexus.publishplugin.internal.StagingRepositoryTransitioner
import org.gradle.api.Action
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal
Expand All @@ -31,10 +32,9 @@ import org.gradle.kotlin.dsl.property

abstract class AbstractTransitionNexusStagingRepositoryTask(
objects: ObjectFactory,
extension: NexusPublishExtension,
repository: NexusRepository,
registry: Provider<InvalidatingStagingRepositoryDescriptorRegistry>
) : AbstractNexusStagingRepositoryTask(objects, extension, repository) {
) : AbstractNexusStagingRepositoryTask(objects, repository) {

@Input
val stagingRepositoryId = objects.property<String>().apply {
Expand All @@ -45,10 +45,8 @@ abstract class AbstractTransitionNexusStagingRepositoryTask(
)
}

@Internal
val transitionCheckOptions = project.objects.property<TransitionCheckOptions>().apply {
set(extension.transitionCheckOptions)
}
@get:Internal
abstract val transitionCheckOptions: Property<TransitionCheckOptions>

fun transitionCheckOptions(action: Action<in TransitionCheckOptions>) = action.execute(transitionCheckOptions.get())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,11 @@ import org.gradle.api.provider.Provider
import org.gradle.api.tasks.options.Option
import javax.inject.Inject

open class CloseNexusStagingRepository @Inject constructor(
abstract class CloseNexusStagingRepository @Inject constructor(
objects: ObjectFactory,
extension: NexusPublishExtension,
repository: NexusRepository,
registry: Provider<InvalidatingStagingRepositoryDescriptorRegistry>
) : AbstractTransitionNexusStagingRepositoryTask(objects, extension, repository, registry) {
) : AbstractTransitionNexusStagingRepositoryTask(objects, repository, registry) {

@Option(option = "staging-repository-id", description = "staging repository id to close")
fun setStagingRepositoryId(stagingRepositoryId: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ import org.gradle.kotlin.dsl.property
import javax.inject.Inject

@Incubating
open class FindStagingRepository @Inject constructor(
abstract class FindStagingRepository @Inject constructor(
objects: ObjectFactory,
extension: NexusPublishExtension,
repository: NexusRepository,
private val registry: Provider<InvalidatingStagingRepositoryDescriptorRegistry>
) : AbstractNexusStagingRepositoryTask(objects, extension, repository) {
) : AbstractNexusStagingRepositoryTask(objects, repository) {

@Optional
@Input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.property
import javax.inject.Inject

open class InitializeNexusStagingRepository @Inject constructor(
abstract class InitializeNexusStagingRepository @Inject constructor(
objects: ObjectFactory,
extension: NexusPublishExtension,
repository: NexusRepository,
private val registry: Provider<InvalidatingStagingRepositoryDescriptorRegistry>
) : AbstractNexusStagingRepositoryTask(objects, extension, repository) {
) : AbstractNexusStagingRepositoryTask(objects, repository) {

@Optional
@Input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,48 +18,45 @@ package io.github.gradlenexus.publishplugin

import org.gradle.api.Action
import org.gradle.api.NamedDomainObjectFactory
import org.gradle.api.Project
import org.gradle.kotlin.dsl.container
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Nested
import org.gradle.kotlin.dsl.domainObjectContainer
import org.gradle.kotlin.dsl.newInstance
import org.gradle.kotlin.dsl.property
import java.time.Duration
import javax.inject.Inject

open class NexusPublishExtension(project: Project) {
abstract class NexusPublishExtension @Inject constructor(objects: ObjectFactory) {

companion object {
internal const val NAME = "nexusPublishing"
}

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

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

val repositoryDescription = project.objects.property<String>().apply {
set(project.provider { project.run { "$group:$name:$version" } })
}
abstract val repositoryDescription: Property<String>

// staging repository initialization can take a few minutes on Sonatype Nexus
val clientTimeout = project.objects.property<Duration>().value(Duration.ofMinutes(5))
abstract val clientTimeout: Property<Duration>

val connectTimeout = project.objects.property<Duration>().value(Duration.ofMinutes(5))
abstract val connectTimeout: Property<Duration>

val transitionCheckOptions = project.objects.property<TransitionCheckOptions>().value(project.objects.newInstance(TransitionCheckOptions::class))
@get:Nested
abstract val transitionCheckOptions: TransitionCheckOptions

fun transitionCheckOptions(action: Action<in TransitionCheckOptions>) = action.execute(transitionCheckOptions.get())
fun transitionCheckOptions(action: Action<in TransitionCheckOptions>) = action.execute(transitionCheckOptions)

val repositories: NexusRepositoryContainer = project.objects.newInstance(
val repositories: NexusRepositoryContainer = objects.newInstance(
DefaultNexusRepositoryContainer::class,
// `project.container(NexusRepository::class) { name -> ... }`,
// `objects.domainObjectContainer(NexusRepository::class) { name -> ... }`,
// but in Kotlin 1.3 "New Inference" is not implemented yet, so we have to be explicit.
// https://kotlinlang.org/docs/whatsnew14.html#new-more-powerful-type-inference-algorithm
project.container(
objects.domainObjectContainer(
NexusRepository::class,
NamedDomainObjectFactory { name ->
project.objects.newInstance(NexusRepository::class, name, project)
objects.newInstance(NexusRepository::class, name)
}
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import org.gradle.kotlin.dsl.register
import org.gradle.kotlin.dsl.typeOf
import org.gradle.kotlin.dsl.withType
import org.gradle.util.GradleVersion
import java.time.Duration

class NexusPublishPlugin : Plugin<Project> {

Expand All @@ -54,11 +55,24 @@ class NexusPublishPlugin : Plugin<Project> {
}

val registry = createRegistry(project)
val extension = project.extensions.create<NexusPublishExtension>(NexusPublishExtension.NAME, project)
val extension = project.extensions.create<NexusPublishExtension>(NexusPublishExtension.NAME)
configureExtension(project, extension)
configureNexusTasks(project, extension, registry)
configurePublishingForAllProjects(project, extension, registry)
}

private fun configureExtension(project: Project, extension: NexusPublishExtension) {
with(extension) {
useStaging.convention(project.provider { !project.version.toString().endsWith("-SNAPSHOT") })
packageGroup.convention(project.provider { project.group.toString() })
repositoryDescription.convention(project.provider { project.run { "$group:$name:$version" } })
clientTimeout.convention(Duration.ofMinutes(5))
connectTimeout.convention(Duration.ofMinutes(5))
transitionCheckOptions.maxRetries.convention(60)
transitionCheckOptions.delayBetween.convention(Duration.ofSeconds(10))
}
}

private fun createRegistry(rootProject: Project): Provider<InvalidatingStagingRepositoryDescriptorRegistry> {
if (GradleVersion.current() >= GradleVersion.version("6.1")) {
return rootProject.gradle.sharedServices.registerIfAbsent("stagingRepositoryUrlRegistry", StagingRepositoryDescriptorRegistryBuildService::class.java) {}.map { it.registry }
Expand All @@ -68,7 +82,20 @@ class NexusPublishPlugin : Plugin<Project> {
}

private fun configureNexusTasks(rootProject: Project, extension: NexusPublishExtension, registry: Provider<InvalidatingStagingRepositoryDescriptorRegistry>) {
rootProject.tasks.withType(AbstractNexusStagingRepositoryTask::class.java).configureEach {
clientTimeout.convention(extension.clientTimeout)
connectTimeout.convention(extension.connectTimeout)
repositoryDescription.convention(extension.repositoryDescription)
useStaging.convention(extension.useStaging)
}
rootProject.tasks.withType(AbstractTransitionNexusStagingRepositoryTask::class.java).configureEach {
transitionCheckOptions.convention(extension.transitionCheckOptions)
}
extension.repositories.all {
username.convention(rootProject.provider { rootProject.findProperty("${name}Username") as? String })
password.convention(rootProject.provider { rootProject.findProperty("${name}Password") as? String })
publicationType.convention(PublicationType.MAVEN)

val repository = this
val retrieveStagingProfileTask = rootProject.tasks.register<RetrieveStagingProfile>("retrieve${capitalizedName}StagingProfile", rootProject.objects, extension, repository)
val initializeTask = rootProject.tasks.register<InitializeNexusStagingRepository>(
Expand All @@ -91,14 +118,12 @@ class NexusPublishPlugin : Plugin<Project> {
val closeTask = rootProject.tasks.register<CloseNexusStagingRepository>(
"close${capitalizedName}StagingRepository",
rootProject.objects,
extension,
repository,
registry
)
val releaseTask = rootProject.tasks.register<ReleaseNexusStagingRepository>(
"release${capitalizedName}StagingRepository",
rootProject.objects,
extension,
repository,
registry
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package io.github.gradlenexus.publishplugin

import org.gradle.api.Action
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.artifacts.repositories.IvyPatternRepositoryLayout
import org.gradle.api.provider.Property
import org.gradle.api.publish.Publication
Expand All @@ -29,45 +28,40 @@ import org.gradle.api.publish.maven.tasks.PublishToMavenRepository
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
import kotlin.reflect.KClass

open class NexusRepository @Inject constructor(@Input val name: String, project: Project) {
abstract class NexusRepository @Inject constructor(@Input val name: String) {

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

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

@Input
val publicationType: Property<PublicationType> = project.objects.property<PublicationType>().convention(PublicationType.MAVEN)
@get:Input
abstract val publicationType: Property<PublicationType>

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

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

@Internal
val allowInsecureProtocol = project.objects.property<Boolean>()
@get:Internal
abstract val allowInsecureProtocol: Property<Boolean>

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

@get:Internal
internal val capitalizedName by lazy { name.capitalize() }

@Optional
@Input
val ivyPatternLayout: Property<Action<IvyPatternRepositoryLayout>> = project.objects.property<Action<IvyPatternRepositoryLayout>>()
@get:Optional
@get:Input
abstract val ivyPatternLayout: Property<Action<IvyPatternRepositoryLayout>>
fun ivyPatternLayout(action: Action<IvyPatternRepositoryLayout>) {
ivyPatternLayout.set(action)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,11 @@ import org.gradle.api.provider.Provider
import org.gradle.api.tasks.options.Option
import javax.inject.Inject

open class ReleaseNexusStagingRepository @Inject constructor(
abstract class ReleaseNexusStagingRepository @Inject constructor(
objects: ObjectFactory,
extension: NexusPublishExtension,
repository: NexusRepository,
registry: Provider<InvalidatingStagingRepositoryDescriptorRegistry>
) : AbstractTransitionNexusStagingRepositoryTask(objects, extension, repository, registry) {
) : AbstractTransitionNexusStagingRepositoryTask(objects, repository, registry) {

@Option(option = "staging-repository-id", description = "staging repository id to release")
fun setStagingRepositoryId(stagingRepositoryId: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ import javax.inject.Inject
* Diagnostic task for retrieving the [NexusRepository.stagingProfileId] for the [packageGroup] from the provided [NexusRepository] and logging it
*/
@Incubating
open class RetrieveStagingProfile @Inject constructor(
abstract class RetrieveStagingProfile @Inject constructor(
objects: ObjectFactory,
extension: NexusPublishExtension,
repository: NexusRepository
) : AbstractNexusStagingRepositoryTask(objects, extension, repository) {
) : AbstractNexusStagingRepositoryTask(objects, repository) {

@Input
val packageGroup = objects.property<String>().apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@

package io.github.gradlenexus.publishplugin

import org.gradle.api.model.ObjectFactory
import org.gradle.kotlin.dsl.property
import org.gradle.api.provider.Property
import java.time.Duration
import javax.inject.Inject

open class TransitionCheckOptions @Inject constructor(objects: ObjectFactory) {
interface TransitionCheckOptions {

val maxRetries = objects.property<Int>().value(60)
val maxRetries: Property<Int>

val delayBetween = objects.property<Duration>().value(Duration.ofSeconds(10))
val delayBetween: Property<Duration>
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class TaskOrchestrationTest {
// given
initSingleProjectWithDefaultConfiguration()
project.extensions.configure<NexusPublishExtension> {
repositories.add(NexusRepository("myNexus", project))
repositories.create("myNexus")
}
// expect
assertGivenTaskMustNotRunAfterAnother(transitioningTaskName, "publishToMyNexus")
Expand Down

0 comments on commit 5850613

Please sign in to comment.