Development Guide
This guide covers setting up your development environment, understanding the codebase, and making contributions to KSail.
Prerequisites
Section titled âPrerequisitesâRequired Tools
Section titled âRequired Toolsâ-
Go 1.26.0+ â KSail is written in Go
- Install from go.dev/dl
- Verify:
go versionshould show 1.26.0 or higher
-
Docker â Required for local cluster testing
- Install Docker Desktop or Docker Engine
- Verify:
docker psshould run without errors
-
Git â Version control
- Install from your package manager or git-scm.com
Optional Tools
Section titled âOptional ToolsâNode.js 22 (docs), golangci-lint v2.8.0 (linting via go install), and VSCode with the Go extension are useful but not required.
Development Setup
Section titled âDevelopment Setupâ1. Clone the Repository
Section titled â1. Clone the Repositoryâgit clone https://github.com/devantler-tech/ksail.gitcd ksail2. Install Dependencies
Section titled â2. Install Dependenciesâ# Go dependencies (automatically downloaded on first build)go mod download
# Development tools (optional)go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.8.0
# Documentation dependencies (if working on docs)cd docs/npm cicd ..3. Build KSail
Section titled â3. Build KSailâ# Development buildgo build -o ksail
# Verify the build./ksail --version4. Run Tests
Section titled â4. Run Testsâ# Unit testsgo test ./...
# Specific packagego test ./pkg/svc/provisioner/cluster/kind
# With coveragego test -cover ./...
# Benchmarksgo test -bench=. -benchmem ./pkg/client/helm5. Run Linters
Section titled â5. Run Lintersâ# Run all lintersgolangci-lint run
# Run specific lintergolangci-lint run --enable-only=gofmt
# Auto-fix issues (import order, etc.)golangci-lint run --fixProject Structure
Section titled âProject StructureâKey Directories
Section titled âKey Directoriesâksail/âââ .github/ # CI/CD workflows and agentic workflowsâ âââ workflows/ # GitHub Actions workflows (.yaml + .md)â âââ copilot-instructions.md # Copilot coding instructionsâââ docs/ # Documentation (Astro/Starlight)â âââ src/content/docs/ # Markdown documentation filesâ âââ public/ # Static assetsâââ internal/ # Internal (private) packagesâ âââ buildmeta/ # Build metadata (version, commit, date)âââ pkg/ # Public packagesâ âââ apis/ # API types and schemasâ âââ cli/ # CLI commands and UIâ âââ client/ # Embedded tool clientsâ âââ svc/ # Core servicesâ â âââ provider/ # Infrastructure providersâ â âââ provisioner/ # Distribution provisionersâ â âââ installer/ # Component installersâ âââ [utilities] # di, envvar, fsutil, k8s, notify, etc.âââ schemas/ # JSON schemas for validationâââ vsce/ # VSCode extensionâââ main.go # Application entry pointâââ go.mod # Go module definitionâââ .golangci.yml # Linter configurationImport Restrictions
Section titled âImport Restrictionsâinternal/ packages can only be imported within the ksail module; pkg/ packages are public. Circular dependencies are not allowed.
Development Workflow
Section titled âDevelopment Workflowâ1. Create a Feature Branch
Section titled â1. Create a Feature Branchâgit checkout -b feature/my-feature2. Make Changes and Push
Section titled â2. Make Changes and PushâKeep changes focused and atomic. Write tests, update documentation, and follow existing code patterns:
go test ./... # Run unit testsgolangci-lint run # Run lintersgo build -o ksail # Build./ksail cluster init # Smoke test
git add . && git commit -m "feat: add new feature"git push origin feature/my-featureCommit types: feat, fix, docs, refactor, test, chore, perf. Open a PR with a clear description and ensure CI passes.
Coding Standards
Section titled âCoding StandardsâGo Style
Section titled âGo StyleâFollow Effective Go. Use gofmt for formatting, goimports for import order, and keep lines under 100 characters (enforced by golines).
Naming Conventions
Section titled âNaming Conventionsâ| Entity | Convention | Example |
|---|---|---|
| Packages | Lowercase, singular | provider, installer |
| Types, Interfaces | PascalCase; interfaces often end in -er | KindClusterProvisioner, Provider |
| Functions/Methods | PascalCase (exported), camelCase (unexported) | Create, validateConfig |
| Variables, Constants | camelCase (unexported), PascalCase (exported) | clusterName, DefaultTimeout |
Error Handling
Section titled âError HandlingâReturn errors explicitly (no panic in library code). Wrap errors with fmt.Errorf("context: %w", err) and use custom error types where appropriate. golangci-lint enforces that all errors are checked.
Testing Patterns
Section titled âTesting PatternsâUnit Tests
Section titled âUnit TestsâUse table-driven tests with t.Parallel():
func TestProvisionerCreate(t *testing.T) { t.Parallel()
tests := []struct { name string wantErr bool }{ {name: "successful creation", wantErr: false}, {name: "creation fails", wantErr: true}, }
for _, testCase := range tests { t.Run(testCase.name, func(t *testing.T) { t.Parallel() m := mocks.NewMockProvisioner(t) if testCase.wantErr { m.On("Create", mock.Anything).Return(errors.New("create failed")) } else { m.On("Create", mock.Anything).Return(nil) } err := m.Create(context.Background()) if (err != nil) != testCase.wantErr { t.Errorf("Create() error = %v, wantErr %v", err, testCase.wantErr) } }) }}Export Pattern for Testing Unexported Functions
Section titled âExport Pattern for Testing Unexported FunctionsâUse export_test.go to expose unexported symbols to _test packages without leaking them into production binaries. This file is compiled only during go test because its name ends with _test.go. It uses the regular package name (for example, package provisioner) so the exported aliases are built along with the package-under-test and can then be accessed from an external package provisioner_test:
package provisioner
var ( ExportValidateConfig = validateConfig ExportGenerateManifests = generateManifests)Test from package provisioner_test for clean black-box testing. Add a //nolint:gochecknoglobals annotation above these exported variables when required to satisfy golangci-lint, unless a path-specific exclusion for test exports is configured.
Mocking with Testify
Section titled âMocking with TestifyâKSail uses mockery for generating mocks via //go:generate go run github.com/vektra/mockery/v2. Use generated mocks in tests:
func TestWithMock(t *testing.T) { mockProv := new(MockProvider) mockProv.On("Create", mock.Anything).Return(nil) // Use mockProv... mockProv.AssertExpectations(t)}Important: Never use .Times(b.N) with for b.Loop() in benchmarks â b.N is 1 when evaluated before the loop. Omit .Times() for unlimited calls.
Benchmarks
Section titled âBenchmarksâfunc BenchmarkProvisionerCreate(b *testing.B) { p := setupProvisioner() ctx := context.Background()
for b.Loop() { // Go 1.26+ style if err := p.Create(ctx); err != nil { b.Fatal(err) } }}Documentation
Section titled âDocumentationâDocument all exported types, functions, and constants with complete sentences starting with the name being documented (e.g., // Provider defines the interface for infrastructure providers.). When adding features, update the relevant .mdx files in docs/src/content/docs/, README.md if needed, and CLI help text if adding commands.
Common Development Tasks
Section titled âCommon Development TasksâAll new components follow the same pattern: create a package under the relevant pkg/svc/ subdirectory, implement the corresponding interface, register in the factory, add tests, and update documentation.
| Task | Package path | Interface | Factory |
|---|---|---|---|
| New Provider | pkg/svc/provider/newprovider/ | Provider | pkg/svc/provider/factory.go |
| New Provisioner | pkg/svc/provisioner/cluster/newdist/ | Provisioner | pkg/svc/provisioner/cluster/factory.go |
| New Installer | pkg/svc/installer/newcomponent/ | Installer | pkg/cli/setup/ |
For a new Provisioner, also add a getting-started guide in docs/src/content/docs/getting-started/. For a new Installer, also add configuration to pkg/apis/cluster/v1alpha1/.
Updating Dependencies
Section titled âUpdating Dependenciesâ# Update all dependenciesgo get -u ./...
# Update specific dependencygo get -u github.com/some/package@latest
# Tidy and verifygo mod tidygo mod verify
# Test after updatego test ./...Working on Documentation
Section titled âWorking on Documentationâcd docs/
# Install dependenciesnpm ci
# Start development servernpm run dev# Visit http://localhost:4321
# Build production sitenpm run build# Output: docs/dist/
# Preview production buildnpm run previewDocumentation Guidelines
Section titled âDocumentation GuidelinesâUse clear, concise language with code examples. Follow existing structure and GitHub Flavored Markdown.
Debugging
Section titled âDebuggingâEnable Debug Logging
Section titled âEnable Debug LoggingâKSail doesnât have built-in debug logging yet. Use temporary fmt.Printf("DEBUG: value = %+v\n", value) statements or the Delve debugger:
go install github.com/go-delve/delve/cmd/dlv@latestdlv test -- -test.run TestName # debug a testdlv exec ./ksail -- cluster create # debug the binaryVSCode users can set breakpoints and press F5 with a .vscode/launch.json configuration.
Common Issues
Section titled âCommon Issuesâ| Error | Fix |
|---|---|
| âDocker not availableâ | Verify Docker is running: docker ps. Check Docker Desktop is started (macOS/Windows) or socket permissions (Linux). |
| âGo version mismatchâ | Run go version â must be 1.26.0+. Update from go.dev/dl. |
| âImport cycle not allowedâ | Move shared types to pkg/apis/ or a utility package. Avoid circular imports. |
| âLinter failuresâ | Run golangci-lint run --fix to auto-fix. Check .golangci.yml for enabled linters; some issues require manual fixes. |
GitHub Actions Workflows
Section titled âGitHub Actions WorkflowsâKSail uses several CI workflows:
ci.yamlâ Runs on every PR and push to main; builds KSail, runs unit and system tests, uploads coverage to Codecovtest-pages.yamlâ Validates documentation builds on docs changespublish-pages.yamlâ Deploys documentation to GitHub Pages on main branch pushesrelease.yamlâ Builds release binaries and publishes to GitHub Releases; triggered by push tomainorworkflow_dispatch
Agentic Workflows
Section titled âAgentic WorkflowsâKSail uses five AI-powered daily workflows for continuous improvement (scheduled at 02:00, 10:00, 14:00, 18:00, and 22:00 UTC):
daily-code-quality.mdâ Refactoring, performance optimization, and test coverage improvementsdaily-plan.mdâ Triages new issues and creates/prioritizes backlog issues from the roadmapdaily-builder.mdâ Implements roadmap features and tackles backlog issuesdaily-workflow-maintenance.mdâ Updates and optimizes CI workflowsdaily-docs.mdâ Keeps documentation in sync and reduces bloat
These run on schedules and can be triggered manually via gh aw commands.
Release Process
Section titled âRelease ProcessâReleases are automated via .goreleaser.yaml and .github/workflows/release.yaml:
-
Prepare a release PR targeting
main:- Bump the version in code/docs as needed (e.g.
v5.x.x) - Update changelog / release notes in the repository
- Open a pull request against
mainand get it reviewed/merged
- Bump the version in code/docs as needed (e.g.
-
When the PR is merged and changes land on
main, the release workflow runs:- Triggered by the push to
main(or manually viaworkflow_dispatchby maintainers) - Builds binaries for all platforms/architectures
- Generates checksums
- Creates a GitHub Release with artifacts
- Publishes the VSCode extension to the marketplace
- Triggered by the push to
-
Optional tagging (for maintainers): Create and push an annotated tag (
git tag -a v5.x.x -m "v5.x.x" && git push origin v5.x.x) and update release notes on GitHub if needed.
Getting Help
Section titled âGetting Helpâ- Discussions: github.com/devantler-tech/ksail/discussions
- Issues: github.com/devantler-tech/ksail/issues
- Documentation: ksail.devantler.tech
- Contributing Guide: CONTRIBUTING.md
Code Review Guidelines
Section titled âCode Review GuidelinesâPRs should be focused on a single concern with clear commit messages, tests for new functionality, and updated documentation. Squash commits before merge (or allow maintainer to).
Review checklist: code style â | tests added and passing â | docs updated â | commit messages clear â | CI passes â | no security issues â