Skip to content

Latest commit

 

History

History
352 lines (265 loc) · 12.9 KB

File metadata and controls

352 lines (265 loc) · 12.9 KB

Contributing to git-hubby

Thank you for your interest in contributing to git-hubby! This guide covers everything you need to get started as a contributor.

Table of Contents

Prerequisites

  • Go 1.25.5 or later (see mise.toml for the exact version)
  • kubectl configured to access a Kubernetes cluster (v1.34+ recommended)
  • Docker (or another OCI-compatible container tool) for image builds
  • mise (optional but recommended — manages Go and Kubebuilder versions automatically)

Local Development Setup

  1. Clone the repository:

    git clone <repository-url>
    cd git-hubby
  2. Initialize tooling with mise (optional):

    mise install
  3. Install Go dependencies:

    go mod download
  4. Create your local environment file:

    make env

    This copies .env.tmpl to .env (git-ignored). Edit .env to override defaults for your local environment — for example:

    LOG_LEVEL=DEBUG
    LOG_FORMAT=console
    WATCH_NAMESPACE="github-configuration"
    APP_CREDENTIALS_SECRET_NAMESPACE="github-controller"

    See Configuration below for all available variables.

  5. Install CRDs into your cluster:

    make install
  6. Run the operator locally:

    make run

    This runs the operator against your current kubectl context with webhooks disabled.

  7. Run in a minimal setup:

    make deploy

    This deploys the operator without cert-manager or webhooks, and creates the GitHub App credentials secret directly from the provided arguments. After that you can apply your secret and organization resources and test your changes.

Development Workflow

Essential Make Targets

Run make help for the full list. The most important targets are:

Command Description
make env Create .env from .env.tmpl (safe to re-run)
make build Build the manager binary
make run Run locally (webhooks disabled)
make test Run unit tests with envtest
make test-e2e Run end-to-end tests on a Kind cluster
make lint Run golangci-lint
make lint-fix Lint with auto-fix
make generate Regenerate deepcopy and apply-configuration code
make manifests Regenerate CRDs and RBAC from kubebuilder markers
make codegen Run all code generation steps after an API change (manifests, generate, crd-docs, schemas)
make install Install CRDs into the current cluster
make deploy IMG=<image> Deploy the operator to the current cluster
make undeploy Remove the operator from the current cluster
make uninstall Remove CRDs from the current cluster

After Editing *_types.go or Kubebuilder Markers

Always regenerate all derived artifacts:

make codegen

After Any Go Code Change

make lint-fix   # Auto-fix style issues
make test       # Run unit tests

Kubebuilder Scaffolding

Always use the Kubebuilder CLI to create new resources — don't create files manually:

# New API / CRD
kubebuilder create api --group github --version v1alpha1 --kind <Kind>

# Validation webhook
kubebuilder create webhook --group github --version v1alpha1 --kind <Kind> --programmatic-validation

# Defaulting (mutating) webhook
kubebuilder create webhook --group github --version v1alpha1 --kind <Kind> --defaulting

Project Layout

├── api/v1alpha1/              CRD type definitions and deepcopy (auto-generated)
├── cmd/main.go                Application entry point and wiring
├── internal/
│   ├── controller/            Controller registration and setup
│   ├── reconciler/            Core reconciliation business logic
│   │   ├── orgrec/            Organization reconciler
│   │   ├── reporec/           Repository reconciler
│   │   ├── teamrec/           Team reconciler
│   │   ├── reconcilerfactory/ Factory for creating reconcilers
│   │   └── spreading/         Startup spreading mechanism
│   ├── ghclient/              GitHub client interface, implementation, and mock
│   ├── mapper/                K8s ↔ GitHub struct mapping and comparison
│   ├── ratelimit/             Rate limiter for the operator work queue
│   ├── webhook/v1alpha1/      Validation webhook logic
│   ├── conditions/            Status condition helpers
│   └── logging/               Log mapping utilities
├── config/                    Kustomize manifests (mostly auto-generated)
└── test/                      E2E and integration tests

Auto-Generated — Do Not Edit

