Skip to content

Commit db0f207

Browse files
committed
Update publishing so that it should work with the new publishing API.
This is inspired by the `org.danilopianini.publish-on-central` plugin, but directly integrated as that plugin doesn't aggregate the publications in a single zip file/publication action.
1 parent 6b59588 commit db0f207

File tree

4 files changed

+169
-46
lines changed

4 files changed

+169
-46
lines changed

.github/workflows/deploy-to-packages.yml

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,33 @@ on:
77
- 'v[0-9]*'
88
workflow_dispatch:
99
jobs:
10-
create-staging-repository:
11-
name: Create staging repository
12-
runs-on: ubuntu-latest
13-
outputs:
14-
repository_id: ${{ steps.create.outputs.repository_id }}
15-
steps:
16-
- id: create
17-
uses: nexus-actions/create-nexus-staging-repo@v1.3.0
18-
with:
19-
username: ${{ secrets.OSSRH_USERNAME }}
20-
password: ${{ secrets.OSSRH_PASSWORD }}
21-
base_url: https://ossrh-staging-api.central.sonatype.com/service/local/
22-
staging_profile_id: ${{ secrets.SONATYPE_PROFILE_ID }}
23-
description: ${{ github.repository }}/${{ github.workflow }}#${{ github.run_number }}
10+
# create-staging-repository:
11+
# name: Create staging repository
12+
# runs-on: ubuntu-latest
13+
# outputs:
14+
# repository_id: ${{ steps.create.outputs.repository_id }}
15+
# steps:
16+
# - id: create
17+
# uses: nexus-actions/create-nexus-staging-repo@v1.3.0
18+
# with:
19+
# username: ${{ secrets.OSSRH_USERNAME }}
20+
# password: ${{ secrets.OSSRH_PASSWORD }}
21+
# base_url: https://ossrh-staging-api.central.sonatype.com/service/local/
22+
# staging_profile_id: ${{ secrets.SONATYPE_PROFILE_ID }}
23+
# description: ${{ github.repository }}/${{ github.workflow }}#${{ github.run_number }}
2424

2525
build-and-publish:
26-
needs: create-staging-repository
27-
runs-on: ${{ matrix.os }}
26+
# needs: create-staging-repository
27+
# runs-on: ${{ matrix.os }}
28+
runs-on: macos-latest
2829
env:
2930
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3031
GPG_PRIV_KEY: ${{ secrets.OSSRH_GPG_SECRET_KEY }}
3132
GPG_PASSPHRASE: ${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }}
32-
strategy:
33-
matrix:
34-
# os: [ macOs-latest, windows-latest, ubuntu-latest ]
35-
os: [ macOs-latest ]
33+
# strategy:
34+
# matrix:
35+
## os: [ macOs-latest, windows-latest, ubuntu-latest ]
36+
# os: [ macOs-latest ]
3637
steps:
3738
- name: Checkout
3839
uses: actions/checkout@v4.2.2
@@ -50,14 +51,9 @@ jobs:
5051
- id: cache-gradle-windows
5152
name: Set up gradle
5253
uses: gradle/actions/setup-gradle@v4
53-
- name: Check (macos / windows)
54-
if: matrix.os != 'ubuntu-latest'
54+
- name: Check
5555
run: ./gradlew -PexcludeSchema nativeTest --stacktrace
5656
shell: bash
57-
- name: Check (ubuntu)
58-
if: matrix.os == 'ubuntu-latest'
59-
run: ./gradlew -PexcludeSchema check --stacktrace
60-
shell: bash
6157
- name: Store reports
6258
if: failure()
6359
uses: actions/upload-artifact@v4
@@ -68,7 +64,7 @@ jobs:
6864
**/build/test-results/
6965
- name: Upload (macOs)
7066
if: matrix.os == 'macOs-latest'
71-
run: ./gradlew -PexcludeSchema publish -Pxmlutil.repositoryId='${{ needs.create-staging-repository.outputs.repository_id }}' -Possrh.username='${{ secrets.OSSRH_USERNAME }}' -Possrh.password='${{ secrets.OSSRH_PASSWORD }}' -Pnative.deploy=all --stacktrace
67+
run: ./gradlew -PexcludeSchema -Possrh.username='${{ secrets.OSSRH_USERNAME }}' -Possrh.password='${{ secrets.OSSRH_PASSWORD }}' -Pnative.deploy=all --stacktrace
7268
shell: bash
7369

7470
drop-on-failure:

