Skip to content

Publish to Sonatype Maven Central#31

Open
gschueler wants to merge 1 commit intomasterfrom
publish-maven-central
Open

Publish to Sonatype Maven Central#31
gschueler wants to merge 1 commit intomasterfrom
publish-maven-central

Conversation

@gschueler
Copy link
Copy Markdown
Member

  • 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>
@gschueler gschueler marked this pull request as ready for review February 19, 2026 20:12
Copilot AI review requested due to automatic review settings February 19, 2026 20:12
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-plugins to org.rundeck.plugins in 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
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Suggested change
description = project.ext.hasProperty('publishDescription') ? publishDescription : publishName
description = publishDescription

Copilot uses AI. Check for mistakes.
Comment on lines +43 to +52
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)
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
licenses {
license {
name = 'The Apache Software License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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'.

Suggested change
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
url = 'https://www.apache.org/licenses/LICENSE-2.0.txt'

Copilot uses AI. Check for mistakes.
asset_content_type: application/zip

- name: Publish to Sonatype Maven Central
if: ${{ secrets.SONATYPE_USERNAME != '' && secrets.SIGNING_KEY != '' }}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. Remove the if condition and let the step fail gracefully if secrets are missing
  2. Use a separate job with environment-level conditions
  3. 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.

Suggested change
if: ${{ secrets.SONATYPE_USERNAME != '' && secrets.SIGNING_KEY != '' }}

Copilot uses AI. Check for mistakes.

publishing {
publications {
mavenZip(MavenPublication) {
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
Suggested change
mavenZip(MavenPublication) {
mavenZip(MavenPublication) {
groupId = project.group
artifactId = project.ext.archivesBaseName

Copilot uses AI. Check for mistakes.
publications {
mavenZip(MavenPublication) {
artifact pluginZip
version = rootProject.version.toString()
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. Documenting this intentional difference
  2. Updating the subproject version logic to use rootProject.version directly
  3. Ensuring the archiveVersion in pluginZip task also uses rootProject.version for consistency

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants