The Gradle plugin publishes to two locations:
- Maven Central (via Central Portal - new way)
- Gradle Plugin Portal
Generate a GPG key if you don't have one:
gpg --gen-keyList your keys:
gpg --list-keysExport your public key to a keyserver:
gpg --keyserver keyserver.ubuntu.com --send-keys YOUR_KEY_ID- Create an account at https://central.sonatype.com/
- Generate a user token:
- Log in to Central Portal
- Go to Account → Generate User Token
- Save the username and password (these are your publishing credentials)
- Create an account at https://plugins.gradle.org/
- Generate API keys:
- Log in to Gradle Plugin Portal
- Go to your profile
- Get your API Key and Secret
Use environment variables when credentials should not persist to disk (CI/CD pipelines, shared build servers):
export CENTRAL_USERNAME="your-central-token-username"
export CENTRAL_PASSWORD="your-central-token-password"
export GRADLE_PUBLISH_KEY="your-gradle-plugin-portal-api-key"
export GRADLE_PUBLISH_SECRET="your-gradle-plugin-portal-secret"
export MAVEN_GPG_PASSPHRASE="your-gpg-passphrase"Note: The GPG key ID is configured in build.gradle.kts. If you need to use a different key, update the
signing.gnupg.keyName value in that file.
Use property files when you want credentials to persist across shell sessions (local development):
Create/edit ~/.gradle/gradle.properties:
# Maven Central Portal (new way)
centralUsername=your-central-token-username
centralPassword=your-central-token-password
# Gradle Plugin Portal
gradle.publish.key=your-gradle-plugin-portal-api-key
gradle.publish.secret=your-gradle-plugin-portal-secret
# GPG Signing
signing.keyId=your-gpg-key-id-last-8-chars
signing.password=your-gpg-passphrase
signing.secretKeyRingFile=/Users/yourname/.gnupg/secring.gpgNote: For GPG signing in Gradle 6+, you may need to export your secret key:
gpg --export-secret-keys YOUR_KEY_ID > ~/.gnupg/secring.gpgOr use the Gradle in-memory key approach:
signing.gnupg.executable=gpg
signing.gnupg.useLegacyGpg=false
signing.gnupg.keyName=your-gpg-key-id
signing.gnupg.passphrase=your-gpg-passphraseUse Maven to publish everything in one command (all Maven modules + Gradle plugin):
# From the root of code-structure project
mvn deploy -PstageThis will:
- Build and deploy all Maven modules to Central Portal
- Build the Gradle plugin
- Publish Gradle plugin to Maven Central
- Publish Gradle plugin to Gradle Plugin Portal
Use Gradle when you only want to publish the Gradle plugin without rebuilding Maven modules:
# From the gradle-plugin directory
# Publish to both Maven Central and Gradle Plugin Portal
./gradlew publishAllPublicationsToCentralRepository publishPlugins
# Or separately:
./gradlew publishAllPublicationsToCentralRepository # Maven Central only
./gradlew publishPlugins # Gradle Plugin Portal only
# Publish to Maven Local for testing
./gradlew publishToMavenLocal- Go to https://central.sonatype.com/
- Search for
com.seanshubin.code.structure - Check that
code-structure-gradle-pluginappears
Note: Maven Central can take 15-30 minutes to sync to Maven Central search
- Go to https://plugins.gradle.org/
- Search for
com.seanshubin.code.structure - Verify the plugin page shows the new version
Note: Gradle Plugin Portal usually updates within a few minutes
Create a test project with:
plugins {
id("com.seanshubin.code.structure") version "1.1.1"
}Run:
./gradlew analyzeCodeStructureThe plugin hasn't synced yet. Wait 15-30 minutes for Maven Central.
Ensure GPG is set up correctly:
gpg --list-secret-keysIf using gpg-agent, make sure it's running:
gpg-agent --daemon- Verify your Central Portal token username/password
- Tokens expire - generate a new one if needed
- Ensure you're using the Central Portal credentials, not OSSRH credentials
- Verify your API key and secret
- Check that your account has publishing permissions
- API keys can be revoked - generate new ones if needed
- Never commit credentials to version control
- Add
~/.gradle/gradle.propertiesto.gitignore(already done globally) - Use environment variables in CI/CD pipelines
- Rotate credentials periodically
- Use token-based authentication (not passwords) where available