Development Guide
This guide covers setting up your development environment, understanding the codebase, and making contributions to KSail.
Prerequisites
Section titled “Prerequisites”Required: Go 1.26.0+ (go version ≥ 1.26.0), Docker (docker ps without errors), Git.
Optional: Node.js 22 (docs), golangci-lint, VSCode with Go extension.
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 mod downloadgo install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest # optionalcd docs/ && npm ci && cd .. # docs only3. Build KSail
Section titled “3. Build KSail”go build -o ksail && ./ksail --version4. Run Tests
Section titled “4. Run Tests”go test ./... # all testsgo test ./pkg/svc/provisioner/cluster/kind # specific packagego test -cover ./... # with coveragego test -bench=. -benchmem ./pkg/client/helm # benchmarks5. Run Linters
Section titled “5. Run Linters”golangci-lint run # all lintersgolangci-lint run --fix # auto-fix (import order, etc.)Project 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 TestMyFunction(t *testing.T) { t.Parallel() tests := []struct { name string wantErr bool }{ {name: "valid", wantErr: false}, {name: "invalid", wantErr: true}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { t.Parallel() // test body }) }}Export Pattern for Testing Unexported Functions
Section titled “Export Pattern for Testing Unexported Functions”Use export_test.go to expose unexported symbols for testing without leaking into production binaries:
package provisioner
var ( ExportValidateConfig = validateConfig ExportGenerateManifests = generateManifests)Test these exports from the corresponding <pkg>_test package (for example, package provisioner_test). Add //nolint:gochecknoglobals on exported vars if required by golangci-lint.
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) } }}PRs that modify Go code are automatically benchmarked against main and a comparison comment is posted on the PR. See BENCHMARK-REGRESSION.md for details on interpreting results.
For install duration benchmarks (per-component timing via --benchmark), see benchmarks/install/BENCHMARKS.md.
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”go get -u ./... # update allgo get -u github.com/some/package@latest # update specificgo mod tidy && go mod verify # tidy and verifygo test ./... # verifyWorking on Documentation
Section titled “Working on Documentation”cd docs/npm ci # install dependenciesnpm run dev # serve at http://localhost:4321npm run build # build to docs/dist/npm run preview # preview production buildDebugging
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 Codecovupdate-skills.yaml— Upgrades npx skills daily and opens a PR when updates are availabletest-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:
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: Bump the version, update changelog, and open a PR targeting
main. - Merge triggers release: Push to
mainbuilds binaries for all platforms, generates checksums, creates a GitHub Release, and publishes the VSCode extension to the marketplace. Can also be triggered viaworkflow_dispatch. - Optional tagging: Create an annotated tag (
git tag -a v5.x.x -m "v5.x.x" && git push origin v5.x.x) for explicit versioning.
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 ✓