Skip to content

Contributing Guide

We welcome contributions to the Neo4j Enterprise Operator! This guide provides comprehensive instructions for contributing code, documentation, and improvements to make the operator better for everyone.

🚀 Quick Start for Contributors

Prerequisites

  • Go: Version 1.24+ for development
  • Docker: Container runtime for building images
  • kubectl: Kubernetes CLI tool
  • kind: Kubernetes in Docker for local clusters
  • git: Version control

1. Repository Setup

# Fork the repository on GitHub, then clone your fork
git clone https://github.com/<your-username>/neo4j-kubernetes-operator.git
cd neo4j-kubernetes-operator

# Add upstream remote for pulling updates
git remote add upstream https://github.com/neo4j-partners/neo4j-kubernetes-operator.git

# Create a feature branch
git checkout -b feature/my-awesome-feature

2. Development Environment Setup

# Generate CRDs and Go code
make manifests generate

# Create development Kind cluster (includes cert-manager for TLS features)
make dev-cluster

# Deploy the operator to development cluster (REQUIRED - in-cluster only)
make operator-setup

Benefits of this setup: - Fast iteration: No container rebuilds needed - Debug support: Full debugger capabilities - Live reloading: Operator restarts when code changes - Direct logs: Console output for immediate feedback

3. Make Your Changes

The operator follows a well-defined architecture. Key areas for contributions:

Controllers (internal/controller/): - Neo4jEnterpriseCluster controller for clustered deployments - Neo4jEnterpriseStandalone controller for single-node deployments - Database, Plugin, Backup, and Restore controllers

Custom Resources (api/v1beta1/): - CRD type definitions for all Neo4j resources - Validation tags and documentation

Resource Builders (internal/resources/): - Kubernetes resource generation logic - ConfigMap, Service, and StatefulSet builders

Validation Framework (internal/validation/): - Input validation and recommendations - Error handling and user guidance

4. Testing Your Changes

# Run unit tests (no cluster required)
make test-unit

# Run integration tests (requires test cluster)
make test-integration

# Run specific controller tests
go test ./internal/controller -run TestClusterReconciler -v

# Test with example deployments
kubectl apply -f examples/clusters/minimal-cluster.yaml
kubectl apply -f examples/standalone/single-node-standalone.yaml

5. Submit Your Contribution

# Run code quality checks
make fmt lint vet

# Commit using conventional commits
git add .
git commit -m "feat: add server role constraints for topology optimization"

# Push and create pull request
git push origin feature/my-awesome-feature
# Create PR via GitHub UI

📝 Development Guidelines

Code Organization

Follow the established patterns:

  1. Controller Pattern: Use the standard Kubernetes controller pattern with proper reconciliation
  2. Builder Pattern: Use resource builders in internal/resources/ for clean separation
  3. Validation Framework: Add validation in internal/validation/ with clear error messages
  4. Testing Strategy: Write unit, integration, and manual tests for new features

Current Architecture (August 2025)

Understand the current architecture before making changes:

Server-Based Architecture

  • Clusters: Use {cluster-name}-server StatefulSet with self-organizing servers
  • Standalone: Use {standalone-name} StatefulSet (single replica)
  • Centralized Backup: Single {cluster-name}-backup-0 StatefulSet per cluster

Dual Deployment Support

  • Neo4jEnterpriseCluster: High-availability clustered deployments (2+ servers)
  • Neo4jEnterpriseStandalone: Single-node deployments for development/testing
  • Plugin System: Supports both deployment types with automatic detection

Code Style Guidelines

Go Code Standards

# Format code
make fmt

# Run linter (strict mode for contributions)
make lint

# Run go vet
make vet

# Security scan
make security

Best Practices

  1. Error Handling: Always handle errors gracefully with proper context
  2. Logging: Use structured logging with appropriate log levels
  3. Resource Management: Use controllerutil.CreateOrUpdate with retry logic
  4. Finalizers: Implement proper cleanup with finalizer handling
  5. Status Updates: Update resource status to reflect current state
  6. Validation: Add comprehensive validation for user inputs

Testing Requirements

Unit Tests

  • Location: Alongside source code (*_test.go)
  • Coverage: Aim for >80% coverage on controller logic
  • Patterns: Use table-driven tests for multiple scenarios
