Publishing Releases
This guide is for maintainers who cut releases of Konditional to Maven Central.
Prerequisites
1. Sonatype User Tokens
Konditional publishes to Maven Central via Sonatype OSSRH. You'll need user tokens for authentication.
Create User Token
- Sign in to Sonatype Central Portal
- Navigate to your User Token page
- Click "Generate User Token"
- Copy the generated username and password
- Add these to
~/.gradle/gradle.propertiesasossrhUsernameandossrhPassword
Important: Use user tokens, not your Sonatype JIRA password. Tokens are scoped specifically for publishing and can be rotated without changing your account password.
2. GPG Key Setup
Konditional uses GPG signing via gpg-agent (recommended) for artifact signing.
Generate GPG Key (if needed)
# Generate new GPG key
gpg --full-generate-key
# Select: RSA and RSA
# Key size: 4096 bits
# Expiration: 2 years (recommended)
# Real name: Your Full Name
# Email: your-email@example.com
Configure GPG Agent
Ensure gpg-agent is running and can cache your passphrase:
# Test GPG agent
echo "test" | gpg --clearsign
# Configure agent for longer cache (optional)
# Add to ~/.gnupg/gpg-agent.conf:
default-cache-ttl 3600
max-cache-ttl 7200
Publish GPG Key
# List your keys
gpg --list-secret-keys --keyid-format=long
# Example output:
# sec rsa4096/ABCD1234EFGH5678 2024-01-08 [SC] [expires: 2026-01-07]
# Full fingerprint here
# uid [ultimate] Your Name <your-email@example.com>
# Export public key (use the key ID after rsa4096/)
gpg --keyserver keys.openpgp.org --send-keys ABCD1234EFGH5678
# Verify it was published
gpg --keyserver keys.openpgp.org --recv-keys ABCD1234EFGH5678
3. Configure ~/.gradle/gradle.properties
Create or edit ~/.gradle/gradle.properties with your credentials:
# Sonatype OSSRH Credentials (from user token)
ossrhUsername=YOUR_SONATYPE_TOKEN_USERNAME
ossrhPassword=YOUR_SONATYPE_TOKEN_PASSWORD
# GPG Signing with gpg-agent (recommended)
# Use the full 40-character fingerprint or last 16 characters
signing.gnupg.keyName=ABCD1234EFGH5678
signing.gnupg.executable=gpg
Publishing Workflow
Snapshot Publishing
Publish development snapshots to Sonatype snapshots repository:
# Ensure version ends with -SNAPSHOT in gradle.properties
# VERSION=0.1.0-SNAPSHOT
# Validate and publish
./scripts/publish.sh snapshot
Snapshots are automatically available at:
- Repository:
https://s01.oss.sonatype.org/content/repositories/snapshots/ - Artifacts:
io.amichne:konditional-*:0.1.0-SNAPSHOT
Release Publishing
Publish stable releases to Maven Central:
# 1. Update VERSION in gradle.properties (remove -SNAPSHOT)
# VERSION=0.1.0
# 2. Validate everything is configured correctly
./scripts/validate-publish.sh
# 3. Publish to Sonatype staging
./scripts/publish.sh release
# 4. Login to Sonatype and release
# - Visit: https://s01.oss.sonatype.org
# - Navigate to: Staging Repositories
# - Find: io.amichne staging repository
# - Click: Close (wait for validation, 2-5 minutes)
# - Click: Release (publishes to Maven Central)
# 5. Wait for Maven Central propagation (10-30 minutes)
# - Verify: https://search.maven.org/search?q=g:io.amichne
Local Testing
Test publishing to local Maven repository:
./scripts/publish.sh local
# Artifacts are published to ~/.m2/repository/
# Use in other projects with: mavenLocal()
Gradle Tasks
The publishing setup provides these Gradle tasks:
# Publish to local Maven repository
./gradlew publishToMavenLocal
# Publish all modules to Sonatype
./gradlew publishAllPublicationsToSonatypeRepository
# Publish and automatically close/release staging repository
./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository
# Generate POM files for inspection
./gradlew generatePomFileForMavenPublication
Published Modules
The following modules are published to Maven Central:
| Module | Artifact ID | Description |
|---|---|---|
| Core | konditional-core | Core feature flag evaluation engine |
| Serialization | konditional-serialization | JSON serialization and configuration codec |
| Runtime | konditional-runtime | Runtime operations and snapshot loading |
| Observability | konditional-observability | Shadow evaluation and A/B testing |
JReleaser release metadata
Guarantee: JReleaser uses the same project metadata as Maven publishing (name, description, website, license,
author).
Mechanism: jreleaser.project is populated from gradle.properties in build.gradle.kts.
Boundary: Incorrect POM_* values result in incorrect release metadata; JReleaser does not validate content
semantics.
GitHub release flow
Guarantee: jreleaserFullRelease creates a GitHub release for the current project version when credentials are
present.
Mechanism: jreleaser.release.github points at the repository owner and project name; the Gradle version becomes
the tag.
Boundary: Missing credentials or missing tags stop the release step; no GitHub release is created.
Steps:
- Update
VERSIONingradle.propertiesto a release (non-SNAPSHOT) version. - Provide GitHub credentials via your JReleaser configuration (for example,
~/.jreleaser/config.properties). - Verify configuration with
./gradlew jreleaserConfig. - Run
./gradlew jreleaserFullReleaseto create the release.
Troubleshooting
GPG Agent Issues
# Restart gpg-agent
gpgconf --kill gpg-agent
gpgconf --launch gpg-agent
# Test signing
echo "test" | gpg --clearsign
# Check agent status
gpg-connect-agent 'getinfo version' /bye
Signing Failures
If you get "gpg: signing failed: No secret key":
- Verify key exists:
gpg --list-secret-keys - Check
signing.gnupg.keyNamematches your key ID - Ensure key hasn't expired:
gpg --list-keys
Sonatype Upload Failures
If upload fails with 401 Unauthorized:
- Verify credentials are correct in
~/.gradle/gradle.properties - Use user token, not JIRA password
- Ensure you have permission for
io.amichnegroup ID
POM Validation Errors
Common Sonatype validation errors:
- Missing Javadoc JAR: Ensure
java { withJavadocJar() }inbuild.gradle.kts - Missing Sources JAR: Ensure
java { withSourcesJar() }inbuild.gradle.kts - Invalid POM metadata: Check all
POM_*properties ingradle.properties - Missing GPG signature: Verify signing configuration