Skip to content

Commit

Permalink
Delay sign errors to execution time
Browse files Browse the repository at this point in the history
  • Loading branch information
natario1 committed Aug 15, 2024
1 parent 469b879 commit 7ae8216
Show file tree
Hide file tree
Showing 9 changed files with 51 additions and 49 deletions.
2 changes: 1 addition & 1 deletion deployer/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ gradlePlugin {
}

group = "io.deepmedia.tools.deployer"
version = "0.14.0-alpha2" // on change, update both docs and README
version = "0.14.0-alpha4" // on change, update both docs and README

val javadocs = tasks.register<Jar>("dokkaJavadocJar") {
dependsOn(tasks.dokkaJavadoc)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.deepmedia.tools.deployer

import io.deepmedia.tools.deployer.model.AbstractDeploySpec
import io.deepmedia.tools.deployer.model.Signing
import org.gradle.api.Project
import org.gradle.api.logging.LogLevel
import org.gradle.api.publish.maven.MavenPublication
Expand All @@ -22,7 +23,7 @@ import org.gradle.security.internal.pgp.BaseInMemoryPgpSignatoryProvider
* at execution time, all tasks use the last key-value pair which is not what we want.
*/
internal fun Project.configureSigning(
info: Pair<String, String>,
credentials: Signing.Provided,
maven: MavenPublication,
log: Logger
): Sign {
Expand All @@ -40,7 +41,7 @@ internal fun Project.configureSigning(
}

val ext = extensions.getByType(SigningExtension::class)
ext.useInMemoryPgpKeys(info.first, info.second)
ext.useInMemoryPgpKeys(credentials.key, credentials.password)
val signatory = ext.signatory
return ext.sign(maven).single().apply {
setSignatory(signatory)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ class DeployerPlugin : Plugin<Project> {
spec: AbstractDeploySpec<*>,
target: Project,
repository: MavenArtifactRepository,
signInfo: Pair<String, String>?
signCredentials: Signing.Credentials
): TaskProvider<*> {
val publishing = target.extensions.getByType(PublishingExtension::class.java)
val publication = component.maybeCreatePublication(publishing.publications, spec)
Expand All @@ -144,17 +144,20 @@ class DeployerPlugin : Plugin<Project> {
target.configureArtifacts(spec, component, publication, log)

// Configure signing if present
val sign = when (signInfo) {
null -> null
else -> target.configureSigning(signInfo, publication, log)
val signTask = when (signCredentials) {
is Signing.Provided -> target.configureSigning(signCredentials, publication, log)
else -> null
}
target.configurePom(spec, component, publication, log)

// Add maven validation, mostly for sonatype
mavenPublish.configure {
if (sign != null) dependsOn(sign)
if (signTask != null) dependsOn(signTask)
onlyIf { component.enabled.get() }
doFirst {
if (signCredentials is Signing.NotFound && signCredentials.error != null) {
error(signCredentials.error)
}
log { "Starting artifact and POM validation"}
spec.validateMavenArtifacts(target, publication.artifacts, log)
spec.validateMavenPom(publication.pom)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,18 @@ abstract class AbstractDeploySpec<A: Auth> constructor(
internal open fun registerInitializationTask(target: Project, name: String, repo: MavenArtifactRepository): TaskProvider<*>? = null
internal open fun registerFinalizationTask(target: Project, name: String, init: TaskProvider<*>?): TaskProvider<*>? = null

internal open fun readSignCredentials(target: Project): Pair<String, String>? {
if (!signing.key.isPresent && !signing.password.isPresent) return null
val key = signing.key.orNull?.resolve(target, "spec.signing.key") ?: error("Got signing password, but no key.")
val password = signing.password.orNull?.resolve(target, "spec.signing.password") ?: error("Got signing key, but no password.")
return key to password
internal open fun readSignCredentials(target: Project): Signing.Credentials {
val hasKey = signing.key.isPresent && signing.key.get().hasKey
val hasPassword = signing.password.isPresent && signing.password.get().hasKey
if (!hasKey && !hasPassword) return Signing.NotDeclared
val key = signing.key.orNull?.resolveOrNull(target.providers, target.layout)
val password = signing.password.orNull?.resolveOrNull(target.providers, target.layout)
return when {
key != null && password != null -> Signing.Provided(key, password)
key != null -> Signing.NotFound("Could not resolve signing password at ${this.name}.signing.password (${signing.password.orNull?.key}).")
password != null -> Signing.NotFound("Could not resolve signing key at ${this.name}.signing.key (${signing.key.orNull?.key}).")
else -> Signing.NotFound("Could not resolve signing key (${signing.key.orNull?.key}) and password (${signing.password.orNull?.key}) at ${this.name}.signing.")
}
}

internal open fun validateMavenArtifacts(target: Project, artifacts: MavenArtifactSet, log: Logger) = Unit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import java.util.*
import java.util.concurrent.ConcurrentHashMap

class Secret(val key: String) {
internal fun resolve(project: Project, location: String): String {
return resolve(project.providers, project.layout, location)
internal val hasKey get() = key.isNotEmpty()

internal fun resolveOrThrow(providers: ProviderFactory, layout: ProjectLayout, location: String): String {
return resolveOrNull(providers, layout) ?: error("Secret key $key (from $location) not found in environment variables nor properties.")
}
internal fun resolve(providers: ProviderFactory, layout: ProjectLayout, location: String): String {
internal fun resolveOrNull(providers: ProviderFactory, layout: ProjectLayout): String? {
if (!hasKey) return null
return findSecret(key, providers, layout)
?: error("Secret key $key (from $location) not found in environment variables nor properties.")
}
}

Expand Down Expand Up @@ -51,4 +53,5 @@ private fun File.localProperties(): Properties? {

interface SecretScope {
fun secret(key: String) = Secret(key)
fun absent() = Secret("")
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,10 @@ open class Signing @Inject constructor(objects: ObjectFactory) : SecretScope {
internal fun resolve(target: org.gradle.api.Project, spec: DeploySpec) {
// Nothing to do
}

internal sealed interface Credentials

internal class Provided(val key: String, val password: String) : Credentials
internal class NotFound(val error: String? = null) : Credentials
internal object NotDeclared : Credentials
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,15 @@ package io.deepmedia.tools.deployer.specs

import io.deepmedia.tools.deployer.Logger
import io.deepmedia.tools.deployer.dump
import io.deepmedia.tools.deployer.model.AbstractDeploySpec
import io.deepmedia.tools.deployer.model.Auth
import io.deepmedia.tools.deployer.model.DeploySpec
import io.deepmedia.tools.deployer.model.Secret
import io.deepmedia.tools.deployer.central.ossrh.OssrhInfo
import io.deepmedia.tools.deployer.central.ossrh.OssrhService
import io.deepmedia.tools.deployer.central.ossrh.OssrhServer
import io.deepmedia.tools.deployer.central.portal.CentralPortalInfo
import io.deepmedia.tools.deployer.central.portal.CentralPortalService
import io.deepmedia.tools.deployer.model.*
import io.deepmedia.tools.deployer.tasks.isDocsJar
import io.deepmedia.tools.deployer.tasks.isSourcesJar
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.artifacts.dsl.RepositoryHandler
import org.gradle.api.artifacts.repositories.MavenArtifactRepository
import org.gradle.api.file.ArchiveOperations
import org.gradle.api.file.Directory
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.FileSystemOperations
import org.gradle.api.file.ProjectLayout
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
Expand All @@ -35,7 +25,6 @@ import org.gradle.kotlin.dsl.property
import org.gradle.kotlin.dsl.register
import java.io.File
import javax.inject.Inject
import kotlin.math.abs
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.minutes
Expand Down Expand Up @@ -86,9 +75,9 @@ class CentralPortalDeploySpec internal constructor(objects: ObjectFactory, name:
}
}

override fun readSignCredentials(target: Project): Pair<String, String> {
val result = super.readSignCredentials(target) ?: error("Signing is mandatory for Central Portal deployments. Please add spec.signing.key and spec.signing.password.")
return result
override fun readSignCredentials(target: Project): Signing.Credentials = when (val result = super.readSignCredentials(target)) {
Signing.NotDeclared -> error("Signing is mandatory for Central Portal deployments. Please add spec.signing.key and spec.signing.password.")
else -> result
}

override fun validateMavenArtifacts(target: Project, artifacts: MavenArtifactSet, log: Logger) {
Expand Down Expand Up @@ -165,8 +154,8 @@ internal abstract class CentralPortalInitializationTask @Inject constructor(
@TaskAction
fun execute() {
val auth = auth.get()
val username = auth.user.get().resolve(providers, layout, "spec.auth.user")
val password = auth.password.get().resolve(providers, layout, "spec.auth.password")
val username = auth.user.get().resolveOrThrow(providers, layout, "spec.auth.user")
val password = auth.password.get().resolveOrThrow(providers, layout, "spec.auth.password")
val info = CentralPortalInfo(username, password, allowSync.get())
val storageRepository = File(storageRepository.get())
storageRepository.delete() // Delete any stale data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import org.gradle.api.artifacts.dsl.RepositoryHandler
import org.gradle.api.artifacts.repositories.MavenArtifactRepository
import org.gradle.api.artifacts.repositories.PasswordCredentials
import org.gradle.api.file.ProjectLayout
import org.gradle.api.internal.AbstractTask
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.provider.ProviderFactory
Expand Down Expand Up @@ -86,7 +85,7 @@ internal open class GithubInitializationTask @Inject constructor(
@TaskAction fun execute() {
val credentials = credentials.get()
val auth = auth.get()
credentials.username = auth.user.get().resolve(providers, layout, "spec.auth.user")
credentials.password = auth.token.get().resolve(providers, layout, "spec.auth.token")
credentials.username = auth.user.get().resolveOrThrow(providers, layout, "spec.auth.user")
credentials.password = auth.token.get().resolveOrThrow(providers, layout, "spec.auth.token")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@ package io.deepmedia.tools.deployer.specs

import io.deepmedia.tools.deployer.Logger
import io.deepmedia.tools.deployer.dump
import io.deepmedia.tools.deployer.model.AbstractDeploySpec
import io.deepmedia.tools.deployer.model.Auth
import io.deepmedia.tools.deployer.model.DeploySpec
import io.deepmedia.tools.deployer.model.Secret
import io.deepmedia.tools.deployer.central.ossrh.OssrhInfo
import io.deepmedia.tools.deployer.central.ossrh.OssrhService
import io.deepmedia.tools.deployer.central.ossrh.OssrhServer
import io.deepmedia.tools.deployer.model.*
import io.deepmedia.tools.deployer.tasks.isDocsJar
import io.deepmedia.tools.deployer.tasks.isSourcesJar
import org.gradle.api.DefaultTask
Expand Down Expand Up @@ -109,12 +106,9 @@ class SonatypeDeploySpec internal constructor(objects: ObjectFactory, name: Stri
}
}

override fun readSignCredentials(target: Project): Pair<String, String>? {
val result = super.readSignCredentials(target)
if (result == null && maySyncToMavenCentral.get()) {
error("Signing is mandatory for OSSRH/Maven Central deployments. Please add spec.signing.key and spec.signing.password.")
}
return result
override fun readSignCredentials(target: Project): Signing.Credentials = when (val result = super.readSignCredentials(target)) {
Signing.NotDeclared -> error("Signing is mandatory for OSSRH/Maven Central deployments. Please add spec.signing.key and spec.signing.password.")
else -> result
}

/*override fun provideDefaultDocsForComponent(target: Project, component: Component): Any {
Expand Down Expand Up @@ -212,8 +206,8 @@ internal abstract class SonatypeInitializationTask @Inject constructor(
fun execute() {
val repo = repo.get()
val auth = auth.get()
val username = auth.user.get().resolve(providers, layout, "spec.auth.user")
val password = auth.password.get().resolve(providers, layout, "spec.auth.password")
val username = auth.user.get().resolveOrThrow(providers, layout, "spec.auth.user")
val password = auth.password.get().resolveOrThrow(providers, layout, "spec.auth.password")
repo.credentials.username = username
repo.credentials.password = password
if (sync.get()) {
Expand Down

0 comments on commit 7ae8216

Please sign in to comment.