func TestGetStatefulSetName(t *testing.T) {
    tests := []struct {
        name       string
        deployment *DeploymentInfo
        expected   string
    }{
        {
            name: "cluster deployment",
            deployment: &DeploymentInfo{
                Type: "cluster",
                Name: "my-cluster",
            },
            expected: "my-cluster-server",
        },
        // Add more test cases...
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            result := getStatefulSetName(tt.deployment)
            assert.Equal(t, tt.expected, result)
        })
    }
}

Integration Tests

  • Location: test/integration/
  • Framework: Ginkgo/Gomega BDD-style testing
  • Requirements: Use 5-minute timeout and proper cleanup
  • Resources: Minimal CPU (100m), adequate memory (1.5Gi for Neo4j Enterprise)
var _ = Describe("Neo4jPlugin Integration Tests", func() {
    const (
        timeout  = time.Second * 300  // 5-minute timeout for CI
        interval = time.Second * 5
    )

    Context("Plugin Installation", func() {
        It("Should install APOC plugin on cluster", func() {
            // Test implementation with proper cleanup
        })
    })
})

Documentation Requirements

Code Documentation

  • Public Functions: Document all exported functions and types
  • Complex Logic: Explain non-obvious code with comments
  • API Changes: Update relevant API documentation

User Documentation

For user-facing features, update: - Examples: Add example configurations in examples/ - User Guide: Update relevant user guide sections - API Reference: Update CRD documentation if API changes

🔄 Development Workflow

Branch Strategy

  1. Feature Branches: Create feature branches from main
  2. Naming Convention: feature/short-description or fix/issue-description
  3. Single Purpose: One feature or fix per branch
  4. Regular Updates: Keep branches updated with upstream changes

Pull Request Process

Before Submitting

  1. Code Quality: Run make fmt lint vet locally
  2. Tests: Ensure all tests pass with make test
  3. Documentation: Update relevant documentation
  4. Examples: Add or update examples if needed

PR Description Template

## Description
Brief description of changes and motivation.

## Type of Change
- [ ] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that causes existing functionality to change)
- [ ] Documentation update

## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests added/updated
- [ ] Manual testing completed
- [ ] Examples tested

## Checklist
- [ ] Code follows project style guidelines
- [ ] Self-review completed
- [ ] Documentation updated
- [ ] Tests added for new functionality
- [ ] All tests pass

Review Process

  1. Automated Checks: CI/CD runs automated tests and linting
  2. Code Review: Maintainers review code for quality and design
  3. Integration Testing: Changes tested against integration suite
  4. Documentation Review: Documentation changes reviewed for accuracy

Git Commit Messages

Follow Conventional Commits specification:

# Feature additions
git commit -m "feat: add server role constraints for topology optimization"

# Bug fixes
git commit -m "fix: resolve resource version conflict during cluster formation"

# Documentation updates
git commit -m "docs: update contributing guide with current architecture"

# Breaking changes
git commit -m "feat!: change topology field structure for server-based architecture"

Format: <type>[optional scope]: <description>

Types: - feat: New features - fix: Bug fixes - docs: Documentation changes - style: Code style changes (no logic changes) - refactor: Code refactoring - test: Test additions or modifications - chore: Maintenance tasks

🐛 Bug Reports and Feature Requests

Reporting Bugs

When reporting bugs, include:

  1. Environment Information:
  2. Kubernetes version
  3. Neo4j version
  4. Operator version
  5. Cloud provider (if applicable)

  6. Reproduction Steps:

  7. Minimal example that reproduces the issue
  8. Expected vs actual behavior
  9. Error messages and logs

  10. Relevant Resources:

  11. YAML configurations (sanitized)
  12. Operator logs
  13. Neo4j logs (if applicable)

Feature Requests

  1. Use Case: Describe the problem you're trying to solve
  2. Proposed Solution: Suggest how the feature might work
  3. Alternatives: Consider alternative solutions
  4. Impact: Describe who would benefit from this feature

🏗️ Advanced Development

Adding New CRDs

