Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.
This file provides guidance to AI coding agents (GitHub Copilot, Claude Code, etc.) when working with code in this repository.
helm-java is a Java client library that allows running Helm commands directly from Java code without requiring a separate Helm CLI installation. It uses JNA (Java Native Access) to call native Go Helm libraries compiled as shared libraries for multiple platforms (darwin-amd64, darwin-arm64, linux-amd64, linux-arm64, windows-amd64). The library provides a fluent API that mirrors Helm CLI commands like install, upgrade, uninstall, template, package, lint, repo, registry, etc.
# Clone and enter the project
git clone https://github.com/manusa/helm-java.git
cd helm-java
# Build native libraries first (required before Maven build)
# Native binaries must exist in native/out/ before Maven enforcer will pass
cd native
go build -buildmode=c-shared -o out/helm-darwin-10.12-amd64.dylib .
# (or the appropriate target for your platform)
cd ..
# Alternatively, use the Makefile for simplified builds
make build-current-platform # Builds native + Java for current platform only# Full build with tests (requires native binaries in native/out/)
./mvnw clean install
# Quick build without tests
./mvnw clean install -Dquickly
# Build specific module
./mvnw clean install -pl helm-java -am
# Build with javadoc and sources
./mvnw clean package
# Using Makefile targets
make build-java # Maven build only
make build-native # Build native library for current platform
make build-native-cross-platform # Build for all platforms (requires xgo)
make build-all # Cross-platform natives + Java build
make clean # Clean all build artifactsIMPORTANT: Tests use Testcontainers with KinD (Kubernetes in Docker) for integration tests. These tests spawn actual Kubernetes clusters and may take significant time.
# Run all tests
./mvnw test
# Run tests in the main helm-java module only
./mvnw test -pl helm-java
# Run a specific test class
./mvnw test -pl helm-java -Dtest=HelmInstallTest
# Run a specific test method
./mvnw test -pl helm-java -Dtest=HelmInstallTest#withName
# Run Go tests only
make test-go
# Or directly:
cd native && go clean -testcache && go test ./...NEVER CANCEL tests that involve Kubernetes operations - they may leave resources in an inconsistent state.
This is a library, not a standalone application. Use it in your Java project:
// Example: Create and install a chart
Helm helm = new Helm(Paths.get("path/to/chart"));
Release release = helm.install()
.withKubeConfig(kubeConfigPath)
.withName("my-release")
.call();helm-java/
├── helm-java/ # Main client library (public API)
│ └── src/
│ ├── main/java/com/marcnuri/helm/
│ │ ├── Helm.java # Main entry point
│ │ ├── *Command.java # Command implementations (InstallCommand, etc.)
│ │ └── *.java # Result types (Release, Repository, etc.)
│ └── test/java/ # JUnit 5 tests with Testcontainers
├── lib/
│ ├── api/ # JNA interface definitions (HelmLib, NativeLibrary)
│ ├── darwin-amd64/ # macOS Intel native library wrapper
│ ├── darwin-arm64/ # macOS Apple Silicon native library wrapper
│ ├── linux-amd64/ # Linux x64 native library wrapper
│ ├── linux-arm64/ # Linux ARM64 native library wrapper
│ └── windows-amd64/ # Windows x64 native library wrapper
├── native/ # Go source code that wraps Helm SDK
│ ├── main.go # CGO exports for JNA
│ ├── main_test.go # Go tests
│ ├── go.mod # Go module dependencies
│ └── out/ # Compiled native libraries (.dylib, .so, .dll)
├── scripts/ # Utility scripts
└── pom.xml # Parent POM (multi-module Maven project)
-
Fluent Builder Pattern: All commands use method chaining for configuration
helm.install() .withName("release") .withNamespace("namespace") .createNamespace() .waitReady() .call();
-
Native Bridge via JNA:
HelmLibinterface defines native method signatures; platform-specific modules contain the actual.dylib/.so/.dllfiles -
Lazy Initialization: Native library loaded on first use via
HelmLibHolder.INSTANCE -
Options Structs: Go code defines C structs that map to Java options classes in
lib/api
- Java 8 compatibility required (
maven.compiler.source=1.8) - Apache License 2.0 header on all source files
- Use AssertJ for assertions in tests
- No external mocking frameworks - use real implementations
- Standard Go formatting (
go fmt) - CGO exports with
//exportcomments - C structs defined in comments for JNA interop
- Command classes:
{Verb}Command.java(e.g.,InstallCommand,UpgradeCommand) - Test classes:
Helm{Feature}Test.java(e.g.,HelmInstallTest,HelmKubernetesTest) - JNI options:
{Operation}Options.java(e.g.,InstallOptions,LintOptions)
-
Black-box Testing: Tests verify behavior and observable outcomes, not implementation details. Test the public API only.
-
Avoid Mocks: Use real implementations and test infrastructure whenever possible. The project uses Testcontainers with KinD for Kubernetes integration tests.
-
Nested Test Structure: Use JUnit 5
@Nestedannotations with inner classes to organize tests by scenario. -
Scenario-Based Setup: Define common scenario in the outer
@BeforeEach; define specific conditions in nested class setup. -
Single Assertion Per Test: Each test block should assert ONE specific condition for clear failure identification.
class HelmFeatureTest {
private Helm helm;
@BeforeEach
void setUp(@TempDir Path tempDir) {
helm = Helm.create().withName("test").withDir(tempDir).call();
}
@Nested
class Install {
@Nested
class Valid {
@Test
void withName() {
final Release result = helm.install()
.clientOnly()
.withName("test")
.call();
assertThat(result)
.returns("test", Release::getName)
.returns("deployed", Release::getStatus);
}
}
@Nested
class Invalid {
@Test
void withMissingChart() {
final InstallCommand install = Helm.install("/tmp/nothing")
.clientOnly()
.withName("test");
assertThatThrownBy(install::call)
.message()
.contains("not found");
}
}
}
}HelmKubernetesTestuses KinD via Testcontainers@BeforeAllstarts the KinD cluster (expensive operation)- Tests use
kubeConfigFileorkubeConfigContentsfor cluster access - Use
@AfterEachto clean up releases to avoid test pollution
- Create options class in
lib/api:lib/api/src/main/java/com/marcnuri/helm/jni/{Operation}Options.java - Add C struct definition in
native/main.go - Implement Go function with
//exportinnative/main.go - Add method to
HelmLibinterface inlib/api - Create command class in
helm-java:helm-java/src/main/java/com/marcnuri/helm/{Operation}Command.java - Add factory method in
Helm.java - Write tests in
helm-java/src/test/java/com/marcnuri/helm/Helm{Feature}Test.java
cd native
# Make changes to main.go
go test ./... # Run Go tests first
# Build for your platform
go build -buildmode=c-shared -o out/helm-darwin-10.12-arm64.dylib .
cd ..
./mvnw test -pl helm-java
# Or use Makefile (auto-detects platform):
make build-nativeEnable debug output in commands:
helm.install().debug().withName("test").call();Ensure the native binaries exist in native/out/ before running Maven. The enforcer plugin requires all platform binaries to exist:
helm-darwin-10.12-amd64.dylibhelm-darwin-10.12-arm64.dylibhelm-linux-amd64.sohelm-linux-arm64.sohelm-windows-4.0-amd64.dll
To build only for your current platform (bypassing the enforcer check):
make build-current-platform
# This sets -Denforcer.skipRules=requireFilesExist automaticallyThe Surefire plugin is configured with KUBECONFIG=/dev/null to prevent tests from using your local kubeconfig. This is intentional.
Ensure Docker is running and has sufficient resources. KinD requires a working Docker environment. On macOS, increase Docker Desktop memory allocation if tests fail with OOM.
Check Go version (go version) matches go.mod requirement (Go 1.25.0+). Run go mod tidy to sync dependencies.
Building native libraries on Windows requires MinGW or similar CGO-compatible toolchain.