diff --git a/.github/workflows/manual-release.yml b/.github/workflows/manual-release.yml
new file mode 100644
index 0000000..96ab317
--- /dev/null
+++ b/.github/workflows/manual-release.yml
@@ -0,0 +1,232 @@
+name: Manual Build Release to Maven Central
+
+on:
+ workflow_dispatch:
+
+jobs:
+ auto-release:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ packages: write
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0 # Need full history for git tags
+ token: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Get latest tag and increment version
+ id: version
+ run: |
+ # Configure git
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+
+ # Get the latest tag matching semantic versioning
+ LATEST_TAG=$(git tag -l "v[0-9]*.[0-9]*.[0-9]*" --sort=-v:refname | head -n 1)
+
+ if [ -z "$LATEST_TAG" ]; then
+ echo "No existing tags found, starting with v0.0.1"
+ NEW_VERSION="0.0.1"
+ NEW_TAG="v0.0.1"
+ else
+ echo "Latest tag: $LATEST_TAG"
+
+ # Extract version without 'v' prefix
+ VERSION=${LATEST_TAG#v}
+
+ # Split version into major.minor.patch
+ IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
+
+ # Strip any pre-release suffix from patch before incrementing (e.g., "0-alpha" -> "0")
+ PATCH=${PATCH%%-*}
+
+ # Increment patch version
+ PATCH=$((PATCH + 1))
+
+ NEW_VERSION="$MAJOR.$MINOR.$PATCH"
+ NEW_TAG="v$NEW_VERSION"
+ fi
+
+ echo "New version: $NEW_VERSION"
+ echo "New tag: $NEW_TAG"
+
+ # Export to GitHub env
+ echo "VERSION=$NEW_VERSION" >> $GITHUB_ENV
+ echo "TAG=$NEW_TAG" >> $GITHUB_ENV
+
+ # Create and push the tag
+ git tag -a "$NEW_TAG" -m "Auto-release $NEW_VERSION"
+ git push origin "$NEW_TAG"
+
+ echo "Created and pushed tag: $NEW_TAG"
+
+ - name: Set up JDK 21
+ uses: actions/setup-java@v4
+ with:
+ java-version: '21'
+ distribution: 'temurin'
+ cache: 'gradle'
+
+ - name: Setup Gradle
+ uses: gradle/actions/setup-gradle@v3
+
+ - name: Verify version matches tag
+ run: |
+ GRADLE_VERSION=$(./gradlew properties -q | grep "^version:" | awk '{print $2}')
+ echo "Gradle version: $GRADLE_VERSION"
+ echo "Expected version: $VERSION"
+ if [ "$GRADLE_VERSION" != "$VERSION" ]; then
+ echo "ERROR: Gradle version ($GRADLE_VERSION) does not match tag version ($VERSION)"
+ exit 1
+ fi
+
+ - name: Build and test
+ run: ./gradlew clean build test
+
+ - name: Import GPG key
+ env:
+ GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
+ GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
+ run: |
+ echo "$GPG_PRIVATE_KEY" | base64 -d | gpg --batch --import
+ # Test signing capability
+ echo "test" | gpg --clearsign --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" > /dev/null
+ echo "GPG key imported and tested successfully"
+
+ - name: Configure GPG for signing
+ run: |
+ # Configure gpg for non-interactive signing
+ echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf
+ echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf
+ gpg-connect-agent reloadagent /bye
+
+ - name: Publish to Maven Central
+ env:
+ CENTRAL_PORTAL_USERNAME: ${{ secrets.CENTRAL_PORTAL_USERNAME }}
+ CENTRAL_PORTAL_PASSWORD: ${{ secrets.CENTRAL_PORTAL_PASSWORD }}
+ GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
+ GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
+ run: |
+ # Export GPG_TTY for passphrase
+ export GPG_TTY=$(tty)
+
+ # Create gradle.properties with GPG credentials
+ cat > ~/.gradle/gradle.properties << EOF
+ signing.gnupg.keyName=$GPG_KEY_ID
+ signing.gnupg.passphrase=$GPG_PASSPHRASE
+ EOF
+
+ chmod 600 ~/.gradle/gradle.properties
+
+ # Publish to Maven Central via Central Portal
+ ./gradlew publishAggregationToCentralPortal \
+ --no-daemon \
+ --stacktrace
+
+ - name: Build distribution archives
+ run: |
+ ./gradlew :codehead-test:jar :codehead-test:javadocJar :codehead-test:sourcesJar
+ ./gradlew :database-test:jar :database-test:javadocJar :database-test:sourcesJar
+ ./gradlew :feature-flag:jar :feature-flag:javadocJar :feature-flag:sourcesJar
+ ./gradlew :feature-flag-ddb:jar :feature-flag-ddb:javadocJar :feature-flag-ddb:sourcesJar
+ ./gradlew :feature-flag-etcd:jar :feature-flag-etcd:javadocJar :feature-flag-etcd:sourcesJar
+ ./gradlew :feature-flag-metrics:jar :feature-flag-metrics:javadocJar :feature-flag-metrics:sourcesJar
+ ./gradlew :feature-flag-sql:jar :feature-flag-sql:javadocJar :feature-flag-sql:sourcesJar
+ ./gradlew :local-queue:jar :local-queue:javadocJar :local-queue:sourcesJar
+ ./gradlew :metrics:jar :metrics:javadocJar :metrics:sourcesJar
+ ./gradlew :metrics-declarative:jar :metrics-declarative:javadocJar :metrics-declarative:sourcesJar
+ ./gradlew :metrics-micrometer:jar :metrics-micrometer:javadocJar :metrics-micrometer:sourcesJar
+ ./gradlew :metrics-test:jar :metrics-test:javadocJar :metrics-test:sourcesJar
+ ./gradlew :oop-mock:jar :oop-mock:javadocJar :oop-mock:sourcesJar
+ ./gradlew :oop-mock-client:jar :oop-mock-client:javadocJar :oop-mock-client:sourcesJar
+ ./gradlew :oop-mock-common:jar :oop-mock-common:javadocJar :oop-mock-common:sourcesJar
+ ./gradlew :oop-mock-dynamodb:jar :oop-mock-dynamodb:javadocJar :oop-mock-dynamodb:sourcesJar
+ ./gradlew :oop-mock-tests:jar :oop-mock-tests:javadocJar :oop-mock-tests:sourcesJar
+ ./gradlew :smr:jar :smr:javadocJar :smr:sourcesJar
+ ./gradlew :smr-metrics:jar :smr-metrics:javadocJar :smr-metrics:sourcesJar
+ ./gradlew :smr-yml:jar :smr-yml:javadocJar :smr-yml:sourcesJar
+
+ - name: Create GitHub Release
+ uses: softprops/action-gh-release@v2
+ with:
+ tag_name: ${{ env.TAG }}
+ name: Release ${{ env.VERSION }}
+ body: |
+ ## Codehead Systems Libraries ${{ env.VERSION }}
+
+ **Auto-released** on merge to main.
+
+ ### Maven Central
+
+ ```xml
+
+ com.codeheadsystems
+ smr
+ ${{ env.VERSION }}
+
+ ```
+
+ ```gradle
+ implementation("com.codeheadsystems:smr:${{ env.VERSION }}")
+ ```
+
+ ### Modules Published
+ - `com.codeheadsystems:codehead-test:${{ env.VERSION }}`
+ - `com.codeheadsystems:database-test:${{ env.VERSION }}`
+ - `com.codeheadsystems:feature-flag:${{ env.VERSION }}`
+ - `com.codeheadsystems:feature-flag-ddb:${{ env.VERSION }}`
+ - `com.codeheadsystems:feature-flag-etcd:${{ env.VERSION }}`
+ - `com.codeheadsystems:feature-flag-metrics:${{ env.VERSION }}`
+ - `com.codeheadsystems:feature-flag-sql:${{ env.VERSION }}`
+ - `com.codeheadsystems:local-queue:${{ env.VERSION }}`
+ - `com.codeheadsystems:metrics:${{ env.VERSION }}`
+ - `com.codeheadsystems:metrics-declarative:${{ env.VERSION }}`
+ - `com.codeheadsystems:metrics-micrometer:${{ env.VERSION }}`
+ - `com.codeheadsystems:metrics-test:${{ env.VERSION }}`
+ - `com.codeheadsystems:oop-mock:${{ env.VERSION }}`
+ - `com.codeheadsystems:oop-mock-client:${{ env.VERSION }}`
+ - `com.codeheadsystems:oop-mock-common:${{ env.VERSION }}`
+ - `com.codeheadsystems:oop-mock-dynamodb:${{ env.VERSION }}`
+ - `com.codeheadsystems:oop-mock-tests:${{ env.VERSION }}`
+ - `com.codeheadsystems:smr:${{ env.VERSION }}`
+ - `com.codeheadsystems:smr-metrics:${{ env.VERSION }}`
+ - `com.codeheadsystems:smr-yml:${{ env.VERSION }}`
+
+ ### What's Changed
+ See commits since last release for details.
+
+ **Note:** Artifacts may take up to 2 hours to appear in Maven Central after release.
+ files: |
+ codehead-test/build/libs/*.jar
+ database-test/build/libs/*.jar
+ feature-flag/build/libs/*.jar
+ feature-flag-ddb/build/libs/*.jar
+ feature-flag-etcd/build/libs/*.jar
+ feature-flag-metrics/build/libs/*.jar
+ feature-flag-sql/build/libs/*.jar
+ local-queue/build/libs/*.jar
+ metrics/build/libs/*.jar
+ metrics-declarative/build/libs/*.jar
+ metrics-micrometer/build/libs/*.jar
+ metrics-test/build/libs/*.jar
+ oop-mock/build/libs/*.jar
+ oop-mock-client/build/libs/*.jar
+ oop-mock-common/build/libs/*.jar
+ oop-mock-dynamodb/build/libs/*.jar
+ oop-mock-tests/build/libs/*.jar
+ smr/build/libs/*.jar
+ smr-metrics/build/libs/*.jar
+ smr-yml/build/libs/*.jar
+ draft: false
+ prerelease: false
+ generate_release_notes: true
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Notify on failure
+ if: failure()
+ run: |
+ echo "::error::Auto-release failed! Check logs for details."
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..e1459a4
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,198 @@
+name: Tag Release to Maven Central
+
+on:
+ push:
+ tags:
+ - 'v[0-9]+.[0-9]+.[0-9]+'
+ - 'v[0-9]+.[0-9]+.[0-9]+-*'
+
+jobs:
+ release:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ packages: write
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0 # Need full history for git describe
+
+ - name: Validate tag format
+ run: |
+ TAG=${GITHUB_REF#refs/tags/}
+ echo "Tag: $TAG"
+ if ! [[ $TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
+ echo "ERROR: Tag must match semantic versioning (vX.Y.Z or vX.Y.Z-suffix)"
+ exit 1
+ fi
+ echo "VERSION=${TAG#v}" >> $GITHUB_ENV
+ echo "TAG=$TAG" >> $GITHUB_ENV
+
+ - name: Set up JDK 21
+ uses: actions/setup-java@v4
+ with:
+ java-version: '21'
+ distribution: 'temurin'
+ cache: 'gradle'
+
+ - name: Setup Gradle
+ uses: gradle/actions/setup-gradle@v3
+
+ - name: Verify version matches tag
+ run: |
+ GRADLE_VERSION=$(./gradlew properties -q | grep "^version:" | awk '{print $2}')
+ echo "Gradle version: $GRADLE_VERSION"
+ echo "Expected version: $VERSION"
+ if [ "$GRADLE_VERSION" != "$VERSION" ]; then
+ echo "ERROR: Gradle version ($GRADLE_VERSION) does not match tag version ($VERSION)"
+ exit 1
+ fi
+
+ - name: Build and test
+ run: ./gradlew clean build test
+
+ - name: Import GPG key
+ env:
+ GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
+ GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
+ run: |
+ echo "$GPG_PRIVATE_KEY" | base64 -d | gpg --batch --import
+ # Test signing capability
+ echo "test" | gpg --clearsign --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" > /dev/null
+ echo "GPG key imported and tested successfully"
+
+ - name: Configure GPG for signing
+ run: |
+ # Configure gpg for non-interactive signing
+ echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf
+ echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf
+ gpg-connect-agent reloadagent /bye
+
+ - name: Publish to Maven Central
+ env:
+ CENTRAL_PORTAL_USERNAME: ${{ secrets.CENTRAL_PORTAL_USERNAME }}
+ CENTRAL_PORTAL_PASSWORD: ${{ secrets.CENTRAL_PORTAL_PASSWORD }}
+ GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
+ GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
+ run: |
+ # Export GPG_TTY for passphrase
+ export GPG_TTY=$(tty)
+
+ # Create gradle.properties with GPG credentials
+ cat > ~/.gradle/gradle.properties << EOF
+ signing.gnupg.keyName=$GPG_KEY_ID
+ signing.gnupg.passphrase=$GPG_PASSPHRASE
+ EOF
+
+ chmod 600 ~/.gradle/gradle.properties
+
+ # Publish to Maven Central via Central Portal
+ ./gradlew publishAggregationToCentralPortal \
+ --no-daemon \
+ --stacktrace
+
+ - name: Build distribution archives
+ run: |
+ ./gradlew :codehead-test:jar :codehead-test:javadocJar :codehead-test:sourcesJar
+ ./gradlew :database-test:jar :database-test:javadocJar :database-test:sourcesJar
+ ./gradlew :feature-flag:jar :feature-flag:javadocJar :feature-flag:sourcesJar
+ ./gradlew :feature-flag-ddb:jar :feature-flag-ddb:javadocJar :feature-flag-ddb:sourcesJar
+ ./gradlew :feature-flag-etcd:jar :feature-flag-etcd:javadocJar :feature-flag-etcd:sourcesJar
+ ./gradlew :feature-flag-metrics:jar :feature-flag-metrics:javadocJar :feature-flag-metrics:sourcesJar
+ ./gradlew :feature-flag-sql:jar :feature-flag-sql:javadocJar :feature-flag-sql:sourcesJar
+ ./gradlew :local-queue:jar :local-queue:javadocJar :local-queue:sourcesJar
+ ./gradlew :metrics:jar :metrics:javadocJar :metrics:sourcesJar
+ ./gradlew :metrics-declarative:jar :metrics-declarative:javadocJar :metrics-declarative:sourcesJar
+ ./gradlew :metrics-micrometer:jar :metrics-micrometer:javadocJar :metrics-micrometer:sourcesJar
+ ./gradlew :metrics-test:jar :metrics-test:javadocJar :metrics-test:sourcesJar
+ ./gradlew :oop-mock:jar :oop-mock:javadocJar :oop-mock:sourcesJar
+ ./gradlew :oop-mock-client:jar :oop-mock-client:javadocJar :oop-mock-client:sourcesJar
+ ./gradlew :oop-mock-common:jar :oop-mock-common:javadocJar :oop-mock-common:sourcesJar
+ ./gradlew :oop-mock-dynamodb:jar :oop-mock-dynamodb:javadocJar :oop-mock-dynamodb:sourcesJar
+ ./gradlew :oop-mock-tests:jar :oop-mock-tests:javadocJar :oop-mock-tests:sourcesJar
+ ./gradlew :smr:jar :smr:javadocJar :smr:sourcesJar
+ ./gradlew :smr-metrics:jar :smr-metrics:javadocJar :smr-metrics:sourcesJar
+ ./gradlew :smr-yml:jar :smr-yml:javadocJar :smr-yml:sourcesJar
+
+ - name: Create GitHub Release
+ uses: softprops/action-gh-release@v2
+ with:
+ name: Release ${{ env.VERSION }}
+ body: |
+ ## Codehead Systems Libraries ${{ env.VERSION }}
+
+ **Auto-released** on merge to main.
+
+ ### Maven Central
+
+ ```xml
+
+ com.codeheadsystems
+ smr
+ ${{ env.VERSION }}
+
+ ```
+
+ ```gradle
+ implementation("com.codeheadsystems:smr:${{ env.VERSION }}")
+ ```
+
+ ### Modules Published
+ - `com.codeheadsystems:codehead-test:${{ env.VERSION }}`
+ - `com.codeheadsystems:database-test:${{ env.VERSION }}`
+ - `com.codeheadsystems:feature-flag:${{ env.VERSION }}`
+ - `com.codeheadsystems:feature-flag-ddb:${{ env.VERSION }}`
+ - `com.codeheadsystems:feature-flag-etcd:${{ env.VERSION }}`
+ - `com.codeheadsystems:feature-flag-metrics:${{ env.VERSION }}`
+ - `com.codeheadsystems:feature-flag-sql:${{ env.VERSION }}`
+ - `com.codeheadsystems:local-queue:${{ env.VERSION }}`
+ - `com.codeheadsystems:metrics:${{ env.VERSION }}`
+ - `com.codeheadsystems:metrics-declarative:${{ env.VERSION }}`
+ - `com.codeheadsystems:metrics-micrometer:${{ env.VERSION }}`
+ - `com.codeheadsystems:metrics-test:${{ env.VERSION }}`
+ - `com.codeheadsystems:oop-mock:${{ env.VERSION }}`
+ - `com.codeheadsystems:oop-mock-client:${{ env.VERSION }}`
+ - `com.codeheadsystems:oop-mock-common:${{ env.VERSION }}`
+ - `com.codeheadsystems:oop-mock-dynamodb:${{ env.VERSION }}`
+ - `com.codeheadsystems:oop-mock-tests:${{ env.VERSION }}`
+ - `com.codeheadsystems:smr:${{ env.VERSION }}`
+ - `com.codeheadsystems:smr-metrics:${{ env.VERSION }}`
+ - `com.codeheadsystems:smr-yml:${{ env.VERSION }}`
+
+ ### What's Changed
+ See commits since last release for details.
+
+ **Note:** Artifacts may take up to 2 hours to appear in Maven Central after release.
+ files: |
+ codehead-test/build/libs/*.jar
+ database-test/build/libs/*.jar
+ feature-flag/build/libs/*.jar
+ feature-flag-ddb/build/libs/*.jar
+ feature-flag-etcd/build/libs/*.jar
+ feature-flag-metrics/build/libs/*.jar
+ feature-flag-sql/build/libs/*.jar
+ local-queue/build/libs/*.jar
+ metrics/build/libs/*.jar
+ metrics-declarative/build/libs/*.jar
+ metrics-micrometer/build/libs/*.jar
+ metrics-test/build/libs/*.jar
+ oop-mock/build/libs/*.jar
+ oop-mock-client/build/libs/*.jar
+ oop-mock-common/build/libs/*.jar
+ oop-mock-dynamodb/build/libs/*.jar
+ oop-mock-tests/build/libs/*.jar
+ smr/build/libs/*.jar
+ smr-metrics/build/libs/*.jar
+ smr-yml/build/libs/*.jar
+ draft: false
+ prerelease: ${{ contains(env.VERSION, '-') }}
+ generate_release_notes: true
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Notify on failure
+ if: failure()
+ run: |
+ echo "::error::Release failed! Check logs for details."
diff --git a/README.md b/README.md
index 9fc6b22..61f17fa 100644
--- a/README.md
+++ b/README.md
@@ -15,9 +15,7 @@ Or to be more blunt, I'm lazy.
## Java support
-For JDK 17, use 3.0.x versions.
-
-For JDK 21, use 3.1.x versions.
+Requires JDK 21 or higher.
## Installation
diff --git a/RELEASING.md b/RELEASING.md
new file mode 100644
index 0000000..2510253
--- /dev/null
+++ b/RELEASING.md
@@ -0,0 +1,501 @@
+# Release Process
+
+This document describes how to create a new release of PretenderDB.
+
+## Prerequisites
+
+Before creating your first release, ensure you have:
+
+1. **Maven Central Account**: Account at https://central.sonatype.com with verified namespace for `io.github.pretenderdb`
+2. **GPG Key**: GPG key for signing artifacts, published to public keyservers
+3. **GitHub Secrets**: Five secrets configured in the repository settings
+
+## One-Time Setup
+
+### 1. Maven Central Account Setup (New Portal Method - 2024+)
+
+**Note:** As of 2024, Sonatype uses the Central Portal instead of the old JIRA-based system.
+
+1. **Register an Account**
+ - Visit https://central.sonatype.com
+ - Click "Sign In" in the top right
+ - Choose authentication method:
+ - **Recommended:** Sign in with GitHub (provides automatic namespace verification)
+ - Alternative: Create username/password account
+ - Provide a valid email address (required for support and notifications)
+
+2. **Verify Namespace for `io.github.pretenderdb`**
+
+ **For GitHub Organization namespaces:**
+ - Currently, `io.github.` namespaces are not automatically available
+ - You must contact Maven Central Support to request the namespace
+ - Email Central Support at: https://central.sonatype.org/support
+ - Provide:
+ - Desired namespace: `io.github.pretenderdb`
+ - GitHub organization: https://github.com/PretenderDB
+ - Proof of ownership (you are an owner/admin of the PretenderDB organization)
+ - They may provide a verification key and ask you to create a temporary public repository
+
+ **Alternative (if using personal account):**
+ - If you sign in with your personal GitHub account, `io.github.` is auto-verified
+ - However, this won't match the `io.github.pretenderdb` namespace
+
+3. **Generate User Token**
+ - Once your namespace is verified, visit https://central.sonatype.com
+ - Navigate to your Account page
+ - Click "Generate User Token"
+ - Save the generated **username** and **password** (this is your publishing token, not your login password)
+ - You'll use these credentials for Gradle/Maven publishing
+
+**Important Notes:**
+- The user token is different from your login credentials
+- These tokens are used specifically for publishing via API/build tools
+- Keep your token secure - treat it like a password
+
+### 2. GPG Key Setup
+
+Generate a GPG key if you don't have one:
+
+```bash
+# Generate key (choose RSA and RSA, 4096 bits)
+gpg --gen-key
+
+# List keys to get the key ID
+gpg --list-secret-keys --keyid-format=long
+# Output shows: sec rsa4096/ABCD1234EFGH5678 ...
+# The key ID is: ABCD1234EFGH5678
+
+# Export private key for GitHub secrets (base64 encoded)
+gpg --export-secret-keys YOUR_KEY_ID | base64 -w 0 > private-key.txt
+
+# Publish public key to keyservers (required for Maven Central)
+gpg --keyserver keyserver.ubuntu.com --send-keys YOUR_KEY_ID
+gpg --keyserver keys.openpgp.org --send-keys YOUR_KEY_ID
+
+# Verify key was published
+gpg --keyserver keyserver.ubuntu.com --recv-keys YOUR_KEY_ID
+```
+
+### 3. Configure GitHub Secrets
+
+Navigate to: https://github.com/PretenderDB/PretenderDB/settings/secrets/actions
+
+Add the following secrets:
+
+| Secret Name | Value | Description |
+|-------------|-------|-------------|
+| `CENTRAL_PORTAL_USERNAME` | User token username | Username from "Generate User Token" (NOT your login username) |
+| `CENTRAL_PORTAL_PASSWORD` | User token password | Password from "Generate User Token" (NOT your login password) |
+| `GPG_PRIVATE_KEY` | Content of private-key.txt | Base64-encoded GPG private key |
+| `GPG_PASSPHRASE` | Your GPG key passphrase | Passphrase for the GPG key |
+| `GPG_KEY_ID` | Last 8 chars of key ID | Short key ID (e.g., EFGH5678) |
+
+**Security Notes:**
+- `CENTRAL_PORTAL_USERNAME` and `CENTRAL_PORTAL_PASSWORD` are the **user token credentials** from https://central.sonatype.com, not your portal login credentials
+- Store the GPG key passphrase securely
+- Delete `private-key.txt` after uploading to GitHub secrets
+- Never commit credentials to the repository
+
+## Creating a Release
+
+### Step 1: Prepare Release
+
+1. Ensure the `main` branch is clean and all tests pass:
+
+```bash
+git checkout main
+git pull
+./gradlew clean build test
+```
+
+2. Review changes since last release:
+
+```bash
+# List changes since last tag
+git log --oneline v1.0.0..HEAD # Replace v1.0.0 with last tag
+
+# Or if this is the first release
+git log --oneline
+```
+
+3. Update documentation if needed:
+ - README.md
+ - CHANGELOG.md (if you maintain one)
+ - IMPLEMENTATION_SUMMARY.md
+
+### Step 2: Create and Push Tag
+
+1. Create a semantic version tag:
+
+```bash
+# For a regular release
+git tag -a v1.0.0 -m "Release version 1.0.0"
+
+# For a pre-release (RC, beta, alpha)
+git tag -a v1.0.0-rc.1 -m "Release candidate 1.0.0-rc.1"
+```
+
+2. Push the tag to GitHub:
+
+```bash
+git push origin v1.0.0
+```
+
+3. The GitHub Actions workflow will automatically:
+ - Validate the tag format (must match `vX.Y.Z` or `vX.Y.Z-suffix`)
+ - Extract the version from the tag
+ - Build and test all modules
+ - Sign artifacts with GPG
+ - Publish to Maven Central via Central Portal
+ - Automatically release the deployment
+ - Create a GitHub release with JAR artifacts
+
+### Step 3: Monitor Release
+
+1. Watch the GitHub Actions workflow at:
+ - https://github.com/PretenderDB/PretenderDB/actions
+
+2. The workflow takes approximately 10-15 minutes to complete
+
+3. If successful:
+ - GitHub release will be created at: https://github.com/PretenderDB/PretenderDB/releases
+ - Artifacts will be available in Maven Central within 15-120 minutes
+ - Pre-release flag will be set automatically for tags with suffixes
+
+### Step 4: Verify Publication
+
+1. Check GitHub release:
+ - https://github.com/PretenderDB/PretenderDB/releases/tag/v1.0.0
+
+2. Verify Maven Central (wait 15-120 minutes after release):
+ - https://repo1.maven.org/maven2/io/github/pretenderdb/
+ - Check that both published modules are present with correct version:
+ - `database-utils`
+ - `pretender`
+
+3. Test downloading the artifacts:
+
+```bash
+# Create a test project
+mkdir /tmp/test-pretenderdb && cd /tmp/test-pretenderdb
+
+# Create minimal build.gradle.kts
+cat > build.gradle.kts << 'EOF'
+plugins {
+ java
+}
+repositories {
+ mavenCentral()
+}
+dependencies {
+ implementation("io.github.pretenderdb:pretender:1.0.0")
+}
+EOF
+
+# Try to resolve
+gradle dependencies --configuration runtimeClasspath
+```
+
+### Step 5: Post-Release
+
+1. Announce the release (optional):
+ - Social media
+ - Mailing lists
+ - Discussion forums
+
+2. Update project status badges if applicable
+
+## Version Strategy
+
+PretenderDB follows [Semantic Versioning](https://semver.org/):
+
+- **Major (X.0.0)**: Breaking API changes, incompatible changes
+- **Minor (1.X.0)**: New features, backward-compatible additions
+- **Patch (1.0.X)**: Bug fixes, backward-compatible fixes
+- **Pre-release (1.0.0-rc.1)**: Release candidates, alphas, betas
+
+Examples:
+- `v1.0.0` - First stable release
+- `v1.1.0` - Added new features
+- `v1.1.1` - Bug fix
+- `v2.0.0` - Breaking changes
+- `v1.2.0-rc.1` - Release candidate
+
+**Both published modules share the same version number.**
+
+Note: The `pretender-integ` module is for integration testing only and is not published to Maven Central.
+
+## Troubleshooting
+
+### Release Failed: GPG Signing Error
+
+**Symptoms:**
+- Error message: "gpg: signing failed: No secret key"
+- Error message: "gpg: signing failed: Inappropriate ioctl for device"
+
+**Solutions:**
+1. Verify `GPG_PRIVATE_KEY` secret is correct (must be base64 encoded)
+2. Verify `GPG_PASSPHRASE` is correct
+3. Verify `GPG_KEY_ID` matches the key in the private key
+4. Ensure GPG public key is published to keyservers:
+ ```bash
+ gpg --keyserver keyserver.ubuntu.com --recv-keys YOUR_KEY_ID
+ ```
+
+### Release Failed: Maven Central Authentication
+
+**Symptoms:**
+- HTTP 401 Unauthorized
+- "Could not authenticate" errors
+- Authentication failures during publishing
+
+**Solutions:**
+1. Verify `CENTRAL_PORTAL_USERNAME` and `CENTRAL_PORTAL_PASSWORD` secrets contain the **user token credentials** (not your login credentials)
+2. Regenerate user token at https://central.sonatype.com (Account page → Generate User Token)
+3. Check your namespace `io.github.pretenderdb` is verified in Central Portal
+4. Verify account has publishing rights for `io.github.pretenderdb` namespace
+5. Try logging into https://central.sonatype.com to confirm your account is active
+
+### Release Failed: Version Mismatch
+
+**Symptoms:**
+- Error: "Gradle version does not match tag version"
+
+**Solutions:**
+1. Ensure tag format is exactly `vX.Y.Z` (e.g., `v1.0.0`)
+2. Check that `git describe --tags --exact-match HEAD` works locally:
+ ```bash
+ git tag v1.0.0
+ git describe --tags --exact-match HEAD # Should output: v1.0.0
+ ```
+
+### Release Failed: Tests Failed
+
+**Symptoms:**
+- Build failed during test phase
+
+**Solutions:**
+1. Run tests locally before tagging:
+ ```bash
+ ./gradlew clean build test
+ ```
+2. Fix any failing tests
+3. Delete the tag and re-tag after fixes:
+ ```bash
+ git tag -d v1.0.0
+ git push --delete origin v1.0.0
+ # Fix issues, then re-tag
+ git tag -a v1.0.0 -m "Release version 1.0.0"
+ git push origin v1.0.0
+ ```
+
+### Release Failed: Central Portal Validation
+
+**Symptoms:**
+- Deployment fails validation on Central Portal
+- Missing POM information or signatures
+
+**Solutions:**
+1. Check POM files are generated correctly:
+ ```bash
+ ./gradlew generatePomFileForMavenJavaPublication
+ find . -name "pom-default.xml" -exec cat {} \;
+ ```
+2. Verify signing is working locally:
+ ```bash
+ ./gradlew signMavenJavaPublication
+ find . -name "*.asc"
+ ```
+3. Check deployment status at https://central.sonatype.com under "Deployments"
+
+### Manual Release Recovery
+
+If the automated release fails after artifacts are uploaded:
+
+1. Log into https://central.sonatype.com
+2. Navigate to "Deployments" in the left sidebar
+3. Find your deployment (check status: Published, Failed, Pending, or Validated)
+4. Review any validation errors
+5. If validation passed but not published:
+ - The nmcp plugin should have auto-published
+ - Contact Central Support if stuck
+6. If validation failed:
+ - Note the errors
+ - Fix issues locally
+ - Delete the Git tag: `git push --delete origin v1.0.0`
+ - Re-run the release after fixes
+
+**Note:** The nmcp Gradle plugin handles the Central Portal publishing API automatically.
+
+### Rollback a Release
+
+**Important:** You cannot unpublish from Maven Central. Once released, artifacts are permanent.
+
+If you need to fix a released version:
+
+1. **For critical bugs:** Release a patch version (e.g., v1.0.1)
+2. **For breaking issues:** Mark the version as problematic in release notes
+3. **For security issues:** Release a hotfix immediately (e.g., v1.0.0-hotfix.1 or v1.0.1)
+
+To mark a GitHub release as problematic:
+1. Edit the release at https://github.com/PretenderDB/PretenderDB/releases
+2. Check "Set as a pre-release" or add a warning to the description
+3. Create a new release with fixes
+
+## Testing Locally
+
+Before creating a production release, test the configuration locally:
+
+### Test Version Extraction
+
+```bash
+# Create a test tag
+git tag -a v0.1.0-test -m "Test tag"
+
+# Verify version is extracted
+./gradlew properties | grep "^version:"
+# Should show: version: 0.1.0-test
+
+# Remove test tag
+git tag -d v0.1.0-test
+```
+
+### Test Publication Configuration
+
+```bash
+# Verify configuration
+./gradlew verifyPublishConfig
+
+# Expected output:
+# Group: io.github.pretenderdb
+# Artifact: pretender (or database-utils, pretender-integ)
+# Version: 0.0.1-SNAPSHOT
+# Is SNAPSHOT: true
+# Repository: snapshots
+```
+
+### Test Local Publishing
+
+```bash
+# Build and publish to local Maven repository
+./gradlew clean build publishToMavenLocal
+
+# Verify artifacts in ~/.m2/repository
+ls -R ~/.m2/repository/io/github/pretenderdb/
+
+# Expected structure:
+# ~/.m2/repository/io/github/pretenderdb/
+# ├── database-utils/
+# ├── pretender/
+# └── pretender-integ/
+```
+
+### Test Signing (Requires GPG Setup)
+
+```bash
+# Configure GPG locally in ~/.gradle/gradle.properties:
+cat >> ~/.gradle/gradle.properties << EOF
+signing.gnupg.keyName=YOUR_KEY_ID
+signing.gnupg.passphrase=YOUR_PASSPHRASE
+EOF
+
+# Test signing
+./gradlew signMavenJavaPublication
+
+# Check for signature files
+find . -name "*.asc"
+```
+
+## Dry-Run Release (Optional)
+
+For additional safety, you can create a manual dry-run workflow:
+
+1. Go to: https://github.com/PretenderDB/PretenderDB/actions
+2. Run "Release Dry Run" workflow (if implemented)
+3. Provide a test version like `0.0.1-dryrun`
+4. Verify the build completes successfully
+
+This tests the build and artifact generation without publishing.
+
+## Release Checklist
+
+Use this checklist when creating a release:
+
+- [ ] All tests pass locally: `./gradlew clean build test`
+- [ ] Documentation is up to date (README, CLAUDE.md, etc.)
+- [ ] Changes reviewed and ready for release
+- [ ] Semantic version chosen appropriately
+- [ ] Tag created with correct format: `vX.Y.Z`
+- [ ] Tag pushed to GitHub
+- [ ] GitHub Actions workflow succeeded
+- [ ] GitHub release created
+- [ ] Artifacts available in Maven Central (wait 15-120 minutes)
+- [ ] Artifacts downloadable and usable
+- [ ] Release announced (if applicable)
+
+## FAQ
+
+### How do I know which version number to use?
+
+Follow semantic versioning:
+- Breaking changes → increment major (2.0.0)
+- New features → increment minor (1.1.0)
+- Bug fixes → increment patch (1.0.1)
+
+### Can I publish SNAPSHOT versions?
+
+**Automatic:** SNAPSHOT versions are automatically published when pushing to the `main` branch. The `snapshot.yml` workflow handles this.
+
+**Manual:** You can also publish snapshots manually:
+```bash
+./gradlew publishAggregationToCentralSnapshots
+```
+
+Snapshots are available at:
+- https://central.sonatype.com/repository/maven-snapshots/io/github/pretenderdb/
+
+Users can depend on SNAPSHOT versions by adding the snapshots repository:
+```kotlin
+repositories {
+ maven("https://central.sonatype.com/repository/maven-snapshots/")
+ mavenCentral()
+}
+
+dependencies {
+ implementation("io.github.pretenderdb:pretender:0.0.1-SNAPSHOT")
+}
+```
+
+### How long does it take for artifacts to appear in Maven Central?
+
+Typically 15-30 minutes, but can take up to 2 hours. The CDN and search index update separately.
+
+### What if I create a tag by mistake?
+
+Delete the tag before the workflow completes:
+
+```bash
+# Delete local tag
+git tag -d v1.0.0
+
+# Delete remote tag
+git push --delete origin v1.0.0
+```
+
+If the workflow already completed, you cannot unpublish from Maven Central. Create a new patch version instead.
+
+### Can I automate releases further?
+
+Yes, you could add:
+- Automatic version bumping based on commit messages
+- Changelog generation
+- Release notes templates
+- Slack/Discord notifications
+
+However, manual tagging provides more control and prevents accidental releases.
+
+## Support
+
+For questions or issues with releases:
+- Create an issue: https://github.com/PretenderDB/PretenderDB/issues
+- Contact: ned.wolpert@gmail.com
diff --git a/build.gradle.kts b/build.gradle.kts
index dbe0370..682667b 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,11 +1,5 @@
-
-allprojects {
- group = "com.codeheadsystems"
- version = "3.1.0-SNAPSHOT"
+// Repositories needed for nmcp plugin runtime dependencies
+repositories {
+ mavenCentral()
+ gradlePluginPortal()
}
-plugins {
- id("nl.littlerobots.version-catalog-update") version "1.1.0"
-}
-
-// gradle jreleaserConfig
-// gradle clean build test publish jreleaserDeploy
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
index b8a2558..0187847 100644
--- a/buildSrc/build.gradle.kts
+++ b/buildSrc/build.gradle.kts
@@ -8,11 +8,6 @@ plugins {
}
repositories {
- mavenCentral()
+ // Use the plugin portal to apply community plugins in convention plugins.
gradlePluginPortal()
}
-
-dependencies {
- implementation(libs.gradleplugin.jreleaser)
- implementation("com.github.ben-manes:gradle-versions-plugin:0.52.0")
-}
diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts
index 51ccb40..31bf56a 100644
--- a/buildSrc/settings.gradle.kts
+++ b/buildSrc/settings.gradle.kts
@@ -5,13 +5,10 @@
*/
dependencyResolutionManagement {
+ // Reuse version catalog from the main build.
versionCatalogs {
- create("libs") {
- from(files("../gradle/libs.versions.toml"))
- }
- }
- repositories {
- gradlePluginPortal()
- mavenCentral()
+ create("libs", { from(files("../gradle/libs.versions.toml")) })
}
}
+
+rootProject.name = "buildSrc"
diff --git a/buildSrc/src/main/kotlin/buildlogic.jacoco-conventions.gradle.kts b/buildSrc/src/main/kotlin/buildlogic.jacoco-conventions.gradle.kts
new file mode 100644
index 0000000..1566f78
--- /dev/null
+++ b/buildSrc/src/main/kotlin/buildlogic.jacoco-conventions.gradle.kts
@@ -0,0 +1,15 @@
+/*
+ * This file was generated by the Gradle 'init' task.
+ */
+
+plugins {
+ // Apply the java Plugin to add support for Java.
+ java
+ jacoco
+}
+tasks.test {
+ finalizedBy(tasks.jacocoTestReport) // report is always generated after tests run
+}
+tasks.jacocoTestReport {
+ dependsOn(tasks.test) // tests are required to run before generating the report
+}
diff --git a/buildSrc/src/main/kotlin/buildlogic.java-application-conventions.gradle.kts b/buildSrc/src/main/kotlin/buildlogic.java-application-conventions.gradle.kts
new file mode 100644
index 0000000..dfb69ac
--- /dev/null
+++ b/buildSrc/src/main/kotlin/buildlogic.java-application-conventions.gradle.kts
@@ -0,0 +1,12 @@
+/*
+ * This file was generated by the Gradle 'init' task.
+ */
+
+plugins {
+ // Apply the common convention plugin for shared build configuration between library and application projects.
+ id("buildlogic.java-common-conventions")
+ id("buildlogic.jacoco-conventions")
+
+ // Apply the application plugin to add support for building a CLI application in Java.
+ application
+}
diff --git a/buildSrc/src/main/kotlin/buildlogic.java-common-conventions.gradle.kts b/buildSrc/src/main/kotlin/buildlogic.java-common-conventions.gradle.kts
index cfc7d34..2f0b5b5 100644
--- a/buildSrc/src/main/kotlin/buildlogic.java-common-conventions.gradle.kts
+++ b/buildSrc/src/main/kotlin/buildlogic.java-common-conventions.gradle.kts
@@ -5,15 +5,23 @@
plugins {
// Apply the java Plugin to add support for Java.
java
- id("com.github.ben-manes.versions")
+ idea
}
repositories {
// Use Maven Central for resolving dependencies.
+ mavenLocal()
mavenCentral()
+ gradlePluginPortal() // was jcenter() which is dying
+ google()
+
+ maven("https://oss.sonatype.org/content/repositories/snapshots/")
+ maven("https://oss.sonatype.org/content/repositories/releases/")
+ maven("https://s3-us-west-2.amazonaws.com/dynamodb-local/release/")
}
dependencies {
+
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
@@ -26,10 +34,16 @@ java {
}
tasks.named("test") {
- // Use JUnit Platform for unit tests.
useJUnitPlatform()
}
+// Ensure we have lint warnings displayed so we can fix or @SuppressWarnings("unchecked")
+tasks.withType().configureEach {
+ options.compilerArgs.add("-Xlint:unchecked")
+}
+
tasks.javadoc {
- (options as StandardJavadocDocletOptions).addBooleanOption("html5", true)
+ if (JavaVersion.current().isJava9Compatible) {
+ (options as StandardJavadocDocletOptions).addBooleanOption("html5", true)
+ }
}
diff --git a/buildSrc/src/main/kotlin/buildlogic.java-library-conventions.gradle.kts b/buildSrc/src/main/kotlin/buildlogic.java-library-conventions.gradle.kts
index ab305d8..9c4517c 100644
--- a/buildSrc/src/main/kotlin/buildlogic.java-library-conventions.gradle.kts
+++ b/buildSrc/src/main/kotlin/buildlogic.java-library-conventions.gradle.kts
@@ -5,6 +5,7 @@
plugins {
// Apply the common convention plugin for shared build configuration between library and application projects.
id("buildlogic.java-common-conventions")
+ id("buildlogic.jacoco-conventions")
// Apply the java-library plugin for API and implementation separation.
`java-library`
diff --git a/buildSrc/src/main/kotlin/buildlogic.java-publish-conventions.gradle.kts b/buildSrc/src/main/kotlin/buildlogic.java-publish-conventions.gradle.kts
deleted file mode 100644
index 614de97..0000000
--- a/buildSrc/src/main/kotlin/buildlogic.java-publish-conventions.gradle.kts
+++ /dev/null
@@ -1,75 +0,0 @@
-
-import org.jreleaser.model.Active
-plugins {
- `maven-publish`
- id("org.jreleaser")
-}
-
-publishing {
- publications {
- create("mavenJava") {
- from(components["java"])
- pom {
- name = "The Codehead Libraries - " + project.name
- description = "Libraries from the CodeHead projects " + project.description
- url = "https://github.com/wolpert/libraries"
- licenses {
- license {
- name = "The Apache License, Version 2.0"
- url = "http://www.apache.org/licenses/LICENSE-2.0.txt"
- }
- }
- developers {
- developer {
- id = "wolpert"
- name = "Ned Wolpert"
- email = "ned.wolpert@gmail.com"
- }
- }
- scm {
- connection = "scm:git:git://github.com/wolpert/libraries.git"
- developerConnection = "scm:git:ssh://github.com/wolpert/libraries.git"
- url = "https://github.com/wolpert/libraries/"
- }
- }
-
- }
- }
- repositories {
- maven {
- setUrl(layout.buildDirectory.dir("staging-deploy"))
- }
- }
-}
-
-jreleaser {
- gitRootSearch = true
- strict = false
- dryrun = false
- signing {
- active = Active.ALWAYS
- armored = true
- }
- release {
- github {
- enabled = true
- repoOwner = "wolpert"
- repoUrl = "https://github.com/wolpert/library"
- skipRelease = true
- skipTag = true
- sign = true
- overwrite = true
- }
- }
- deploy {
- maven {
- mavenCentral {
- register("sonatype") {
- active = Active.ALWAYS
- url = "https://central.sonatype.com/api/v1/publisher"
- stagingRepository("build/staging-deploy")
- }
- }
- }
- }
-}
diff --git a/buildSrc/src/main/kotlin/buildlogic.publish-conventions.gradle.kts b/buildSrc/src/main/kotlin/buildlogic.publish-conventions.gradle.kts
new file mode 100644
index 0000000..fab8214
--- /dev/null
+++ b/buildSrc/src/main/kotlin/buildlogic.publish-conventions.gradle.kts
@@ -0,0 +1,72 @@
+plugins {
+ `maven-publish`
+ signing
+}
+
+// Publication configuration for Maven Central via nmcp plugin
+// The nmcp settings plugin (configured in settings.gradle.kts) handles the actual
+// upload to Central Portal. This convention plugin defines the publication metadata.
+publishing {
+ publications {
+ create("mavenJava") {
+ from(components["java"])
+
+ // Set artifact coordinates
+ groupId = project.group.toString()
+ artifactId = project.name
+ version = project.version.toString()
+
+ pom {
+ // Module-specific name and description
+ // Override these in individual module build.gradle.kts if needed
+ name.set(project.findProperty("pomName")?.toString() ?: project.name)
+ description.set(project.findProperty("description")?.toString()
+ ?: "Libraries used by Codehead Systems projects")
+ url.set("https://github.com/codeheadsystems/libraries")
+
+ licenses {
+ license {
+ name.set("The Apache License, Version 2.0")
+ url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
+ }
+ }
+
+ developers {
+ developer {
+ id.set("wolpert")
+ name.set("Ned Wolpert")
+ email.set("ned.wolpert@gmail.com")
+ }
+ }
+
+ scm {
+ connection.set("scm:git:git://github.com/codeheadsystems/libraries.git")
+ developerConnection.set("scm:git:ssh://git@github.com:codeheadsystems/libraries.git")
+ url.set("https://github.com/codeheadsystems/libraries")
+ }
+ }
+ }
+ }
+ // Note: No repositories block needed - nmcp plugin handles upload to Central Portal
+}
+
+signing {
+ // Only sign if credentials are available (not required for local builds)
+ val signingRequired = project.hasProperty("signing.gnupg.keyName")
+ || System.getenv("GPG_KEY_ID") != null
+
+ isRequired = signingRequired && !version.toString().endsWith("SNAPSHOT")
+
+ useGpgCmd()
+ sign(publishing.publications["mavenJava"])
+}
+
+// Task to verify publication configuration
+tasks.register("verifyPublishConfig") {
+ doLast {
+ println("Group: ${project.group}")
+ println("Artifact: ${project.name}")
+ println("Version: ${project.version}")
+ println("Is SNAPSHOT: ${version.toString().endsWith("SNAPSHOT")}")
+ }
+}
diff --git a/codehead-test/build.gradle.kts b/codehead-test/build.gradle.kts
index 4ab96ec..3cf0d58 100644
--- a/codehead-test/build.gradle.kts
+++ b/codehead-test/build.gradle.kts
@@ -2,7 +2,7 @@ description = "General testing utilities"
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
diff --git a/database-test/build.gradle.kts b/database-test/build.gradle.kts
index ee717ea..19cc3c0 100644
--- a/database-test/build.gradle.kts
+++ b/database-test/build.gradle.kts
@@ -4,7 +4,7 @@ description = "Database testing utilities for DynamoDB"
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
dependencies {
diff --git a/feature-flag-ddb/build.gradle.kts b/feature-flag-ddb/build.gradle.kts
index 2ca9b20..c431efb 100644
--- a/feature-flag-ddb/build.gradle.kts
+++ b/feature-flag-ddb/build.gradle.kts
@@ -1,6 +1,6 @@
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
diff --git a/feature-flag-etcd/build.gradle.kts b/feature-flag-etcd/build.gradle.kts
index a64f9ed..c21f849 100644
--- a/feature-flag-etcd/build.gradle.kts
+++ b/feature-flag-etcd/build.gradle.kts
@@ -1,6 +1,6 @@
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
diff --git a/feature-flag-metrics/build.gradle.kts b/feature-flag-metrics/build.gradle.kts
index 861eac9..fb5a994 100644
--- a/feature-flag-metrics/build.gradle.kts
+++ b/feature-flag-metrics/build.gradle.kts
@@ -1,6 +1,6 @@
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
diff --git a/feature-flag-sql/build.gradle.kts b/feature-flag-sql/build.gradle.kts
index adbb460..129da94 100644
--- a/feature-flag-sql/build.gradle.kts
+++ b/feature-flag-sql/build.gradle.kts
@@ -1,6 +1,6 @@
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
dependencies {
diff --git a/feature-flag/build.gradle.kts b/feature-flag/build.gradle.kts
index cb6671a..1d17371 100644
--- a/feature-flag/build.gradle.kts
+++ b/feature-flag/build.gradle.kts
@@ -1,6 +1,6 @@
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
diff --git a/gradle.properties b/gradle.properties
index de01d49..328aff2 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -16,4 +16,11 @@
#
# gradle
#
-org.gradle.parallel=true
\ No newline at end of file
+org.gradle.parallel=true
+
+
+#
+# project identity
+#
+group=com.codeheadsystems
+version=3.1-SNAPSHOT
diff --git a/local-queue/build.gradle.kts b/local-queue/build.gradle.kts
index e4ff5a8..4bd27b4 100644
--- a/local-queue/build.gradle.kts
+++ b/local-queue/build.gradle.kts
@@ -1,7 +1,7 @@
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
dependencies {
diff --git a/metrics-declarative/build.gradle.kts b/metrics-declarative/build.gradle.kts
index bbddcd2..0ec9e48 100644
--- a/metrics-declarative/build.gradle.kts
+++ b/metrics-declarative/build.gradle.kts
@@ -1,6 +1,6 @@
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
id("io.freefair.aspectj.post-compile-weaving") version "9.2.0"
}
dependencies {
diff --git a/metrics-micrometer/build.gradle.kts b/metrics-micrometer/build.gradle.kts
index 2070bc4..009a3ad 100644
--- a/metrics-micrometer/build.gradle.kts
+++ b/metrics-micrometer/build.gradle.kts
@@ -1,6 +1,6 @@
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
dependencies {
implementation(project(":metrics"))
diff --git a/metrics-test/build.gradle.kts b/metrics-test/build.gradle.kts
index 2aecffd..6426573 100644
--- a/metrics-test/build.gradle.kts
+++ b/metrics-test/build.gradle.kts
@@ -1,6 +1,6 @@
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
dependencies {
implementation(project(":metrics"))
diff --git a/metrics/build.gradle.kts b/metrics/build.gradle.kts
index 284dd82..291e1bf 100644
--- a/metrics/build.gradle.kts
+++ b/metrics/build.gradle.kts
@@ -2,7 +2,7 @@
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
dependencies {
implementation(libs.slf4j.api)
diff --git a/oop-mock-client/build.gradle.kts b/oop-mock-client/build.gradle.kts
index 8159bf0..bed76da 100644
--- a/oop-mock-client/build.gradle.kts
+++ b/oop-mock-client/build.gradle.kts
@@ -1,6 +1,6 @@
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
dependencies {
implementation(project(":oop-mock-common"))
diff --git a/oop-mock-common/build.gradle.kts b/oop-mock-common/build.gradle.kts
index 41c54a8..57a5df5 100644
--- a/oop-mock-common/build.gradle.kts
+++ b/oop-mock-common/build.gradle.kts
@@ -1,6 +1,6 @@
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
dependencies {
implementation(libs.slf4j.api)
diff --git a/oop-mock-dynamodb/build.gradle.kts b/oop-mock-dynamodb/build.gradle.kts
index cde2561..931488b 100644
--- a/oop-mock-dynamodb/build.gradle.kts
+++ b/oop-mock-dynamodb/build.gradle.kts
@@ -1,7 +1,7 @@
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
dependencies {
diff --git a/oop-mock-tests/build.gradle.kts b/oop-mock-tests/build.gradle.kts
index f954a75..7651d50 100644
--- a/oop-mock-tests/build.gradle.kts
+++ b/oop-mock-tests/build.gradle.kts
@@ -1,7 +1,7 @@
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
dependencies {
diff --git a/oop-mock/build.gradle.kts b/oop-mock/build.gradle.kts
index 8159bf0..bed76da 100644
--- a/oop-mock/build.gradle.kts
+++ b/oop-mock/build.gradle.kts
@@ -1,6 +1,6 @@
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
dependencies {
implementation(project(":oop-mock-common"))
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 15b0531..5363b1e 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -5,9 +5,18 @@
* For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.9/userguide/multi_project_builds.html in the Gradle documentation.
*/
+pluginManagement {
+ repositories {
+ gradlePluginPortal()
+ mavenCentral()
+ }
+}
+
plugins {
// Apply the foojay-resolver plugin to allow automatic download of JDKs
- //id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0"
+ id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
+ // Nmcp plugin for publishing to Maven Central via Central Portal
+ id("com.gradleup.nmcp.settings") version "1.4.4"
}
rootProject.name = "libraries"
@@ -19,3 +28,32 @@ include(
"oop-mock","oop-mock-client","oop-mock-common","oop-mock-dynamodb","oop-mock-tests",
"feature-flag", "feature-flag-metrics", "feature-flag-test", "feature-flag-etcd", "feature-flag-ddb", "feature-flag-ddb-test", "feature-flag-sql", "feature-flag-integ"
)
+
+// Configure Central Portal publishing credentials
+nmcpSettings {
+ centralPortal {
+ username = System.getenv("CENTRAL_PORTAL_USERNAME") ?: providers.gradleProperty("centralPortalUsername").orNull
+ password = System.getenv("CENTRAL_PORTAL_PASSWORD") ?: providers.gradleProperty("centralPortalPassword").orNull
+ }
+}
+
+// Extract version from Git tag or use gradle.properties default
+gradle.beforeProject {
+ val gitVersion = providers.exec {
+ commandLine("git", "describe", "--tags", "--exact-match", "HEAD")
+ isIgnoreExitValue = true
+ }.standardOutput.asText.get().trim()
+
+ if (gitVersion.isNotEmpty() && gitVersion.startsWith("v")) {
+ // Remove 'v' prefix from tag (v1.0.0 -> 1.0.0)
+ // Validate semantic versioning format
+ val versionPattern = Regex("^v(\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.]+)?)$")
+ val matchResult = versionPattern.matchEntire(gitVersion)
+ if (matchResult != null) {
+ version = matchResult.groupValues[1]
+ logger.lifecycle("Using version from Git tag: $version")
+ } else {
+ logger.warn("Git tag '$gitVersion' does not match semantic versioning format (vX.Y.Z)")
+ }
+ }
+}
diff --git a/smr-metrics/build.gradle.kts b/smr-metrics/build.gradle.kts
index 2168aef..567ff8f 100644
--- a/smr-metrics/build.gradle.kts
+++ b/smr-metrics/build.gradle.kts
@@ -1,7 +1,7 @@
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
project.description = "Metrics integratino for the simplified state machine"
diff --git a/smr-yml/build.gradle.kts b/smr-yml/build.gradle.kts
index 5bbd1dc..612f2f9 100644
--- a/smr-yml/build.gradle.kts
+++ b/smr-yml/build.gradle.kts
@@ -1,7 +1,7 @@
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
project.description = "Provides YAML support for the simplified state machine"
diff --git a/smr/build.gradle.kts b/smr/build.gradle.kts
index ee411f7..9b4d51b 100644
--- a/smr/build.gradle.kts
+++ b/smr/build.gradle.kts
@@ -1,7 +1,7 @@
plugins {
id("buildlogic.java-library-conventions")
- id("buildlogic.java-publish-conventions")
+ id("buildlogic.publish-conventions")
}
project.description = "Simplified state machine"