When adding new Custom Resource Definitions:

  1. Define Types (api/v1beta1/):

    # Create new CRD type file
    touch api/v1beta1/mynewresource_types.go
    

  2. Create Controller (internal/controller/):

    # Generate controller scaffold
    kubebuilder create api --group neo4j --version v1beta1 --kind MyNewResource
    

  3. Add Validation (internal/validation/):

  4. Implement validation logic
  5. Add to validation framework

  6. Add RBAC markers (no manual config/rbac/ edits needed):

    //+kubebuilder:rbac:groups=neo4j.neo4j.com,resources=mynewresources,verbs=get;list;watch;create;update;patch;delete
    //+kubebuilder:rbac:groups=neo4j.neo4j.com,resources=mynewresources/status,verbs=get;update;patch
    //+kubebuilder:rbac:groups=neo4j.neo4j.com,resources=mynewresources/finalizers,verbs=update
    
    These flow through make manifests into config/rbac/role.yaml and from there into the Helm chart's ClusterRole via make helm-sync-rbac.

  7. Add a sample manifest (used by the OperatorHub CSV's alm-examples):

    # config/samples/neo4j_v1beta1_mynewresource.yaml
    

  8. Wire the controller into cmd/main.go (production + development controller maps + cache config).

  9. Add a description to the artifacthub-crds map: Edit scripts/helm-sync-artifacthub-crds.sh and add a case "$kind" in row for your new Kind. The script fails loudly if any CRD lacks a description, so you can't forget.

  10. Run the full sync pipeline (single command):

    make ship-prep
    
    This regenerates: CRDs, RBAC, DeepCopy, kustomize lists, editor/viewer roles, the Helm chart's CRDs and ClusterRole, the ArtifactHub annotation, and the OperatorHub bundle. It also lints the Helm chart and verifies CSV coverage.

  11. Add documentation:

  12. API reference: docs/api_reference/<kind>.md (mirror an existing one).
  13. User guide entry if the resource introduces a new workflow.
  14. Update the CRD list in README.md and docs/README.md.

  15. Add tests:

    • Unit tests for validators and any custom logic.
    • Integration tests in test/integration/ (one Ginkgo file per CRD; mirror test/integration/neo4juser_test.go).
    • Add cleanup logic to cleanupCustomResourcesInNamespace in test/integration/integration_suite_test.go.

CI's check-drift job runs make sync-all bundle and fails the PR if anything is out of date — this enforces step 8.

Performance Considerations

Controller Optimization: - Use client.Reader for read-only operations - Implement proper caching strategies - Minimize API calls with efficient resource queries - Use controllerutil.CreateOrUpdate for idempotent operations

Resource Management: - Set appropriate resource requests/limits - Use owner references for automatic cleanup - Implement proper finalizer handling

Debugging Tips

Local Debugging

# Deploy operator with debug logging to development cluster
make operator-setup
# Check operator logs with debug verbosity
kubectl patch -n neo4j-operator-dev deployment/neo4j-operator-controller-manager \
  -p '{"spec":{"template":{"spec":{"containers":[{"name":"manager","args":["--mode=dev","--zap-log-level=debug"]}]}}}}'

# Check operator logs
kubectl logs -l app.kubernetes.io/name=neo4j-operator -f

# Examine resource status
kubectl describe neo4jenterprisecluster my-cluster

VS Code Debug Configuration

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Launch Operator",
      "type": "go",
      "request": "launch",
      "mode": "debug",
      "program": "${workspaceFolder}/cmd/main.go",
      "args": ["--zap-log-level=debug"],
      "env": {
        "KUBECONFIG": "${env:HOME}/.kube/config"
      }
    }
  ]
}

🤝 Community Guidelines

Code of Conduct

We follow the Contributor Covenant Code of Conduct. Please be respectful and inclusive in all interactions.

Getting Help

  • GitHub Discussions: For questions and community interaction
  • GitHub Issues: For bug reports and feature requests
  • Code Review: Ask questions during the PR review process
  • Documentation: Check existing documentation first

Recognition

Contributors are recognized in: - Release notes for significant contributions - GitHub contributors list - Project documentation acknowledgments

📚 Resources

Learning Resources

Project Resources

Thank you for contributing to the Neo4j Enterprise Operator! Your contributions help make Neo4j deployments easier and more reliable for everyone.