1
0
Fork 0
mirror of https://github.com/imjasonh/git-k8s synced 2026-07-06 22:12:25 +00:00
git-k8s/CLAUDE.md
Claude ee281430b6
Add repo-watcher-controller for polling remote Git refs
Introduces a fourth controller that watches GitRepository resources and
polls their remotes via git ls-remote on a configurable per-repo interval
(spec.pollInterval, defaulting to 30s). It auto-creates, updates, and
deletes GitBranch CRDs to reflect the actual state of the remote,
enabling fast detection of external pushes to trigger downstream sync.

Key changes:
- Add PollInterval field to GitRepositorySpec
- New pkg/reconciler/repowatcher with controller and reconciler
- New cmd/repo-watcher-controller binary
- CRD manifest updated for pollInterval
- Deployment manifest for the new controller
- Unit tests for ref filtering, naming, and poll interval logic
- CLAUDE.md updated with new controller docs and Go module workaround

https://claude.ai/code/session_01P7xfBqARU5DFS8QJ4uDPVj
2026-02-28 14:09:58 +00:00

7.7 KiB

CLAUDE.md — git-k8s

Project Overview

git-k8s is a Kubernetes-native controller system for managing Git repositories and automated Git operations. It provides four Custom Resource Definitions (CRDs) and three controllers that enable declarative Git workflows within a Kubernetes cluster.

Module: github.com/imjasonh/git-k8s Language: Go 1.24.7 License: Apache-2.0

Architecture

Four-Controller Design

  1. Push Controller (cmd/push-controller/) — Watches GitPushTransaction resources, clones repos into memory using go-git, executes atomic pushes, and updates transaction status through phases (Pending → InProgress → Succeeded/Failed).

  2. Sync Controller (cmd/sync-controller/) — Watches GitRepoSync and GitBranch resources. Compares HEAD commits between two repos, calculates merge bases, and creates push transactions to keep branches synchronized. Marks as Conflicted when both sides have diverged.

  3. Resolver Controller (cmd/resolver-controller/) — Watches GitRepoSync resources in Conflicted phase. Performs automated 3-way merge with file-level conflict detection. Creates merge commits and push transactions to both repos. Falls back to RequiresManualIntervention on failure.

  4. Repo Watcher Controller (cmd/repo-watcher-controller/) — Watches GitRepository resources and polls their remotes via git ls-remote on a configurable interval. Auto-creates, updates, and deletes GitBranch CRDs to reflect the actual state of the remote. Enables fast detection of external pushes to trigger downstream sync.

Custom Resources (CRDs)

CRD Purpose
GitRepository Defines a managed Git repo (clone URL, default branch, auth, poll interval)
GitBranch Tracks a branch within a repo (head commit, last updated)
GitPushTransaction Atomic push operation with refspecs and CAS support
GitRepoSync Two-way sync relationship between two repositories

CRD manifests live in config/crds/.

Key Packages

Package Purpose
pkg/apis/git/v1alpha1 API type definitions, scheme registration, defaults
pkg/client Hand-written typed client wrapper over Kubernetes dynamic client
pkg/reconciler/internal Generic reconciler adapter (KindReconciler[T] interface)
pkg/reconciler/push Push transaction reconciliation logic
pkg/reconciler/sync Repo sync reconciliation logic
pkg/reconciler/resolver Conflict resolution via 3-way merge
pkg/reconciler/repowatcher Remote polling and GitBranch CRD lifecycle

Directory Structure

cmd/                          # Controller entry points
  push-controller/
  sync-controller/
  resolver-controller/
  repo-watcher-controller/
pkg/
  apis/git/v1alpha1/          # CRD types, scheme, defaults, deepcopy
  client/                     # Typed client wrapper (manual, not generated)
  reconciler/
    internal/                 # Shared reconciler adapter pattern
    push/                     # Push transaction controller + reconciler
    sync/                     # Sync controller + reconciler
    resolver/                 # Conflict resolver controller + reconciler
    repowatcher/              # Remote polling + GitBranch lifecycle
config/
  crds/                       # CRD YAML manifests
  rbac/                       # RBAC role definitions
  deployments/                # Controller deployment manifests
  core/                       # Supporting infrastructure (Gitea)
