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"