Skip to content

Commit

Permalink
Fix artifact signing and multi-spec conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
natario1 committed Aug 4, 2024
1 parent 706c3d0 commit a09b67c
Show file tree
Hide file tree
Showing 12 changed files with 264 additions and 155 deletions.
1 change: 0 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions
# Renaming ? Change the README badge.
name: Build
on:
push:
Expand Down
32 changes: 13 additions & 19 deletions deployer/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,23 @@
plugins {
`kotlin-dsl`
`java-gradle-plugin`
id("io.deepmedia.tools.deployer") version "0.13.0-rc1"
id("io.deepmedia.tools.deployer") version "0.14.0-alpha14"
kotlin("plugin.serialization") version "1.9.23"
id("org.jetbrains.dokka") version "1.9.20"
}

dependencies {
compileOnly("com.android.tools.build:gradle:8.0.2")
compileOnly("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.23")

api("org.jetbrains.dokka:dokka-gradle-plugin:1.8.20")
// api("org.jetbrains.dokka:dokka-gradle-plugin:1.8.20")

implementation("io.ktor:ktor-client-core:2.3.11")
implementation("io.ktor:ktor-client-cio:2.3.11")
implementation("io.ktor:ktor-client-content-negotiation:2.3.11")
implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.11")
}

// Gradle 7.X has embedded kotlin version 1.6, but kotlin-dsl plugins are compiled with 1.4 for compatibility with older
// gradle versions (I guess). 1.4 is very old and generates a warning, so let's bump to the embedded kotlin version.
// https://handstandsam.com/2022/04/13/using-the-kotlin-dsl-gradle-plugin-forces-kotlin-1-4-compatibility/
// https://github.com/gradle/gradle/blob/7a69f2f3d791044b946040cd43097ce57f430ca8/subprojects/kotlin-dsl-plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslCompilerPlugins.kt#L48-L49
/* afterEvaluate {
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions {
val embedded = embeddedKotlinVersion.split(".").take(2).joinToString(".")
apiVersion = embedded
languageVersion = embedded
}
}
} */

// To publish the plugin itself...