test/e2e/                     # End-to-end tests (build tag: e2e)
hack/                         # Code generation scripts

Build & Development

Prerequisites

  • Go 1.24.7+
  • ko (for container image builds)
  • A Kubernetes cluster (KinD for local development)
  • kubectl

Common Commands

# Build all controller binaries
go build ./cmd/push-controller/
go build ./cmd/sync-controller/
go build ./cmd/resolver-controller/
go build ./cmd/repo-watcher-controller/

# Run unit tests
go test ./...

# Run linting
go vet ./...

# Verify module tidiness
go mod tidy

# Build and deploy to a cluster with ko
ko apply -f config/deployments/

# Install CRDs
kubectl apply -f config/crds/

E2E Tests

E2E tests require a running Kubernetes cluster with Gitea deployed. They are gated behind a build tag:

GITEA_URL=http://localhost:3000 \
GITEA_INTERNAL_URL=http://gitea.git-system.svc.cluster.local:3000 \
  go test -v -count=1 -timeout=10m -tags=e2e ./test/e2e/

Environment variables:

  • GITEA_URL — External Gitea URL accessible from the test runner
  • GITEA_INTERNAL_URL — In-cluster Gitea URL used by controllers

Key Dependencies

  • github.com/go-git/go-git/v5 — All Git operations (clone, push, tree diffing, merge base)
  • k8s.io/client-go — Kubernetes client (dynamic client as foundation)
  • k8s.io/apimachinery — API types, serialization, scheme
  • knative.dev/pkg — Controller lifecycle, injection, logging, leader election

Conventions & Patterns

Reconciler Pattern

Each controller follows the Knative KindReconciler[T] pattern: the generic adapter in pkg/reconciler/internal handles key splitting, resource fetching, and not-found handling. Developers implement only the ReconcileKind(ctx, *T) method with business logic.

Typed Client

The typed client in pkg/client/ is hand-written over the Kubernetes dynamic client (not code-generated). It uses context-based injection (client.WithClient, client.Get). The zz_generated.deepcopy.go file is also hand-written. Both may be replaced with full code generation in the future.

Controller Separation

Each controller is a separate binary/deployment. Controllers communicate through Kubernetes resources — for example, the sync controller creates GitPushTransaction resources that the push controller then processes.

In-Memory Git Operations

All Git operations use go-git with memory.NewStorage(), keeping controllers stateless with no persistent volume requirements.

Status & Phase Management

Resources use phase-based state machines:

  • GitPushTransaction: PendingInProgressSucceeded / Failed
  • GitRepoSync: InSync / Syncing / Conflicted / RequiresManualIntervention

Labels & Ownership

Resources use labels (e.g., git-k8s.imjasonh.com/repo-sync) and owner references for resource relationships. No finalizers are used.

API Group

All CRDs are in the git-k8s.imjasonh.com API group, version v1alpha1.

CI/CD

GitHub Actions (.github/workflows/ci.yaml) runs two jobs:

  1. Buildgo mod tidy check, build all binaries, go test ./..., go vet ./...
  2. E2E — Sets up KinD cluster, installs CRDs, deploys controllers via ko, deploys Gitea, runs e2e tests with -tags=e2e

Container images use ko with a gcr.io/distroless/static:nonroot base image (configured in .ko.yaml).

Go Module Download Workaround

In some CI/cloud environments, go mod download (and go build, go test, etc.) may fail with DNS resolution errors for storage.googleapis.com. This happens when the no_proxy / NO_PROXY environment variable includes *.googleapis.com, causing Go's HTTP client to bypass the egress proxy and attempt direct DNS resolution, which fails.

Fix: Strip *.googleapis.com from no_proxy so that requests to storage.googleapis.com (where the Go module proxy stores zip files) route through the egress proxy:

NO_PROXY=$(echo "$no_proxy" | sed 's/,\*\.googleapis\.com//; s/\*\.googleapis\.com,//; s/\*\.googleapis\.com//') \
no_proxy=$(echo "$no_proxy" | sed 's/,\*\.googleapis\.com//; s/\*\.googleapis\.com,//; s/\*\.googleapis\.com//') \
  go mod download

Apply the same prefix to go build, go test, go vet, etc. when downloading new modules.