Path Regenerated by
api/v1alpha1/zz_generated.deepcopy.go make generate
config/crd/bases/*.yaml make manifests
config/rbac/role.yaml make manifests
config/webhook/manifests.yaml make manifests
docs/crds.md make crd-docs
schemas/*.json make schemas
PROJECT Kubebuilder CLI

Where to Look

Task Location
CRD schemas & validation markers api/v1alpha1/*_types.go
Application wiring & startup cmd/main.go
Controller registration internal/controller/*_controller.go
Reconciliation logic internal/reconciler/{orgrec,reporec,teamrec}/
GitHub API calls internal/ghclient/
K8s ↔ GitHub mapping internal/mapper/
Validation webhooks internal/webhook/v1alpha1/
Status conditions internal/conditions/

Code Conventions

Go Style

  • Follow standard Go conventions and the project's golangci-lint configuration.
  • Run make lint-fix before committing.

Logging

Follow Kubernetes logging message style guidelines:

  • Start with a capital letter, no trailing period.
  • Use past tense: "Deleted Pod", not "Deleting Pod".
  • Specify the object type: "Created Deployment", not "Created".
  • Use structured key-value pairs:
log.Info("Created Deployment", "name", deploy.Name)
log.Error(err, "Failed to create Pod", "name", name)

Testing

  • All packages under cmd/, api/, and internal/ must use Ginkgo v2 + Gomega (BDD style).
  • Each package needs a suite_test.go with the Ginkgo bootstrap.
  • Behaviour tests go in separate *_test.go files using Describe, Context, It, DescribeTable/Entry, Expect(), etc.
  • Do not use plain testing.T assertions in operator packages. The testing package is only acceptable for standalone tooling under hack/ and test/.
  • Use the mock GitHub client in internal/ghclient/mock.go for unit tests.

Kubebuilder Markers

  • CRD validation: +kubebuilder:validation:* on struct fields in *_types.go.
  • RBAC: +kubebuilder:rbac:groups=...,resources=...,verbs=... on controller Reconcile() methods.
  • Webhooks: +kubebuilder:webhook:path=...,mutating=false,... on webhook structs.
  • Never remove // +kubebuilder:scaffold:* comments — the CLI injects code at these markers.

Reconciler Pattern

  • Each reconciler lives in a dedicated package (orgrec, reporec, teamrec) with logic split by concern into separate files (e.g., rec_org.go, rec_rulesets.go).
  • Reconcilers define sequential groups of parallel tasks via RequiredReconciliations().
  • Labels are applied in reconcilers via addLabels()not in webhooks.
  • Webhooks are validation-only; no mutating webhooks exist.

Testing

Unit Tests

make test

Uses envtest (standalone API server + etcd). Coverage for internal/controller/ will show 0% by design — integration tests run reconciliation in separate goroutines outside Go's coverage instrumentation scope.

E2E Tests

make test-e2e

Creates an isolated Kind cluster, runs tests, then tears it down. Never run e2e tests against a production cluster.

IDE Integration

Install the Ginkgo plugin for your IDE for enhanced test debugging and navigation.

Configuration

The operator reads configuration from environment variables, CLI flags, and .env files.

Environment Variables

Variable Description Default
LOG_LEVEL Log level (debug, info, warn, error; case-insensitive) info
LOG_FORMAT Log format: json (default), ecs (Elastic Common Schema), console (human-readable) json
WATCH_NAMESPACE Comma-separated namespace(s) to watch (required)
APP_CREDENTIALS_SECRET_NAMESPACE Namespace containing the GitHub App credentials secret (required)
ENABLE_WEBHOOKS Set to false to disable webhooks (for local development) true
ENABLE_STARTUP_SPREADING Enable startup spreading to prevent API rate limit exhaustion true
STARTUP_SPREAD_PERIOD_MINUTES Grace period after startup during which reconciliations may be delayed 5
SPREAD_INTERVAL_MINUTES Time window across which warm-start reconciliations are distributed 180

.env File

The .env file is loaded automatically on startup and is git-ignored. Create it from the template:

make env

Edit .env freely — it won't be committed. The template (.env.tmpl) contains sensible defaults for local development.

Submitting Changes

  1. Fork the repository and create a feature branch from main.
  2. Make your changes, following the conventions above.
  3. Run the full validation suite:
    make codegen   # if you changed types or markers
    make lint-fix
    make test
  4. Write or update tests for your changes.
  5. Commit using Conventional Commits format. This is enforced by CI on pull requests.
  6. Open a Pull Request against main with a description of what changed and why.

CI/CD Workflows

Codegen Check

The Codegen Check workflow verifies that generated code is up to date on every PR. It runs all generation steps, then fails if there are uncommitted changes. Always run this before pushing:

make codegen

Helm Chart Update

The Update Helm Chart workflow manages CRD updates in Interhyp/git-hubby-helm:

  • Automatic (after release): After a successful "Build & Release" workflow, CRDs are copied to the helm chart repo with an updated appVersion, and a draft PR is created (main only) labeled automatic-update.
  • Manual (any branch): You can trigger the workflow manually via workflow_dispatch to test CRD updates from your feature branch. The result is pushed to a snapshot/<branch> branch in git-hubby-helm (no PR is created).

To manually trigger from your branch:

gh workflow run "Update Helm Chart" --ref <your-branch-name>

Note: Only CRDs are updated automatically. The Helm chart's other templates (deployment, RBAC, webhooks) are maintained manually. The CI workflow will comment on your PR if it detects changes that require a matching Helm chart update:

  • +kubebuilder:rbac markers → RBAC template
  • +kubebuilder:webhook markers → webhook configuration template
  • config/manager/manager.yaml → deployment template (env vars, args, ports, volumes)

Commit Message Format

This project uses Conventional Commits for automated semantic versioning and changelog generation.

<type>(<scope>): <subject>

[optional body]

[optional footer(s)]

Types (determines version bump):

Type Description Version bump
feat A new feature Minor
fix A bug fix Patch
docs Documentation only None
style Code style (formatting, no logic change) None
refactor Code change (no new feature, no fix) None
perf Performance improvement Patch
test Adding or updating tests None
build Build system or dependency changes None
ci CI configuration changes None
chore Maintenance tasks None
revert Reverts a previous commit Patch

Breaking changes (major version bump): Add BREAKING CHANGE: in the footer or ! after the type:

feat!: remove deprecated API endpoints

BREAKING CHANGE: The /v1/legacy endpoint has been removed.

Examples:

feat(org): add support for organization-level custom roles
fix(repo): handle 404 when repository is deleted externally
docs: update CONTRIBUTING.md with commit format guide
chore(deps): bump go-github to v87

License

By contributing to git-hubby, you agree that your contributions will be licensed under the Apache License 2.0.