project-plugins/src/main/kotlin/io/github/xmlutil/plugin/ProjectPlugin.kt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ import org.gradle.api.provider.Property
3838
import org.gradle.api.publish.PublishingExtension
3939
import org.gradle.api.publish.maven.MavenPublication
4040
import org.gradle.api.publish.maven.internal.publication.DefaultMavenPublication
41+
import org.gradle.api.publish.plugins.PublishingPlugin
42+
import org.gradle.api.tasks.bundling.Zip
4143
import org.gradle.api.tasks.testing.Test
4244
import org.gradle.jvm.toolchain.JavaLanguageVersion
4345
import org.gradle.kotlin.dsl.*
@@ -55,6 +57,21 @@ class ProjectPlugin @Inject constructor(
5557
override fun apply(project: Project) {
5658
project.logger.info("===================\nUsing ProjectPlugin\n===================")
5759

60+
if (project == project.rootProject) {
61+
val collateTask = project.tasks.register<Zip>("collateModuleRepositories") {
62+
group = PublishingPlugin.PUBLISH_TASK_GROUP
63+
description = "Zip task that collates all local repositories into a single zip file"
64+
destinationDirectory = project.layout.buildDirectory.dir("repositoryArchive")
65+
archiveBaseName = "moduleRepository"
66+
}
67+
68+
val publishToSonatype = project.tasks.register<PublishToSonatypeTask>("publishToSonatype") {
69+
dependsOn(collateTask)
70+
from(collateTask.flatMap { t -> t.archiveFile.map { it.asFile } })
71+
}
72+
73+
}
74+
5875
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
5976
val xmlutil_version = libs.findVersion("xmlutil").get().requiredVersion
6077

@@ -262,7 +279,7 @@ class ProjectPlugin @Inject constructor(
262279
}
263280
project.afterEvaluate {
264281
for (c in project.components) {
265-
project.logger.warn("Found component: ${c.name}")
282+
project.logger.debug("Found component: ${c.name}")
266283
}
267284
}
268285
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright (c) 2025.
3+
*
4+
* This file is part of xmlutil.
5+
*
6+
* This file is licenced to you under the Apache License, Version 2.0
7+
* (the "License"); you may not use this file except in compliance
8+
* with the License. You should have received a copy of the license
9+
* with the source distribution. Alternatively, you may obtain a copy
10+
* of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
17+
* implied. See the License for the specific language governing
18+
* permissions and limitations under the License.
19+
*/
20+
21+
package io.github.xmlutil.plugin
22+
23+
import org.gradle.api.DefaultTask
24+
import org.gradle.api.Project
25+
import org.gradle.api.provider.Property
26+
import org.gradle.api.provider.Provider
27+
import org.gradle.api.tasks.InputFile
28+
import org.gradle.api.tasks.TaskAction
29+
import org.gradle.internal.impldep.org.joda.time.Instant
30+
import java.io.File
31+
import java.net.HttpURLConnection
32+
import java.net.URI
33+
import java.util.*
34+
35+
abstract class PublishToSonatypeTask() : DefaultTask() {
36+
37+
@get:InputFile
38+
abstract val archive: Property<File>
39+
40+
fun from(file: Provider<out File>) { archive.set(file) }
41+
fun from(file: File) { archive.set(file) }
42+
43+
@TaskAction
44+
fun run() {
45+
val archiveFile = archive.get()
46+
val username = project.findProperty("ossrh.username") as String
47+
val password = project.findProperty("ossrh.password") as String
48+
val authHeader = "UserToken ${Base64.getEncoder().encode("$username:$password".toByteArray())}"
49+
50+
val url = URI("https://central.sonatype.com/api/v1/publisher/upload?publishingType=USER_MANAGED")
51+
val connection = url.toURL().openConnection() as HttpURLConnection
52+
try {
53+
val boundary = "*******${Instant.now().millis}*******"
54+
55+
connection.requestMethod = "POST"
56+
connection.doOutput = true
57+
connection.setRequestProperty("Accept", "text/plain")
58+
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=$boundary")
59+
60+
connection.getOutputStream().use { output ->
61+
output.write("--$boundary\r\n".toByteArray())
62+
output.write("Content-Disposition: form-data; name=\"bundle\"; filename=\"${archiveFile.name}\"\r\n".toByteArray())
63+
output.write("Content-Type: application/octet-stream\r\n".toByteArray())
64+
65+
archiveFile.inputStream().copyTo(output)
66+
output.write("\r\n--$boundary\r\n".toByteArray())
67+
}
68+
69+
connection.connect()
70+
71+
if (connection.responseCode !in 200 .. 299) {
72+
throw IllegalStateException("Unexpected response: ${connection.responseCode} - ${connection.responseMessage} ")
73+
}
74+
75+
val deploymentId = connection.getInputStream().readAllBytes().toString(Charsets.UTF_8)
76+
77+
logger.lifecycle("Published archive with deployment id $deploymentId")
78+
} finally {
79+
connection.disconnect()
80+
}
81+
}
82+
83+
84+
}
85+
86+
fun Project.f() {
87+
val f: File = file("Foo")
88+
}

project-plugins/src/main/kotlin/net/devrieze/gradle/ext/publishing.kt

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ import org.gradle.api.publish.maven.MavenPublication
2727
import org.gradle.api.publish.maven.tasks.AbstractPublishToMaven
2828
import org.gradle.api.publish.maven.tasks.PublishToMavenRepository
2929
import org.gradle.api.tasks.bundling.Jar
30+
import org.gradle.api.tasks.bundling.Zip
3031
import org.gradle.kotlin.dsl.*
3132
import org.gradle.plugins.signing.SigningExtension
32-
import java.util.*
3333

3434
@Suppress("LocalVariableName")
3535
fun Project.doPublish(
@@ -41,28 +41,33 @@ fun Project.doPublish(
4141
extra["isReleaseVersion"] = isReleaseVersion
4242

4343

44-
val javadocJarTask = tasks.create<Jar>("javadocJar") {
44+
val javadocJarTask = tasks.register<Jar>("javadocJar") {
4545
archiveClassifier.set("javadoc")
46-
from(tasks.named("dokkaGenerateModuleHtml"))
46+
from(tasks.named("dokkaGeneratePublicationHtml"))
4747
}
4848

4949
configure<PublishingExtension> {
50-
repositories {
50+
this.repositories {
5151
maven {
52-
name = "OSS_registry"
53-
val repositoryId = project.properties["xmlutil.repositoryId"] as String?
54-
url = when {
55-
"SNAPSHOT" in version.toString().uppercase(Locale.getDefault()) ->
56-
uri("https://central.sonatype.com/repository/maven-snapshots/")
57-
repositoryId != null ->
58-
uri("https://ossrh-staging-api.central.sonatype.com/service/local/staging/deployByRepositoryId/$repositoryId/")
59-
else ->
60-
uri("https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/")
61-
}
62-
credentials {
63-
username = project.findProperty("ossrh.username") as String?
64-
password = project.findProperty("ossrh.password") as String?
65-
}
52+
name = "projectLocal"
53+
54+
setUrl(project.layout.buildDirectory.dir("project-local-repository").map { it.asFile.toURI() })
55+
/*
56+
url = when {
57+
"SNAPSHOT" in version.toString().uppercase(Locale.getDefault()) ->
58+
uri("https://central.sonatype.com/repository/maven-snapshots/")
59+
repositoryId != null ->
60+
uri("https://ossrh-staging-api.central.sonatype.com/service/local/staging/deployByRepositoryId/$repositoryId/")
61+
else ->
62+
uri("https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/")
63+
}
64+
*/
65+
/*
66+
credentials {
67+
username = project.findProperty("ossrh.username") as String?
68+
password = project.findProperty("ossrh.password") as String?
69+
}
70+
*/
6671

6772
}
6873
}
@@ -141,8 +146,25 @@ fun Project.doPublish(
141146
description = "Task to publish all native artefacts only"
142147
}
143148

149+
150+
144151
tasks.withType<PublishToMavenRepository> {
145152
if (isEnabled) {
153+
154+
if (repository?.name == "projectLocal") {
155+
val repositoryDir = project.layout.buildDirectory.dir("project-local-repository")
156+
if (repositoryDir.isPresent) {
157+
repositoryDir.get().asFile.deleteRecursively()
158+
}
159+
160+
val publishTask = this
161+
162+
rootProject.tasks.named<Zip>("collateModuleRepositories") {
163+
dependsOn(publishTask)
164+
from(repositoryDir)
165+
}
166+
}
167+
146168
val doPublish = arrayOf("publishKotlinMultiplatform", "publishJs", "publishJvm", "publishAndroid").none { "${it}Publication" in name }
147169
if (doPublish) {
148170
publishNativeTask.dependsOn(this)

0 commit comments

Comments
 (0)