Skip to content

Commit 6a42a6f

Browse files
committed
fix gradle plugin publication
fix duplicate publishing to netflix oss and sonatype add tests for gradle plugin marker signing
1 parent 452169e commit 6a42a6f

File tree

11 files changed

+858
-27
lines changed

11 files changed

+858
-27
lines changed

build.gradle.kts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ dependencies {
4242
testImplementation("org.ajoberstar.grgit:grgit-core:4.1.1") {
4343
exclude (group= "org.codehaus.groovy", module= "groovy")
4444
}
45+
testImplementation("org.mock-server:mockserver-netty:5.15.0")
4546
}
4647

4748
gradlePlugin {
@@ -67,6 +68,11 @@ testing {
6768
suites {
6869
named<JvmTestSuite>("test"){
6970
useJUnitJupiter()
71+
targets.all {
72+
testTask.configure {
73+
maxParallelForks = 2
74+
}
75+
}
7076
}
7177
}
7278
}

gradle.lockfile

Lines changed: 105 additions & 3 deletions
Large diffs are not rendered by default.

src/main/kotlin/nebula/plugin/publishing/NebulaOssPublishingPlugin.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,19 @@ open class NebulaOssPublishingPlugin @Inject constructor(private val providerFac
5757
?.dependsOn(project.tasks.withType<PublishToMavenRepository>())
5858
}
5959
}
60+
61+
project.plugins.withId("com.gradle.plugin-publish"){
62+
project.afterEvaluate {
63+
project.tasks.findByName("publishPluginMavenPublicationToNetflixOSSRepository")?.onlyIf {
64+
project.logger.info("disabling gradle plugin publish to Netflix OSS to prevent duplicate")
65+
false
66+
}
67+
project.tasks.findByName("publishPluginMavenPublicationToSonatypeRepository")?.onlyIf {
68+
project.logger.info("disabling gradle plugin publish to Sonatype to prevent duplicate")
69+
false
70+
}
71+
}
72+
}
6073
}
6174

