Skip to content

Commit 76de895

Browse files
committed
Merge upgrade branch: Sonatype Central Portal migration
Merge upgrade branch with complete Sonatype Central Portal migration: - Upgrade to Gradle 7.6.4 with updated dependencies - Migrate publishing to Central Portal with gradle-nexus plugin 2.0.0 - Add CLAUDE.md documentation This brings full Central Portal support with JDK 11+ build requirement while maintaining Java 8 compatibility for plugin users.
2 parents 30f37a4 + a6a7348 commit 76de895

File tree

3 files changed

+240
-98
lines changed

3 files changed

+240
-98
lines changed

CLAUDE.md

Lines changed: 103 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -4,110 +4,143 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
44

55
## Project Overview
66

7-
This is a Gradle settings plugin that enables build caching with a Hazelcast node as the backend. The plugin implements Gradle's BuildCacheService interface using Hazelcast's distributed map as storage.
8-
9-
**Key characteristics:**
10-
- Settings plugin (not a project plugin) - applied in `settings.gradle`, not `build.gradle`
11-
- Disables local cache by default since Hazelcast serves as both local and remote cache
12-
- Supports multiple Hazelcast hosts via comma-separated host list
13-
- Uses Hazelcast client (not embedded node) to connect to external Hazelcast cluster
7+
This is a Gradle settings plugin that enables build caching using Hazelcast as the cache backend. The plugin allows Gradle builds to store and retrieve task outputs from a distributed Hazelcast cluster, speeding up builds across multiple machines or build agents.
148

159
## Build Commands
1610

1711
```bash
1812
# Build the plugin
1913
./gradlew build
2014

21-
# Run tests (includes integration tests with embedded Hazelcast)
15+
# Run tests
2216
./gradlew test
2317

24-
# Run single test class
25-
./gradlew test --tests "IntegrationTest"
26-
27-
# Run single test method
28-
./gradlew test --tests "IntegrationTest.no task is re-executed when inputs are unchanged"
18+
# Clean build artifacts
19+
./gradlew clean
2920

30-
# Check for dependency vulnerabilities
21+
# Check for dependency vulnerabilities (OWASP)
3122
./gradlew dependencyCheckAnalyze
3223

3324
# Check for dependency updates
34-
./gradlew dependenceUpdates
25+
./gradlew dependenceiesUpdates
26+
```
3527

36-
# Publish to local Maven repo
28+
## Publishing Commands
29+
30+
```bash
31+
# Publish to local Maven repository for testing
3732
./gradlew publishToMavenLocal
3833

39-
# Release (tags, publishes to Sonatype)
40-
./gradlew release
34+
# Release workflow (requires credentials and JDK 11+)
35+
./gradlew release # This creates a git tag, publishes, and closes the staging repository
36+
37+
# Publish manually to Central Portal (for testing)
38+
./gradlew publishToSonatype
39+
40+
# Close staging repository (after publishToSonatype)
41+
./gradlew closeSonatypeStagingRepository
42+
43+
# Release to Maven Central (manually after closing - requires separate invocation)
44+
./gradlew findSonatypeStagingRepository releaseSonatypeStagingRepository
45+
46+
# All-in-one manual publish and close
47+
./gradlew publishToSonatype closeSonatypeStagingRepository
4148
```
4249

