Development Guide
Development Guide
This guide covers development workflows and tooling for the Kure project.
Quick Start
# Get help with all available commands
make help
# Run all standard development tasks
make all
# Quick development cycle
make checkContributing Workflow
The main branch is protected — all changes must go through pull requests.
Branch Workflow
Create a feature branch from
main:git checkout -b feat/my-feature mainUse branch prefixes:
feat/,fix/,docs/,chore/Develop and test locally:
make check # Quick validation make precommit # Full pre-commit checksPush and create a pull request:
git push -u origin feat/my-feature gh pr createFill out the PR template (
.github/PULL_REQUEST_TEMPLATE.md).Pass required CI checks:
lint,test,buildGet 1 approving review, resolve all conversations
Merge (linear history required — rebase, no merge commits)
Branch Protection Rules
Enforced via the main-protection repository ruleset
:
- Required status checks:
lint,test,build - Merge queue: merging goes through a GitHub merge queue (rebase method) that rebases and tests the merged result before landing — no manual rebasing, no auto-rebase force-pushes
- Pull requests required: all changes must go through a PR
- Conversation resolution: all review threads must be resolved
- Linear history: enforced (rebase only, no merge commits)
- Force pushes: disabled
- Branch deletion: disabled
- Bypass actors:
kure-release-bot(GitHub App) — allowed to push release commits directly
Development Workflow
1. Initial Setup
Prerequisites:
goandmise— requiredmake,git— requiredbash4+ — requiredyq— required byscripts/sync-versions.sh; pinned inmise.tomlmktemp— required byscripts/sync-versions.shandscripts/vendor-guard.sh, and also by thescripts/test/harness itself (lib.sh’snew_fixture/_run). An external coreutils utility, not a bash builtin, but present on virtually every host with coreutils installed; the two scripts name the failure clearly on the rare host without it.timeout(or macOS Homebrew’sgtimeout) from GNU coreutils — split by scope, not one blanket status:- optional for
scripts/sync-versions.sh check(production runtime): the two bounded probes it uses degrade gracefully to running unbounded, with a startup warning, when neither binary is found. - required to run the full local gate (
mise run verify/scripts/test/run-tests.sh): harness cases09-mvs-floor-hang-timeout.sh(pre-existing) and36-timeout-present-no-warning.sh(new) both need a realtimeout/gtimeoutto pass — seedocs/dependency-updates.md’s harness section for the caveat.
- optional for
# Install dependencies
make deps
# Install development tools
make tools2. Development Cycle
# Format code
make fmt
# Run quick checks (lint, vet, short tests)
make check
# Run all tests
make test
# Run tests with coverage
make test-coverage3. Testing
# Run all tests
make test
# Run tests with verbose output
make test-verbose
# Run tests with race detection
make test-race
# Run only short tests (good for quick feedback)
make test-short
# Run tests with coverage report
make test-coverage
# Run benchmark tests
make test-benchmark
# Run integration tests (when available)
make test-integration4. Code Quality
# Run all linting
make lint
# Format code
make fmt
# Run go vet
make vet
# Tidy modules
make tidy
# Run Qodana static analysis (requires Docker)
make qodanaPre-commit Workflow
Before committing changes, run:
make precommitThis will:
- Format code with
go fmt - Tidy modules
- Run linters
- Run
go vet - Run all tests
CI/CD Pipeline
The project uses several GitHub Actions workflows:
Main CI Pipeline (.github/workflows/ci.yml)
- Triggers: Push to main/develop, PRs
- Jobs:
- Test (unit, race, coverage)
- Lint and format check
- Integration tests (main branch only)
- Security scanning
- Dependency vulnerability checks
Qodana Code Quality (.github/workflows/code_quality.yml)
- Triggers: Push, PRs
- Purpose: Static analysis with JetBrains Qodana
- Uses:
make depsfor setup
Create Release (.github/workflows/release-create.yml)
- Triggers: Manual (
workflow_dispatch) - Inputs: Release type (alpha/beta/rc/stable/bump), scope, dry-run
- Purpose: Creates release commits and tags on
main, pushes atomically - Auth: Uses GitHub App token (
RELEASE_APP_ID+RELEASE_APP_PRIVATE_KEY); thekure-release-botApp is listed as a bypass actor in themain-protectionrepository ruleset, allowing it to push release commits directly tomain - Concurrency: Only one release at a time (
release-creategroup)
To create a release:
- Go to Actions > “Create Release” > Run workflow
- Select release type and optional scope
- Optionally enable dry-run for preview
- Click “Run workflow”
The pushed tag triggers the release pipeline below.
Release Pipeline (.github/workflows/release.yml)
- Triggers: Version tags (
v*.*.*) - Jobs:
- Pre-release validation with
make ci-coverage - Release readiness check with
make release-check - Multi-platform build with
make release-build - GitHub release creation
- Go proxy refresh
- Pre-release validation with
PR Checks (.github/workflows/pr-checks.yml)
- Triggers: PR events
- Jobs:
- Quick validation with
make check - Security and dependency checks
- Test coverage validation
- Changed files analysis
- Performance benchmarks (when labeled)
- Documentation validation
- Quick validation with
Renovate Management
Dependency updates come from Renovate (renovate.json, extending the shared
go-kure/.github preset). The Dependency Dashboard issue is the control
surface:
- Gated updates (every major, all Go-toolchain updates, Flux minors) sit under Pending Approval — tick the checkbox to let Renovate open the PR. Nothing gated is ever proposed on its own.
- Deferring an update: leave its dashboard checkbox unticked; there is nothing to close. To reopen a closed/ignored update, tick its checkbox on the dashboard.
- Rebasing a PR: tick the “rebase/retry” checkbox in the PR body, or the per-PR entry on the dashboard. Renovate also rebases automatically when the PR falls behind the base branch.
- Closing a PR: closing it normally tells Renovate not to recreate that version; the dashboard lists it under Closed/Ignored.
Renovate regenerates docs/compatibility.md on its own branch after gomod or
mise bumps (postUpgradeTasks running ./scripts/sync-versions.sh generate),
so its PRs pass the validate drift check without manual help. The same
postUpgradeTasks rule also runs sh scripts/sync-tool-versions.sh, which
keeps the golangci-lint pin in Makefile, .github/workflows/ci.yml and
docs/github-workflows.md in step with mise.toml, and sh scripts/sync-go-version.sh, which keeps go.mod’s own go directive in step
with mise.toml’s go pin — a bot PR touching those files, or a
check-tool-versions/check-go-version failure on one, is this same
automation. The rule’s last command, ./scripts/gen-builders.sh generate,
regenerates the per-kind constructor wrappers under pkg/kubernetes
(zz_generated_*.go) from the registered scheme, so an API-module bump that
adds or drops a kind arrives with its wrapper; validate runs
./scripts/gen-builders.sh check and fails on drift. Locally:
make gen-builders / make check-builders (or mise run builders:generate /
builders:check).
For the full dependency update process (review, bundling, version tracking), see Dependency Updates .
Makefile Targets Reference
Development
help- Display help messageall- Run all standard development tasksinfo- Display project informationclean- Clean build artifacts and caches
Dependencies
deps- Download and tidy Go modulesdeps-upgrade- Upgrade all dependenciestools- Install development toolsoutdated- Check for outdated dependencies
Testing
test- Run all teststest-verbose- Run tests with verbose outputtest-race- Run tests with race detectiontest-short- Run short tests onlytest-coverage- Run tests with coverage reporttest-benchmark- Run benchmark teststest-integration- Run integration tests
Code Quality
lint- Run all linterslint-go- Run golangci-lintfmt- Format Go codevet- Run go vettidy- Tidy modulesqodana- Run Qodana static analysis
CI/CD
ci- Run CI pipeline tasksci-coverage- Run CI with coverageci-integration- Run CI with integration testscheck- Quick code quality checkprecommit- Run all pre-commit checks
Release
release TYPE=<type>- Preview release (dry-run); types: alpha, beta, rc, stable, bumprelease-check- Check if ready for releaserelease-build- Build release artifacts for multiple platforms
Utilities
generate- Run go generatemod-graph- Display module dependency graphlist-packages- List all packages
Environment Variables
Key environment variables the Makefile respects:
GO- Go command (default:go)GOROOT- Go root directoryVERSION- Version string for buildsBUILD_DIR- Clean target artifact directory (default:bin)OUTPUT_DIR- Clean target artifact directory (default:out)TEST_TIMEOUT- Test timeout (default:30s)PACKAGE_PATH- Package path for kurel operations
Development Tips
Testing Strategy
- Use
make test-shortfor quick feedback during development - Use
make test-coverageto check coverage before PRs - Use
make test-raceto catch concurrency issues - Use
make checkfor quick pre-commit validation
Code Quality
- The CI pipeline enforces 85% test coverage
- All code must pass golangci-lint checks
- Code must be properly formatted with
go fmt - Modules must be tidy
Active Linters
The .golangci.yml enables these linters, aligned with the shared Go standard:
| Linter | Category | Purpose |
|---|---|---|
errcheck | Default | Unchecked errors |
govet | Default | Suspicious constructs |
ineffassign | Default | Ineffectual assignments |
staticcheck | Default | Comprehensive static analysis (includes gosimple S* checks) |
unused | Default | Unused code |
bodyclose | Required | HTTP response body closed |
durationcheck | Required | time.Duration mistakes |
errorlint | Required | Error wrapping issues |
exhaustive | Required | Exhaustive enum switches |
misspell | Required | Common misspellings |
nilerr | Required | Nil error returns |
unconvert | Required | Unnecessary conversions |
whitespace | Required | Unnecessary whitespace |
gosec | Optional | Security checks (kure-specific) |
Formatters: gofmt, goimports (with github.com/go-kure/kure as local prefix).
Performance
- Benchmark tests can be run with
make test-benchmark - PR checks include performance benchmarks when labeled with
performance - Build targets include optimized release builds with
-s -wflags
Troubleshooting
Build Issues
# Clean everything and rebuild
make clean all
# Check Go installation and environment
make infoTest Failures
# Run tests with verbose output for more details
make test-verbose
# Run specific test
go test -v ./pkg/specific/package -run TestSpecificDependency Issues
# Update dependencies
make deps-upgrade
# Check for outdated or vulnerable dependencies
make outdatedThis development guide provides a comprehensive overview of the development workflow using the Makefile and CI/CD pipeline.
Documentation Updates
When modifying a package’s public API, update documentation in the same PR:
- Package README — Update the
README.mdin the package directory (e.g.,pkg/stack/README.md) - Guides — Check the reverse mapping in
AGENTS.mdfor guides that reference the changed package
To verify the docs site builds correctly:
# Check all mounted files exist
bash site/scripts/check-mounts.sh
# Build site
mise run site:buildConsumer Compatibility
Kure’s public packages are consumed by external projects. Keep public APIs stable when possible, describe integration requirements as reusable library capabilities, and follow the organization API stability contract for deprecations or breaking changes.
For local co-development, a consumer can use a Go workspace without adding a committed replace directive:
go work init
go work use ./kure ./consumerBefore publishing a Kure change needed by a consumer, verify Kure with GOWORK=off, then update
and verify the consumer against the released Kure version in its own repository.