gradlePlugin {
Expand All @@ -46,17 +33,24 @@ gradlePlugin {
}

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

val javadocs = tasks.register<Jar>("dokkaJavadocJar") {
dependsOn(tasks.dokkaJavadoc)
from(tasks.dokkaJavadoc.flatMap { it.outputDirectory })
archiveClassifier.set("javadoc")
}

deployer {
verbose = true

content {
gradlePluginComponents {
kotlinSources()
emptyDocs()
docs(javadocs)
}
}

projectInfo {
description = "A lightweight, handy tool for publishing maven / Gradle packages to different kinds of repositories."
url = "https://github.com/deepmedia/MavenDeployer"
Expand All @@ -72,7 +66,7 @@ deployer {

// use "deployLocal" to deploy to local maven repository
localSpec {
// directory.set(layout.buildDirectory.get().dir("inspect"))
directory.set(rootProject.layout.buildDirectory.get().dir("inspect"))
}

// use "deployNexus" to deploy to OSSRH / maven central
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,35 @@ package io.deepmedia.tools.deployer
import io.deepmedia.tools.deployer.model.AbstractDeploySpec
import io.deepmedia.tools.deployer.model.Artifacts
import io.deepmedia.tools.deployer.model.Component
import io.deepmedia.tools.deployer.model.DeploySpec
import io.deepmedia.tools.deployer.tasks.wrapped
import org.gradle.api.Project
import org.gradle.api.component.SoftwareComponent
import org.gradle.api.provider.Provider
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenArtifactSet
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.publish.maven.internal.publication.DefaultMavenPublication
import org.gradle.api.publish.maven.internal.publication.MavenPublicationInternal
import org.gradle.kotlin.dsl.get

private fun MavenPublication.addArtifacts(log: Logger, artifacts: Artifacts) {
private fun MavenPublication.addArtifacts(log: Logger, artifacts: Artifacts, project: Project, spec: DeploySpec, component: Component, groupId: String) {
var suffix = 0
artifacts.entries.configureEach {
log { "configureArtifacts: adding $artifact to MavenPublication $name" }
addArtifact(this)
addArtifact(log, this, project, spec, component, artifactId = "${groupId}$suffix")
suffix++
}
}

private fun MavenPublication.addArtifact(artifact: Artifacts.Entry) {
val res = artifact(artifact.artifact)
if (artifact.builtBy != null) {
res.builtBy(artifact.builtBy)
private fun MavenPublication.addArtifact(log: Logger, entry: Artifacts.Entry, project: Project, spec: DeploySpec, component: Component, artifactId: String) {
val resolvedEntry = when (entry) {
is Artifacts.Entry.Promise -> entry.resolve(project)
is Artifacts.Entry.Resolved -> entry
}
val wrappedEntry = resolvedEntry.wrapped(project, log, spec, component, artifactId)
log { "configureArtifacts: adding ${wrappedEntry.artifact} to MavenPublication $name" }
val res = artifact(wrappedEntry.artifact)
if (wrappedEntry.builtBy != null) {
res.builtBy(wrappedEntry.builtBy)
}
}

Expand All @@ -47,7 +55,7 @@ internal fun Project.configureArtifacts(
}
is Component.Origin.ArtifactSet -> {
log { "configureArtifacts: artifact-based, copying artifacts over" }
maven.addArtifacts(log, origin.artifacts)
maven.addArtifacts(log, origin.artifacts, this, spec, component, "origin")
}
is Component.Origin.MavenPublicationName -> {
if (!origin.clone) {
Expand All @@ -73,15 +81,15 @@ internal fun Project.configureArtifacts(
// Also had to stop using spec.provideDefault*ForComponent: we don't know if the inferred component already
// has (or will have...) that kind of artifact, so adding one automatically will lead to crashes.

component.resolveSources(this, spec)?.let {
component.sources.orNull?.let {
log { "configureArtifacts: adding sources to MavenPublication ${maven.name}" }
maven.addArtifact(it)
maven.addArtifact(log, it, this, spec, component, "sources")
}
component.resolveDocs(this, spec)?.let {
component.docs.orNull?.let {
log { "configureArtifacts: adding docs to MavenPublication ${maven.name}" }
maven.addArtifact(it)
maven.addArtifact(log, it, this, spec, component, "docs")
}
maven.addArtifacts(log, component.extras)
maven.addArtifacts(log, component.extras, this, spec, component, "extras")
}

private fun Project.clonePublication(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@ internal fun Project.configureSigning(
val signatory = ext.signatory
return ext.sign(maven).single().apply {
setSignatory(signatory)
log { "configureSigning: ${maven.name} signatures = ${this.signatures.map { it.signatureType.extension }}" }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package io.deepmedia.tools.deployer.inference

import io.deepmedia.tools.deployer.model.Component
import io.deepmedia.tools.deployer.model.DeploySpec
import io.deepmedia.tools.deployer.tasks.makeDocsJar
import io.deepmedia.tools.deployer.tasks.makeSourcesJar
import io.deepmedia.tools.deployer.whenEvaluated
import org.gradle.api.Project
import org.gradle.kotlin.dsl.getByType
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,70 @@
package io.deepmedia.tools.deployer.model

import org.gradle.api.Project
import org.gradle.api.artifacts.PublishArtifact
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Provider
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import org.gradle.kotlin.dsl.domainObjectSet
import javax.inject.Inject

open class Artifacts @Inject constructor(objects: ObjectFactory) {

internal class Entry(val artifact: Any, val builtBy: Any?) {
constructor(artifact: Any, classifier: String, extension: String, builtBy: Any?) : this(
artifact = mapOf(
"source" to artifact,
"classifier" to classifier,
"extension" to extension
),
builtBy = builtBy
)
internal sealed class Entry {
sealed class Resolved(private val builtByCandidate: Any?) : Entry() {
abstract val artifact: Any

// Unwraps dictionary notation and providers, so the result should be one of the accepted types
// (PublishArtifact, AbstractArchiveTask, or something resolvable with file())
val unwrappedArtifact: Any get() {
val unwrapDictionary = when (this) {
is Dictionary -> this.source
is Regular -> this.artifact
}
return when (unwrapDictionary) {
is Provider<*> -> unwrapDictionary.get()
else -> unwrapDictionary
}
}

// Note that MavenPublication.artifact() *should* already correctly pull the dependencies,
// but we use an intermediate task (Workarounds.kt) and it is important to keep them explicitly
val builtBy: Any? get() = builtByCandidate ?: when (val raw = unwrappedArtifact) {
is PublishArtifact -> raw.buildDependencies
is AbstractArchiveTask -> raw
else -> null
}
}

class Regular(override val artifact: Any, builtBy: Any?) : Resolved(builtBy)

class Dictionary(private val dictionary: Map<String, Any?>, builtBy: Any?) : Resolved(builtBy) {
constructor(source: Any, classifier: String?, extension: String, builtBy: Any?) : this(
mapOf(
"source" to source,
"classifier" to classifier,
"extension" to extension
),
builtBy
)
val source: Any get() = dictionary["source"]!!
val classifier: String? get() = dictionary["classifier"] as? String
val extension: String get() = dictionary["extension"] as String
override val artifact get() = dictionary
}

class Promise(val make: (Project) -> Any) : Entry() {
fun resolve(project: Project): Resolved = Unknown(make(project), null)
}

companion object {
@Suppress("UNCHECKED_CAST")
fun Unknown(artifact: Any, builtBy: Any?): Resolved = when {
artifact is Map<*, *> -> Dictionary(artifact as Map<String, Any?>, builtBy)
else -> Regular(artifact, builtBy)
}
}
}

internal val entries = objects.domainObjectSet(Entry::class)
Expand Down Expand Up @@ -44,10 +93,10 @@ open class Artifacts @Inject constructor(objects: ObjectFactory) {
* - A Kotlin function or Groovy closure. It may return any of the types in this list.
*/
fun artifact(artifact: Any, builtBy: Any? = null) {
entries.add(Entry(artifact, builtBy))
entries.add(Entry.Unknown(artifact, builtBy))
}

fun artifact(artifact: Any, classifier: String, extension: String, builtBy: Any? = null) {
entries.add(Entry(artifact, classifier, extension, builtBy))
fun artifact(artifact: Any, classifier: String?, extension: String, builtBy: Any? = null) {
entries.add(Entry.Dictionary(artifact, classifier, extension, builtBy))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ package io.deepmedia.tools.deployer.model

import io.deepmedia.tools.deployer.capitalized
import io.deepmedia.tools.deployer.tasks.*
import io.deepmedia.tools.deployer.tasks.makeDocsJar
import io.deepmedia.tools.deployer.tasks.makeEmptyDocsJar
import io.deepmedia.tools.deployer.tasks.makeEmptySourcesJar
import io.deepmedia.tools.deployer.tasks.makeSourcesJar
import org.gradle.api.*
import org.gradle.api.component.SoftwareComponent
import org.gradle.api.model.ObjectFactory
Expand Down Expand Up @@ -43,22 +41,22 @@ open class Component @Inject constructor(private val objects: ObjectFactory) {
internal val origin: Property<Origin> = objects.property()

internal val shortName: String get() = when (val o = origin.get()) {
is Origin.SoftwareComponent -> "soft:${o.component.name}"
is Origin.SoftwareComponentName -> "softn:${o.name}"
is Origin.MavenPublicationName -> "pub:${o.name}"
is Origin.ArtifactSet -> "art:${o.id}"
is Origin.SoftwareComponent -> "${o.component.name}Component"
is Origin.SoftwareComponentName -> "${o.name}Component"
is Origin.MavenPublicationName -> "${o.name}Publication"
is Origin.ArtifactSet -> "artifacts${o.id}"
}

internal fun maybeCreatePublication(publications: PublicationContainer, spec: DeploySpec): MavenPublication {
val origin = origin.get()
val name = when (origin) {
is Origin.SoftwareComponent -> origin.component.name + "SoftwareFor" + spec.name.capitalized()
is Origin.SoftwareComponentName -> origin.name + "SoftwareFor" + spec.name.capitalized()
is Origin.SoftwareComponent -> spec.name + origin.component.name.capitalized() + "Component"
is Origin.SoftwareComponentName -> spec.name + origin.name.capitalized() + "Component"
is Origin.MavenPublicationName -> when {
origin.clone -> origin.name + "ClonedFor" + spec.name.capitalized()
origin.clone -> spec.name + origin.name.capitalized() + "Clone"
else -> origin.name
}
is Origin.ArtifactSet -> "artifacts" + origin.id + "For" + spec.name.capitalized()
is Origin.ArtifactSet -> spec.name + "Artifacts" + origin.id
}
val existing = publications.findByName(name)
return when {
Expand Down Expand Up @@ -189,29 +187,52 @@ open class Component @Inject constructor(private val objects: ObjectFactory) {
configureWhen { block -> block() }
}

private val sources: Property<Artifacts.Entry> = objects.property()
private val docs: Property<Artifacts.Entry> = objects.property()
fun sources(task: Any?) { sources.set(task?.let { Artifacts.Entry(it, it) }) }
fun docs(task: Any?) { docs.set(task?.let { Artifacts.Entry(it, it) }) }
internal val sources: Property<Artifacts.Entry> = objects.property()
internal val docs: Property<Artifacts.Entry> = objects.property()

private val fallbackSources: Property<Project.() -> TaskProvider<Jar>> = objects.property()
private val fallbackDocs: Property<Project.() -> TaskProvider<Jar>> = objects.property()
fun sources(artifact: Any, classifier: String = "sources", extension: String = "jar", builtBy: Any? = null) {
sources.set(Artifacts.Entry.Dictionary(artifact, classifier, extension, builtBy))
}

fun emptySources() {
sources.set(Artifacts.Entry.Promise { it.makeEmptySourcesJar })
}

fun kotlinSources() {
sources.set(Artifacts.Entry.Promise { it.makeKotlinSourcesJar })
}

fun emptySources() { fallbackSources.set { makeEmptySourcesJar } }
fun kotlinSources() { fallbackSources.set { makeKotlinSourcesJar } }
fun javaSources() { fallbackSources.set { makeJavaSourcesJar } }
fun javaSources() {
sources.set(Artifacts.Entry.Promise { it.makeJavaSourcesJar })
}

fun emptyDocs() { fallbackDocs.set { makeEmptyDocsJar } }
fun docs(artifact: Any, classifier: String = "javadoc", extension: String = "jar", builtBy: Any? = null) {
docs.set(Artifacts.Entry.Dictionary(artifact, classifier, extension, builtBy))
}

internal fun resolveSources(project: Project, spec: DeploySpec): Artifacts.Entry? {
val fallback = fallbackSources.map { project.makeSourcesJar(spec, this, project.it()) }
fun emptyDocs() {
docs.set(Artifacts.Entry.Promise { it.makeEmptyDocsJar })
}

// private val fallbackSources: Property<Project.() -> TaskProvider<Jar>> = objects.property()
// private val fallbackDocs: Property<Project.() -> TaskProvider<Jar>> = objects.property()
// fun emptySources() { fallbackSources.set { makeEmptySourcesJar } }
// fun kotlinSources() { fallbackSources.set { makeKotlinSourcesJar } }
// fun javaSources() { fallbackSources.set { makeJavaSourcesJar } }
// fun emptyDocs() { fallbackDocs.set { makeEmptyDocsJar } }
/* internal fun resolveSources(project: Project): Artifacts.Entry? {
val fallback = fallbackSources.map { project.it() }
.map { taskProvider -> Artifacts.Entry(taskProvider, taskProvider) }
// val fallback = fallbackSources.map { project.makeSourcesJar(spec, this, project.it()) }
return sources.orElse(fallback).orNull
}
internal fun resolveDocs(project: Project, spec: DeploySpec): Artifacts.Entry? {
val fallback = fallbackDocs.map { project.makeDocsJar(spec, this, project.it()) }
internal fun resolveDocs(project: Project): Artifacts.Entry? {
val fallback = fallbackSources.map { project.it() }
.map { taskProvider -> Artifacts.Entry(taskProvider, taskProvider) }
// val fallback = fallbackDocs.map { project.makeDocsJar(spec, this, project.it()) }
return docs.orElse(fallback).orNull
}
} */

val extras: Artifacts = objects.newInstance()

Expand Down
Loading

0 comments on commit a09b67c

Please sign in to comment.