50+
The release process is automated using the `net.researchgate.release` plugin. After release, the `afterReleaseBuild` task automatically publishes and closes the staging repository using gradle-nexus/publish-plugin 2.0.0. You must then manually release via the Portal UI at [central.sonatype.com/publishing/deployments](https://central.sonatype.com/publishing/deployments) or run `releaseSonatypeStagingRepository` separately.
51+
4352
## Architecture
4453

4554
### Core Components
4655

47-
1. **HazelcastPlugin** (`src/main/java/.../HazelcastPlugin.java`)
48-
- Entry point: implements `Plugin<Settings>`
49-
- Registers `HazelcastBuildCacheServiceFactory` with Gradle's build cache configuration
50-
- Disables local cache and configures Hazelcast as remote cache
51-
- Factory creates `MapBasedBuildCacheService` backed by Hazelcast IMap
56+
**HazelcastPlugin** (`src/main/java/com/github/sinwe/gradle/caching/hazelcast/HazelcastPlugin.java`)
57+
- Entry point - implements Gradle's `Plugin<Settings>` interface
58+
- Registers `HazelcastBuildCache` as a build cache service via `HazelcastBuildCacheServiceFactory`
59+
- Automatically disables local cache and configures Hazelcast as the remote cache
60+
- The factory creates a Hazelcast client connection and wraps the Hazelcast IMap in Gradle's `MapBasedBuildCacheService`
5261

53-
2. **HazelcastBuildCache** (`src/main/java/.../HazelcastBuildCache.java`)
54-
- Configuration object for the cache backend
55-
- Properties: `host` (supports comma-separated list), `port`, `name`
56-
- Reads system properties as defaults (can be overridden in settings.gradle):
57-
- `com.github.sinwe.gradle.caching.hazelcast.host` (default: 127.0.0.1)
58-
- `com.github.sinwe.gradle.caching.hazelcast.port` (default: 5701)
59-
- `com.github.sinwe.gradle.caching.hazelcast.name` (default: gradle-task-cache)
62+
**HazelcastBuildCache** (`src/main/java/com/github/sinwe/gradle/caching/hazelcast/HazelcastBuildCache.java`)
63+
- Configuration class extending `AbstractBuildCache`
64+
- Defines three configurable properties: `host`, `port`, and `name`
65+
- Supports system property overrides: `com.github.sinwe.gradle.caching.hazelcast.{host,port,name}`
66+
- Default values: host=`127.0.0.1`, port=`5701`, name=`gradle-task-cache`
67+
- The `host` property supports comma-separated values for multiple Hazelcast nodes
6068

61-
3. **HazelcastBuildCacheServiceFactory** (inner class in HazelcastPlugin)
62-
- Creates Hazelcast client with configured addresses (host:port)
63-
- Returns `MapBasedBuildCacheService` using Hazelcast's distributed map
64-
- Gradle's `MapBasedBuildCacheService` handles serialization and key-value storage
69+
### Key Design Decisions
6570

66-
### Test Structure
71+
1. **Settings Plugin**: This is a settings plugin (not a project plugin), so it's applied in `settings.gradle` rather than `build.gradle`. This is required because build cache configuration happens at settings evaluation time.
6772

68-
- **IntegrationTest.groovy**: Spock integration tests using GradleRunner
69-
- **HazelcastService.java**: JUnit rule that starts/stops embedded Hazelcast for tests
70-
- Tests verify caching behavior: cache hits, cache misses, task outcomes
71-
- Uses custom port (5710) to avoid conflicts with running Hazelcast instances
73+
2. **MapBasedBuildCacheService**: The plugin leverages Gradle's built-in `MapBasedBuildCacheService` which wraps any `java.util.Map` implementation. The Hazelcast `IMap` is a distributed map that naturally fits this pattern.
7274

73-
## Project Configuration
75+
3. **Client Connection**: Uses Hazelcast client mode (not embedded), connecting to an external Hazelcast cluster. The connection is established once per build when the factory creates the service.
7476

75-
- **Java 8 compatibility** (sourceCompatibility/targetCompatibility = 1.8)
76-
- **Gradle 7.6.4** with Java 8+ runtime
77-
- **Dependencies managed in versions.gradle**
78-
- **Hazelcast 3.10.2** (client and full distribution for tests)
77+
4. **Multiple Hosts**: The factory parses the comma-separated host list and appends the port to each host address before configuring the Hazelcast client's network config.
7978

80-
## Publishing
79+
## Testing
8180

82-
The plugin publishes to:
83-
1. **Gradle Plugin Portal** (via `repo.gradle.org/gradle` with Artifactory)
84-
2. **Maven Central** (via Central Portal at `central.sonatype.com`)
81+
**IntegrationTest.groovy** (`src/test/groovy/com/github/sinwe/gradle/caching/hazelcast/IntegrationTest.groovy`)
82+
- Uses Gradle TestKit to run actual Gradle builds
83+
- Tests verify tasks are cached and retrieved correctly
84+
- The `HazelcastService` JUnit rule starts an embedded Hazelcast instance on port 5710 for testing
8585

86-
Release process uses `net.researchgate.release` plugin:
87-
- Creates git tag
88-
- Uses `publish` task to upload to Maven Central Portal
89-
- Requires signing for non-SNAPSHOT versions
86+
**HazelcastService.java** (`src/test/groovy/com/github/sinwe/gradle/caching/hazelcast/HazelcastService.java`)
87+
- JUnit `ExternalResource` that manages a test Hazelcast instance lifecycle
88+
- Configures Hazelcast with multicast disabled (using the specified port only)
89+
- Automatically starts before each test and shuts down after
9090

91-
### Credentials
91+
## Dependencies Management
9292

93-
For publishing to Maven Central Portal, set these properties in `~/.gradle/gradle.properties`:
94-
```properties
95-
mavenCentralUsername=<your-token-username>
96-
mavenCentralPassword=<your-token-password>
97-
```
93+
Dependencies are centralized in `versions.gradle` using `ext.libraries` map. When updating dependencies:
94+
- Update version numbers in the `ext` block at the top of `versions.gradle`
95+
- Reference them via the `libraries` map in `build.gradle`
9896

99-
For Artifactory (Gradle internal repo):
100-
```properties
101-
artifactory_user=<your-username>
102-
artifactory_password=<your-password>
103-
```
97+
Key dependencies:
98+
- `hazelcast-client`: Used by the plugin to connect to Hazelcast
99+
- `hazelcast`: Used only in tests for the embedded instance
100+
- Gradle plugin dependencies: release plugin, OWASP dependency check, version checker
101+
102+
## Gradle Configuration
103+
104+
The project uses:
105+
- Gradle 6.9.4 (via Gradle wrapper)
106+
- Java 8 source/target compatibility (requires JDK 11+ for building due to gradle-nexus/publish-plugin 2.0.0)
107+
- `java-gradle-plugin` for automatic plugin metadata generation
108+
- Plugin ID: `com.github.sinwe.gradle.caching.hazelcast`
109+
- Group: `com.github.sinwe.gradle.caching.hazelcast`
110+
- Artifact: `gradle-hazelcast-plugin`
111+
112+
## Publishing Configuration
113+
114+
The project uses the `io.github.gradle-nexus.publish-plugin` (version 2.0.0) for publishing to Sonatype Central Portal.
115+
116+
Publications go to:
117+
- **Releases/Staging**: `https://ossrh-staging-api.central.sonatype.com/service/local/`
118+
- **Snapshots**: `https://central.sonatype.com/repository/maven-snapshots/`
119+
120+
### Authentication Setup
121+
122+
Credentials are sourced from (in order of precedence):
123+
1. Gradle properties in `~/.gradle/gradle.properties`:
124+
- `sonatypeUsername` - User token username from central.sonatype.com/account
125+
- `sonatypePassword` - User token password from central.sonatype.com/account
126+
2. Environment variables:
127+
- `ORG_GRADLE_PROJECT_sonatypeUsername`
128+
- `ORG_GRADLE_PROJECT_sonatypePassword`
129+
130+
**Important**: Central Portal tokens are different from legacy OSSRH tokens. Generate new tokens at https://central.sonatype.com/account
131+
132+
### Publication Artifacts
133+
134+
Artifacts include:
135+
- Main JAR (from Java component)
136+
- Sources JAR
137+
- Javadoc JAR
104138

105-
Note: OSSRH (oss.sonatype.org) was shut down on June 30, 2025. All publishing now goes through Central Portal.
139+
Signing is required only for release versions (non-SNAPSHOT).
106140

107-
## Important Implementation Details
141+
### Migration Notes
108142

109-
- Plugin must be applied in `settings.gradle` (not `build.gradle`) because it configures build cache during settings evaluation
110-
- Hazelcast client connection is created once per build, map name identifies the cache
111-
- Multiple hosts support allows failover: "host1,host2,host3" all use same port
112-
- MapBasedBuildCacheService is Gradle's built-in implementation - we just provide the Map
113-
- Local cache disabled to avoid double-caching (Hazelcast already provides fast access)
143+
This project has been migrated from the legacy OSSRH system to Sonatype Central Portal (as of 2025). The OSSRH service was sunset on June 30, 2025. Key changes:
144+
- New authentication tokens required from central.sonatype.com
145+
- Publishing workflow now uses staging repositories with explicit close/release steps
146+
- Publication timeline: ~15 minutes after release for artifacts to appear on Maven Central

0 commit comments

Comments
 (0)