6275
private fun setExtensionDefaults(nebulaOssPublishingExtension: NebulaOssPublishingExtension, project: Project) {
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package nebula.plugin.publishing
2+
3+
import org.mockserver.integration.ClientAndServer
4+
import org.mockserver.model.HttpRequest.request
5+
import org.mockserver.model.HttpResponse.response
6+
7+
fun expectPublicationWithChecksums(mockServer: ClientAndServer, path: String): List<(ClientAndServer) -> Unit> {
8+
val verifications = mutableListOf<(ClientAndServer) -> Unit>()
9+
val paths = listOf(
10+
path,
11+
"$path.md5",
12+
"$path.sha1",
13+
"$path.sha256",
14+
"$path.sha512"
15+
)
16+
paths.forEach {
17+
val request = request(it).withMethod("PUT")
18+
mockServer
19+
.`when`(request)
20+
.respond { response().withStatusCode(200) }
21+
verifications.add { it.verify(request) }
22+
}
23+
return verifications
24+
}
25+
26+
fun expectSignedPublicationWithChecksums(mockServer: ClientAndServer, path: String): List<(ClientAndServer) -> Unit> {
27+
return expectPublicationWithChecksums(mockServer, path) +
28+
expectPublicationWithChecksums(mockServer, "$path.asc")
29+
}
30+
31+
class Publication(
32+
val mockServer: ClientAndServer,
33+
val repo: String,
34+
val groupName: String,
35+
val moduleName: String,
36+
val version: String,
37+
) {
38+
private val groupPath = groupName.replace(".", "/")
39+
private val modulePath = "$repo/$groupPath/${moduleName}"
40+
private val fullPath = "$modulePath/${version}"
41+
private val verifications = mutableListOf<(ClientAndServer) -> Unit>()
42+
fun withArtifact(classifier: String, extension: String) {
43+
verifications.addAll(
44+
expectSignedPublicationWithChecksums(
45+
mockServer,
46+
"/$fullPath/$moduleName-${version}-$classifier.$extension"
47+
)
48+
)
49+
}
50+
51+
fun withGradleModuleMetadata() {
52+
verifications.addAll(
53+
expectSignedPublicationWithChecksums(mockServer, "/$fullPath/$moduleName-${version}.module")
54+
)
55+
}
56+
57+
fun withArtifact(extension: String) {
58+
verifications.addAll(
59+
expectSignedPublicationWithChecksums(mockServer, "/$fullPath/$moduleName-${version}.$extension")
60+
)
61+
}
62+
63+
fun verifications(): List<(ClientAndServer) -> Unit> {
64+
return verifications
65+
}
66+
}
67+
68+
fun ClientAndServer.expectPublication(
69+
repo: String,
70+
groupName: String,
71+
moduleName: String,
72+
version: String,
73+
additional: Publication.() -> Unit = {}
74+
): VerificationsContainer {
75+
val groupPath = groupName.replace(".", "/")
76+
val modulePath = "$repo/$groupPath/${moduleName}"
77+
val fullPath = "$modulePath/${version}"
78+
val allVersionsXml = listOf("0.0.0").joinToString("/n") { " <version>$it</version>" }
79+
`when`(request("/$modulePath/maven-metadata.xml"))
80+
.respond {
81+
response().withBody(
82+
"""
83+
<?xml version="1.0" encoding="UTF-8"?>
84+
<metadata>
85+
<groupId>${groupName}</groupId>
86+
<artifactId>${moduleName}</artifactId>
87+
<versioning>
88+
<latest>0.0.0</latest>
89+
<release>0.0.0</release>
90+
<versions>
91+
$allVersionsXml
92+
</versions>
93+
<lastUpdated>20210816163607</lastUpdated>
94+
</versioning>
95+
</metadata>
96+
"""
97+
).withStatusCode(200)
98+
}
99+
val verifications = mutableListOf<(ClientAndServer) -> Unit>()
100+
verifications.addAll(
101+
expectSignedPublicationWithChecksums(this, "/$fullPath/${moduleName}-${version}.pom")
102+
)
103+
verifications.addAll(
104+
expectPublicationWithChecksums(this, "/$modulePath/maven-metadata.xml")
105+
)
106+
107+
verifications.addAll(
108+
Publication(this, repo, groupName, moduleName, version).apply { additional() }.verifications()
109+
)
110+
return VerificationsContainer(verifications)
111+
}
112+
113+
class VerificationsContainer(val verifications: List<(ClientAndServer) -> Unit>) {
114+
fun verify(mockServer: ClientAndServer) {
115+
verifications.forEach { verification ->
116+
verification(mockServer)
117+
}
118+
}
119+
}
Lines changed: 123 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,138 @@
11
package nebula.plugin.publishing
22

3+
import nebula.test.dsl.ProjectBuilder
4+
import nebula.test.dsl.main
5+
import nebula.test.dsl.src
6+
37
//language=kotlin
4-
const val DISABLE_PUBLISH_TASKS : String = """
8+
const val DISABLE_PUBLISH_TASKS: String = """
59
afterEvaluate {
610
tasks.withType<AbstractPublishToMaven>() {
711
onlyIf { false }
812
}
9-
tasks.withType<Sign>(){
10-
onlyIf { false } // we don't have a signing key in integration tests (yet)
11-
}
13+
tasks.findByName("publishPlugins")?.onlyIf { false }
1214
}
1315
"""
1416

1517

1618
//language=kotlin
17-
const val DISABLE_MAVEN_CENTRAL_TASKS : String = """
19+
const val DISABLE_MAVEN_CENTRAL_TASKS: String = """
1820
project.tasks.findByName("initializeSonatypeStagingRepository")?.onlyIf { false }
1921
project.tasks.findByName("closeSonatypeStagingRepository")?.onlyIf { false }
2022
project.tasks.findByName("releaseSonatypeStagingRepository")?.onlyIf { false }
21-
"""
23+
"""
24+
25+
//language=kotlin
26+
const val MOCK_SIGN: String = """
27+
afterEvaluate {
28+
project.extensions.getByType<SigningExtension>().signatories = object:
29+
org.gradle.plugins.signing.signatory.SignatoryProvider<Signatory> {
30+
override fun configure(settings: SigningExtension?, closure: groovy.lang.Closure<*>?) {
31+
}
32+
33+
override fun getDefaultSignatory(project: Project?): Signatory {
34+
return object: Signatory {
35+
override fun getName(): String {
36+
return "name"
37+
}
38+
39+
override fun sign(toSign: java.io.InputStream?, destination: java.io.OutputStream?) {
40+
destination?.write( sign(toSign))
41+
}
42+
43+
override fun sign(toSign: java.io.InputStream?): ByteArray {
44+
return "signature".toByteArray()
45+
}
46+
47+
override fun getKeyId(): String {
48+
return "id"
49+
}
50+
}
51+
}
52+
53+
override fun getSignatory(name: String?): Signatory {
54+
return object: Signatory {
55+
override fun getName(): String {
56+
return "name"
57+
}
58+
59+
override fun sign(toSign: java.io.InputStream?, destination: java.io.OutputStream?) {
60+
destination?.write( sign(toSign))
61+
}
62+
63+
override fun sign(toSign: java.io.InputStream?): ByteArray {
64+
return "signature".toByteArray()
65+
}
66+
67+
override fun getKeyId(): String {
68+
return "id"
69+
}
70+
}
71+
}
72+
}
73+
}
74+
"""
75+
76+
fun ProjectBuilder.gradlePluginSource() {
77+
src {
78+
main {
79+
java(
80+
"MyPlugin.java",
81+
//language=java
82+
"""
83+
import org.gradle.api.Plugin;
84+
import org.gradle.api.Project;
85+
86+
/**
87+
* comment
88+
*/
89+
public class MyPlugin implements Plugin<Project> {
90+
public void apply(Project project){
91+
}
92+
}
93+
"""
94+
)
95+
}
96+
}
97+
}
98+
99+
fun ProjectBuilder.overrideSonatypeUrl(url: String) {
100+
rawBuildScript(
101+
//language=kotlin
102+
"""
103+
afterEvaluate {
104+
project.extensions.findByType<io.github.gradlenexus.publishplugin.NexusPublishExtension>()?.repositories {
105+
named("sonatype") {
106+
nexusUrl.set(`java.net`.URI("$url"))
107+
allowInsecureProtocol.set(true)
108+
}
109+
}
110+
publishing {
111+
repositories {
112+
named<MavenArtifactRepository>("sonatype"){
113+
isAllowInsecureProtocol = true
114+
}
115+
}
116+
}
117+
}
118+
"""
119+
)
120+
}
121+
122+
fun ProjectBuilder.nebulaOssPublishing(
123+
netflixOssRepositoryBaseUrl: String,
124+
packageGroup: String = "com.netflix",
125+
netflixOssRepository: String = "netflix-oss"
126+
) {
127+
rawBuildScript(
128+
"""
129+
nebulaOssPublishing {
130+
signingKey = "something"
131+
signingPassword = "something"
132+
packageGroup = "$packageGroup"
133+
netflixOssRepositoryBaseUrl = "$netflixOssRepositoryBaseUrl"
134+
netflixOssRepository = "$netflixOssRepository"
135+
}
136+
"""
137+
)
138+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package nebula.plugin.publishing
2+
3+
import org.mockserver.integration.ClientAndServer
4+
import org.mockserver.model.HttpRequest.request
5+
import org.mockserver.model.HttpResponse.response
6+
7+
fun ClientAndServer.mockGradlePluginPortal(pluginId: String) {
8+
`when`(
9+
request()
10+
.withMethod("POST")
11+
.withPath("/api/v1/publish/versions/validate/$pluginId")
12+
)
13+
.respond {
14+
response().withBody(
15+
//language=json
16+
"""{"failed": false}""")
17+
}
18+
}

src/test/kotlin/nebula/plugin/publishing/MultiprojectIntegrationTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ $DISABLE_MAVEN_CENTRAL_TASKS
7373
group = "test"
7474
description = "description"
7575
$DISABLE_PUBLISH_TASKS
76+
$MOCK_SIGN
7677
"""
7778
)
7879
}
@@ -94,6 +95,7 @@ $DISABLE_PUBLISH_TASKS
9495
group = "test"
9596
description = "description"
9697
$DISABLE_PUBLISH_TASKS
98+
$MOCK_SIGN
9799
"""
98100
)
99101
}

0 commit comments

Comments
 (0)