Conversation
gschueler
commented
Feb 19, 2026
- Add nexus-publish plugin and Sonatype repo to root build.gradle
- Set project version from scmVersion (no v prefix) for Maven coordinates
- Set group to org.rundeck.plugins in gradle.properties
- Add shared gradle/publishing.gradle for POM metadata and GPG signing
- In plugin-build.gradle: set mavenZip version from root, apply publishing script
- Release workflow: optional publish to Maven Central after GitHub release (when secrets set)
- README: document publishing and required properties
- Add nexus-publish plugin and Sonatype repo to root build.gradle - Set project version from scmVersion (no v prefix) for Maven coordinates - Set group to org.rundeck.plugins in gradle.properties - Add shared gradle/publishing.gradle for POM metadata and GPG signing - In plugin-build.gradle: set mavenZip version from root, apply publishing script - Release workflow: optional publish to Maven Central after GitHub release (when secrets set) - README: document publishing and required properties Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Pull request overview
This PR adds Maven Central publishing capability to the nixy-step-plugins project. It configures the nexus-publish plugin for Sonatype integration, sets up proper Maven coordinates with group org.rundeck.plugins, and implements POM metadata generation with GPG signing support for artifact publication.
Changes:
- Configured nexus-publish plugin and Sonatype repository in root build.gradle with version from scmVersion (no 'v' prefix)
- Changed Maven group from
org.rundeck.rundeck-pluginstoorg.rundeck.pluginsin gradle.properties - Added shared gradle/publishing.gradle for centralized POM metadata (license, SCM, developers) and conditional GPG signing
- Updated plugin-build.gradle to set Maven artifact version from root project and apply shared publishing script
- Extended release workflow to optionally publish to Maven Central when Sonatype/signing secrets are configured
- Documented publishing process and required properties in README.md
Reviewed changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| build.gradle | Added nexus-publish plugin, set project version from scmVersion, configured Sonatype repository |
| gradle.properties | Changed group to org.rundeck.plugins for Maven coordinates |
| gradle/publishing.gradle | New shared script defining POM metadata (license, SCM, developers) and conditional GPG signing |
| plugin-build.gradle | Added POM metadata defaults, set mavenZip version from root project, applied shared publishing script |
| .github/workflows/release.yml | Added optional Maven Central publishing step after GitHub release |
| README.md | Documented Maven Central publishing process and required properties |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| publishing.publications.mavenZip.pom { | ||
| name = publishName | ||
| description = project.ext.hasProperty('publishDescription') ? publishDescription : publishName |
There was a problem hiding this comment.
The fallback logic is redundant. Line 16 checks project.ext.hasProperty('publishDescription') when publishDescription is already guaranteed to exist from line 62 in plugin-build.gradle. This check will always be true, making the ternary operator unnecessary.
The line can be simplified to just:
description = publishDescription
| description = project.ext.hasProperty('publishDescription') ? publishDescription : publishName | |
| description = publishDescription |
| def base64Decode = { String prop -> | ||
| project.findProperty(prop) ? | ||
| new String(Base64.getDecoder().decode(project.findProperty(prop).toString())).trim() : | ||
| null | ||
| } | ||
|
|
||
| if (project.hasProperty('signingKey') && project.hasProperty('signingPassword')) { | ||
| apply plugin: 'signing' | ||
| signing { | ||
| useInMemoryPgpKeys(base64Decode("signingKey"), project.signingPassword) |
There was a problem hiding this comment.
The signing configuration has a potential security issue. The base64Decode function decodes the signingKey but doesn't validate it. If the signingKey property contains invalid base64 data, this will throw an IllegalArgumentException at runtime, which could expose the partial key data in error logs.
Consider adding try-catch error handling around the base64 decode operation to fail gracefully with a clearer error message that doesn't risk exposing sensitive data.
| licenses { | ||
| license { | ||
| name = 'The Apache Software License, Version 2.0' | ||
| url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' |
There was a problem hiding this comment.
The Apache License URL uses HTTP instead of HTTPS. Maven Central and modern best practices recommend using HTTPS URLs for all external references. The URL should be 'https://www.apache.org/licenses/LICENSE-2.0.txt' instead of 'http://www.apache.org/licenses/LICENSE-2.0.txt'.
| url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' | |
| url = 'https://www.apache.org/licenses/LICENSE-2.0.txt' |
| asset_content_type: application/zip | ||
|
|
||
| - name: Publish to Sonatype Maven Central | ||
| if: ${{ secrets.SONATYPE_USERNAME != '' && secrets.SIGNING_KEY != '' }} |
There was a problem hiding this comment.
The if condition syntax is incorrect. In GitHub Actions, the secrets context cannot be accessed directly within the if expression like this. The condition secrets.SONATYPE_USERNAME != '' will always evaluate to false because secrets are not available in the if context.
To conditionally run this step based on whether secrets are set, you should either:
- Remove the if condition and let the step fail gracefully if secrets are missing
- Use a separate job with environment-level conditions
- Check for the secrets in a previous step and set an output variable
The recommended approach is to simply remove the if condition, as the Gradle task will fail with a clear error if the required properties are missing.
| if: ${{ secrets.SONATYPE_USERNAME != '' && secrets.SIGNING_KEY != '' }} |
|
|
||
| publishing { | ||
| publications { | ||
| mavenZip(MavenPublication) { |
There was a problem hiding this comment.
The mavenZip publication is missing required Maven coordinates (groupId and artifactId). While the version is set, Maven Central requires all three coordinates. The groupId should be set to the project's group property, and the artifactId should be set to identify each plugin artifact.
Add these properties within the mavenZip publication block:
- groupId = project.group (or explicitly 'org.rundeck.plugins')
- artifactId should be set to the plugin's artifact name (e.g., project.ext.archivesBaseName)
| mavenZip(MavenPublication) { | |
| mavenZip(MavenPublication) { | |
| groupId = project.group | |
| artifactId = project.ext.archivesBaseName |
| publications { | ||
| mavenZip(MavenPublication) { | ||
| artifact pluginZip | ||
| version = rootProject.version.toString() |
There was a problem hiding this comment.
There's a version conflict between the subproject version and the Maven publication version. The subprojects (e.g., command/build.gradle line 9) set project.version = 'v' + scmVersion.version (with 'v' prefix), but the mavenZip publication uses version = rootProject.version.toString() which comes from the root build.gradle that sets project.version = scmVersion.version (without 'v' prefix).
This creates an inconsistency where the plugin zip file will be named with the 'v' prefix (e.g., command-v1.0.0.zip) but the Maven artifact will be published with version 1.0.0 (no 'v' prefix). While this may be intentional for Maven coordinates (which shouldn't have a 'v' prefix), the inconsistency could cause confusion.
Consider either:
- Documenting this intentional difference
- Updating the subproject version logic to use rootProject.version directly
- Ensuring the archiveVersion in pluginZip task also uses rootProject.version for consistency